changeset: 7111:908bea74acef
user:      Kevin McCarthy <ke...@8t8.us>
date:      Sat Jul 22 19:48:49 2017 -0700
link:      http://dev.mutt.org/hg/mutt/rev/908bea74acef

Add timeout parameter to mutt_socket_poll.

This will be used in the next commit to add a timeout when polling for
new mail.

changeset: 7112:4a1390537a29
user:      Kevin McCarthy <ke...@8t8.us>
date:      Sat Jul 22 19:48:50 2017 -0700
link:      http://dev.mutt.org/hg/mutt/rev/4a1390537a29

Add $imap_poll_timeout to allow mailbox polling to time out.

Enable the polling flag for the NOOP in imap_check_mailbox(), the
STATUS command in imap_buffy_check(), and the LOGOUT command.

This is not intended to handle all blocking-IO related issues.
However, the periodic NOOP and STATUS are the most frequent places for
mutt to freeze up, especially after a laptop is sleep/woken.

Since these are quick operations with little data, this is a good place
to check if the connection is still working before hanging on a read.

diffs (321 lines):

diff -r a533c22715c8 -r 4a1390537a29 globals.h
--- a/globals.h Thu Jul 20 17:30:05 2017 -0700
+++ b/globals.h Sat Jul 22 19:48:50 2017 -0700
@@ -233,6 +233,7 @@
 #ifdef USE_IMAP
 WHERE short ImapKeepalive;
 WHERE short ImapPipelineDepth;
+WHERE short ImapPollTimeout;
 #endif
 
 /* flags for received signals */
diff -r a533c22715c8 -r 4a1390537a29 imap/command.c
--- a/imap/command.c    Thu Jul 20 17:30:05 2017 -0700
+++ b/imap/command.c    Sat Jul 22 19:48:50 2017 -0700
@@ -39,7 +39,7 @@
 /* forward declarations */
 static int cmd_start (IMAP_DATA* idata, const char* cmdstr, int flags);
 static int cmd_queue_full (IMAP_DATA* idata);
-static int cmd_queue (IMAP_DATA* idata, const char* cmdstr);
+static int cmd_queue (IMAP_DATA* idata, const char* cmdstr, int flags);
 static IMAP_COMMAND* cmd_new (IMAP_DATA* idata);
 static int cmd_status (const char *s);
 static void cmd_handle_fatal (IMAP_DATA* idata);
@@ -237,6 +237,7 @@
  *     for checking for a mailbox on append and login
  *   IMAP_CMD_PASS: command contains a password. Suppress logging.
  *   IMAP_CMD_QUEUE: only queue command, do not execute.
+ *   IMAP_CMD_POLL: poll the socket for a response before running 
imap_cmd_step.
  * Return 0 on success, -1 on Failure, -2 on OK Failure
  */
 int imap_exec (IMAP_DATA* idata, const char* cmdstr, int flags)
@@ -252,6 +253,16 @@
   if (flags & IMAP_CMD_QUEUE)
     return 0;
 
+  if ((flags & IMAP_CMD_POLL) &&
+      (ImapPollTimeout > 0) &&
+      (mutt_socket_poll (idata->conn, ImapPollTimeout)) == 0)
+  {
+    mutt_error (_("Connection to %s timed out"), idata->conn->account.host);
+    mutt_sleep (2);
+    cmd_handle_fatal (idata);
+    return -1;
+  }
+
   do
     rc = imap_cmd_step (idata);
   while (rc == IMAP_CMD_CONTINUE);
@@ -377,7 +388,7 @@
 }
 
 /* queues command. If the queue is full, attempts to drain it. */
