WIP: refactor socket/ip connections
authorJeremy Harris <jgh146exb@wizmail.org>
Sat, 8 Feb 2014 13:24:29 +0000 (13:24 +0000)
committerJeremy Harris <jgh146exb@wizmail.org>
Sat, 8 Feb 2014 13:24:29 +0000 (13:24 +0000)
src/src/acl.c
src/src/expand.c
src/src/functions.h
src/src/ip.c
src/src/malware.c

index 29e0617d9565f2c6862a00accc2a51c055178bde..89932bbf1e5a5481b4892d2e467ff7ea17434f3f 100644 (file)
@@ -2846,9 +2846,9 @@ uschar *portstr;
 uschar *portend;
 host_item *h;
 int portnum;
-int host_af;
 int len;
 int r, s;
+uschar * errstr;
 
 hostname = string_nextinlist(&arg, &sep, NULL, 0);
 portstr = string_nextinlist(&arg, &sep, NULL, 0);
@@ -2895,14 +2895,17 @@ if (r == HOST_FIND_FAILED || r == HOST_FIND_AGAIN)
 HDEBUG(D_acl)
   debug_printf("udpsend [%s]:%d %s\n", h->address, portnum, arg);
 
-host_af = (Ustrchr(h->address, ':') == NULL)? AF_INET:AF_INET6;
-r = s = ip_socket(SOCK_DGRAM, host_af);
-if (r < 0) goto defer;
-r = ip_connect(s, host_af, h->address, portnum, 1);
+r = s = ip_connectedsocket(SOCK_DGRAM, h_address, portnum, 1, &errstr);
 if (r < 0) goto defer;
 len = Ustrlen(arg);
 r = send(s, arg, len, 0);
-if (r < 0) goto defer;
+if (r < 0)
+  {
+  errstr = strerror(errno);
+  close(s);
+  goto defer;
+  }
+close(s);
 if (r < len)
   {
   *log_msgptr =
@@ -2916,7 +2919,7 @@ HDEBUG(D_acl)
 return OK;
 
 defer:
-*log_msgptr = string_sprintf("\"udpsend\" failed: %s", strerror(errno));
+*log_msgptr = string_sprintf("\"udpsend\" failed: %s", errstr);
 return DEFER;
 }
 
index 7e1b32343050182980b40062f3b155ed8e18b25a..a47cc0d64ca2db7516bd2a5fc69c8038d9fb9039 100644 (file)
@@ -4537,76 +4537,9 @@ while (*s != 0)
             port = ntohs(service_info->s_port);
             }
 
-          /* Sort out the server. */
-
-          shost.next = NULL;
-          shost.address = NULL;
-          shost.port = port;
-          shost.mx = -1;
-
-          namelen = Ustrlen(server_name);
-
-          /* Anything enclosed in [] must be an IP address. */
-
-          if (server_name[0] == '[' &&
-              server_name[namelen - 1] == ']')
-            {
-            server_name[namelen - 1] = 0;
-            server_name++;
-            if (string_is_ip_address(server_name, NULL) == 0)
-              {
-              expand_string_message =
-                string_sprintf("malformed IP address \"%s\"", server_name);
-              goto EXPAND_FAILED;
-              }
-            shost.name = shost.address = server_name;
-            }
-
-          /* Otherwise check for an unadorned IP address */
-
-          else if (string_is_ip_address(server_name, NULL) != 0)
-            shost.name = shost.address = server_name;
-
-          /* Otherwise lookup IP address(es) from the name */
-
-          else
-            {
-            shost.name = server_name;
-            if (host_find_byname(&shost, NULL, HOST_FIND_QUALIFY_SINGLE, NULL,
-                FALSE) != HOST_FOUND)
-              {
-              expand_string_message =
-                string_sprintf("no IP address found for host %s", shost.name);
-              goto EXPAND_FAILED;
-              }
-            }
-
-          /* Try to connect to the server - test each IP till one works */
-
-          for (h = &shost; h != NULL; h = h->next)
-            {
-            int af = (Ustrchr(h->address, ':') != 0)? AF_INET6 : AF_INET;
-            if ((fd = ip_socket(SOCK_STREAM, af)) == -1)
-              {
-              expand_string_message = string_sprintf("failed to create socket: "
-                "%s", strerror(errno));
+         if ((fd = ip_connectedsocket(SOCK_STREAM, server_name, port, port,
+                 timeout, &expand_string_message)) < 0)
               goto SOCK_FAIL;
-              }
-
-            if (ip_connect(fd, af, h->address, port, timeout) == 0)
-              {
-              connected = TRUE;
-              break;
-              }
-            }
-
-          if (!connected)
-            {
-            expand_string_message = string_sprintf("failed to connect to "
-              "socket %s: couldn't connect to any host", sub_arg[0],
-              strerror(errno));
-            goto SOCK_FAIL;
-            }
           }
 
         /* Handle a Unix domain socket */
index 9d933fea77b37e09092ac3a0d58d3fab6ea4f9be..574675f480ae5454af74bfd37b7dc9be249e37f7 100644 (file)
@@ -171,6 +171,8 @@ extern int     host_scan_for_local_hosts(host_item *, host_item **, BOOL *);
 extern void    invert_address(uschar *, uschar *);
 extern int     ip_bind(int, int, uschar *, int);
 extern int     ip_connect(int, int, uschar *, int, int);
+extern int     ip_connected_socket(int, const uschar *, int, int, int,
+                 uschar **);
 extern int     ip_get_address_family(int);
 extern void    ip_keepalive(int, uschar *, BOOL);
 extern int     ip_recv(int, uschar *, int, int);
