[Haskell-cafe] how to listen on a specific IP using the network library

Jeremy Shaw jeremy at n-heptane.com
Mon Mar 15 15:09:06 EDT 2010


Hello,

I would really like to modify happstack so that you can specific what IP
address to listen on.

So I think I want a function like:

listenOnAddr :: SockAddr -> IO Socket

The problem is that the user might want to specify IPv4 or IPv6 address. But
support for IPv6 is only conditionally compiled into the network library.

I can not figure out how to write my code so that it will compile regardless
of whether network was compiled with ipv6 enabled.

I got this far:


--------------------------------
import qualified Control.Exception as Exception
import Network.BSD    (getProtocolNumber)
import Network.Socket

listenOnAddr :: Family -> SocketType -> SockAddr -> IO Socket
listenOnAddr fam typ sockAddr =
  do proto <- getProtocolNumber "tcp"
     Exception.bracketOnError
      (socket fam typ proto)
      (sClose)
      (\sock -> do
          setSocketOption sock ReuseAddr 1
          bindSocket sock sockAddr
          listen sock maxListenQueue
          return sock
        )
---------------------------------------

But I am not sure how to modify it to calculate 'fam' and 'typ' from
'sockAddr' with out making my code depend on IPv6 being enabled.

If I was adding this function directly to the network package, there would
be no problem. I could just use:

#if defined(IPV6_SOCKET_SUPPORT)
#endif

But in a 3rd party library IPV6_SOCKET_SUPPORT is not defined. I could copy
the autoconf code into my library -- but there is no guarantee that my
library and the network library were compiled with the same value for
IPV6_SOCKET_SUPPORT.

In happstack we use a really horrible trick involving template haskell where
we see if the  SockAddrInet6 constructor exists at compile time and
conditionally compile different versions of the code that way. But it is
really ugly. We defined supportsIPv6 here:

http://patch-tag.com/r/mae/happstack/snapshot/current/content/pretty/happstack-server/src/Happstack/Server/HTTP/SocketTH.hs

And then use it in acceptLite here:

http://patch-tag.com/r/mae/happstack/snapshot/current/content/pretty/happstack-server/src/Happstack/Server/HTTP/Socket.hs

It wouldn't be that bad if we could actually use the [| |] mechanism. But we
can't because it won't compile when ipv6 support is not enabled due to
'(S.SockAddrInet6 _ _ ha _) -> showHostAddress6 ha'.

Any suggestions? At this point I am thinking that the best solution is to
add a new function to network, since it is not trivial to do it anywhere
else in a portable way, and it seems like a fairly useful and common
operation?

- jeremy
-------------- next part --------------
An HTML attachment was scrubbed...
URL: http://www.haskell.org/pipermail/haskell-cafe/attachments/20100315/ef0f7955/attachment.html


More information about the Haskell-Cafe mailing list