-static int cmd_queue (IMAP_DATA* idata, const char* cmdstr)
+static int cmd_queue (IMAP_DATA* idata, const char* cmdstr, int flags)
 {
   IMAP_COMMAND* cmd;
   int rc;
@@ -386,7 +397,7 @@
   {
     dprint (3, (debugfile, "Draining IMAP command pipeline\n"));
 
-    rc = imap_exec (idata, NULL, IMAP_CMD_FAIL_OK);
+    rc = imap_exec (idata, NULL, IMAP_CMD_FAIL_OK | (flags & IMAP_CMD_POLL));
 
     if (rc < 0 && rc != -2)
       return rc;
@@ -411,7 +422,7 @@
     return -1;
   }
 
-  if (cmdstr && ((rc = cmd_queue (idata, cmdstr)) < 0))
+  if (cmdstr && ((rc = cmd_queue (idata, cmdstr, flags)) < 0))
     return rc;
 
   if (flags & IMAP_CMD_QUEUE)
diff -r a533c22715c8 -r 4a1390537a29 imap/imap.c
--- a/imap/imap.c       Thu Jul 20 17:30:05 2017 -0700
+++ b/imap/imap.c       Sat Jul 22 19:48:50 2017 -0700
@@ -832,8 +832,12 @@
    * receive a bye response (so it doesn't freak out and close the conn) */
   (*idata)->status = IMAP_BYE;
   imap_cmd_start (*idata, "LOGOUT");
-  while (imap_cmd_step (*idata) == IMAP_CMD_CONTINUE)
-    ;
+  if (ImapPollTimeout <= 0 ||
+      mutt_socket_poll ((*idata)->conn, ImapPollTimeout) != 0)
+  {
+    while (imap_cmd_step (*idata) == IMAP_CMD_CONTINUE)
+      ;
+  }
 
   mutt_socket_close ((*idata)->conn);
   imap_free_idata (idata);
@@ -1459,7 +1463,7 @@
   }
   if (idata->state == IMAP_IDLE)
   {
-    while ((result = mutt_socket_poll (idata->conn)) > 0)
+    while ((result = mutt_socket_poll (idata->conn, 0)) > 0)
     {
       if (imap_cmd_step (idata) != IMAP_CMD_CONTINUE)
       {
@@ -1476,7 +1480,7 @@
 
   if ((force ||
        (idata->state != IMAP_IDLE && time(NULL) >= idata->lastread + Timeout))
-      && imap_exec (idata, "NOOP", 0) != 0)
+      && imap_exec (idata, "NOOP", IMAP_CMD_POLL) != 0)
     return -1;
 
   /* We call this even when we haven't run NOOP in case we have pending
@@ -1600,14 +1604,14 @@
       snprintf (command, sizeof (command),
              "STATUS %s (UIDNEXT UIDVALIDITY UNSEEN RECENT)", munged);
 
-    if (imap_exec (idata, command, IMAP_CMD_QUEUE) < 0)
+    if (imap_exec (idata, command, IMAP_CMD_QUEUE | IMAP_CMD_POLL) < 0)
     {
       dprint (1, (debugfile, "Error queueing command\n"));
       return 0;
     }
   }
 
-  if (lastdata && (imap_exec (lastdata, NULL, IMAP_CMD_FAIL_OK) == -1))
+  if (lastdata && (imap_exec (lastdata, NULL, IMAP_CMD_FAIL_OK | 
IMAP_CMD_POLL) == -1))
   {
     dprint (1, (debugfile, "Error polling mailboxes\n"));
     return 0;
diff -r a533c22715c8 -r 4a1390537a29 imap/imap_private.h
--- a/imap/imap_private.h       Thu Jul 20 17:30:05 2017 -0700
+++ b/imap/imap_private.h       Sat Jul 22 19:48:50 2017 -0700
@@ -70,6 +70,7 @@
 #define IMAP_CMD_FAIL_OK (1<<0)
 #define IMAP_CMD_PASS    (1<<1)
 #define IMAP_CMD_QUEUE   (1<<2)
+#define IMAP_CMD_POLL    (1<<3)
 
 /* length of "DD-MMM-YYYY HH:MM:SS +ZZzz" (null-terminated) */
 #define IMAP_DATELEN 27
diff -r a533c22715c8 -r 4a1390537a29 init.h
--- a/init.h    Thu Jul 20 17:30:05 2017 -0700
+++ b/init.h    Sat Jul 22 19:48:50 2017 -0700
@@ -1310,6 +1310,14 @@
   ** .pp
   ** \fBNote:\fP Changes to this variable have no effect on open connections.
   */
+  { "imap_poll_timeout", DT_NUM,  R_NONE, UL &ImapPollTimeout, 15 },
+  /*
+  ** .pp
+  ** This variable specifies the maximum amount of time in seconds
+  ** that mutt will wait for a response when polling IMAP connections
+  ** for new mail, before timing out and closing the connection.  Set
+  ** to 0 to disable timing out.
+  */
   { "imap_servernoise",                DT_BOOL, R_NONE, OPTIMAPSERVERNOISE, 1 
},
   /*
   ** .pp
diff -r a533c22715c8 -r 4a1390537a29 mutt_sasl.c
--- a/mutt_sasl.c       Thu Jul 20 17:30:05 2017 -0700
+++ b/mutt_sasl.c       Sat Jul 22 19:48:50 2017 -0700
@@ -101,7 +101,7 @@
 static int mutt_sasl_conn_read (CONNECTION* conn, char* buf, size_t len);
 static int mutt_sasl_conn_write (CONNECTION* conn, const char* buf,
   size_t count);
-static int mutt_sasl_conn_poll (CONNECTION* conn);
+static int mutt_sasl_conn_poll (CONNECTION* conn, time_t wait_secs);
 
 /* utility function, stolen from sasl2 sample code */
 static int iptostring(const struct sockaddr *addr, socklen_t addrlen,
@@ -613,13 +613,13 @@
   return -1;
 }
 
-static int mutt_sasl_conn_poll (CONNECTION* conn)
+static int mutt_sasl_conn_poll (CONNECTION* conn, time_t wait_secs)
 {
   SASL_DATA* sasldata = conn->sockdata;
   int rc;
 
   conn->sockdata = sasldata->sockdata;
-  rc = sasldata->msasl_poll (conn);
+  rc = sasldata->msasl_poll (conn, wait_secs);
   conn->sockdata = sasldata;
 
   return rc;
diff -r a533c22715c8 -r 4a1390537a29 mutt_sasl.h
--- a/mutt_sasl.h       Thu Jul 20 17:30:05 2017 -0700
+++ b/mutt_sasl.h       Sat Jul 22 19:48:50 2017 -0700
@@ -48,7 +48,7 @@
   int (*msasl_close) (CONNECTION* conn);
   int (*msasl_read) (CONNECTION* conn, char* buf, size_t len);
   int (*msasl_write) (CONNECTION* conn, const char* buf, size_t count);
-  int (*msasl_poll) (CONNECTION* conn);
+  int (*msasl_poll) (CONNECTION* conn, time_t wait_secs);
 }
 SASL_DATA;
 
diff -r a533c22715c8 -r 4a1390537a29 mutt_socket.c
--- a/mutt_socket.c     Thu Jul 20 17:30:05 2017 -0700
+++ b/mutt_socket.c     Sat Jul 22 19:48:50 2017 -0700
@@ -153,13 +153,13 @@
  *   Returns: >0 if there is data to read,
  *            0 if a read would block,
  *            -1 if this connection doesn't support polling */
-int mutt_socket_poll (CONNECTION* conn)
+int mutt_socket_poll (CONNECTION* conn, time_t wait_secs)
 {
   if (conn->bufpos < conn->available)
     return conn->available - conn->bufpos;
 
   if (conn->conn_poll)
-    return conn->conn_poll (conn);
+    return conn->conn_poll (conn, wait_secs);
 
   return -1;
 }
@@ -431,18 +431,41 @@
   return rc;
 }
 
-int raw_socket_poll (CONNECTION* conn)
+int raw_socket_poll (CONNECTION* conn, time_t wait_secs)
 {
   fd_set rfds;
-  struct timeval tv = { 0, 0 };
+  struct timeval tv;
+  struct timespec pre_t, post_t;
+  time_t sleep_secs;
+  int rv;
 
   if (conn->fd < 0)
     return -1;
 
-  FD_ZERO (&rfds);
-  FD_SET (conn->fd, &rfds);
-  
-  return select (conn->fd + 1, &rfds, NULL, NULL, &tv);
+  FOREVER
+  {
+    tv.tv_sec = wait_secs;
+    tv.tv_usec = 0;
+
+    FD_ZERO (&rfds);
+    FD_SET (conn->fd, &rfds);
+
+    clock_gettime (CLOCK_MONOTONIC, &pre_t);
+    rv = select (conn->fd + 1, &rfds, NULL, NULL, &tv);
+    clock_gettime (CLOCK_MONOTONIC, &post_t);
+
+    if (rv > 0 ||
+        (rv < 0 && errno != EINTR))
+      return rv;
+
+    if (SigInt)
+      mutt_query_exit ();
+
+    sleep_secs = post_t.tv_sec - pre_t.tv_sec;
+    if (wait_secs <= sleep_secs)
+      return 0;
+    wait_secs -= sleep_secs;
+  }
 }
 
 int raw_socket_open (CONNECTION* conn)
diff -r a533c22715c8 -r 4a1390537a29 mutt_socket.h
--- a/mutt_socket.h     Thu Jul 20 17:30:05 2017 -0700
+++ b/mutt_socket.h     Sat Jul 22 19:48:50 2017 -0700
@@ -48,13 +48,13 @@
   int (*conn_write) (struct _connection *conn, const char *buf, size_t count);
   int (*conn_open) (struct _connection *conn);
   int (*conn_close) (struct _connection *conn);
-  int (*conn_poll) (struct _connection *conn);
+  int (*conn_poll) (struct _connection *conn, time_t wait_secs);
 } CONNECTION;
 
 int mutt_socket_open (CONNECTION* conn);
 int mutt_socket_close (CONNECTION* conn);
 int mutt_socket_read (CONNECTION* conn, char* buf, size_t len);
-int mutt_socket_poll (CONNECTION* conn);
+int mutt_socket_poll (CONNECTION* conn, time_t wait_secs);
 int mutt_socket_readchar (CONNECTION *conn, char *c);
 #define mutt_socket_readln(A,B,C) mutt_socket_readln_d(A,B,C,MUTT_SOCK_LOG_CMD)
 int mutt_socket_readln_d (char *buf, size_t buflen, CONNECTION *conn, int dbg);
@@ -71,6 +71,6 @@
 int raw_socket_write (CONNECTION* conn, const char* buf, size_t count);
 int raw_socket_open (CONNECTION *conn);
 int raw_socket_close (CONNECTION *conn);
-int raw_socket_poll (CONNECTION* conn);
+int raw_socket_poll (CONNECTION* conn, time_t wait_secs);
 
 #endif /* _MUTT_SOCKET_H_ */
diff -r a533c22715c8 -r 4a1390537a29 mutt_tunnel.c
--- a/mutt_tunnel.c     Thu Jul 20 17:30:05 2017 -0700
+++ b/mutt_tunnel.c     Sat Jul 22 19:48:50 2017 -0700
@@ -45,7 +45,7 @@
 static int tunnel_socket_close (CONNECTION*);
 static int tunnel_socket_read (CONNECTION* conn, char* buf, size_t len);
 static int tunnel_socket_write (CONNECTION* conn, const char* buf, size_t len);
-static int tunnel_socket_poll (CONNECTION* conn);
+static int tunnel_socket_poll (CONNECTION* conn, time_t wait_secs);
 
 /* -- public functions -- */
 int mutt_tunnel_socket_setup (CONNECTION *conn)
@@ -188,7 +188,7 @@
   return rc;
 }
 
-static int tunnel_socket_poll (CONNECTION* conn)
+static int tunnel_socket_poll (CONNECTION* conn, time_t wait_secs)
 {
   TUNNEL_DATA* tunnel = (TUNNEL_DATA*) conn->sockdata;
   int ofd;
@@ -196,7 +196,7 @@
 
   ofd = conn->fd;
   conn->fd = tunnel->readfd;
-  rc = raw_socket_poll (conn);
+  rc = raw_socket_poll (conn, wait_secs);
   conn->fd = ofd;
 
   return rc;

Reply via email to