> From: openssl-users [mailto:[email protected]] 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