tcpsock tcpattach(int fd, int listening) { if(listening == 0) { struct mill_tcpconn *conn = malloc(sizeof(struct mill_tcpconn)); if(!conn) { errno = ENOMEM; return NULL; } tcpconn_init(conn, fd); errno = 0; return (tcpsock)conn; } /* It's a listening socket. Find out the port it is listening on. */ ipaddr addr; socklen_t sz = sizeof(ipaddr); int rc = getsockname(fd, (struct sockaddr*)&addr, &sz); if(rc == -1) return NULL; struct mill_tcplistener *l = malloc(sizeof(struct mill_tcplistener)); if(!l) { errno = ENOMEM; return NULL; } l->sock.type = MILL_TCPLISTENER; l->fd = fd; l->port = mill_ipport(addr); errno = 0; return &l->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); struct mill_tcpconn *conn = malloc(sizeof(struct mill_tcpconn)); if(!conn) { close(as); errno = ENOMEM; return NULL; } tcpconn_init(conn, as); errno = 0; return (tcpsock)conn; } mill_assert(as == -1); if(errno != EAGAIN && errno != EWOULDBLOCK) return NULL; /* Wait till new connection is available. */ int rc = mill_fdwait(l->fd, FDW_IN, deadline); if(rc == 0) { errno = ETIMEDOUT; return NULL; } mill_assert(rc == FDW_IN); } }
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; fdclean(s); close(s); errno = err; return NULL; } if(err != 0) { fdclean(s); close(s); errno = err; return NULL; } } /* Create the object. */ struct mill_tcpconn *conn = malloc(sizeof(struct mill_tcpconn)); if(!conn) { fdclean(s); close(s); errno = ENOMEM; return NULL; } tcpconn_init(conn, s); errno = 0; return (tcpsock)conn; }