mirror of https://github.com/getdnsapi/getdns.git
Merge pull request #353 from getdnsapi/devel/errno_handling
Handle more harmless I/O error cases +
This commit is contained in:
commit
168d83ac19
13
src/anchor.c
13
src/anchor.c
|
@ -1199,10 +1199,10 @@ static void tas_read_cb(void *userarg)
|
|||
return;
|
||||
}
|
||||
}
|
||||
} else if (_getdns_socketerror() == _getdns_EWOULDBLOCK)
|
||||
} else if (_getdns_socketerror_wants_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_socketerror_wants_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);
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
|
|
@ -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_socketerror_wants_retry())
|
||||
return;
|
||||
|
||||
DEBUG_SCHED("I/O error with select(): %s\n", _getdns_errnostr());
|
||||
return;
|
||||
}
|
||||
#ifdef USE_WINSOCK
|
||||
}
|
||||
|
|
111
src/platform.c
111
src/platform.c
|
@ -59,6 +59,113 @@ 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 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)errnum);
|
||||
return unknown;
|
||||
}
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
void _getdns_perror(const char *str)
|
||||
|
@ -66,4 +173,8 @@ void _getdns_perror(const char *str)
|
|||
perror(str);
|
||||
}
|
||||
|
||||
const char *_getdns_strerror(int errnum)
|
||||
{
|
||||
return strerror(errnum);
|
||||
}
|
||||
#endif
|
||||
|
|
|
@ -39,16 +39,27 @@
|
|||
|
||||
#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)
|
||||
#ifdef WSAENFILE
|
||||
# define _getdns_ENFILE (WSAENFILE)
|
||||
#else
|
||||
# define _getdns_ENFILE (0)
|
||||
#endif
|
||||
#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 +68,53 @@ typedef u_short sa_family_t;
|
|||
# include <poll.h>
|
||||
#endif
|
||||
|
||||
#define _getdns_EINTR (EINTR)
|
||||
#define _getdns_EAGAIN (EAGAIN)
|
||||
#ifdef EWOULDBLOCK
|
||||
#define _getdns_EWOULDBLOCK (EWOULDBLOCK)
|
||||
#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 +130,22 @@ 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_error_wants_retry(X) ( (X) != 0 \
|
||||
&& ( (X) == _getdns_EINTR \
|
||||
|| (X) == _getdns_EAGAIN \
|
||||
|| (X) == _getdns_EWOULDBLOCK \
|
||||
|| (X) == _getdns_EINPROGRESS \
|
||||
|| (X) == _getdns_ENOBUFS ))
|
||||
#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 ))
|
||||
|
||||
#endif
|
||||
|
|
52
src/server.c
52
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_socketerror_wants_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_socketerror_wants_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_socketerror_wants_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_socketerror_wants_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_socketerror_wants_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 {
|
||||
|
|
82
src/stub.c
82
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_error_wants_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_socketerror_wants_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)) ||
|
||||
if ((written == -1 && _getdns_socketerror_wants_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_socketerror_wants_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_socketerror_wants_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:
|
||||
|
@ -2064,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;
|
||||
}
|
||||
|
|
|
@ -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++;
|
||||
|
|
Loading…
Reference in New Issue