> From: openssl-users [mailto:openssl-users-boun...@openssl.org] On Behalf Of
> Charles Mills
> Sent: Friday, January 11, 2019 17:06
>
> >        SSL_shutdown(connection) || SSL_shutdown(connection);
>
> I like it! (Not!)
>
> I don't pretend to be a bits and bytes expert on TCP protocol. You can't be
> an expert on everything.
>
> So I will listen to expert advice. I know 99% of you all are 'nix guys and
> this is a Windows problem. I am seeing OTOH where my Windows doc says
> closesocket() does an abortive termination, and OTOH a discussion of a
> graceful closesocket() with SO_LINGER/SO_DONTLINGER.
>
> (1) This code is (at the application level) purely a receiver of data and
> (2) without the TLS layer in place it is hard to picture any meaningful data
> transfer and (3) we are in a session cleanup situation anyway -- so it seems
> to me that an abortive disconnect is perfectly fine. Am I wrong?

Yes, you're wrong. You don't want an abortive disconnect.

A TCP connection can be closed in four (or five) ways:

1. Normal close, which involves the FIN / FIN-ACK / ACK sequence. When the last 
ACK is received, both sides know that all data has been received by the peer 
stack, and at the point when the corresponding ACK was generated, the peer 
"believed" it would be able to deliver the data to the application eventually. 
(That is, the stack hadn't been informed that the application's identifier for 
the connection - the socket - had been closed.)

2. Abortive close, which involves a RST from one side to the peer, and that's 
it. RST is a one-way, unacknowledged flow. There are a number of reasons why 
it's undesirable, some of which I'll go into below.

3. Abortive close due to network management message: the stack receives an ICMP 
message indicating a packet could not be delivered, such as HOST_UNREACH. From 
the application's point of view, the result is similar to #2, except for the 
particular error code it sees.

4. Timeout from TCP retransmit, either for an application send or, if it's 
enabled, TCP keepalive.

5. Arguably a separate case: 1-3 but generated by a middlebox, such as as a 
router, or an application firewall. In other words, the connection is forced 
closed by someone spoofing the peer. From the application's point of view, that 
makes no difference.

Applications should almost never use an abortive close. TCP is intended to be a 
reliable (best-effort) stream transport, and it can only meet its (already 
weak) service guarantees if you let it acknowledge all application data and 
close the conversation cleanly.

Now, when you have a higher-level conversation protocol such as TLS, and the 
higher-level protocol has already negotiated end-of-conversation, that may not 
seem important; the peers have agreed that they're not going to send anything 
more. That assumes, however, that the peers are well-behaved. And it is at the 
very least notionally cleaner to let the conversation close normally.

Beyond that, an abortive close can cause TIME_WAIT Assassination, which is a 
Bad Thing. If you don't know what TIME_WAIT Assassination is, that's a sign you 
shouldn't be doing abortive closes. Don't invoke extraordinary behavior you 
don't understand.

Now, all that said: Winsock closesocket will NOT do an abortive disconnect if 
you have not mucked with the SO_LINGER socket option (which you should not do 
unless you understand TCP). I don't know what documentation you saw that claims 
otherwise, but it's wrong.

Calling shutdown before closesocket won't hurt anything, but (if you use the 
pattern that we've discussed in this thread) won't do anything useful either, 
in most cases.

One case I forgot in my previous discussion: It's worth remembering that 
close/closesocket operates on a single reference to the connection, while 
shutdown operates on the connection itself. That is, the logic for 
close/closesocket is notionally something like this:

   close the descriptor/handle
   decrement the conversation's reference count
   if the reference count is 0
      if connection is still open for sending
         shutdown(SHUT_WR)
      if connection is still open for receiving
         shutdown(SHUT_RD)

In the case where you have multiple descriptors or handles for a conversation - 
for example due to dup'ing a socket or forking on UNIX, or duplicating a handle 
(possibly into a different process) on Windows - then close/closesocket won't 
do the shutdown-equivalent until they have *all* been closed. An explicit 
shutdown, on the other hand, doesn't close any of the descriptors/handles, but 
it does send a FIN (for SHUT_WR) or flush inbound data and refuse to receive 
any more (for SHUT_RD) on the conversation, which of course affects all 
descriptors/handles.

So if your application creates multiple references to the conversation, then 
depending on your design, you might want the shutdown. Or you might not, if you 
want the shutdown-on-last-close semantics. Neither option is correct for all 
applications.

--
Michael Wojcik
Distinguished Engineer, Micro Focus



-- 
openssl-users mailing list
To unsubscribe: https://mta.openssl.org/mailman/listinfo/openssl-users

Reply via email to