Hi all,

> > There was an irritating glitch, which I have also seen mentioned a few 
> > times 
> > online. It is that if you have mutt open, pack up your laptop, and go 
> > somewhere else, mutt is completely unresponsive and needs to be killed. I 
> > tracked down what was causing this and to my satisfaction my fix works. 
> > 
> > Would you be interested in this patch? And, if the intended behaviour is 
> > that it should hang like this, then perhaps my fix could be implemented as 
> > a 
> > config variable. (It’s basically just a simple timeout + retry mechanism in 
> > the socket_connect function).
> 
> Please go ahead and post your patch, either to this list, or perhaps to
> a ticket.  It looks like http://dev.mutt.org/trac/ticket/3369 or
> http://dev.mutt.org/trac/ticket/3491 might be related.
> 
> Most of the committers are quite busy right now, so it may take a while
> to get a response.

Attached is my patch for the hanging socket problem.

I hope this fixes 3369 and 3491, which indeed sound very similar to the 
problem I reported.

All comments welcome.

I used hg export against the tip of the default branch to produce the diff; 
please let me know if you would rather have it another way.

> 
> > Also, you’ve probably talked about this many times before, but is there a 
> > reason not to implement a config option to call a command when there is new 
> > mail? 
> 
> Yoshiki Vazquez Baeza posted a patch for this a couple months ago, and
> David Champion is incorporating it into a related patch set.
> 

Yours, Allen
# HG changeset patch
# User misterfish <al...@netherrealm.net>
# Date 1430247531 -7200
#      Tue Apr 28 20:58:51 2015 +0200
# Node ID 65d3b99e229cefaec62e8205fec116a7c00fce72
# Parent  755a18da99bc0a57bd6e462f5971eba7b9f61604
Fix bug where mutt hangs indefinitely when, for example, you pack up your
laptop and open it again somewhere else.

Introduce a timeout on sockets ("socket_timeout" in muttrc, default 5
seconds) and a fixed number of retries for GNUTLS ("ssl_socket_num_tries" in
muttrc, default is 2).

Hopefully fixes #3369 and #3491.

diff -r 755a18da99bc -r 65d3b99e229c globals.h
--- a/globals.h Sat Apr 25 19:00:13 2015 -0700
+++ b/globals.h Tue Apr 28 20:58:51 2015 +0200
@@ -193,6 +193,8 @@
 WHERE unsigned short Counter INITVAL (0);
 
 WHERE short ConnectTimeout;
+WHERE short SocketTimeout;
+WHERE short GNUTLSSocketNumTries;
 WHERE short HistSize;
 WHERE short MenuContext;
 WHERE short PagerContext;
diff -r 755a18da99bc -r 65d3b99e229c init.h
--- a/init.h    Sat Apr 25 19:00:13 2015 -0700
+++ b/init.h    Tue Apr 28 20:58:51 2015 +0200
@@ -2888,6 +2888,14 @@
   ** variable.
   */
 #endif /* USE_SMTP */
+  { "socket_timeout", DT_NUM, R_NONE, UL &SocketTimeout, 5 },
+  /*
+  ** .pp
+  ** Close inactive sockets after this many seconds. When set to zero or a
+  ** negative value, mutt will wait indefinitely on sockets, but be warned
+  ** that this can cause mutt to hang. If using GNUTLS, you must also set
+  ** $$ssl_socket_num_tries to a non-zero value.
+  */
   { "sort",            DT_SORT, R_INDEX|R_RESORT, UL &Sort, SORT_DATE },
   /*
   ** .pp
@@ -3025,6 +3033,15 @@
   ** for use in any Diffie-Hellman key exchange. A value of 0 will use
   ** the default from the GNUTLS library.
   */
+  { "ssl_socket_num_tries", DT_NUM, R_NONE, UL &GNUTLSSocketNumTries, 2 },
+  /*
+  ** .pp
+  ** When using GNUTLS, this can be used in conjunction with
+  ** $$socket_timeout to cause the mailbox to close after the socket has
+  ** timed out this many times. If set to zero or a negative number, the
+  ** socket will wait for data indefinitely, but be aware that this can
+  ** cause mutt to hang.
+  */
 # endif /* USE_SSL_GNUTLS */
   { "ssl_starttls", DT_QUAD, R_NONE, OPT_SSLSTARTTLS, M_YES },
   /*
diff -r 755a18da99bc -r 65d3b99e229c mutt_socket.c
--- a/mutt_socket.c     Sat Apr 25 19:00:13 2015 -0700
+++ b/mutt_socket.c     Tue Apr 28 20:58:51 2015 +0200
@@ -344,6 +344,7 @@
 {
   int sa_size;
   int save_errno;
+  struct timeval socket_timeout_tv = {0};
 
   if (sa->sa_family == AF_INET)
     sa_size = sizeof (struct sockaddr_in);
@@ -364,6 +365,28 @@
 
   save_errno = 0;
 
+  /* Set a timeout on the socket. 
+   * Can be set to 0 for no timeout, but then, mutt can hang forever waiting
+   * for data.
+   * For OpenSSL this is enough to avoid hanging, but with GNUTLS,
+   * ssl_socket_num_tries must also be set in the config.
+   */
+
+  if (SocketTimeout > 0) {
+    socket_timeout_tv.tv_sec = SocketTimeout;
+    if (setsockopt(fd, 
+      SOL_SOCKET,         /* protocol level */
+      SO_RCVTIMEO,        /* optname */
+      &socket_timeout_tv, /* const void *optval */
+      sizeof(struct timeval)
+    )) 
+    {
+      mutt_perror(_("Couldn't set socket_timeout"));
+      mutt_sleep(3);
+      return -1;
+    }
+  }
+
   if (connect (fd, sa, sa_size) < 0)
   {
       save_errno = errno;
diff -r 755a18da99bc -r 65d3b99e229c mutt_ssl_gnutls.c
--- a/mutt_ssl_gnutls.c Sat Apr 25 19:00:13 2015 -0700
+++ b/mutt_ssl_gnutls.c Tue Apr 28 20:58:51 2015 +0200
@@ -131,6 +131,7 @@
 {
   tlssockdata *data = conn->sockdata;
   int ret;
+  int try = 0;
 
   if (!data)
   {
@@ -139,7 +140,20 @@
     return -1;
   }
 
+  /* When the socket times out, ret is GNUTLS_E_AGAIN. 
+   * When socket_timeout (SocketTimeout) is 0, the socket is set to
+   * blocking, and this will hang forever on gnutls_record_recv.
+   * If the timeout is set, but ssl_socket_num_tries (GNUTLSSocketNumTries)
+   * is equal to zero or a negative value, this will become an infinite loop
+   * and mutt will hang.
+   */
+
   do {
+    if (GNUTLSSocketNumTries > 0 && ++try > GNUTLSSocketNumTries) {
+      mutt_error(_("Timed out reading from socket, closing mailbox."));
+      mutt_sleep(2);
+      return -1;
+    }
     ret = gnutls_record_recv (data->state, buf, len);
     if (ret < 0 && gnutls_error_is_fatal(ret) == 1)
     {

Attachment: signature.asc
Description: Digital signature

Reply via email to