Blocking read after select

Hi,

I’ve some trouble reading an IO after a select

Here is the code.

while sock = tunnel.accept

Thread.start(sock) do |s|

ssl_sock = get_ssl_socket("ssl.gwikzone.org", 443)

#set_non_blocking ssl_sock.to_io
#set_non_blocking s.to_io
STDERR.puts "thread start

#{Thread.current.object_id}/#{s.object_id}/#{ssl_sock.object_id}"

while true
  STDERR.puts "select..."
  res = select([s, ssl_sock])

  unless res.nil?

    for rsock in res[0]
      #delete closed connections
      if rsock.eof? || ssl_sock.closed?
        s.close
        ssl_sock.close
        Thread.current.terminate
      end

      if rsock == s
        STDERR.puts "read s"
        buf = s.read
        STDERR.puts "s: \n#{send}"
        ssl_sock.write buf unless buf.nil? || buf.empty?
      end

      if rsock == ssl_sock
        STDERR.puts "read ssl"
        buf = rsock.read
        STDERR.puts "ssl: \n#{send}"
        s.write buf unless buf.nil? || buf.empty?
      end

    end #for
  end #unless
end #while true

end #Thread.start

end #while

output :

thread start 539408208/539408228/539408078
select…
read s
<<— get stuck here

I tried to use non-blocking io but same thing happened which is very
strange.

Thank’s for help

Antonin AMAND wrote:

Hi,

I’ve some trouble reading an IO after a select

Could it by related with the fact that require use openssl stdlib

On Mon, 26 Jun 2006, Antonin AMAND wrote:

Hi,

I’ve some trouble reading an IO after a select

you are calling IO#read, which reads till eof. try something like

buf = rsock.read 8192

and you should see data. typically one would have the client do
somthing like

bufsize = [buf.size].pack ‘N’
s.write bufsize
s.write buf
s.flush

and, in the server, something like

bufsize = s.read 4
bufsize = bufsize.unpack(‘N’).first
buf = s.read bufsize

in otherwords, every message is preceded by it’s length in a packet
guarunteed
to be 4 bytes big. you might start out with something like this
(untested):

class NetString < ::String
def self.recv io
buf = io.read 4
size = buf.unpack(‘N’).first
new(read(size))
end

 def self.send s, io
   s = s.to_s
   size = [s.size].pack('N')
   io.write size
   io.write s
 end

 def send io
   self.class.send self, io
 end

end

then you can do

ns = NetString.recv socket

or

ns = NetString.new ‘foobar’
ns.send socket

regards.

-a

unknown wrote:

On Mon, 26 Jun 2006, Antonin AMAND wrote:

Hi,

I’ve some trouble reading an IO after a select

you are calling IO#read, which reads till eof. try something like

buf = rsock.read 8192

I’ve already tried that with different values. I also tried with IO#gets
(with different values as separator("\n", “\r\n”, “\n”)). It always
block.

I’ve used tcpdump to see if something comming on the socket and it does,
but i’m never able to read. That’s very very strange.

Does the fact that I require ‘openssl’ modify the problem.

The goal is to provide a https tunnel. In order to use iCal with ssl
socket.
<<<

Try the eventmachine library. Can probably accomplish this goal with
much
less code.

Here is the full code.

The goal is to provide a https tunnel. In order to use iCal with ssl
socket.
The server will listen on 127.0.0.7:8888 and forward all traffic comming
from one socket to a ssl socket connected to the distant https server.
And back.

#! /usr/bin/env/ruby

require ‘openssl’
require ‘socket’

def set_non_blocking(io)
flag = File::NONBLOCK
if defined?(Fcntl::F_GETFL)
flag |= io.fcntl(Fcntl::F_GETFL)
end
io.fcntl(Fcntl::F_SETFL, flag)
end

