malware: use sendfile for ClamAV TCP
authorJeremy Harris <jgh146exb@wizmail.org>
Sun, 17 Jan 2021 20:42:10 +0000 (20:42 +0000)
committerJeremy Harris <jgh146exb@wizmail.org>
Sun, 17 Jan 2021 20:54:18 +0000 (20:54 +0000)
src/src/malware.c

index abe627ded3a7e537c61e32985068579236ec0472..7c134d7597e8baaa2d9fd8b128c71ad0d42aedb7 100644 (file)
@@ -1559,10 +1559,7 @@ badseek:  err = errno;
       if (!use_scan_command)
        { cmd_str.data = US"zINSTREAM"; cmd_str.len = 10; }
       else
-       {
-       cmd_str.data = string_sprintf("SCAN %s\n", eml_filename);
-       cmd_str.len = Ustrlen(cmd_str.data);
-       }
+       cmd_str.data = string_sprintf("SCAN %s\n%n", eml_filename, &cmd_str.len);
 
       /* We have some network servers specified */
       if (num_servers)
@@ -1583,13 +1580,14 @@ badseek:  err = errno;
          on both connections (as one host could resolve to multiple ips) */
          for (;;)
            {
-           /*XXX we trust that the cmd_str is ideempotent */
+           /*XXX we trust that the cmd_str is idempotent */
            if ((malware_daemon_ctx.sock = m_tcpsocket(cd->hostspec, cd->tcp_port,
-                                   &connhost, &errstr, &cmd_str)) >= 0)
+                                   &connhost, &errstr,
+                                   use_scan_command ? &cmd_str : NULL)) >= 0)
              {
              /* Connection successfully established with a server */
              hostname = cd->hostspec;
-             cmd_str.len = 0;
+             if (use_scan_command) cmd_str.len = 0;
              break;
              }
            if (cd->retry <= 0) break;
@@ -1630,17 +1628,21 @@ badseek:  err = errno;
       if (!use_scan_command)
        {
        struct stat st;
-#ifdef EXIM_TCP_CORK
+#if defined(EXIM_TCP_CORK) && !defined(OS_SENDFILE)
        BOOL corked = TRUE;
 #endif
        /* New protocol: "zINSTREAM\n" followed by a sequence of <length><data>
        chunks, <n> a 4-byte number (network order), terminated by a zero-length
-       chunk. */
+       chunk. We only send one chunk. */
 
        DEBUG(D_acl) debug_printf_indent(
            "Malware scan: issuing %s new-style remote scan (zINSTREAM)\n",
            scanner_name);
 
+#if defined(EXIM_TCP_CORK)
+       (void) setsockopt(malware_daemon_ctx.sock, IPPROTO_TCP, EXIM_TCP_CORK,
+                         US &on, sizeof(on));
+#endif
        /* Pass the string to ClamAV (10 = "zINSTREAM\0"), if not already sent */
        if (cmd_str.len)
          if (send(malware_daemon_ctx.sock, cmd_str.data, cmd_str.len, 0) < 0)
@@ -1676,10 +1678,6 @@ badseek:  err = errno;
          }
 
        /* send file size */
-#ifdef EXIM_TCP_CORK
-       (void) setsockopt(malware_daemon_ctx.sock, 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,
@@ -1687,10 +1685,17 @@ badseek:  err = errno;
            malware_daemon_ctx.sock);
 
        /* send file body */
-       /*XXX sendfile? */
        while (fsize_uint)
          {
-         unsigned n = MIN(fsize_uint, big_buffer_size);
+#ifdef OS_SENDFILE
+         int n = os_sendfile(malware_daemon_ctx.sock, clam_fd, NULL, (size_t)fsize_uint);
+         if (n < 0)
+           return m_panic_defer_3(scanent, NULL,
+             string_sprintf("unable to send file body to socket (%s): %s", hostname, strerror(errno)),
+             malware_daemon_ctx.sock);
+         fsize_uint -= n;
+#else
+         int n = MIN(fsize_uint, big_buffer_size);
          if ((n = read(clam_fd, big_buffer, n)) < 0)
            return m_panic_defer_3(scanent, NULL,
              string_sprintf("can't read spool file %s: %s",
@@ -1701,14 +1706,16 @@ badseek:  err = errno;
              string_sprintf("unable to send file body to socket (%s): %s", hostname, strerror(errno)),
              malware_daemon_ctx.sock);
          fsize_uint -= n;
-#ifdef EXIM_TCP_CORK
+# ifdef EXIM_TCP_CORK
          if (corked)
            {
            corked = FALSE;
            (void) setsockopt(malware_daemon_ctx.sock, IPPROTO_TCP, EXIM_TCP_CORK,
                              US &off, sizeof(off));
            }
-#endif
+# endif
+#endif /*!OS_SENDFILE*/
+
          }
 
        send_final_zeroblock = 0;
@@ -1716,11 +1723,15 @@ 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 OS_SENDFILE
+       (void) setsockopt(malware_daemon_ctx.sock, IPPROTO_TCP, EXIM_TCP_CORK,
+                         US &off, sizeof(off));
+#endif
        }
       else
        { /* use scan command */
        /* Send a SCAN command pointing to a filename; then in the then in the
-        * scan-method-neutral part, read the response back */
+       scan-method-neutral part, read the response back */
 
 /* ================================================================= */