packages feed

sockets-and-pipes-0.1: src/SocketsAndPipes/Serve/Sockets.hs

{- |

    The 'PassiveSocket' and 'PeerSocket' newtypes
    distinguish passive sockets from peer sockets.

    This module also includes a few basic operations
    involving these types.

-}
module SocketsAndPipes.Serve.Sockets
    (

      Socket,
      PortNumber,

      PassiveSocket (..), closePassiveSocket,
                          passiveSocketAddress,

      PeerSocket    (..), closePeerSocketAbruptly,
                          closePeerSocketPolitely,

      accept

    ) where

import Network.Socket ( Socket, PortNumber )
import qualified Network.Socket as Socket

newtype PassiveSocket = PassiveSocket { passiveSocket :: Socket }
    -- ^ A passive socket that is listening for connections.

newtype PeerSocket = PeerSocket { peerSocket :: Socket }
    -- ^ A socket that we're using to talk to a client
    --   that has connected to our server.

closePassiveSocket :: PassiveSocket -> IO ()
closePassiveSocket = Socket.close . passiveSocket

closePeerSocketAbruptly :: PeerSocket -> IO ()
closePeerSocketAbruptly = Socket.close . peerSocket

closePeerSocketPolitely :: PeerSocket -> IO ()
closePeerSocketPolitely s =
    Socket.gracefulClose (peerSocket s) finMilliseconds
{- ^
    Closes a TCP connection by sending a FIN packet, which is more
    respectful to the peer than if we were to simply ghost them.
-}

finMilliseconds :: Int
finMilliseconds = 5_000
{- ^
    Timeout for the 'fin' action.
    5 seconds = 5000 milliseconds
-}

accept :: PassiveSocket -> IO PeerSocket
accept s =
    Socket.accept (passiveSocket s) >>=
    \(s', _) -> return (PeerSocket s')
{- ^
    Waits until a new client shows up to connect to our server.
    Returns the socket that we use to talk to this particular peer.
-}

passiveSocketAddress :: PassiveSocket -> IO Socket.SockAddr
passiveSocketAddress = Socket.getSocketName . passiveSocket