{-# LANGUAGE Trustworthy #-}
{-# OPTIONS_GHC -fno-warn-name-shadowing #-}
module Network.SocketServer(
InetServerOptions(..),
simpleTCPOptions,
SocketServer(..),
HandlerT,
serveTCPforever,
setupSocketServer,
handleOne,
serveForever,
closeSocketServer,
loggingHandler,
threadedHandler,
handleHandler
)
where
import Control.Concurrent ( forkIO )
import Data.Functor (void)
import Network.BSD
( getProtocolNumber, Family(AF_INET), HostAddress, PortNumber )
import Network.Socket
( socketToHandle,
setSocketOption,
accept,
bind,
getSocketName,
listen,
socket,
close,
SocketOption(ReuseAddr),
SockAddr(SockAddrInet),
Socket,
SocketType(Stream) )
import Network.Utils ( showSockAddr )
import System.IO
( Handle,
hClose,
hSetBuffering,
BufferMode(LineBuffering),
IOMode(ReadWriteMode) )
import qualified System.Log.Logger
data InetServerOptions = InetServerOptions {InetServerOptions -> Int
listenQueueSize :: Int,
InetServerOptions -> PortNumber
portNumber :: PortNumber,
InetServerOptions -> HostAddress
interface :: HostAddress,
InetServerOptions -> Bool
reuse :: Bool,
InetServerOptions -> Family
family :: Family,
InetServerOptions -> SocketType
sockType :: SocketType,
InetServerOptions -> String
protoStr :: String
}
deriving (InetServerOptions -> InetServerOptions -> Bool
(InetServerOptions -> InetServerOptions -> Bool)
-> (InetServerOptions -> InetServerOptions -> Bool)
-> Eq InetServerOptions
forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
$c== :: InetServerOptions -> InetServerOptions -> Bool
== :: InetServerOptions -> InetServerOptions -> Bool
$c/= :: InetServerOptions -> InetServerOptions -> Bool
/= :: InetServerOptions -> InetServerOptions -> Bool
Eq, Int -> InetServerOptions -> ShowS
[InetServerOptions] -> ShowS
InetServerOptions -> String
(Int -> InetServerOptions -> ShowS)
-> (InetServerOptions -> String)
-> ([InetServerOptions] -> ShowS)
-> Show InetServerOptions
forall a.
(Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a
$cshowsPrec :: Int -> InetServerOptions -> ShowS
showsPrec :: Int -> InetServerOptions -> ShowS
$cshow :: InetServerOptions -> String
show :: InetServerOptions -> String
$cshowList :: [InetServerOptions] -> ShowS
showList :: [InetServerOptions] -> ShowS
Show)
type HandlerT = Socket -> SockAddr -> SockAddr -> IO ()
simpleTCPOptions :: Int
-> InetServerOptions
simpleTCPOptions :: Int -> InetServerOptions
simpleTCPOptions Int
p = InetServerOptions {listenQueueSize :: Int
listenQueueSize = Int
5,
portNumber :: PortNumber
portNumber = (Int -> PortNumber
forall a b. (Integral a, Num b) => a -> b
fromIntegral Int
p),
interface :: HostAddress
interface = HostAddress
0,
reuse :: Bool
reuse = Bool
False,
family :: Family
family = Family
AF_INET,
sockType :: SocketType
sockType = SocketType
Stream,
protoStr :: String
protoStr = String
"tcp"
}
data SocketServer = SocketServer {SocketServer -> InetServerOptions
optionsSS :: InetServerOptions,
SocketServer -> Socket
sockSS :: Socket}
deriving (SocketServer -> SocketServer -> Bool
(SocketServer -> SocketServer -> Bool)
-> (SocketServer -> SocketServer -> Bool) -> Eq SocketServer
forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
$c== :: SocketServer -> SocketServer -> Bool
== :: SocketServer -> SocketServer -> Bool
$c/= :: SocketServer -> SocketServer -> Bool
/= :: SocketServer -> SocketServer -> Bool
Eq, Int -> SocketServer -> ShowS
[SocketServer] -> ShowS
SocketServer -> String
(Int -> SocketServer -> ShowS)
-> (SocketServer -> String)
-> ([SocketServer] -> ShowS)
-> Show SocketServer
forall a.
(Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a
$cshowsPrec :: Int -> SocketServer -> ShowS
showsPrec :: Int -> SocketServer -> ShowS
$cshow :: SocketServer -> String
show :: SocketServer -> String
$cshowList :: [SocketServer] -> ShowS
showList :: [SocketServer] -> ShowS
Show)
setupSocketServer :: InetServerOptions -> IO SocketServer
setupSocketServer :: InetServerOptions -> IO SocketServer
setupSocketServer InetServerOptions
opts =
do proto <- String -> IO ProtocolNumber
getProtocolNumber (InetServerOptions -> String
protoStr InetServerOptions
opts)
s <- socket (family opts) (sockType opts) proto
setSocketOption s ReuseAddr (case (reuse opts) of
Bool
True -> Int
1
Bool
False -> Int
0)
bind s (SockAddrInet (portNumber opts)
(interface opts))
listen s (listenQueueSize opts)
return $ SocketServer {optionsSS = opts, sockSS = s}
closeSocketServer :: SocketServer -> IO ()
closeSocketServer :: SocketServer -> IO ()
closeSocketServer SocketServer
ss =
Socket -> IO ()
close (SocketServer -> Socket
sockSS SocketServer
ss)
handleOne :: SocketServer -> HandlerT -> IO ()
handleOne :: SocketServer -> HandlerT -> IO ()
handleOne SocketServer
ss HandlerT
func = do
a <- Socket -> IO (Socket, SockAddr)
accept (SocketServer -> Socket
sockSS SocketServer
ss)
localaddr <- getSocketName (fst a)
func (fst a) (snd a) localaddr
serveForever :: SocketServer -> HandlerT -> IO ()
serveForever :: SocketServer -> HandlerT -> IO ()
serveForever SocketServer
ss HandlerT
func =
[IO ()] -> IO ()
forall (t :: * -> *) (m :: * -> *) a.
(Foldable t, Monad m) =>
t (m a) -> m ()
sequence_ (IO () -> [IO ()]
forall a. a -> [a]
repeat (SocketServer -> HandlerT -> IO ()
handleOne SocketServer
ss HandlerT
func))
serveTCPforever :: InetServerOptions
-> HandlerT
-> IO ()
serveTCPforever :: InetServerOptions -> HandlerT -> IO ()
serveTCPforever InetServerOptions
options HandlerT
func =
do sockserv <- InetServerOptions -> IO SocketServer
setupSocketServer InetServerOptions
options
serveForever sockserv func
loggingHandler :: String
-> System.Log.Logger.Priority
-> HandlerT
-> HandlerT
loggingHandler :: String -> Priority -> HandlerT -> HandlerT
loggingHandler String
hname Priority
prio HandlerT
nexth Socket
socket SockAddr
r_sockaddr SockAddr
l_sockaddr =
do sockStr <- SockAddr -> IO String
showSockAddr SockAddr
r_sockaddr
System.Log.Logger.logM hname prio
("Received connection from " ++ sockStr)
System.Log.Logger.traplogging hname
System.Log.Logger.WARNING "" (nexth socket r_sockaddr
l_sockaddr)
System.Log.Logger.logM hname prio
("Connection " ++ sockStr ++ " disconnected")
threadedHandler :: HandlerT
-> HandlerT
threadedHandler :: HandlerT -> HandlerT
threadedHandler HandlerT
nexth Socket
socket SockAddr
r_sockaddr SockAddr
l_sockaddr = IO ThreadId -> IO ()
forall (f :: * -> *) a. Functor f => f a -> f ()
void (IO ThreadId -> IO ()) -> IO ThreadId -> IO ()
forall a b. (a -> b) -> a -> b
$
IO () -> IO ThreadId
forkIO (HandlerT
nexth Socket
socket SockAddr
r_sockaddr SockAddr
l_sockaddr)
handleHandler :: (Handle -> SockAddr -> SockAddr -> IO ())
-> HandlerT
handleHandler :: (Handle -> SockAddr -> SockAddr -> IO ()) -> HandlerT
handleHandler Handle -> SockAddr -> SockAddr -> IO ()
func Socket
socket SockAddr
r_sockaddr SockAddr
l_sockaddr =
do h <- Socket -> IOMode -> IO Handle
socketToHandle Socket
socket IOMode
ReadWriteMode
hSetBuffering h LineBuffering
func h r_sockaddr l_sockaddr
hClose h