Support a few more socket options, and refactor the option setting a bit. (Patch...
authorSteinar H. Gunderson <sesse@google.com>
Fri, 28 Sep 2007 15:15:39 +0000 (15:15 +0000)
committerSteinar H. Gunderson <sesse@google.com>
Fri, 28 Sep 2007 15:15:39 +0000 (15:15 +0000)
ares/ares.h
ares/ares_init.c
ares/ares_process.c

index 50ce7f8..03b6a92 100644 (file)
@@ -98,6 +98,8 @@ extern "C" {
 #define ARES_OPT_LOOKUPS        (1 << 8)
 #define ARES_OPT_SOCK_STATE_CB  (1 << 9)
 #define ARES_OPT_SORTLIST       (1 << 10)
+#define ARES_OPT_SOCK_SNDBUF    (1 << 11)
+#define ARES_OPT_SOCK_RCVBUF    (1 << 12)
 
 /* Nameinfo flag values */
 #define ARES_NI_NOFQDN                  (1 << 0)
@@ -177,6 +179,8 @@ struct ares_options {
   int ndots;
   unsigned short udp_port;
   unsigned short tcp_port;
+  int socket_send_buffer_size;
+  int socket_receive_buffer_size;
   struct in_addr *servers;
   int nservers;
   char **domains;
index 298dd7b..6c36d6e 100644 (file)
@@ -133,6 +133,8 @@ int ares_init_options(ares_channel *channelptr, struct ares_options *options,
   channel->ndots = -1;
   channel->udp_port = -1;
   channel->tcp_port = -1;
+  channel->socket_send_buffer_size = -1;
+  channel->socket_receive_buffer_size = -1;
   channel->nservers = -1;
   channel->ndomains = -1;
   channel->nsort = -1;
@@ -320,6 +322,12 @@ static int init_by_options(ares_channel channel,
       channel->sock_state_cb = options->sock_state_cb;
       channel->sock_state_cb_data = options->sock_state_cb_data;
     }
+  if ((optmask & ARES_OPT_SOCK_SNDBUF)
+      && channel->socket_send_buffer_size == -1)
+    channel->socket_send_buffer_size = options->socket_send_buffer_size;
+  if ((optmask & ARES_OPT_SOCK_RCVBUF)
+      && channel->socket_receive_buffer_size == -1)
+    channel->socket_receive_buffer_size = options->socket_receive_buffer_size;
 
   /* Copy the servers, if given. */
   if ((optmask & ARES_OPT_SERVERS) && channel->nservers == -1)
index d359b11..1db3d11 100644 (file)
@@ -25,6 +25,7 @@
 #ifdef HAVE_SYS_UIO_H
 #include <sys/uio.h>
 #endif
+#include <netinet/tcp.h>   /* for TCP_NODELAY */
 #include <netinet/in.h>
 #include <netdb.h>
 #include <arpa/nameser.h>
@@ -732,9 +733,36 @@ static int nonblock(ares_socket_t sockfd,    /* operate on this */
 #endif
 }
 
+static int configure_socket(int s, ares_channel channel)
+{
+  nonblock(s, TRUE);
+
+#ifdef FD_CLOEXEC
+  /* Configure the socket fd as close-on-exec. */
+  if (fcntl(s, F_SETFD, FD_CLOEXEC) == -1)
+    return -1;
+#endif
+
+  /* Set the socket's send and receive buffer sizes. */
+  if ((channel->socket_send_buffer_size > 0) &&
+      setsockopt(s, SOL_SOCKET, SO_SNDBUF,
+                 &channel->socket_send_buffer_size,
+                 sizeof(channel->socket_send_buffer_size)) == -1)
+    return -1;
+       
+  if ((channel->socket_receive_buffer_size > 0) &&
+      setsockopt(s, SOL_SOCKET, SO_RCVBUF,
+                 &channel->socket_receive_buffer_size,
+                 sizeof(channel->socket_receive_buffer_size)) == -1)
+    return -1;
+
+  return 0;
+ } 
+
 static int open_tcp_socket(ares_channel channel, struct server_state *server)
 {
   ares_socket_t s;
+  int opt;
   struct sockaddr_in sockin;
 
   /* Acquire a socket. */
@@ -742,8 +770,25 @@ static int open_tcp_socket(ares_channel channel, struct server_state *server)
   if (s == ARES_SOCKET_BAD)
     return -1;
 
-  /* Set the socket non-blocking. */
-  nonblock(s, TRUE);
+  /* Configure it. */
+  if (configure_socket(s, channel) < 0)
+    {
+       close(s);
+       return -1;
+    }
+
+  /*
+   * Disable the Nagle algorithm (only relevant for TCP sockets, and thus not in
+   * configure_socket). In general, in DNS lookups we're pretty much interested
+   * in firing off a single request and then waiting for a reply, so batching
+   * isn't very interesting in general.
+   */
+  opt = 1;
+  if (setsockopt(s, IPPROTO_TCP, TCP_NODELAY, &opt, sizeof(opt)) == -1)
+    {
+       close(s);
+       return -1;
+    }
 
   /* Connect to the server. */
   memset(&sockin, 0, sizeof(sockin));
@@ -777,7 +822,11 @@ static int open_udp_socket(ares_channel channel, struct server_state *server)
     return -1;
 
   /* Set the socket non-blocking. */
-  nonblock(s, TRUE);
+  if (configure_socket(s, channel) < 0)
+    {
+       close(s);
+       return -1;
+    }
 
   /* Connect to the server. */
   memset(&sockin, 0, sizeof(sockin));