module System.Posix.Socket
( Socket
, withSocketFd
, unsafeSocketFd
, unsafeSocketFromFd
, SockFamily(..)
, SockAddr(..)
, SockType(..)
, streamSockType
, datagramSockType
, rawSockType
, seqPacketSockType
, SockProto(..)
, defaultSockProto
, SockOpt(..)
, SO_ERROR(..)
, SO_KEEPALIVE(..)
, SO_REUSEADDR(..)
, SockOps
, sendSockOp
, recvSockOp
, MsgFlags
, peekMsgFlag
, truncMsgFlag
, oobMsgFlag
, dontRouteMsgFlag
, socket
, getSockOpt
, setSockOpt
, bind
, connect
, tryConnect
, listen
, accept
, getLocalAddr
, getRemoteAddr
, hasOobData
, recvBufs
, recvBuf
, recv'
, recv
, recvBufsFrom
, recvBufFrom
, recvFrom'
, recvFrom
, sendBufs
, sendMany'
, sendMany
, sendBuf
, send'
, send
, sendBufsTo
, sendManyTo'
, sendManyTo
, sendBufTo
, sendTo'
, sendTo
, shutdown
, close
) where
import Data.Typeable (Typeable)
import Data.Proxy (Proxy(..))
import Data.Word
import Data.Bits ((.|.))
import Data.Default.Class
import Data.List (partition)
import Data.ByteString (ByteString)
import qualified Data.ByteString.Internal as BS
import qualified Data.ByteString.Unsafe as BS
import Data.Flags (Flags(..), (.>=.))
import Data.Flags.TH (bitmaskWrapper)
import Data.Foldable (forM_)
import Control.Applicative ((<$>))
import Control.Monad (void, when, foldM)
import Control.Monad.Base
import Control.Exception (throwIO)
import Control.Concurrent (threadWaitRead, threadWaitWrite)
import Control.Concurrent.MVar
import Foreign.Storable (Storable(..))
import Foreign.Ptr (Ptr, castPtr, nullPtr, plusPtr)
import Foreign.Marshal.Alloc (alloca, allocaBytesAligned)
import Foreign.Marshal.Utils (with)
import Foreign.C.Types (CInt(..), CSize(..))
import System.Posix.Types (CSsize(..))
import Foreign.C.Error (Errno(..), eOK, eINVAL, eMSGSIZE, eINPROGRESS, eAGAIN,
eWOULDBLOCK, getErrno, errnoToIOError,
throwErrno, throwErrnoIfMinus1, throwErrnoIfMinus1_)
import System.IO.Error (eofErrorType, mkIOError)
import System.Posix.Types (Fd(..))
import System.Posix.IO (closeFd)
import GHC.Conc (closeFdWith)
newtype Socket f = Socket (MVar Fd) deriving (Typeable, Eq)
withSocketFd ∷ MonadBase IO μ ⇒ Socket f → (Fd → IO α) → μ α
withSocketFd (Socket v) f = liftBase $ withMVar v f
unsafeSocketFd ∷ MonadBase IO μ ⇒ Socket f → μ Fd
unsafeSocketFd (Socket v) = liftBase $ readMVar v
unsafeSocketFromFd ∷ MonadBase IO μ ⇒ Fd → μ (Socket f)
unsafeSocketFromFd = liftBase . fmap Socket . newMVar
class SockAddr a where
sockAddrMaxSize ∷ Proxy a → Int
sockAddrSize ∷ a → Int
peekSockAddr ∷ Ptr a
→ Int
→ IO a
pokeSockAddr ∷ Ptr a
→ a
→ IO ()
class SockAddr (SockFamilyAddr f) ⇒ SockFamily f where
type SockFamilyAddr f
sockFamilyCode ∷ f → CInt
newtype SockType = SockType CInt deriving (Typeable, Eq, Ord, Show, Storable)
streamSockType ∷ SockType
streamSockType = SockType 1
datagramSockType ∷ SockType
datagramSockType = SockType 2
rawSockType ∷ SockType
rawSockType = SockType 3
seqPacketSockType ∷ SockType
seqPacketSockType = SockType 5
newtype SockProto = SockProto CInt deriving (Typeable, Eq, Ord, Show, Storable)
defaultSockProto ∷ SockProto
defaultSockProto = SockProto 0
instance Default SockProto where
def = defaultSockProto
class Storable (SockOptRaw o) ⇒ SockOpt o where
type SockOptValue o
type SockOptRaw o
type SockOptReadable o ∷ Bool
type SockOptWritable o ∷ Bool
sockOptRaw ∷ o → SockOptValue o → SockOptRaw o
sockOptValue ∷ o → SockOptRaw o → SockOptValue o
sockOptLevel ∷ o → CInt
sockOptCode ∷ o → CInt
data SO_ERROR = SO_ERROR deriving (Typeable, Eq, Show)
instance SockOpt SO_ERROR where
type SockOptValue SO_ERROR = Errno
type SockOptRaw SO_ERROR = CInt
type SockOptReadable SO_ERROR = 'True
type SockOptWritable SO_ERROR = 'False
sockOptRaw _ (Errno e) = e
sockOptValue _ = Errno
sockOptLevel _ = 1
sockOptCode _ = 4
data SO_KEEPALIVE = SO_KEEPALIVE deriving (Typeable, Eq, Show)
instance SockOpt SO_KEEPALIVE where
type SockOptValue SO_KEEPALIVE = Bool
type SockOptRaw SO_KEEPALIVE = CInt
type SockOptReadable SO_KEEPALIVE = 'True
type SockOptWritable SO_KEEPALIVE = 'True
sockOptRaw _ False = 0
sockOptRaw _ True = 1
sockOptValue _ = (/= 0)
sockOptLevel _ = 1
sockOptCode _ = 9
data SO_REUSEADDR = SO_REUSEADDR deriving (Typeable, Eq, Show)
instance SockOpt SO_REUSEADDR where
type SockOptValue SO_REUSEADDR = Bool
type SockOptRaw SO_REUSEADDR = CInt
type SockOptReadable SO_REUSEADDR = 'True
type SockOptWritable SO_REUSEADDR = 'True
sockOptRaw _ False = 0
sockOptRaw _ True = 1
sockOptValue _ = (/= 0)
sockOptLevel _ = 1
sockOptCode _ = 2
$(bitmaskWrapper "SockOps" ''Int []
[("sendSockOp", 1),
("recvSockOp", 2)])
newtype MsgFlags = MsgFlags CInt deriving (Typeable, Eq, Show, Storable, Flags)
peekMsgFlag ∷ MsgFlags
peekMsgFlag = MsgFlags 2
truncMsgFlag ∷ MsgFlags
truncMsgFlag = MsgFlags 32
oobMsgFlag ∷ MsgFlags
oobMsgFlag = MsgFlags 1
dontRouteMsgFlag ∷ MsgFlags
dontRouteMsgFlag = MsgFlags 4
allocaMaxAddr ∷ SockAddr a ⇒ Proxy a → (Ptr a → Word32 → IO α) → IO α
allocaMaxAddr addrProxy f =
allocaBytesAligned size (2) $
(`f` (fromIntegral size))
where size = sockAddrMaxSize addrProxy
allocaAddr ∷ SockAddr a ⇒ a → (Ptr a → Word32 → IO α) → IO α
allocaAddr addr f =
allocaBytesAligned size (2) $
(`f` (fromIntegral size))
where size = sockAddrSize addr
peekAddrOfSize ∷ SockFamily f
⇒ f → Ptr (SockFamilyAddr f) → Ptr Word32
→ IO (SockFamilyAddr f)
peekAddrOfSize fam p pSize = do
outSize ← fromIntegral <$> peek pSize
famCode ∷ Word16 ← (\hsc_ptr -> peekByteOff hsc_ptr 0) p
when (fromIntegral famCode /= sockFamilyCode fam) $
ioError $ userError "Invalid socket address family"
peekSockAddr p outSize
withAddr ∷ SockFamily f
⇒ f
→ SockFamilyAddr f
→ (Ptr (SockFamilyAddr f) → Word32 → IO α)
→ IO α
withAddr fam addr f =
allocaAddr addr $ \p size → do
pokeSockAddr p addr
(\hsc_ptr -> pokeByteOff hsc_ptr 0) p famCode
f p size
where famCode ∷ Word16
famCode = fromIntegral $ sockFamilyCode fam
socket ∷ (SockFamily f, MonadBase IO μ)
⇒ f → SockType → SockProto → μ (Socket f)
socket f (SockType t) p = liftBase $ do
fd ← throwErrnoIfMinus1 "socket" $
c_socket (sockFamilyCode f)
(t .|. 2048) p
fmap Socket $ newMVar $ Fd fd
getFdOpt ∷ ∀ o . (SockOpt o, SockOptReadable o ~ 'True)
⇒ Fd → o → IO (SockOptValue o)
getFdOpt fd o =
alloca $ \p →
with (fromIntegral $ sizeOf (undefined ∷ SockOptRaw o)) $ \pSize → do
throwErrnoIfMinus1_ "getSockOpt" $
c_getsockopt fd (sockOptLevel o) (sockOptCode o) p pSize
sockOptValue o <$> peek p
getSockOpt ∷ (SockOpt o, SockOptReadable o ~ 'True, MonadBase IO μ)
⇒ Socket f → o → μ (SockOptValue o)
getSockOpt s o = withSocketFd s $ \fd → getFdOpt fd o
setSockOpt ∷ (SockOpt o, SockOptWritable o ~ 'True, MonadBase IO μ)
⇒ Socket f → o → SockOptValue o → μ ()
setSockOpt s o v = withSocketFd s $ \fd →
with raw $ \p →
throwErrnoIfMinus1_ "setSockOpt" $
c_setsockopt fd (sockOptLevel o) (sockOptCode o) p $
fromIntegral (sizeOf raw)
where raw = sockOptRaw o v
bind ∷ ∀ f μ . (SockFamily f, MonadBase IO μ)
⇒ Socket f → SockFamilyAddr f → μ ()
bind s addr = withSocketFd s $ \fd →
withAddr (undefined ∷ f) addr $ \p size →
throwErrnoIfMinus1_ "bind" $ c_bind fd p $ fromIntegral size
connect ∷ ∀ f μ . (SockFamily f, MonadBase IO μ)
⇒ Socket f → SockFamilyAddr f → μ ()
connect s addr = withSocketFd s $ \fd →
withAddr (undefined ∷ f) addr $ \p size →
doConnect fd p $ fromIntegral size
where doConnect fd p size = do
r ← c_connect fd p size
if r == 1 then do
errno ← getErrno
case errno of
e | e == eINPROGRESS → do
threadWaitWrite fd
errno' ← getFdOpt fd SO_ERROR
when (errno' /= eOK) $
throwIO $ errnoToIOError "connect" errno' Nothing Nothing
_ → throwErrno "connect"
else
return ()
tryConnect ∷ ∀ f μ . (SockFamily f, MonadBase IO μ)
⇒ Socket f → SockFamilyAddr f → μ Bool
tryConnect s addr = withSocketFd s $ \fd →
withAddr (undefined ∷ f) addr $ \p size → do
r ← c_connect fd p $ fromIntegral size
if r == 1
then do
errno ← getErrno
if errno == eINPROGRESS
then return False
else throwErrno "connect"
else
return True
listen ∷ MonadBase IO μ ⇒ Socket f → Int → μ ()
listen s backlog = withSocketFd s $ \fd →
throwErrnoIfMinus1_ "listen" $ c_listen fd $ fromIntegral backlog
accept ∷ ∀ f μ . (SockFamily f, MonadBase IO μ)
⇒ Socket f → μ (Socket f, SockFamilyAddr f)
accept s = withSocketFd s $ \fd →
allocaMaxAddr (Proxy ∷ Proxy (SockFamilyAddr f)) $ \p size →
with size $ \pSize → doAccept fd p pSize
where doAccept fd p pSize = do
cfd ← c_accept fd p pSize
2048
if cfd == 1 then do
errno ← getErrno
case errno of
e | e == eAGAIN || e == eWOULDBLOCK → do
threadWaitRead fd
doAccept fd p pSize
_ → throwErrno "accept"
else do
addr ← peekAddrOfSize (undefined ∷ f) p pSize
(, addr) <$> unsafeSocketFromFd (Fd cfd)
getLocalAddr ∷ ∀ f μ . (SockFamily f, MonadBase IO μ)
⇒ Socket f → μ (SockFamilyAddr f)
getLocalAddr s = withSocketFd s $ \fd →
allocaMaxAddr (Proxy ∷ Proxy (SockFamilyAddr f)) $ \p size →
with size $ \pSize → do
throwErrnoIfMinus1_ "getLocalAddr" $ c_getsockname fd p pSize
peekAddrOfSize (undefined ∷ f) p pSize
getRemoteAddr ∷ ∀ f μ . (SockFamily f, MonadBase IO μ)
⇒ Socket f → μ (SockFamilyAddr f)
getRemoteAddr s = withSocketFd s $ \fd →
allocaMaxAddr (Proxy ∷ Proxy (SockFamilyAddr f)) $ \p size →
with size $ \pSize → do
throwErrnoIfMinus1_ "getRemoteAddr" $ c_getpeername fd p pSize
peekAddrOfSize (undefined ∷ f) p pSize
hasOobData ∷ MonadBase IO μ ⇒ Socket f → μ Bool
hasOobData s = withSocketFd s $ \fd →
fmap (== 1) $ throwErrnoIfMinus1 "hasOOBData" $ c_sockatmark fd
throwCustomErrno ∷ String → Errno → IO α
throwCustomErrno loc errno =
throwIO $ errnoToIOError loc errno Nothing Nothing
throwInval ∷ String → IO α
throwInval loc = throwCustomErrno loc eINVAL
recvBufsFromFd ∷ ∀ f . SockFamily f
⇒ f → Fd → [(Ptr Word8, Int)] → MsgFlags
→ IO (Maybe (SockFamilyAddr f), Int, MsgFlags)
recvBufsFromFd _ fd bufs' flags = do
let (bufs, bufs'') = partition ((> 0) . snd) bufs'
nn = length bufs
when (any ((< 0) . snd) bufs'' || nn == 0) $ throwInval "recv"
when (nn > 1024) $ throwCustomErrno "recv" eMSGSIZE
allocaBytesAligned (56)
(8) $ \pHdr →
allocaMaxAddr (Proxy ∷ Proxy (SockFamilyAddr f)) $ \pAddr addrLen → do
(\hsc_ptr -> pokeByteOff hsc_ptr 0) pHdr pAddr
(\hsc_ptr -> pokeByteOff hsc_ptr 8) pHdr addrLen
let doRecv = do
r ← c_recvmsg fd pHdr flags
case r of
(1) → do
errno ← getErrno
case errno of
e | e == eAGAIN || e == eWOULDBLOCK → do
threadWaitRead fd
doRecv
_ → throwErrno "recv"
0 → throwIO $ mkIOError eofErrorType "recv" Nothing Nothing
_ → do
addrLen' ← (\hsc_ptr -> peekByteOff hsc_ptr 8) pHdr ∷
IO Word32
addr ← if addrLen' == 0
then return Nothing
else fmap Just $ peekSockAddr pAddr $
fromIntegral addrLen'
flags' ← (\hsc_ptr -> peekByteOff hsc_ptr 48) pHdr
return (addr, fromIntegral r, flags')
allocaBytesAligned (nn * (16))
(8) $ \pIoVs → do
void . ($ bufs) . ($ pIoVs) . foldM $ \pIoV (p, n) → do
(\hsc_ptr -> pokeByteOff hsc_ptr 0) pIoV p
(\hsc_ptr -> pokeByteOff hsc_ptr 8) pIoV (fromIntegral n ∷ CSize)
return $ plusPtr pIoV (16)
(\hsc_ptr -> pokeByteOff hsc_ptr 16) pHdr pIoVs
(\hsc_ptr -> pokeByteOff hsc_ptr 24) pHdr (fromIntegral nn ∷ CSize)
(\hsc_ptr -> pokeByteOff hsc_ptr 32) pHdr nullPtr
(\hsc_ptr -> pokeByteOff hsc_ptr 40) pHdr (0 ∷ CSize)
(\hsc_ptr -> pokeByteOff hsc_ptr 48) pHdr (0 ∷ CInt)
doRecv
recvBufsFrom' ∷ ∀ f μ . (SockFamily f, MonadBase IO μ)
⇒ Socket f → [(Ptr Word8, Int)] → MsgFlags
→ μ (Maybe (SockFamilyAddr f), Int, MsgFlags)
recvBufsFrom' s bufs flags = withSocketFd s $ \fd →
recvBufsFromFd (undefined ∷ f) fd bufs flags
recvBufs ∷ (SockFamily f, MonadBase IO μ)
⇒ Socket f
→ [(Ptr Word8, Int)]
→ MsgFlags
→ μ (Int, MsgFlags)
recvBufs s bufs flags = do
(_, r, flags') ← recvBufsFrom' s bufs flags
return (r, flags')
recvBuf ∷ (SockFamily f, MonadBase IO μ)
⇒ Socket f
→ Ptr α
→ Int
→ MsgFlags
→ μ (Int, MsgFlags)
recvBuf s p len flags = recvBufs s [(castPtr p, len)] flags
recv' ∷ (SockFamily f, MonadBase IO μ)
⇒ Socket f
→ Int
→ MsgFlags
→ μ (ByteString, MsgFlags)
recv' s len flags =
liftBase $ BS.createAndTrim' len $ \p → do
(r, flags') ← recvBuf s p len flags
return (0, r, flags')
recv ∷ (SockFamily f, MonadBase IO μ)
⇒ Socket f
→ Int
→ μ ByteString
recv s len = fst <$> recv' s len noFlags
recvBufsFrom ∷ ∀ f μ . (SockFamily f, MonadBase IO μ)
⇒ Socket f
→ [(Ptr Word8, Int)]
→ MsgFlags
→ μ (SockFamilyAddr f, Int, MsgFlags)
recvBufsFrom s bufs flags = withSocketFd s $ \fd → do
(mAddr, n, flags') ← recvBufsFromFd (undefined ∷ f) fd bufs flags
let getpeername =
allocaMaxAddr (Proxy ∷ Proxy (SockFamilyAddr f)) $ \p size →
with size $ \pSize → do
throwErrnoIfMinus1_ "recv" $ c_getpeername fd p pSize
peekAddrOfSize (undefined ∷ f) p pSize
(, n, flags') <$> maybe getpeername return mAddr
recvBufFrom ∷ (SockFamily f, MonadBase IO μ)
⇒ Socket f
→ Ptr α
→ Int
→ MsgFlags
→ μ (SockFamilyAddr f, Int, MsgFlags)
recvBufFrom s p len flags = recvBufsFrom s [(castPtr p, len)] flags
recvFrom' ∷ (SockFamily f, MonadBase IO μ)
⇒ Socket f
→ Int
→ MsgFlags
→ μ (SockFamilyAddr f, ByteString, MsgFlags)
recvFrom' s len flags = liftBase $ do
(bs, (addr, flags')) ← BS.createAndTrim' len $ \p → do
(addr, len', flags') ← recvBufFrom s p len flags
return (0, len', (addr, flags'))
return (addr, bs, flags')
recvFrom ∷ (SockFamily f, MonadBase IO μ)
⇒ Socket f
→ Int
→ μ (SockFamilyAddr f, ByteString)
recvFrom s len = do
(addr, bs, _) ← recvFrom' s len noFlags
return (addr, bs)
_sendBufs ∷ ∀ f μ . (SockFamily f, MonadBase IO μ)
⇒ Socket f → [(Ptr Word8, Int)] → MsgFlags
→ Maybe (SockFamilyAddr f) → μ Int
_sendBufs s bufs' flags mAddr = withSocketFd s $ \fd → do
let (bufs, bufs'') = partition ((> 0) . snd) bufs'
nn = length bufs
when (any ((< 0) . snd) bufs'') $ throwInval "send"
when (nn > 1024) $ throwCustomErrno "send" eMSGSIZE
if nn == 0 then return 0
else allocaBytesAligned (56)
(8) $ \pHdr → do
let doSend = do
r ← c_sendmsg fd pHdr flags
if r == 1 then do
errno ← getErrno
case errno of
e | e == eAGAIN || e == eWOULDBLOCK → do
threadWaitWrite fd
doSend
_ → throwErrno "send"
else
return $ fromIntegral r
let cont = allocaBytesAligned (nn * (16))
(8) $ \pIoVs → do
void . ($ bufs) . ($ pIoVs) . foldM $ \pIoV (p, n) → do
(\hsc_ptr -> pokeByteOff hsc_ptr 0) pIoV p
(\hsc_ptr -> pokeByteOff hsc_ptr 8) pIoV (fromIntegral n ∷ CSize)
return $ plusPtr pIoV (16)
(\hsc_ptr -> pokeByteOff hsc_ptr 16) pHdr pIoVs
(\hsc_ptr -> pokeByteOff hsc_ptr 24) pHdr (fromIntegral nn ∷ CSize)
(\hsc_ptr -> pokeByteOff hsc_ptr 32) pHdr nullPtr
(\hsc_ptr -> pokeByteOff hsc_ptr 40) pHdr (0 ∷ CSize)
(\hsc_ptr -> pokeByteOff hsc_ptr 48) pHdr (0 ∷ CInt)
doSend
case mAddr of
Just addr →
withAddr (undefined ∷ f) addr $ \pAddr addrLen → do
(\hsc_ptr -> pokeByteOff hsc_ptr 0) pHdr pAddr
(\hsc_ptr -> pokeByteOff hsc_ptr 8) pHdr addrLen
cont
Nothing → do
(\hsc_ptr -> pokeByteOff hsc_ptr 0) pHdr nullPtr
(\hsc_ptr -> pokeByteOff hsc_ptr 8) pHdr (0 ∷ Word32)
cont
sendBufs ∷ (SockFamily f, MonadBase IO μ)
⇒ Socket f
→ [(Ptr Word8, Int)]
→ MsgFlags
→ μ Int
sendBufs s bufs flags = _sendBufs s bufs flags Nothing
withBufs ∷ [ByteString] → ([(Ptr Word8, Int)] → IO α) → IO α
withBufs bss f = go bss []
where go [] rbufs = f (reverse rbufs)
go (bs : bss') rbufs = BS.unsafeUseAsCStringLen bs $ \(p, len) →
go bss' ((castPtr p, len) : rbufs)
sendMany' ∷ (SockFamily f, MonadBase IO μ)
⇒ Socket f
→ [ByteString]
→ MsgFlags
→ μ Int
sendMany' s bss flags =
liftBase $ withBufs bss $ \bufs → sendBufs s bufs flags
sendMany ∷ (SockFamily f, MonadBase IO μ)
⇒ Socket f
→ [ByteString]
→ μ Int
sendMany s bss = sendMany' s bss noFlags
sendBuf ∷ (SockFamily f, MonadBase IO μ)
⇒ Socket f
→ Ptr α
→ Int
→ MsgFlags
→ μ Int
sendBuf s p len flags = sendBufs s [(castPtr p, len)] flags
send' ∷ (SockFamily f, MonadBase IO μ)
⇒ Socket f
→ ByteString
→ MsgFlags
→ μ Int
send' s bs flags = liftBase $ BS.unsafeUseAsCStringLen bs $ \(p, len) →
sendBuf s p len flags
send ∷ (SockFamily f, MonadBase IO μ)
⇒ Socket f
→ ByteString
→ μ Int
send s bs = send' s bs noFlags
sendBufsTo ∷ (SockFamily f, MonadBase IO μ)
⇒ Socket f
→ [(Ptr Word8, Int)]
→ MsgFlags
→ SockFamilyAddr f
→ μ Int
sendBufsTo s bufs flags addr = _sendBufs s bufs flags (Just addr)
sendManyTo' ∷ (SockFamily f, MonadBase IO μ)
⇒ Socket f
→ [ByteString]
→ MsgFlags
→ SockFamilyAddr f
→ μ Int
sendManyTo' s bss flags addr = liftBase $ withBufs bss $ \bufs →
sendBufsTo s bufs flags addr
sendManyTo ∷ (SockFamily f, MonadBase IO μ)
⇒ Socket f
→ [ByteString]
→ SockFamilyAddr f
→ μ Int
sendManyTo s bss addr = sendManyTo' s bss noFlags addr
sendBufTo ∷ (SockFamily f, MonadBase IO μ)
⇒ Socket f
→ Ptr α
→ Int
→ MsgFlags
→ SockFamilyAddr f
→ μ Int
sendBufTo s p len flags addr = sendBufsTo s [(castPtr p, len)] flags addr
sendTo' ∷ (SockFamily f, MonadBase IO μ)
⇒ Socket f
→ ByteString
→ MsgFlags
→ SockFamilyAddr f
→ μ Int
sendTo' s bs flags addr =
liftBase $ BS.unsafeUseAsCStringLen bs $ \(p, len) →
sendBufTo s p len flags addr
sendTo ∷ (SockFamily f, MonadBase IO μ)
⇒ Socket f
→ ByteString
→ SockFamilyAddr f
→ μ Int
sendTo s bs addr = sendTo' s bs noFlags addr
shutdown ∷ MonadBase IO μ ⇒ Socket f → SockOps → μ ()
shutdown s dirs = withSocketFd s $ \fd →
forM_ how $ throwErrnoIfMinus1_ "shutdown" . c_shutdown fd
where how = if dirs .>=. sendSockOp then
if dirs .>=. recvSockOp then
Just 2
else
Just 1
else
if dirs .>=. recvSockOp then
Just 0
else
Nothing
close ∷ MonadBase IO μ ⇒ Socket f → μ ()
close (Socket v) = liftBase $ modifyMVar_ v $ \fd → do
when (fd >= 0) $ closeFdWith closeFd fd
return (1)
foreign import ccall "socket"
c_socket ∷ CInt → CInt → SockProto → IO CInt
foreign import ccall "getsockopt"
c_getsockopt ∷ Fd → CInt → CInt → Ptr α → Ptr Word32 → IO CInt
foreign import ccall "setsockopt"
c_setsockopt ∷ Fd → CInt → CInt → Ptr α → Word32 → IO CInt
foreign import ccall "bind"
c_bind ∷ Fd → Ptr α → Word32 → IO CInt
foreign import ccall "connect"
c_connect ∷ Fd → Ptr α → Word32 → IO CInt
foreign import ccall "listen"
c_listen ∷ Fd → CInt → IO CInt
foreign import ccall "accept4"
c_accept ∷ Fd → Ptr α → Ptr Word32 → CInt → IO CInt
foreign import ccall "getsockname"
c_getsockname ∷ Fd → Ptr α → Ptr Word32 → IO CInt
foreign import ccall "getpeername"
c_getpeername ∷ Fd → Ptr α → Ptr Word32 → IO CInt
foreign import ccall "sockatmark"
c_sockatmark ∷ Fd → IO CInt
foreign import ccall "recvmsg"
c_recvmsg ∷ Fd → Ptr β → MsgFlags → IO CSsize
foreign import ccall "sendmsg"
c_sendmsg ∷ Fd → Ptr β → MsgFlags → IO CSsize
foreign import ccall "shutdown"
c_shutdown ∷ Fd → CInt → IO CInt