+ descriptor->constant_timeout = msec;
+ iohandler_log(IOLOG_DEBUG, "added timer descriptor (sec: %d; usec: %d)", timeout.tv_sec, timeout.tv_usec);
+ return descriptor;
+}
+
+static void iohandler_process_iostartup(struct IODescriptorStartup *iostartup) {
+ struct IODescriptor *iofd = iostartup->iofd;
+ struct IOLowlevelDescriptor *iold;
+ struct IOEvent callback_event;
+ struct sockaddr_in ip4;
+ struct sockaddr_in6 ip6;
+ int addr_family, sockfd, opt;
+
+ //open socket
+ if(iostartup->use_srcaddr)
+ iostartup->iptype = iostartup->use_srcaddr->type;
+ else if(iostartup->use_dstaddr)
+ iostartup->iptype = iostartup->use_dstaddr->type;
+
+ addr_family = ((iostartup->iptype & IODNS_RECORD_AAAA) ? AF_INET6 : AF_INET);
+
+ sockfd = socket(addr_family, SOCK_STREAM, 0);
+ if(!sockfd) {
+ callback_event.type = IOEVENT_SOCKET_ERROR;
+ goto iohandler_process_iostartup_fail;
+ }
+
+ //prevent SIGPIPE
+ #ifndef WIN32
+ #if defined(SO_NOSIGPIPE)
+ opt = 1;
+ setsockopt(sockfd, SOL_SOCKET, SO_NOSIGPIPE, (void *)&opt, sizeof(opt));
+ #else
+ signal(SIGPIPE, SIG_IGN);
+ #endif
+ #endif
+ //make sockfd unblocking
+ #if defined(F_GETFL)
+ opt = fcntl(sockfd, F_GETFL);
+ fcntl(sockfd, F_SETFL, opt|O_NONBLOCK);
+ opt = fcntl(sockfd, F_GETFD);
+ fcntl(sockfd, F_SETFD, opt|FD_CLOEXEC);
+ #endif
+
+ if(iostartup->listening) {
+ opt = 1;
+ setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR, (void *)&opt, sizeof(opt));
+ } else {
+ if((iostartup->iptype & IODNS_RECORD_AAAA)) {
+ struct sockaddr_in6 *ip6ptr = iostartup->use_srcaddr->address;
+ ip6ptr->sin6_family = addr_family;
+ ip6ptr->sin6_port = htons(iostartup->port);
+ } else {
+ struct sockaddr_in *ip4ptr = iostartup->use_srcaddr->address;
+ ip4ptr->sin_family = addr_family;
+ ip4ptr->sin_port = htons(iostartup->port);
+ }
+ }
+
+ // Bind Socket to IP
+ if(iostartup->listening || iostartup->use_srcaddr) {
+ if((iostartup->iptype & IODNS_RECORD_AAAA)) {
+ memset(&ip6, 0, sizeof(ip6));
+ if(iostartup->use_srcaddr) {
+ struct sockaddr_in6 *ip6ptr = iostartup->use_srcaddr->address;
+ ip6.sin6_addr = ip6ptr->sin6_addr;
+ } else
+ inet_pton(AF_INET6, "::1", &ip6.sin6_addr);
+ ip6.sin6_family = addr_family;
+ ip6.sin6_port = htons((iostartup->listening ? iostartup->port : 0));
+ opt = bind(sockfd, (struct sockaddr*)&ip6, sizeof(ip6));
+ } else {
+ memset(&ip6, 0, sizeof(ip6));
+ if(iostartup->use_srcaddr) {
+ struct sockaddr_in4 *ip4ptr = iostartup->use_srcaddr->address;
+ ip6.sin6_addr = ip4ptr->sin_addr;
+ } else
+ ip4.sin_addr = INADDR_ANY;
+ ip4.sin_family = addr_family;
+ ip4.sin_port = htons((iostartup->listening ? iostartup->port : 0));
+ opt = bind(sockfd, (struct sockaddr*)&ip4, sizeof(ip4));
+ }
+ if(!opt) {
+ callback_event.type = IOEVENT_BIND_ERROR;
+ goto iohandler_process_iostartup_fail;
+ }
+ }
+
+ iold = calloc(1, sizeof(*iold));
+ iold->fd = sockfd;
+ iold->flags = IOFLAGS_HAVE_IOFD | IOFLAGS_WANT_READ;
+ iold->data.iofd = iofd;
+
+ if(iostartup->listening) {
+ listen(sockfd, 1);
+ iofd->state = IO_LISTENING;
+ } else {
+ connect(sockfd, iostartup->use_dstaddr->address, iostartup->use_dstaddr->addresslen);
+ iofd->state = IO_CONNECTING;
+ }
+
+ iofd->fd.iold = iold;
+ iofd->flags = IOFDFLAGS_HAVE_IOLD;
+
+ iostartup->iofd = NULL;
+ iohandler_remove_iostartup(iostartup);
+ return;
+
+ iohandler_process_iostartup_fail:
+ if(sockfd)
+ close(sockfd);
+ callback_event.iofd = iostartup->iofd;
+ iostartup->iofd->flags |= IOFDFLAGS_FREE_LOCK;
+ iohandler_trigger_event(&callback_event);
+ iostartup->iofd->flags &= ~IOFDFLAGS_FREE_LOCK;
+ if(iostartup->iofd->flags & IOFDFLAGS_WANT_FREE)
+ iohandler_remove_iostartup(iostartup);
+ else
+ iohandler_close(iostartup->iofd);
+}
+
+static IODNS_CALLBACK(iohandler_dns_callback) {
+ struct IODNSQuery *query = event->query;
+ struct IODescriptorStartup *iostartup = query->data;
+ int trigger_dns_fail = 0;
+ iostartup->iodns = NULL;
+
+ switch((iostartup->flags & IOSTARTUP_LOOKUPS)) {
+ case IOSTARTUP_SRCLOOKUP:
+ if(event->type == IODNSEVENT_FAILED) {
+ trigger_dns_fail = 1;