Example #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;
        }
    }
}
Example #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);
    }
}
Example #3
0
static void
C_schedule(lcbio_CTX *ctx)
{
    lcbio_TABLE *io = ctx->io;
    lcb_sockdata_t *sd = CTX_SD(ctx);
    int rv;

    if (ctx->output && ctx->output->rb.nbytes) {
        /** Schedule a write */
        lcb_IOV iov[2];
        unsigned niov;

        ringbuffer_get_iov(&ctx->output->rb, RINGBUFFER_READ, iov);
        niov = iov[1].iov_len ? 2 : 1;
        rv = IOT_V1(io).write2(IOT_ARG(io), sd, iov, niov, ctx->output, Cw_handler);
        if (rv) {
            lcbio_ctx_senderr(ctx, convert_lcberr(ctx, LCBIO_IOERR));
            return;
        } else {
            ctx->output = NULL;
            ctx->npending++;
        }
    }

    if (ctx->wwant) {
        ctx->wwant = 0;
        ctx->procs.cb_flush_ready(ctx);
    }

    if (ctx->rdwant && sd->is_reading == 0) {
        lcb_IOV iov[RWINL_IOVSIZE];
        unsigned ii;
        unsigned niov = rdb_rdstart(&ctx->ior, (nb_IOV *)iov, RWINL_IOVSIZE);

        assert(niov);
        for (ii = 0; ii < niov; ++ii) {
            assert(iov[ii].iov_len);
        }

        rv = IOT_V1(io).read2(IOT_ARG(io), sd, iov, niov, ctx, Cr_handler);
        if (rv) {
            lcbio_ctx_senderr(ctx, convert_lcberr(ctx, LCBIO_IOERR));

        } else {
            sd->is_reading = 1;
            ctx->npending++;
        }
    }
}
Example #4
0
lcbio_CTX *
lcbio_ctx_new(lcbio_SOCKET *sock, void *data, const lcbio_EASYPROCS *procs)
{
    lcbio_CTX *ctx = calloc(1, sizeof(*ctx));
    ctx->sock = sock;
    sock->ctx = ctx;
    ctx->io = sock->io;
    ctx->data = data;
    ctx->procs = *procs;
    ctx->state = ES_ACTIVE;
    ctx->as_err = lcbio_timer_new(ctx->io, ctx, err_handler);
    ctx->subsys = "unknown";

    rdb_init(&ctx->ior, sock->settings->allocator_factory());
    lcbio_ref(sock);

    if (IOT_IS_EVENT(ctx->io)) {
        ctx->event = IOT_V0EV(ctx->io).create(IOT_ARG(ctx->io));
        ctx->fd = sock->u.fd;
    } else {
        ctx->sd = sock->u.sd;
    }

    ctx->procs = *procs;
    ctx->state = ES_ACTIVE;

    lcb_log(LOGARGS(ctx, DEBUG), CTX_LOGFMT "Pairing with SOCK=%p", CTX_LOGID(ctx), (void*)sock);
    return ctx;
}
Example #5
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;
        }
    }
}
Example #6
0
static void
deactivate_watcher(lcbio_CTX *ctx)
{
    if (ctx->evactive && ctx->event) {
        IOT_V0EV(CTX_IOT(ctx)).cancel(
                IOT_ARG(CTX_IOT(ctx)), CTX_FD(ctx), ctx->event);
        ctx->evactive = 0;
    }
}
Example #7
0
void
lcbio_ctx_close_ex(lcbio_CTX *ctx, lcbio_CTXCLOSE_cb cb, void *arg,
                   lcbio_CTXDTOR_cb dtor, void *dtor_arg)
{
    unsigned oldrc;
    ctx->state = ES_DETACHED;
    assert(ctx->sock);

    if (ctx->event) {
        deactivate_watcher(ctx);
        IOT_V0EV(CTX_IOT(ctx)).destroy(IOT_ARG(CTX_IOT(ctx)), ctx->event);
        ctx->event = NULL;
    }

    if (ctx->as_err) {
        lcbio_timer_destroy(ctx->as_err);
        ctx->as_err = NULL;
    }

    oldrc = ctx->sock->refcount;
    lcb_log(LOGARGS(ctx, DEBUG), CTX_LOGFMT "Destroying. PND=%d,ENT=%d,SORC=%d", CTX_LOGID(ctx), (int)ctx->npending, (int)ctx->entered, oldrc);

    if (cb) {
        int reusable =
                ctx->npending == 0 && /* no pending events */
                ctx->err == LCB_SUCCESS && /* no socket errors */
                ctx->rdwant == 0 && /* no expected input */
                ctx->wwant == 0 && /* no expected output */
                (ctx->output == NULL || ctx->output->rb.nbytes == 0);
        cb(ctx->sock, reusable, arg);
    }

    if (oldrc == ctx->sock->refcount) {
        lcbio_shutdown(ctx->sock);
    }

    if (ctx->output) {
        ringbuffer_destruct(&ctx->output->rb);
        free(ctx->output);
        ctx->output = NULL;
    }

    ctx->fd = INVALID_SOCKET;
    ctx->sd = NULL;

    if (dtor) {
        ctx->data = dtor_arg;
        ctx->procs.cb_flush_ready = dtor;

    } else {
        ctx->procs.cb_flush_ready = NULL;
    }

    if (ctx->npending == 0 && ctx->entered == 0) {
        free_ctx(ctx);
    }
}
Example #8
0
/**
 * Handler invoked to deliver final status for a connection. This will invoke
 * the user supplied callback with the relevant status (if it has not been
 * cancelled) and then free the CONNSTART object.
 */
