diff --git a/src/gnutls.c b/src/gnutls.c index 903393fed1..e7d0d3d845 100644 --- a/src/gnutls.c +++ b/src/gnutls.c @@ -708,16 +708,18 @@ emacs_gnutls_read (struct Lisp_Process *proc, char *buf, ptrdiff_t nbyte) rtnval = gnutls_record_recv (state, buf, nbyte); if (rtnval >= 0) return rtnval; - else if (rtnval == GNUTLS_E_UNEXPECTED_PACKET_LENGTH) - /* The peer closed the connection. */ - return 0; else if (emacs_gnutls_handle_error (state, rtnval)) - /* non-fatal error */ - return -1; - else { - /* a fatal error occurred */ - return 0; - } + { + /* non-fatal error */ + errno = EAGAIN; + return -1; + } + else + { + /* a fatal error occurred */ + errno = EPROTO; + return 0; + } } static char const * @@ -756,8 +758,10 @@ emacs_gnutls_handle_error (gnutls_session_t session, int err) connection. */ # ifdef HAVE_GNUTLS3 if (err == GNUTLS_E_PREMATURE_TERMINATION) - level = 3; +# else + if (err == GNUTLS_E_UNEXPECTED_PACKET_LENGTH) # endif + level = 3; GNUTLS_LOG2 (level, max_log_level, "fatal error:", str); ret = false; diff --git a/src/process.c b/src/process.c index 9b9b9f3550..f8fed56d5b 100644 --- a/src/process.c +++ b/src/process.c @@ -5392,60 +5392,31 @@ wait_reading_process_output (intmax_t time_limit, int nsecs, int read_kbd, #endif /* !HAVE_GLIB */ #ifdef HAVE_GNUTLS - /* GnuTLS buffers data internally. In lowat mode it leaves - some data in the TCP buffers so that select works, but - with custom pull/push functions we need to check if some - data is available in the buffers manually. */ - if (nfds == 0) + /* GnuTLS buffers data internally. select() will only report + available data for the underlying kernel sockets API, not + what has been buffered internally. As such, we need to loop + through all channels and check for available data manually. */ + if (nfds >= 0) { - fd_set tls_available; - int set = 0; - - FD_ZERO (&tls_available); - if (! wait_proc) - { - /* We're not waiting on a specific process, so loop - through all the channels and check for data. - This is a workaround needed for some versions of - the gnutls library -- 2.12.14 has been confirmed - to need it. See - http://comments.gmane.org/gmane.emacs.devel/145074 */ - for (channel = 0; channel < FD_SETSIZE; ++channel) - if (! NILP (chan_process[channel])) - { - struct Lisp_Process *p = - XPROCESS (chan_process[channel]); - if (p && p->gnutls_p && p->gnutls_state - && ((emacs_gnutls_record_check_pending - (p->gnutls_state)) - > 0)) - { - nfds++; - eassert (p->infd == channel); - FD_SET (p->infd, &tls_available); - set++; - } - } - } - else - { - /* Check this specific channel. */ - if (wait_proc->gnutls_p /* Check for valid process. */ - && wait_proc->gnutls_state - /* Do we have pending data? */ - && ((emacs_gnutls_record_check_pending - (wait_proc->gnutls_state)) - > 0)) - { - nfds = 1; - eassert (0 <= wait_proc->infd); - /* Set to Available. */ - FD_SET (wait_proc->infd, &tls_available); - set++; - } - } - if (set) - Available = tls_available; + for (channel = 0; channel < FD_SETSIZE; ++channel) + if (! NILP (chan_process[channel])) + { + struct Lisp_Process *p = + XPROCESS (chan_process[channel]); + + if (just_wait_proc && p != wait_proc) + continue; + + if (p && p->gnutls_p && p->gnutls_state + && ((emacs_gnutls_record_check_pending + (p->gnutls_state)) + > 0)) + { + nfds++; + eassert (p->infd == channel); + FD_SET (p->infd, &Available); + } + } } #endif } diff --git a/src/xgselect.c b/src/xgselect.c index fedd3127ef..f68982143e 100644 --- a/src/xgselect.c +++ b/src/xgselect.c @@ -143,6 +143,14 @@ xg_select (int fds_lim, fd_set *rfds, fd_set *wfds, fd_set *efds, ++retval; } } + else if (nfds == 0) + { + // pselect() clears the file descriptor sets if no fd is ready (but + // not if an error occurred), so should we to be compatible. (Bug#21337) + if (rfds) FD_ZERO (rfds); + if (wfds) FD_ZERO (wfds); + if (efds) FD_ZERO (efds); + } /* If Gtk+ is in use eventually gtk_main_iteration will be called, unless retval is zero. */