Ticket #3 (closed defect: fixed)

Opened 5 years ago

Last modified 5 years ago

Cannot call connect with a socket that is already bound.

Reported by: igloo Owned by:
Priority: critical Milestone:
Component: network Version:
Keywords: Cc:


Originally reported here: http://hackage.haskell.org/trac/ghc/ticket/2784

> import Network.Socket
> sock <- socket AF_INET Datagram 0
Loading package parsec- ... linking ... done.
Loading package network- ... linking ... done.
> bindSocket sock (SockAddrInet aNY_PORT iNADDR_ANY)
> connect sock undefined
*** Exception: user error (connect: can't peform connect on socket in status Bound)

Network.Socket.connect checks the SocketStatus of the socket:

if currentStatus /= NotConnected

From The Open Group Base Specifications Issue 6: "If the socket has not already been bound to a local address, connect() shall bind it to an address which, unless the socket's address family is AF_UNIX, is an unused local address."

Change History

Changed 5 years ago by David

  • priority changed from major to critical

I think this should be considered a very high priority bug, especially since the fix is so easy (only changes one line of code).

Just to add some perspective, let me give several examples of where you absolutely need to bind a socket before connecting it:

- Many NAT boxes simply won't allow active mode FTP to work unless back connections come from the ftp-data port (20). Some ftp clients also insist on this port. The ftp server needs to bind port 20, then connect back to the client. That means you can't even implement a functional ftp server in haskell.

- Some servers only accept connections from reserved TCP ports. For example, if you are trying to interact with an NFS mountd server, as typically configured, the server will reject requests from TCP ports >= 1024. The (now obsolete) rsh and rlogin commands worked this way, too, as well as certain authentication modes in some versions of SSH.

- With UDP, the only way for non-superuser software to get feedback from ICMP port unreachable messages is to connect sockets. Without feedback from these messages, you have no way of knowing whether or not a process is listening on a particular UDP port. Yet two processes using UDP often want to select and know about their port number ahead of time.

So basically this bug is a show stopper for many classes of application. (I currently need the functionality for a test harness that has the process under test exchange packets with my UDP port, which I must know in advance as the other process binds a random port. I want to detect the process has crashed quickly though ICMP port unreachable messages, rather than having to time out.) Yet I'm hoping the fix is only one line, some thing like this:

 connect sock@(MkSocket s _family _stype _protocol socketStatus) addr = do
  modifyMVar_ socketStatus $ \currentStatus -> do
- if currentStatus /= NotConnected 
+ if currentStatus /= NotConnected && currentStatus /= Bound
    ioError (userError ("connect: can't peform connect on socket in status " ++
          show currentStatus))

Unless I'm missing some subtle issue about why this restriction is in place, if the fix really is this easy, then I hope the bug can be fixed quickly.


Changed 5 years ago by anonymous

  • status changed from new to closed
  • resolution set to fixed

Fixed in darcs head. Thanks for the report.

Changed 5 years ago by bos

Uh, oops, I didn't realise I could make changes to tickets while not logged in. That last was me.

Note: See TracTickets for help on using tickets.