|
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
|