1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118
|
{-# LANGUAGE CPP #-}
module Network.Socket.SockAddr (
getPeerName
, getSocketName
, connect
, bind
, accept
, sendBufTo
, recvBufFrom
, sendBufMsg
, recvBufMsg
) where
import Control.Exception (try, throwIO, IOException)
import System.Directory (removeFile)
import System.IO.Error (isAlreadyInUseError, isDoesNotExistError)
import qualified Network.Socket.Buffer as G
import qualified Network.Socket.Name as G
import qualified Network.Socket.Syscall as G
import Network.Socket.Flag
import Network.Socket.Imports
#if !defined(mingw32_HOST_OS)
import Network.Socket.Posix.Cmsg
#else
import Network.Socket.Win32.Cmsg
#endif
import Network.Socket.Types
-- | Getting peer's 'SockAddr'.
getPeerName :: Socket -> IO SockAddr
getPeerName = G.getPeerName
-- | Getting my 'SockAddr'.
getSocketName :: Socket -> IO SockAddr
getSocketName = G.getSocketName
-- | Connect to a remote socket at address.
connect :: Socket -> SockAddr -> IO ()
connect = G.connect
-- | Bind the socket to an address. The socket must not already be
-- bound. The 'Family' passed to @bind@ must be the
-- same as that passed to 'socket'. If the special port number
-- 'defaultPort' is passed then the system assigns the next available
-- use port.
bind :: Socket -> SockAddr -> IO ()
bind s a = case a of
SockAddrUnix p -> do
-- gracefully handle the fact that UNIX systems don't clean up closed UNIX
-- domain sockets, inspired by https://stackoverflow.com/a/13719866
res <- try (G.bind s a)
case res of
Right () -> return ()
Left e | not (isAlreadyInUseError e) -> throwIO (e :: IOException)
Left e | otherwise -> do
-- socket might be in use, try to connect
res2 <- try (G.connect s a)
case res2 of
Right () -> close s >> throwIO e
Left e2 | not (isDoesNotExistError e2) -> throwIO (e2 :: IOException)
_ -> do
-- socket not actually in use, remove it and retry bind
void (try $ removeFile p :: IO (Either IOError ()))
G.bind s a
_ -> G.bind s a
-- | Accept a connection. The socket must be bound to an address and
-- listening for connections. The return value is a pair @(conn,
-- address)@ where @conn@ is a new socket object usable to send and
-- receive data on the connection, and @address@ is the address bound
-- to the socket on the other end of the connection.
-- On Unix, FD_CLOEXEC is set to the new 'Socket'.
accept :: Socket -> IO (Socket, SockAddr)
accept = G.accept
-- | Send data to the socket. The recipient can be specified
-- explicitly, so the socket need not be in a connected state.
-- Returns the number of bytes sent. Applications are responsible for
-- ensuring that all data has been sent.
sendBufTo :: Socket -> Ptr a -> Int -> SockAddr -> IO Int
sendBufTo = G.sendBufTo
-- | Receive data from the socket, writing it into buffer instead of
-- creating a new string. The socket need not be in a connected
-- state. Returns @(nbytes, address)@ where @nbytes@ is the number of
-- bytes received and @address@ is a 'SockAddr' representing the
-- address of the sending socket.
--
-- If the first return value is zero, it means EOF.
--
-- For 'Stream' sockets, the second return value would be invalid.
--
-- NOTE: blocking on Windows unless you compile with -threaded (see
-- GHC ticket #1129)
recvBufFrom :: Socket -> Ptr a -> Int -> IO (Int, SockAddr)
recvBufFrom = G.recvBufFrom
-- | Send data to the socket using sendmsg(2).
sendBufMsg :: Socket -- ^ Socket
-> SockAddr -- ^ Destination address
-> [(Ptr Word8,Int)] -- ^ Data to be sent
-> [Cmsg] -- ^ Control messages
-> MsgFlag -- ^ Message flags
-> IO Int -- ^ The length actually sent
sendBufMsg = G.sendBufMsg
-- | Receive data from the socket using recvmsg(2).
recvBufMsg :: Socket -- ^ Socket
-> [(Ptr Word8,Int)] -- ^ A list of a pair of buffer and its size.
-- If the total length is not large enough,
-- 'MSG_TRUNC' is returned
-> Int -- ^ The buffer size for control messages.
-- If the length is not large enough,
-- 'MSG_CTRUNC' is returned
-> MsgFlag -- ^ Message flags
-> IO (SockAddr,Int,[Cmsg],MsgFlag) -- ^ Source address, received data, control messages and message flags
recvBufMsg = G.recvBufMsg
|