Bugs item #2872, was opened at 2005-11-23 11:36
You can respond by visiting: 
http://rubyforge.org/tracker/?func=detail&atid=1698&aid=2872&group_id=426

Category: Standard Library
Group: None
Status: Open
Resolution: None
Priority: 3
Submitted By: Andrew Wason (awason)
Assigned to: Nobody (None)
Summary: TCPServer should not use SO_REUSEADDR in Cygwin port

Initial Comment:
SO_REUSEADDR behaves strangely under Win32, it allows multiple LISTENs on the same port with indeterminate results. On other platforms SO_REUSEADDR only allows binding to a port not in use or in the TIME_WAIT state.

"This socket option tells the kernel that even if this port is busy (in the TIME_WAIT state), go ahead and reuse it anyway.  If it is busy, but with another state, you will still get an address already in use error."
http://www.unixguide.net/network/socketfaq/4.5.shtml

"Once the second sockey has successfully bound, the behvaior for all sockets bound to that port is indeterminate."
http://msdn.microsoft.com/library/default.asp?url=/library/en-us/winsock/winsock/using_so_reuseaddr_and_so_exclusiveaddruse.asp

In Ruby 1.8.2/1.8.3, ext/socket/socket.c does not set SO_REUSEADDR for TCPServer if _WIN32 is defined, so things work normally in the i386-mswin32 builds. But the i386-cygwin builds do set SO_REUSEADDR and so weird things can happen.

So in socket.c init_inetsock_internal(), this code should also not be compiled for Cygwin (__CYGWIN__):

	if (type == INET_SERVER) {
#ifndef _WIN32
	    status = 1;
	    setsockopt(fd, SOL_SOCKET, SO_REUSEADDR,
		       (char*)&status, sizeof(status));
#endif

Here is a comparison of current mswin32 and cygwin behaviors:

== Cygwin, 2 process actively listening to same port

$ ruby -v
ruby 1.8.3 (2005-09-21) [i386-cygwin]

# From two different consoles:
$ ruby -rsocket -e 'TCPServer.new("localhost", 3900).accept'
$ ruby -rsocket -e 'TCPServer.new("localhost", 3900).accept'

$ netstat -a -p TCP | grep 3900
  TCP    jello:3900             jello:0                LISTENING
  TCP    jello:3900             jello:0                LISTENING


== MSWIN32, 2nd process correctly fails with EADDRINUSE

C:\>ruby -v
ruby 1.8.2 (2004-12-25) [i386-mswin32]

# From two different consoles:
C:\>ruby -rsocket -e 'TCPServer.new("localhost", 3900).accept'
C:\>ruby -rsocket -e 'TCPServer.new("localhost", 3900).accept'
-e:1:in `initialize': Only one usage of each socket address (protocol/network address/port) is normally permitted. - bind(2) (Errno::EADDRINUSE)
        from -e:1:in `new'
        from -e:1



----------------------------------------------------------------------

You can respond by visiting: 
http://rubyforge.org/tracker/?func=detail&atid=1698&aid=2872&group_id=426