althepal has asked for the wisdom of the Perl Monks concerning the following question:

I think I've noticed a problem with IO::Socket::SSL, and I think I have a solution for it for my case, but I'd like to know what people think.

I have a server I've written in perl, and I wanted to make it work with SSL, so I used this very convenient module. Testing seemed to tell me that everything was working great. I was amazed at how easy it was. But then I noticed that many of the real-life SSL connections were timing out.

I don't use <>, or getline() to read from the socket. Instead, for greater control, I use select() to see if there's data waiting, then sysread() to read the data. Like this:

if (select($rout=$rin, undef, undef, $timeout)) { unless ($length = sysread($socket, $buf="", 1024)) { #connection error } # handle data in $buf } else { # timeout error }

It's more complicated than this, but this is the gist of it. Fyi, I've found through benchmarking that this method of reading the socket has considerably better performance than using an alarm to time out getline on the socket.

After a lot of debugging and trying different things, I realized that if I read in a larger data size with sysread (4096 instead of 1024), the timeout problem went away.

I think that what's happening is this: The SSL module must be reading ahead on the socket to do the proper decoding, so while sysread will return data, the select function does not see that the socket has data to read, because the SSL module has already cleared out the actual buffer. I don't understand exactly how the SSL module disguises the SSL socket as a normal socket, so I'm guessing here.

So, everything seems to work now with the larger value for sysread, but I'm concerned that I'm just getting lucky. I'm afraid that some length of data will cause the same problem, whereby select will tell me that no data is available, but sysread will still return data.

So what do you think? Is this going to come back to haunt me, or have I solved the problem?

Replies are listed 'Best First'.
Re: IO::Socket::SSL buffering issue?
by starbolin (Hermit) on Apr 25, 2005 at 07:25 UTC

    When using sysread, your read length needs to be the same size as your systems' IO buffer. This is usually 4 or 8 k which is why 4k worked well for you.


    s//----->\t/;$~="JAPH";s//\r<$~~/;{s|~$~-|-~$~|||s |-$~~|$~~-|||s,<$~~,<~$~,,s,~$~>,$~~>,, $|=1,select$,,$,,$,,1e-1;print;redo}

      That makes sense, but how come I never noticed a problem before I started using SSL?

      Also, how do I determine my systems IO buffer?

        I don't know. Which system? You could try sending long packets and see how many reads it takes to empty the buffer.


        s//----->\t/;$~="JAPH";s//\r<$~~/;{s|~$~-|-~$~|||s |-$~~|$~~-|||s,<$~~,<~$~,,s,~$~>,$~~>,, $|=1,select$,,$,,$,,1e-1;print;redo}
Re: IO::Socket::SSL buffering issue?
by salva (Canon) on Apr 25, 2005 at 11:03 UTC
    The problem with SSL connections is that you never know if its addaptation layer needs to read or write from the underlaying socket.

    Maybe you just want to read from the SSL socket so you pass the socket file descriptor number to select on the read group... but under the hood, maybe IO::Socket::SSL needs to write first and the other party SSL socket is waiting also for some input, so your app just locks.

    I don't believe this problem could be easily solved without a select replacement that knows about SSL.

Re: IO::Socket::SSL buffering issue?
by 5p1d3r (Hermit) on Apr 25, 2005 at 15:05 UTC
    I've mixed openSSL with select in the C programming world sucessfully so I may be able to offer some insight into what is going on under the hood.

    The SSL protocol makes a pure select based programming model difficult unless you're aware of what is going on in the SSL layer. The primary problem is the SSL handshake. This is where the two parties decide on an encryption algorithm, swap certificates and generate a secret key. There is a decent amount of back and forth during this phase. Once the connection is established a small amount of read ahead is needed if a block cipher was chosen as the encryption algorithm. These blocks are usuablly pretty small (64 bytes I think) so this usually doesn't present a problem.

    A server will typically, on accepting a new connection, want to read from it. If you're using blocking sockets you can, at this point, perform the SSL handshake in its entirety. Because of the back and forth a slow/broken client can cause a hang during this phase so you're left with finding a way to time it out. Using select on the socket during handshake is one way to do this (I don't know enough about IO::Socket::SSL to say whether this is possible here). The openSSL API for performing the handshake will, if the socket is non-blocking, return whether the handshake has completed, failed, is waiting for incoming data or is waiting to output data. Combine this with a smarter select loop and you you manage time outs quite nicely.