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;