static void
cs_handler(void *cookie)
{
    lcbio_CONNSTART *cs = cookie;
    lcb_error_t err;
    lcbio_SOCKET *s = cs->sock;

    if (s && cs->event) {
        cs_unwatch(cs);
        IOT_V0EV(s->io).destroy(IOT_ARG(s->io), cs->event);
    }

    if (cs->state == CS_PENDING) {
        /* state was not changed since initial scheduling */
        err = LCB_ETIMEDOUT;
    } else if (cs->state == CS_CONNECTED) {
        /* clear pending error */
        err = LCB_SUCCESS;
    } else {
        if (s != NULL && cs->pending == LCB_CONNECT_ERROR) {
            err = lcbio_mklcberr(cs->syserr, s->settings);
        } else {
            err = cs->pending;
        }
    }

    if (cs->state == CS_CANCELLED) {
        /* ignore everything. Clean up resources */
        goto GT_DTOR;
    }

    if (s) {
        lcbio__load_socknames(s);
        if (err == LCB_SUCCESS) {
            lcb_log(LOGARGS(s, INFO), CSLOGFMT "Connected ", CSLOGID(s));
        } else {
            lcb_log(LOGARGS(s, ERR), CSLOGFMT "Failed: lcb_err=0x%x, os_errno=%u", CSLOGID(s), err, cs->syserr);
        }
    }

    /** Handler section */
    cs->in_uhandler = 1;
    cs->handler(err == LCB_SUCCESS ? s : NULL, cs->arg, err, cs->syserr);

    GT_DTOR:
    if (cs->async) {
        lcbio_timer_destroy(cs->async);
    }
    if (cs->sock) {
        lcbio_unref(cs->sock);
    }
    if (cs->ai_root) {
        freeaddrinfo(cs->ai_root);
    }
    free(cs);
}
Example #9
0
static void
cs_unwatch(lcbio_CONNSTART *cs)
{
    lcbio_SOCKET *s = cs->sock;
    if (s && cs->ev_active) {
        lcb_assert(s->u.fd != INVALID_SOCKET);
        IOT_V0EV(s->io).cancel(IOT_ARG(s->io), s->u.fd, cs->event);
        cs->ev_active = 0;
    }
}
Example #10
0
LIBCOUCHBASE_API
lcb_error_t lcb_tick_nowait(lcb_t instance)
{
    lcb_io_tick_fn tick = instance->iotable->loop.tick;
    if (!tick) {
        return LCB_CLIENT_FEATURE_UNAVAILABLE;
    } else {
        maybe_reset_timeouts(instance);
        tick(IOT_ARG(instance->iotable));
        return LCB_SUCCESS;
    }
}
Example #11
0
void
lcb_maybe_breakout(lcb_t instance)
{
    if (!instance->wait) {
        return;
    }
    if (has_pending(instance)) {
        return;
    }

    instance->wait = 0;
    instance->iotable->loop.stop(IOT_ARG(instance->iotable));
}
Example #12
0
static void
C_connect(lcbio_CONNSTART *cs)
{
    int rv;
    lcbio_SOCKET *s = cs->sock;
    int retry_once = 0;
    lcbio_CSERR status;
    lcbio_TABLE *io = s->io;

    GT_NEXTSOCK:
    if (ensure_sock(cs) != 0) {
        lcbio_mksyserr(IOT_ERRNO(io), &cs->syserr);
        cs_state_signal(cs, CS_ERROR, LCB_CONNECT_ERROR);
        return;
    }

    GT_CONNECT:
    rv = IOT_V1(io).connect(IOT_ARG(io), s->u.sd, cs->ai->ai_addr,
                            (unsigned)cs->ai->ai_addrlen, C_conncb);
    if (rv == 0) {
        lcbio_ref(s);
        return;
    }

    lcbio_mksyserr(IOT_ERRNO(io), &cs->syserr);
    status = lcbio_mkcserr(IOT_ERRNO(io));
    switch (status) {

    case LCBIO_CSERR_INTR:
        goto GT_CONNECT;

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

    case LCBIO_CSERR_BUSY:
        return;

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

    case LCBIO_CSERR_EFAIL:
    default:
        destroy_cursock(cs);
        goto GT_NEXTSOCK;
    }
}
Example #13
0
lcb_sockdata_t *
lcbio_C_ai2sock(lcbio_TABLE *io, struct addrinfo **ai, int *connerr)
{
    lcb_sockdata_t *ret = NULL;
    for (; *ai; *ai = (*ai)->ai_next) {
        ret = IOT_V1(io).socket(
                IOT_ARG(io), (*ai)->ai_family, (*ai)->ai_socktype,
                (*ai)->ai_protocol);
        if (ret) {
            return ret;
        } else {
            *connerr = IOT_ERRNO(io);
        }
    }
    return ret;
}
Example #14
0
static int
C_put_ex(lcbio_CTX *ctx, lcb_IOV *iov, unsigned niov, unsigned nb)
{
    lcbio_TABLE *iot = ctx->io;
    lcb_sockdata_t *sd = CTX_SD(ctx);
    int status = IOT_V1(iot).write2(IOT_ARG(iot),
        sd, iov, niov, (void *)(uintptr_t)nb, Cw_ex_handler);
    if (status) {
        /** error! */
        lcbio_OSERR saverr = IOT_ERRNO(iot);
        ctx->procs.cb_flush_done(ctx, nb, nb);
        lcbio_ctx_senderr(ctx, lcbio_mklcberr(saverr, ctx->sock->settings));
        return 0;
    } else {
        ctx->npending++;
        return 1;
    }
}
Example #15
0
static int
ensure_sock(lcbio_CONNSTART *cs)
{
    lcbio_SOCKET *s = cs->sock;
    lcbio_TABLE *io = s->io;
    int errtmp = 0;

    if (cs->ai == NULL) {
        return -1;
    }

    if (IOT_IS_EVENT(io)) {
        if (s->u.fd != INVALID_SOCKET) {
            /* already have one? */
            return 0;
        }

        while (s->u.fd == INVALID_SOCKET && cs->ai != NULL) {
            s->u.fd = lcbio_E_ai2sock(io, &cs->ai, &errtmp);
            if (s->u.fd != INVALID_SOCKET) {
                return 0;
            }
        }
    } else {
        if (s->u.sd) {
            return 0;
        }

        while (s->u.sd == NULL && cs->ai != NULL) {
            s->u.sd = lcbio_C_ai2sock(io, &cs->ai, &errtmp);
            if (s->u.sd) {
                s->u.sd->lcbconn = (void *) cs->sock;
                s->u.sd->parent = IOT_ARG(io);
                return 0;
            }
        }
    }

    if (cs->ai == NULL) {
        lcbio_mksyserr(IOT_ERRNO(io), &cs->syserr);
        return -1;
    }
    return 0;
}
Example #16
0
void
lcbio__load_socknames(lcbio_SOCKET *sock)
{
    int n_salocal, n_saremote, rv;
    struct lcb_nameinfo_st ni;
    lcbio_CONNINFO *info = sock->info;

    n_salocal = sizeof(info->sa_local);
    n_saremote = sizeof(info->sa_remote);
    ni.local.name = (struct sockaddr *)&info->sa_local;
    ni.local.len = &n_salocal;
    ni.remote.name = (struct sockaddr *)&info->sa_remote;
    ni.remote.len = &n_saremote;

    if (!IOT_IS_EVENT(sock->io)) {
        if (!sock->u.sd) {
            return;
        }

        rv = IOT_V1(sock->io).nameinfo(IOT_ARG(sock->io), sock->u.sd, &ni);

        if (ni.local.len == 0 || ni.remote.len == 0 || rv < 0) {
            return;
        }

    } else {
        socklen_t sl_tmp = sizeof(info->sa_local);
        if (sock->u.fd == INVALID_SOCKET) {
            return;
        }

        rv = getsockname(sock->u.fd, ni.local.name, &sl_tmp);
        n_salocal = sl_tmp;
        if (rv < 0) {
            return;
        }
        rv = getpeername(sock->u.fd, ni.remote.name, &sl_tmp);
        n_saremote = sl_tmp;
        if (rv < 0) {
            return;
        }
    }
    info->naddr = n_salocal;
}
Example #17
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;
}
Example #18
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;
}
Example #19
0
static void
E_schedule(lcbio_CTX *ctx)
{
    lcbio_TABLE *io = ctx->io;
    short which = 0;

    if (ctx->rdwant) {
        which |= LCB_READ_EVENT;
    }
    if (ctx->wwant || (ctx->output && ctx->output->rb.nbytes)) {
        which |= LCB_WRITE_EVENT;
    }

    if (!which) {
        deactivate_watcher(ctx);
        return;
    }

    IOT_V0EV(io).watch(IOT_ARG(io), CTX_FD(ctx), ctx->event, which, ctx, E_handler);
    ctx->evactive = 1;
}
Example #20
0
static void destroy_timer(lcb_io_opt_t io, void *timer) {
    lcbio_XSSL *xs = IOTSSL_FROM_IOPS(io);
    xs->orig->timer.destroy(IOT_ARG(xs->orig), timer);
}
Example #21
0
struct lcbio_CONNSTART *
lcbio_connect(lcbio_TABLE *iot, lcb_settings *settings, lcb_host_t *dest,
              uint32_t timeout, lcbio_CONNDONE_cb handler, void *arg)
{
    lcbio_SOCKET *s;
    lcbio_CONNSTART *ret;
    struct addrinfo hints;
    int rv;

    s = calloc(1, sizeof(*s));
    ret = calloc(1, sizeof(*ret));

    /** Initialize the socket first */
    s->io = iot;
    s->settings = settings;
    s->ctx = ret;
    s->refcount = 1;
    s->info = calloc(1, sizeof(*s->info));
    s->info->ep = *dest;
    lcbio_table_ref(s->io);
    lcb_settings_ref(s->settings);
    lcb_list_init(&s->protos);

    if (IOT_IS_EVENT(iot)) {
        s->u.fd = INVALID_SOCKET;
        ret->event = IOT_V0EV(iot).create(IOT_ARG(iot));
    }

    /** Initialize the connstart structure */
    ret->handler = handler;
    ret->arg = arg;
    ret->sock = s;
    ret->async = lcbio_timer_new(iot, ret, cs_handler);

    lcbio_timer_rearm(ret->async, timeout);
    lcb_log(LOGARGS(s, INFO), CSLOGFMT "Starting. Timeout=%uus", CSLOGID(s), timeout);

    /** Hostname lookup: */
    memset(&hints, 0, sizeof(hints));
    hints.ai_flags = AI_PASSIVE;
    hints.ai_socktype = SOCK_STREAM;
    if (settings->ipv6 == LCB_IPV6_DISABLED) {
        hints.ai_family = AF_INET;
    } else if (settings->ipv6 == LCB_IPV6_ONLY) {
        hints.ai_family = AF_INET6;
    } else {
        hints.ai_family = AF_UNSPEC;
    }

    if ((rv = getaddrinfo(dest->host, dest->port, &hints, &ret->ai_root))) {
        const char *errstr = rv != EAI_SYSTEM ? gai_strerror(rv) : "";
        lcb_log(LOGARGS(s, ERR), CSLOGFMT "Couldn't look up %s (%s) [EAI=%d]", CSLOGID(s), dest->host, errstr, rv);
        cs_state_signal(ret, CS_ERROR, LCB_UNKNOWN_HOST);
    } else {
        ret->ai = ret->ai_root;

        /** Figure out how to connect */
        if (IOT_IS_EVENT(iot)) {
            E_connect(-1, LCB_WRITE_EVENT, ret);
        } else {
            C_connect(ret);
        }
    }
    return ret;
}
Example #22
0
static void *create_timer(lcb_io_opt_t io) {
    lcbio_XSSL *xs = IOTSSL_FROM_IOPS(io);
    return xs->orig->timer.create(IOT_ARG(xs->orig));
}
Example #23
0
static int schedule_timer(lcb_io_opt_t io, void *timer, lcb_uint32_t us,
    void *arg, lcb_ioE_callback callback) {
    lcbio_XSSL *xs = IOTSSL_FROM_IOPS(io);
    return xs->orig->timer.schedule(IOT_ARG(xs->orig), timer, us, arg, callback);
}
Example #24
0
static int Cis_closed(lcb_io_opt_t io, lcb_sockdata_t *sd, int flags) {
    lcbio_XSSL *xs = IOTSSL_FROM_IOPS(io);
    return xs->orig->u_io.completion.is_closed(IOT_ARG(xs->orig), sd, flags);
}
Example #25
0
static int Eis_closed(lcb_io_opt_t io, lcb_socket_t sock, int flags) {
    lcbio_XSSL *xs = IOTSSL_FROM_IOPS(io);
    return xs->orig->u_io.v0.io.is_closed(IOT_ARG(xs->orig), sock, flags);
}
Example #26
0
static void cancel_timer(lcb_io_opt_t io, void *timer) {
    lcbio_XSSL *xs = IOTSSL_FROM_IOPS(io);
    xs->orig->timer.cancel(IOT_ARG(xs->orig), timer);
}
Example #27
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;
    }
}