FdEventHandlerPtr do_accept(int fd, int (*handler) (int, FdEventHandlerPtr, AcceptRequestPtr), void *data) { FdEventHandlerPtr event; int done; event = schedule_accept(fd, handler, data); if (event == NULL) { done = (*handler) (-ENOMEM, NULL, NULL); assert(done); } return event; }
FdEventHandlerPtr do_accept(int fd, int (*handler)(int, FdEventHandlerPtr, AcceptRequestPtr), void *data) { FdEventHandlerPtr event; int done; event = schedule_accept(fd, handler, data); if(event == NULL) { done = (*handler)(-ENOMEM, NULL, NULL); assert(done); } /* But don't invoke it now - this will delay accept if under load. */ return event; }
FdEventHandlerPtr create_listener(char *address, int port, int (*handler)(int, FdEventHandlerPtr, AcceptRequestPtr), void *data) { int fd, rc; int one = 1; int done; struct sockaddr_in addr; #ifdef HAVE_IPv6 int inet6 = 1; struct sockaddr_in6 addr6; #else int inet6 = 0; #endif if(inet6 && address) { struct in_addr buf; rc = inet_aton(address, &buf); if(rc == 1) inet6 = 0; } fd = -1; errno = EAFNOSUPPORT; #ifdef HAVE_IPv6 if(inet6) { fd = socket(PF_INET6, SOCK_STREAM, 0); } #endif if(fd < 0 && (errno == EPROTONOSUPPORT || errno == EAFNOSUPPORT)) { inet6 = 0; fd = socket(PF_INET, SOCK_STREAM, 0); } if(fd < 0) { done = (*handler)(-errno, NULL, NULL); assert(done); return NULL; } rc = setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, (char *)&one, sizeof(one)); if(rc < 0) do_log_error(L_WARN, errno, "Couldn't set SO_REUSEADDR"); if(inet6) { #ifdef HAVE_IPv6 rc = setV6only(fd, 0); if(rc < 0) /* Reportedly OpenBSD returns an error for that. So only log it as a debugging message. */ do_log_error(D_CLIENT_CONN, errno, "Couldn't reset IPV6_V6ONLY"); memset(&addr6, 0, sizeof(addr6)); rc = inet_pton(AF_INET6, address, &addr6.sin6_addr); if(rc != 1) { done = (*handler)(rc == 0 ? -ESYNTAX : -errno, NULL, NULL); assert(done); return NULL; } addr6.sin6_family = AF_INET6; addr6.sin6_port = htons(port); rc = bind(fd, (struct sockaddr*)&addr6, sizeof(addr6)); #else rc = -1; errno = EAFNOSUPPORT; #endif } else { memset(&addr, 0, sizeof(addr)); rc = inet_aton(address, &addr.sin_addr); if(rc != 1) { done = (*handler)(rc == 0 ? -ESYNTAX : -errno, NULL, NULL); assert(done); close(fd); return NULL; } addr.sin_family = AF_INET; addr.sin_port = htons(port); rc = bind(fd, (struct sockaddr*)&addr, sizeof(addr)); } if(rc < 0) { do_log_error(L_ERROR, errno, "Couldn't bind"); CLOSE(fd); done = (*handler)(-errno, NULL, NULL); assert(done); return NULL; } rc = setNonblocking(fd, 1); if(rc < 0) { do_log_error(L_ERROR, errno, "Couldn't set non blocking mode"); CLOSE(fd); done = (*handler)(-errno, NULL, NULL); assert(done); return NULL; } rc = listen(fd, 1024); if(rc < 0) { do_log_error(L_ERROR, errno, "Couldn't listen"); CLOSE(fd); done = (*handler)(-errno, NULL, NULL); assert(done); return NULL; } do_log(L_INFO, "Established listening socket on port %d.\n", port); return schedule_accept(fd, handler, data); }
FdEventHandlerPtr create_listener(char *address, int port, int (*handler) (int, FdEventHandlerPtr, AcceptRequestPtr), void *data) { int fd, rc; int one = 1; int done; struct sockaddr_in addr; int inet6 = 0; if (inet6 && address) { struct in_addr buf; rc = inet_aton(address, &buf); if (rc == 1) inet6 = 0; } fd = -1; errno = EAFNOSUPPORT; if (fd < 0 && (errno == EPROTONOSUPPORT || errno == EAFNOSUPPORT)) { inet6 = 0; fd = socket(PF_INET, SOCK_STREAM, 0); } if (fd < 0) { done = (*handler) (-errno, NULL, NULL); assert(done); return NULL; } rc = setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, (char *)&one, sizeof(one)); if (rc < 0) do_log_error(L_WARN, errno, "Couldn't set SO_REUSEADDR"); if (inet6) { rc = -1; errno = EAFNOSUPPORT; } else { memset(&addr, 0, sizeof(addr)); rc = inet_aton(address, &addr.sin_addr); if (rc != 1) { done = (*handler) (rc == 0 ? -ESYNTAX : -errno, NULL, NULL); assert(done); return NULL; } addr.sin_family = AF_INET; addr.sin_port = htons(port); rc = bind(fd, (struct sockaddr *)&addr, sizeof(addr)); } if (rc < 0) { do_log_error(L_ERROR, errno, "Couldn't bind"); CLOSE(fd); done = (*handler) (-errno, NULL, NULL); assert(done); return NULL; } rc = setNonblocking(fd, 1); if (rc < 0) { do_log_error(L_ERROR, errno, "Couldn't set non blocking mode"); CLOSE(fd); done = (*handler) (-errno, NULL, NULL); assert(done); return NULL; } rc = listen(fd, 32); if (rc < 0) { do_log_error(L_ERROR, errno, "Couldn't listen"); CLOSE(fd); done = (*handler) (-errno, NULL, NULL); assert(done); return NULL; } /* do_log(L_INFO, "Established listening socket on port %d.\n", port); */ return schedule_accept(fd, handler, data); }