问题
Here
http://marc.info/?l=openssl-users&m=124386218929227
It states that
"...This is why it is very important to understand that any possible forward progress on any port (and a write operation that returns WANT_READ may have made forward progress!) requires you to retry all pending operations on all ports...."
So am I correct in understanding that an SSL_read()
that returned WANT_READ
may have made forward progress (even if it did not return any data)?
I have an event driven single threaded app that has 3 non blocking ssl sockets. When each socket completes its connection, I have the sockets read until I get a WANT_READ
. My understanding is that a WANT_READ
means I may now invoke select()
and wait until the socket is ready for reading again.
When select()
returns, a loop goes through the 3 sockets calling ssl_read()
on each of them.
Say a read on Socket 1 returned WANT_READ
and no data.
Is it possible that Socket 2 returns some data, returns WANT_READ
when there is nothing more to read, and has now made some progress so a read on socket 1 may now return data? But as the loop has already done the read for socket 1, it will not happen.
As the loop has run through the 3 sockets, it waits there and hangs. Could this situation happen?
If this is the case, how do I see if no more progress can be made on all 3 sockets? For example, say the loop runs through;
- socket 1 returns
WANT_READ
. - socket 2 returns some data, then
WANT_READ
(and makes progress such that socket 1 can now return data) - socket 3 returns
WANT_READ
.
But based on the quote above (where any forward progress requires retrying all pending operations), I should retry all sockets again; so the second run through the loop;
- socket 1 now returns data, then
WANT_READ
- socket 2 returns
WANT_READ
- socket 3 now returns data (because the read on socket 1 made enough progress for socket 3 to return data), then
WANT_READ
.
But what if the last read on socket 3 made progress so socket 2 now returns data again? So my question is (if my understanding is correct), how can I tell if no more progress can be made?
edit 1:
So what I'm seeing is this:
My loop runs through all sockets (eg say there are 2 sockets) connected to client1
- socket 1:
ssl_read()
returns WANT_READ - socket 2:
ssl_read()
returns data,ssl_read()
returns data again, thenssl_read()
finally returns WANT_READ
Then as all sockets have returned WANT_READ, I wait on select()
. However my app is still waiting for data that the client has already sent. If I get the client to start another connection (while keeping the originals active), select returns and this is what I see:
- socket 1:
ssl_read()
returns data, thenssl_read()
again returns WANT_READ - socket 2:
ssl_read()
returns WANT_READ - socket 3(new):
ssl_read()
returns data, then returns WANT_READ.
So select detects the new connection and runs through my loop, which goes through all active connections. This time, it has found data from socket 1 from last time, in addition to the new data on socket 3. So my theory is that select() doesn't return the first time because the data I'm waiting to receive on socket 1 has already arrived and is ready and waiting for me to call ssl_read(). But last time I called ssl_read, I got WANT_READ.
回答1:
When SSL_read()
returns a negative value, you should obtain the error code from SSL_get_error()
. If the error code is SSL_ERROR_WANT_READ it means that you should wait (e.g. using select()
or poll
) for that socket to be readable (untill some data arrives from the network). When it happens you should retry SSL_read() on that socket again. You don't have to retry SSL_read()
on all SSL sockets that you have, only on those ones that returned SSL_ERROR_WANT_READ. You should do simmilar things with SSL_write()
(when it returns SSL_ERROR_WANT_WRITE
).
Be careful though, SSL_read()
can potentially return (SSL_get_error()
that is) SSL_ERROR_WANT_WRITE
and SSL_write()
can return SSL_ERROR_WANT_READ
. It may happen, because SSL needs to send/receive some additional messages besides your data (e.g. in order to send your data it needs to send some message and receive response first).
To summarize:
When
n = SSL_read()
returns:a)
n > 0
--> you have just receivedn
bytes of datab)
n < 0
-->err = SSL_get_error()
returned- SSL_ERROR_WANT_READ -->
select()
untill socket is readable and callSSL_read()
again - SSL_ERROR_WANT_WRITE -->
select()
untill socket is writable and callSSL_read()
again
c)
n = 0
-->if(SSL_get_shutdown(SSL*) & SSL_RECEIVED_SHUTDOWN)
: the other side did clean shutdown, otherwise the shudown was not clean, but the SSL connection is closed you can close the socket (SSL* object too)- SSL_ERROR_WANT_READ -->
When
n = SSL_write()
returns:a)
n > 0
--> you have just sentn
bytes of datab)
n < 0
-->err = SSL_get_error()
returned- SSL_ERROR_WANT_READ -->
select()
untill socket is readable and callSSL_write()
again - SSL_ERROR_WANT_WRITE -->
select()
untill socket is writable and callSSL_write
again
c)
n = 0
-->if((err = SSL_get_error(SSL*,err)) == SSL_ERROR_ZERO_RETURN)
: the other side did clean shutdown, otherwise the shudown was not clean, but the SSL connection is closed you can close the socket (SSL* object too)- SSL_ERROR_WANT_READ -->
I hope that helps.
来源:https://stackoverflow.com/questions/14378189/how-to-tell-when-no-more-progress-can-be-made-on-an-ssl-connection