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; } } }
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); } }
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; } } }
/** 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; }
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; }
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; } }