FdEventHandlerPtr do_connect(AtomPtr addr, int index, int port, int (*handler)(int, FdEventHandlerPtr, ConnectRequestPtr), void *data) { ConnectRequestRec request; FdEventHandlerPtr event; int done, fd, af; assert(addr->length > 0 && addr->string[0] == DNS_A); assert(addr->length % sizeof(HostAddressRec) == 1); if(index >= (addr->length - 1)/ sizeof(HostAddressRec)) index = 0; request.firstindex = index; request.port = port; request.handler = handler; request.data = data; again: af = addr->string[1 + index * sizeof(HostAddressRec)]; fd = serverSocket(af); request.fd = fd; request.af = af; request.addr = addr; request.index = index; if(fd < 0) { int n = (addr->length - 1) / sizeof(HostAddressRec); if(errno == EAFNOSUPPORT || errno == EPROTONOSUPPORT) { if((index + 1) % n != request.firstindex) { index = (index + 1) % n; goto again; } } do_log_error(L_ERROR, errno, "Couldn't create socket"); done = (*handler)(-errno, NULL, &request); assert(done); return NULL; } /* POLLIN is apparently needed on Windows */ event = registerFdEvent(fd, POLLIN | POLLOUT, do_scheduled_connect, sizeof(ConnectRequestRec), &request); if(event == NULL) { done = (*handler)(-ENOMEM, NULL, &request); assert(done); return NULL; } done = event->handler(0, event); if(done) { unregisterFdEvent(event); return NULL; } return event; }
int lingeringClose(int fd) { int rc; LingeringClosePtr l; rc = shutdown(fd, 1); if(rc < 0) { if(errno != ENOTCONN) { do_log_error(L_ERROR, errno, "Shutdown failed"); } else if(errno == EFAULT || errno == EBADF) { abort(); } CLOSE(fd); return 1; } l = malloc(sizeof(LingeringCloseRec)); if(l == NULL) goto fail; l->fd = fd; l->handler = NULL; l->timeout = NULL; l->timeout = scheduleTimeEvent(10, lingeringCloseTimeoutHandler, sizeof(LingeringClosePtr), &l); if(l->timeout == NULL) { free(l); goto fail; } l->handler = registerFdEvent(fd, POLLIN, lingeringCloseHandler, sizeof(LingeringClosePtr), &l); if(l->handler == NULL) { do_log(L_ERROR, "Couldn't schedule lingering close handler.\n"); /* But don't close -- the timeout will do its work. */ } return 1; fail: do_log(L_ERROR, "Couldn't schedule lingering close.\n"); CLOSE(fd); return 1; }
static int establishDnsSocket() { int rc; #ifdef HAVE_IPv6 int inet6 = (nameserverAddress.sa_family == AF_INET6); int pf = inet6 ? PF_INET6 : PF_INET; int sa_size = inet6 ? sizeof(struct sockaddr_in6) : sizeof(struct sockaddr_in); #else int pf = PF_INET; int sa_size = sizeof(struct sockaddr_in); #endif if(dnsSocket < 0) { assert(!dnsSocketHandler); dnsSocket = socket(pf, SOCK_DGRAM, 0); if(dnsSocket < 0) { do_log_error(L_ERROR, errno, "Couldn't create DNS socket"); return -errno; } rc = connect(dnsSocket, &nameserverAddress, sa_size); if(rc < 0) { CLOSE(dnsSocket); dnsSocket = -1; do_log_error(L_ERROR, errno, "Couldn't create DNS \"connection\""); return -errno; } } if(!dnsSocketHandler) { dnsSocketHandler = registerFdEvent(dnsSocket, POLLIN, dnsReplyHandler, 0, NULL); if(dnsSocketHandler == NULL) { do_log(L_ERROR, "Couldn't register DNS socket handler.\n"); CLOSE(dnsSocket); dnsSocket = -1; return -ENOMEM; } } return 1; }
FdEventHandlerPtr schedule_accept(int fd, int (*handler)(int, FdEventHandlerPtr, AcceptRequestPtr), void *data) { FdEventHandlerPtr event; AcceptRequestRec request; int done; request.fd = fd; request.handler = handler; request.data = data; event = registerFdEvent(fd, POLLOUT|POLLIN, do_scheduled_accept, sizeof(request), &request); if(!event) { done = (*handler)(-ENOMEM, NULL, NULL); assert(done); } return event; }