Problem: TCPSocket.new host, port fails with
. . . :in `new': Invalid argument - "connect(2)" (Errno::EINVAL)
Environment:
Windows 2000
Cygwin dll versions 1.1.8 & 1.3.2
Ruby versions 1.6.4 & 1.7.0
Details:
This appears to be a timing issue. I have tracked the error down to
file ruby-source/ext/socket/socket.c, function ruby_connect(). The
first time connect() (translates to cygwin_connect() from
cygwin-source/winsup/cygwin/net.cc) is called, it returns EINPROGRESS
(windows returns WSAEWOULDBLOCK to cygwin1.dll which translates it to
EINPROGRESS) and windows begins setting up the socket. If connect()
is called again, too soon after the first call, EINVAL is returned. I
believe this is because of a delay in resource allocation inside the
windows ip stack but I have no way to confirm this.
Temporary Solution:
I have fixed this on my machine by implementing a .1 second delay
before subsequent calls to connect() if the prior connect() returns
EAGAIN or EINPROGRESS. I used select to implement this and I have no
idea how portable or thread safe my kludge is but it currently works
for me.
----- from initialization in ruby_connect
#ifdef EINPROGRESS
struct timeval tv;
#endif
-----
----- from switch (errno) in ruby_connect
----- after case EINPROGRESS:
----- before #endif
tv.tv_sec = 0;
tv.tv_usec = 100000;
select(0, NULL, NULL, NULL, &tv);
-----
Permanent Solution:
I do not know a good portable and safe solution. Someone from my
office suggested the windows API call WaitForObject but that seems
more appropriate for the cygwin code than for ruby code. I am more
than willing to help test and/or research the problem further but I do
not have the expertise to solve it myself.
Sean Carley
seanacarley / hotmail.com