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

Re: [msmtp-users] Patches for timeout on Windows



Hi!

Thanks for your contribution, I applied all three patches and they will
be in the next release soon.

Regards
Martin

On Sat, 9 Jun 2018 12:12:40 +0000, Konst Mayer wrote:
> 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.
>