From: Brian Modra Date: 2013-01-30T17:02:43+09:00 Subject: SSLSocket in non-blocking mode Hi, I've had a little trouble getting SSLSocket to behave as I want it to. It's #pending method returns 0 until I call #sysread(1)... which throws EOFError if there is nothing to read, or 1 byte after some bytes have become available. I suspect that the implementation does not fill its internal buffer with raw bytes to decrypt to its output buffer until #sysread is called on an empty output buffer. Given that the SSLSocket class almost certainly would not be implementing its own thread to do this automatically, that seems reasonable. But my solution seems a bit "hackish", and I would appreciate if someone knows a better way to do this? (Maybe IO:select on the tcp socket to see if it has bytes ready, then call #sysread) Following is a simplified code snippet that shows essentially what I'm doing: class SslSocketServer def initialize(port, hostname, cert_fname, key_fname) @socket_server = Socket.new(AF_INET, SOCK_STREAM, 0) sockaddr = Socket.sockaddr_in(port, hostname) @socket_server.bind(sockaddr) @socket_server.listen(5) @ssl_context = OpenSSL::SSL::SSLContext.new cert_file = File.open(cert_fname) key_file = File.open(key_fname) @ssl_context.cert = OpenSSL::X509::Certificate.new(cert_file) @ssl_context.key = OpenSSL::PKey::RSA.new(key_file) end def accept ssl = nil begin sock, addr = @socket_server.accept begin sslsock = OpenSSL::SSL::SSLSocket.new(sock, @ssl_context) sslsock.sync_close = true sslsock.accept ssl = SslConnection.new(sock, sslsock, addr) rescue SSLError => ex sock.close raise ex end rescue IO::WaitReadable rescue Errno::EINTR => e STDERR.puts("#{e.class}: #{e.to_s}") STDERR.puts(e.backtrace.join("\n")) end ssl end end class SslConnection def initialize(sock, sslsock, addr) @sock = sock @sslsock = sslsock @addr = addr end def recvfrom_nonblock(size) available = @sslsock.pending if available == 0 begin byte = @sslsock.sysread(1) [byte, @addr] rescue EOFError raise SslNotEnoughPending, "EOFError" end else size = available if available < size [@sslsock.sysread(size), @addr] end end def close @sslsock.close @sock.close end def write(bytes) @sslsock.syswrite(bytes) end end Then I read from the SslConnection as if it were a socket returned from Socket#accept, using the rcvfrom_nonblock and write methods only. -- Posted via http://www.ruby-forum.com/.