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

Hi monks,

I made a STARTTLS application, that is to timeout eventually and does roughly:

$fh = IO::Socket::INET->new(%arg); IO::Socket::SSL->start_SSL($fh , %opts); # this is the snippet to fetch new data $bits = ''; vec($bits, fileno($fh), 1) = 1; if(select($bits, undef, undef, $timeout)) { $len = sysread($fh, $buf, 200, length($buf)); } else { die "timeout: $!\n"; }

the buffer size "200" is used just as example here. The protocol is not line-based and may contain arbitary 8bit data.

I have the problem, that when the server sends a packet larger than 200 bytes immediately after the SSL handshake while reading the server greating, select() succeeds exactly once, the second call of select() simply stalls, but it should rather return true, because of the remaining stuff in Net::SSLeay's buffer, I think.

Another user has the problem with a buffer size of 2048, which was my default actually, later in the operation and not just right after the SSL handshake. Presumly that particular communication produced a pending buffer of more than 2048 byte.

To work around I will probably code a loop around sysread() to fetch all data available at the particular time. Maybe a large read size, say 32KB as this is the buffer size in Net::SSLeay, will do the trick as well.

But, am I really wrong to assume select() is to return true in this case? Or is there another way to have a working timeout in sysread()/syswrite()? $fh->timeout(num) in blocking mode does not work.

my versions of IO::Socket::SSL v1.31, Net::SSLeay v1.30

Regards, ska

Replies are listed 'Best First'.
Re: IO::Socket::SSL's select() ignores pending data (kernel)
by tye (Sage) on Jun 18, 2010 at 23:39 UTC

    No, select knows nothing about Net::SSLeay nor its buffers. select, being an interface to a low-level (kernel) routine (select(2)) only knows about buffers inside of the operating system.

    IO::Socket::SSL notes of start_SSL():

    This will convert a glob reference or a socket that you provide to an IO::Socket::SSL object.
    so you are lucky that select even works at all.

    Perhaps IO::Socket::SSL could use some support for "asking if there is any data left inside of its buffers". Then you can loop until there is no data left in the buffers inside of the loop that uses select.

    But that assumes that asking for 200 bytes when there are only, for example, 100 bytes in the buffer doesn't hang waiting for the next 100 bytes to arrive.

    But it looks like IO::Socket::SSL supports non-blocking reads, so you should be able to get something working.

    Update: Ah, pending(); I missed that. Well spotted, rowdog. That makes for a nice solution.

    - tye        

Re: IO::Socket::SSL's select() ignores pending data
by choroba (Cardinal) on Jun 18, 2010 at 15:29 UTC
Re: IO::Socket::SSL's select() ignores pending data
by rowdog (Curate) on Jun 19, 2010 at 17:30 UTC

    Why not read all available data at once?

    $len = sysread($fh, $buf, $fh->pending(), length($buf));
Re: IO::Socket::SSL's select() ignores pending data
by dk (Chaplain) on Jun 20, 2010 at 16:12 UTC
    In your select(), you're waiting for socket to become readable, but SSL communication is not as simple as that, it may require some internal writing in between. Your generic code should be more like this:

    if ( $SSL_ERROR == SSL_WANT_READ) { select($rbits,undef,undef,...); sysread... } elsif ( $SSL_ERROR == SSL_WANT_WRITE) { select(undef,$wbits,undef,...); sysread... # YES, sysread! }
    I recently played with non-blocking SSL stuff, and both timeout and select work fine for me that way.

    OTOH all that stuff is needed only for non-blocking code. If the only thing needed is timeout in blocking code, I'd just use alarm($timeout).