def get_ssl_socket(host, port)
ssl_context = OpenSSL::SSL::SSLContext.new()
ssl_context.verify_mode = OpenSSL::SSL::VERIFY_NONE
socket = TCPSocket.new(host, port)
sslsocket = OpenSSL::SSL::SSLSocket.new(socket, ssl_context)
unless ssl_context.verify_mode
warn “warning: peer certificate won’t be verified this session.”
end
sslsocket.sync_close = true
sslsocket.connect
sslsocket
end

FIXME: listen on all interfaces -> localhost

tunnel = TCPServer.new(8888)
tunnel.listen(5)

while sock = tunnel.accept

Thread.start(sock) do |s|

ssl_sock = get_ssl_socket("ssl.gwikzone.org", 443)

#set_non_blocking ssl_sock.to_io
#set_non_blocking s.to_io
STDERR.puts "thread start 

#{Thread.current.object_id}/#{s.object_id}/#{ssl_sock.object_id}"

while true
  STDERR.puts "select..."
  res = select([s, ssl_sock])

  unless res.nil?

    for rsock in res[0]
      #delete closed connections
      if rsock.eof? || ssl_sock.closed?
        s.close
        ssl_sock.close
        Thread.current.terminate
      end

      if rsock == s
        STDERR.puts "read s"
        buf = s.read unless s.ready?
        STDERR.puts "s: \n#{send}"
        ssl_sock.write buf unless buf.nil? || buf.empty?
      end

      if rsock == ssl_sock
        STDERR.puts "read ssl"
        buf = rsock.read
        STDERR.puts "ssl: \n#{send}"
        s.write buf unless buf.nil? || buf.empty?
      end

    end #for
  end #unless
end #while true

end #Thread.start

end #while

Francis C. wrote:

The goal is to provide a https tunnel. In order to use iCal with ssl
socket.
<<<

Try the eventmachine library. Can probably accomplish this goal with
much
less code.

I will look at this but I would like to know why this isn’t working.

Thanks anyway.

unknown wrote:

On Mon, 26 Jun 2006, Antonin AMAND wrote:

Here is the full code.

if you make the mod i suggested it works fine:

It actually do work. I don’t know why it wasn’t i’ve tried with gets
dozens of times. Anyway, it’s working fine now but is very very slow,
the ssl socket respond with some strange delay (2-3 sec). Is it related
with buffering ??

On Mon, 26 Jun 2006, Antonin AMAND wrote:

Here is the full code.

if you make the mod i suggested it works fine:

harp:~ > ruby a.rb
thread start -609397948/-609397928/-609398078
select…
reading s…
read: <“11223 @ Mon Jun 26 08:18:09 MDT 2006\n”>
select…
thread start -609398348/-609398318/-609398498
select…
reading s…
read: <“11224 @ Mon Jun 26 08:18:10 MDT 2006\n”>
select…
thread start -609398768/-609398738/-609398918
select…
reading s…
read: <“11225 @ Mon Jun 26 08:18:11 MDT 2006\n”>
select…

harp:~ > cat a.rb
#! /usr/bin/env/ruby

require ‘openssl’
require ‘socket’

def set_non_blocking(io)
flag = File::NONBLOCK
if defined?(Fcntl::F_GETFL)
flag |= io.fcntl(Fcntl::F_GETFL)
end
io.fcntl(Fcntl::F_SETFL, flag)
end

def get_ssl_socket(host, port)
ssl_context = OpenSSL::SSL::SSLContext.new()
ssl_context.verify_mode = OpenSSL::SSL::VERIFY_NONE
socket = TCPSocket.new(host, port)
sslsocket = OpenSSL::SSL::SSLSocket.new(socket, ssl_context)
unless ssl_context.verify_mode
warn “warning: peer certificate won’t be verified this session.”
end
sslsocket.sync_close = true
sslsocket.connect
sslsocket
end

FIXME: listen on all interfaces -> localhost

tunnel = TCPServer.new(8888)
tunnel.listen(5)

