From 22a8550caa95ea9da0bd1563c55a37a7050ae15c Mon Sep 17 00:00:00 2001 From: unknown Date: Fri, 4 Dec 2015 16:12:43 -0500 Subject: [PATCH] Bug fix in get_os_defaults, clean up code in winsock_event, add code to handle event handling differences in Winsock2 --- src/context.c | 24 +- src/stub.c | 47 +- src/util/winsock_event.c | 1162 +++++++++++++++++++------------------- src/util/winsock_event.h | 157 ++--- 4 files changed, 704 insertions(+), 686 deletions(-) diff --git a/src/context.c b/src/context.c index 5076a14a..83ae9c82 100644 --- a/src/context.c +++ b/src/context.c @@ -803,10 +803,9 @@ set_os_defaults_windows(struct getdns_context *context) hints.ai_addr = NULL; hints.ai_next = NULL; - //g FIXED_INFO *info; ULONG buflen = sizeof(*info); - IP_ADDR_STRING *ptr; + IP_ADDR_STRING *ptr = 0; info = (FIXED_INFO *)malloc(sizeof(FIXED_INFO)); if (info == NULL) @@ -821,7 +820,7 @@ set_os_defaults_windows(struct getdns_context *context) if (GetNetworkParams(info, &buflen) == NO_ERROR) { int retval = 0; - ptr = &(info->DnsServerList); + ptr = info->DnsServerList.Next; *domain = 0; while (ptr) { for (size_t i = 0; i < GETDNS_UPSTREAM_TRANSPORTS; i++) { @@ -843,7 +842,6 @@ set_os_defaults_windows(struct getdns_context *context) free(info); } - (void)getdns_list_get_length(context->suffix, &length); if (length == 0 && *domain != 0) { bindata.data = (uint8_t *)domain; @@ -994,7 +992,7 @@ getdns_context_create_with_extended_memory_functions( result->fchg_resolvconf = NULL; result->fchg_hosts = NULL; - //g resolv.conf does not exist on Windows, handle differently + // resolv.conf does not exist on Windows, handle differently #ifndef USE_WINSOCK if (set_from_os && (r = set_os_defaults(result))) goto error; @@ -2358,18 +2356,24 @@ _getdns_context_prepare_for_resolution(struct getdns_context *context, /* Create client context, use TLS v1.2 only for now */ context->tls_ctx = SSL_CTX_new(TLSv1_2_client_method()); if (context->tls_ctx == NULL) - printf("ERROR! Bad TLS context!"); - //g return GETDNS_RETURN_BAD_CONTEXT; +#ifndef USE_WINSOCK + return GETDNS_RETURN_BAD_CONTEXT; +#else + printf("Warning! Bad TLS context, check openssl version on Windows!\n");; +#endif /* Be strict and only use the cipher suites recommended in RFC7525 Unless we later fallback to opportunistic. */ const char* const PREFERRED_CIPHERS = "EECDH+aRSA+AESGCM:EECDH+aECDSA+AESGCM:EDH+aRSA+AESGCM"; - if (!SSL_CTX_set_cipher_list(context->tls_ctx, PREFERRED_CIPHERS)) + if (!SSL_CTX_set_cipher_list(context->tls_ctx, PREFERRED_CIPHERS)) { return GETDNS_RETURN_BAD_CONTEXT; - if (!SSL_CTX_set_default_verify_paths(context->tls_ctx)) + } + if (!SSL_CTX_set_default_verify_paths(context->tls_ctx)) { return GETDNS_RETURN_BAD_CONTEXT; + } #else - if (tls_only_is_in_transports_list(context) == 1) + if (tls_only_is_in_transports_list(context) == 1) { return GETDNS_RETURN_BAD_CONTEXT; + } /* A null tls_ctx will make TLS fail and fallback to the other transports will kick-in.*/ #endif diff --git a/src/stub.c b/src/stub.c index 8072d5da..96265c87 100644 --- a/src/stub.c +++ b/src/stub.c @@ -50,6 +50,7 @@ #define EINPROGRESS 112 #define EWOULDBLOCK 140 typedef u_short sa_family_t; +#include "util/winsock_event.h" #endif #define STUB_OUT_OF_OPTIONS -5 /* upstream options exceeded MAXIMUM_UPSTREAM_OPTION_SPACE */ @@ -623,7 +624,7 @@ stub_tls_timeout_cb(void *userarg) /****************************/ static int -stub_tcp_read(int fd, getdns_tcp_state *tcp, struct mem_funcs *mf) +stub_tcp_read(int fd, getdns_tcp_state *tcp, struct mem_funcs *mf, getdns_eventloop_event* event) { ssize_t read; uint8_t *buf; @@ -640,10 +641,24 @@ stub_tcp_read(int fd, getdns_tcp_state *tcp, struct mem_funcs *mf) } read = recv(fd, tcp->read_pos, tcp->to_read, 0); if (read == -1) { +#ifdef USE_WINSOCK + printf("read (in tcp ) %s\n", + wsa_strerror(WSAGetLastError())); + if (WSAGetLastError() == WSAECONNRESET) + return STUB_TCP_AGAIN; + if (WSAGetLastError() == WSAEINPROGRESS) + return STUB_TCP_AGAIN; + if (WSAGetLastError() == WSAEWOULDBLOCK) { + winsock_tcp_wouldblock(event, EV_READ); + return STUB_TCP_AGAIN; + } + +#else if (errno == EAGAIN || errno == EWOULDBLOCK) return STUB_TCP_AGAIN; else return STUB_TCP_ERROR; +#endif } else if (read == 0) { /* Remote end closed the socket */ /* TODO: Try to reconnect */ @@ -747,19 +762,19 @@ stub_tcp_write(int fd, getdns_tcp_state *tcp, getdns_network_req *netreq) upstream). We must let the handshake complete since non-blocking. */ errno == EINPROGRESS)) || written < pkt_len + 2) { -#else - -#ifdef USE_WINSOCK - written = sendto(fd, netreq->query - 2, pkt_len + 2, - 0, (struct sockaddr *)&(netreq->upstream->addr), - netreq->upstream->addr_len); - -#else - written = write(fd, netreq->query - 2, pkt_len + 2); -#endif - if ((written == -1 && (errno == EAGAIN || - errno == EWOULDBLOCK)) || - written < pkt_len + 2) { +#else + +#ifdef USE_WINSOCK + written = sendto(fd, netreq->query - 2, pkt_len + 2, + 0, (struct sockaddr *)&(netreq->upstream->addr), + netreq->upstream->addr_len); + +#else + written = write(fd, netreq->query - 2, pkt_len + 2); +#endif + if ((written == -1 && (errno == EAGAIN || + errno == EWOULDBLOCK)) || + written < pkt_len + 2) { #endif /* We couldn't write the whole packet. * We have to return with STUB_TCP_AGAIN. @@ -1359,7 +1374,7 @@ stub_tcp_read_cb(void *userarg) int q; switch ((q = stub_tcp_read(netreq->fd, &netreq->tcp, - &dnsreq->context->mf))) { + &dnsreq->context->mf, &netreq->event))) { case STUB_TCP_AGAIN: return; @@ -1437,7 +1452,7 @@ upstream_read_cb(void *userarg) &upstream->upstreams->mf); else q = stub_tcp_read(upstream->fd, &upstream->tcp, - &upstream->upstreams->mf); + &upstream->upstreams->mf, &netreq->event); switch (q) { case STUB_TCP_AGAIN: diff --git a/src/util/winsock_event.c b/src/util/winsock_event.c index f29c9f32..9bb78cf9 100644 --- a/src/util/winsock_event.c +++ b/src/util/winsock_event.c @@ -36,10 +36,11 @@ * \file * Implementation of the getdns WinSock2 API event notification handler * for the getdns Windows port. + * Code is originally from the Unbound source for Windows. */ #include "config.h" -#ifdef USE_WINSOCK +#ifdef USE_WINSOCK // only included for Windows builds #include #ifdef HAVE_TIME_H #include @@ -55,117 +56,118 @@ void log_err(const char *format, ...) { - va_list args; - va_start(args, format); - fprintf(stderr, "error", format, args); - va_end(args); + va_list args; + va_start(args, format); + fprintf(stderr, "error", format, args); + va_end(args); } + char* wsa_strerror(DWORD err) { - static char unknown[32]; + static char unknown[32]; - switch (err) { - case WSA_INVALID_HANDLE: return "Specified event object handle is invalid."; - case WSA_NOT_ENOUGH_MEMORY: return "Insufficient memory available."; - case WSA_INVALID_PARAMETER: return "One or more parameters are invalid."; - case WSA_OPERATION_ABORTED: return "Overlapped operation aborted."; - case WSA_IO_INCOMPLETE: return "Overlapped I/O event object not in signaled state."; - case WSA_IO_PENDING: return "Overlapped operations will complete later."; - case WSAEINTR: return "Interrupted function call."; - case WSAEBADF: return "File handle is not valid."; - case WSAEACCES: return "Permission denied."; - case WSAEFAULT: return "Bad address."; - case WSAEINVAL: return "Invalid argument."; - case WSAEMFILE: return "Too many open files."; - case WSAEWOULDBLOCK: return "Resource temporarily unavailable."; - case WSAEINPROGRESS: return "Operation now in progress."; - case WSAEALREADY: return "Operation already in progress."; - case WSAENOTSOCK: return "Socket operation on nonsocket."; - case WSAEDESTADDRREQ: return "Destination address required."; - case WSAEMSGSIZE: return "Message too long."; - case WSAEPROTOTYPE: return "Protocol wrong type for socket."; - case WSAENOPROTOOPT: return "Bad protocol option."; - case WSAEPROTONOSUPPORT: return "Protocol not supported."; - case WSAESOCKTNOSUPPORT: return "Socket type not supported."; - case WSAEOPNOTSUPP: return "Operation not supported."; - case WSAEPFNOSUPPORT: return "Protocol family not supported."; - case WSAEAFNOSUPPORT: return "Address family not supported by protocol family."; - case WSAEADDRINUSE: return "Address already in use."; - case WSAEADDRNOTAVAIL: return "Cannot assign requested address."; - case WSAENETDOWN: return "Network is down."; - case WSAENETUNREACH: return "Network is unreachable."; - case WSAENETRESET: return "Network dropped connection on reset."; - case WSAECONNABORTED: return "Software caused connection abort."; - case WSAECONNRESET: return "Connection reset by peer."; - case WSAENOBUFS: return "No buffer space available."; - case WSAEISCONN: return "Socket is already connected."; - case WSAENOTCONN: return "Socket is not connected."; - case WSAESHUTDOWN: return "Cannot send after socket shutdown."; - case WSAETOOMANYREFS: return "Too many references."; - case WSAETIMEDOUT: return "Connection timed out."; - case WSAECONNREFUSED: return "Connection refused."; - case WSAELOOP: return "Cannot translate name."; - case WSAENAMETOOLONG: return "Name too long."; - case WSAEHOSTDOWN: return "Host is down."; - case WSAEHOSTUNREACH: return "No route to host."; - case WSAENOTEMPTY: return "Directory not empty."; - case WSAEPROCLIM: return "Too many processes."; - case WSAEUSERS: return "User quota exceeded."; - case WSAEDQUOT: return "Disk quota exceeded."; - case WSAESTALE: return "Stale file handle reference."; - case WSAEREMOTE: return "Item is remote."; - case WSASYSNOTREADY: return "Network subsystem is unavailable."; - case WSAVERNOTSUPPORTED: return "Winsock.dll version out of range."; - case WSANOTINITIALISED: return "Successful WSAStartup not yet performed."; - case WSAEDISCON: return "Graceful shutdown in progress."; - case WSAENOMORE: return "No more results."; - case WSAECANCELLED: return "Call has been canceled."; - case WSAEINVALIDPROCTABLE: return "Procedure call table is invalid."; - case WSAEINVALIDPROVIDER: return "Service provider is invalid."; - case WSAEPROVIDERFAILEDINIT: return "Service provider failed to initialize."; - case WSASYSCALLFAILURE: return "System call failure."; - case WSASERVICE_NOT_FOUND: return "Service not found."; - case WSATYPE_NOT_FOUND: return "Class type not found."; - case WSA_E_NO_MORE: return "No more results."; - case WSA_E_CANCELLED: return "Call was canceled."; - case WSAEREFUSED: return "Database query was refused."; - case WSAHOST_NOT_FOUND: return "Host not found."; - case WSATRY_AGAIN: return "Nonauthoritative host not found."; - case WSANO_RECOVERY: return "This is a nonrecoverable error."; - case WSANO_DATA: return "Valid name, no data record of requested type."; - case WSA_QOS_RECEIVERS: return "QOS receivers."; - case WSA_QOS_SENDERS: return "QOS senders."; - case WSA_QOS_NO_SENDERS: return "No QOS senders."; - case WSA_QOS_NO_RECEIVERS: return "QOS no receivers."; - case WSA_QOS_REQUEST_CONFIRMED: return "QOS request confirmed."; - case WSA_QOS_ADMISSION_FAILURE: return "QOS admission error."; - case WSA_QOS_POLICY_FAILURE: return "QOS policy failure."; - case WSA_QOS_BAD_STYLE: return "QOS bad style."; - case WSA_QOS_BAD_OBJECT: return "QOS bad object."; - case WSA_QOS_TRAFFIC_CTRL_ERROR: return "QOS traffic control error."; - case WSA_QOS_GENERIC_ERROR: return "QOS generic error."; - case WSA_QOS_ESERVICETYPE: return "QOS service type error."; - case WSA_QOS_EFLOWSPEC: return "QOS flowspec error."; - case WSA_QOS_EPROVSPECBUF: return "Invalid QOS provider buffer."; - case WSA_QOS_EFILTERSTYLE: return "Invalid QOS filter style."; - case WSA_QOS_EFILTERTYPE: return "Invalid QOS filter type."; - case WSA_QOS_EFILTERCOUNT: return "Incorrect QOS filter count."; - case WSA_QOS_EOBJLENGTH: return "Invalid QOS object length."; - case WSA_QOS_EFLOWCOUNT: return "Incorrect QOS flow count."; - /*case WSA_QOS_EUNKOWNPSOBJ: return "Unrecognized QOS object.";*/ - case WSA_QOS_EPOLICYOBJ: return "Invalid QOS policy object."; - case WSA_QOS_EFLOWDESC: return "Invalid QOS flow descriptor."; - case WSA_QOS_EPSFLOWSPEC: return "Invalid QOS provider-specific flowspec."; - case WSA_QOS_EPSFILTERSPEC: return "Invalid QOS provider-specific filterspec."; - case WSA_QOS_ESDMODEOBJ: return "Invalid QOS shape discard mode object."; - case WSA_QOS_ESHAPERATEOBJ: return "Invalid QOS shaping rate object."; - case WSA_QOS_RESERVED_PETYPE: return "Reserved policy QOS element type."; - default: - snprintf(unknown, sizeof(unknown), - "unknown WSA error code %d", (int)err); - return unknown; - } + switch (err) { + case WSA_INVALID_HANDLE: return "Specified event object handle is invalid."; + case WSA_NOT_ENOUGH_MEMORY: return "Insufficient memory available."; + case WSA_INVALID_PARAMETER: return "One or more parameters are invalid."; + case WSA_OPERATION_ABORTED: return "Overlapped operation aborted."; + case WSA_IO_INCOMPLETE: return "Overlapped I/O event object not in signaled state."; + case WSA_IO_PENDING: return "Overlapped operations will complete later."; + case WSAEINTR: return "Interrupted function call."; + case WSAEBADF: return "File handle is not valid."; + case WSAEACCES: return "Permission denied."; + case WSAEFAULT: return "Bad address."; + case WSAEINVAL: return "Invalid argument."; + case WSAEMFILE: return "Too many open files."; + case WSAEWOULDBLOCK: return "Resource temporarily unavailable."; + case WSAEINPROGRESS: return "Operation now in progress."; + case WSAEALREADY: return "Operation already in progress."; + case WSAENOTSOCK: return "Socket operation on nonsocket."; + case WSAEDESTADDRREQ: return "Destination address required."; + case WSAEMSGSIZE: return "Message too long."; + case WSAEPROTOTYPE: return "Protocol wrong type for socket."; + case WSAENOPROTOOPT: return "Bad protocol option."; + case WSAEPROTONOSUPPORT: return "Protocol not supported."; + case WSAESOCKTNOSUPPORT: return "Socket type not supported."; + case WSAEOPNOTSUPP: return "Operation not supported."; + case WSAEPFNOSUPPORT: return "Protocol family not supported."; + case WSAEAFNOSUPPORT: return "Address family not supported by protocol family."; + case WSAEADDRINUSE: return "Address already in use."; + case WSAEADDRNOTAVAIL: return "Cannot assign requested address."; + case WSAENETDOWN: return "Network is down."; + case WSAENETUNREACH: return "Network is unreachable."; + case WSAENETRESET: return "Network dropped connection on reset."; + case WSAECONNABORTED: return "Software caused connection abort."; + case WSAECONNRESET: return "Connection reset by peer."; + case WSAENOBUFS: return "No buffer space available."; + case WSAEISCONN: return "Socket is already connected."; + case WSAENOTCONN: return "Socket is not connected."; + case WSAESHUTDOWN: return "Cannot send after socket shutdown."; + case WSAETOOMANYREFS: return "Too many references."; + case WSAETIMEDOUT: return "Connection timed out."; + case WSAECONNREFUSED: return "Connection refused."; + case WSAELOOP: return "Cannot translate name."; + case WSAENAMETOOLONG: return "Name too long."; + case WSAEHOSTDOWN: return "Host is down."; + case WSAEHOSTUNREACH: return "No route to host."; + case WSAENOTEMPTY: return "Directory not empty."; + case WSAEPROCLIM: return "Too many processes."; + case WSAEUSERS: return "User quota exceeded."; + case WSAEDQUOT: return "Disk quota exceeded."; + case WSAESTALE: return "Stale file handle reference."; + case WSAEREMOTE: return "Item is remote."; + case WSASYSNOTREADY: return "Network subsystem is unavailable."; + case WSAVERNOTSUPPORTED: return "Winsock.dll version out of range."; + case WSANOTINITIALISED: return "Successful WSAStartup not yet performed."; + case WSAEDISCON: return "Graceful shutdown in progress."; + case WSAENOMORE: return "No more results."; + case WSAECANCELLED: return "Call has been canceled."; + case WSAEINVALIDPROCTABLE: return "Procedure call table is invalid."; + case WSAEINVALIDPROVIDER: return "Service provider is invalid."; + case WSAEPROVIDERFAILEDINIT: return "Service provider failed to initialize."; + case WSASYSCALLFAILURE: return "System call failure."; + case WSASERVICE_NOT_FOUND: return "Service not found."; + case WSATYPE_NOT_FOUND: return "Class type not found."; + case WSA_E_NO_MORE: return "No more results."; + case WSA_E_CANCELLED: return "Call was canceled."; + case WSAEREFUSED: return "Database query was refused."; + case WSAHOST_NOT_FOUND: return "Host not found."; + case WSATRY_AGAIN: return "Nonauthoritative host not found."; + case WSANO_RECOVERY: return "This is a nonrecoverable error."; + case WSANO_DATA: return "Valid name, no data record of requested type."; + case WSA_QOS_RECEIVERS: return "QOS receivers."; + case WSA_QOS_SENDERS: return "QOS senders."; + case WSA_QOS_NO_SENDERS: return "No QOS senders."; + case WSA_QOS_NO_RECEIVERS: return "QOS no receivers."; + case WSA_QOS_REQUEST_CONFIRMED: return "QOS request confirmed."; + case WSA_QOS_ADMISSION_FAILURE: return "QOS admission error."; + case WSA_QOS_POLICY_FAILURE: return "QOS policy failure."; + case WSA_QOS_BAD_STYLE: return "QOS bad style."; + case WSA_QOS_BAD_OBJECT: return "QOS bad object."; + case WSA_QOS_TRAFFIC_CTRL_ERROR: return "QOS traffic control error."; + case WSA_QOS_GENERIC_ERROR: return "QOS generic error."; + case WSA_QOS_ESERVICETYPE: return "QOS service type error."; + case WSA_QOS_EFLOWSPEC: return "QOS flowspec error."; + case WSA_QOS_EPROVSPECBUF: return "Invalid QOS provider buffer."; + case WSA_QOS_EFILTERSTYLE: return "Invalid QOS filter style."; + case WSA_QOS_EFILTERTYPE: return "Invalid QOS filter type."; + case WSA_QOS_EFILTERCOUNT: return "Incorrect QOS filter count."; + case WSA_QOS_EOBJLENGTH: return "Invalid QOS object length."; + case WSA_QOS_EFLOWCOUNT: return "Incorrect QOS flow count."; + /*case WSA_QOS_EUNKOWNPSOBJ: return "Unrecognized QOS object.";*/ + case WSA_QOS_EPOLICYOBJ: return "Invalid QOS policy object."; + case WSA_QOS_EFLOWDESC: return "Invalid QOS flow descriptor."; + case WSA_QOS_EPSFLOWSPEC: return "Invalid QOS provider-specific flowspec."; + case WSA_QOS_EPSFILTERSPEC: return "Invalid QOS provider-specific filterspec."; + case WSA_QOS_ESDMODEOBJ: return "Invalid QOS shape discard mode object."; + case WSA_QOS_ESHAPERATEOBJ: return "Invalid QOS shaping rate object."; + case WSA_QOS_RESERVED_PETYPE: return "Reserved policy QOS element type."; + default: + snprintf(unknown, sizeof(unknown), + "unknown WSA error code %d", (int)err); + return unknown; + } } int _getdns_mini_ev_cmp(const void* a, const void* b) @@ -184,7 +186,7 @@ int _getdns_mini_ev_cmp(const void* a, const void* b) return -1; if(e > f) return 1; - return 0; + return 0; } /** set time */ @@ -200,7 +202,7 @@ settime(struct _getdns_event_base* base) return 0; } -#ifdef UNBOUND_DEBUG +#ifdef WINSOCK_DEBUG /** * Find a fd in the list of items. * Note that not all items have a fd associated (those are -1). @@ -212,12 +214,12 @@ settime(struct _getdns_event_base* base) static int find_fd(struct _getdns_event_base* base, int fd) { - int i; - for(i=0; imax; i++) { - if(base->items[i]->ev_fd == fd) - return i; - } - return -1; + int i; + for(i=0; imax; i++) { + if(base->items[i]->ev_fd == fd) + return i; + } + return -1; } #endif @@ -225,61 +227,61 @@ find_fd(struct _getdns_event_base* base, int fd) static void zero_waitfor(WSAEVENT waitfor[], WSAEVENT x) { - int i; - for(i=0; itime_secs = time_secs; - base->time_tv = time_tv; - if(settime(base) < 0) { + struct _getdns_event_base* base = (struct _getdns_event_base*)malloc( + sizeof(struct _getdns_event_base)); + if(!base) + return NULL; + memset(base, 0, sizeof(*base)); + base->time_secs = time_secs; + base->time_tv = time_tv; + if(settime(base) < 0) { + _getdns_event_base_free(base); + return NULL; + } + base->items = (struct _getdns_event**)calloc(WSK_MAX_ITEMS, + sizeof(struct _getdns_event*)); + if(!base->items) { _getdns_event_base_free(base); return NULL; - } - base->items = (struct _getdns_event**)calloc(WSK_MAX_ITEMS, - sizeof(struct _getdns_event*)); - if(!base->items) { - _getdns_event_base_free(base); + } + base->cap = WSK_MAX_ITEMS; + base->max = 0; + base->times = _getdns_rbtree_create(_getdns_mini_ev_cmp); + if(!base->times) { + _getdns_event_base_free(base); + return NULL; + } + base->signals = (struct _getdns_event**)calloc(MAX_SIG, + sizeof(struct _getdns_event*)); + if(!base->signals) { + _getdns_event_base_free(base); return NULL; - } - base->cap = WSK_MAX_ITEMS; - base->max = 0; - base->times = _getdns_rbtree_create(_getdns_mini_ev_cmp); - if(!base->times) { - _getdns_event_base_free(base); - return NULL; - } - base->signals = (struct _getdns_event**)calloc(MAX_SIG, sizeof(struct _getdns_event*)); - if(!base->signals) { - _getdns_event_base_free(base); - return NULL; - } - base->tcp_stickies = 0; - base->tcp_reinvigorated = 0; - //verbose(VERB_CLIENT, "winsock_event inited"); - return base; + } + base->tcp_stickies = 0; + base->tcp_reinvigorated = 0; + + return base; } const char *_getdns_event_get_version(void) { - return "winsock-event-"PACKAGE_VERSION; + return "winsock-event-"PACKAGE_VERSION; } const char *_getdns_event_get_method(void) { - return "WSAWaitForMultipleEvents"; + return "WSAWaitForMultipleEvents"; } - -//gowri remove static + /** call timeouts handlers, and return how long to wait for next one or -1 */ void _getdns_handle_timeouts(struct _getdns_event_base* base, struct timeval* now, struct timeval* wait) @@ -288,352 +290,347 @@ void _getdns_handle_timeouts(struct _getdns_event_base* base, struct timeval* no #ifndef S_SPLINT_S wait->tv_sec = (time_t)-1; #endif - //verbose(VERB_CLIENT, "winsock_event handle_timeouts"); - while((_getdns_rbnode_t*)(p = (struct _getdns_event*)_getdns_rbtree_first(base->times)) + while((_getdns_rbnode_t*)(p = (struct _getdns_event*)_getdns_rbtree_first(base->times)) !=RBTREE_NULL) { #ifndef S_SPLINT_S - if(p->ev_timeout.tv_sec > now->tv_sec || + if(p->ev_timeout.tv_sec > now->tv_sec || (p->ev_timeout.tv_sec==now->tv_sec && p->ev_timeout.tv_usec > now->tv_usec)) { - /* there is a next larger timeout. wait for it */ - wait->tv_sec = p->ev_timeout.tv_sec - now->tv_sec; - if(now->tv_usec > p->ev_timeout.tv_usec) { - wait->tv_sec--; - wait->tv_usec = 1000000 - (now->tv_usec - - p->ev_timeout.tv_usec); - } else { - wait->tv_usec = p->ev_timeout.tv_usec - - now->tv_usec; - } - //verbose(VERB_CLIENT, "winsock_event wait=" ARG_LL "d.%6.6d", - // (long long)wait->tv_sec, (int)wait->tv_usec); - return; - } -#endif - /* event times out, remove it */ - (void)_getdns_rbtree_delete(base->times, p); - p->ev_events &= ~EV_TIMEOUT; - fptr_ok(fptr_whitelist_event(p->ev_callback)); - (*p->ev_callback)(p->ev_fd, EV_TIMEOUT, p->ev_arg); + /* there is a next larger timeout. wait for it */ + wait->tv_sec = p->ev_timeout.tv_sec - now->tv_sec; + if(now->tv_usec > p->ev_timeout.tv_usec) { + wait->tv_sec--; + wait->tv_usec = 1000000 - (now->tv_usec - + p->ev_timeout.tv_usec); + } else { + wait->tv_usec = p->ev_timeout.tv_usec + - now->tv_usec; } - //verbose(VERB_CLIENT, "winsock_event wait=(-1)"); + return; + } +#endif + /* event times out, remove it */ + (void)_getdns_rbtree_delete(base->times, p); + p->ev_events &= ~EV_TIMEOUT; + fptr_ok(fptr_whitelist_event(p->ev_callback)); + (*p->ev_callback)(p->ev_fd, EV_TIMEOUT, p->ev_arg); + } } /** handle is_signal events and see if signalled */ static void _getdns_handle_signal(struct _getdns_event* ev) { - printf("In _getdns_handle_signal\n"); - DWORD ret; - //log_assert(ev->is_signal && ev->hEvent); - /* see if the event is signalled */ - ret = WSAWaitForMultipleEvents(1, &ev->hEvent, 0 /* any object */, - 0 /* return immediately */, 0 /* not alertable for IOcomple*/); - if(ret == WSA_WAIT_IO_COMPLETION || ret == WSA_WAIT_FAILED) { - log_err("getdns: WSAWaitForMultipleEvents(signal) failed: %s", - wsa_strerror(WSAGetLastError())); - return; - } - if(ret == WSA_WAIT_TIMEOUT) { - /* not signalled */ - return; - } + printf("In _getdns_handle_signal\n"); + DWORD ret; + //log_assert(ev->is_signal && ev->hEvent); + /* see if the event is signalled */ + ret = WSAWaitForMultipleEvents(1, &ev->hEvent, 0 /* any object */, + 0 /* return immediately */, 0 /* not alertable for IOcomple*/); + if(ret == WSA_WAIT_IO_COMPLETION || ret == WSA_WAIT_FAILED) { + log_err("getdns: WSAWaitForMultipleEvents(signal) failed: %s", + wsa_strerror(WSAGetLastError())); + return; + } + if(ret == WSA_WAIT_TIMEOUT) { + /* not signalled */ + return; + } - /* reset the signal */ - if(!WSAResetEvent(ev->hEvent)) - log_err("getdns: WSAResetEvent failed: %s", - wsa_strerror(WSAGetLastError())); - /* do the callback (which may set the signal again) */ - fptr_ok(fptr_whitelist_event(ev->ev_callback)); - (*ev->ev_callback)(ev->ev_fd, ev->ev_events, ev->ev_arg); + /* reset the signal */ + if(!WSAResetEvent(ev->hEvent)) + log_err("getdns: WSAResetEvent failed: %s", + wsa_strerror(WSAGetLastError())); + /* do the callback (which may set the signal again) */ + fptr_ok(fptr_whitelist_event(ev->ev_callback)); + (*ev->ev_callback)(ev->ev_fd, ev->ev_events, ev->ev_arg); } /** call select and callbacks for that */ int _getdns_handle_select(struct _getdns_event_base* base, struct timeval* wait) { - DWORD timeout = 0; /* in milliseconds */ - DWORD ret; - WSANETWORKEVENTS netev; - struct _getdns_event* eventlist[WSK_MAX_ITEMS]; - int i, numwait = 0, startidx = 0, was_timeout = 0; - int newstickies = 0; - struct timeval nultm; + DWORD timeout = 0; /* in milliseconds */ + DWORD ret; + WSANETWORKEVENTS netev; + struct _getdns_event* eventlist[WSK_MAX_ITEMS]; + int i, numwait = 0, startidx = 0, was_timeout = 0; + int newstickies = 0; + struct timeval nultm; #ifndef S_SPLINT_S - if(wait->tv_sec==(time_t)-1) - wait = NULL; - if (wait) - // timeout = 10 + wait->tv_usec / 1000; - timeout = wait->tv_sec * 1000 + wait->tv_usec / 1000; - if(base->tcp_stickies) { - wait = &nultm; - nultm.tv_sec = 0; - nultm.tv_usec = 0; - timeout = 0; /* no waiting, we have sticky events */ - } + if(wait->tv_sec==(time_t)-1) + wait = NULL; + if (wait) + // timeout = 10 + wait->tv_usec / 1000; + timeout = wait->tv_sec * 1000 + wait->tv_usec / 1000; + if(base->tcp_stickies) { + wait = &nultm; + nultm.tv_sec = 0; + nultm.tv_usec = 0; + timeout = 0; /* no waiting, we have sticky events */ + } #endif - /* prepare event array */ - for(i=0; imax; i++) { - if(base->items[i]->ev_fd == -1 && !base->items[i]->is_signal) - continue; /* skip timer only events */ - eventlist[numwait] = base->items[i]; - base->waitfor[numwait++] = base->items[i]->hEvent; - printf("winsock_event bmax=%d numwait=%d wait=%x " - "timeout=%d hEvent %d\n", base->max, numwait, (int)wait, (int)timeout, base->items[i]->hEvent); - if (numwait == WSK_MAX_ITEMS) - break; /* sanity check */ - } - //log_assert(numwait <= WSA_MAXIMUM_WAIT_EVENTS); + /* prepare event array */ + for(i=0; imax; i++) { + if(base->items[i]->ev_fd == -1 && !base->items[i]->is_signal) + continue; /* skip timer only events */ + eventlist[numwait] = base->items[i]; + base->waitfor[numwait++] = base->items[i]->hEvent; + printf("winsock_event bmax=%d numwait=%d wait=%x " + "timeout=%d hEvent %d\n", base->max, numwait, (int)wait, + (int)timeout, base->items[i]->hEvent); + if (numwait == WSK_MAX_ITEMS) + break; /* sanity check */ + } + //log_assert(numwait <= WSA_MAXIMUM_WAIT_EVENTS); - /* do the wait */ - if(numwait == 0) { - /* WSAWaitFor.. doesn't like 0 event objects */ - if(wait) { - Sleep(timeout); - } - was_timeout = 1; - } - else { - //gv: do not schedule udp write - for (i = 0; imax; i++) { - if (!base->items[i]->is_tcp && base->items[i]->ev_events&EV_WRITE) { - //gprintf("skip UDP sched\n"); - (*eventlist[i]->ev_callback)(eventlist[i]->ev_fd, - EV_WRITE & eventlist[i]->ev_events, - eventlist[i]->ev_arg); - return 0; - } - } - //gprintf("before wait %d\n", base->items[0]->ev_events); - ret = WSAWaitForMultipleEvents(numwait, base->waitfor, - 0 /* do not wait for all, just one will do */, - wait?timeout:WSA_INFINITE, - 0); /* we are not alertable (IO completion events) */ - //gprintf("after wait %d %d\n", ret, numwait); - if(ret == WSA_WAIT_IO_COMPLETION) { - //printf("getdns: WSAWaitForMultipleEvents failed: WSA_WAIT_IO_COMPLETION"); - return -1; - } else if(ret == WSA_WAIT_FAILED) { - //printf("getdns: WSAWaitForMultipleEvents failed: %s", - // wsa_strerror(WSAGetLastError())); - return -1; - } else if(ret == WSA_WAIT_TIMEOUT) { - //printf("timeout\n"); - was_timeout = 1; - } else - startidx = ret - WSA_WAIT_EVENT_0; - } - ////verbose(VERB_CLIENT, "winsock_event wake was_timeout=%d startidx=%d", - // was_timeout, startidx); + /* do the wait */ + if(numwait == 0) { + /* WSAWaitFor.. doesn't like 0 event objects */ + if(wait) { + Sleep(timeout); + } + was_timeout = 1; + } + else { + //gv: do not schedule udp write + for (i = 0; imax; i++) { + if (!base->items[i]->is_tcp && base->items[i]->ev_events&EV_WRITE) { + printf("skip UDP sched\n"); + (*eventlist[i]->ev_callback)(eventlist[i]->ev_fd, + EV_WRITE & eventlist[i]->ev_events, + eventlist[i]->ev_arg); + return 0; + } + } + printf("before wait %d\n", base->items[0]->ev_events); + ret = WSAWaitForMultipleEvents(numwait, base->waitfor, + 0 /* do not wait for all, just one will do */, + wait?timeout:WSA_INFINITE, + 0); /* we are not alertable (IO completion events) */ + printf("after wait %d %d\n", ret, numwait); + if(ret == WSA_WAIT_IO_COMPLETION) { + //printf("getdns: WSAWaitForMultipleEvents failed: WSA_WAIT_IO_COMPLETION"); + return -1; + } else if(ret == WSA_WAIT_FAILED) { + //printf("getdns: WSAWaitForMultipleEvents failed: %s", + // wsa_strerror(WSAGetLastError())); + return -1; + } else if(ret == WSA_WAIT_TIMEOUT) { + printf("timeout\n"); + was_timeout = 1; + } else + startidx = ret - WSA_WAIT_EVENT_0; + } + ////verbose(VERB_CLIENT, "winsock_event wake was_timeout=%d startidx=%d", + // was_timeout, startidx); - /* get new time after wait */ + /* get new time after wait */ if(settime(base) < 0) return -1; - /* callbacks */ - if(base->tcp_stickies) - startidx = 0; /* process all events, some are sticky */ - for(i=startidx; ijust_checked = 1; + /* callbacks */ + if(base->tcp_stickies) + startidx = 0; /* process all events, some are sticky */ + for(i=startidx; ijust_checked = 1; - //verbose(VERB_CLIENT, "winsock_event signals"); - for(i=startidx; iwaitfor[i]) - continue; /* was deleted */ - if(eventlist[i]->is_signal) { - eventlist[i]->just_checked = 0; - _getdns_handle_signal(eventlist[i]); - } - } - /* early exit - do not process network, exit quickly */ - if(base->need_to_exit) - return 0; + //verbose(VERB_CLIENT, "winsock_event signals"); + for(i=startidx; iwaitfor[i]) + continue; /* was deleted */ + if(eventlist[i]->is_signal) { + eventlist[i]->just_checked = 0; + _getdns_handle_signal(eventlist[i]); + } + } + /* early exit - do not process network, exit quickly */ + if(base->need_to_exit) + return 0; - //verbose(VERB_CLIENT, "winsock_event net"); - for(i=startidx; iwaitfor[i]) - continue; /* was deleted */ - if(!eventlist[i]->just_checked) - continue; /* added by other callback */ - if(eventlist[i]->is_signal) - continue; /* not a network event at all */ - eventlist[i]->just_checked = 0; + //verbose(VERB_CLIENT, "winsock_event net"); + for(i=startidx; iwaitfor[i]) + continue; /* was deleted */ + if(!eventlist[i]->just_checked) + continue; /* added by other callback */ + if(eventlist[i]->is_signal) + continue; /* not a network event at all */ + eventlist[i]->just_checked = 0; - if(WSAEnumNetworkEvents(eventlist[i]->ev_fd, - base->waitfor[i], /* reset the event handle */ - /*NULL,*/ /* do not reset the event handle */ - &netev) != 0) { - log_err("getdns: WSAEnumNetworkEvents failed: %s", - wsa_strerror(WSAGetLastError())); - return -1; - } - if((netev.lNetworkEvents & FD_READ)) { - if(netev.iErrorCode[FD_READ_BIT] != 0) - printf("FD_READ_BIT error: %s\n", - wsa_strerror(netev.iErrorCode[FD_READ_BIT])); - bits |= EV_READ; - printf("FD_READ_BIT\n"); - } - if((netev.lNetworkEvents & FD_WRITE)) { - if(netev.iErrorCode[FD_WRITE_BIT] != 0) - printf("FD_WRITE_BIT error: %s\n", - wsa_strerror(netev.iErrorCode[FD_WRITE_BIT])); - bits |= EV_WRITE; - printf("FD_WRITE_BIT\n"); - } - if((netev.lNetworkEvents & FD_CONNECT)) { - if(netev.iErrorCode[FD_CONNECT_BIT] != 0) - printf("FD_CONNECT_BIT error: %s\n", - wsa_strerror(netev.iErrorCode[FD_CONNECT_BIT])); - bits |= EV_READ; - bits |= EV_WRITE; - printf("FD_CONNECT_BIT\n"); - } - if((netev.lNetworkEvents & FD_ACCEPT)) { - if(netev.iErrorCode[FD_ACCEPT_BIT] != 0) - printf("FD_ACCEPT_BIT error: %s\n", - wsa_strerror(netev.iErrorCode[FD_ACCEPT_BIT])); - bits |= EV_READ; - printf("FD_ACCEPT_BIT\n"); - } - if((netev.lNetworkEvents & FD_CLOSE)) { - if(netev.iErrorCode[FD_CLOSE_BIT] != 0) - printf("FD_CLOSE_BIT error: %s\n", - wsa_strerror(netev.iErrorCode[FD_CLOSE_BIT])); - //g bits |= EV_READ; - //g bits |= EV_WRITE; - printf("FD_CLOSE_BIT\n"); - } - if(eventlist[i]->is_tcp && eventlist[i]->stick_events) { - /* - printf("winsock %d pass sticky %s%s\n", - eventlist[i]->ev_fd, - (eventlist[i]->old_events&EV_READ)?"EV_READ":"", - (eventlist[i]->old_events&EV_WRITE)?"EV_WRITE":""); - */ - bits |= eventlist[i]->old_events; - } - if(eventlist[i]->is_tcp && bits) { - eventlist[i]->old_events = bits; - eventlist[i]->stick_events = 1; - if((eventlist[i]->ev_events & bits)) { - newstickies = 1; - } - /* - printf("winsock %d store sticky %s%s", - eventlist[i]->ev_fd, - (eventlist[i]->old_events&EV_READ)?"EV_READ":"", - (eventlist[i]->old_events&EV_WRITE)?"EV_WRITE":""); - */ - } - if((bits & eventlist[i]->ev_events)) { - printf( "winsock event callback %p fd=%d " - "%s%s%s%s%s ; %s%s%s\n", - eventlist[i], eventlist[i]->ev_fd, - (netev.lNetworkEvents&FD_READ)?" FD_READ":"", - (netev.lNetworkEvents&FD_WRITE)?" FD_WRITE":"", - (netev.lNetworkEvents&FD_CONNECT)? - " FD_CONNECT":"", - (netev.lNetworkEvents&FD_ACCEPT)? - " FD_ACCEPT":"", - (netev.lNetworkEvents&FD_CLOSE)?" FD_CLOSE":"", - (bits&EV_READ)?" EV_READ":"", - (bits&EV_WRITE)?" EV_WRITE":"", - (bits&EV_TIMEOUT)?" EV_TIMEOUT":""); - - fptr_ok(fptr_whitelist_event( - eventlist[i]->ev_callback)); - (*eventlist[i]->ev_callback)(eventlist[i]->ev_fd, - bits & eventlist[i]->ev_events, - eventlist[i]->ev_arg); - } - /* - if(eventlist[i]->is_tcp && bits) - printf( "winsock %d got sticky %s%s\n", - eventlist[i]->ev_fd, - (eventlist[i]->old_events&EV_READ)?"EV_READ":"", - (eventlist[i]->old_events&EV_WRITE)?"EV_WRITE":""); - */ - } - //verbose(VERB_CLIENT, "winsock_event net"); - if(base->tcp_reinvigorated) { - printf("winsock_event reinvigorated\n"); - base->tcp_reinvigorated = 0; - newstickies = 1; - } - base->tcp_stickies = newstickies; - //gprintf("winsock_event handle_select end\n"); - return 0; + if(WSAEnumNetworkEvents(eventlist[i]->ev_fd, + base->waitfor[i], /* reset the event handle */ + /*NULL,*/ /* do not reset the event handle */ + &netev) != 0) { + log_err("getdns: WSAEnumNetworkEvents failed: %s", + wsa_strerror(WSAGetLastError())); + return -1; + } + if((netev.lNetworkEvents & FD_READ)) { + if(netev.iErrorCode[FD_READ_BIT] != 0) + printf("FD_READ_BIT error: %s\n", + wsa_strerror(netev.iErrorCode[FD_READ_BIT])); + bits |= EV_READ; + printf("FD_READ_BIT\n"); + } + if((netev.lNetworkEvents & FD_WRITE)) { + if(netev.iErrorCode[FD_WRITE_BIT] != 0) + printf("FD_WRITE_BIT error: %s\n", + wsa_strerror(netev.iErrorCode[FD_WRITE_BIT])); + bits |= EV_WRITE; + printf("FD_WRITE_BIT\n"); + } + if((netev.lNetworkEvents & FD_CONNECT)) { + if(netev.iErrorCode[FD_CONNECT_BIT] != 0) + printf("FD_CONNECT_BIT error: %s\n", + wsa_strerror(netev.iErrorCode[FD_CONNECT_BIT])); + bits |= EV_READ; + bits |= EV_WRITE; + printf("FD_CONNECT_BIT\n"); + } + if((netev.lNetworkEvents & FD_ACCEPT)) { + if(netev.iErrorCode[FD_ACCEPT_BIT] != 0) + printf("FD_ACCEPT_BIT error: %s\n", + wsa_strerror(netev.iErrorCode[FD_ACCEPT_BIT])); + bits |= EV_READ; + printf("FD_ACCEPT_BIT\n"); + } + if((netev.lNetworkEvents & FD_CLOSE)) { + if(netev.iErrorCode[FD_CLOSE_BIT] != 0) + printf("FD_CLOSE_BIT error: %s\n", + wsa_strerror(netev.iErrorCode[FD_CLOSE_BIT])); + //g bits |= EV_READ; + //g bits |= EV_WRITE; + printf("FD_CLOSE_BIT\n"); + } + if(eventlist[i]->is_tcp && eventlist[i]->stick_events) { + + printf("winsock %d pass sticky %s%s\n", + eventlist[i]->ev_fd, + (eventlist[i]->old_events&EV_READ)?"EV_READ":"", + (eventlist[i]->old_events&EV_WRITE)?"EV_WRITE":""); + + bits |= eventlist[i]->old_events; + } + if(eventlist[i]->is_tcp && bits) { + eventlist[i]->old_events = bits; + eventlist[i]->stick_events = 1; + if((eventlist[i]->ev_events & bits)) { + newstickies = 1; + } + + printf("winsock %d store sticky %s%s", + eventlist[i]->ev_fd, + (eventlist[i]->old_events&EV_READ)?"EV_READ":"", + (eventlist[i]->old_events&EV_WRITE) ? "EV_WRITE" : ""); + + } + if((bits & eventlist[i]->ev_events)) { + printf( "winsock event callback %p fd=%d " + "%s%s%s%s%s ; %s%s%s\n", + eventlist[i], eventlist[i]->ev_fd, + (netev.lNetworkEvents&FD_READ)?" FD_READ":"", + (netev.lNetworkEvents&FD_WRITE)?" FD_WRITE":"", + (netev.lNetworkEvents&FD_CONNECT)? + " FD_CONNECT":"", + (netev.lNetworkEvents&FD_ACCEPT)? + " FD_ACCEPT":"", + (netev.lNetworkEvents&FD_CLOSE)?" FD_CLOSE":"", + (bits&EV_READ)?" EV_READ":"", + (bits&EV_WRITE)?" EV_WRITE":"", + (bits&EV_TIMEOUT)?" EV_TIMEOUT":""); + + fptr_ok(fptr_whitelist_event( + eventlist[i]->ev_callback)); + (*eventlist[i]->ev_callback)(eventlist[i]->ev_fd, + bits & eventlist[i]->ev_events, + eventlist[i]->ev_arg); + } + + if(eventlist[i]->is_tcp && bits) + printf( "winsock %d got sticky %s%s\n", + eventlist[i]->ev_fd, + (eventlist[i]->old_events&EV_READ)?"EV_READ":"", + (eventlist[i]->old_events&EV_WRITE)?"EV_WRITE":""); + + } + //verbose(VERB_CLIENT, "winsock_event net"); + if(base->tcp_reinvigorated) { + printf("winsock_event reinvigorated\n"); + base->tcp_reinvigorated = 0; + newstickies = 1; + } + base->tcp_stickies = newstickies; + //gprintf("winsock_event handle_select end\n"); + return 0; } int _getdns_event_base_dispatch(struct _getdns_event_base *base) { - struct timeval wait; - if(settime(base) < 0) - return -1; - while(!base->need_to_exit) - { - /* see if timeouts need handling */ - _getdns_handle_timeouts(base, base->time_tv, &wait); + struct timeval wait; + if(settime(base) < 0) + return -1; + while(!base->need_to_exit) + { + /* see if timeouts need handling */ + _getdns_handle_timeouts(base, base->time_tv, &wait); + if(base->need_to_exit) + return 0; + /* do select */ + if(_getdns_handle_select(base, &wait) < 0) { if(base->need_to_exit) - return 0; - /* do select */ - if(_getdns_handle_select(base, &wait) < 0) { - if(base->need_to_exit) - return 0; - return -1; - } + return 0; + return -1; } - return 0; + } + return 0; } int _getdns_event_base_loopexit(struct _getdns_event_base *base, - struct timeval * ATTR_UNUSED(tv)) + struct timeval * ATTR_UNUSED(tv)) { - //verbose(VERB_CLIENT, "winsock_event loopexit"); - base->need_to_exit = 1; - return 0; + base->need_to_exit = 1; + return 0; } void _getdns_event_base_free(struct _getdns_event_base *base) { - //verbose(VERB_CLIENT, "winsock_event event_base_free"); - if(!base) + if(!base) return; - if(base->items) - free(base->items); - if(base->times) - free(base->times); - if(base->signals) - free(base->signals); - free(base); + if(base->items) + free(base->items); + if(base->times) + free(base->times); + if(base->signals) + free(base->signals); + free(base); } void _getdns_event_set(struct _getdns_event *ev, int fd, short bits, - void (*cb)(int, short, void *), void *arg) + void (*cb)(int, short, void *), void *arg) { - ev->node.key = ev; - ev->ev_fd = fd; - ev->ev_events = bits; - ev->ev_callback = cb; - fptr_ok(fptr_whitelist_event(ev->ev_callback)); - ev->ev_arg = arg; - ev->just_checked = 0; - ev->added = 0; + ev->node.key = ev; + ev->ev_fd = fd; + ev->ev_events = bits; + ev->ev_callback = cb; + fptr_ok(fptr_whitelist_event(ev->ev_callback)); + ev->ev_arg = arg; + ev->just_checked = 0; + ev->added = 0; } int _getdns_event_base_set(struct _getdns_event_base *base, struct _getdns_event *ev) { - ev->ev_base = base; - ev->old_events = 0; - ev->stick_events = 0; - ev->added = 0; - return 0; + ev->ev_base = base; + ev->old_events = 0; + ev->stick_events = 0; + ev->added = 0; + return 0; } /** @@ -647,91 +644,92 @@ int _getdns_event_base_set(struct _getdns_event_base *base, struct _getdns_event static int find_fd(struct _getdns_event_base* base, int fd) { - int i; - for (i = 0; imax; i++) { - if (base->items[i]->ev_fd == fd) - return i; - } - return -1; + int i; + for (i = 0; imax; i++) { + if (base->items[i]->ev_fd == fd) + return i; + } + return -1; } int _getdns_event_add(struct _getdns_event *ev, struct timeval *tv) { - printf( "event_add %p added=%d fd=%d tv=" ARG_LL "d %s%s%s\n", - ev, ev->added, ev->ev_fd, - (tv?(long long)tv->tv_sec*1000+(long long)tv->tv_usec/1000:-1), - (ev->ev_events&EV_READ)?" EV_READ":"", - (ev->ev_events&EV_WRITE)?" EV_WRITE":"", - (ev->ev_events&EV_TIMEOUT)?" EV_TIMEOUT":""); - + printf( "event_add %p added=%d fd=%d tv=" ARG_LL "d %s%s%s\n", + ev, ev->added, ev->ev_fd, + (tv?(long long)tv->tv_sec*1000+(long long)tv->tv_usec/1000:-1), + (ev->ev_events&EV_READ)?" EV_READ":"", + (ev->ev_events&EV_WRITE)?" EV_WRITE":"", + (ev->ev_events&EV_TIMEOUT)?" EV_TIMEOUT":""); + if(ev->added) _getdns_event_del(ev); - ev->is_tcp = 0; - ev->is_signal = 0; - ev->just_checked = 0; + ev->is_tcp = 0; + ev->is_signal = 0; + ev->just_checked = 0; - if ((ev->ev_events&(EV_READ | EV_WRITE)) && ev->ev_fd != -1) { - BOOL b = 0; - int t, l; - long events = 0; - //gprintf("\getdns_event_add %d %d\n", ev->ev_fd, events); + if ((ev->ev_events&(EV_READ | EV_WRITE)) && ev->ev_fd != -1) { + BOOL b = 0; + int t, l; + long events = 0; + //gprintf("\getdns_event_add %d %d\n", ev->ev_fd, events); - if (ev->ev_base->max == ev->ev_base->cap) - return -1; - ev->idx = ev->ev_base->max++; - ev->ev_base->items[ev->idx] = ev; + if (ev->ev_base->max == ev->ev_base->cap) + return -1; + ev->idx = ev->ev_base->max++; + ev->ev_base->items[ev->idx] = ev; - if ((ev->ev_events&EV_READ)) - events |= FD_READ; - if ((ev->ev_events&EV_WRITE)) - { - events |= FD_CONNECT; - events |= FD_WRITE; - } + if ((ev->ev_events&EV_READ)) + events |= FD_READ; + if ((ev->ev_events&EV_WRITE)) + { + events |= FD_CONNECT; + events |= FD_WRITE; + } - //printf("\getdns_event_add %d read = %d write = %d %d\n", ev->ev_fd, ev->ev_events&EV_READ, ev->ev_events&EV_WRITE, events); + //printf("\getdns_event_add %d read = %d write = %d %d\n", ev->ev_fd, ev->ev_events&EV_READ, ev->ev_events&EV_WRITE, events); - l = sizeof(t); - if(getsockopt(ev->ev_fd, SOL_SOCKET, SO_TYPE, - (void*)&t, &l) != 0) - log_err("getdns: getsockopt(SO_TYPE) failed: %s", - wsa_strerror(WSAGetLastError())); - if(t == SOCK_STREAM) { - /* TCP socket */ - ev->is_tcp = 1; - events |= FD_CLOSE; - if( (ev->ev_events&EV_WRITE) ) - events |= FD_CONNECT; - l = sizeof(b); - if(getsockopt(ev->ev_fd, SOL_SOCKET, SO_ACCEPTCONN, - (void*)&b, &l) != 0) - log_err("getdns: getsockopt(SO_ACCEPTCONN) failed: %s", - wsa_strerror(WSAGetLastError())); - if(b) /* TCP accept socket */ - events |= FD_ACCEPT; - } - ev->hEvent = WSACreateEvent(); - if(ev->hEvent == WSA_INVALID_EVENT) - log_err("getdns: WSACreateEvent failed: %s", - wsa_strerror(WSAGetLastError())); - /* automatically sets fd to nonblocking mode. - * nonblocking cannot be disabled, until wsaES(fd, NULL, 0) */ - printf("\nWSAEventSelect %d events %d hEvent %d\n", ev->ev_fd, events, ev->hEvent); - //gg if (WSAEventSelect(ev->ev_fd, ev->hEvent, FD_ACCEPT | FD_CONNECT | FD_READ | FD_CLOSE | FD_WRITE) != 0) { - //if (WSAEventSelect(ev->ev_fd, ev->hEvent,FD_READ | FD_WRITE) != 0) { - if (WSAEventSelect(ev->ev_fd, ev->hEvent, events) != 0) { - log_err("getdns: WSAEventSelect in getdns failed: %s", - wsa_strerror(WSAGetLastError())); - } - if(ev->is_tcp && ev->stick_events && - (ev->ev_events & ev->old_events)) { - /* go to processing the sticky event right away */ - ev->ev_base->tcp_reinvigorated = 1; - } - } + l = sizeof(t); + if(getsockopt(ev->ev_fd, SOL_SOCKET, SO_TYPE, + (void*)&t, &l) != 0) + log_err("getdns: getsockopt(SO_TYPE) failed: %s", + wsa_strerror(WSAGetLastError())); + if(t == SOCK_STREAM) { + /* TCP socket */ + ev->is_tcp = 1; + events |= FD_CLOSE; + if( (ev->ev_events&EV_WRITE) ) + events |= FD_CONNECT; + l = sizeof(b); + if(getsockopt(ev->ev_fd, SOL_SOCKET, SO_ACCEPTCONN, + (void*)&b, &l) != 0) + log_err("getdns: getsockopt(SO_ACCEPTCONN) failed: %s", + wsa_strerror(WSAGetLastError())); + if(b) /* TCP accept socket */ + events |= FD_ACCEPT; + } + ev->hEvent = WSACreateEvent(); + if(ev->hEvent == WSA_INVALID_EVENT) + log_err("getdns: WSACreateEvent failed: %s", + wsa_strerror(WSAGetLastError())); + /* automatically sets fd to nonblocking mode. + * nonblocking cannot be disabled, until wsaES(fd, NULL, 0) */ + printf("\nWSAEventSelect %d events %d hEvent %d\n", ev->ev_fd, events, ev->hEvent); + if (WSAEventSelect(ev->ev_fd, ev->hEvent, events) != 0) { + log_err("getdns: WSAEventSelect in getdns failed: %s", + wsa_strerror(WSAGetLastError())); + } + if(ev->is_tcp && ev->stick_events && + (ev->ev_events & ev->old_events)) { + /* go to processing the sticky event right away */ + printf("\nWSAEventSelect sticky %d events %d hEvent %d\n", ev->ev_fd, events, ev->hEvent); + ev->ev_base->tcp_reinvigorated = 1; + } + } + + if(tv && (ev->ev_events&EV_TIMEOUT)) { + printf("\nWSAEventSelect timeout %d hEvent %d\n", ev->ev_fd, ev->hEvent); - if(tv && (ev->ev_events&EV_TIMEOUT)) { #ifndef S_SPLINT_S struct timeval *now = ev->ev_base->time_tv; ev->ev_timeout.tv_sec = tv->tv_sec + now->tv_sec; @@ -744,42 +742,42 @@ int _getdns_event_add(struct _getdns_event *ev, struct timeval *tv) (void)_getdns_rbtree_insert(ev->ev_base->times, &ev->node); } ev->added = 1; - return 0; + return 0; } int _getdns_event_del(struct _getdns_event *ev) { - //verbose(VERB_ALGO, "event_del %p added=%d fd=%d tv=" ARG_LL "d %s%s%s", - // ev, ev->added, ev->ev_fd, - // (ev->ev_events&EV_TIMEOUT)?(long long)ev->ev_timeout.tv_sec*1000+ - // (long long)ev->ev_timeout.tv_usec/1000:-1, - // (ev->ev_events&EV_READ)?" EV_READ":"", - // (ev->ev_events&EV_WRITE)?" EV_WRITE":"", - // (ev->ev_events&EV_TIMEOUT)?" EV_TIMEOUT":""); - if(!ev->added) - return 0; - //log_assert(ev->added); + //verbose(VERB_ALGO, "event_del %p added=%d fd=%d tv=" ARG_LL "d %s%s%s", + // ev, ev->added, ev->ev_fd, + // (ev->ev_events&EV_TIMEOUT)?(long long)ev->ev_timeout.tv_sec*1000+ + // (long long)ev->ev_timeout.tv_usec/1000:-1, + // (ev->ev_events&EV_READ)?" EV_READ":"", + // (ev->ev_events&EV_WRITE)?" EV_WRITE":"", + // (ev->ev_events&EV_TIMEOUT)?" EV_TIMEOUT":""); + if(!ev->added) + return 0; + //log_assert(ev->added); if((ev->ev_events&EV_TIMEOUT)) (void)_getdns_rbtree_delete(ev->ev_base->times, &ev->node); if((ev->ev_events&(EV_READ|EV_WRITE)) && ev->ev_fd != -1) { - //log_assert(ev->ev_base->max > 0); - /* remove item and compact the list */ - ev->ev_base->items[ev->idx] = - ev->ev_base->items[ev->ev_base->max-1]; - ev->ev_base->items[ev->ev_base->max-1] = NULL; - ev->ev_base->max--; - if(ev->idx < ev->ev_base->max) - ev->ev_base->items[ev->idx]->idx = ev->idx; - zero_waitfor(ev->ev_base->waitfor, ev->hEvent); + //log_assert(ev->ev_base->max > 0); + /* remove item and compact the list */ + ev->ev_base->items[ev->idx] = + ev->ev_base->items[ev->ev_base->max-1]; + ev->ev_base->items[ev->ev_base->max-1] = NULL; + ev->ev_base->max--; + if(ev->idx < ev->ev_base->max) + ev->ev_base->items[ev->idx]->idx = ev->idx; + zero_waitfor(ev->ev_base->waitfor, ev->hEvent); - if(WSAEventSelect(ev->ev_fd, ev->hEvent, 0) != 0) - log_err("getdns: WSAEventSelect(disable) failed: %s", - wsa_strerror(WSAGetLastError())); - if(!WSACloseEvent(ev->hEvent)) - log_err("getdns: WSACloseEvent failed: %s", - wsa_strerror(WSAGetLastError())); - } - ev->just_checked = 0; + if(WSAEventSelect(ev->ev_fd, ev->hEvent, 0) != 0) + log_err("getdns: WSAEventSelect(disable) failed: %s", + wsa_strerror(WSAGetLastError())); + if(!WSACloseEvent(ev->hEvent)) + log_err("getdns: WSACloseEvent failed: %s", + wsa_strerror(WSAGetLastError())); + } + ev->just_checked = 0; ev->added = 0; return 0; } @@ -796,7 +794,7 @@ static RETSIGTYPE sigh(int sig) if(!ev) return; //g fptr_ok(fptr_whitelist_event(ev->ev_callback)); - //g (*ev->ev_callback)(sig, EV_SIGNAL, ev->ev_arg); + //g (*ev->ev_callback)(sig, EV_SIGNAL, ev->ev_arg); } int _getdns_signal_add(struct _getdns_event *ev, struct timeval * ATTR_UNUSED(tv)) @@ -823,47 +821,47 @@ int _getdns_signal_del(struct _getdns_event *ev) void winsock_tcp_wouldblock(struct _getdns_event* ev, int eventbits) { - //verbose(VERB_ALGO, "winsock: tcp wouldblock %s", - //eventbits==EV_READ?"EV_READ":"EV_WRITE"); - ev->old_events &= (~eventbits); - if(ev->old_events == 0) - ev->stick_events = 0; - /* in case this is the last sticky event, we could - * possibly run an empty handler loop to reset the base - * tcp_stickies variable - */ + printf("winsock: tcp wouldblock %s\n", + eventbits==EV_READ?"EV_READ":"EV_WRITE"); + ev->old_events &= (~eventbits); + if(ev->old_events == 0) + ev->stick_events = 0; + /* in case this is the last sticky event, we could + * possibly run an empty handler loop to reset the base + * tcp_stickies variable + */ } int winsock_register_wsaevent(struct _getdns_event_base* base, struct _getdns_event* ev, - WSAEVENT wsaevent, void (*cb)(int, short, void*), void* arg) + WSAEVENT wsaevent, void (*cb)(int, short, void*), void* arg) { - if(base->max == base->cap) - return 0; - memset(ev, 0, sizeof(*ev)); - ev->ev_fd = -1; - ev->ev_events = EV_READ; - ev->ev_callback = cb; - ev->ev_arg = arg; - ev->is_signal = 1; - ev->hEvent = wsaevent; - ev->added = 1; - ev->ev_base = base; - ev->idx = ev->ev_base->max++; - ev->ev_base->items[ev->idx] = ev; - return 1; + if(base->max == base->cap) + return 0; + memset(ev, 0, sizeof(*ev)); + ev->ev_fd = -1; + ev->ev_events = EV_READ; + ev->ev_callback = cb; + ev->ev_arg = arg; + ev->is_signal = 1; + ev->hEvent = wsaevent; + ev->added = 1; + ev->ev_base = base; + ev->idx = ev->ev_base->max++; + ev->ev_base->items[ev->idx] = ev; + return 1; } void winsock_unregister_wsaevent(struct _getdns_event* ev) { - if(!ev || !ev->added) return; - //log_assert(ev->added && ev->ev_base->max > 0) - /* remove item and compact the list */ - ev->ev_base->items[ev->idx] = ev->ev_base->items[ev->ev_base->max-1]; - ev->ev_base->items[ev->ev_base->max-1] = NULL; - ev->ev_base->max--; - if(ev->idx < ev->ev_base->max) - ev->ev_base->items[ev->idx]->idx = ev->idx; - ev->added = 0; + if(!ev || !ev->added) return; + //log_assert(ev->added && ev->ev_base->max > 0) + /* remove item and compact the list */ + ev->ev_base->items[ev->idx] = ev->ev_base->items[ev->ev_base->max-1]; + ev->ev_base->items[ev->ev_base->max-1] = NULL; + ev->ev_base->max--; + if(ev->idx < ev->ev_base->max) + ev->ev_base->items[ev->idx]->idx = ev->idx; + ev->added = 0; } #else /* USE_WINSOCK */ diff --git a/src/util/winsock_event.h b/src/util/winsock_event.h index 595116b2..6083cfc5 100644 --- a/src/util/winsock_event.h +++ b/src/util/winsock_event.h @@ -40,6 +40,7 @@ * This file contains interface functions with the WinSock2 API on Windows. * It uses the winsock WSAWaitForMultipleEvents interface on a number of * sockets. + * Code is originally from the Unbound source for Windows. * * Note that windows can only wait for max 64 events at one time. * @@ -133,92 +134,92 @@ */ struct _getdns_event_base { - /** sorted by timeout (absolute), ptr */ - _getdns_rbtree_t* times; - /** array (first part in use) of handles to work on */ - struct _getdns_event** items; - /** number of items in use in array */ - int max; - /** capacity of array, size of array in items */ - int cap; - /** array of 0 - maxsig of ptr to event for it */ - struct _getdns_event** signals; - /** if we need to exit */ - int need_to_exit; - /** where to store time in seconds */ - time_t* time_secs; - /** where to store time in microseconds */ - struct timeval* time_tv; - /** - * TCP streams have sticky events to them, these are not - * reported by the windows event system anymore, we have to - * keep reporting those events as present until wouldblock() is - * signalled by the handler back to use. - */ - int tcp_stickies; - /** - * should next cycle process reinvigorated stickies, - * these are stickies that have been stored, but due to a new - * event_add a sudden interest in the event has incepted. - */ - int tcp_reinvigorated; - /** The list of events that is currently being processed. */ - WSAEVENT waitfor[WSK_MAX_ITEMS]; + /** sorted by timeout (absolute), ptr */ + _getdns_rbtree_t* times; + /** array (first part in use) of handles to work on */ + struct _getdns_event** items; + /** number of items in use in array */ + int max; + /** capacity of array, size of array in items */ + int cap; + /** array of 0 - maxsig of ptr to event for it */ + struct _getdns_event** signals; + /** if we need to exit */ + int need_to_exit; + /** where to store time in seconds */ + time_t* time_secs; + /** where to store time in microseconds */ + struct timeval* time_tv; + /** + * TCP streams have sticky events to them, these are not + * reported by the windows event system anymore, we have to + * keep reporting those events as present until wouldblock() is + * signalled by the handler back to use. + */ + int tcp_stickies; + /** + * should next cycle process reinvigorated stickies, + * these are stickies that have been stored, but due to a new + * event_add a sudden interest in the event has incepted. + */ + int tcp_reinvigorated; + /** The list of events that is currently being processed. */ + WSAEVENT waitfor[WSK_MAX_ITEMS]; - /* fdset for read write, for fds ready, and added */ - fd_set - /** fds for reading */ - reads, - /** fds for writing */ - writes, - /** fds determined ready for use */ - ready, - /** ready plus newly added events. */ - content; + /* fdset for read write, for fds ready, and added */ + fd_set + /** fds for reading */ + reads, + /** fds for writing */ + writes, + /** fds determined ready for use */ + ready, + /** ready plus newly added events. */ + content; }; /** * Event structure. Has some of the event elements. */ struct _getdns_event { - /** node in timeout rbtree */ - _getdns_rbnode_t node; - /** is event already added */ - int added; + /** node in timeout rbtree */ + _getdns_rbnode_t node; + /** is event already added */ + int added; - /** event base it belongs to */ - struct _getdns_event_base *ev_base; - /** fd to poll or -1 for timeouts. signal number for sigs. */ - int ev_fd; - /** what events this event is interested in, see EV_.. above. */ - short ev_events; - /** timeout value */ - struct timeval ev_timeout; + /** event base it belongs to */ + struct _getdns_event_base *ev_base; + /** fd to poll or -1 for timeouts. signal number for sigs. */ + int ev_fd; + /** what events this event is interested in, see EV_.. above. */ + short ev_events; + /** timeout value */ + struct timeval ev_timeout; - /** callback to call: fd, eventbits, userarg */ - void (*ev_callback)(int, short, void *); - /** callback user arg */ - void *ev_arg; + /** callback to call: fd, eventbits, userarg */ + void (*ev_callback)(int, short, void *); + /** callback user arg */ + void *ev_arg; - /* ----- nonpublic part, for winsock_event only ----- */ - /** index of this event in the items array (if added) */ - int idx; - /** the event handle to wait for new events to become ready */ - WSAEVENT hEvent; - /** true if this filedes is a TCP socket and needs special attention */ - int is_tcp; - /** remembered EV_ values */ - short old_events; - /** should remembered EV_ values be used for TCP streams. - * Reset after WOULDBLOCK is signaled using the function. */ - int stick_events; + /* ----- nonpublic part, for winsock_event only ----- */ + /** index of this event in the items array (if added) */ + int idx; + /** the event handle to wait for new events to become ready */ + WSAEVENT hEvent; + /** true if this filedes is a TCP socket and needs special attention */ + int is_tcp; + /** remembered EV_ values */ + short old_events; + /** should remembered EV_ values be used for TCP streams. + * Reset after WOULDBLOCK is signaled using the function. */ + int stick_events; - /** true if this event is a signaling WSAEvent by the user. - * User created and user closed WSAEvent. Only signaled/unsigneled, - * no read/write/distinctions needed. */ - int is_signal; - /** used during callbacks to see which events were just checked */ - int just_checked; + /** true if this event is a signaling WSAEvent by the user. + * User created and user closed WSAEvent. Only signaled/unsigneled, + * no read/write/distinctions needed. */ + int is_signal; + /** used during callbacks to see which events were just checked */ + int just_checked; }; char* wsa_strerror(DWORD err); @@ -267,7 +268,7 @@ int getdns_mini_ev_cmp(const void* a, const void* b); * retesting the event. * Pass if EV_READ or EV_WRITE gave wouldblock. */ -static void winsock_tcp_wouldblock(struct _getdns_event* ev, int eventbit); +void winsock_tcp_wouldblock(struct _getdns_event* ev, int eventbit); /** * Routine for windows only. where you pass a signal WSAEvent that @@ -275,14 +276,14 @@ static void winsock_tcp_wouldblock(struct _getdns_event* ev, int eventbit); * The callback has to WSAResetEvent to disable the signal. * @param base: the event base. * @param ev: the event structure for data storage - * can be passed uninitialised. + * can be passed uninitialised. * @param wsaevent: the WSAEvent that gets signaled. * @param cb: callback routine. * @param arg: user argument to callback routine. * @return false on error. */ static int winsock_register_wsaevent(struct _getdns_event_base* base, struct _getdns_event* ev, - WSAEVENT wsaevent, void (*cb)(int, short, void*), void* arg); + WSAEVENT wsaevent, void (*cb)(int, short, void*), void* arg); /** * Unregister a wsaevent. User has to close the WSAEVENT itself.