Blame Network/Socket.hsc

Packit 090c59
{-# LANGUAGE CPP, ScopedTypeVariables #-}
Packit 090c59
{-# OPTIONS_GHC -fno-warn-orphans #-}
Packit 090c59
-----------------------------------------------------------------------------
Packit 090c59
-- |
Packit 090c59
-- Module      :  Network.Socket
Packit 090c59
-- Copyright   :  (c) The University of Glasgow 2001
Packit 090c59
-- License     :  BSD-style (see the file libraries/network/LICENSE)
Packit 090c59
--
Packit 090c59
-- Maintainer  :  libraries@haskell.org
Packit 090c59
-- Stability   :  provisional
Packit 090c59
-- Portability :  portable
Packit 090c59
--
Packit 090c59
-- The "Network.Socket" module is for when you want full control over
Packit 090c59
-- sockets.  Essentially the entire C socket API is exposed through
Packit 090c59
-- this module; in general the operations follow the behaviour of the C
Packit 090c59
-- functions of the same name (consult your favourite Unix networking book).
Packit 090c59
--
Packit 090c59
-- A higher level interface to networking operations is provided
Packit 090c59
-- through the module "Network".
Packit 090c59
--
Packit 090c59
-----------------------------------------------------------------------------
Packit 090c59
Packit 090c59
#include "HsNet.h"
Packit 090c59
Packit 090c59
-- In order to process this file, you need to have CALLCONV defined.
Packit 090c59
Packit 090c59
module Network.Socket
Packit 090c59
    (
Packit 090c59
    -- * Types
Packit 090c59
      Socket(..)
Packit 090c59
    , Family(..)
Packit 090c59
    , isSupportedFamily
Packit 090c59
    , SocketType(..)
Packit 090c59
    , isSupportedSocketType
Packit 090c59
    , SockAddr(..)
Packit 090c59
    , isSupportedSockAddr
Packit 090c59
    , SocketStatus(..)
Packit 090c59
    , HostAddress
Packit 090c59
    , hostAddressToTuple
Packit 090c59
    , tupleToHostAddress
Packit 090c59
#if defined(IPV6_SOCKET_SUPPORT)
Packit 090c59
    , HostAddress6
Packit 090c59
    , hostAddress6ToTuple
Packit 090c59
    , tupleToHostAddress6
Packit 090c59
    , FlowInfo
Packit 090c59
    , ScopeID
Packit 090c59
#endif
Packit 090c59
    , htonl
Packit 090c59
    , ntohl
Packit 090c59
    , ShutdownCmd(..)
Packit 090c59
    , ProtocolNumber
Packit 090c59
    , defaultProtocol
Packit 090c59
    , PortNumber(..)
Packit 090c59
    -- PortNumber is used non-abstractly in Network.BSD.  ToDo: remove
Packit 090c59
    -- this use and make the type abstract.
Packit 090c59
Packit 090c59
    -- * Address operations
Packit 090c59
Packit 090c59
    , HostName
Packit 090c59
    , ServiceName
Packit 090c59
Packit 090c59
#if defined(IPV6_SOCKET_SUPPORT)
Packit 090c59
    , AddrInfo(..)
Packit 090c59
Packit 090c59
    , AddrInfoFlag(..)
Packit 090c59
    , addrInfoFlagImplemented
Packit 090c59
Packit 090c59
    , defaultHints
Packit 090c59
Packit 090c59
    , getAddrInfo
Packit 090c59
Packit 090c59
    , NameInfoFlag(..)
Packit 090c59
Packit 090c59
    , getNameInfo
Packit 090c59
#endif
Packit 090c59
Packit 090c59
    -- * Socket operations
Packit 090c59
    , socket
Packit 090c59
#if defined(DOMAIN_SOCKET_SUPPORT)
Packit 090c59
    , socketPair
Packit 090c59
#endif
Packit 090c59
    , connect
Packit 090c59
    , bind
Packit 090c59
    , listen
Packit 090c59
    , accept
Packit 090c59
    , getPeerName
Packit 090c59
    , getSocketName
Packit 090c59
Packit 090c59
#if defined(HAVE_STRUCT_UCRED) || defined(HAVE_GETPEEREID)
Packit 090c59
    -- get the credentials of our domain socket peer.
Packit 090c59
    , getPeerCred
Packit 090c59
#if defined(HAVE_GETPEEREID)
Packit 090c59
    , getPeerEid
Packit 090c59
#endif
Packit 090c59
#endif
Packit 090c59
Packit 090c59
    , socketPort
Packit 090c59
Packit 090c59
    , socketToHandle
Packit 090c59
Packit 090c59
    -- ** Sending and receiving data
Packit 090c59
    -- *** Sending and receiving with String
Packit 090c59
    -- $sendrecv
Packit 090c59
    , send
Packit 090c59
    , sendTo
Packit 090c59
    , recv
Packit 090c59
    , recvFrom
Packit 090c59
    , recvLen
Packit 090c59
Packit 090c59
    -- *** Sending and receiving with a buffer
Packit 090c59
    , sendBuf
Packit 090c59
    , recvBuf
Packit 090c59
    , sendBufTo
Packit 090c59
    , recvBufFrom
Packit 090c59
Packit 090c59
    -- ** Misc
Packit 090c59
    , inet_addr
Packit 090c59
    , inet_ntoa
Packit 090c59
Packit 090c59
    , shutdown
Packit 090c59
    , close
Packit 090c59
Packit 090c59
    -- ** Predicates on sockets
Packit 090c59
    , isConnected
Packit 090c59
    , isBound
Packit 090c59
    , isListening
Packit 090c59
    , isReadable
Packit 090c59
    , isWritable
Packit 090c59
Packit 090c59
    -- * Socket options
Packit 090c59
    , SocketOption(..)
Packit 090c59
    , isSupportedSocketOption
Packit 090c59
    , getSocketOption
Packit 090c59
    , setSocketOption
Packit 090c59
Packit 090c59
    -- * File descriptor transmission
Packit 090c59
#ifdef DOMAIN_SOCKET_SUPPORT
Packit 090c59
    , sendFd
Packit 090c59
    , recvFd
Packit 090c59
Packit 090c59
#endif
Packit 090c59
Packit 090c59
    -- * Special constants
Packit 090c59
    , aNY_PORT
Packit 090c59
    , iNADDR_ANY
Packit 090c59
#if defined(IPV6_SOCKET_SUPPORT)
Packit 090c59
    , iN6ADDR_ANY
Packit 090c59
#endif
Packit 090c59
    , sOMAXCONN
Packit 090c59
    , sOL_SOCKET
Packit 090c59
#ifdef SCM_RIGHTS
Packit 090c59
    , sCM_RIGHTS
Packit 090c59
#endif
Packit 090c59
    , maxListenQueue
Packit 090c59
Packit 090c59
    -- * Initialisation
Packit 090c59
    , withSocketsDo
Packit 090c59
Packit 090c59
    -- * Very low level operations
Packit 090c59
    -- in case you ever want to get at the underlying file descriptor..
Packit 090c59
    , fdSocket
Packit 090c59
    , mkSocket
Packit 090c59
    , setNonBlockIfNeeded
Packit 090c59
Packit 090c59
    -- * Deprecated aliases
Packit 090c59
    -- $deprecated-aliases
Packit 090c59
    , bindSocket
Packit 090c59
    , sClose
Packit 090c59
    , sIsConnected
Packit 090c59
    , sIsBound
Packit 090c59
    , sIsListening
Packit 090c59
    , sIsReadable
Packit 090c59
    , sIsWritable
Packit 090c59
Packit 090c59
    -- * Internal
Packit 090c59
Packit 090c59
    -- | The following are exported ONLY for use in the BSD module and
Packit 090c59
    -- should not be used anywhere else.
Packit 090c59
Packit 090c59
    , packFamily
Packit 090c59
    , unpackFamily
Packit 090c59
    , packSocketType
Packit 090c59
    ) where
Packit 090c59
Packit 090c59
import Data.Bits
Packit 090c59
import Data.Functor
Packit 090c59
import Data.List (foldl')
Packit 090c59
import Data.Maybe (isJust)
Packit 090c59
import Data.Word (Word8, Word32)
Packit 090c59
import Foreign.Ptr (Ptr, castPtr, nullPtr)
Packit 090c59
import Foreign.Storable (Storable(..))
Packit 090c59
import Foreign.C.Error
Packit 090c59
import Foreign.C.String (CString, withCString, withCStringLen, peekCString, peekCStringLen)
Packit 090c59
import Foreign.C.Types (CUInt, CChar)
Packit 090c59
import Foreign.C.Types (CInt(..), CSize(..))
Packit 090c59
import Foreign.Marshal.Alloc ( alloca, allocaBytes )
Packit 090c59
import Foreign.Marshal.Array ( peekArray )
Packit 090c59
import Foreign.Marshal.Utils ( maybeWith, with )
Packit 090c59
Packit 090c59
import System.IO
Packit 090c59
import Control.Monad (liftM, when)
Packit 090c59
Packit 090c59
import Control.Concurrent.MVar
Packit 090c59
import Data.Typeable
Packit 090c59
import System.IO.Error
Packit 090c59
Packit 090c59
import GHC.Conc (threadWaitRead, threadWaitWrite)
Packit 090c59
##if MIN_VERSION_base(4,3,1)
Packit 090c59
import GHC.Conc (closeFdWith)
Packit 090c59
##endif
Packit 090c59
# if defined(mingw32_HOST_OS)
Packit 090c59
import qualified Control.Exception as E
Packit 090c59
import GHC.Conc (asyncDoProc)
Packit 090c59
import GHC.IO.FD (FD(..), readRawBufferPtr, writeRawBufferPtr)
Packit 090c59
import Foreign (FunPtr)
Packit 090c59
# endif
Packit 090c59
# if defined(darwin_HOST_OS)
Packit 090c59
import Data.List (delete)
Packit 090c59
# endif
Packit 090c59
import qualified GHC.IO.Device
Packit 090c59
import GHC.IO.Handle.FD
Packit 090c59
import GHC.IO.Exception
Packit 090c59
import GHC.IO
Packit 090c59
import qualified System.Posix.Internals
Packit 090c59
Packit 090c59
import Network.Socket.Internal
Packit 090c59
import Network.Socket.Types
Packit 090c59
Packit 090c59
import Prelude -- Silence AMP warnings
Packit 090c59
Packit 090c59
-- | Either a host name e.g., @\"haskell.org\"@ or a numeric host
Packit 090c59
-- address string consisting of a dotted decimal IPv4 address or an
Packit 090c59
-- IPv6 address e.g., @\"192.168.0.1\"@.
Packit 090c59
type HostName       = String
Packit 090c59
type ServiceName    = String
Packit 090c59
Packit 090c59
-- ----------------------------------------------------------------------------
Packit 090c59
-- On Windows, our sockets are not put in non-blocking mode (non-blocking
Packit 090c59
-- is not supported for regular file descriptors on Windows, and it would
Packit 090c59
-- be a pain to support it only for sockets).  So there are two cases:
Packit 090c59
--
Packit 090c59
--  - the threaded RTS uses safe calls for socket operations to get
Packit 090c59
--    non-blocking I/O, just like the rest of the I/O library
Packit 090c59
--
Packit 090c59
--  - with the non-threaded RTS, only some operations on sockets will be
Packit 090c59
--    non-blocking.  Reads and writes go through the normal async I/O
Packit 090c59
--    system.  accept() uses asyncDoProc so is non-blocking.  A handful
Packit 090c59
--    of others (recvFrom, sendFd, recvFd) will block all threads - if this
Packit 090c59
--    is a problem, -threaded is the workaround.
Packit 090c59
--
Packit 090c59
##if defined(mingw32_HOST_OS)
Packit 090c59
##define SAFE_ON_WIN safe
Packit 090c59
##else
Packit 090c59
##define SAFE_ON_WIN unsafe
Packit 090c59
##endif
Packit 090c59
Packit 090c59
-----------------------------------------------------------------------------
Packit 090c59
-- Socket types
Packit 090c59
Packit 090c59
#if defined(mingw32_HOST_OS)
Packit 090c59
socket2FD  (MkSocket fd _ _ _ _) =
Packit 090c59
  -- HACK, 1 means True
Packit 090c59
  FD{fdFD = fd,fdIsSocket_ = 1}
Packit 090c59
#endif
Packit 090c59
Packit 090c59
-- | Smart constructor for constructing a 'Socket'. It should only be
Packit 090c59
-- called once for every new file descriptor. The caller must make
Packit 090c59
-- sure that the socket is in non-blocking mode. See
Packit 090c59
-- 'setNonBlockIfNeeded'.
Packit 090c59
mkSocket :: CInt
Packit 090c59
         -> Family
Packit 090c59
         -> SocketType
Packit 090c59
         -> ProtocolNumber
Packit 090c59
         -> SocketStatus
Packit 090c59
         -> IO Socket
Packit 090c59
mkSocket fd fam sType pNum stat = do
Packit 090c59
   mStat <- newMVar stat
Packit 090c59
   withSocketsDo $ return ()
Packit 090c59
   return (MkSocket fd fam sType pNum mStat)
Packit 090c59
Packit 090c59
Packit 090c59
fdSocket :: Socket -> CInt
Packit 090c59
fdSocket (MkSocket fd _ _ _ _) = fd
Packit 090c59
Packit 090c59
-- | This is the default protocol for a given service.
Packit 090c59
defaultProtocol :: ProtocolNumber
Packit 090c59
defaultProtocol = 0
Packit 090c59
Packit 090c59
-----------------------------------------------------------------------------
Packit 090c59
-- SockAddr
Packit 090c59
Packit 090c59
instance Show SockAddr where
Packit 090c59
#if defined(DOMAIN_SOCKET_SUPPORT)
Packit 090c59
  showsPrec _ (SockAddrUnix str) = showString str
Packit 090c59
#endif
Packit 090c59
  showsPrec _ (SockAddrInet port ha)
Packit 090c59
   = showString (unsafePerformIO (inet_ntoa ha))
Packit 090c59
   . showString ":"
Packit 090c59
   . shows port
Packit 090c59
#if defined(IPV6_SOCKET_SUPPORT)
Packit 090c59
  showsPrec _ addr@(SockAddrInet6 port _ _ _)
Packit 090c59
   = showChar '['
Packit 090c59
   . showString (unsafePerformIO $
Packit 090c59
                 fst `liftM` getNameInfo [NI_NUMERICHOST] True False addr >>=
Packit 090c59
                 maybe (fail "showsPrec: impossible internal error") return)
Packit 090c59
   . showString "]:"
Packit 090c59
   . shows port
Packit 090c59
#endif
Packit 090c59
#if defined(CAN_SOCKET_SUPPORT)
Packit 090c59
  showsPrec _ (SockAddrCan ifidx) = shows ifidx
Packit 090c59
#endif
Packit 090c59
Packit 090c59
-----------------------------------------------------------------------------
Packit 090c59
-- Connection Functions
Packit 090c59
Packit 090c59
-- In the following connection and binding primitives.  The names of
Packit 090c59
-- the equivalent C functions have been preserved where possible. It
Packit 090c59
-- should be noted that some of these names used in the C library,
Packit 090c59
-- \tr{bind} in particular, have a different meaning to many Haskell
Packit 090c59
-- programmers and have thus been renamed by appending the prefix
Packit 090c59
-- Socket.
Packit 090c59
Packit 090c59
-- | Create a new socket using the given address family, socket type
Packit 090c59
-- and protocol number.  The address family is usually 'AF_INET',
Packit 090c59
-- 'AF_INET6', or 'AF_UNIX'.  The socket type is usually 'Stream' or
Packit 090c59
-- 'Datagram'.  The protocol number is usually 'defaultProtocol'.
Packit 090c59
-- If 'AF_INET6' is used and the socket type is 'Stream' or 'Datagram',
Packit 090c59
-- the 'IPv6Only' socket option is set to 0 so that both IPv4 and IPv6
Packit 090c59
-- can be handled with one socket.
Packit 090c59
--
Packit 090c59
-- >>> let hints = defaultHints { addrFlags = [AI_NUMERICHOST, AI_NUMERICSERV], addrSocketType = Stream }
Packit 090c59
-- >>> addr:_ <- getAddrInfo (Just hints) (Just "127.0.0.1") (Just "5000")
Packit 090c59
-- >>> sock@(MkSocket _ fam stype _ _) <- socket (addrFamily addr) (addrSocketType addr) (addrProtocol addr)
Packit 090c59
-- >>> fam
Packit 090c59
-- AF_INET
Packit 090c59
-- >>> stype
Packit 090c59
-- Stream
Packit 090c59
-- >>> bind sock (addrAddress addr)
Packit 090c59
-- >>> getSocketName sock
Packit 090c59
-- 127.0.0.1:5000
Packit 090c59
socket :: Family         -- Family Name (usually AF_INET)
Packit 090c59
       -> SocketType     -- Socket Type (usually Stream)
Packit 090c59
       -> ProtocolNumber -- Protocol Number (getProtocolByName to find value)
Packit 090c59
       -> IO Socket      -- Unconnected Socket
Packit 090c59
socket family stype protocol = do
Packit 090c59
    c_stype <- packSocketTypeOrThrow "socket" stype
Packit 090c59
    fd <- throwSocketErrorIfMinus1Retry "Network.Socket.socket" $
Packit 090c59
                c_socket (packFamily family) c_stype protocol
Packit 090c59
    setNonBlockIfNeeded fd
Packit 090c59
    socket_status <- newMVar NotConnected
Packit 090c59
    withSocketsDo $ return ()
Packit 090c59
    let sock = MkSocket fd family stype protocol socket_status
Packit 090c59
#if HAVE_DECL_IPV6_V6ONLY
Packit 090c59
    -- The default value of the IPv6Only option is platform specific,
Packit 090c59
    -- so we explicitly set it to 0 to provide a common default.
Packit 090c59
# if defined(mingw32_HOST_OS)
Packit 090c59
    -- The IPv6Only option is only supported on Windows Vista and later,
Packit 090c59
    -- so trying to change it might throw an error.
Packit 090c59
    when (family == AF_INET6 && (stype == Stream || stype == Datagram)) $
Packit 090c59
      E.catch (setSocketOption sock IPv6Only 0) $ (\(_ :: E.IOException) -> return ())
Packit 090c59
# else
Packit 090c59
    when (family == AF_INET6 && (stype == Stream || stype == Datagram)) $
Packit 090c59
      setSocketOption sock IPv6Only 0 `onException` close sock
Packit 090c59
# endif
Packit 090c59
#endif
Packit 090c59
    return sock
Packit 090c59
Packit 090c59
-- | Build a pair of connected socket objects using the given address
Packit 090c59
-- family, socket type, and protocol number.  Address family, socket
Packit 090c59
-- type, and protocol number are as for the 'socket' function above.
Packit 090c59
-- Availability: Unix.
Packit 090c59
#if defined(DOMAIN_SOCKET_SUPPORT)
Packit 090c59
socketPair :: Family              -- Family Name (usually AF_INET or AF_INET6)
Packit 090c59
           -> SocketType          -- Socket Type (usually Stream)
Packit 090c59
           -> ProtocolNumber      -- Protocol Number
Packit 090c59
           -> IO (Socket, Socket) -- unnamed and connected.
Packit 090c59
socketPair family stype protocol = do
Packit 090c59
    allocaBytes (2 * sizeOf (1 :: CInt)) $ \ fdArr -> do
Packit 090c59
    c_stype <- packSocketTypeOrThrow "socketPair" stype
Packit 090c59
    _rc <- throwSocketErrorIfMinus1Retry "Network.Socket.socketpair" $
Packit 090c59
                c_socketpair (packFamily family) c_stype protocol fdArr
Packit 090c59
    [fd1,fd2] <- peekArray 2 fdArr
Packit 090c59
    s1 <- mkNonBlockingSocket fd1
Packit 090c59
    s2 <- mkNonBlockingSocket fd2
Packit 090c59
    return (s1,s2)
Packit 090c59
  where
Packit 090c59
    mkNonBlockingSocket fd = do
Packit 090c59
       setNonBlockIfNeeded fd
Packit 090c59
       stat <- newMVar Connected
Packit 090c59
       withSocketsDo $ return ()
Packit 090c59
       return (MkSocket fd family stype protocol stat)
Packit 090c59
Packit 090c59
foreign import ccall unsafe "socketpair"
Packit 090c59
  c_socketpair :: CInt -> CInt -> CInt -> Ptr CInt -> IO CInt
Packit 090c59
#endif
Packit 090c59
Packit 090c59
-- | Set the socket to nonblocking, if applicable to this platform.
Packit 090c59
--
Packit 090c59
-- Depending on the platform this is required when using sockets from file
Packit 090c59
-- descriptors that are passed in through 'recvFd' or other means.
Packit 090c59
setNonBlockIfNeeded :: CInt -> IO ()
Packit 090c59
setNonBlockIfNeeded fd =
Packit 090c59
    System.Posix.Internals.setNonBlockingFD fd True
Packit 090c59
Packit 090c59
-----------------------------------------------------------------------------
Packit 090c59
-- Binding a socket
Packit 090c59
Packit 090c59
-- | Bind the socket to an address. The socket must not already be
Packit 090c59
-- bound.  The 'Family' passed to @bind@ must be the
Packit 090c59
-- same as that passed to 'socket'.  If the special port number
Packit 090c59
-- 'aNY_PORT' is passed then the system assigns the next available
Packit 090c59
-- use port.
Packit 090c59
bind :: Socket    -- Unconnected Socket
Packit 090c59
           -> SockAddr  -- Address to Bind to
Packit 090c59
           -> IO ()
Packit 090c59
bind (MkSocket s _family _stype _protocol socketStatus) addr = do
Packit 090c59
 modifyMVar_ socketStatus $ \ status -> do
Packit 090c59
 if status /= NotConnected
Packit 090c59
  then
Packit 090c59
   ioError $ userError $
Packit 090c59
     "Network.Socket.bind: can't bind to socket with status " ++ show status
Packit 090c59
  else do
Packit 090c59
   withSockAddr addr $ \p_addr sz -> do
Packit 090c59
   _status <- throwSocketErrorIfMinus1Retry "Network.Socket.bind" $
Packit 090c59
     c_bind s p_addr (fromIntegral sz)
Packit 090c59
   return Bound
Packit 090c59
Packit 090c59
-----------------------------------------------------------------------------
Packit 090c59
-- Connecting a socket
Packit 090c59
Packit 090c59
-- | Connect to a remote socket at address.
Packit 090c59
connect :: Socket    -- Unconnected Socket
Packit 090c59
        -> SockAddr  -- Socket address stuff
Packit 090c59
        -> IO ()
Packit 090c59
connect sock@(MkSocket s _family _stype _protocol socketStatus) addr = withSocketsDo $ do
Packit 090c59
 modifyMVar_ socketStatus $ \currentStatus -> do
Packit 090c59
 if currentStatus /= NotConnected && currentStatus /= Bound
Packit 090c59
  then
Packit 090c59
    ioError $ userError $
Packit 090c59
      errLoc ++ ": can't connect to socket with status " ++ show currentStatus
Packit 090c59
  else do
Packit 090c59
    withSockAddr addr $ \p_addr sz -> do
Packit 090c59
Packit 090c59
    let connectLoop = do
Packit 090c59
           r <- c_connect s p_addr (fromIntegral sz)
Packit 090c59
           if r == -1
Packit 090c59
               then do
Packit 090c59
#if !(defined(HAVE_WINSOCK2_H))
Packit 090c59
                   err <- getErrno
Packit 090c59
                   case () of
Packit 090c59
                     _ | err == eINTR       -> connectLoop
Packit 090c59
                     _ | err == eINPROGRESS -> connectBlocked
Packit 090c59
--                   _ | err == eAGAIN      -> connectBlocked
Packit 090c59
                     _otherwise             -> throwSocketError errLoc
Packit 090c59
#else
Packit 090c59
                   throwSocketError errLoc
Packit 090c59
#endif
Packit 090c59
               else return ()
Packit 090c59
Packit 090c59
        connectBlocked = do
Packit 090c59
           threadWaitWrite (fromIntegral s)
Packit 090c59
           err <- getSocketOption sock SoError
Packit 090c59
           if (err == 0)
Packit 090c59
                then return ()
Packit 090c59
                else throwSocketErrorCode errLoc (fromIntegral err)
Packit 090c59
Packit 090c59
    connectLoop
Packit 090c59
    return Connected
Packit 090c59
 where
Packit 090c59
   errLoc = "Network.Socket.connect: " ++ show sock
Packit 090c59
Packit 090c59
-----------------------------------------------------------------------------
Packit 090c59
-- Listen
Packit 090c59
Packit 090c59
-- | Listen for connections made to the socket.  The second argument
Packit 090c59
-- specifies the maximum number of queued connections and should be at
Packit 090c59
-- least 1; the maximum value is system-dependent (usually 5).
Packit 090c59
listen :: Socket  -- Connected & Bound Socket
Packit 090c59
       -> Int     -- Queue Length
Packit 090c59
       -> IO ()
Packit 090c59
listen (MkSocket s _family _stype _protocol socketStatus) backlog = do
Packit 090c59
 modifyMVar_ socketStatus $ \ status -> do
Packit 090c59
 if status /= Bound
Packit 090c59
   then
Packit 090c59
     ioError $ userError $
Packit 090c59
       "Network.Socket.listen: can't listen on socket with status " ++ show status
Packit 090c59
   else do
Packit 090c59
     throwSocketErrorIfMinus1Retry_ "Network.Socket.listen" $
Packit 090c59
       c_listen s (fromIntegral backlog)
Packit 090c59
     return Listening
Packit 090c59
Packit 090c59
-----------------------------------------------------------------------------
Packit 090c59
-- Accept
Packit 090c59
--
Packit 090c59
-- A call to `accept' only returns when data is available on the given
Packit 090c59
-- socket, unless the socket has been set to non-blocking.  It will
Packit 090c59
-- return a new socket which should be used to read the incoming data and
Packit 090c59
-- should then be closed. Using the socket returned by `accept' allows
Packit 090c59
-- incoming requests to be queued on the original socket.
Packit 090c59
Packit 090c59
-- | Accept a connection.  The socket must be bound to an address and
Packit 090c59
-- listening for connections.  The return value is a pair @(conn,
Packit 090c59
-- address)@ where @conn@ is a new socket object usable to send and
Packit 090c59
-- receive data on the connection, and @address@ is the address bound
Packit 090c59
-- to the socket on the other end of the connection.
Packit 090c59
accept :: Socket                        -- Queue Socket
Packit 090c59
       -> IO (Socket,                   -- Readable Socket
Packit 090c59
              SockAddr)                 -- Peer details
Packit 090c59
Packit 090c59
accept sock@(MkSocket s family stype protocol status) = do
Packit 090c59
 currentStatus <- readMVar status
Packit 090c59
 okay <- isAcceptable sock
Packit 090c59
 if not okay
Packit 090c59
   then
Packit 090c59
     ioError $ userError $
Packit 090c59
       "Network.Socket.accept: can't accept socket (" ++
Packit 090c59
         show (family, stype, protocol) ++ ") with status " ++
Packit 090c59
         show currentStatus
Packit 090c59
   else do
Packit 090c59
     let sz = sizeOfSockAddrByFamily family
Packit 090c59
     allocaBytes sz $ \ sockaddr -> do
Packit 090c59
#if defined(mingw32_HOST_OS)
Packit 090c59
     new_sock <-
Packit 090c59
        if threaded
Packit 090c59
           then with (fromIntegral sz) $ \ ptr_len ->
Packit 090c59
                  throwSocketErrorIfMinus1Retry "Network.Socket.accept" $
Packit 090c59
                    c_accept_safe s sockaddr ptr_len
Packit 090c59
           else do
Packit 090c59
                paramData <- c_newAcceptParams s (fromIntegral sz) sockaddr
Packit 090c59
                rc        <- asyncDoProc c_acceptDoProc paramData
Packit 090c59
                new_sock  <- c_acceptNewSock    paramData
Packit 090c59
                c_free paramData
Packit 090c59
                when (rc /= 0) $
Packit 090c59
                     throwSocketErrorCode "Network.Socket.accept" (fromIntegral rc)
Packit 090c59
                return new_sock
Packit 090c59
#else
Packit 090c59
     with (fromIntegral sz) $ \ ptr_len -> do
Packit 090c59
# ifdef HAVE_ACCEPT4
Packit 090c59
     new_sock <- throwSocketErrorIfMinus1RetryMayBlock "Network.Socket.accept"
Packit 090c59
                        (threadWaitRead (fromIntegral s))
Packit 090c59
                        (c_accept4 s sockaddr ptr_len (#const SOCK_NONBLOCK))
Packit 090c59
# else
Packit 090c59
     new_sock <- throwSocketErrorWaitRead sock "Network.Socket.accept"
Packit 090c59
                        (c_accept s sockaddr ptr_len)
Packit 090c59
     setNonBlockIfNeeded new_sock
Packit 090c59
# endif /* HAVE_ACCEPT4 */
Packit 090c59
#endif
Packit 090c59
     addr <- peekSockAddr sockaddr
Packit 090c59
     new_status <- newMVar Connected
Packit 090c59
     return ((MkSocket new_sock family stype protocol new_status), addr)
Packit 090c59
Packit 090c59
#if defined(mingw32_HOST_OS)
Packit 090c59
foreign import ccall unsafe "HsNet.h acceptNewSock"
Packit 090c59
  c_acceptNewSock :: Ptr () -> IO CInt
Packit 090c59
foreign import ccall unsafe "HsNet.h newAcceptParams"
Packit 090c59
  c_newAcceptParams :: CInt -> CInt -> Ptr a -> IO (Ptr ())
Packit 090c59
foreign import ccall unsafe "HsNet.h &acceptDoProc"
Packit 090c59
  c_acceptDoProc :: FunPtr (Ptr () -> IO Int)
Packit 090c59
foreign import ccall unsafe "free"
Packit 090c59
  c_free:: Ptr a -> IO ()
Packit 090c59
#endif
Packit 090c59
Packit 090c59
-----------------------------------------------------------------------------
Packit 090c59
-- ** Sending and receiving data
Packit 090c59
Packit 090c59
-- $sendrecv
Packit 090c59
--
Packit 090c59
-- Do not use the @send@ and @recv@ functions defined in this section
Packit 090c59
-- in new code, as they incorrectly represent binary data as a Unicode
Packit 090c59
-- string.  As a result, these functions are inefficient and may lead
Packit 090c59
-- to bugs in the program.  Instead use the @send@ and @recv@
Packit 090c59
-- functions defined in the "Network.Socket.ByteString" module.
Packit 090c59
Packit 090c59
-----------------------------------------------------------------------------
Packit 090c59
-- sendTo & recvFrom
Packit 090c59
Packit 090c59
-- | Send data to the socket.  The recipient can be specified
Packit 090c59
-- explicitly, so the socket need not be in a connected state.
Packit 090c59
-- Returns the number of bytes sent.  Applications are responsible for
Packit 090c59
-- ensuring that all data has been sent.
Packit 090c59
--
Packit 090c59
-- NOTE: blocking on Windows unless you compile with -threaded (see
Packit 090c59
-- GHC ticket #1129)
Packit 090c59
{-# WARNING sendTo "Use sendTo defined in \"Network.Socket.ByteString\"" #-}
Packit 090c59
sendTo :: Socket        -- (possibly) bound/connected Socket
Packit 090c59
       -> String        -- Data to send
Packit 090c59
       -> SockAddr
Packit 090c59
       -> IO Int        -- Number of Bytes sent
Packit 090c59
sendTo sock xs addr = do
Packit 090c59
 withCStringLen xs $ \(str, len) -> do
Packit 090c59
   sendBufTo sock str len addr
Packit 090c59
Packit 090c59
-- | Send data to the socket.  The recipient can be specified
Packit 090c59
-- explicitly, so the socket need not be in a connected state.
Packit 090c59
-- Returns the number of bytes sent.  Applications are responsible for
Packit 090c59
-- ensuring that all data has been sent.
Packit 090c59
sendBufTo :: Socket            -- (possibly) bound/connected Socket
Packit 090c59
          -> Ptr a -> Int  -- Data to send
Packit 090c59
          -> SockAddr
Packit 090c59
          -> IO Int            -- Number of Bytes sent
Packit 090c59
sendBufTo sock@(MkSocket s _family _stype _protocol _status) ptr nbytes addr = do
Packit 090c59
 withSockAddr addr $ \p_addr sz -> do
Packit 090c59
   liftM fromIntegral $
Packit 090c59
     throwSocketErrorWaitWrite sock "Network.Socket.sendTo" $
Packit 090c59
        c_sendto s ptr (fromIntegral $ nbytes) 0{-flags-}
Packit 090c59
                        p_addr (fromIntegral sz)
Packit 090c59
Packit 090c59
-- | Receive data from the socket. The socket need not be in a
Packit 090c59
-- connected state. Returns @(bytes, nbytes, address)@ where @bytes@
Packit 090c59
-- is a @String@ of length @nbytes@ representing the data received and
Packit 090c59
-- @address@ is a 'SockAddr' representing the address of the sending
Packit 090c59
-- socket.
Packit 090c59
--
Packit 090c59
-- NOTE: blocking on Windows unless you compile with -threaded (see
Packit 090c59
-- GHC ticket #1129)
Packit 090c59
{-# WARNING recvFrom "Use recvFrom defined in \"Network.Socket.ByteString\"" #-}
Packit 090c59
recvFrom :: Socket -> Int -> IO (String, Int, SockAddr)
Packit 090c59
recvFrom sock nbytes =
Packit 090c59
  allocaBytes nbytes $ \ptr -> do
Packit 090c59
    (len, sockaddr) <- recvBufFrom sock ptr nbytes
Packit 090c59
    str <- peekCStringLen (ptr, len)
Packit 090c59
    return (str, len, sockaddr)
Packit 090c59
Packit 090c59
-- | Receive data from the socket, writing it into buffer instead of
Packit 090c59
-- creating a new string.  The socket need not be in a connected
Packit 090c59
-- state. Returns @(nbytes, address)@ where @nbytes@ is the number of
Packit 090c59
-- bytes received and @address@ is a 'SockAddr' representing the
Packit 090c59
-- address of the sending socket.
Packit 090c59
--
Packit 090c59
-- NOTE: blocking on Windows unless you compile with -threaded (see
Packit 090c59
-- GHC ticket #1129)
Packit 090c59
recvBufFrom :: Socket -> Ptr a -> Int -> IO (Int, SockAddr)
Packit 090c59
recvBufFrom sock@(MkSocket s family _stype _protocol _status) ptr nbytes
Packit 090c59
 | nbytes <= 0 = ioError (mkInvalidRecvArgError "Network.Socket.recvFrom")
Packit 090c59
 | otherwise   =
Packit 090c59
    withNewSockAddr family $ \ptr_addr sz -> do
Packit 090c59
      alloca $ \ptr_len -> do
Packit 090c59
        poke ptr_len (fromIntegral sz)
Packit 090c59
        len <- throwSocketErrorWaitRead sock "Network.Socket.recvFrom" $
Packit 090c59
                   c_recvfrom s ptr (fromIntegral nbytes) 0{-flags-}
Packit 090c59
                                ptr_addr ptr_len
Packit 090c59
        let len' = fromIntegral len
Packit 090c59
        if len' == 0
Packit 090c59
         then ioError (mkEOFError "Network.Socket.recvFrom")
Packit 090c59
         else do
Packit 090c59
           flg <- isConnected sock
Packit 090c59
             -- For at least one implementation (WinSock 2), recvfrom() ignores
Packit 090c59
             -- filling in the sockaddr for connected TCP sockets. Cope with
Packit 090c59
             -- this by using getPeerName instead.
Packit 090c59
           sockaddr <-
Packit 090c59
                if flg then
Packit 090c59
                   getPeerName sock
Packit 090c59
                else
Packit 090c59
                   peekSockAddr ptr_addr
Packit 090c59
           return (len', sockaddr)
Packit 090c59
Packit 090c59
-----------------------------------------------------------------------------
Packit 090c59
-- send & recv
Packit 090c59
Packit 090c59
-- | Send data to the socket. The socket must be connected to a remote
Packit 090c59
-- socket. Returns the number of bytes sent.  Applications are
Packit 090c59
-- responsible for ensuring that all data has been sent.
Packit 090c59
--
Packit 090c59
-- Sending data to closed socket may lead to undefined behaviour.
Packit 090c59
{-# WARNING send "Use send defined in \"Network.Socket.ByteString\"" #-}
Packit 090c59
send :: Socket  -- Bound/Connected Socket
Packit 090c59
     -> String  -- Data to send
Packit 090c59
     -> IO Int  -- Number of Bytes sent
Packit 090c59
send sock xs = withCStringLen xs $ \(str, len) ->
Packit 090c59
    sendBuf sock (castPtr str) len
Packit 090c59
Packit 090c59
-- | Send data to the socket. The socket must be connected to a remote
Packit 090c59
-- socket. Returns the number of bytes sent.  Applications are
Packit 090c59
-- responsible for ensuring that all data has been sent.
Packit 090c59
--
Packit 090c59
-- Sending data to closed socket may lead to undefined behaviour.
Packit 090c59
sendBuf :: Socket     -- Bound/Connected Socket
Packit 090c59
        -> Ptr Word8  -- Pointer to the data to send
Packit 090c59
        -> Int        -- Length of the buffer
Packit 090c59
        -> IO Int     -- Number of Bytes sent
Packit 090c59
sendBuf sock@(MkSocket s _family _stype _protocol _status) str len = do
Packit 090c59
   liftM fromIntegral $
Packit 090c59
#if defined(mingw32_HOST_OS)
Packit 090c59
-- writeRawBufferPtr is supposed to handle checking for errors, but it's broken
Packit 090c59
-- on x86_64 because of GHC bug #12010 so we duplicate the check here. The call
Packit 090c59
-- to throwSocketErrorIfMinus1Retry can be removed when no GHC version with the
Packit 090c59
-- bug is supported.
Packit 090c59
    throwSocketErrorIfMinus1Retry "Network.Socket.sendBuf" $ writeRawBufferPtr
Packit 090c59
      "Network.Socket.sendBuf"
Packit 090c59
      (socket2FD sock)
Packit 090c59
      (castPtr str)
Packit 090c59
      0
Packit 090c59
      (fromIntegral len)
Packit 090c59
#else
Packit 090c59
     throwSocketErrorWaitWrite sock "Network.Socket.sendBuf" $
Packit 090c59
        c_send s str (fromIntegral len) 0{-flags-}
Packit 090c59
#endif
Packit 090c59
Packit 090c59
Packit 090c59
-- | Receive data from the socket.  The socket must be in a connected
Packit 090c59
-- state. This function may return fewer bytes than specified.  If the
Packit 090c59
-- message is longer than the specified length, it may be discarded
Packit 090c59
-- depending on the type of socket.  This function may block until a
Packit 090c59
-- message arrives.
Packit 090c59
--
Packit 090c59
-- Considering hardware and network realities, the maximum number of
Packit 090c59
-- bytes to receive should be a small power of 2, e.g., 4096.
Packit 090c59
--
Packit 090c59
-- For TCP sockets, a zero length return value means the peer has
Packit 090c59
-- closed its half side of the connection.
Packit 090c59
--
Packit 090c59
-- Receiving data from closed socket may lead to undefined behaviour.
Packit 090c59
{-# WARNING recv "Use recv defined in \"Network.Socket.ByteString\"" #-}
Packit 090c59
recv :: Socket -> Int -> IO String
Packit 090c59
recv sock l = fst <$> recvLen sock l
Packit 090c59
Packit 090c59
{-# WARNING recvLen "Use recvLen defined in \"Network.Socket.ByteString\"" #-}
Packit 090c59
recvLen :: Socket -> Int -> IO (String, Int)
Packit 090c59
recvLen sock nbytes =
Packit 090c59
     allocaBytes nbytes $ \ptr -> do
Packit 090c59
        len <- recvBuf sock ptr nbytes
Packit 090c59
        s <- peekCStringLen (castPtr ptr,len)
Packit 090c59
        return (s, len)
Packit 090c59
Packit 090c59
-- | Receive data from the socket.  The socket must be in a connected
Packit 090c59
-- state. This function may return fewer bytes than specified.  If the
Packit 090c59
-- message is longer than the specified length, it may be discarded
Packit 090c59
-- depending on the type of socket.  This function may block until a
Packit 090c59
-- message arrives.
Packit 090c59
--
Packit 090c59
-- Considering hardware and network realities, the maximum number of
Packit 090c59
-- bytes to receive should be a small power of 2, e.g., 4096.
Packit 090c59
--
Packit 090c59
-- For TCP sockets, a zero length return value means the peer has
Packit 090c59
-- closed its half side of the connection.
Packit 090c59
--
Packit 090c59
-- Receiving data from closed socket may lead to undefined behaviour.
Packit 090c59
recvBuf :: Socket -> Ptr Word8 -> Int -> IO Int
Packit 090c59
recvBuf sock@(MkSocket s _family _stype _protocol _status) ptr nbytes
Packit 090c59
 | nbytes <= 0 = ioError (mkInvalidRecvArgError "Network.Socket.recvBuf")
Packit 090c59
 | otherwise   = do
Packit 090c59
        len <-
Packit 090c59
#if defined(mingw32_HOST_OS)
Packit 090c59
-- see comment in sendBuf above.
Packit 090c59
            throwSocketErrorIfMinus1Retry "Network.Socket.recvBuf" $
Packit 090c59
                readRawBufferPtr "Network.Socket.recvBuf"
Packit 090c59
                (socket2FD sock) ptr 0 (fromIntegral nbytes)
Packit 090c59
#else
Packit 090c59
               throwSocketErrorWaitRead sock "Network.Socket.recvBuf" $
Packit 090c59
                   c_recv s (castPtr ptr) (fromIntegral nbytes) 0{-flags-}
Packit 090c59
#endif
Packit 090c59
        let len' = fromIntegral len
Packit 090c59
        if len' == 0
Packit 090c59
         then ioError (mkEOFError "Network.Socket.recvBuf")
Packit 090c59
         else return len'
Packit 090c59
Packit 090c59
Packit 090c59
-- ---------------------------------------------------------------------------
Packit 090c59
-- socketPort
Packit 090c59
--
Packit 090c59
-- The port number the given socket is currently connected to can be
Packit 090c59
-- determined by calling $port$, is generally only useful when bind
Packit 090c59
-- was given $aNY\_PORT$.
Packit 090c59
Packit 090c59
socketPort :: Socket            -- Connected & Bound Socket
Packit 090c59
           -> IO PortNumber     -- Port Number of Socket
Packit 090c59
socketPort sock@(MkSocket _ AF_INET _ _ _) = do
Packit 090c59
    (SockAddrInet port _) <- getSocketName sock
Packit 090c59
    return port
Packit 090c59
#if defined(IPV6_SOCKET_SUPPORT)
Packit 090c59
socketPort sock@(MkSocket _ AF_INET6 _ _ _) = do
Packit 090c59
    (SockAddrInet6 port _ _ _) <- getSocketName sock
Packit 090c59
    return port
Packit 090c59
#endif
Packit 090c59
socketPort (MkSocket _ family _ _ _) =
Packit 090c59
    ioError $ userError $
Packit 090c59
      "Network.Socket.socketPort: address family '" ++ show family ++
Packit 090c59
      "' not supported."
Packit 090c59
Packit 090c59
Packit 090c59
-- ---------------------------------------------------------------------------
Packit 090c59
-- getPeerName
Packit 090c59
Packit 090c59
-- Calling $getPeerName$ returns the address details of the machine,
Packit 090c59
-- other than the local one, which is connected to the socket. This is
Packit 090c59
-- used in programs such as FTP to determine where to send the
Packit 090c59
-- returning data.  The corresponding call to get the details of the
Packit 090c59
-- local machine is $getSocketName$.
Packit 090c59
Packit 090c59
getPeerName   :: Socket -> IO SockAddr
Packit 090c59
getPeerName (MkSocket s family _ _ _) = do
Packit 090c59
 withNewSockAddr family $ \ptr sz -> do
Packit 090c59
   with (fromIntegral sz) $ \int_star -> do
Packit 090c59
   throwSocketErrorIfMinus1Retry_ "Network.Socket.getPeerName" $
Packit 090c59
     c_getpeername s ptr int_star
Packit 090c59
   _sz <- peek int_star
Packit 090c59
   peekSockAddr ptr
Packit 090c59
Packit 090c59
getSocketName :: Socket -> IO SockAddr
Packit 090c59
getSocketName (MkSocket s family _ _ _) = do
Packit 090c59
 withNewSockAddr family $ \ptr sz -> do
Packit 090c59
   with (fromIntegral sz) $ \int_star -> do
Packit 090c59
   throwSocketErrorIfMinus1Retry_ "Network.Socket.getSocketName" $
Packit 090c59
     c_getsockname s ptr int_star
Packit 090c59
   peekSockAddr ptr
Packit 090c59
Packit 090c59
-----------------------------------------------------------------------------
Packit 090c59
-- Socket Properties
Packit 090c59
Packit 090c59
-- | Socket options for use with 'setSocketOption' and 'getSocketOption'.
Packit 090c59
--
Packit 090c59
-- The existence of a constructor does not imply that the relevant option
Packit 090c59
-- is supported on your system: see 'isSupportedSocketOption'
Packit 090c59
data SocketOption
Packit 090c59
    = Debug         -- ^ SO_DEBUG
Packit 090c59
    | ReuseAddr     -- ^ SO_REUSEADDR
Packit 090c59
    | Type          -- ^ SO_TYPE
Packit 090c59
    | SoError       -- ^ SO_ERROR
Packit 090c59
    | DontRoute     -- ^ SO_DONTROUTE
Packit 090c59
    | Broadcast     -- ^ SO_BROADCAST
Packit 090c59
    | SendBuffer    -- ^ SO_SNDBUF
Packit 090c59
    | RecvBuffer    -- ^ SO_RCVBUF
Packit 090c59
    | KeepAlive     -- ^ SO_KEEPALIVE
Packit 090c59
    | OOBInline     -- ^ SO_OOBINLINE
Packit 090c59
    | TimeToLive    -- ^ IP_TTL
Packit 090c59
    | MaxSegment    -- ^ TCP_MAXSEG
Packit 090c59
    | NoDelay       -- ^ TCP_NODELAY
Packit 090c59
    | Cork          -- ^ TCP_CORK
Packit 090c59
    | Linger        -- ^ SO_LINGER
Packit 090c59
    | ReusePort     -- ^ SO_REUSEPORT
Packit 090c59
    | RecvLowWater  -- ^ SO_RCVLOWAT
Packit 090c59
    | SendLowWater  -- ^ SO_SNDLOWAT
Packit 090c59
    | RecvTimeOut   -- ^ SO_RCVTIMEO
Packit 090c59
    | SendTimeOut   -- ^ SO_SNDTIMEO
Packit 090c59
    | UseLoopBack   -- ^ SO_USELOOPBACK
Packit 090c59
    | UserTimeout   -- ^ TCP_USER_TIMEOUT
Packit 090c59
    | IPv6Only      -- ^ IPV6_V6ONLY
Packit 090c59
    | CustomSockOpt (CInt, CInt)
Packit 090c59
    deriving (Show, Typeable)
Packit 090c59
Packit 090c59
-- | Does the 'SocketOption' exist on this system?
Packit 090c59
isSupportedSocketOption :: SocketOption -> Bool
Packit 090c59
isSupportedSocketOption = isJust . packSocketOption
Packit 090c59
Packit 090c59
-- | For a socket option, return Just (level, value) where level is the
Packit 090c59
-- corresponding C option level constant (e.g. SOL_SOCKET) and value is
Packit 090c59
-- the option constant itself (e.g. SO_DEBUG)
Packit 090c59
-- If either constant does not exist, return Nothing.
Packit 090c59
packSocketOption :: SocketOption -> Maybe (CInt, CInt)
Packit 090c59
packSocketOption so =
Packit 090c59
  -- The Just here is a hack to disable GHC's overlapping pattern detection:
Packit 090c59
  -- the problem is if all constants are present, the fallback pattern is
Packit 090c59
  -- redundant, but if they aren't then it isn't. Hence we introduce an
Packit 090c59
  -- extra pattern (Nothing) that can't possibly happen, so that the
Packit 090c59
  -- fallback is always (in principle) necessary.
Packit 090c59
  -- I feel a little bad for including this, but such are the sacrifices we
Packit 090c59
  -- make while working with CPP - excluding the fallback pattern correctly
Packit 090c59
  -- would be a serious nuisance.
Packit 090c59
  -- (NB: comments elsewhere in this file refer to this one)
Packit 090c59
  case Just so of
Packit 090c59
#ifdef SOL_SOCKET
Packit 090c59
#ifdef SO_DEBUG
Packit 090c59
    Just Debug         -> Just ((#const SOL_SOCKET), (#const SO_DEBUG))
Packit 090c59
#endif
Packit 090c59
#ifdef SO_REUSEADDR
Packit 090c59
    Just ReuseAddr     -> Just ((#const SOL_SOCKET), (#const SO_REUSEADDR))
Packit 090c59
#endif
Packit 090c59
#ifdef SO_TYPE
Packit 090c59
    Just Type          -> Just ((#const SOL_SOCKET), (#const SO_TYPE))
Packit 090c59
#endif
Packit 090c59
#ifdef SO_ERROR
Packit 090c59
    Just SoError       -> Just ((#const SOL_SOCKET), (#const SO_ERROR))
Packit 090c59
#endif
Packit 090c59
#ifdef SO_DONTROUTE
Packit 090c59
    Just DontRoute     -> Just ((#const SOL_SOCKET), (#const SO_DONTROUTE))
Packit 090c59
#endif
Packit 090c59
#ifdef SO_BROADCAST
Packit 090c59
    Just Broadcast     -> Just ((#const SOL_SOCKET), (#const SO_BROADCAST))
Packit 090c59
#endif
Packit 090c59
#ifdef SO_SNDBUF
Packit 090c59
    Just SendBuffer    -> Just ((#const SOL_SOCKET), (#const SO_SNDBUF))
Packit 090c59
#endif
Packit 090c59
#ifdef SO_RCVBUF
Packit 090c59
    Just RecvBuffer    -> Just ((#const SOL_SOCKET), (#const SO_RCVBUF))
Packit 090c59
#endif
Packit 090c59
#ifdef SO_KEEPALIVE
Packit 090c59
    Just KeepAlive     -> Just ((#const SOL_SOCKET), (#const SO_KEEPALIVE))
Packit 090c59
#endif
Packit 090c59
#ifdef SO_OOBINLINE
Packit 090c59
    Just OOBInline     -> Just ((#const SOL_SOCKET), (#const SO_OOBINLINE))
Packit 090c59
#endif
Packit 090c59
#ifdef SO_LINGER
Packit 090c59
    Just Linger        -> Just ((#const SOL_SOCKET), (#const SO_LINGER))
Packit 090c59
#endif
Packit 090c59
#ifdef SO_REUSEPORT
Packit 090c59
    Just ReusePort     -> Just ((#const SOL_SOCKET), (#const SO_REUSEPORT))
Packit 090c59
#endif
Packit 090c59
#ifdef SO_RCVLOWAT
Packit 090c59
    Just RecvLowWater  -> Just ((#const SOL_SOCKET), (#const SO_RCVLOWAT))
Packit 090c59
#endif
Packit 090c59
#ifdef SO_SNDLOWAT
Packit 090c59
    Just SendLowWater  -> Just ((#const SOL_SOCKET), (#const SO_SNDLOWAT))
Packit 090c59
#endif
Packit 090c59
#ifdef SO_RCVTIMEO
Packit 090c59
    Just RecvTimeOut   -> Just ((#const SOL_SOCKET), (#const SO_RCVTIMEO))
Packit 090c59
#endif
Packit 090c59
#ifdef SO_SNDTIMEO
Packit 090c59
    Just SendTimeOut   -> Just ((#const SOL_SOCKET), (#const SO_SNDTIMEO))
Packit 090c59
#endif
Packit 090c59
#ifdef SO_USELOOPBACK
Packit 090c59
    Just UseLoopBack   -> Just ((#const SOL_SOCKET), (#const SO_USELOOPBACK))
Packit 090c59
#endif
Packit 090c59
#endif // SOL_SOCKET
Packit 090c59
#if HAVE_DECL_IPPROTO_IP
Packit 090c59
#ifdef IP_TTL
Packit 090c59
    Just TimeToLive    -> Just ((#const IPPROTO_IP), (#const IP_TTL))
Packit 090c59
#endif
Packit 090c59
#endif // HAVE_DECL_IPPROTO_IP
Packit 090c59
#if HAVE_DECL_IPPROTO_TCP
Packit 090c59
#ifdef TCP_MAXSEG
Packit 090c59
    Just MaxSegment    -> Just ((#const IPPROTO_TCP), (#const TCP_MAXSEG))
Packit 090c59
#endif
Packit 090c59
#ifdef TCP_NODELAY
Packit 090c59
    Just NoDelay       -> Just ((#const IPPROTO_TCP), (#const TCP_NODELAY))
Packit 090c59
#endif
Packit 090c59
#ifdef TCP_USER_TIMEOUT
Packit 090c59
    Just UserTimeout   -> Just ((#const IPPROTO_TCP), (#const TCP_USER_TIMEOUT))
Packit 090c59
#endif
Packit 090c59
#ifdef TCP_CORK
Packit 090c59
    Just Cork          -> Just ((#const IPPROTO_TCP), (#const TCP_CORK))
Packit 090c59
#endif
Packit 090c59
#endif // HAVE_DECL_IPPROTO_TCP
Packit 090c59
#if HAVE_DECL_IPPROTO_IPV6
Packit 090c59
#if HAVE_DECL_IPV6_V6ONLY
Packit 090c59
    Just IPv6Only      -> Just ((#const IPPROTO_IPV6), (#const IPV6_V6ONLY))
Packit 090c59
#endif
Packit 090c59
#endif // HAVE_DECL_IPPROTO_IPV6
Packit 090c59
    Just (CustomSockOpt opt) -> Just opt
Packit 090c59
    _             -> Nothing
Packit 090c59
Packit 090c59
-- | Return the option level and option value if they exist,
Packit 090c59
-- otherwise throw an error that begins "Network.Socket." ++ the String
Packit 090c59
-- parameter
Packit 090c59
packSocketOption' :: String -> SocketOption -> IO (CInt, CInt)
Packit 090c59
packSocketOption' caller so = maybe err return (packSocketOption so)
Packit 090c59
 where
Packit 090c59
  err = ioError . userError . concat $ ["Network.Socket.", caller,
Packit 090c59
    ": socket option ", show so, " unsupported on this system"]
Packit 090c59
Packit 090c59
-- | Set a socket option that expects an Int value.
Packit 090c59
-- There is currently no API to set e.g. the timeval socket options
Packit 090c59
setSocketOption :: Socket
Packit 090c59
                -> SocketOption -- Option Name
Packit 090c59
                -> Int          -- Option Value
Packit 090c59
                -> IO ()
Packit 090c59
setSocketOption (MkSocket s _ _ _ _) so v = do
Packit 090c59
   (level, opt) <- packSocketOption' "setSocketOption" so
Packit 090c59
   with (fromIntegral v) $ \ptr_v -> do
Packit 090c59
   throwSocketErrorIfMinus1_ "Network.Socket.setSocketOption" $
Packit 090c59
       c_setsockopt s level opt ptr_v
Packit 090c59
          (fromIntegral (sizeOf (undefined :: CInt)))
Packit 090c59
   return ()
Packit 090c59
Packit 090c59
Packit 090c59
-- | Get a socket option that gives an Int value.
Packit 090c59
-- There is currently no API to get e.g. the timeval socket options
Packit 090c59
getSocketOption :: Socket
Packit 090c59
                -> SocketOption  -- Option Name
Packit 090c59
                -> IO Int        -- Option Value
Packit 090c59
getSocketOption (MkSocket s _ _ _ _) so = do
Packit 090c59
   (level, opt) <- packSocketOption' "getSocketOption" so
Packit 090c59
   alloca $ \ptr_v ->
Packit 090c59
     with (fromIntegral (sizeOf (undefined :: CInt))) $ \ptr_sz -> do
Packit 090c59
       throwSocketErrorIfMinus1Retry_ "Network.Socket.getSocketOption" $
Packit 090c59
         c_getsockopt s level opt ptr_v ptr_sz
Packit 090c59
       fromIntegral `liftM` peek ptr_v
Packit 090c59
Packit 090c59
Packit 090c59
#if defined(HAVE_STRUCT_UCRED) || defined(HAVE_GETPEEREID)
Packit 090c59
-- | Returns the processID, userID and groupID of the socket's peer.
Packit 090c59
--
Packit 090c59
-- Only available on platforms that support SO_PEERCRED or GETPEEREID(3)
Packit 090c59
-- on domain sockets.
Packit 090c59
-- GETPEEREID(3) returns userID and groupID. processID is always 0.
Packit 090c59
getPeerCred :: Socket -> IO (CUInt, CUInt, CUInt)
Packit 090c59
getPeerCred sock = do
Packit 090c59
#ifdef HAVE_STRUCT_UCRED
Packit 090c59
  let fd = fdSocket sock
Packit 090c59
  let sz = (#const sizeof(struct ucred))
Packit 090c59
  allocaBytes sz $ \ ptr_cr ->
Packit 090c59
   with (fromIntegral sz) $ \ ptr_sz -> do
Packit 090c59
     _ <- ($) throwSocketErrorIfMinus1Retry "Network.Socket.getPeerCred" $
Packit 090c59
       c_getsockopt fd (#const SOL_SOCKET) (#const SO_PEERCRED) ptr_cr ptr_sz
Packit 090c59
     pid <- (#peek struct ucred, pid) ptr_cr
Packit 090c59
     uid <- (#peek struct ucred, uid) ptr_cr
Packit 090c59
     gid <- (#peek struct ucred, gid) ptr_cr
Packit 090c59
     return (pid, uid, gid)
Packit 090c59
#else
Packit 090c59
  (uid,gid) <- getPeerEid sock
Packit 090c59
  return (0,uid,gid)
Packit 090c59
#endif
Packit 090c59
Packit 090c59
#ifdef HAVE_GETPEEREID
Packit 090c59
-- | The getpeereid() function returns the effective user and group IDs of the
Packit 090c59
-- peer connected to a UNIX-domain socket
Packit 090c59
getPeerEid :: Socket -> IO (CUInt, CUInt)
Packit 090c59
getPeerEid sock = do
Packit 090c59
  let fd = fdSocket sock
Packit 090c59
  alloca $ \ ptr_uid ->
Packit 090c59
    alloca $ \ ptr_gid -> do
Packit 090c59
      throwSocketErrorIfMinus1Retry_ "Network.Socket.getPeerEid" $
Packit 090c59
        c_getpeereid fd ptr_uid ptr_gid
Packit 090c59
      uid <- peek ptr_uid
Packit 090c59
      gid <- peek ptr_gid
Packit 090c59
      return (uid, gid)
Packit 090c59
#endif
Packit 090c59
#endif
Packit 090c59
Packit 090c59
##if !(MIN_VERSION_base(4,3,1))
Packit 090c59
closeFdWith closer fd = closer fd
Packit 090c59
##endif
Packit 090c59
Packit 090c59
#if defined(DOMAIN_SOCKET_SUPPORT)
Packit 090c59
-- sending/receiving ancillary socket data; low-level mechanism
Packit 090c59
-- for transmitting file descriptors, mainly.
Packit 090c59
sendFd :: Socket -> CInt -> IO ()
Packit 090c59
sendFd sock outfd = do
Packit 090c59
  _ <- ($) throwSocketErrorWaitWrite sock "Network.Socket.sendFd" $
Packit 090c59
     c_sendFd (fdSocket sock) outfd
Packit 090c59
   -- Note: If Winsock supported FD-passing, thi would have been
Packit 090c59
   -- incorrect (since socket FDs need to be closed via closesocket().)
Packit 090c59
  closeFd outfd
Packit 090c59
Packit 090c59
-- | Receive a file descriptor over a domain socket. Note that the resulting
Packit 090c59
-- file descriptor may have to be put into non-blocking mode in order to be
Packit 090c59
-- used safely. See 'setNonBlockIfNeeded'.
Packit 090c59
recvFd :: Socket -> IO CInt
Packit 090c59
recvFd sock = do
Packit 090c59
  theFd <- throwSocketErrorWaitRead sock "Network.Socket.recvFd" $
Packit 090c59
               c_recvFd (fdSocket sock)
Packit 090c59
  return theFd
Packit 090c59
Packit 090c59
foreign import ccall SAFE_ON_WIN "sendFd" c_sendFd :: CInt -> CInt -> IO CInt
Packit 090c59
foreign import ccall SAFE_ON_WIN "recvFd" c_recvFd :: CInt -> IO CInt
Packit 090c59
Packit 090c59
#endif
Packit 090c59
Packit 090c59
-- ---------------------------------------------------------------------------
Packit 090c59
-- Utility Functions
Packit 090c59
Packit 090c59
aNY_PORT :: PortNumber
Packit 090c59
aNY_PORT = 0
Packit 090c59
Packit 090c59
-- | The IPv4 wild card address.
Packit 090c59
Packit 090c59
iNADDR_ANY :: HostAddress
Packit 090c59
iNADDR_ANY = htonl (#const INADDR_ANY)
Packit 090c59
Packit 090c59
-- | Converts the from host byte order to network byte order.
Packit 090c59
foreign import CALLCONV unsafe "htonl" htonl :: Word32 -> Word32
Packit 090c59
-- | Converts the from network byte order to host byte order.
Packit 090c59
foreign import CALLCONV unsafe "ntohl" ntohl :: Word32 -> Word32
Packit 090c59
Packit 090c59
#if defined(IPV6_SOCKET_SUPPORT)
Packit 090c59
-- | The IPv6 wild card address.
Packit 090c59
Packit 090c59
iN6ADDR_ANY :: HostAddress6
Packit 090c59
iN6ADDR_ANY = (0, 0, 0, 0)
Packit 090c59
#endif
Packit 090c59
Packit 090c59
sOMAXCONN :: Int
Packit 090c59
sOMAXCONN = #const SOMAXCONN
Packit 090c59
Packit 090c59
sOL_SOCKET :: Int
Packit 090c59
sOL_SOCKET = #const SOL_SOCKET
Packit 090c59
Packit 090c59
#ifdef SCM_RIGHTS
Packit 090c59
sCM_RIGHTS :: Int
Packit 090c59
sCM_RIGHTS = #const SCM_RIGHTS
Packit 090c59
#endif
Packit 090c59
Packit 090c59
-- | This is the value of SOMAXCONN, typically 128.
Packit 090c59
-- 128 is good enough for normal network servers but
Packit 090c59
-- is too small for high performance servers.
Packit 090c59
maxListenQueue :: Int
Packit 090c59
maxListenQueue = sOMAXCONN
Packit 090c59
Packit 090c59
-- -----------------------------------------------------------------------------
Packit 090c59
Packit 090c59
data ShutdownCmd
Packit 090c59
 = ShutdownReceive
Packit 090c59
 | ShutdownSend
Packit 090c59
 | ShutdownBoth
Packit 090c59
 deriving Typeable
Packit 090c59
Packit 090c59
sdownCmdToInt :: ShutdownCmd -> CInt
Packit 090c59
sdownCmdToInt ShutdownReceive = 0
Packit 090c59
sdownCmdToInt ShutdownSend    = 1
Packit 090c59
sdownCmdToInt ShutdownBoth    = 2
Packit 090c59
Packit 090c59
-- | Shut down one or both halves of the connection, depending on the
Packit 090c59
-- second argument to the function.  If the second argument is
Packit 090c59
-- 'ShutdownReceive', further receives are disallowed.  If it is
Packit 090c59
-- 'ShutdownSend', further sends are disallowed.  If it is
Packit 090c59
-- 'ShutdownBoth', further sends and receives are disallowed.
Packit 090c59
shutdown :: Socket -> ShutdownCmd -> IO ()
Packit 090c59
shutdown (MkSocket s _ _ _ _) stype = do
Packit 090c59
  throwSocketErrorIfMinus1Retry_ "Network.Socket.shutdown" $
Packit 090c59
    c_shutdown s (sdownCmdToInt stype)
Packit 090c59
  return ()
Packit 090c59
Packit 090c59
-- -----------------------------------------------------------------------------
Packit 090c59
Packit 090c59
-- | Close the socket. Sending data to or receiving data from closed socket
Packit 090c59
-- may lead to undefined behaviour.
Packit 090c59
close :: Socket -> IO ()
Packit 090c59
close (MkSocket s _ _ _ socketStatus) = do
Packit 090c59
 modifyMVar_ socketStatus $ \ status ->
Packit 090c59
   case status of
Packit 090c59
     ConvertedToHandle ->
Packit 090c59
         ioError (userError ("close: converted to a Handle, use hClose instead"))
Packit 090c59
     Closed ->
Packit 090c59
         return status
Packit 090c59
     _ -> closeFdWith (closeFd . fromIntegral) (fromIntegral s) >> return Closed
Packit 090c59
Packit 090c59
-- -----------------------------------------------------------------------------
Packit 090c59
Packit 090c59
-- | Determines whether 'close' has been used on the 'Socket'. This
Packit 090c59
-- does /not/ indicate any status about the socket beyond this. If the
Packit 090c59
-- socket has been closed remotely, this function can still return
Packit 090c59
-- 'True'.
Packit 090c59
isConnected :: Socket -> IO Bool
Packit 090c59
isConnected (MkSocket _ _ _ _ status) = do
Packit 090c59
    value <- readMVar status
Packit 090c59
    return (value == Connected)
Packit 090c59
Packit 090c59
-- -----------------------------------------------------------------------------
Packit 090c59
-- Socket Predicates
Packit 090c59
Packit 090c59
isBound :: Socket -> IO Bool
Packit 090c59
isBound (MkSocket _ _ _ _ status) = do
Packit 090c59
    value <- readMVar status
Packit 090c59
    return (value == Bound)
Packit 090c59
Packit 090c59
isListening :: Socket -> IO Bool
Packit 090c59
isListening (MkSocket _ _ _  _ status) = do
Packit 090c59
    value <- readMVar status
Packit 090c59
    return (value == Listening)
Packit 090c59
Packit 090c59
isReadable  :: Socket -> IO Bool
Packit 090c59
isReadable (MkSocket _ _ _ _ status) = do
Packit 090c59
    value <- readMVar status
Packit 090c59
    return (value == Listening || value == Connected)
Packit 090c59
Packit 090c59
isWritable  :: Socket -> IO Bool
Packit 090c59
isWritable = isReadable -- sort of.
Packit 090c59
Packit 090c59
isAcceptable :: Socket -> IO Bool
Packit 090c59
#if defined(DOMAIN_SOCKET_SUPPORT)
Packit 090c59
isAcceptable (MkSocket _ AF_UNIX x _ status)
Packit 090c59
    | x == Stream || x == SeqPacket = do
Packit 090c59
        value <- readMVar status
Packit 090c59
        return (value == Connected || value == Bound || value == Listening)
Packit 090c59
isAcceptable (MkSocket _ AF_UNIX _ _ _) = return False
Packit 090c59
#endif
Packit 090c59
isAcceptable (MkSocket _ _ _ _ status) = do
Packit 090c59
    value <- readMVar status
Packit 090c59
    return (value == Connected || value == Listening)
Packit 090c59
Packit 090c59
-- -----------------------------------------------------------------------------
Packit 090c59
-- Internet address manipulation routines:
Packit 090c59
Packit 090c59
inet_addr :: String -> IO HostAddress
Packit 090c59
inet_addr ipstr = withSocketsDo $ do
Packit 090c59
   withCString ipstr $ \str -> do
Packit 090c59
   had <- c_inet_addr str
Packit 090c59
   if had == -1
Packit 090c59
    then ioError $ userError $
Packit 090c59
      "Network.Socket.inet_addr: Malformed address: " ++ ipstr
Packit 090c59
    else return had  -- network byte order
Packit 090c59
Packit 090c59
inet_ntoa :: HostAddress -> IO String
Packit 090c59
inet_ntoa haddr = withSocketsDo $ do
Packit 090c59
  pstr <- c_inet_ntoa haddr
Packit 090c59
  peekCString pstr
Packit 090c59
Packit 090c59
-- | Turns a Socket into an 'Handle'. By default, the new handle is
Packit 090c59
-- unbuffered. Use 'System.IO.hSetBuffering' to change the buffering.
Packit 090c59
--
Packit 090c59
-- Note that since a 'Handle' is automatically closed by a finalizer
Packit 090c59
-- when it is no longer referenced, you should avoid doing any more
Packit 090c59
-- operations on the 'Socket' after calling 'socketToHandle'.  To
Packit 090c59
-- close the 'Socket' after 'socketToHandle', call 'System.IO.hClose'
Packit 090c59
-- on the 'Handle'.
Packit 090c59
Packit 090c59
socketToHandle :: Socket -> IOMode -> IO Handle
Packit 090c59
socketToHandle s@(MkSocket fd _ _ _ socketStatus) mode = do
Packit 090c59
 modifyMVar socketStatus $ \ status ->
Packit 090c59
    if status == ConvertedToHandle
Packit 090c59
        then ioError (userError ("socketToHandle: already a Handle"))
Packit 090c59
        else do
Packit 090c59
    h <- fdToHandle' (fromIntegral fd) (Just GHC.IO.Device.Stream) True (show s) mode True{-bin-}
Packit 090c59
    hSetBuffering h NoBuffering
Packit 090c59
    return (ConvertedToHandle, h)
Packit 090c59
Packit 090c59
-- | Pack a list of values into a bitmask.  The possible mappings from
Packit 090c59
-- value to bit-to-set are given as the first argument.  We assume
Packit 090c59
-- that each value can cause exactly one bit to be set; unpackBits will
Packit 090c59
-- break if this property is not true.
Packit 090c59
Packit 090c59
packBits :: (Eq a, Num b, Bits b) => [(a, b)] -> [a] -> b
Packit 090c59
Packit 090c59
packBits mapping xs = foldl' pack 0 mapping
Packit 090c59
    where pack acc (k, v) | k `elem` xs = acc .|. v
Packit 090c59
                          | otherwise   = acc
Packit 090c59
Packit 090c59
-- | Unpack a bitmask into a list of values.
Packit 090c59
Packit 090c59
unpackBits :: (Num b, Bits b) => [(a, b)] -> b -> [a]
Packit 090c59
Packit 090c59
-- Be permissive and ignore unknown bit values. At least on OS X,
Packit 090c59
-- getaddrinfo returns an ai_flags field with bits set that have no
Packit 090c59
-- entry in <netdb.h>.
Packit 090c59
unpackBits [] _    = []
Packit 090c59
unpackBits ((k,v):xs) r
Packit 090c59
    | r .&. v /= 0 = k : unpackBits xs (r .&. complement v)
Packit 090c59
    | otherwise    = unpackBits xs r
Packit 090c59
Packit 090c59
-----------------------------------------------------------------------------
Packit 090c59
-- Address and service lookups
Packit 090c59
Packit 090c59
#if defined(IPV6_SOCKET_SUPPORT)
Packit 090c59
Packit 090c59
-- | Flags that control the querying behaviour of 'getAddrInfo'.
Packit 090c59
--   For more information, see <https://tools.ietf.org/html/rfc3493#page-25>
Packit 090c59
data AddrInfoFlag =
Packit 090c59
    -- | The list of returned 'AddrInfo' values will
Packit 090c59
    --   only contain IPv4 addresses if the local system has at least
Packit 090c59
    --   one IPv4 interface configured, and likewise for IPv6.
Packit 090c59
    --   (Only some platforms support this.)
Packit 090c59
      AI_ADDRCONFIG
Packit 090c59
    -- | If 'AI_ALL' is specified, return all matching IPv6 and
Packit 090c59
    --   IPv4 addresses.  Otherwise, this flag has no effect.
Packit 090c59
    --   (Only some platforms support this.)
Packit 090c59
    | AI_ALL
Packit 090c59
    -- | The 'addrCanonName' field of the first returned
Packit 090c59
    --   'AddrInfo' will contain the "canonical name" of the host.
Packit 090c59
    | AI_CANONNAME
Packit 090c59
    -- | The 'HostName' argument /must/ be a numeric
Packit 090c59
    --   address in string form, and network name lookups will not be
Packit 090c59
    --   attempted.
Packit 090c59
    | AI_NUMERICHOST
Packit 090c59
    -- | The 'ServiceName' argument /must/ be a port
Packit 090c59
    --   number in string form, and service name lookups will not be
Packit 090c59
    --   attempted. (Only some platforms support this.)
Packit 090c59
    | AI_NUMERICSERV
Packit 090c59
    -- | If no 'HostName' value is provided, the network
Packit 090c59
    --   address in each 'SockAddr'
Packit 090c59
    --   will be left as a "wild card", i.e. as either 'iNADDR_ANY'
Packit 090c59
    --   or 'iN6ADDR_ANY'.  This is useful for server applications that
Packit 090c59
    --   will accept connections from any client.
Packit 090c59
    | AI_PASSIVE
Packit 090c59
    -- | If an IPv6 lookup is performed, and no IPv6
Packit 090c59
    --   addresses are found, IPv6-mapped IPv4 addresses will be
Packit 090c59
    --   returned. (Only some platforms support this.)
Packit 090c59
    | AI_V4MAPPED
Packit 090c59
    deriving (Eq, Read, Show, Typeable)
Packit 090c59
Packit 090c59
aiFlagMapping :: [(AddrInfoFlag, CInt)]
Packit 090c59
Packit 090c59
aiFlagMapping =
Packit 090c59
    [
Packit 090c59
#if HAVE_DECL_AI_ADDRCONFIG
Packit 090c59
     (AI_ADDRCONFIG, #const AI_ADDRCONFIG),
Packit 090c59
#else
Packit 090c59
     (AI_ADDRCONFIG, 0),
Packit 090c59
#endif
Packit 090c59
#if HAVE_DECL_AI_ALL
Packit 090c59
     (AI_ALL, #const AI_ALL),
Packit 090c59
#else
Packit 090c59
     (AI_ALL, 0),
Packit 090c59
#endif
Packit 090c59
     (AI_CANONNAME, #const AI_CANONNAME),
Packit 090c59
     (AI_NUMERICHOST, #const AI_NUMERICHOST),
Packit 090c59
#if HAVE_DECL_AI_NUMERICSERV
Packit 090c59
     (AI_NUMERICSERV, #const AI_NUMERICSERV),
Packit 090c59
#else
Packit 090c59
     (AI_NUMERICSERV, 0),
Packit 090c59
#endif
Packit 090c59
     (AI_PASSIVE, #const AI_PASSIVE),
Packit 090c59
#if HAVE_DECL_AI_V4MAPPED
Packit 090c59
     (AI_V4MAPPED, #const AI_V4MAPPED)
Packit 090c59
#else
Packit 090c59
     (AI_V4MAPPED, 0)
Packit 090c59
#endif
Packit 090c59
    ]
Packit 090c59
Packit 090c59
-- | Indicate whether the given 'AddrInfoFlag' will have any effect on
Packit 090c59
-- this system.
Packit 090c59
addrInfoFlagImplemented :: AddrInfoFlag -> Bool
Packit 090c59
addrInfoFlagImplemented f = packBits aiFlagMapping [f] /= 0
Packit 090c59
Packit 090c59
data AddrInfo =
Packit 090c59
    AddrInfo {
Packit 090c59
        addrFlags :: [AddrInfoFlag],
Packit 090c59
        addrFamily :: Family,
Packit 090c59
        addrSocketType :: SocketType,
Packit 090c59
        addrProtocol :: ProtocolNumber,
Packit 090c59
        addrAddress :: SockAddr,
Packit 090c59
        addrCanonName :: Maybe String
Packit 090c59
        }
Packit 090c59
    deriving (Eq, Show, Typeable)
Packit 090c59
Packit 090c59
instance Storable AddrInfo where
Packit 090c59
    sizeOf    _ = #const sizeof(struct addrinfo)
Packit 090c59
    alignment _ = alignment (undefined :: CInt)
Packit 090c59
Packit 090c59
    peek p = do
Packit 090c59
        ai_flags <- (#peek struct addrinfo, ai_flags) p
Packit 090c59
        ai_family <- (#peek struct addrinfo, ai_family) p
Packit 090c59
        ai_socktype <- (#peek struct addrinfo, ai_socktype) p
Packit 090c59
        ai_protocol <- (#peek struct addrinfo, ai_protocol) p
Packit 090c59
        ai_addr <- (#peek struct addrinfo, ai_addr) p >>= peekSockAddr
Packit 090c59
        ai_canonname_ptr <- (#peek struct addrinfo, ai_canonname) p
Packit 090c59
Packit 090c59
        ai_canonname <- if ai_canonname_ptr == nullPtr
Packit 090c59
                        then return Nothing
Packit 090c59
                        else liftM Just $ peekCString ai_canonname_ptr
Packit 090c59
Packit 090c59
        socktype <- unpackSocketType' "AddrInfo.peek" ai_socktype
Packit 090c59
        return (AddrInfo
Packit 090c59
                {
Packit 090c59
                 addrFlags = unpackBits aiFlagMapping ai_flags,
Packit 090c59
                 addrFamily = unpackFamily ai_family,
Packit 090c59
                 addrSocketType = socktype,
Packit 090c59
                 addrProtocol = ai_protocol,
Packit 090c59
                 addrAddress = ai_addr,
Packit 090c59
                 addrCanonName = ai_canonname
Packit 090c59
                })
Packit 090c59
Packit 090c59
    poke p (AddrInfo flags family socketType protocol _ _) = do
Packit 090c59
        c_stype <- packSocketTypeOrThrow "AddrInfo.poke" socketType
Packit 090c59
Packit 090c59
        (#poke struct addrinfo, ai_flags) p (packBits aiFlagMapping flags)
Packit 090c59
        (#poke struct addrinfo, ai_family) p (packFamily family)
Packit 090c59
        (#poke struct addrinfo, ai_socktype) p c_stype
Packit 090c59
        (#poke struct addrinfo, ai_protocol) p protocol
Packit 090c59
Packit 090c59
        -- stuff below is probably not needed, but let's zero it for safety
Packit 090c59
Packit 090c59
        (#poke struct addrinfo, ai_addrlen) p (0::CSize)
Packit 090c59
        (#poke struct addrinfo, ai_addr) p nullPtr
Packit 090c59
        (#poke struct addrinfo, ai_canonname) p nullPtr
Packit 090c59
        (#poke struct addrinfo, ai_next) p nullPtr
Packit 090c59
Packit 090c59
-- | Flags that control the querying behaviour of 'getNameInfo'.
Packit 090c59
--   For more information, see <https://tools.ietf.org/html/rfc3493#page-30>
Packit 090c59
data NameInfoFlag =
Packit 090c59
    -- | Resolve a datagram-based service name.  This is
Packit 090c59
    --   required only for the few protocols that have different port
Packit 090c59
    --   numbers for their datagram-based versions than for their
Packit 090c59
    --   stream-based versions.
Packit 090c59
      NI_DGRAM
Packit 090c59
    -- | If the hostname cannot be looked up, an IO error is thrown.
Packit 090c59
    | NI_NAMEREQD
Packit 090c59
    -- | If a host is local, return only the hostname part of the FQDN.
Packit 090c59
    | NI_NOFQDN
Packit 090c59
    -- | The name of the host is not looked up.
Packit 090c59
    --   Instead, a numeric representation of the host's
Packit 090c59
    --   address is returned.  For an IPv4 address, this will be a
Packit 090c59
    --   dotted-quad string.  For IPv6, it will be colon-separated
Packit 090c59
    --   hexadecimal.
Packit 090c59
    | NI_NUMERICHOST
Packit 090c59
    -- | The name of the service is not
Packit 090c59
    --   looked up.  Instead, a numeric representation of the
Packit 090c59
    --   service is returned.
Packit 090c59
    | NI_NUMERICSERV
Packit 090c59
    deriving (Eq, Read, Show, Typeable)
Packit 090c59
Packit 090c59
niFlagMapping :: [(NameInfoFlag, CInt)]
Packit 090c59
Packit 090c59
niFlagMapping = [(NI_DGRAM, #const NI_DGRAM),
Packit 090c59
                 (NI_NAMEREQD, #const NI_NAMEREQD),
Packit 090c59
                 (NI_NOFQDN, #const NI_NOFQDN),
Packit 090c59
                 (NI_NUMERICHOST, #const NI_NUMERICHOST),
Packit 090c59
                 (NI_NUMERICSERV, #const NI_NUMERICSERV)]
Packit 090c59
Packit 090c59
-- | Default hints for address lookup with 'getAddrInfo'.  The values
Packit 090c59
-- of the 'addrAddress' and 'addrCanonName' fields are 'undefined',
Packit 090c59
-- and are never inspected by 'getAddrInfo'.
Packit 090c59
--
Packit 090c59
-- >>> addrFlags defaultHints
Packit 090c59
-- []
Packit 090c59
-- >>> addrFamily defaultHints
Packit 090c59
-- AF_UNSPEC
Packit 090c59
-- >>> addrSocketType defaultHints
Packit 090c59
-- NoSocketType
Packit 090c59
-- >>> addrProtocol defaultHints
Packit 090c59
-- 0
Packit 090c59
Packit 090c59
defaultHints :: AddrInfo
Packit 090c59
defaultHints = AddrInfo {
Packit 090c59
                         addrFlags = [],
Packit 090c59
                         addrFamily = AF_UNSPEC,
Packit 090c59
                         addrSocketType = NoSocketType,
Packit 090c59
                         addrProtocol = defaultProtocol,
Packit 090c59
                         addrAddress = undefined,
Packit 090c59
                         addrCanonName = undefined
Packit 090c59
                        }
Packit 090c59
Packit 090c59
-- | Resolve a host or service name to one or more addresses.
Packit 090c59
-- The 'AddrInfo' values that this function returns contain 'SockAddr'
Packit 090c59
-- values that you can pass directly to 'connect' or
Packit 090c59
-- 'bind'.
Packit 090c59
--
Packit 090c59
-- This function is protocol independent.  It can return both IPv4 and
Packit 090c59
-- IPv6 address information.
Packit 090c59
--
Packit 090c59
-- The 'AddrInfo' argument specifies the preferred query behaviour,
Packit 090c59
-- socket options, or protocol.  You can override these conveniently
Packit 090c59
-- using Haskell's record update syntax on 'defaultHints', for example
Packit 090c59
-- as follows:
Packit 090c59
--
Packit 090c59
-- >>> let hints = defaultHints { addrFlags = [AI_NUMERICHOST], addrSocketType = Stream }
Packit 090c59
--
Packit 090c59
-- You must provide a 'Just' value for at least one of the 'HostName'
Packit 090c59
-- or 'ServiceName' arguments.  'HostName' can be either a numeric
Packit 090c59
-- network address (dotted quad for IPv4, colon-separated hex for
Packit 090c59
-- IPv6) or a hostname.  In the latter case, its addresses will be
Packit 090c59
-- looked up unless 'AI_NUMERICHOST' is specified as a hint.  If you
Packit 090c59
-- do not provide a 'HostName' value /and/ do not set 'AI_PASSIVE' as
Packit 090c59
-- a hint, network addresses in the result will contain the address of
Packit 090c59
-- the loopback interface.
Packit 090c59
--
Packit 090c59
-- If the query fails, this function throws an IO exception instead of
Packit 090c59
-- returning an empty list.  Otherwise, it returns a non-empty list
Packit 090c59
-- of 'AddrInfo' values.
Packit 090c59
--
Packit 090c59
-- There are several reasons why a query might result in several
Packit 090c59
-- values.  For example, the queried-for host could be multihomed, or
Packit 090c59
-- the service might be available via several protocols.
Packit 090c59
--
Packit 090c59
-- Note: the order of arguments is slightly different to that defined
Packit 090c59
-- for @getaddrinfo@ in RFC 2553.  The 'AddrInfo' parameter comes first
Packit 090c59
-- to make partial application easier.
Packit 090c59
--
Packit 090c59
-- >>> addr:_ <- getAddrInfo (Just hints) (Just "127.0.0.1") (Just "http")
Packit 090c59
-- >>> addrAddress addr
Packit 090c59
-- 127.0.0.1:80
Packit 090c59
Packit 090c59
getAddrInfo :: Maybe AddrInfo -- ^ preferred socket type or protocol
Packit 090c59
            -> Maybe HostName -- ^ host name to look up
Packit 090c59
            -> Maybe ServiceName -- ^ service name to look up
Packit 090c59
            -> IO [AddrInfo] -- ^ resolved addresses, with "best" first
Packit 090c59
Packit 090c59
getAddrInfo hints node service = withSocketsDo $
Packit 090c59
  maybeWith withCString node $ \c_node ->
Packit 090c59
    maybeWith withCString service $ \c_service ->
Packit 090c59
      maybeWith with filteredHints $ \c_hints ->
Packit 090c59
        alloca $ \ptr_ptr_addrs -> do
Packit 090c59
          ret <- c_getaddrinfo c_node c_service c_hints ptr_ptr_addrs
Packit 090c59
          case ret of
Packit 090c59
            0 -> do ptr_addrs <- peek ptr_ptr_addrs
Packit 090c59
                    ais <- followAddrInfo ptr_addrs
Packit 090c59
                    c_freeaddrinfo ptr_addrs
Packit 090c59
                    return ais
Packit 090c59
            _ -> do err <- gai_strerror ret
Packit 090c59
                    ioError (ioeSetErrorString
Packit 090c59
                             (mkIOError NoSuchThing "Network.Socket.getAddrInfo" Nothing
Packit 090c59
                              Nothing) err)
Packit 090c59
    -- Leaving out the service and using AI_NUMERICSERV causes a
Packit 090c59
    -- segfault on OS X 10.8.2. This code removes AI_NUMERICSERV
Packit 090c59
    -- (which has no effect) in that case.
Packit 090c59
  where
Packit 090c59
#if defined(darwin_HOST_OS)
Packit 090c59
    filteredHints = case service of
Packit 090c59
        Nothing -> fmap (\ h -> h { addrFlags = delete AI_NUMERICSERV (addrFlags h) }) hints
Packit 090c59
        _       -> hints
Packit 090c59
#else
Packit 090c59
    filteredHints = hints
Packit 090c59
#endif
Packit 090c59
Packit 090c59
followAddrInfo :: Ptr AddrInfo -> IO [AddrInfo]
Packit 090c59
Packit 090c59
followAddrInfo ptr_ai | ptr_ai == nullPtr = return []
Packit 090c59
                      | otherwise = do
Packit 090c59
    a <- peek ptr_ai
Packit 090c59
    as <- (#peek struct addrinfo, ai_next) ptr_ai >>= followAddrInfo
Packit 090c59
    return (a:as)
Packit 090c59
Packit 090c59
foreign import ccall safe "hsnet_getaddrinfo"
Packit 090c59
    c_getaddrinfo :: CString -> CString -> Ptr AddrInfo -> Ptr (Ptr AddrInfo)
Packit 090c59
                  -> IO CInt
Packit 090c59
Packit 090c59
foreign import ccall safe "hsnet_freeaddrinfo"
Packit 090c59
    c_freeaddrinfo :: Ptr AddrInfo -> IO ()
Packit 090c59
Packit 090c59
gai_strerror :: CInt -> IO String
Packit 090c59
Packit 090c59
#ifdef HAVE_GAI_STRERROR
Packit 090c59
gai_strerror n = c_gai_strerror n >>= peekCString
Packit 090c59
Packit 090c59
foreign import ccall safe "gai_strerror"
Packit 090c59
    c_gai_strerror :: CInt -> IO CString
Packit 090c59
#else
Packit 090c59
gai_strerror n = ioError $ userError $ "Network.Socket.gai_strerror not supported: " ++ show n
Packit 090c59
#endif
Packit 090c59
Packit 090c59
withCStringIf :: Bool -> Int -> (CSize -> CString -> IO a) -> IO a
Packit 090c59
withCStringIf False _ f = f 0 nullPtr
Packit 090c59
withCStringIf True n f = allocaBytes n (f (fromIntegral n))
Packit 090c59
Packit 090c59
-- | Resolve an address to a host or service name.
Packit 090c59
-- This function is protocol independent.
Packit 090c59
-- The list of 'NameInfoFlag' values controls query behaviour.
Packit 090c59
--
Packit 090c59
-- If a host or service's name cannot be looked up, then the numeric
Packit 090c59
-- form of the address or service will be returned.
Packit 090c59
--
Packit 090c59
-- If the query fails, this function throws an IO exception.
Packit 090c59
--
Packit 090c59
-- Example:
Packit 090c59
-- @
Packit 090c59
--   (hostName, _) <- getNameInfo [] True False myAddress
Packit 090c59
-- @
Packit 090c59
Packit 090c59
getNameInfo :: [NameInfoFlag] -- ^ flags to control lookup behaviour
Packit 090c59
            -> Bool -- ^ whether to look up a hostname
Packit 090c59
            -> Bool -- ^ whether to look up a service name
Packit 090c59
            -> SockAddr -- ^ the address to look up
Packit 090c59
            -> IO (Maybe HostName, Maybe ServiceName)
Packit 090c59
Packit 090c59
getNameInfo flags doHost doService addr = withSocketsDo $
Packit 090c59
  withCStringIf doHost (#const NI_MAXHOST) $ \c_hostlen c_host ->
Packit 090c59
    withCStringIf doService (#const NI_MAXSERV) $ \c_servlen c_serv -> do
Packit 090c59
      withSockAddr addr $ \ptr_addr sz -> do
Packit 090c59
        ret <- c_getnameinfo ptr_addr (fromIntegral sz) c_host c_hostlen
Packit 090c59
                             c_serv c_servlen (packBits niFlagMapping flags)
Packit 090c59
        case ret of
Packit 090c59
          0 -> do
Packit 090c59
            let peekIf doIf c_val = if doIf
Packit 090c59
                                     then liftM Just $ peekCString c_val
Packit 090c59
                                     else return Nothing
Packit 090c59
            host <- peekIf doHost c_host
Packit 090c59
            serv <- peekIf doService c_serv
Packit 090c59
            return (host, serv)
Packit 090c59
          _ -> do err <- gai_strerror ret
Packit 090c59
                  ioError (ioeSetErrorString
Packit 090c59
                           (mkIOError NoSuchThing "Network.Socket.getNameInfo" Nothing
Packit 090c59
                            Nothing) err)
Packit 090c59
Packit 090c59
foreign import ccall safe "hsnet_getnameinfo"
Packit 090c59
    c_getnameinfo :: Ptr SockAddr -> CInt{-CSockLen???-} -> CString -> CSize -> CString
Packit 090c59
                  -> CSize -> CInt -> IO CInt
Packit 090c59
#endif
Packit 090c59
Packit 090c59
mkInvalidRecvArgError :: String -> IOError
Packit 090c59
mkInvalidRecvArgError loc = ioeSetErrorString (mkIOError
Packit 090c59
                                    InvalidArgument
Packit 090c59
                                    loc Nothing Nothing) "non-positive length"
Packit 090c59
Packit 090c59
mkEOFError :: String -> IOError
Packit 090c59
mkEOFError loc = ioeSetErrorString (mkIOError EOF loc Nothing Nothing) "end of file"
Packit 090c59
Packit 090c59
-- ---------------------------------------------------------------------------
Packit 090c59
-- foreign imports from the C library
Packit 090c59
Packit 090c59
foreign import ccall unsafe "hsnet_inet_ntoa"
Packit 090c59
  c_inet_ntoa :: HostAddress -> IO (Ptr CChar)
Packit 090c59
Packit 090c59
foreign import CALLCONV unsafe "inet_addr"
Packit 090c59
  c_inet_addr :: Ptr CChar -> IO HostAddress
Packit 090c59
Packit 090c59
foreign import CALLCONV unsafe "shutdown"
Packit 090c59
  c_shutdown :: CInt -> CInt -> IO CInt
Packit 090c59
Packit 090c59
closeFd :: CInt -> IO ()
Packit 090c59
closeFd fd = throwSocketErrorIfMinus1_ "Network.Socket.close" $ c_close fd
Packit 090c59
Packit 090c59
#if !defined(WITH_WINSOCK)
Packit 090c59
foreign import ccall unsafe "close"
Packit 090c59
  c_close :: CInt -> IO CInt
Packit 090c59
#else
Packit 090c59
foreign import stdcall unsafe "closesocket"
Packit 090c59
  c_close :: CInt -> IO CInt
Packit 090c59
#endif
Packit 090c59
Packit 090c59
foreign import CALLCONV unsafe "socket"
Packit 090c59
  c_socket :: CInt -> CInt -> CInt -> IO CInt
Packit 090c59
foreign import CALLCONV unsafe "bind"
Packit 090c59
  c_bind :: CInt -> Ptr SockAddr -> CInt{-CSockLen???-} -> IO CInt
Packit 090c59
foreign import CALLCONV SAFE_ON_WIN "connect"
Packit 090c59
  c_connect :: CInt -> Ptr SockAddr -> CInt{-CSockLen???-} -> IO CInt
Packit 090c59
#ifdef HAVE_ACCEPT4
Packit 090c59
foreign import CALLCONV unsafe "accept4"
Packit 090c59
  c_accept4 :: CInt -> Ptr SockAddr -> Ptr CInt{-CSockLen???-} -> CInt -> IO CInt
Packit 090c59
#else
Packit 090c59
foreign import CALLCONV unsafe "accept"
Packit 090c59
  c_accept :: CInt -> Ptr SockAddr -> Ptr CInt{-CSockLen???-} -> IO CInt
Packit 090c59
#endif
Packit 090c59
foreign import CALLCONV unsafe "listen"
Packit 090c59
  c_listen :: CInt -> CInt -> IO CInt
Packit 090c59
Packit 090c59
#if defined(mingw32_HOST_OS)
Packit 090c59
foreign import CALLCONV safe "accept"
Packit 090c59
  c_accept_safe :: CInt -> Ptr SockAddr -> Ptr CInt{-CSockLen???-} -> IO CInt
Packit 090c59
Packit 090c59
foreign import ccall unsafe "rtsSupportsBoundThreads" threaded :: Bool
Packit 090c59
#endif
Packit 090c59
Packit 090c59
foreign import CALLCONV unsafe "send"
Packit 090c59
  c_send :: CInt -> Ptr a -> CSize -> CInt -> IO CInt
Packit 090c59
foreign import CALLCONV SAFE_ON_WIN "sendto"
Packit 090c59
  c_sendto :: CInt -> Ptr a -> CSize -> CInt -> Ptr SockAddr -> CInt -> IO CInt
Packit 090c59
foreign import CALLCONV unsafe "recv"
Packit 090c59
  c_recv :: CInt -> Ptr CChar -> CSize -> CInt -> IO CInt
Packit 090c59
foreign import CALLCONV SAFE_ON_WIN "recvfrom"
Packit 090c59
  c_recvfrom :: CInt -> Ptr a -> CSize -> CInt -> Ptr SockAddr -> Ptr CInt -> IO CInt
Packit 090c59
foreign import CALLCONV unsafe "getpeername"
Packit 090c59
  c_getpeername :: CInt -> Ptr SockAddr -> Ptr CInt -> IO CInt
Packit 090c59
foreign import CALLCONV unsafe "getsockname"
Packit 090c59
  c_getsockname :: CInt -> Ptr SockAddr -> Ptr CInt -> IO CInt
Packit 090c59
Packit 090c59
foreign import CALLCONV unsafe "getsockopt"
Packit 090c59
  c_getsockopt :: CInt -> CInt -> CInt -> Ptr CInt -> Ptr CInt -> IO CInt
Packit 090c59
foreign import CALLCONV unsafe "setsockopt"
Packit 090c59
  c_setsockopt :: CInt -> CInt -> CInt -> Ptr CInt -> CInt -> IO CInt
Packit 090c59
Packit 090c59
#if defined(HAVE_GETPEEREID)
Packit 090c59
foreign import CALLCONV unsafe "getpeereid"
Packit 090c59
  c_getpeereid :: CInt -> Ptr CUInt -> Ptr CUInt -> IO CInt
Packit 090c59
#endif
Packit 090c59
-- ---------------------------------------------------------------------------
Packit 090c59
-- * Deprecated aliases
Packit 090c59
Packit 090c59
-- $deprecated-aliases
Packit 090c59
--
Packit 090c59
-- These aliases are deprecated and should not be used in new code.
Packit 090c59
-- They will be removed in some future version of the package.
Packit 090c59
Packit 090c59
{-# DEPRECATED bindSocket "use 'bind'" #-}
Packit 090c59
Packit 090c59
-- | Deprecated alias for 'bind'.
Packit 090c59
bindSocket :: Socket    -- Unconnected Socket
Packit 090c59
           -> SockAddr  -- Address to Bind to
Packit 090c59
           -> IO ()
Packit 090c59
bindSocket = bind
Packit 090c59
Packit 090c59
{-# DEPRECATED sClose "use 'close'" #-}
Packit 090c59
Packit 090c59
-- | Deprecated alias for 'close'.
Packit 090c59
sClose :: Socket -> IO ()
Packit 090c59
sClose = close
Packit 090c59
Packit 090c59
{-# DEPRECATED sIsConnected "use 'isConnected'" #-}
Packit 090c59
Packit 090c59
-- | Deprecated alias for 'isConnected'.
Packit 090c59
sIsConnected :: Socket -> IO Bool
Packit 090c59
sIsConnected = isConnected
Packit 090c59
Packit 090c59
{-# DEPRECATED sIsBound "use 'isBound'" #-}
Packit 090c59
Packit 090c59
-- | Deprecated alias for 'isBound'.
Packit 090c59
sIsBound :: Socket -> IO Bool
Packit 090c59
sIsBound = isBound
Packit 090c59
Packit 090c59
{-# DEPRECATED sIsListening "use 'isListening'" #-}
Packit 090c59
Packit 090c59
-- | Deprecated alias for 'isListening'.
Packit 090c59
sIsListening :: Socket -> IO Bool
Packit 090c59
sIsListening = isListening
Packit 090c59
Packit 090c59
{-# DEPRECATED sIsReadable "use 'isReadable'" #-}
Packit 090c59
Packit 090c59
-- | Deprecated alias for 'isReadable'.
Packit 090c59
sIsReadable  :: Socket -> IO Bool
Packit 090c59
sIsReadable = isReadable
Packit 090c59
Packit 090c59
{-# DEPRECATED sIsWritable "use 'isWritable'" #-}
Packit 090c59
Packit 090c59
-- | Deprecated alias for 'isWritable'.
Packit 090c59
sIsWritable  :: Socket -> IO Bool
Packit 090c59
sIsWritable = isWritable