Beispiel #1
0
static void
destroy_cursock(lcbio_CONNSTART *cs)
{
    lcbio_SOCKET *s = cs->sock;
    lcbio_TABLE *iot = s->io;
    if (cs->ai) {
        cs->ai = cs->ai->ai_next;
    }

    if (!cs->ai) {
        return;
    }

    if (IOT_IS_EVENT(iot)) {
        if (cs->ev_active) {
            lcb_assert(s->u.fd != INVALID_SOCKET);
            IOT_V0EV(iot).cancel(IOT_ARG(iot), s->u.fd, cs->event);
            cs->ev_active = 0;
        }
        IOT_V0IO(iot).close(IOT_ARG(iot), s->u.fd);
        s->u.fd = INVALID_SOCKET;
    } else {
        if (s->u.sd) {
            IOT_V1(iot).close(IOT_ARG(iot), s->u.sd);
            s->u.sd = NULL;
        }
    }
}
Beispiel #2
0
int
lcbio_is_netclosed(lcbio_SOCKET *sock, int flags)
{
    lcbio_pTABLE iot = sock->io;

    if (IOT_IS_EVENT(iot)) {
        return IOT_V0IO(iot).is_closed(IOT_ARG(iot), sock->u.fd, flags);
    } else {
        return IOT_V1(iot).is_closed(IOT_ARG(iot), sock->u.sd, flags);
    }
}
Beispiel #3
0
void
lcbio_shutdown(lcbio_SOCKET *s)
{
    lcbio_TABLE *io = s->io;

    lcbio__protoctx_delall(s);
    if (IOT_IS_EVENT(io)) {
        if (s->u.fd != INVALID_SOCKET) {
            IOT_V0IO(io).close(IOT_ARG(io), s->u.fd);
            s->u.fd = INVALID_SOCKET;
        }
    } else {
        if (s->u.sd) {
            IOT_V1(io).close(IOT_ARG(io), s->u.sd);
            s->u.sd = NULL;
        }
    }
}
Beispiel #4
0
/** Extended function used for write-on-callback mode */
static int
E_put_ex(lcbio_CTX *ctx, lcb_IOV *iov, unsigned niov, unsigned nb)
{
    lcb_ssize_t nw;
    lcbio_TABLE *iot = ctx->io;
    lcb_socket_t fd = CTX_FD(ctx);

    GT_WRITE_AGAIN:
    nw = IOT_V0IO(iot).sendv(IOT_ARG(iot), fd, iov, niov);
    if (nw > 0) {
        ctx->procs.cb_flush_done(ctx, nb, nw);
        return 1;

    } else if (nw == -1) {
        switch (IOT_ERRNO(iot)) {
        case EINTR:
            /* jump back to retry */
            goto GT_WRITE_AGAIN;

        case C_EAGAIN:
        case EWOULDBLOCK:
            nw = 0;
            /* indicate zero bytes were written, but don't send an error */
            goto GT_WRITE0;
        default:
            /* pretend all the bytes were written and deliver an error during
             * the next event loop iteration. */
            nw = nb;
            lcbio_ctx_senderr(ctx, convert_lcberr(ctx, LCBIO_IOERR));
            goto GT_WRITE0;
        }
    } else {
        /* connection closed. pretend everything was written and send an error */
        nw = nb;
        lcbio_ctx_senderr(ctx, convert_lcberr(ctx, LCBIO_SHUTDOWN));
        goto GT_WRITE0;
    }

    GT_WRITE0:
    ctx->procs.cb_flush_done(ctx, nb, nw);
    return 0;
}
Beispiel #5
0
lcb_socket_t
lcbio_E_ai2sock(lcbio_TABLE *io, struct addrinfo **ai, int *connerr)
{
    lcb_socket_t ret = INVALID_SOCKET;
    *connerr = 0;

    for (; *ai; *ai = (*ai)->ai_next) {
        ret = IOT_V0IO(io).socket0(
                IOT_ARG(io), (*ai)->ai_family, (*ai)->ai_socktype,
                (*ai)->ai_protocol);

        if (ret != INVALID_SOCKET) {
            return ret;
        } else {
            *connerr = IOT_ERRNO(io);
        }
    }

    return ret;
}
Beispiel #6
0
static void
E_connect(lcb_socket_t sock, short events, void *arg)
{
    lcbio_CONNSTART *cs = arg;
    lcbio_SOCKET *s = cs->sock;
    lcbio_TABLE *io = s->io;
    int retry_once = 0;
    lcbio_CSERR connstatus;

    (void)sock;

    lcb_log(LOGARGS(s, TRACE), CSLOGFMT "Got event handler for new connection", CSLOGID(s));

    GT_NEXTSOCK:
    if (ensure_sock(cs) == -1) {
        cs_state_signal(cs, CS_ERROR, LCB_CONNECT_ERROR);
        return;
    }

    if (events & LCB_ERROR_EVENT) {
        socklen_t errlen = sizeof(int);
        int sockerr = 0;
        lcb_log(LOGARGS(s, TRACE), CSLOGFMT "Received ERROR_EVENT", CSLOGID(s));
        getsockopt(s->u.fd, SOL_SOCKET, SO_ERROR, (char *)&sockerr, &errlen);
        lcbio_mksyserr(sockerr, &cs->syserr);
        destroy_cursock(cs);
        goto GT_NEXTSOCK;

    } else {
        int rv = 0;
        struct addrinfo *ai = cs->ai;

        GT_CONNECT:
        rv = IOT_V0IO(io).connect0(
                IOT_ARG(io), s->u.fd, ai->ai_addr, (unsigned)ai->ai_addrlen);

        if (rv == 0) {
            cs_unwatch(cs);
            cs_state_signal(cs, CS_CONNECTED, LCB_SUCCESS);
            return;
        }
    }

    connstatus = lcbio_mkcserr(IOT_ERRNO(io));
    lcbio_mksyserr(IOT_ERRNO(io), &cs->syserr);


    switch (connstatus) {

    case LCBIO_CSERR_INTR:
        goto GT_CONNECT;

    case LCBIO_CSERR_CONNECTED:
        cs_unwatch(cs);
        cs_state_signal(cs, CS_CONNECTED, LCB_SUCCESS);
        return;

    case LCBIO_CSERR_BUSY:
        lcb_log(LOGARGS(s, TRACE), CSLOGFMT "Scheduling asynchronous watch for socket.", CSLOGID(s));
        IOT_V0EV(io).watch(
                IOT_ARG(io), s->u.fd, cs->event, LCB_WRITE_EVENT, cs, E_connect);
        cs->ev_active = 1;
        return;

    case LCBIO_CSERR_EINVAL:
        if (!retry_once) {
            retry_once = 1;
            goto GT_CONNECT;
        }
        /* fallthrough */

    case LCBIO_CSERR_EFAIL:
    default:
        /* close the current socket and try again */
        lcb_log(LOGARGS(s, TRACE), CSLOGFMT "connect() failed. os_error=%d [%s]", CSLOGID(s), IOT_ERRNO(io), strerror(IOT_ERRNO(io)));
        destroy_cursock(cs);
        goto GT_NEXTSOCK;
    }
}