From a8fac29a66a3871f1e9dbb1802b629228385395d Mon Sep 17 00:00:00 2001 From: Willem Toorop Date: Fri, 3 Nov 2017 13:50:13 +0100 Subject: [PATCH 1/5] Handle more harmless I/O error cases + - never exit on I/O errors - never stop listening on I/O errors - extended platfrom.[ch] with _getdns_strerror() --- src/anchor.c | 13 +-- src/extension/poll_eventloop.c | 8 +- src/extension/select_eventloop.c | 7 +- src/platform.c | 137 +++++++++++++++++++++++++++++++ src/platform.h | 67 ++++++++++++++- src/server.c | 52 ++++++++---- src/stub.c | 82 +++++++++--------- src/test/check_getdns_common.c | 1 + 8 files changed, 294 insertions(+), 73 deletions(-) diff --git a/src/anchor.c b/src/anchor.c index a5a31b2e..6d3877e0 100644 --- a/src/anchor.c +++ b/src/anchor.c @@ -1199,10 +1199,10 @@ static void tas_read_cb(void *userarg) return; } } - } else if (_getdns_socketerror() == _getdns_EWOULDBLOCK) + } else if (_getdns_socket_retry()) return; - DEBUG_ANCHOR("Read error: %d %s\n", (int)n, strerror(errno)); + DEBUG_ANCHOR("Read error: %d %s\n", (int)n, _getdns_errnostr()); GETDNS_CLEAR_EVENT(a->loop, &a->event); tas_next(context, a); } @@ -1249,10 +1249,10 @@ static void tas_write_cb(void *userarg) tas_read_cb, NULL, tas_timeout_cb)); return; - } else if (_getdns_socketerror() == _getdns_EWOULDBLOCK || _getdns_socketerror() == _getdns_EINPROGRESS) + } else if (_getdns_socket_retry()) return; - DEBUG_ANCHOR("Write error: %s\n", strerror(errno)); + DEBUG_ANCHOR("Write error: %s\n", _getdns_errnostr()); GETDNS_CLEAR_EVENT(a->loop, &a->event); tas_next(context, a); } @@ -1316,7 +1316,8 @@ static void tas_connect(getdns_context *context, tas_connection *a) if ((a->fd = socket(( a->req->request_type == GETDNS_RRTYPE_A ? AF_INET : AF_INET6), SOCK_STREAM, IPPROTO_TCP)) == -1) { - DEBUG_ANCHOR("Error creating socket: %s\n", strerror(errno)); + DEBUG_ANCHOR("Error creating socket: %s\n", + _getdns_errnostr()); tas_next(context, a); return; } @@ -1426,7 +1427,7 @@ static void tas_connect(getdns_context *context, tas_connection *a) DEBUG_ANCHOR("Scheduled write with event\n"); return; } else - DEBUG_ANCHOR("Connect error: %s\n", strerror(errno)); + DEBUG_ANCHOR("Connect error: %s\n", _getdns_errnostr()); error: tas_next(context, a); diff --git a/src/extension/poll_eventloop.c b/src/extension/poll_eventloop.c index 6924ebe1..743c6a81 100644 --- a/src/extension/poll_eventloop.c +++ b/src/extension/poll_eventloop.c @@ -408,8 +408,12 @@ poll_eventloop_run_once(getdns_eventloop *loop, int blocking) } else #endif if (_getdns_poll(poll_loop->pfds, poll_loop->fd_events_free, poll_timeout) < 0) { - _getdns_perror("poll() failed"); - exit(EXIT_FAILURE); + if (_getdns_socketerror() == _getdns_EAGAIN || + _getdns_socketerror() == _getdns_EINTR ) + return; + + DEBUG_SCHED("I/O error with poll(): %s\n", _getdns_errnostr()); + return; } now = get_now_plus(0); diff --git a/src/extension/select_eventloop.c b/src/extension/select_eventloop.c index 7980d0da..0b7b3592 100644 --- a/src/extension/select_eventloop.c +++ b/src/extension/select_eventloop.c @@ -245,8 +245,11 @@ select_eventloop_run_once(getdns_eventloop *loop, int blocking) #endif if (select(max_fd + 1, &readfds, &writefds, NULL, (timeout == TIMEOUT_FOREVER ? NULL : &tv)) < 0) { - _getdns_perror("select() failed"); - exit(EXIT_FAILURE); + if (_getdns_socket_retr()) + return; + + DEBUG_SCHED("I/O error with select(): %s\n", _getdns_errnostr()); + return; } #ifdef USE_WINSOCK } diff --git a/src/platform.c b/src/platform.c index 61f2bdb6..aad62d63 100644 --- a/src/platform.c +++ b/src/platform.c @@ -59,6 +59,139 @@ void _getdns_perror(const char *str) fputs(msg, stderr); } +const char *_getdns_strerror(DWORD errnum) +{ + static char unknown[32]; + + switch(errnum) { + 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 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; + } +} + #else void _getdns_perror(const char *str) @@ -66,4 +199,8 @@ void _getdns_perror(const char *str) perror(str); } +const char *_getdns_strerror(int errnum) +{ + return strerror(errnum); +} #endif diff --git a/src/platform.h b/src/platform.h index e0ec5454..d2b69da5 100644 --- a/src/platform.h +++ b/src/platform.h @@ -39,16 +39,23 @@ #ifdef USE_WINSOCK typedef u_short sa_family_t; +#define _getdns_EINTR (WSAEINTR) #define _getdns_EAGAIN (WSATRY_AGAIN) #define _getdns_EWOULDBLOCK (WSAEWOULDBLOCK) #define _getdns_EINPROGRESS (WSAEINPROGRESS) +#define _getdns_ENOBUFS (WSAENOBUFS) +#define _getdns_EPROTO (0) #define _getdns_EMFILE (WSAEMFILE) +#define _getdns_ENFILE (WSAENFILE) #define _getdns_ECONNRESET (WSAECONNRESET) +#define _getdns_ECONNABORTED (0) +#define _getdns_EISCONN (WSAEISCONN) #define _getdns_closesocket(fd) closesocket(fd) #define _getdns_poll(fdarray, nsockets, timer) WSAPoll(fdarray, nsockets, timer) #define _getdns_socketerror() (WSAGetLastError()) +const char *_getdns_strerror(DWORD errnum); #else /* USE_WINSOCK */ #ifdef HAVE_SYS_POLL_H @@ -57,11 +64,53 @@ typedef u_short sa_family_t; # include #endif +#define _getdns_EINTR (EINTR) #define _getdns_EAGAIN (EAGAIN) +#ifdef EWOULDBLOCK #define _getdns_EWOULDBLOCK (EWOULDBLOCK) -#define _getdns_EINPROGRESS (EINPROGRESS) -#define _getdns_EMFILE (EMFILE) -#define _getdns_ECONNRESET (ECONNRESET) +#else +#define _getdns_EWOULDBLOCK (0) +#endif +#ifdef EINPROGRESS +# define _getdns_EINPROGRESS (EINPROGRESS) +#else +# define _getdns_EINPROGRESS (0) +#endif +#ifdef ENOBUFS +# define _getdns_ENOBUFS (ENOBUFS) +#else +# define _getdns_ENOBUFS (0) +#endif +#ifdef EPROTO +# define _getdns_EPROTO (EPROTO) +#else +# define _getdns_EPROTO (0) +#endif +#ifdef EMFILE +# define _getdns_EMFILE (EMFILE) +#else +# define _getdns_EMFILE (0) +#endif +#ifdef ENFILE +# define _getdns_ENFILE (ENFILE) +#else +# define _getdns_ENFILE (0) +#endif +#ifdef ECONNRESET +# define _getdns_ECONNRESET (ECONNRESET) +#else +# define _getdns_ECONNRESET (0) +#endif +#ifdef ECONNABORTED +# define _getdns_ECONNABORTED (ECONNABORTED) +#else +# define _getdns_ECONNABORTED (0) +#endif +#ifdef EISCONN +# define _getdns_EISCONN (EISCONN) +#else +# define _getdns_EISCONN (0) +#endif #define SOCKADDR struct sockaddr #define SOCKADDR_IN struct sockaddr_in @@ -77,8 +126,20 @@ typedef u_short sa_family_t; #define _getdns_closesocket(fd) close(fd) #define _getdns_poll(fdarray, nsockets, timer) poll(fdarray, nsockets, timer) #define _getdns_socketerror() (errno) + +const char *_getdns_strerror(int errnum); #endif void _getdns_perror(const char *str); +#define _getdns_errnostr() (_getdns_strerror(_getdns_socketerror())) +#define _getdns_errno_retry(X) ( (X) == _getdns_EINTR \ + || (X) == _getdns_EAGAIN \ + || (X) == _getdns_EWOULDBLOCK \ + || (X) == _getdns_EINPROGRESS \ + || (X) == _getdns_ENOBUFS ) +#define _getdns_socket_retry() (_getdns_errno_retry(_getdns_socketerror())) +#define _getdns_resource_depletion() ( _getdns_socketerror() == _getdns_ENFILE \ + || _getdns_socketerror() == _getdns_EMFILE ) + #endif diff --git a/src/server.c b/src/server.c index f29cb603..28aa9052 100644 --- a/src/server.c +++ b/src/server.c @@ -191,6 +191,12 @@ static void tcp_write_cb(void *userarg) (const void *)&to_write->write_buf[to_write->written], to_write->write_buf_len - to_write->written, 0)) == -1) { + if (_getdns_socket_retry()) + return; + + DEBUG_SERVER("I/O error from send(): %s\n", + _getdns_errnostr()); + /* IO error, close connection */ conn->event.read_cb = conn->event.write_cb = conn->event.timeout_cb = NULL; @@ -281,10 +287,11 @@ getdns_reply( if (conn->l->fd >= 0 && sendto(conn->l->fd, (void *)buf, len, 0, (struct sockaddr *)&conn->remote_in, conn->addrlen) == -1) { - /* IO error, cleanup this listener */ - loop->vmt->clear(loop, &conn->l->event); - _getdns_closesocket(conn->l->fd); - conn->l->fd = -1; + /* TODO: handle _getdns_socket_retry() */ + + /* IO error, never cleanup a listener because of I/O error */ + DEBUG_SERVER("I/O error from sendto(): %s\n", + _getdns_errnostr()); } /* Unlink this connection */ (void) _getdns_rbtree_delete( @@ -364,10 +371,13 @@ static void tcp_read_cb(void *userarg) if ((bytes_read = recv(conn->fd, (void *)conn->read_pos, conn->to_read, 0)) < 0) { - if (errno == EAGAIN || errno == EWOULDBLOCK) + if (_getdns_socket_retry()) return; /* Come back to do the read later */ /* IO error, close connection */ + DEBUG_SERVER("I/O error from recv(): %s\n", + _getdns_errnostr()); + tcp_connection_destroy(conn); return; } @@ -475,10 +485,19 @@ static void tcp_accept_cb(void *userarg) conn->super.addrlen = sizeof(conn->super.remote_in); if ((conn->fd = accept(l->fd, (struct sockaddr *) &conn->super.remote_in, &conn->super.addrlen)) == -1) { - /* IO error, cleanup this listener */ - loop->vmt->clear(loop, &l->event); - _getdns_closesocket(l->fd); - l->fd = -1; + + if (_getdns_socket_retry() || + _getdns_socketerror() == _getdns_ECONNRESET) + ; /* pass */ + + else if (_getdns_resource_depletion()) + ; /* TODO: Stop listening for a little while? */ + + else + DEBUG_SERVER("I/O error during accept: %s\n", + _getdns_errnostr()); + + /* Never cleanup a listener because of I/O errors! */ GETDNS_FREE(*mf, conn); return; } @@ -545,18 +564,17 @@ static void udp_read_cb(void *userarg) conn->addrlen = sizeof(conn->remote_in); if ((len = recvfrom(l->fd, (void *)buf, sizeof(buf), 0, (struct sockaddr *)&conn->remote_in, &conn->addrlen)) == -1) { - if (_getdns_socketerror() == _getdns_ECONNRESET) { + if ( _getdns_socket_retry() && + _getdns_socketerror() != _getdns_ECONNRESET) { /* * WINSOCK gives ECONNRESET on ICMP Port Unreachable * being received. Ignore it. - * */ - GETDNS_FREE(*mf, conn); - return; + */ + DEBUG_SERVER("I/O error from recvfrom: %s\n", + _getdns_errnostr()); + } - /* IO error, cleanup this listener. */ - loop->vmt->clear(loop, &l->event); - _getdns_closesocket(l->fd); - l->fd = -1; + /* Never cleanup a listener because of an I/O error! */ #if 0 && defined(SERVER_DEBUG) && SERVER_DEBUG } else { diff --git a/src/stub.c b/src/stub.c index 49af9d8c..e9089291 100644 --- a/src/stub.c +++ b/src/stub.c @@ -57,16 +57,17 @@ #include "pubkey-pinning.h" /* WSA TODO: - * STUB_TCP_WOULDBLOCK added to deal with edge triggered event loops (versus + * STUB_TCP_RETRY added to deal with edge triggered event loops (versus * level triggered). See also lines containing WSA TODO below... */ #define STUB_TRY_AGAIN_LATER -24 /* EMFILE, i.e. Out of OS resources */ #define STUB_NO_AUTH -8 /* Existing TLS connection is not authenticated */ #define STUB_CONN_GONE -7 /* Connection has failed, clear queue*/ -#define STUB_TCP_WOULDBLOCK -6 +#define STUB_TCP_RETRY -6 #define STUB_OUT_OF_OPTIONS -5 /* upstream options exceeded MAXIMUM_UPSTREAM_OPTION_SPACE */ #define STUB_SETUP_ERROR -4 -#define STUB_TCP_AGAIN -3 +#define STUB_TCP_MORE_TO_READ -3 +#define STUB_TCP_MORE_TO_WRITE -3 #define STUB_TCP_ERROR -2 /* Don't currently have access to the context whilst doing handshake */ @@ -407,9 +408,9 @@ tcp_connect(getdns_upstream *upstream, getdns_transport_list_t transport) NULL, 0, NULL, NULL) == 0) { return fd; } - if (errno == EINPROGRESS) { + if (_getdns_socketerror() == _getdns_EINPROGRESS || + _getdns_socketerror() == _getdns_EWOULDBLOCK) return fd; - } #else (void)transport; #endif @@ -429,10 +430,8 @@ tcp_connected(getdns_upstream *upstream) { int error = 0; socklen_t len = (socklen_t)sizeof(error); getsockopt(upstream->fd, SOL_SOCKET, SO_ERROR, (void*)&error, &len); - if (error == _getdns_EINPROGRESS) - return STUB_TCP_AGAIN; - else if (error == _getdns_EWOULDBLOCK || error == _getdns_EAGAIN) - return STUB_TCP_WOULDBLOCK; + if (_getdns_errno_retry(error)) + return STUB_TCP_RETRY; else if (error != 0) { return STUB_SETUP_ERROR; } @@ -639,8 +638,8 @@ stub_tcp_read(int fd, getdns_tcp_state *tcp, struct mem_funcs *mf) } read = recv(fd, (void *)tcp->read_pos, tcp->to_read, 0); if (read < 0) { - if (_getdns_socketerror() == _getdns_EWOULDBLOCK) - return STUB_TCP_WOULDBLOCK; + if (_getdns_socket_retry()) + return STUB_TCP_RETRY; else return STUB_TCP_ERROR; } else if (read == 0) { @@ -654,7 +653,7 @@ stub_tcp_read(int fd, getdns_tcp_state *tcp, struct mem_funcs *mf) tcp->read_pos += read; if (tcp->to_read > 0) - return STUB_TCP_AGAIN; + return STUB_TCP_MORE_TO_READ; read = tcp->read_pos - tcp->read_buf; if (read == 2) { @@ -679,14 +678,14 @@ stub_tcp_read(int fd, getdns_tcp_state *tcp, struct mem_funcs *mf) } /* Ready to start reading the packet */ tcp->read_pos = tcp->read_buf; - return STUB_TCP_AGAIN; + return STUB_TCP_MORE_TO_READ; } return GLDNS_ID_WIRE(tcp->read_buf); } /* stub_tcp_write(fd, tcp, netreq) - * will return STUB_TCP_AGAIN when we need to come back again, - * STUB_TCP_ERROR on error and a query_id on successful sent. + * will return STUB_TCP_RETRY or STUB_TCP_MORE_TO_WRITE when we need to come + * back again, STUB_TCP_ERROR on error and a query_id on successful sent. */ static int stub_tcp_write(int fd, getdns_tcp_state *tcp, getdns_network_req *netreq) @@ -749,7 +748,7 @@ stub_tcp_write(int fd, getdns_tcp_state *tcp, getdns_network_req *netreq) netreq->upstream->addr_len); /* If pipelining we will find that the connection is already up so just fall back to a 'normal' write. */ - if (written == -1 && errno == EISCONN) + if (written == -1 && _getdns_socketerror() == _getdns_EISCONN) written = write(fd, netreq->query - 2, pkt_len + 2); #else written = sendto(fd, (const char *)(netreq->query - 2), @@ -757,27 +756,24 @@ stub_tcp_write(int fd, getdns_tcp_state *tcp, getdns_network_req *netreq) (struct sockaddr *)&(netreq->upstream->addr), netreq->upstream->addr_len); #endif - if ((written < 0 && (_getdns_socketerror() == _getdns_EWOULDBLOCK || - /* Add the error case where the connection is in progress which is when - a cookie is not available (e.g. when doing the first request to an - upstream). We must let the handshake complete since non-blocking. */ - _getdns_socketerror() == _getdns_EINPROGRESS)) || - (size_t)written < pkt_len + 2) { + if ((written == -1 && _getdns_socket_retry()) || + (size_t)written < pkt_len + 2) { /* We couldn't write the whole packet. - * We have to return with STUB_TCP_AGAIN. * Setup tcp to track the state. */ tcp->write_buf = netreq->query - 2; tcp->write_buf_len = pkt_len + 2; tcp->written = written >= 0 ? written : 0; - return STUB_TCP_WOULDBLOCK; + return written == -1 + ? STUB_TCP_RETRY + : STUB_TCP_MORE_TO_WRITE; } else if (written == -1) { DEBUG_STUB("%s %-35s: MSG: %p error while writing to TCP socket:" " %s\n", STUB_DEBUG_WRITE, __FUNC__, (void*)netreq - , strerror(errno)); + , _getdns_errnostr()); return STUB_TCP_ERROR; } @@ -792,12 +788,12 @@ stub_tcp_write(int fd, getdns_tcp_state *tcp, getdns_network_req *netreq) written = send(fd, (void *)(tcp->write_buf + tcp->written), tcp->write_buf_len - tcp->written, 0); if (written == -1) { - if (_getdns_socketerror() == _getdns_EWOULDBLOCK) - return STUB_TCP_WOULDBLOCK; + if (_getdns_socket_retry()) + return STUB_TCP_RETRY; else { DEBUG_STUB("%s %-35s: MSG: %p error while writing to TCP socket:" " %s\n", STUB_DEBUG_WRITE, __FUNC__, (void*)netreq - , strerror(errno)); + , _getdns_errnostr()); return STUB_TCP_ERROR; } @@ -805,7 +801,7 @@ stub_tcp_write(int fd, getdns_tcp_state *tcp, getdns_network_req *netreq) tcp->written += written; if (tcp->written < tcp->write_buf_len) /* Still more to send */ - return STUB_TCP_AGAIN; + return STUB_TCP_MORE_TO_WRITE; query_id = (int)GLDNS_ID_WIRE(tcp->write_buf + 2); /* Done. Start reading */ @@ -1029,7 +1025,7 @@ tls_do_handshake(getdns_upstream *upstream) GETDNS_SCHEDULE_EVENT(upstream->loop, upstream->fd, TIMEOUT_TLS, &upstream->event); upstream->tls_hs_state = GETDNS_HS_READ; - return STUB_TCP_AGAIN; + return STUB_TCP_RETRY; case SSL_ERROR_WANT_WRITE: GETDNS_CLEAR_EVENT(upstream->loop, &upstream->event); upstream->event.read_cb = NULL; @@ -1037,7 +1033,7 @@ tls_do_handshake(getdns_upstream *upstream) GETDNS_SCHEDULE_EVENT(upstream->loop, upstream->fd, TIMEOUT_TLS, &upstream->event); upstream->tls_hs_state = GETDNS_HS_WRITE; - return STUB_TCP_AGAIN; + return STUB_TCP_RETRY; default: DEBUG_STUB("%s %-35s: FD: %d Handshake failed %d\n", STUB_DEBUG_SETUP_TLS, __FUNC__, upstream->fd, @@ -1121,7 +1117,7 @@ stub_tls_read(getdns_upstream *upstream, getdns_tcp_state *tcp, renegotiation. Need to keep handshake state to do that.*/ int want = SSL_get_error(tls_obj, read); if (want == SSL_ERROR_WANT_READ) { - return STUB_TCP_AGAIN; /* read more later */ + return STUB_TCP_RETRY; /* Come back later */ } else return STUB_TCP_ERROR; } @@ -1129,7 +1125,7 @@ stub_tls_read(getdns_upstream *upstream, getdns_tcp_state *tcp, tcp->read_pos += read; if ((int)tcp->to_read > 0) - return STUB_TCP_AGAIN; + return STUB_TCP_MORE_TO_READ; read = tcp->read_pos - tcp->read_buf; if (read == 2) { @@ -1161,14 +1157,14 @@ stub_tls_read(getdns_upstream *upstream, getdns_tcp_state *tcp, renegotiation. Need to keep handshake state to do that.*/ int want = SSL_get_error(tls_obj, read); if (want == SSL_ERROR_WANT_READ) { - return STUB_TCP_AGAIN; /* read more later */ + return STUB_TCP_RETRY; /* read more later */ } else return STUB_TCP_ERROR; } tcp->to_read -= read; tcp->read_pos += read; if ((int)tcp->to_read > 0) - return STUB_TCP_AGAIN; + return STUB_TCP_MORE_TO_READ; } return GLDNS_ID_WIRE(tcp->read_buf); } @@ -1285,7 +1281,7 @@ stub_tls_write(getdns_upstream *upstream, getdns_tcp_state *tcp, switch (SSL_get_error(tls_obj, written)) { case SSL_ERROR_WANT_READ: case SSL_ERROR_WANT_WRITE: - return STUB_TCP_AGAIN; + return STUB_TCP_RETRY; default: return STUB_TCP_ERROR; } @@ -1335,14 +1331,14 @@ stub_udp_read_cb(void *userarg) * i.e. overflow */ 0, NULL, NULL); - if (read == -1 && (_getdns_socketerror() == _getdns_EWOULDBLOCK || + if (read == -1 && (_getdns_socket_retry() || _getdns_socketerror() == _getdns_ECONNRESET)) return; /* Try again later */ if (read == -1) { DEBUG_STUB("%s %-35s: MSG: %p error while reading from socket:" " %s\n", STUB_DEBUG_READ, __FUNC__, (void*)netreq - , strerror(errno)); + , _getdns_errnostr()); stub_cleanup(netreq); _getdns_netreq_change_state(netreq, NET_REQ_ERRORED); @@ -1451,7 +1447,7 @@ stub_udp_write_cb(void *userarg) if (written == -1) DEBUG_STUB( "%s %-35s: MSG: %p error: %s\n" , STUB_DEBUG_WRITE, __FUNC__, (void *)netreq - , strerror(errno)); + , _getdns_errnostr()); else DEBUG_STUB( "%s %-35s: MSG: %p returned: %d, expeced: %d\n" , STUB_DEBUG_WRITE, __FUNC__, (void *)netreq @@ -1517,10 +1513,10 @@ upstream_read_cb(void *userarg) &upstream->upstreams->mf); switch (q) { - case STUB_TCP_AGAIN: + case STUB_TCP_MORE_TO_READ: /* WSA TODO: if callback is still upstream_read_cb, do it again */ - case STUB_TCP_WOULDBLOCK: + case STUB_TCP_RETRY: return; case STUB_SETUP_ERROR: /* Can happen for TLS HS*/ case STUB_TCP_ERROR: @@ -1648,10 +1644,10 @@ upstream_write_cb(void *userarg) q = stub_tcp_write(upstream->fd, &upstream->tcp, netreq); switch (q) { - case STUB_TCP_AGAIN: + case STUB_TCP_MORE_TO_WRITE: /* WSA TODO: if callback is still upstream_write_cb, do it again */ - case STUB_TCP_WOULDBLOCK: + case STUB_TCP_RETRY: return; case STUB_OUT_OF_OPTIONS: case STUB_TCP_ERROR: diff --git a/src/test/check_getdns_common.c b/src/test/check_getdns_common.c index 8fe9f8c6..af894be5 100644 --- a/src/test/check_getdns_common.c +++ b/src/test/check_getdns_common.c @@ -217,6 +217,7 @@ void assert_address_in_answer(struct extracted_response *ex_response, int a, int case GETDNS_RRTYPE_A: if(a && type == GETDNS_RRTYPE_A) address_records++; + /* fallthrough */ case GETDNS_RRTYPE_AAAA: if(aaaa && type == GETDNS_RRTYPE_AAAA) address_records++; From 3b7b83e309e98762d2ebe71cb29d35b4ec3bcc49 Mon Sep 17 00:00:00 2001 From: Willem Toorop Date: Fri, 3 Nov 2017 15:41:31 +0100 Subject: [PATCH 2/5] Review comments from Jim --- src/anchor.c | 4 ++-- src/platform.c | 28 +--------------------------- src/platform.h | 8 ++++++-- src/server.c | 10 +++++----- src/stub.c | 8 ++++---- 5 files changed, 18 insertions(+), 40 deletions(-) diff --git a/src/anchor.c b/src/anchor.c index 6d3877e0..7f992a5c 100644 --- a/src/anchor.c +++ b/src/anchor.c @@ -1199,7 +1199,7 @@ static void tas_read_cb(void *userarg) return; } } - } else if (_getdns_socket_retry()) + } else if (_getdns_socket_wants_retry()) return; DEBUG_ANCHOR("Read error: %d %s\n", (int)n, _getdns_errnostr()); @@ -1249,7 +1249,7 @@ static void tas_write_cb(void *userarg) tas_read_cb, NULL, tas_timeout_cb)); return; - } else if (_getdns_socket_retry()) + } else if (_getdns_socket_wants_retry()) return; DEBUG_ANCHOR("Write error: %s\n", _getdns_errnostr()); diff --git a/src/platform.c b/src/platform.c index aad62d63..49a7e225 100644 --- a/src/platform.c +++ b/src/platform.c @@ -147,32 +147,6 @@ const char *_getdns_strerror(DWORD errnum) 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 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."; @@ -187,7 +161,7 @@ const char *_getdns_strerror(DWORD errnum) case WSA_QOS_RESERVED_PETYPE: return "Reserved policy QOS element type."; default: snprintf(unknown, sizeof(unknown), - "unknown WSA error code %d", (int)err); + "unknown WSA error code %d", (int)errnum); return unknown; } } diff --git a/src/platform.h b/src/platform.h index d2b69da5..940d0f6e 100644 --- a/src/platform.h +++ b/src/platform.h @@ -46,7 +46,11 @@ typedef u_short sa_family_t; #define _getdns_ENOBUFS (WSAENOBUFS) #define _getdns_EPROTO (0) #define _getdns_EMFILE (WSAEMFILE) -#define _getdns_ENFILE (WSAENFILE) +#ifdef WSAENFILE +# define _getdns_ENFILE (WSAENFILE) +#else +# define _getdns_ENFILE (0) +#endif #define _getdns_ECONNRESET (WSAECONNRESET) #define _getdns_ECONNABORTED (0) #define _getdns_EISCONN (WSAEISCONN) @@ -138,7 +142,7 @@ void _getdns_perror(const char *str); || (X) == _getdns_EWOULDBLOCK \ || (X) == _getdns_EINPROGRESS \ || (X) == _getdns_ENOBUFS ) -#define _getdns_socket_retry() (_getdns_errno_retry(_getdns_socketerror())) +#define _getdns_socket_wants_retry() (_getdns_errno_retry(_getdns_socketerror())) #define _getdns_resource_depletion() ( _getdns_socketerror() == _getdns_ENFILE \ || _getdns_socketerror() == _getdns_EMFILE ) diff --git a/src/server.c b/src/server.c index 28aa9052..7bbda6eb 100644 --- a/src/server.c +++ b/src/server.c @@ -191,7 +191,7 @@ static void tcp_write_cb(void *userarg) (const void *)&to_write->write_buf[to_write->written], to_write->write_buf_len - to_write->written, 0)) == -1) { - if (_getdns_socket_retry()) + if (_getdns_socket_wants_retry()) return; DEBUG_SERVER("I/O error from send(): %s\n", @@ -287,7 +287,7 @@ getdns_reply( if (conn->l->fd >= 0 && sendto(conn->l->fd, (void *)buf, len, 0, (struct sockaddr *)&conn->remote_in, conn->addrlen) == -1) { - /* TODO: handle _getdns_socket_retry() */ + /* TODO: handle _getdns_socket_wants_retry() */ /* IO error, never cleanup a listener because of I/O error */ DEBUG_SERVER("I/O error from sendto(): %s\n", @@ -371,7 +371,7 @@ static void tcp_read_cb(void *userarg) if ((bytes_read = recv(conn->fd, (void *)conn->read_pos, conn->to_read, 0)) < 0) { - if (_getdns_socket_retry()) + if (_getdns_socket_wants_retry()) return; /* Come back to do the read later */ /* IO error, close connection */ @@ -486,7 +486,7 @@ static void tcp_accept_cb(void *userarg) if ((conn->fd = accept(l->fd, (struct sockaddr *) &conn->super.remote_in, &conn->super.addrlen)) == -1) { - if (_getdns_socket_retry() || + if (_getdns_socket_wants_retry() || _getdns_socketerror() == _getdns_ECONNRESET) ; /* pass */ @@ -564,7 +564,7 @@ static void udp_read_cb(void *userarg) conn->addrlen = sizeof(conn->remote_in); if ((len = recvfrom(l->fd, (void *)buf, sizeof(buf), 0, (struct sockaddr *)&conn->remote_in, &conn->addrlen)) == -1) { - if ( _getdns_socket_retry() && + if ( _getdns_socket_wants_retry() && _getdns_socketerror() != _getdns_ECONNRESET) { /* * WINSOCK gives ECONNRESET on ICMP Port Unreachable diff --git a/src/stub.c b/src/stub.c index e9089291..247862d6 100644 --- a/src/stub.c +++ b/src/stub.c @@ -638,7 +638,7 @@ stub_tcp_read(int fd, getdns_tcp_state *tcp, struct mem_funcs *mf) } read = recv(fd, (void *)tcp->read_pos, tcp->to_read, 0); if (read < 0) { - if (_getdns_socket_retry()) + if (_getdns_socket_wants_retry()) return STUB_TCP_RETRY; else return STUB_TCP_ERROR; @@ -756,7 +756,7 @@ stub_tcp_write(int fd, getdns_tcp_state *tcp, getdns_network_req *netreq) (struct sockaddr *)&(netreq->upstream->addr), netreq->upstream->addr_len); #endif - if ((written == -1 && _getdns_socket_retry()) || + if ((written == -1 && _getdns_socket_wants_retry()) || (size_t)written < pkt_len + 2) { /* We couldn't write the whole packet. @@ -788,7 +788,7 @@ stub_tcp_write(int fd, getdns_tcp_state *tcp, getdns_network_req *netreq) written = send(fd, (void *)(tcp->write_buf + tcp->written), tcp->write_buf_len - tcp->written, 0); if (written == -1) { - if (_getdns_socket_retry()) + if (_getdns_socket_wants_retry()) return STUB_TCP_RETRY; else { DEBUG_STUB("%s %-35s: MSG: %p error while writing to TCP socket:" @@ -1331,7 +1331,7 @@ stub_udp_read_cb(void *userarg) * i.e. overflow */ 0, NULL, NULL); - if (read == -1 && (_getdns_socket_retry() || + if (read == -1 && (_getdns_socket_wants_retry() || _getdns_socketerror() == _getdns_ECONNRESET)) return; /* Try again later */ From 4508ec77fbb4bf7a5148088e2736b87994355664 Mon Sep 17 00:00:00 2001 From: Willem Toorop Date: Fri, 3 Nov 2017 16:26:19 +0100 Subject: [PATCH 3/5] Few more renames --- src/extension/select_eventloop.c | 2 +- src/platform.h | 12 ++++++------ src/stub.c | 2 +- 3 files changed, 8 insertions(+), 8 deletions(-) diff --git a/src/extension/select_eventloop.c b/src/extension/select_eventloop.c index 0b7b3592..2b0ddf21 100644 --- a/src/extension/select_eventloop.c +++ b/src/extension/select_eventloop.c @@ -245,7 +245,7 @@ select_eventloop_run_once(getdns_eventloop *loop, int blocking) #endif if (select(max_fd + 1, &readfds, &writefds, NULL, (timeout == TIMEOUT_FOREVER ? NULL : &tv)) < 0) { - if (_getdns_socket_retr()) + if (_getdns_socket_wants_retry()) return; DEBUG_SCHED("I/O error with select(): %s\n", _getdns_errnostr()); diff --git a/src/platform.h b/src/platform.h index 940d0f6e..952668c6 100644 --- a/src/platform.h +++ b/src/platform.h @@ -137,12 +137,12 @@ const char *_getdns_strerror(int errnum); void _getdns_perror(const char *str); #define _getdns_errnostr() (_getdns_strerror(_getdns_socketerror())) -#define _getdns_errno_retry(X) ( (X) == _getdns_EINTR \ - || (X) == _getdns_EAGAIN \ - || (X) == _getdns_EWOULDBLOCK \ - || (X) == _getdns_EINPROGRESS \ - || (X) == _getdns_ENOBUFS ) -#define _getdns_socket_wants_retry() (_getdns_errno_retry(_getdns_socketerror())) +#define _getdns_error_wants_retry(X) ( (X) == _getdns_EINTR \ + || (X) == _getdns_EAGAIN \ + || (X) == _getdns_EWOULDBLOCK \ + || (X) == _getdns_EINPROGRESS \ + || (X) == _getdns_ENOBUFS ) +#define _getdns_socket_wants_retry() (_getdns_error_wants_retry(_getdns_socketerror())) #define _getdns_resource_depletion() ( _getdns_socketerror() == _getdns_ENFILE \ || _getdns_socketerror() == _getdns_EMFILE ) diff --git a/src/stub.c b/src/stub.c index 247862d6..bb46e5b0 100644 --- a/src/stub.c +++ b/src/stub.c @@ -430,7 +430,7 @@ tcp_connected(getdns_upstream *upstream) { int error = 0; socklen_t len = (socklen_t)sizeof(error); getsockopt(upstream->fd, SOL_SOCKET, SO_ERROR, (void*)&error, &len); - if (_getdns_errno_retry(error)) + if (_getdns_error_wants_retry(error)) return STUB_TCP_RETRY; else if (error != 0) { return STUB_SETUP_ERROR; From 9b019b8c6e86d2620bb09ca3ba48513b83663d2e Mon Sep 17 00:00:00 2001 From: Willem Toorop Date: Fri, 3 Nov 2017 16:29:43 +0100 Subject: [PATCH 4/5] Check errno is not 0 before testing errors --- src/platform.h | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-) diff --git a/src/platform.h b/src/platform.h index 952668c6..ffff4c97 100644 --- a/src/platform.h +++ b/src/platform.h @@ -137,13 +137,15 @@ const char *_getdns_strerror(int errnum); void _getdns_perror(const char *str); #define _getdns_errnostr() (_getdns_strerror(_getdns_socketerror())) -#define _getdns_error_wants_retry(X) ( (X) == _getdns_EINTR \ - || (X) == _getdns_EAGAIN \ - || (X) == _getdns_EWOULDBLOCK \ - || (X) == _getdns_EINPROGRESS \ - || (X) == _getdns_ENOBUFS ) +#define _getdns_error_wants_retry(X) ( (X) != 0 \ + && ( (X) == _getdns_EINTR \ + || (X) == _getdns_EAGAIN \ + || (X) == _getdns_EWOULDBLOCK \ + || (X) == _getdns_EINPROGRESS \ + || (X) == _getdns_ENOBUFS )) #define _getdns_socket_wants_retry() (_getdns_error_wants_retry(_getdns_socketerror())) -#define _getdns_resource_depletion() ( _getdns_socketerror() == _getdns_ENFILE \ - || _getdns_socketerror() == _getdns_EMFILE ) +#define _getdns_resource_depletion() ( _getdns_socketerror() != 0 \ + && ( _getdns_socketerror() == _getdns_ENFILE \ + || _getdns_socketerror() == _getdns_EMFILE )) #endif From 439f41149b34f4df4feb19bc7063f30831835022 Mon Sep 17 00:00:00 2001 From: Willem Toorop Date: Fri, 3 Nov 2017 16:42:38 +0100 Subject: [PATCH 5/5] Last rename + explicit EMFILE check replacement --- src/anchor.c | 4 ++-- src/extension/select_eventloop.c | 2 +- src/platform.h | 2 +- src/server.c | 10 +++++----- src/stub.c | 10 +++++----- 5 files changed, 14 insertions(+), 14 deletions(-) diff --git a/src/anchor.c b/src/anchor.c index 7f992a5c..006e5da4 100644 --- a/src/anchor.c +++ b/src/anchor.c @@ -1199,7 +1199,7 @@ static void tas_read_cb(void *userarg) return; } } - } else if (_getdns_socket_wants_retry()) + } else if (_getdns_socketerror_wants_retry()) return; DEBUG_ANCHOR("Read error: %d %s\n", (int)n, _getdns_errnostr()); @@ -1249,7 +1249,7 @@ static void tas_write_cb(void *userarg) tas_read_cb, NULL, tas_timeout_cb)); return; - } else if (_getdns_socket_wants_retry()) + } else if (_getdns_socketerror_wants_retry()) return; DEBUG_ANCHOR("Write error: %s\n", _getdns_errnostr()); diff --git a/src/extension/select_eventloop.c b/src/extension/select_eventloop.c index 2b0ddf21..7855c21d 100644 --- a/src/extension/select_eventloop.c +++ b/src/extension/select_eventloop.c @@ -245,7 +245,7 @@ select_eventloop_run_once(getdns_eventloop *loop, int blocking) #endif if (select(max_fd + 1, &readfds, &writefds, NULL, (timeout == TIMEOUT_FOREVER ? NULL : &tv)) < 0) { - if (_getdns_socket_wants_retry()) + if (_getdns_socketerror_wants_retry()) return; DEBUG_SCHED("I/O error with select(): %s\n", _getdns_errnostr()); diff --git a/src/platform.h b/src/platform.h index ffff4c97..ddfb9575 100644 --- a/src/platform.h +++ b/src/platform.h @@ -143,7 +143,7 @@ void _getdns_perror(const char *str); || (X) == _getdns_EWOULDBLOCK \ || (X) == _getdns_EINPROGRESS \ || (X) == _getdns_ENOBUFS )) -#define _getdns_socket_wants_retry() (_getdns_error_wants_retry(_getdns_socketerror())) +#define _getdns_socketerror_wants_retry() (_getdns_error_wants_retry(_getdns_socketerror())) #define _getdns_resource_depletion() ( _getdns_socketerror() != 0 \ && ( _getdns_socketerror() == _getdns_ENFILE \ || _getdns_socketerror() == _getdns_EMFILE )) diff --git a/src/server.c b/src/server.c index 7bbda6eb..ef5676f8 100644 --- a/src/server.c +++ b/src/server.c @@ -191,7 +191,7 @@ static void tcp_write_cb(void *userarg) (const void *)&to_write->write_buf[to_write->written], to_write->write_buf_len - to_write->written, 0)) == -1) { - if (_getdns_socket_wants_retry()) + if (_getdns_socketerror_wants_retry()) return; DEBUG_SERVER("I/O error from send(): %s\n", @@ -287,7 +287,7 @@ getdns_reply( if (conn->l->fd >= 0 && sendto(conn->l->fd, (void *)buf, len, 0, (struct sockaddr *)&conn->remote_in, conn->addrlen) == -1) { - /* TODO: handle _getdns_socket_wants_retry() */ + /* TODO: handle _getdns_socketerror_wants_retry() */ /* IO error, never cleanup a listener because of I/O error */ DEBUG_SERVER("I/O error from sendto(): %s\n", @@ -371,7 +371,7 @@ static void tcp_read_cb(void *userarg) if ((bytes_read = recv(conn->fd, (void *)conn->read_pos, conn->to_read, 0)) < 0) { - if (_getdns_socket_wants_retry()) + if (_getdns_socketerror_wants_retry()) return; /* Come back to do the read later */ /* IO error, close connection */ @@ -486,7 +486,7 @@ static void tcp_accept_cb(void *userarg) if ((conn->fd = accept(l->fd, (struct sockaddr *) &conn->super.remote_in, &conn->super.addrlen)) == -1) { - if (_getdns_socket_wants_retry() || + if (_getdns_socketerror_wants_retry() || _getdns_socketerror() == _getdns_ECONNRESET) ; /* pass */ @@ -564,7 +564,7 @@ static void udp_read_cb(void *userarg) conn->addrlen = sizeof(conn->remote_in); if ((len = recvfrom(l->fd, (void *)buf, sizeof(buf), 0, (struct sockaddr *)&conn->remote_in, &conn->addrlen)) == -1) { - if ( _getdns_socket_wants_retry() && + if ( _getdns_socketerror_wants_retry() && _getdns_socketerror() != _getdns_ECONNRESET) { /* * WINSOCK gives ECONNRESET on ICMP Port Unreachable diff --git a/src/stub.c b/src/stub.c index bb46e5b0..10745928 100644 --- a/src/stub.c +++ b/src/stub.c @@ -638,7 +638,7 @@ stub_tcp_read(int fd, getdns_tcp_state *tcp, struct mem_funcs *mf) } read = recv(fd, (void *)tcp->read_pos, tcp->to_read, 0); if (read < 0) { - if (_getdns_socket_wants_retry()) + if (_getdns_socketerror_wants_retry()) return STUB_TCP_RETRY; else return STUB_TCP_ERROR; @@ -756,7 +756,7 @@ stub_tcp_write(int fd, getdns_tcp_state *tcp, getdns_network_req *netreq) (struct sockaddr *)&(netreq->upstream->addr), netreq->upstream->addr_len); #endif - if ((written == -1 && _getdns_socket_wants_retry()) || + if ((written == -1 && _getdns_socketerror_wants_retry()) || (size_t)written < pkt_len + 2) { /* We couldn't write the whole packet. @@ -788,7 +788,7 @@ stub_tcp_write(int fd, getdns_tcp_state *tcp, getdns_network_req *netreq) written = send(fd, (void *)(tcp->write_buf + tcp->written), tcp->write_buf_len - tcp->written, 0); if (written == -1) { - if (_getdns_socket_wants_retry()) + if (_getdns_socketerror_wants_retry()) return STUB_TCP_RETRY; else { DEBUG_STUB("%s %-35s: MSG: %p error while writing to TCP socket:" @@ -1331,7 +1331,7 @@ stub_udp_read_cb(void *userarg) * i.e. overflow */ 0, NULL, NULL); - if (read == -1 && (_getdns_socket_wants_retry() || + if (read == -1 && (_getdns_socketerror_wants_retry() || _getdns_socketerror() == _getdns_ECONNRESET)) return; /* Try again later */ @@ -2060,7 +2060,7 @@ upstream_find_for_netreq(getdns_network_req *netreq) continue; if (fd == -1) { - if (_getdns_socketerror() == _getdns_EMFILE) + if (_getdns_resource_depletion()) return STUB_TRY_AGAIN_LATER; return -1; }