fork tester clients in background

fork do
loop do
fork do
s = TCPSocket.new ‘localhost’, 8888
s.puts “#{ $$ } @ #{ Time.now.to_s }”
end
Process.wait
sleep 1
end
end

while sock = tunnel.accept

Thread.start(sock) do |s|

 ssl_sock = get_ssl_socket("ssl.gwikzone.org", 443)

 #set_non_blocking ssl_sock.to_io
 #set_non_blocking s.to_io
 STDERR.puts "thread start 

#{Thread.current.object_id}/#{s.object_id}/#{ssl_sock.object_id}"

 while true
   STDERR.puts "select..."
   res = select([s, ssl_sock])

   unless res.nil?

     for rsock in res[0]
       #delete closed connections
       if rsock.eof? || ssl_sock.closed?
         s.close
         ssl_sock.close
         Thread.current.terminate
       end

       if rsock == s
         STDERR.puts "reading s..."
         buf = s.gets
         STDERR.puts "read: <#{ buf.inspect }>"
         #buf = s.read unless s.ready?
         #STDERR.puts "s: \n#{send}"
         #ssl_sock.write buf unless buf.nil? || buf.empty?
       end

       if rsock == ssl_sock
         STDERR.puts "read ssl"
         buf = rsock.read
         STDERR.puts "ssl: \n#{send}"
         s.write buf unless buf.nil? || buf.empty?
       end

     end #for
   end #unless
 end #while true

end #Thread.start
end #while

perhaps networking is fubar on your machine? any silly virus software
running?

regards.

-a

unknown wrote:

On Mon, Jun 26, 2006 at 11:54:11PM +0900, Antonin A. wrote:

with buffering ??
Have you thought about using an ssh-tunnel. Prob would be faster.

iCal require http

On Mon, 26 Jun 2006, Antonin A. wrote:

with buffering ??
ipv6? dns issues? other than that i dunno - it’s fast on my machine.

btw. did you know about this

http://icalendar.rubyforge.org/

might help along the way - or it might not…

cheers.

-a

unknown wrote:

On Mon, 26 Jun 2006, Antonin A. wrote:

with buffering ??
ipv6? dns issues? other than that i dunno - it’s fast on my machine.

I’ll check

btw. did you know about this

http://icalendar.rubyforge.org/

Not helping, but very interesting.

Thx.

On Tue, Jun 27, 2006 at 12:46:28AM +0900, Antonin A. wrote:

unknown wrote:

On Mon, Jun 26, 2006 at 11:54:11PM +0900, Antonin A. wrote:

with buffering ??
Have you thought about using an ssh-tunnel. Prob would be faster.

iCal require http

Give stunnel ( http://www.stunnel.org/ ) a try. It does what you are
trying to do, is very fast, and works great!

–Aaron

I think I’ve found a part of the problem.

Reading the openssl library source code I discover that SSLSocket are
non-blocking IO.

I’m not very familiar with the non-blocking IO. How would I now when I
should read or not without an active loop ?

Thank.

Antonin.

On Mon, Jun 26, 2006 at 11:54:11PM +0900, Antonin A. wrote:

with buffering ??
Have you thought about using an ssh-tunnel. Prob would be faster.

Aaron P. wrote:

On Tue, Jun 27, 2006 at 12:46:28AM +0900, Antonin A. wrote:

unknown wrote:

On Mon, Jun 26, 2006 at 11:54:11PM +0900, Antonin A. wrote:

with buffering ??
Have you thought about using an ssh-tunnel. Prob would be faster.

iCal require http

Give stunnel ( http://www.stunnel.org/ ) a try. It does what you are
trying to do, is very fast, and works great!

–Aaron

Seems to be. If I’ve seen that sooner I may not have start this program
and I’ll probably use it at last. But for now I’ll continue searching a
solution to my problem, I’m not giving up !

Thank you.