# Blocking read after select

**URL:** <https://www.ruby-forum.com/t/blocking-read-after-select/96113>\
**Category:** Ruby\
**Created:** [June 26, 2006, 3:03pm UTC](https://www.ruby-forum.com/t/blocking-read-after-select/96113 "2006-06-26T15:03:09Z")\
**Posts on this page:** 16\
**Page:** 1

<div class="post-metadata">

**Author:** ![gwik](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/g/90ced4/32.png) [@gwik](https://www.ruby-forum.com/u/gwik)\
**Post date:** [June 26, 2006, 3:03pm UTC](https://www.ruby-forum.com/t/blocking-read-after-select/96113/1 "2006-06-26T15:03:09Z")

</div>

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

---

<div class="post-metadata">

**Author:** ![gwik](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/g/90ced4/32.png) [@gwik](https://www.ruby-forum.com/u/gwik)\
**Post date:** [June 26, 2006, 3:26pm UTC](https://www.ruby-forum.com/t/blocking-read-after-select/96113/2 "2006-06-26T15:26:10Z")

</div>

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

---

<div class="post-metadata">

**Author:** ![gwik](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/g/90ced4/32.png) [@gwik](https://www.ruby-forum.com/u/gwik)\
**Post date:** [June 26, 2006, 3:45pm UTC](https://www.ruby-forum.com/t/blocking-read-after-select/96113/3 "2006-06-26T15:45:48Z")

</div>

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

---

<div class="post-metadata">

**Author:** ![gwik](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/g/90ced4/32.png) [@gwik](https://www.ruby-forum.com/u/gwik)\
**Post date:** [June 26, 2006, 3:54pm UTC](https://www.ruby-forum.com/t/blocking-read-after-select/96113/4 "2006-06-26T15:54:56Z")

</div>

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.

---

<div class="post-metadata">

**Author:** ![gwik](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/g/90ced4/32.png) [@gwik](https://www.ruby-forum.com/u/gwik)\
**Post date:** [June 26, 2006, 4:08pm UTC](https://www.ruby-forum.com/t/blocking-read-after-select/96113/5 "2006-06-26T16:08:20Z")

</div>

> > > > 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.

---

<div class="post-metadata">

**Author:** ![gwik](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/g/90ced4/32.png) [@gwik](https://www.ruby-forum.com/u/gwik)\
**Post date:** [June 26, 2006, 3:58pm UTC](https://www.ruby-forum.com/t/blocking-read-after-select/96113/6 "2006-06-26T15:58:33Z")

</div>

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

---

<div class="post-metadata">

**Author:** ![gwik](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/g/90ced4/32.png) [@gwik](https://www.ruby-forum.com/u/gwik)\
**Post date:** [June 26, 2006, 4:17pm UTC](https://www.ruby-forum.com/t/blocking-read-after-select/96113/7 "2006-06-26T16:17:23Z")

</div>

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.

---

<div class="post-metadata">

**Author:** ![gwik](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/g/90ced4/32.png) [@gwik](https://www.ruby-forum.com/u/gwik)\
**Post date:** [June 26, 2006, 4:53pm UTC](https://www.ruby-forum.com/t/blocking-read-after-select/96113/8 "2006-06-26T16:53:56Z")

</div>

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 ??

---

<div class="post-metadata">

**Author:** ![gwik](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/g/90ced4/32.png) [@gwik](https://www.ruby-forum.com/u/gwik)\
**Post date:** [June 26, 2006, 4:23pm UTC](https://www.ruby-forum.com/t/blocking-read-after-select/96113/9 "2006-06-26T16:23:40Z")

</div>

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

---

<div class="post-metadata">

**Author:** ![gwik](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/g/90ced4/32.png) [@gwik](https://www.ruby-forum.com/u/gwik)\
**Post date:** [June 26, 2006, 5:46pm UTC](https://www.ruby-forum.com/t/blocking-read-after-select/96113/10 "2006-06-26T17:46:16Z")

</div>

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

---

<div class="post-metadata">

**Author:** ![gwik](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/g/90ced4/32.png) [@gwik](https://www.ruby-forum.com/u/gwik)\
**Post date:** [June 26, 2006, 6:32pm UTC](https://www.ruby-forum.com/t/blocking-read-after-select/96113/11 "2006-06-26T18:32:42Z")

</div>

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/](http://icalendar.rubyforge.org/)

might help along the way - or it might not…

cheers.

-a

---

<div class="post-metadata">

**Author:** ![gwik](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/g/90ced4/32.png) [@gwik](https://www.ruby-forum.com/u/gwik)\
**Post date:** [June 26, 2006, 7:10pm UTC](https://www.ruby-forum.com/t/blocking-read-after-select/96113/12 "2006-06-26T19:10:36Z")

</div>

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/](http://icalendar.rubyforge.org/)

Not helping, but very interesting.

Thx.

---

<div class="post-metadata">

**Author:** ![gwik](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/g/90ced4/32.png) [@gwik](https://www.ruby-forum.com/u/gwik)\
**Post date:** [June 26, 2006, 7:11pm UTC](https://www.ruby-forum.com/t/blocking-read-after-select/96113/13 "2006-06-26T19:11:41Z")

</div>

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/](http://www.stunnel.org/) ) a try. It does what you are  
trying to do, is very fast, and works great!

–Aaron

---

<div class="post-metadata">

**Author:** ![gwik](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/g/90ced4/32.png) [@gwik](https://www.ruby-forum.com/u/gwik)\
**Post date:** [June 26, 2006, 7:14pm UTC](https://www.ruby-forum.com/t/blocking-read-after-select/96113/14 "2006-06-26T19:14:00Z")

</div>

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.

---

<div class="post-metadata">

**Author:** ![gwik](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/g/90ced4/32.png) [@gwik](https://www.ruby-forum.com/u/gwik)\
**Post date:** [June 26, 2006, 5:12pm UTC](https://www.ruby-forum.com/t/blocking-read-after-select/96113/15 "2006-06-26T17:12:34Z")

</div>

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.

---

<div class="post-metadata">

**Author:** ![gwik](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/g/90ced4/32.png) [@gwik](https://www.ruby-forum.com/u/gwik)\
**Post date:** [June 26, 2006, 7:23pm UTC](https://www.ruby-forum.com/t/blocking-read-after-select/96113/16 "2006-06-26T19:23:50Z")

</div>

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/](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.
