This article is from the Secure Sockets Layer Discussion List FAQ, by Shannon Appel SAppel@consensus.com with numerous contributions by others.
The difficulty is that it's hard for SSL to precisely emulate the
behavior of Unix-style socket calls.
The problem is that you are using SSL Plus in its blocking mode; if
you return SSLWouldBlock from your I/O Read callback, the library
will return the data it has along with the SSLWouldBlock error.
The best way to solve this is always to know how much data you're
waiting for and to request exactly that much. I know this doesn't
work with a lot of free-form Internet protocols.
Alternatively, you would like the call to block until it gets some
data, then return it to you, even if it's less than 512 bytes.
Ideally, you'd like to do this without busy-looping the CPU waiting
for data. The best way to do this using SSL Plus is to write a
wrapper for SSLRead() which does the following:
* Make a blocking select() call until there is some data
available on the TCP/IP connection over which you're speaking
SSL. This will cause you to block in a friendly way until data
* Call SSLRead(). If zero bytes are returned from the read,
loop and do the select() again. Otherwise, return whatever
* Make your Read() callback non-blocking. The easiest thing to
do is to check how much data is available on the incoming
connection and return SSLWouldBlockErr if you can't completely
fulfill the request. (You can optionally read what data there
is and return it first; this won't affect functionality).
This will result in the following behavior:
1. Your program will block gracefully in the select() call until
something arrives on the connection.
2. You will then ask SSL Plus to read some data.
3. SSL Plus will ask the Read() callback to read the header of the
next record (3 or 5 bytes).
4. The Read() callback will fulfill that, if possible
5. SSL Plus will ask to read the body of the record (whose length
will be equal to how much data was sent by the other side, plus
MAC and encryption padding).
6. The Read() callback will fulfill that, if possible.
7. If the amount of data received is greater than or equal to how
much was requested in 2., the data will be returned
8. Otherwise, go back to 3.
What will happen in practice looks something like this: because the
SSL peer on the other end of the connection generates record layer
records monolithically, and they're relatively small, the header and
content of a record will arrive at your machine all together. Thus,
when your select() call returns, you will be able to successfully
read a header and body without blocking. When SSL Plus goes to read
another one, your Read() callback will see that there's no data
available on the connection (assuming another record hasn't arrived)
and return SSLWouldBlockErr. SSL Plus will then return the data it
has received and the error SSLWouldBlockErr; you can return that
data as a partial completion of the desired read.
If a partial record arrives, your select() will wake up, but SSL
Plus won't be able to decrypt and check a complete record before the
Read() callback returns SSLWouldBlockErr; thus, your read will
return with zero bytes returned. Since this isn't the behavior your
client expects, you should select() again until more data arrives,
hopefully completing the record.