summaryrefslogtreecommitdiff
path: root/ares_process.c
diff options
context:
space:
mode:
authorDaniel Stenberg <daniel@haxx.se>2005-06-02 11:58:04 +0000
committerDaniel Stenberg <daniel@haxx.se>2005-06-02 11:58:04 +0000
commit4e9c5b2dbb6b30b2662a70d9756d717d63475df8 (patch)
tree1557100c90922cff0a4ab212a4c13d97bbef357e /ares_process.c
parentae75ee14234b6d1b22832081d7dbd1d281c955cb (diff)
downloadc-ares-4e9c5b2dbb6b30b2662a70d9756d717d63475df8.tar.gz
c-ares-4e9c5b2dbb6b30b2662a70d9756d717d63475df8.tar.bz2
c-ares-4e9c5b2dbb6b30b2662a70d9756d717d63475df8.zip
William Ahern:
Make UDP sockets non-blocking. I've confirmed that at least on Linux 2.4 a read event can come back from poll() on a valid SOCK_DGRAM socket but recv(2) will still block. This patch doesn't ignore EAGAIN in read_udp_packets(), though maybe it should. (This patch was edited by Daniel Stenberg and a new configure test was added (imported from curl's configure) to properly detect what non-blocking socket approach to use.)
Diffstat (limited to 'ares_process.c')
-rw-r--r--ares_process.c94
1 files changed, 71 insertions, 23 deletions
diff --git a/ares_process.c b/ares_process.c
index 15d3726..a1e16af 100644
--- a/ares_process.c
+++ b/ares_process.c
@@ -466,13 +466,76 @@ void ares__send_query(ares_channel channel, struct query *query, time_t now)
}
}
-static int open_tcp_socket(ares_channel channel, struct server_state *server)
+/*
+ * nonblock() set the given socket to either blocking or non-blocking mode
+ * based on the 'nonblock' boolean argument. This function is highly portable.
+ */
+static int nonblock(ares_socket_t sockfd, /* operate on this */
+ int nonblock /* TRUE or FALSE */)
{
-#if defined(WIN32)
- u_long flags;
-#else
+#undef SETBLOCK
+#define SETBLOCK 0
+#ifdef HAVE_O_NONBLOCK
+ /* most recent unix versions */
+ int flags;
+
+ flags = fcntl(sockfd, F_GETFL, 0);
+ if (TRUE == nonblock)
+ return fcntl(sockfd, F_SETFL, flags | O_NONBLOCK);
+ else
+ return fcntl(sockfd, F_SETFL, flags & (~O_NONBLOCK));
+#undef SETBLOCK
+#define SETBLOCK 1
+#endif
+
+#if defined(HAVE_FIONBIO) && (SETBLOCK == 0)
+ /* older unix versions */
int flags;
+
+ flags = nonblock;
+ return ioctl(sockfd, FIONBIO, &flags);
+#undef SETBLOCK
+#define SETBLOCK 2
+#endif
+
+#if defined(HAVE_IOCTLSOCKET) && (SETBLOCK == 0)
+ /* Windows? */
+ unsigned long flags;
+ flags = nonblock;
+
+ return ioctlsocket(sockfd, FIONBIO, &flags);
+#undef SETBLOCK
+#define SETBLOCK 3
+#endif
+
+#if defined(HAVE_IOCTLSOCKET_CASE) && (SETBLOCK == 0)
+ /* presumably for Amiga */
+ return IoctlSocket(sockfd, FIONBIO, (long)nonblock);
+#undef SETBLOCK
+#define SETBLOCK 4
+#endif
+
+#if defined(HAVE_SO_NONBLOCK) && (SETBLOCK == 0)
+ /* BeOS */
+ long b = nonblock ? 1 : 0;
+ return setsockopt(sockfd, SOL_SOCKET, SO_NONBLOCK, &b, sizeof(b));
+#undef SETBLOCK
+#define SETBLOCK 5
+#endif
+
+#ifdef HAVE_DISABLED_NONBLOCKING
+ return 0; /* returns success */
+#undef SETBLOCK
+#define SETBLOCK 6
+#endif
+
+#if (SETBLOCK == 0)
+#error "no non-blocking method was found/used/set"
#endif
+}
+
+static int open_tcp_socket(ares_channel channel, struct server_state *server)
+{
ares_socket_t s;
struct sockaddr_in sockin;
@@ -482,25 +545,7 @@ static int open_tcp_socket(ares_channel channel, struct server_state *server)
return -1;
/* Set the socket non-blocking. */
-
-#if defined(WIN32) || defined(WATT32)
- flags = 1;
- ioctlsocket(s, FIONBIO, &flags);
-#else
- flags = fcntl(s, F_GETFL, 0);
-
- if (flags == -1)
- {
- closesocket(s);
- return -1;
- }
- flags |= O_NONBLOCK;
- if (fcntl(s, F_SETFL, flags) == -1)
- {
- closesocket(s);
- return -1;
- }
-#endif
+ nonblock(s, TRUE);
/* Connect to the server. */
memset(&sockin, 0, sizeof(sockin));
@@ -531,6 +576,9 @@ static int open_udp_socket(ares_channel channel, struct server_state *server)
if (s == ARES_SOCKET_BAD)
return -1;
+ /* Set the socket non-blocking. */
+ nonblock(s, TRUE);
+
/* Connect to the server. */
memset(&sockin, 0, sizeof(sockin));
sockin.sin_family = AF_INET;