{-# LINE 1 "Network/Socket.hsc" #-}
{-# LANGUAGE CPP, ScopedTypeVariables #-}
{-# LINE 2 "Network/Socket.hsc" #-}
{-# OPTIONS_GHC -fno-warn-orphans #-}
{-# LINE 24 "Network/Socket.hsc" #-}
module Network.Socket
(
Socket(..)
, Family(..)
, isSupportedFamily
, SocketType(..)
, isSupportedSocketType
, SockAddr(..)
, isSupportedSockAddr
, SocketStatus(..)
, HostAddress
, hostAddressToTuple
, tupleToHostAddress
{-# LINE 42 "Network/Socket.hsc" #-}
, HostAddress6
, hostAddress6ToTuple
, tupleToHostAddress6
, FlowInfo
, ScopeID
{-# LINE 48 "Network/Socket.hsc" #-}
, htonl
, ntohl
, ShutdownCmd(..)
, ProtocolNumber
, defaultProtocol
, PortNumber(..)
, HostName
, ServiceName
{-# LINE 63 "Network/Socket.hsc" #-}
, AddrInfo(..)
, AddrInfoFlag(..)
, addrInfoFlagImplemented
, defaultHints
, getAddrInfo
, NameInfoFlag(..)
, getNameInfo
{-# LINE 76 "Network/Socket.hsc" #-}
, socket
{-# LINE 80 "Network/Socket.hsc" #-}
, socketPair
{-# LINE 82 "Network/Socket.hsc" #-}
, connect
, bind
, listen
, accept
, getPeerName
, getSocketName
{-# LINE 90 "Network/Socket.hsc" #-}
, getPeerCred
{-# LINE 95 "Network/Socket.hsc" #-}
{-# LINE 96 "Network/Socket.hsc" #-}
, socketPort
, socketToHandle
, send
, sendTo
, recv
, recvFrom
, recvLen
, sendBuf
, recvBuf
, sendBufTo
, recvBufFrom
, inet_addr
, inet_ntoa
, shutdown
, close
, isConnected
, isBound
, isListening
, isReadable
, isWritable
, SocketOption(..)
, isSupportedSocketOption
, getSocketOption
, setSocketOption
{-# LINE 138 "Network/Socket.hsc" #-}
, sendFd
, recvFd
{-# LINE 142 "Network/Socket.hsc" #-}
, aNY_PORT
, iNADDR_ANY
{-# LINE 147 "Network/Socket.hsc" #-}
, iN6ADDR_ANY
{-# LINE 149 "Network/Socket.hsc" #-}
, sOMAXCONN
, sOL_SOCKET
{-# LINE 152 "Network/Socket.hsc" #-}
, sCM_RIGHTS
{-# LINE 154 "Network/Socket.hsc" #-}
, maxListenQueue
, withSocketsDo
, fdSocket
, mkSocket
, bindSocket
, sClose
, sIsConnected
, sIsBound
, sIsListening
, sIsReadable
, sIsWritable
, packFamily
, unpackFamily
, packSocketType
) where
import Data.Bits
import Data.Functor
import Data.List (foldl')
import Data.Maybe (isJust)
import Data.Word (Word8, Word32)
import Foreign.Ptr (Ptr, castPtr, nullPtr)
import Foreign.Storable (Storable(..))
import Foreign.C.Error
import Foreign.C.String (CString, withCString, withCStringLen, peekCString, peekCStringLen)
import Foreign.C.Types (CUInt, CChar)
import Foreign.C.Types (CInt(..), CSize(..))
import Foreign.Marshal.Alloc ( alloca, allocaBytes )
import Foreign.Marshal.Array ( peekArray )
import Foreign.Marshal.Utils ( maybeWith, with )
import System.IO
import Control.Monad (liftM, when)
import Control.Concurrent.MVar
import Data.Typeable
import System.IO.Error
import GHC.Conc (threadWaitRead, threadWaitWrite)
#if MIN_VERSION_base(4,3,1)
import GHC.Conc (closeFdWith)
#endif
{-# LINE 216 "Network/Socket.hsc" #-}
{-# LINE 219 "Network/Socket.hsc" #-}
import qualified GHC.IO.Device
import GHC.IO.Handle.FD
import GHC.IO.Exception
import GHC.IO
import qualified System.Posix.Internals
import Network.Socket.Internal
import Network.Socket.Types
import Prelude
type HostName = String
type ServiceName = String
#if defined(mingw32_HOST_OS)
#define SAFE_ON_WIN safe
#else
#define SAFE_ON_WIN unsafe
#endif
{-# LINE 264 "Network/Socket.hsc" #-}
mkSocket :: CInt
-> Family
-> SocketType
-> ProtocolNumber
-> SocketStatus
-> IO Socket
mkSocket fd fam sType pNum stat = do
mStat <- newMVar stat
withSocketsDo $ return ()
return (MkSocket fd fam sType pNum mStat)
fdSocket :: Socket -> CInt
fdSocket (MkSocket fd _ _ _ _) = fd
defaultProtocol :: ProtocolNumber
defaultProtocol = 0
instance Show SockAddr where
{-# LINE 289 "Network/Socket.hsc" #-}
showsPrec _ (SockAddrUnix str) = showString str
{-# LINE 291 "Network/Socket.hsc" #-}
showsPrec _ (SockAddrInet port ha)
= showString (unsafePerformIO (inet_ntoa ha))
. showString ":"
. shows port
{-# LINE 296 "Network/Socket.hsc" #-}
showsPrec _ addr@(SockAddrInet6 port _ _ _)
= showChar '['
. showString (unsafePerformIO $
fst `liftM` getNameInfo [NI_NUMERICHOST] True False addr >>=
maybe (fail "showsPrec: impossible internal error") return)
. showString "]:"
. shows port
{-# LINE 304 "Network/Socket.hsc" #-}
{-# LINE 305 "Network/Socket.hsc" #-}
showsPrec _ (SockAddrCan ifidx) = shows ifidx
{-# LINE 307 "Network/Socket.hsc" #-}
socket :: Family
-> SocketType
-> ProtocolNumber
-> IO Socket
socket family stype protocol = do
c_stype <- packSocketTypeOrThrow "socket" stype
fd <- throwSocketErrorIfMinus1Retry "socket" $
c_socket (packFamily family) c_stype protocol
setNonBlockIfNeeded fd
socket_status <- newMVar NotConnected
withSocketsDo $ return ()
let sock = MkSocket fd family stype protocol socket_status
{-# LINE 349 "Network/Socket.hsc" #-}
{-# LINE 357 "Network/Socket.hsc" #-}
when (family == AF_INET6 && (stype == Stream || stype == Datagram)) $
setSocketOption sock IPv6Only 0 `onException` close sock
{-# LINE 360 "Network/Socket.hsc" #-}
{-# LINE 361 "Network/Socket.hsc" #-}
return sock
{-# LINE 368 "Network/Socket.hsc" #-}
socketPair :: Family
-> SocketType
-> ProtocolNumber
-> IO (Socket, Socket)
socketPair family stype protocol = do
allocaBytes (2 * sizeOf (1 :: CInt)) $ \ fdArr -> do
c_stype <- packSocketTypeOrThrow "socketPair" stype
_rc <- throwSocketErrorIfMinus1Retry "socketpair" $
c_socketpair (packFamily family) c_stype protocol fdArr
[fd1,fd2] <- peekArray 2 fdArr
s1 <- mkNonBlockingSocket fd1
s2 <- mkNonBlockingSocket fd2
return (s1,s2)
where
mkNonBlockingSocket fd = do
setNonBlockIfNeeded fd
stat <- newMVar Connected
withSocketsDo $ return ()
return (MkSocket fd family stype protocol stat)
foreign import ccall unsafe "socketpair"
c_socketpair :: CInt -> CInt -> CInt -> Ptr CInt -> IO CInt
{-# LINE 391 "Network/Socket.hsc" #-}
setNonBlockIfNeeded :: CInt -> IO ()
setNonBlockIfNeeded fd =
System.Posix.Internals.setNonBlockingFD fd True
bind :: Socket
-> SockAddr
-> IO ()
bind (MkSocket s _family _stype _protocol socketStatus) addr = do
modifyMVar_ socketStatus $ \ status -> do
if status /= NotConnected
then
ioError (userError ("bind: can't peform bind on socket in status " ++
show status))
else do
withSockAddr addr $ \p_addr sz -> do
_status <- throwSocketErrorIfMinus1Retry "bind" $ c_bind s p_addr (fromIntegral sz)
return Bound
connect :: Socket
-> SockAddr
-> IO ()
connect sock@(MkSocket s _family _stype _protocol socketStatus) addr = withSocketsDo $ do
modifyMVar_ socketStatus $ \currentStatus -> do
if currentStatus /= NotConnected && currentStatus /= Bound
then
ioError (userError ("connect: can't peform connect on socket in status " ++
show currentStatus))
else do
withSockAddr addr $ \p_addr sz -> do
let connectLoop = do
r <- c_connect s p_addr (fromIntegral sz)
if r == -1
then do
{-# LINE 440 "Network/Socket.hsc" #-}
err <- getErrno
case () of
_ | err == eINTR -> connectLoop
_ | err == eINPROGRESS -> connectBlocked
_otherwise -> throwSocketError "connect"
{-# LINE 449 "Network/Socket.hsc" #-}
else return ()
connectBlocked = do
threadWaitWrite (fromIntegral s)
err <- getSocketOption sock SoError
if (err == 0)
then return ()
else throwSocketErrorCode "connect" (fromIntegral err)
connectLoop
return Connected
listen :: Socket
-> Int
-> IO ()
listen (MkSocket s _family _stype _protocol socketStatus) backlog = do
modifyMVar_ socketStatus $ \ status -> do
if status /= Bound
then
ioError (userError ("listen: can't peform listen on socket in status " ++
show status))
else do
throwSocketErrorIfMinus1Retry_ "listen" (c_listen s (fromIntegral backlog))
return Listening
accept :: Socket
-> IO (Socket,
SockAddr)
accept sock@(MkSocket s family stype protocol status) = do
currentStatus <- readMVar status
okay <- isAcceptable sock
if not okay
then
ioError (userError ("accept: can't perform accept on socket (" ++ (show (family,stype,protocol)) ++") in status " ++
show currentStatus))
else do
let sz = sizeOfSockAddrByFamily family
allocaBytes sz $ \ sockaddr -> do
{-# LINE 523 "Network/Socket.hsc" #-}
with (fromIntegral sz) $ \ ptr_len -> do
{-# LINE 525 "Network/Socket.hsc" #-}
new_sock <- throwSocketErrorIfMinus1RetryMayBlock "accept"
(threadWaitRead (fromIntegral s))
(c_accept4 s sockaddr ptr_len (2048))
{-# LINE 528 "Network/Socket.hsc" #-}
{-# LINE 533 "Network/Socket.hsc" #-}
{-# LINE 534 "Network/Socket.hsc" #-}
addr <- peekSockAddr sockaddr
new_status <- newMVar Connected
return ((MkSocket new_sock family stype protocol new_status), addr)
{-# LINE 548 "Network/Socket.hsc" #-}
{-# WARNING sendTo "Use sendTo defined in \"Network.Socket.ByteString\"" #-}
sendTo :: Socket
-> String
-> SockAddr
-> IO Int
sendTo sock xs addr = do
withCStringLen xs $ \(str, len) -> do
sendBufTo sock str len addr
sendBufTo :: Socket
-> Ptr a -> Int
-> SockAddr
-> IO Int
sendBufTo sock@(MkSocket s _family _stype _protocol _status) ptr nbytes addr = do
withSockAddr addr $ \p_addr sz -> do
liftM fromIntegral $
throwSocketErrorWaitWrite sock "sendTo" $
c_sendto s ptr (fromIntegral $ nbytes) 0
p_addr (fromIntegral sz)
{-# WARNING recvFrom "Use recvFrom defined in \"Network.Socket.ByteString\"" #-}
recvFrom :: Socket -> Int -> IO (String, Int, SockAddr)
recvFrom sock nbytes =
allocaBytes nbytes $ \ptr -> do
(len, sockaddr) <- recvBufFrom sock ptr nbytes
str <- peekCStringLen (ptr, len)
return (str, len, sockaddr)
recvBufFrom :: Socket -> Ptr a -> Int -> IO (Int, SockAddr)
recvBufFrom sock@(MkSocket s family _stype _protocol _status) ptr nbytes
| nbytes <= 0 = ioError (mkInvalidRecvArgError "Network.Socket.recvFrom")
| otherwise =
withNewSockAddr family $ \ptr_addr sz -> do
alloca $ \ptr_len -> do
poke ptr_len (fromIntegral sz)
len <- throwSocketErrorWaitRead sock "recvFrom" $
c_recvfrom s ptr (fromIntegral nbytes) 0
ptr_addr ptr_len
let len' = fromIntegral len
if len' == 0
then ioError (mkEOFError "Network.Socket.recvFrom")
else do
flg <- isConnected sock
sockaddr <-
if flg then
getPeerName sock
else
peekSockAddr ptr_addr
return (len', sockaddr)
{-# WARNING send "Use send defined in \"Network.Socket.ByteString\"" #-}
send :: Socket
-> String
-> IO Int
send sock xs = withCStringLen xs $ \(str, len) ->
sendBuf sock (castPtr str) len
sendBuf :: Socket
-> Ptr Word8
-> Int
-> IO Int
sendBuf sock@(MkSocket s _family _stype _protocol _status) str len = do
liftM fromIntegral $
{-# LINE 681 "Network/Socket.hsc" #-}
throwSocketErrorWaitWrite sock "sendBuf" $
c_send s str (fromIntegral len) 0
{-# LINE 684 "Network/Socket.hsc" #-}
{-# WARNING recv "Use recv defined in \"Network.Socket.ByteString\"" #-}
recv :: Socket -> Int -> IO String
recv sock l = fst <$> recvLen sock l
{-# WARNING recvLen "Use recvLen defined in \"Network.Socket.ByteString\"" #-}
recvLen :: Socket -> Int -> IO (String, Int)
recvLen sock nbytes =
allocaBytes nbytes $ \ptr -> do
len <- recvBuf sock ptr nbytes
s <- peekCStringLen (castPtr ptr,len)
return (s, len)
recvBuf :: Socket -> Ptr Word8 -> Int -> IO Int
recvBuf sock@(MkSocket s _family _stype _protocol _status) ptr nbytes
| nbytes <= 0 = ioError (mkInvalidRecvArgError "Network.Socket.recvBuf")
| otherwise = do
len <-
{-# LINE 735 "Network/Socket.hsc" #-}
throwSocketErrorWaitRead sock "recvBuf" $
c_recv s (castPtr ptr) (fromIntegral nbytes) 0
{-# LINE 738 "Network/Socket.hsc" #-}
let len' = fromIntegral len
if len' == 0
then ioError (mkEOFError "Network.Socket.recvBuf")
else return len'
socketPort :: Socket
-> IO PortNumber
socketPort sock@(MkSocket _ AF_INET _ _ _) = do
(SockAddrInet port _) <- getSocketName sock
return port
{-# LINE 757 "Network/Socket.hsc" #-}
socketPort sock@(MkSocket _ AF_INET6 _ _ _) = do
(SockAddrInet6 port _ _ _) <- getSocketName sock
return port
{-# LINE 761 "Network/Socket.hsc" #-}
socketPort (MkSocket _ family _ _ _) =
ioError (userError ("socketPort: not supported for Family " ++ show family))
getPeerName :: Socket -> IO SockAddr
getPeerName (MkSocket s family _ _ _) = do
withNewSockAddr family $ \ptr sz -> do
with (fromIntegral sz) $ \int_star -> do
throwSocketErrorIfMinus1Retry_ "getPeerName" $ c_getpeername s ptr int_star
_sz <- peek int_star
peekSockAddr ptr
getSocketName :: Socket -> IO SockAddr
getSocketName (MkSocket s family _ _ _) = do
withNewSockAddr family $ \ptr sz -> do
with (fromIntegral sz) $ \int_star -> do
throwSocketErrorIfMinus1Retry_ "getSocketName" $ c_getsockname s ptr int_star
peekSockAddr ptr
data SocketOption
= Debug
| ReuseAddr
| Type
| SoError
| DontRoute
| Broadcast
| SendBuffer
| RecvBuffer
| KeepAlive
| OOBInline
| TimeToLive
| MaxSegment
| NoDelay
| Cork
| Linger
| ReusePort
| RecvLowWater
| SendLowWater
| RecvTimeOut
| SendTimeOut
| UseLoopBack
| UserTimeout
| IPv6Only
| CustomSockOpt (CInt, CInt)
deriving (Show, Typeable)
isSupportedSocketOption :: SocketOption -> Bool
isSupportedSocketOption = isJust . packSocketOption
packSocketOption :: SocketOption -> Maybe (CInt, CInt)
packSocketOption so =
case Just so of
{-# LINE 844 "Network/Socket.hsc" #-}
{-# LINE 845 "Network/Socket.hsc" #-}
Just Debug -> Just ((1), (1))
{-# LINE 846 "Network/Socket.hsc" #-}
{-# LINE 847 "Network/Socket.hsc" #-}
{-# LINE 848 "Network/Socket.hsc" #-}
Just ReuseAddr -> Just ((1), (2))
{-# LINE 849 "Network/Socket.hsc" #-}
{-# LINE 850 "Network/Socket.hsc" #-}
{-# LINE 851 "Network/Socket.hsc" #-}
Just Type -> Just ((1), (3))
{-# LINE 852 "Network/Socket.hsc" #-}
{-# LINE 853 "Network/Socket.hsc" #-}
{-# LINE 854 "Network/Socket.hsc" #-}
Just SoError -> Just ((1), (4))
{-# LINE 855 "Network/Socket.hsc" #-}
{-# LINE 856 "Network/Socket.hsc" #-}
{-# LINE 857 "Network/Socket.hsc" #-}
Just DontRoute -> Just ((1), (5))
{-# LINE 858 "Network/Socket.hsc" #-}
{-# LINE 859 "Network/Socket.hsc" #-}
{-# LINE 860 "Network/Socket.hsc" #-}
Just Broadcast -> Just ((1), (6))
{-# LINE 861 "Network/Socket.hsc" #-}
{-# LINE 862 "Network/Socket.hsc" #-}
{-# LINE 863 "Network/Socket.hsc" #-}
Just SendBuffer -> Just ((1), (7))
{-# LINE 864 "Network/Socket.hsc" #-}
{-# LINE 865 "Network/Socket.hsc" #-}
{-# LINE 866 "Network/Socket.hsc" #-}
Just RecvBuffer -> Just ((1), (8))
{-# LINE 867 "Network/Socket.hsc" #-}
{-# LINE 868 "Network/Socket.hsc" #-}
{-# LINE 869 "Network/Socket.hsc" #-}
Just KeepAlive -> Just ((1), (9))
{-# LINE 870 "Network/Socket.hsc" #-}
{-# LINE 871 "Network/Socket.hsc" #-}
{-# LINE 872 "Network/Socket.hsc" #-}
Just OOBInline -> Just ((1), (10))
{-# LINE 873 "Network/Socket.hsc" #-}
{-# LINE 874 "Network/Socket.hsc" #-}
{-# LINE 875 "Network/Socket.hsc" #-}
Just Linger -> Just ((1), (13))
{-# LINE 876 "Network/Socket.hsc" #-}
{-# LINE 877 "Network/Socket.hsc" #-}
{-# LINE 880 "Network/Socket.hsc" #-}
{-# LINE 881 "Network/Socket.hsc" #-}
Just RecvLowWater -> Just ((1), (18))
{-# LINE 882 "Network/Socket.hsc" #-}
{-# LINE 883 "Network/Socket.hsc" #-}
{-# LINE 884 "Network/Socket.hsc" #-}
Just SendLowWater -> Just ((1), (19))
{-# LINE 885 "Network/Socket.hsc" #-}
{-# LINE 886 "Network/Socket.hsc" #-}
{-# LINE 887 "Network/Socket.hsc" #-}
Just RecvTimeOut -> Just ((1), (20))
{-# LINE 888 "Network/Socket.hsc" #-}
{-# LINE 889 "Network/Socket.hsc" #-}
{-# LINE 890 "Network/Socket.hsc" #-}
Just SendTimeOut -> Just ((1), (21))
{-# LINE 891 "Network/Socket.hsc" #-}
{-# LINE 892 "Network/Socket.hsc" #-}
{-# LINE 895 "Network/Socket.hsc" #-}
{-# LINE 896 "Network/Socket.hsc" #-}
{-# LINE 897 "Network/Socket.hsc" #-}
{-# LINE 898 "Network/Socket.hsc" #-}
Just TimeToLive -> Just ((0), (2))
{-# LINE 899 "Network/Socket.hsc" #-}
{-# LINE 900 "Network/Socket.hsc" #-}
{-# LINE 901 "Network/Socket.hsc" #-}
{-# LINE 902 "Network/Socket.hsc" #-}
{-# LINE 903 "Network/Socket.hsc" #-}
Just MaxSegment -> Just ((6), (2))
{-# LINE 904 "Network/Socket.hsc" #-}
{-# LINE 905 "Network/Socket.hsc" #-}
{-# LINE 906 "Network/Socket.hsc" #-}
Just NoDelay -> Just ((6), (1))
{-# LINE 907 "Network/Socket.hsc" #-}
{-# LINE 908 "Network/Socket.hsc" #-}
{-# LINE 909 "Network/Socket.hsc" #-}
Just UserTimeout -> Just ((6), (18))
{-# LINE 910 "Network/Socket.hsc" #-}
{-# LINE 911 "Network/Socket.hsc" #-}
{-# LINE 912 "Network/Socket.hsc" #-}
Just Cork -> Just ((6), (3))
{-# LINE 913 "Network/Socket.hsc" #-}
{-# LINE 914 "Network/Socket.hsc" #-}
{-# LINE 915 "Network/Socket.hsc" #-}
{-# LINE 916 "Network/Socket.hsc" #-}
{-# LINE 917 "Network/Socket.hsc" #-}
Just IPv6Only -> Just ((41), (26))
{-# LINE 918 "Network/Socket.hsc" #-}
{-# LINE 919 "Network/Socket.hsc" #-}
{-# LINE 920 "Network/Socket.hsc" #-}
Just (CustomSockOpt opt) -> Just opt
_ -> Nothing
packSocketOption' :: String -> SocketOption -> IO (CInt, CInt)
packSocketOption' caller so = maybe err return (packSocketOption so)
where
err = ioError . userError . concat $ ["Network.Socket.", caller,
": socket option ", show so, " unsupported on this system"]
setSocketOption :: Socket
-> SocketOption
-> Int
-> IO ()
setSocketOption (MkSocket s _ _ _ _) so v = do
(level, opt) <- packSocketOption' "setSocketOption" so
with (fromIntegral v) $ \ptr_v -> do
throwSocketErrorIfMinus1_ "setSocketOption" $
c_setsockopt s level opt ptr_v
(fromIntegral (sizeOf (undefined :: CInt)))
return ()
getSocketOption :: Socket
-> SocketOption
-> IO Int
getSocketOption (MkSocket s _ _ _ _) so = do
(level, opt) <- packSocketOption' "getSocketOption" so
alloca $ \ptr_v ->
with (fromIntegral (sizeOf (undefined :: CInt))) $ \ptr_sz -> do
throwSocketErrorIfMinus1Retry_ "getSocketOption" $
c_getsockopt s level opt ptr_v ptr_sz
fromIntegral `liftM` peek ptr_v
{-# LINE 962 "Network/Socket.hsc" #-}
getPeerCred :: Socket -> IO (CUInt, CUInt, CUInt)
getPeerCred sock = do
{-# LINE 970 "Network/Socket.hsc" #-}
let fd = fdSocket sock
let sz = (12)
{-# LINE 972 "Network/Socket.hsc" #-}
allocaBytes sz $ \ ptr_cr ->
with (fromIntegral sz) $ \ ptr_sz -> do
_ <- ($) throwSocketErrorIfMinus1Retry "getPeerCred" $
c_getsockopt fd (1) (17) ptr_cr ptr_sz
{-# LINE 976 "Network/Socket.hsc" #-}
pid <- ((\hsc_ptr -> peekByteOff hsc_ptr 0)) ptr_cr
{-# LINE 977 "Network/Socket.hsc" #-}
uid <- ((\hsc_ptr -> peekByteOff hsc_ptr 4)) ptr_cr
{-# LINE 978 "Network/Socket.hsc" #-}
gid <- ((\hsc_ptr -> peekByteOff hsc_ptr 8)) ptr_cr
{-# LINE 979 "Network/Socket.hsc" #-}
return (pid, uid, gid)
{-# LINE 984 "Network/Socket.hsc" #-}
{-# LINE 999 "Network/Socket.hsc" #-}
{-# LINE 1000 "Network/Socket.hsc" #-}
#if !(MIN_VERSION_base(4,3,1))
closeFdWith closer fd = closer fd
#endif
{-# LINE 1006 "Network/Socket.hsc" #-}
sendFd :: Socket -> CInt -> IO ()
sendFd sock outfd = do
_ <- ($) throwSocketErrorWaitWrite sock "sendFd" $
c_sendFd (fdSocket sock) outfd
closeFd outfd
recvFd :: Socket -> IO CInt
recvFd sock = do
theFd <- throwSocketErrorWaitRead sock "recvFd" $
c_recvFd (fdSocket sock)
return theFd
foreign import ccall SAFE_ON_WIN "sendFd" c_sendFd :: CInt -> CInt -> IO CInt
foreign import ccall SAFE_ON_WIN "recvFd" c_recvFd :: CInt -> IO CInt
{-# LINE 1026 "Network/Socket.hsc" #-}
aNY_PORT :: PortNumber
aNY_PORT = 0
iNADDR_ANY :: HostAddress
iNADDR_ANY = htonl (0)
{-# LINE 1037 "Network/Socket.hsc" #-}
foreign import CALLCONV unsafe "htonl" htonl :: Word32 -> Word32
foreign import CALLCONV unsafe "ntohl" ntohl :: Word32 -> Word32
{-# LINE 1044 "Network/Socket.hsc" #-}
iN6ADDR_ANY :: HostAddress6
iN6ADDR_ANY = (0, 0, 0, 0)
{-# LINE 1049 "Network/Socket.hsc" #-}
sOMAXCONN :: Int
sOMAXCONN = 128
{-# LINE 1052 "Network/Socket.hsc" #-}
sOL_SOCKET :: Int
sOL_SOCKET = 1
{-# LINE 1055 "Network/Socket.hsc" #-}
{-# LINE 1057 "Network/Socket.hsc" #-}
sCM_RIGHTS :: Int
sCM_RIGHTS = 1
{-# LINE 1059 "Network/Socket.hsc" #-}
{-# LINE 1060 "Network/Socket.hsc" #-}
maxListenQueue :: Int
maxListenQueue = sOMAXCONN
data ShutdownCmd
= ShutdownReceive
| ShutdownSend
| ShutdownBoth
deriving Typeable
sdownCmdToInt :: ShutdownCmd -> CInt
sdownCmdToInt ShutdownReceive = 0
sdownCmdToInt ShutdownSend = 1
sdownCmdToInt ShutdownBoth = 2
shutdown :: Socket -> ShutdownCmd -> IO ()
shutdown (MkSocket s _ _ _ _) stype = do
throwSocketErrorIfMinus1Retry_ "shutdown" (c_shutdown s (sdownCmdToInt stype))
return ()
close :: Socket -> IO ()
close (MkSocket s _ _ _ socketStatus) = do
modifyMVar_ socketStatus $ \ status ->
case status of
ConvertedToHandle ->
ioError (userError ("close: converted to a Handle, use hClose instead"))
Closed ->
return status
_ -> closeFdWith (closeFd . fromIntegral) (fromIntegral s) >> return Closed
isConnected :: Socket -> IO Bool
isConnected (MkSocket _ _ _ _ status) = do
value <- readMVar status
return (value == Connected)
isBound :: Socket -> IO Bool
isBound (MkSocket _ _ _ _ status) = do
value <- readMVar status
return (value == Bound)
isListening :: Socket -> IO Bool
isListening (MkSocket _ _ _ _ status) = do
value <- readMVar status
return (value == Listening)
isReadable :: Socket -> IO Bool
isReadable (MkSocket _ _ _ _ status) = do
value <- readMVar status
return (value == Listening || value == Connected)
isWritable :: Socket -> IO Bool
isWritable = isReadable
isAcceptable :: Socket -> IO Bool
{-# LINE 1138 "Network/Socket.hsc" #-}
isAcceptable (MkSocket _ AF_UNIX x _ status)
| x == Stream || x == SeqPacket = do
value <- readMVar status
return (value == Connected || value == Bound || value == Listening)
isAcceptable (MkSocket _ AF_UNIX _ _ _) = return False
{-# LINE 1144 "Network/Socket.hsc" #-}
isAcceptable (MkSocket _ _ _ _ status) = do
value <- readMVar status
return (value == Connected || value == Listening)
inet_addr :: String -> IO HostAddress
inet_addr ipstr = withSocketsDo $ do
withCString ipstr $ \str -> do
had <- c_inet_addr str
if had == -1
then ioError (userError ("inet_addr: Malformed address: " ++ ipstr))
else return had
inet_ntoa :: HostAddress -> IO String
inet_ntoa haddr = withSocketsDo $ do
pstr <- c_inet_ntoa haddr
peekCString pstr
socketToHandle :: Socket -> IOMode -> IO Handle
socketToHandle s@(MkSocket fd _ _ _ socketStatus) mode = do
modifyMVar socketStatus $ \ status ->
if status == ConvertedToHandle
then ioError (userError ("socketToHandle: already a Handle"))
else do
h <- fdToHandle' (fromIntegral fd) (Just GHC.IO.Device.Stream) True (show s) mode True
hSetBuffering h NoBuffering
return (ConvertedToHandle, h)
packBits :: (Eq a, Num b, Bits b) => [(a, b)] -> [a] -> b
packBits mapping xs = foldl' pack 0 mapping
where pack acc (k, v) | k `elem` xs = acc .|. v
| otherwise = acc
unpackBits :: (Num b, Bits b) => [(a, b)] -> b -> [a]
unpackBits [] _ = []
unpackBits ((k,v):xs) r
| r .&. v /= 0 = k : unpackBits xs (r .&. complement v)
| otherwise = unpackBits xs r
{-# LINE 1210 "Network/Socket.hsc" #-}
data AddrInfoFlag =
AI_ADDRCONFIG
| AI_ALL
| AI_CANONNAME
| AI_NUMERICHOST
| AI_NUMERICSERV
| AI_PASSIVE
| AI_V4MAPPED
deriving (Eq, Read, Show, Typeable)
aiFlagMapping :: [(AddrInfoFlag, CInt)]
aiFlagMapping =
[
{-# LINE 1251 "Network/Socket.hsc" #-}
(AI_ADDRCONFIG, 32),
{-# LINE 1252 "Network/Socket.hsc" #-}
{-# LINE 1255 "Network/Socket.hsc" #-}
{-# LINE 1256 "Network/Socket.hsc" #-}
(AI_ALL, 16),
{-# LINE 1257 "Network/Socket.hsc" #-}
{-# LINE 1260 "Network/Socket.hsc" #-}
(AI_CANONNAME, 2),
{-# LINE 1261 "Network/Socket.hsc" #-}
(AI_NUMERICHOST, 4),
{-# LINE 1262 "Network/Socket.hsc" #-}
{-# LINE 1263 "Network/Socket.hsc" #-}
(AI_NUMERICSERV, 1024),
{-# LINE 1264 "Network/Socket.hsc" #-}
{-# LINE 1267 "Network/Socket.hsc" #-}
(AI_PASSIVE, 1),
{-# LINE 1268 "Network/Socket.hsc" #-}
{-# LINE 1269 "Network/Socket.hsc" #-}
(AI_V4MAPPED, 8)
{-# LINE 1270 "Network/Socket.hsc" #-}
{-# LINE 1273 "Network/Socket.hsc" #-}
]
addrInfoFlagImplemented :: AddrInfoFlag -> Bool
addrInfoFlagImplemented f = packBits aiFlagMapping [f] /= 0
data AddrInfo =
AddrInfo {
addrFlags :: [AddrInfoFlag],
addrFamily :: Family,
addrSocketType :: SocketType,
addrProtocol :: ProtocolNumber,
addrAddress :: SockAddr,
addrCanonName :: Maybe String
}
deriving (Eq, Show, Typeable)
instance Storable AddrInfo where
sizeOf _ = 48
{-# LINE 1293 "Network/Socket.hsc" #-}
alignment _ = alignment (undefined :: CInt)
peek p = do
ai_flags <- ((\hsc_ptr -> peekByteOff hsc_ptr 0)) p
{-# LINE 1297 "Network/Socket.hsc" #-}
ai_family <- ((\hsc_ptr -> peekByteOff hsc_ptr 4)) p
{-# LINE 1298 "Network/Socket.hsc" #-}
ai_socktype <- ((\hsc_ptr -> peekByteOff hsc_ptr 8)) p
{-# LINE 1299 "Network/Socket.hsc" #-}
ai_protocol <- ((\hsc_ptr -> peekByteOff hsc_ptr 12)) p
{-# LINE 1300 "Network/Socket.hsc" #-}
ai_addr <- ((\hsc_ptr -> peekByteOff hsc_ptr 24)) p >>= peekSockAddr
{-# LINE 1301 "Network/Socket.hsc" #-}
ai_canonname_ptr <- ((\hsc_ptr -> peekByteOff hsc_ptr 32)) p
{-# LINE 1302 "Network/Socket.hsc" #-}
ai_canonname <- if ai_canonname_ptr == nullPtr
then return Nothing
else liftM Just $ peekCString ai_canonname_ptr
socktype <- unpackSocketType' "AddrInfo.peek" ai_socktype
return (AddrInfo
{
addrFlags = unpackBits aiFlagMapping ai_flags,
addrFamily = unpackFamily ai_family,
addrSocketType = socktype,
addrProtocol = ai_protocol,
addrAddress = ai_addr,
addrCanonName = ai_canonname
})
poke p (AddrInfo flags family socketType protocol _ _) = do
c_stype <- packSocketTypeOrThrow "AddrInfo.poke" socketType
((\hsc_ptr -> pokeByteOff hsc_ptr 0)) p (packBits aiFlagMapping flags)
{-# LINE 1322 "Network/Socket.hsc" #-}
((\hsc_ptr -> pokeByteOff hsc_ptr 4)) p (packFamily family)
{-# LINE 1323 "Network/Socket.hsc" #-}
((\hsc_ptr -> pokeByteOff hsc_ptr 8)) p c_stype
{-# LINE 1324 "Network/Socket.hsc" #-}
((\hsc_ptr -> pokeByteOff hsc_ptr 12)) p protocol
{-# LINE 1325 "Network/Socket.hsc" #-}
((\hsc_ptr -> pokeByteOff hsc_ptr 16)) p (0::CSize)
{-# LINE 1329 "Network/Socket.hsc" #-}
((\hsc_ptr -> pokeByteOff hsc_ptr 24)) p nullPtr
{-# LINE 1330 "Network/Socket.hsc" #-}
((\hsc_ptr -> pokeByteOff hsc_ptr 32)) p nullPtr
{-# LINE 1331 "Network/Socket.hsc" #-}
((\hsc_ptr -> pokeByteOff hsc_ptr 40)) p nullPtr
{-# LINE 1332 "Network/Socket.hsc" #-}
data NameInfoFlag =
NI_DGRAM
| NI_NAMEREQD
| NI_NOFQDN
| NI_NUMERICHOST
| NI_NUMERICSERV
deriving (Eq, Read, Show, Typeable)
niFlagMapping :: [(NameInfoFlag, CInt)]
niFlagMapping = [(NI_DGRAM, 16),
{-# LINE 1360 "Network/Socket.hsc" #-}
(NI_NAMEREQD, 8),
{-# LINE 1361 "Network/Socket.hsc" #-}
(NI_NOFQDN, 4),
{-# LINE 1362 "Network/Socket.hsc" #-}
(NI_NUMERICHOST, 1),
{-# LINE 1363 "Network/Socket.hsc" #-}
(NI_NUMERICSERV, 2)]
{-# LINE 1364 "Network/Socket.hsc" #-}
defaultHints :: AddrInfo
defaultHints = AddrInfo {
addrFlags = [],
addrFamily = AF_UNSPEC,
addrSocketType = NoSocketType,
addrProtocol = defaultProtocol,
addrAddress = undefined,
addrCanonName = undefined
}
getAddrInfo :: Maybe AddrInfo
-> Maybe HostName
-> Maybe ServiceName
-> IO [AddrInfo]
getAddrInfo hints node service = withSocketsDo $
maybeWith withCString node $ \c_node ->
maybeWith withCString service $ \c_service ->
maybeWith with filteredHints $ \c_hints ->
alloca $ \ptr_ptr_addrs -> do
ret <- c_getaddrinfo c_node c_service c_hints ptr_ptr_addrs
case ret of
0 -> do ptr_addrs <- peek ptr_ptr_addrs
ais <- followAddrInfo ptr_addrs
c_freeaddrinfo ptr_addrs
return ais
_ -> do err <- gai_strerror ret
ioError (ioeSetErrorString
(mkIOError NoSuchThing "getAddrInfo" Nothing
Nothing) err)
where
{-# LINE 1457 "Network/Socket.hsc" #-}
filteredHints = hints
{-# LINE 1459 "Network/Socket.hsc" #-}
followAddrInfo :: Ptr AddrInfo -> IO [AddrInfo]
followAddrInfo ptr_ai | ptr_ai == nullPtr = return []
| otherwise = do
a <- peek ptr_ai
as <- ((\hsc_ptr -> peekByteOff hsc_ptr 40)) ptr_ai >>= followAddrInfo
{-# LINE 1466 "Network/Socket.hsc" #-}
return (a:as)
foreign import ccall safe "hsnet_getaddrinfo"
c_getaddrinfo :: CString -> CString -> Ptr AddrInfo -> Ptr (Ptr AddrInfo)
-> IO CInt
foreign import ccall safe "hsnet_freeaddrinfo"
c_freeaddrinfo :: Ptr AddrInfo -> IO ()
gai_strerror :: CInt -> IO String
{-# LINE 1478 "Network/Socket.hsc" #-}
gai_strerror n = c_gai_strerror n >>= peekCString
foreign import ccall safe "gai_strerror"
c_gai_strerror :: CInt -> IO CString
{-# LINE 1485 "Network/Socket.hsc" #-}
withCStringIf :: Bool -> Int -> (CSize -> CString -> IO a) -> IO a
withCStringIf False _ f = f 0 nullPtr
withCStringIf True n f = allocaBytes n (f (fromIntegral n))
getNameInfo :: [NameInfoFlag]
-> Bool
-> Bool
-> SockAddr
-> IO (Maybe HostName, Maybe ServiceName)
getNameInfo flags doHost doService addr = withSocketsDo $
withCStringIf doHost (1025) $ \c_hostlen c_host ->
{-# LINE 1512 "Network/Socket.hsc" #-}
withCStringIf doService (32) $ \c_servlen c_serv -> do
{-# LINE 1513 "Network/Socket.hsc" #-}
withSockAddr addr $ \ptr_addr sz -> do
ret <- c_getnameinfo ptr_addr (fromIntegral sz) c_host c_hostlen
c_serv c_servlen (packBits niFlagMapping flags)
case ret of
0 -> do
let peekIf doIf c_val = if doIf
then liftM Just $ peekCString c_val
else return Nothing
host <- peekIf doHost c_host
serv <- peekIf doService c_serv
return (host, serv)
_ -> do err <- gai_strerror ret
ioError (ioeSetErrorString
(mkIOError NoSuchThing "getNameInfo" Nothing
Nothing) err)
foreign import ccall safe "hsnet_getnameinfo"
c_getnameinfo :: Ptr SockAddr -> CInt -> CString -> CSize -> CString
-> CSize -> CInt -> IO CInt
{-# LINE 1533 "Network/Socket.hsc" #-}
mkInvalidRecvArgError :: String -> IOError
mkInvalidRecvArgError loc = ioeSetErrorString (mkIOError
InvalidArgument
loc Nothing Nothing) "non-positive length"
mkEOFError :: String -> IOError
mkEOFError loc = ioeSetErrorString (mkIOError EOF loc Nothing Nothing) "end of file"
foreign import ccall unsafe "my_inet_ntoa"
c_inet_ntoa :: HostAddress -> IO (Ptr CChar)
foreign import CALLCONV unsafe "inet_addr"
c_inet_addr :: Ptr CChar -> IO HostAddress
foreign import CALLCONV unsafe "shutdown"
c_shutdown :: CInt -> CInt -> IO CInt
closeFd :: CInt -> IO ()
closeFd fd = throwSocketErrorIfMinus1_ "Network.Socket.close" $ c_close fd
{-# LINE 1558 "Network/Socket.hsc" #-}
foreign import ccall unsafe "close"
c_close :: CInt -> IO CInt
{-# LINE 1564 "Network/Socket.hsc" #-}
foreign import CALLCONV unsafe "socket"
c_socket :: CInt -> CInt -> CInt -> IO CInt
foreign import CALLCONV unsafe "bind"
c_bind :: CInt -> Ptr SockAddr -> CInt -> IO CInt
foreign import CALLCONV SAFE_ON_WIN "connect"
c_connect :: CInt -> Ptr SockAddr -> CInt -> IO CInt
{-# LINE 1572 "Network/Socket.hsc" #-}
foreign import CALLCONV unsafe "accept4"
c_accept4 :: CInt -> Ptr SockAddr -> Ptr CInt -> CInt -> IO CInt
{-# LINE 1578 "Network/Socket.hsc" #-}
foreign import CALLCONV unsafe "listen"
c_listen :: CInt -> CInt -> IO CInt
{-# LINE 1587 "Network/Socket.hsc" #-}
foreign import CALLCONV unsafe "send"
c_send :: CInt -> Ptr a -> CSize -> CInt -> IO CInt
foreign import CALLCONV SAFE_ON_WIN "sendto"
c_sendto :: CInt -> Ptr a -> CSize -> CInt -> Ptr SockAddr -> CInt -> IO CInt
foreign import CALLCONV unsafe "recv"
c_recv :: CInt -> Ptr CChar -> CSize -> CInt -> IO CInt
foreign import CALLCONV SAFE_ON_WIN "recvfrom"
c_recvfrom :: CInt -> Ptr a -> CSize -> CInt -> Ptr SockAddr -> Ptr CInt -> IO CInt
foreign import CALLCONV unsafe "getpeername"
c_getpeername :: CInt -> Ptr SockAddr -> Ptr CInt -> IO CInt
foreign import CALLCONV unsafe "getsockname"
c_getsockname :: CInt -> Ptr SockAddr -> Ptr CInt -> IO CInt
foreign import CALLCONV unsafe "getsockopt"
c_getsockopt :: CInt -> CInt -> CInt -> Ptr CInt -> Ptr CInt -> IO CInt
foreign import CALLCONV unsafe "setsockopt"
c_setsockopt :: CInt -> CInt -> CInt -> Ptr CInt -> CInt -> IO CInt
{-# LINE 1610 "Network/Socket.hsc" #-}
{-# DEPRECATED bindSocket "use 'bind'" #-}
bindSocket :: Socket
-> SockAddr
-> IO ()
bindSocket = bind
{-# DEPRECATED sClose "use 'close'" #-}
sClose :: Socket -> IO ()
sClose = close
{-# DEPRECATED sIsConnected "use 'isConnected'" #-}
sIsConnected :: Socket -> IO Bool
sIsConnected = isConnected
{-# DEPRECATED sIsBound "use 'isBound'" #-}
sIsBound :: Socket -> IO Bool
sIsBound = isBound
{-# DEPRECATED sIsListening "use 'isListening'" #-}
sIsListening :: Socket -> IO Bool
sIsListening = isListening
{-# DEPRECATED sIsReadable "use 'isReadable'" #-}
sIsReadable :: Socket -> IO Bool
sIsReadable = isReadable
{-# DEPRECATED sIsWritable "use 'isWritable'" #-}
sIsWritable :: Socket -> IO Bool
sIsWritable = isWritable