{-# language BangPatterns #-} {-# language LambdaCase #-} {-# language OverloadedStrings #-} import Prelude hiding (log) import Control.Exception (Exception,throwIO) import System.Environment (getArgs) import Data.Primitive (ByteArray(..)) import Control.Monad (replicateM_) import qualified Socket.Datagram.IPv4.Undestined as DIU import qualified Socket.Stream.IPv4 as SI import qualified GHC.Exts as E import qualified Data.Primitive as PM import qualified Data.Primitive.MVar as PM import qualified Net.IPv4 as IPv4 import qualified Data.ByteString as B import qualified Data.ByteString.Short.Internal as SB import qualified Data.ByteString.Char8 as BC import qualified System.Log.FastLogger as FL main :: IO () main = udpStdoutServer gettysburgClient :: IO () gettysburgClient = do [port] <- getArgs unhandled $ SI.withConnection (SI.Endpoint IPv4.loopback (read port)) $ \conn -> do unhandled $ SI.sendByteArray conn gettysburgAddress -- This waits until a single connection is established. It then dumps out -- anything it receives to stdout. When the remote application shuts down -- its end, this shuts down its end in return and then terminates. tcpStdoutServer :: IO () tcpStdoutServer = do FL.withFastLogger (FL.LogStdout 2048) $ \log -> do unhandled $ SI.withListener (SI.Endpoint IPv4.loopback 0) $ \listener port -> do log (FL.toLogStr ("Listening on 127.0.0.1:" <> BC.pack (show port) <> "\n============================\n")) unhandled $ SI.withAccepted listener $ \conn _ -> do let go = SI.receiveBoundedByteArray conn 512 >>= \case Left (SI.SocketException SI.Receive SI.RemoteShutdown) -> pure () Left e -> throwIO e Right (PM.ByteArray arr) -> do log (FL.toLogStr (SB.fromShort (SB.SBS arr))) go go -- Print every UDP packet that we receive. This terminates, closing the -- socket, after receiving ten packets. udpStdoutServer :: IO () udpStdoutServer = do unhandled $ DIU.withSocket (DIU.Endpoint IPv4.loopback 0) $ \sock port -> do BC.putStrLn ("Receiving datagrams on 127.0.0.1:" <> BC.pack (show port)) replicateM_ 10 $ do (remote,ByteArray payload) <- unhandled (DIU.receive sock 1024) BC.putStrLn ("Datagram from " <> BC.pack (show remote)) BC.putStr (SB.fromShort (SB.SBS payload)) unhandled :: Exception e => IO (Either e a) -> IO a unhandled action = action >>= either throwIO pure gettysburgAddress :: PM.ByteArray gettysburgAddress = PM.ByteArray arr where !(SB.SBS arr) = SB.toShort $ mconcat [ "Four score and seven years ago our fathers brought forth on this " , "continent, a new nation, conceived in Liberty, and dedicated to " , "the proposition that all men are created equal. Now we are engaged " , "in a great civil war, testing whether that nation, or any nation so " , "conceived and so dedicated, can long endure. We are met on a great " , "battle-field of that war. We have come to dedicate a portion of that " , "field, as a final resting place for those who here gave their lives " , "that that nation might live. It is altogether fitting and proper that " , "we should do this." ]