FreeBSD: packet coalescing
[exim.git] / src / src / malware.c
index 2883f225af4b7c526940c530ad65583f4a790ebc..b581a87524bd66bf36e01945f4cd600e99d6d68b 100644 (file)
@@ -132,7 +132,6 @@ static const uschar * malware_regex_default = US ".+";
 static const pcre * malware_default_re = NULL;
 
 
-
 #ifndef DISABLE_MAL_CLAM
 /* The maximum number of clamd servers that are supported in the configuration */
 # define MAX_CLAMD_SERVERS 32
@@ -272,8 +271,19 @@ static inline int
 m_tcpsocket(const uschar * hostname, unsigned int port,
        host_item * host, uschar ** errstr, const blob * fastopen_blob)
 {
-return ip_connectedsocket(SOCK_STREAM, hostname, port, port, 5,
+int fd = ip_connectedsocket(SOCK_STREAM, hostname, port, port, 5,
                          host, errstr, fastopen_blob);
+#ifdef EXIM_TFO_FREEBSD
+/* Under some fault conditions, FreeBSD 12.2 seen to send a (non-TFO) SYN
+and, getting no response, wait for a long time.  Impose a 5s max. */
+if (fd >= 0)
+  {
+  struct timeval tv = {.tv_sec = 5};
+  fd_set fds;
+  FD_ZERO(fds); FD_SET(fd, &fds); (void) select(fd+1, NULL, &fds, NULL, &tv);
+  }
+#endif
+return fd;
 }
 #endif
 
@@ -1559,8 +1569,8 @@ badseek:  err = errno;
       if (num_servers)
        {
        /* Confirmed in ClamAV source (0.95.3) that the TCPAddr option of clamd
-        * only supports AF_INET, but we should probably be looking to the
-        * future and rewriting this to be protocol-independent anyway. */
+       only supports AF_INET, but we should probably be looking to the
+       future and rewriting this to be protocol-independent anyway. */
 
        while (num_servers > 0)
          {
@@ -1571,7 +1581,7 @@ badseek:  err = errno;
                         cd->hostspec, cd->tcp_port);
 
          /* Lookup the host. This is to ensure that we connect to the same IP
-          * on both connections (as one host could resolve to multiple ips) */
+         on both connections (as one host could resolve to multiple ips) */
          for (;;)
            {
            /*XXX we trust that the cmd_str is ideempotent */
@@ -1614,9 +1624,9 @@ badseek:  err = errno;
          }
 
       /* have socket in variable "sock"; command to use is semi-independent of
-       * the socket protocol.  We use SCAN if is local (either Unix/local
-       * domain socket, or explicitly told local) else we stream the data.
-       * How we stream the data depends upon how we were built.  */
+      the socket protocol.  We use SCAN if is local (either Unix/local
+      domain socket, or explicitly told local) else we stream the data.
+      How we stream the data depends upon how we were built.  */
 
       if (!use_scan_command)
        {
@@ -1663,13 +1673,17 @@ badseek:  err = errno;
            malware_daemon_ctx.sock);
          }
 
-       /* send file body to socket */
+       /* send file size */
+#ifdef EXIM_TCP_CORK
+       (void) setsockopt(clam_fd, IPPROTO_TCP, EXIM_TCP_CORK, US &on, sizeof(on));
+#endif
        send_size = htonl(fsize_uint);
        if (send(malware_daemon_ctx.sock, &send_size, sizeof(send_size), 0) < 0)
          return m_panic_defer_3(scanent, NULL,
            string_sprintf("unable to send file size to socket (%s)", hostname),
            malware_daemon_ctx.sock);
 
+       /* send file body */
        while (fsize_uint)
          {
          unsigned n = MIN(fsize_uint, big_buffer_size);
@@ -1690,6 +1704,9 @@ badseek:  err = errno;
          return m_panic_defer_3(scanent, NULL,
            string_sprintf("unable to send file terminator to socket (%s)", hostname),
            malware_daemon_ctx.sock);
+#ifdef EXIM_TCP_CORK
+       (void) setsockopt(clam_fd, IPPROTO_TCP, EXIM_TCP_CORK, US &off, sizeof(off));
+#endif
        }
       else
        { /* use scan command */
@@ -1719,10 +1736,10 @@ badseek:  err = errno;
              malware_daemon_ctx.sock);
 
        /* Do not shut down the socket for writing; a user report noted that
-        * clamd 0.70 does not react well to this. */
+       clamd 0.70 does not react well to this. */
        }
       /* Commands have been sent, no matter which scan method or connection
-       * type we're using; now just read the result, independent of method. */
+      type we're using; now just read the result, independent of method. */
 
       /* Read the result */
       memset(av_buffer, 0, sizeof(av_buffer));
@@ -1768,6 +1785,7 @@ badseek:  err = errno;
       /* strip newline at the end (won't be present for zINSTREAM)
       (also any trailing whitespace, which shouldn't exist, but we depend upon
       this below, so double-check) */
+
       p = av_buffer + Ustrlen(av_buffer) - 1;
       if (*p == '\n') *p = '\0';