[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[msmtp-users] Patches for timeout on Windows



Hi!

I've come up with some patches regarding the timeout setting on Windows
(which doesn't work right now).

The first patch correctly handles timeout on send()/recv() operations.

--- msmtp-1.6.6/src/net.c	2016-11-11 15:12:04.000000000 +0700
+++ msmtp/src/net.c	2018-06-09 18:03:35.407374256 +0700
@@ -179,7 +179,7 @@
     {
 #ifdef W32_NATIVE
         int e = WSAGetLastError();
-        if (e == WSAEWOULDBLOCK)
+        if (e == WSAETIMEDOUT)
         {
             *errstr = xasprintf(_("network read error: %s"),
                     _("the operation timed out"));
@@ -226,7 +226,7 @@
     {
 #ifdef W32_NATIVE
         int e = WSAGetLastError();
-        if (e == WSAEWOULDBLOCK)
+        if (e == WSAETIMEDOUT)
         {
             *errstr = xasprintf(_("network write error: %s"),
                     _("the operation timed out"))

The second patch implements timeout on connect() for Windows. I also removed
the unnecessary rset variable (it doesn't matter for select() on connect()).

--- msmtp-1.6.6/src/net.c	2016-11-11 15:12:04.000000000 +0700
+++ msmtp/src/net.c	2018-06-09 18:23:11.721796148 +0700
@@ -319,16 +319,17 @@
         int timeout)
 {
 #ifdef W32_NATIVE
-    /* TODO: I don't know how to do this on Win32. Please send a patch. */
-    return connect(fd, serv_addr, addrlen);
-#else /* UNIX or DJGPP */
-
+    u_long flags;
+    DWORD err;
+    int optlen;
+    fd_set eset;
+#else
     int flags;
-    struct timeval tv;
-    fd_set rset;
-    fd_set wset;
     int err;
     socklen_t optlen;
+#endif
+    struct timeval tv;
+    fd_set wset;

     if (timeout <= 0)
     {
@@ -337,8 +338,13 @@
     else
     {
         /* make socket non-blocking */
+#ifdef W32_NATIVE
+        flags = 1;
+        if (ioctlsocket(fd, FIONBIO, &flags) == SOCKET_ERROR)
+#else
         flags = fcntl(fd, F_GETFL, 0);
         if (fcntl(fd, F_SETFL, flags | O_NONBLOCK) == -1)
+#endif
         {
             return -1;
         }
@@ -346,51 +352,75 @@
         /* start connect */
         if (connect(fd, serv_addr, addrlen) < 0)
         {
+#ifdef W32_NATIVE
+            if (WSAGetLastError() != WSAEWOULDBLOCK)
+#else
             if (errno != EINPROGRESS)
+#endif
             {
                 return -1;
             }

             tv.tv_sec = timeout;
             tv.tv_usec = 0;
-            FD_ZERO(&rset);
             FD_ZERO(&wset);
-            FD_SET(fd, &rset);
             FD_SET(fd, &wset);
+#ifdef W32_NATIVE
+            FD_ZERO(&eset);
+            FD_SET(fd, &eset);
+#endif

             /* wait for connect() to finish */
-            if ((err = select(fd + 1, &rset, &wset, NULL, &tv)) <= 0)
+#ifdef W32_NATIVE
+            /* In case of an error on connect(), eset will be affected instead
+             * of wset (on Windows only). */
+            if ((err = select(fd + 1, NULL, &wset, &eset, &tv)) <= 0)
+#else
+            if ((err = select(fd + 1, NULL, &wset, NULL, &tv)) <= 0)
+#endif
             {
                 /* errno is already set if err < 0 */
                 if (err == 0)
                 {
+#ifdef W32_NATIVE
+                    WSASetLastError(WSAETIMEDOUT);
+#else
                     errno = ETIMEDOUT;
+#endif
                 }
                 return -1;
             }

             /* test for success, set errno */
-            optlen = sizeof(int);
+            optlen = sizeof(err);
             if (getsockopt(fd, SOL_SOCKET, SO_ERROR, &err, &optlen) < 0)
             {
                 return -1;
             }
             if (err != 0)
             {
+#ifdef W32_NATIVE
+                WSASetLastError(err);
+#else
                 errno = err;
+#endif
                 return -1;
             }
         }

         /* restore blocking mode */
+#ifdef W32_NATIVE
+        flags = 0;
+        if (ioctlsocket(fd, FIONBIO, &flags) == SOCKET_ERROR)
+#else
         if (fcntl(fd, F_SETFL, flags) == -1)
+#endif
         {
             return -1;
         }

         return 0;
     }
-#endif /* UNIX */
 }

And the third patch just closes Windows sockets properly.

--- msmtp-1.6.6/src/net.c   2016-11-11 15:12:04.000000000 +0700
+++ msmtp/src/net.c	2018-06-09 18:38:52.920735844 +0700
@@ -682,7 +712,7 @@
                 failure_errno = errno;
             }
 #endif
-            close(fd);
+            net_close_socket(fd);
             fd = -1;
             continue;
         }

I've tested the patches mildly on both Windows 7 and Wine.