index ae629b0513d47a577e407f218f954630c43e9fff..b5feaf0d45748d4a3161797e41d6151eefce7589 100644 (file)
@@ -172,7 +172,7 @@ Arguments:
   af          AF_INET6 or AF_INET for the socket type
   address     the remote address, in text form
   port        the remote port
-  timeout     a timeout
+  timeout     a timeout (zero for indefinite timeout)
 
 Returns:      0 on success; -1 on failure, with errno set
 */
@@ -248,6 +248,98 @@ return -1;
 }
 
 
+/*
+Arguments:
+  type          SOCK_DGRAM or SOCK_STREAM
+  af            AF_INET6 or AF_INET for the socket type
+  address       the remote address, in text form
+  portlo,porthi the remote port range
+  timeout       a timeout
+  errstr        pointer for allocated string on error
+
+Return:
+  socket fd, or -1 on failure (having allocated an error string)
+*/
+int
+ip_connectedsocket(int type, const uschar * hostname, int portlo, int porthi,
+       int timeout, uschar ** errstr)
+{
+int namelen, port;
+host_item shost;
+host_item *h;
+int fd, fd4 = -1, fd6 = -1;
+
+shost.next = NULL;
+shost.address = NULL;
+shost.port = port;
+shost.mx = -1;
+
+namelen = Ustrlen(hostname);
+
+/* Anything enclosed in [] must be an IP address. */
+
+if (hostname[0] == '[' &&
+    hostname[namelen - 1] == ']')
+  {
+  uschar * host = string_copy(hostname);
+  host[namelen - 1] = 0;
+  host++;
+  if (string_is_ip_address(host, NULL) == 0)
+    {
+    *errstr = string_sprintf("malformed IP address \"%s\"", hostname);
+    return -1;
+    }
+  shost.name = shost.address = host;
+  }
+
+/* Otherwise check for an unadorned IP address */
+
+else if (string_is_ip_address(hostname, NULL) != 0)
+  shost.name = shost.address = hostname;
+
+/* Otherwise lookup IP address(es) from the name */
+
+else
+  {
+  shost.name = hostname;
+  if (host_find_byname(&shost, NULL, HOST_FIND_QUALIFY_SINGLE, NULL,
+      FALSE) != HOST_FOUND)
+    {
+    *errstr = string_sprintf("no IP address found for host %s", shost.name);
+    return -1;
+    }
+  }
+
+/* Try to connect to the server - test each IP till one works */
+
+for (h = &shost; h != NULL; h = h->next)
+  {
+  fd = (Ustrchr(h->address, ':') != 0)
+    ? (fd6 < 0) ? (fd6 = ip_socket(SOCK_STREAM, AF_INET6)) : fd6
+    : (fd4 < 0) ? (fd4 = ip_socket(SOCK_STREAM, AF_INET )) : fd4;
+
+  if (fd < 0)
+    {
+    *errstr = string_sprintf("failed to create socket: %s", strerror(errno));
+    goto bad;
+    }
+
+  for(port = portlo, port <= porthi; port++)
+    if (ip_connect(fd, af, h->address, port, timeout) == 0)
+      {
+      if (fd != fd6) close(fd6);
+      if (fd != fd4) close(fd4);
+      return fd;
+      }
+  }
+
+*errstr = string_sprintf("failed to connect to "
+  "%s: couldn't connect to any host", hostname, strerror(errno));
+
+bad:
+  close(fd4); close(fd6); return -1;
+}
+
 
 /*************************************************
 *         Set keepalive on a socket              *
index ba62e103b0cd05d4d02ccb12136f90cd0a15afef..9a822fdc21e554066d152c4da212f915e585f4ec 100644 (file)
@@ -237,6 +237,7 @@ m_streamsocket(const uschar * hostname, struct in_addr * inp, uschar ** errstr)
     *errstr = string_sprintf("failed to lookup host '%s'", hostname);
     return -1;
   }
+/*XXX will fail for ipv6 */
   *inp = *(struct in_addr *) he->h_addr_list[0];
 
   /* Create the TCP socket */
@@ -270,10 +271,7 @@ m_tcpsocket_fromdef(const uschar * hostport, uschar ** errstr)
 {
   int scan;
   uschar hostname[256];
-  unsigned int port, portlow, porthigh;
-  struct hostent * he;
-  struct in_addr in;
-  int sock;
+  unsigned int portlow, porthigh;
 
   /* extract host and port part */
   scan = sscanf(CS hostport, "%255s %u-%u", hostname, &portlow, &porthigh);
@@ -285,18 +283,8 @@ m_tcpsocket_fromdef(const uschar * hostport, uschar ** errstr)
     porthigh = portlow;
   }
 
-  if ((sock = m_streamsocket(hostname, &in, errstr)) < 0)
-    return -1;
-
-  /* Try to connect to all ports low-high until connection is established */
-  for (port = portlow; port <= porthigh; port++)
-    if (ip_connect(sock, AF_INET, (uschar*)inet_ntoa(in), port, 5) >= 0)
-      return sock;
-
-  *errstr = string_sprintf("connection to %s, port %u-%u failed (%s)",
-                     inet_ntoa(in), portlow, porthigh, strerror(errno));
-  (void)close(sock);
-  return -1;
+  return ip_connectedsocket(SOCK_STREAM, hostname, portlow, porthigh,
+                           5, errstr);
 }
 
 static int