content: {-# 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
  