How to set socket option SO_RCVTIMEO

Hi,

How to set socket option SO_RCVTIMEO in Windows XP?
The C version use somekind struct.

Regards,

– Zakaria
[email protected] Yahoo!: z4k4ri4

Did you ever find out how to do this? I am looking around, haven’t
found any documentation

Zakaria wrote:

Hi,

How to set socket option SO_RCVTIMEO in Windows XP?
The C version use somekind struct.

Regards,

– Zakaria
[email protected] Yahoo!: z4k4ri4

Zakaria wrote:

How to set socket option SO_RCVTIMEO in Windows XP?
The C version use somekind struct.

First, read the option:

irb(main):001:0> require ‘socket’
=> true
irb(main):002:0> s = TCPServer.new(1234)
=> #TCPServer:0xb7d246d4
irb(main):003:0> s.getsockopt(Socket::SOL_SOCKET, Socket::SO_RCVTIMEO)
=> “\000\000\000\000\000\000\000\000”

So if it’s a struct timeval, that’s a 32-bit tv_sec followed by a 32-bit
tv_usec. Not clear about the byte order, though, since it’s all zero
here.

So let’s try native byte ordering, to set a timeout of 1.5 seconds (1
second + 500,000 microseconds):

irb(main):008:0> n = [1, 500_000].pack(“I_2”)
=> “\001\000\000\000 \241\a\000”
irb(main):009:0> s.setsockopt(Socket::SOL_SOCKET, Socket::SO_RCVTIMEO, n
)
=> 0
irb(main):010:0> s.accept
Errno::EAGAIN: Resource temporarily unavailable
from (irb):10:in `accept’
from (irb):10
from :0

Yep, there was a pause of 1.5 seconds before the exception was raised.

Look OK?

It appears that I am supposed to call setsockopt before connecting –
which would explain why your example (which calls setsockopt before
calling accept()) works, and mine, where it is client side, does not. I
have yet to figure out how to create a client socket that I can call
setsockopt on without connecting right away.

I’ll post any update

How about something like:

s = Socket.new(…)
s.setsockopt(Socket::SOL_SOCKET, Socket::SO_RCVTIMEO, …)
s.connect(…)

–wpd

I tried something like that, and it never timed out – so after your
post, I tried the following (the server I’m connecting to reads a CRLF
terminated string, and returns a response after X seconds (150 in this
case))

sock = TCPSocket.new(‘foodlinux’, 3232)
=> #TCPSocket:0x2be080
opt = [1, 1].pack(“I_2”)
=> “\001\000\000\000\001\000\000\000”
sock.setsockopt(Socket::SOL_SOCKET, Socket::SO_RCVTIMEO, opt)
=> 0
sock.write(“150\r\n”)
=> 5
puts “read: #{sock.gets}”

it never times out – seems like it should return after 1.000001 seconds
regardless of the byte ordering.

What am I missing here?

Brian C. wrote:

Zakaria wrote:

How to set socket option SO_RCVTIMEO in Windows XP?
The C version use somekind struct.

First, read the option:

irb(main):001:0> require ‘socket’
=> true
irb(main):002:0> s = TCPServer.new(1234)
=> #TCPServer:0xb7d246d4
irb(main):003:0> s.getsockopt(Socket::SOL_SOCKET, Socket::SO_RCVTIMEO)
=> “\000\000\000\000\000\000\000\000”

So if it’s a struct timeval, that’s a 32-bit tv_sec followed by a 32-bit
tv_usec. Not clear about the byte order, though, since it’s all zero
here.

So let’s try native byte ordering, to set a timeout of 1.5 seconds (1
second + 500,000 microseconds):

irb(main):008:0> n = [1, 500_000].pack(“I_2”)
=> “\001\000\000\000 \241\a\000”
irb(main):009:0> s.setsockopt(Socket::SOL_SOCKET, Socket::SO_RCVTIMEO, n
)
=> 0
irb(main):010:0> s.accept
Errno::EAGAIN: Resource temporarily unavailable
from (irb):10:in `accept’
from (irb):10
from :0

Yep, there was a pause of 1.5 seconds before the exception was raised.

Look OK?

hehe yeh I just realized I could use a regular Socket instead of a TCP
Socket – it doesn’t appear to be the only problem though. here’s my
latest code (which still doesn’t timeout properly)

require ‘socket’

opt = [1, 500_000].pack(“I_2”)

sock = Socket.new(Socket::AF_INET, Socket::SOCK_STREAM, 0)
sockaddr = Socket.pack_sockaddr_in(3232, ‘192.168.1.10’)

sock.setsockopt(Socket::SOL_SOCKET, Socket::SO_RCVTIMEO, opt)
puts “sockopt = #{sock.getsockopt(Socket::SOL_SOCKET,
Socket::SO_RCVTIMEO).inspect}”

sock.connect(sockaddr)

#this tells the server at 192.168.1.10:3232 to wait 10 seconds before
responding, so we should get a timeout on our socket
sock.write(“10\r\n”)

start_time = Time.now
result = sock.gets
time = Time.now - start_time

puts “read: #{sock.gets} after: #{time} seconds”
#no timeout occured, this read returns after 10 seconds

Patrick D. wrote:

How about something like:

s = Socket.new(…)
s.setsockopt(Socket::SOL_SOCKET, Socket::SO_RCVTIMEO, …)
s.connect(…)

–wpd

Also, if you’re not concerned about the possibility of transmission
stopping part way through a response, you can do

if select([sock],nil,nil,1.5)
result = sock.gets
else
puts “I timed out!”
end

Kem Mason wrote:

hehe yeh I just realized I could use a regular Socket instead of a TCP
Socket – it doesn’t appear to be the only problem though. here’s my
latest code (which still doesn’t timeout properly)

Well, probably you shouldn’t be using setsockopt for this at all. Note
that setting SO_RCVTIMEO just raises an EAGAIN on timeout; I’d expect
that gets would trap that and retry.

Why not simply:

require ‘timeout’
result = nil
timeout(1.5) {
result = sock.gets
}

The problem with using timeout is that it is unsafe: (see
http://tinyurl.com/5fngha )
I have actually encountered a problem using timeout where my thread hung
forever (10 times in production over the last couple months) – so this
is why I am starting to do something else.

You’re right that gets silently ignores the exception – turns out that
was the main problem – if I use sock.recvfrom, I get the exception as I
want – then I just have to handle the case where I get only part of the
response (and still have time left).

All is working now when using the code at: http://pastie.org/314914

thanks much for your help all

Brian C. wrote:

Kem Mason wrote:

hehe yeh I just realized I could use a regular Socket instead of a TCP
Socket – it doesn’t appear to be the only problem though. here’s my
latest code (which still doesn’t timeout properly)

Well, probably you shouldn’t be using setsockopt for this at all. Note
that setting SO_RCVTIMEO just raises an EAGAIN on timeout; I’d expect
that gets would trap that and retry.

Why not simply:

require ‘timeout’
result = nil
timeout(1.5) {
result = sock.gets
}