    {- arch-tag: Network utilities main file
    Copyright (C) 2004-2008 John Goerzen <jgoerzen@complete.org>

    This program is free software; you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
    the Free Software Foundation; either version 2 of the License, or
    (at your option) any later version.

    This program is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU General Public License for more details.

    You should have received a copy of the GNU General Public License
    along with this program; if not, write to the Free Software
    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
    -}
    {- |
       Module     : Network.Utils
       Copyright  : Copyright (C) 2004-2008 John Goerzen
       License    : GNU GPL, version 2 or above

       Maintainer : John Goerzen <jgoerzen@complete.org>
       Stability  : provisional
       Portability: systems with networking

    This module provides various helpful utilities for dealing with networking

    Written by John Goerzen, jgoerzen\@complete.org

    -}

    module Network.Utils (niceSocketsDo, connectTCP, connectTCPAddr,
                            listenTCPAddr, showSockAddr)
        where

    import Network
    import Network.Socket
    import Network.BSD
    import System.IO
    #if !(defined(mingw32_HOST_OS) || defined(mingw32_TARGET_OS) || defined(__MINGW32__))
    import qualified System.Posix.Signals
    #endif

    {- | Sets up the system for networking.  Similar to the built-in
    withSocketsDo (and actually, calls it), but also sets the SIGPIPE
    handler so that signal is ignored.

    Example:

    > main = niceSocketsDo $ do { ... }
    -}

    -- FIXME integrate with WebCont.Util.UDP

    niceSocketsDo :: IO a -> IO a
    niceSocketsDo func = do
    #if !(defined(mingw32_HOST_OS) || defined(mingw32_TARGET_OS) || defined(__MINGW32__))
                    -- No signals on Windows anyway
                    System.Posix.Signals.installHandler
                          System.Posix.Signals.sigPIPE
                          System.Posix.Signals.Ignore
                          Nothing
    #endif
                    withSocketsDo func

    connectTCP :: HostName -> PortNumber -> IO Socket
    connectTCP host port = do
                           he <- getHostByName host
                           connectTCPAddr (SockAddrInet port (hostAddress he))

    connectTCPAddr :: SockAddr -> IO Socket
    connectTCPAddr addr = do
                          proto <- getProtocolNumber "tcp"
                          s <- socket AF_INET Stream proto
                          connect s addr
                          return s

    listenTCPAddr :: SockAddr -> Int -> IO Socket
    listenTCPAddr addr queuelen = do
                         proto <- getProtocolNumber "tcp"
                         s <- socket AF_INET Stream proto
                         bindSocket s addr
                         listen s queuelen
                         return s

    showSockAddr :: SockAddr -> IO String
    #if !(defined(mingw32_HOST_OS) || defined(mingw32_TARGET_OS) || defined(__MINGW32__))
    showSockAddr (SockAddrUnix x) = return $ "UNIX socket at " ++ x
    #endif
    showSockAddr (SockAddrInet port host) =
        do h <- inet_ntoa host
           return $ "IPv4 host " ++ h ++ ", port " ++ (show port)