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