openssl bit of dark art.
First, the page you linked to did not return HTML return values โโwell. This is what the manual page actually says:
RETURN VALUES The following return values can occur: 0 The shutdown is not yet finished. Call SSL_shutdown() for a second time, if a bidirectional shutdown shall be performed. The output of SSL_get_error(3) may be misleading, as an erroneous SSL_ERROR_SYSCALL may be flagged even though no error occurred. 1 The shutdown was successfully completed. The "close notify" alert was sent and the peer "close notify" alert was received. -1 The shutdown was not successful because a fatal error occurred either at the protocol level or a connection failure occurred. It can also occur if action is need to continue the operation for non- blocking BIOs. Call SSL_get_error(3) with the return value ret to find out the reason.
If you have blocking BIOs, everything is relatively simple. "0" on the first call means you need to re-call SSL_shutdown if you want to completely disable two-way communication. In essence, this means that you sent a close_notify warning, but you have not received it yet). 1 means that you previously received a close_notify warning from another partner, and you are completely done. -1 means fatal error. The second call (which you only make if you returned 0) then triggers a bi-directional disconnect (that is, now wait on the other side for them to send you their warning "close_notify"). Logic tells you that you cannot return 0 again (because it is a blocking BIO and the first step will be performed). -1 indicates an error, and 1 indicates success.
If you have non-blocking BIOs, the same return values โโare applied, โpossibly 0 and then 1โ, except for the fact that you also need to go through the entire SSL_ERROR_WANT_READ and SSL_ERROR_WANT_WRITE , i.e.
If the underlying BIO is non-blocking, SSL_shutdown() will also return when the underlying BIO could not satisfy the needs of SSL_shutdown() to continue the handshake. In this case a call to SSL_get_error() with the return value of SSL_shutdown() will yield SSL_ERROR_WANT_READ or SSL_ERROR_WANT_WRITE. The calling process then must repeat the call after taking appropriate action to satisfy the needs of SSL_shutdown(). The action depends on the underlying BIO. When using a non-blocking socket, nothing is to be done, but select() can be used to check for the required condition. When using a buffering BIO, like a BIO pair, data must be written into or retrieved out of the BIO before being able to continue.
So you have two levels of repetition. You call SSL_shutdown "first" time, but repeat if you get SSL_ERROR_WANT_READ or SSL_ERROR_WANT_WRITE after SSL_ERROR_WANT_WRITE around the select() loop in the usual way, and consider the "first" SSL_shutdown to complete if you get an error code other than SSL_ERROR_WANT_ (in this case, a failure ), or you will receive a refund of 0 or 1 . If you received a refund of 1 , you are done. If you get a return of 0 and want a bi-directional disconnect, then you need to make a second call, after which you will again need to check SSL_ERROR_WANT_READ or SSL_ERROR_WANT_WRITE and repeat the selection; this should not return 1 , but may return 0 or an error.
Not easy.
A couple of additional notes from the documents : after calling SSL_Shutdown and getting "0" back for the first time, you can additionally call SSL_Read instead of SSL_Shutdown (in case the host still sends you any data on this SSL socket) and, I suppose, I โhopeโ that they will eventually send you a message on their part to clear the pipes.
Also, if you plan to close the socket after completion of the operation "anyway", you can completely skip the second SSL_Shutdown call ("1" from "0, then 1") and just go ahead and close the socket, the kernel should take care to cancel "now ignored "close_notify alerts that they should be sent ...