[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.
>