int tcpconnect(const ipaddr *addr, int64_t deadline) { int err; /* Open a socket. */ int s = socket(ipfamily(addr), SOCK_STREAM, 0); if(dill_slow(s < 0)) return -1; tcptune(s); /* Connect to the remote endpoint. */ int rc = dsconnect(s, ipsockaddr(addr), iplen(addr), deadline); if(dill_slow(rc < 0)) return -1; /* Create the object. */ struct tcpconn *conn = tcpconn_create(); if(dill_slow(!conn)) {err = errno; goto error1;} conn->fd = s; conn->addr = *addr; /* Bind the object to a sock handle. */ int bs = bsock(tcpconn_type, conn, &tcpconn_vfptrs); if(dill_slow(bs < 0)) {err = errno; goto error2;} return bs; error2: tcpconn_destroy(conn); error1: rc = dsclose(s); dill_assert(rc == 0); errno = err; return -1; }
int tcpaccept(int s, int64_t deadline) { int err; struct tcplistener *lst = hdata(s, tcplistener_type); if(dill_slow(!lst)) return -1; /* Try to get new connection in a non-blocking way. */ ipaddr addr; socklen_t addrlen; int as = dsaccept(lst->fd, (struct sockaddr*)&addr, &addrlen, deadline); if(dill_slow(as < 0)) return -1; tcptune(as); /* Create the object. */ struct tcpconn *conn = tcpconn_create(); if(dill_slow(!conn)) {err = errno; goto error1;} conn->fd = as; conn->addr = addr; /* Bind the object to a handle. */ int hndl = bsock(tcpconn_type, conn, &tcpconn_vfptrs); if(dill_slow(hndl < 0)) {err = errno; goto error2;} return hndl; error2: tcpconn_destroy(conn); error1:; int rc = dsclose(s); dill_assert(rc == 0); errno = err; return -1; }
tcpsock tcpconnect(ipaddr addr, int64_t deadline) { /* Open a socket. */ int s = socket(mill_ipfamily(addr), SOCK_STREAM, 0); if(s == -1) return NULL; mill_tcptune(s); /* Connect to the remote endpoint. */ int rc = connect(s, (struct sockaddr*)&addr, mill_iplen(addr)); if(rc != 0) { mill_assert(rc == -1); if(errno != EINPROGRESS) return NULL; rc = fdwait(s, FDW_OUT, deadline); if(rc == 0) { errno = ETIMEDOUT; return NULL; } int err; socklen_t errsz = sizeof(err); rc = getsockopt(s, SOL_SOCKET, SO_ERROR, (void*)&err, &errsz); if(rc != 0) { err = errno; close(s); errno = err; return NULL; } if(err != 0) { close(s); errno = err; return NULL; } } /* Create the object. */ errno = 0; return &tcpconn_create(s)->sock; }
tcpsock tcpaccept(tcpsock s, int64_t deadline) { if(s->type != MILL_TCPLISTENER) mill_panic("trying to accept on a socket that isn't listening"); struct mill_tcplistener *l = (struct mill_tcplistener*)s; while(1) { /* Try to get new connection (non-blocking). */ int as = accept(l->fd, NULL, NULL); if (as >= 0) { mill_tcptune(as); errno = 0; return &tcpconn_create(as)->sock; } mill_assert(as == -1); if(errno != EAGAIN && errno != EWOULDBLOCK) return NULL; /* Wait till new connection is available. */ int rc = fdwait(l->fd, FDW_IN, deadline); if(rc == 0) { errno = ETIMEDOUT; return NULL; } mill_assert(rc == FDW_IN); } }