On Wed, Jul 15, 2015 at 08:15:55PM -0700, Kevin J. McCarthy wrote: > Kevin J. McCarthy wrote: > > Kevin J. McCarthy wrote: > > > I wasn't really happy having a loop counter option for GnuTLS. It turns > > > out the GNUTLS_E_AGAIN is translated directly from EAGAIN/EWOULDBLOCK. > > > Since we're not using non-blocking io, this will only be triggered by > > > our timeout. > > > > Sorry, I was wrong. It will return GNUTLS_E_AGAIN for situations other > > than the timeout we set, so my patch is incorrect. I'll have to think > > about this some more. > > After looking some more, I've re-convinced myself the patch approach is > actually okay. > > It looks like GnuTLS will return the GNUTLS_E_AGAIN for a partial > read only if recv returns a EAGAIN or EINTR. Otherwise it will keep > looping until it gets the needed amount. (see _gnutls_stream_read() and > _gnutls_io_read_buffered()) > > The EAGAIN should only occur for a timeout on no data, and the EINTR > should only occur for a signal. Since the timeout is ours and we aren't > setting signals, there is no more reason to loop or handle these errors > than there is with raw_socket_read or raw_socket_write. Therefore I > believe patch should be okay after all. > > I am attaching a somewhat more aggressive patch that removes the looping > from tls_socket_read, and returns tls_socket_write to its behavior of > aborting on any error. > > Feedback and testing is definitely appreciated!
Looks like nice work, Kevin. Cool that this will hopefully get crossed off the list. But personally I can’t give any feedback or test it until next week at the earliest. Grts! Allen > WHERE short SendmailWait; > WHERE short SleepTime INITVAL (1); > +WHERE short SocketTimeout; > WHERE short TimeInc; > WHERE short Timeout; > WHERE short Wrap; > WHERE short WrapHeaders; > WHERE short WriteInc; > > WHERE short ScoreThresholdDelete; > WHERE short ScoreThresholdRead; > diff --git a/init.h b/init.h > --- a/init.h > +++ b/init.h > @@ -2883,16 +2883,22 @@ > ** smtp[s]://[user[:pass]@]host[:port] > ** .te > ** .pp > ** where ``[...]'' denotes an optional part. > ** Setting this variable overrides the value of the $$sendmail > ** variable. > */ > #endif /* USE_SMTP */ > + { "socket_timeout", DT_NUM, R_NONE, UL &SocketTimeout, 30 }, > + /* > + ** .pp > + ** Set socket send and receive timeouts to this many seconds. When > + ** set to zero, send and receive operations will not time out. > + */ > { "sort", DT_SORT, R_INDEX|R_RESORT, UL &Sort, SORT_DATE }, > /* > ** .pp > ** Specifies how to sort messages in the ``index'' menu. Valid values > ** are: > ** .il > ** .dd date or date-sent > ** .dd date-received > diff --git a/mutt_socket.c b/mutt_socket.c > --- a/mutt_socket.c > +++ b/mutt_socket.c > @@ -339,16 +339,17 @@ > return 0; > } > > /* socket_connect: set up to connect to a socket fd. */ > static int socket_connect (int fd, struct sockaddr* sa) > { > int sa_size; > int save_errno; > + struct timeval socket_timeout_tv = { 0, 0 }; > > if (sa->sa_family == AF_INET) > sa_size = sizeof (struct sockaddr_in); > #ifdef HAVE_GETADDRINFO > else if (sa->sa_family == AF_INET6) > sa_size = sizeof (struct sockaddr_in6); > #endif > else > @@ -359,16 +360,35 @@ > > if (ConnectTimeout > 0) > alarm (ConnectTimeout); > > mutt_allow_interrupt (1); > > save_errno = 0; > > + if (SocketTimeout > 0) > + { > + socket_timeout_tv.tv_sec = SocketTimeout; > + if (setsockopt (fd, SOL_SOCKET, SO_RCVTIMEO, &socket_timeout_tv, > + sizeof(struct timeval))) > + { > + mutt_perror ("setsockopt"); > + mutt_sleep(3); > + return -1; > + } > + if (setsockopt (fd, SOL_SOCKET, SO_SNDTIMEO, &socket_timeout_tv, > + sizeof(struct timeval))) > + { > + mutt_perror ("setsockopt"); > + mutt_sleep(3); > + return -1; > + } > + } > + > if (connect (fd, sa, sa_size) < 0) > { > save_errno = errno; > dprint (2, (debugfile, "Connection failed. errno: %d...\n", errno)); > SigInt = 0; /* reset in case we caught SIGINTR while in connect() */ > } > > if (ConnectTimeout > 0) > diff --git a/mutt_ssl_gnutls.c b/mutt_ssl_gnutls.c > --- a/mutt_ssl_gnutls.c > +++ b/mutt_ssl_gnutls.c > @@ -134,26 +134,23 @@ > > if (!data) > { > mutt_error (_("Error: no TLS socket open")); > mutt_sleep (2); > return -1; > } > > - do { > - ret = gnutls_record_recv (data->state, buf, len); > - if (ret < 0 && gnutls_error_is_fatal(ret) == 1) > - { > - mutt_error ("tls_socket_read (%s)", gnutls_strerror (ret)); > - mutt_sleep (4); > - return -1; > - } > + ret = gnutls_record_recv (data->state, buf, len); > + if (ret < 0) > + { > + mutt_error ("tls_socket_read (%s)", gnutls_strerror (ret)); > + mutt_sleep (4); > + return -1; > } > - while (ret == GNUTLS_E_AGAIN || ret == GNUTLS_E_INTERRUPTED); > > return ret; > } > > static int tls_socket_write (CONNECTION* conn, const char* buf, size_t len) > { > tlssockdata *data = conn->sockdata; > int ret; > @@ -166,25 +163,22 @@ > return -1; > } > > do > { > ret = gnutls_record_send (data->state, buf + sent, len - sent); > if (ret < 0) > { > - if (gnutls_error_is_fatal(ret) == 1) > - { > - mutt_error ("tls_socket_write (%s)", gnutls_strerror (ret)); > - mutt_sleep (4); > - return -1; > - } > - return ret; > + mutt_error ("tls_socket_write (%s)", gnutls_strerror (ret)); > + mutt_sleep (4); > + return -1; > } > - sent += ret; > + else > + sent += ret; > } while (sent < len); > > return sent; > } > > static int tls_socket_open (CONNECTION* conn) > { > if (raw_socket_open (conn) < 0)
signature.asc
Description: PGP signature