module Network.Run.UDP (
runUDPClient
, runUDPServer
, runUDPServerFork
) where
import Control.Concurrent (forkIO, forkFinally)
import qualified Control.Exception as E
import Control.Monad (forever, void)
import Data.ByteString (ByteString)
import Network.Socket
import Network.Socket.ByteString
import Network.Run.Core
runUDPClient :: HostName -> ServiceName -> (Socket -> SockAddr -> IO a) -> IO a
runUDPClient host port client = withSocketsDo $ do
addr <- resolve Datagram (Just host) port False
let sockAddr = addrAddress addr
E.bracket (openSocket addr) close $ \sock -> client sock sockAddr
runUDPServer :: Maybe HostName -> ServiceName -> (Socket -> IO a) -> IO a
runUDPServer mhost port server = withSocketsDo $ do
addr <- resolve Datagram mhost port True
E.bracket (openServerSocket addr) close server
runUDPServerFork :: [HostName] -> ServiceName -> (Socket -> ByteString -> IO ()) -> IO ()
runUDPServerFork [] _ _ = return ()
runUDPServerFork (h:hs) port server = do
mapM_ (forkIO . run) hs
run h
where
run host = runUDPServer (Just host) port $ \lsock -> forever $ do
(bs0,peeraddr) <- recvFrom lsock 2048
let family = case peeraddr of
SockAddrInet{} -> AF_INET
SockAddrInet6{} -> AF_INET6
_ -> error "family"
hints = defaultHints {
addrSocketType = Datagram
, addrFamily = family
, addrFlags = [AI_PASSIVE]
}
addr <- head <$> getAddrInfo (Just hints) Nothing (Just port)
s <- openServerSocket addr
connect s peeraddr
void $ forkFinally (server s bs0) (\_ -> close s)