Subject: Re: bug#22493: 25.1.50; open-gnutls-stream doesn't respect :nowait, so the connections are synchronous

From: Lars Ingebrigtsen <[email-masked]>
Date: Sat, 30 Jan 2016 23:55:57 +0100

Eli Zaretskii <[email-masked]> writes:

>> The problem is, though, that the process isn't marked as a gnutls
>> process until gnutls_boot is called, so this needs to happen much
>> earlier.  Possibly by adding another keyword to make-network-process
>> that just sets
>> 
>>   XPROCESS (proc)->gnutls_p = 1;
>
> Why do you need to mark a process gnutls_p, when it definitely still
> isn't, not until the GnuTLS negotiation is successfully completed?

It is a socket that will only be used for TLS.  And the current way
we're creating TLS streams is by calling `open-gnutls-stream', which
(simplified) just calls `make-network-stream' and then `gnutls-boot' in
rapid succession.  So any stream you get out of `open-gnutls-stream'
will look just the same -- it'll have gnutls_p set.

It'll just happen slightly earlier.

> That'd just add confusion (a.k.a. "bugs waiting to happen") on the C
> level.  Can't we use a GnuTLS-specific sentinel instead?

I'm not sure I follow...  a sentinel?

>> The other problem is that reading/writing from these things will just
>> send plain text if the gnutls stuff hasn't been initialised:
>> 
>> #ifdef HAVE_GNUTLS
>> 	      if (p->gnutls_p && p->gnutls_state)
>> 		written = emacs_gnutls_write (p, cur_buf, cur_len);
>> 	      else
>> #endif
>> 		written = emacs_write_sig (outfd, cur_buf, cur_len);
>> 
>> I think that looks rather nonsensical.
>
> Does this happen today?  If so, in what scenario?

It does not happen today, but it will happen if we open the TLS stream
:nowait.  For instance, url.el calls `open-network-stream' and then
sends a "GET /" on the socket immediately.  Since setup is synchronous
today, that's fine, but when it gets async, then that p->gnutls_state
will be 0, and url.el will send an unencrypted "GET /" to the server,
which will fail, of course.

> If you want GnuTLS negotiation to happen from the sentinel, you need
> some machinery to block such process objects from communicating.
> I'm not sure silently skipping I/O is TRT for that: won't Lisp
> programs that happen to start communicating too early become confused
> about what's going on?

The "GET /" will block, sort of, as it would on any socket that's backed
up.  I don't think there will be anything user-noticeable from, say, the
perspective of `send-process-string'...

> More generally, what advantages do we expect to gain by making these
> changes?  Let DNS resolution proceed in the background, only to have
> to wait for GnuTLS negotiations anyway, before we can start using the
> stream?  Or are there more significant advantages?

It makes the entire connection, both the DNS resolution and the TLS
negotiation, asynchronous.  So Emacs doesn't hang while eww is
connecting to https://google.com.

-- 
(domestic pets only, the antidote for overdose, milk.)
   bloggy blog: http://lars.ingebrigtsen.no