On Mon, Nov 28, 2022 at 11:24:13PM -0800, Matthew Sotoudeh via Mutt-dev wrote:
> On an unreliable connection (e.g., laptop put to sleep and changing wifi
> networks) I've had mutt fairly regularly become stuck in SSL_read and
> have to be killed.
> 
> Per some of the comments on
> https://stackoverflow.com/questions/46517875/ssl-read-blocks-indefinitely
> adding a timeout to the socket should carry over to the SSL_read call.
> 
> Using this receive_timeout option appears to resolve the issue for me,
> thought others may find it useful.
> 
> Signed-off-by: Matthew Sotoudeh <matt...@masot.net>

Thanks, Matthew. Looks good other than 1 suggestion below.

Acked-by: David Vernet <v...@manifault.com>

> ---
> 
> Thanks for the great tips! Hope this is a bit nicer formatted :)
> (Also, happy to move to gitlab if preferable & more changes desired for
> this. Sent here just bc doc/devel-notes.txt suggested.)
> 
> Changelog per recent David/Kevin suggestions:
>     * move setsockopt to right before the connect
>     * check return value of setsockopt, log the error if it fails
> 
>  globals.h     | 1 +
>  init.h        | 7 +++++++
>  mutt_socket.c | 8 ++++++++
>  3 files changed, 16 insertions(+)
> 
> diff --git a/globals.h b/globals.h
> index 06ce410e..b782114e 100644
> --- a/globals.h
> +++ b/globals.h
> @@ -236,6 +236,7 @@ WHERE short PagerContext;
>  WHERE short PagerIndexLines;
>  WHERE short PagerSkipQuotedContext;
>  WHERE short ReadInc;
> +WHERE short ReceiveTimeout;
>  WHERE short ReflowWrap;
>  WHERE short SaveHist;
>  WHERE short SendmailWait;
> diff --git a/init.h b/init.h
> index e160d3d3..e268d796 100644
> --- a/init.h
> +++ b/init.h
> @@ -3221,6 +3221,13 @@ struct option_t MuttVars[] = {
>    ** .pp
>    ** Also see $$postponed variable.
>    */
> +  { "receive_timeout",  DT_NUM, R_NONE, {.p=&ReceiveTimeout}, {.l=0} },
> +  /*
> +  ** .pp
> +  ** Causes Mutt to timeout any socket read operation (e.g. SSL_read) after
> +  ** this many seconds.  A zero (default) or negative value causes Mutt to 
> wait
> +  ** indefinitely for the read to complete.
> +  */
>    { "record",                DT_PATH, R_NONE, {.p=&Outbox}, {.p="~/sent"} },
>    /*
>    ** .pp
> diff --git a/mutt_socket.c b/mutt_socket.c
> index 3e192072..9468319e 100644
> --- a/mutt_socket.c
> +++ b/mutt_socket.c
> @@ -433,6 +433,14 @@ static int socket_connect (int fd, struct sockaddr* sa)
>  
>    save_errno = 0;
>  
> +  if (ReceiveTimeout > 0)
> +  {
> +    struct timeval tv = { ReceiveTimeout, 0 };
> +    if (setsockopt (fd, SOL_SOCKET, SO_RCVTIMEO, (char *)&tv, sizeof(tv)) < 
> 0)

I personally don't think the < 0 is necessary here. setsockopt() fails
on any non-zero return value. connect() checks < 0 though, so it's
probably fine to leave it as is to match the rest of the code.

> +      dprint (1, (debugfile, "socket_connect: error setting receive timeout 
> (%s)\n",
> +                  strerror(errno)));
> +  }
> +
>    if (connect (fd, sa, sa_size) < 0)
>    {
>      save_errno = errno;
> -- 
> 2.34.1
> 

Reply via email to