socket-unix 0.1.0.0 → 0.1.1.0
raw patch · 11 files changed
+410/−252 lines, 11 filesPVP: major bump suggested
API removals or changes: PVP suggests a major version bump
API changes (from Hackage documentation)
- System.Socket.Family.Unix: getUnixPath :: SocketAddress Unix -> Maybe (ByteString)
- System.Socket.Family.Unix: instance Foreign.Storable.Storable (System.Socket.Internal.Socket.SocketAddress System.Socket.Family.Unix.Unix)
- System.Socket.Family.Unix: instance GHC.Classes.Eq (System.Socket.Internal.Socket.SocketAddress System.Socket.Family.Unix.Unix)
- System.Socket.Family.Unix: instance GHC.Show.Show (System.Socket.Internal.Socket.SocketAddress System.Socket.Family.Unix.Unix)
- System.Socket.Family.Unix: instance System.Socket.Internal.Socket.Family System.Socket.Family.Unix.Unix
- System.Socket.Family.Unix: instance System.Socket.Internal.Socket.Protocol System.Socket.Family.Unix.Unix
- System.Socket.Family.Unix: socketAddressUnixAbstract :: ByteString -> Maybe (SocketAddress Unix)
- System.Socket.Family.Unix: socketAddressUnixPath :: ByteString -> Maybe (SocketAddress Unix)
+ System.Socket.Family.Unix: eNoEntry :: SocketException
Files
- README.md +1/−1
- platform/linux/System/Socket/Family/Unix/Platform.hsc +99/−0
- platform/unix/System/Socket/Family/Unix/Platform.hsc +76/−0
- platform_test/linux/Platform.hs +42/−0
- platform_test/unix/Platform.hs +7/−0
- socket-unix.cabal +21/−2
- src/System/Socket/Family/Unix.hs +14/−0
- src/System/Socket/Family/Unix.hsc +0/−108
- src/System/Socket/Family/Unix/Internal.hsc +32/−0
- test/Internal.hs +115/−0
- test/test.hs +3/−141
README.md view
@@ -23,7 +23,7 @@ ### Symlinks Binding to a socket with a filename creates a socket in the filesystem, but does not unlink it after `close` called. You should handle deleting links yourself. ## Portability-Only Linux is supported.+Linux and OS X are supported. [badge-travis]: https://img.shields.io/travis/VyacheslavHashov/haskell-socket-unix.svg
+ platform/linux/System/Socket/Family/Unix/Platform.hsc view
@@ -0,0 +1,99 @@+-- |+-- Stability : experimental+-- Portability : Linux++{-# options_ghc -fno-warn-orphans #-}+{-# language TypeFamilies #-}+{-# language FlexibleInstances #-}++module System.Socket.Family.Unix.Platform+ ( SocketAddress+ , socketAddressUnixPath+ , socketAddressUnixAbstract+ , getUnixPath+ ) where++import Foreign.Ptr (castPtr, plusPtr)+import Foreign.Storable (Storable(..))+import Foreign.Marshal.Utils (fillBytes, copyBytes)++import Data.Word (Word16, Word8)+import Data.ByteString (ByteString)+import Data.ByteString.Unsafe (unsafeUseAsCStringLen)+import qualified Data.ByteString as B++import System.Socket (SocketAddress)+import System.Socket.Family.Unix.Internal (Unix)++#include "hs_socket.h"++#if __GLASGOW_HASKELL__ < 800+#let alignment t = "%lu", (unsigned long)offsetof(struct {char x__; t (y__); }, y__)+#endif++-- | A Unix socket address+data instance SocketAddress Unix+ -- | Address is connected to a filesystem pathname. When used to bind+ -- a socket file with this name is created in the file system.+ = SocketAddressUnixPath ByteString+ -- | Address is in abstract namespace which is a Linux-specific feature+ -- that allows us to bind a UNIX domain socket to a name without that+ -- name being created in the file system.+ | SocketAddressUnixAbstract ByteString+ deriving (Eq, Show)++-- | The maximal length of a address path.+-- SUSv3 doesn’t specify the size of the sun_path field. Early BSD+-- implementations used 108 and 104 bytes, and one contemporary implementation+-- (HP-UX 11) uses 92 bytes. On linux it is declared as+-- > char sun_path[108];+-- and 1 byte is reserved for null byte.+maxPathLength :: Int+maxPathLength = 107++-- | Creates address which is connected to a filesystem pathname.+-- Returns Nothing if @path@'s length exceeds maximal supported.+socketAddressUnixPath :: ByteString -> Maybe (SocketAddress Unix)+socketAddressUnixPath path+ | B.length path <= maxPathLength = Just $ SocketAddressUnixPath path+ | otherwise = Nothing++-- | Creates address with name in abstract namespace.+-- Returns Nothing if @path@'s length exceeds maximal supported.+socketAddressUnixAbstract :: ByteString -> Maybe (SocketAddress Unix)+socketAddressUnixAbstract path+ | len <= maxPathLength = Just . SocketAddressUnixAbstract $+ path `B.append` B.replicate (maxPathLength - len) 0+ | otherwise = Nothing+ where len = B.length path++-- | Returns filesystem pathname where address is connected to.+getUnixPath :: SocketAddress Unix -> Maybe (ByteString)+getUnixPath (SocketAddressUnixPath path) = Just path+getUnixPath _ = Nothing++-- For implementation details see @man unix@+instance Storable (SocketAddress Unix) where+ sizeOf _ = (#size struct sockaddr_un)+ alignment _ = (#alignment struct sockaddr_un)++ peek ptr = do+ first <- peek (sun_path ptr) :: IO Word8+ case first of+ 0 -> SocketAddressUnixAbstract <$>+ B.packCStringLen (castPtr $ sun_path ptr `plusPtr` 1, maxPathLength)+ _ -> SocketAddressUnixPath <$> B.packCString (castPtr $ sun_path ptr)+ where+ sun_path = (#ptr struct sockaddr_un, sun_path)++ poke ptr socketAddress = do+ fillBytes ptr 0 (#const sizeof(struct sockaddr_un))+ poke (sun_family ptr) ((#const AF_UNIX) :: Word16)+ case socketAddress of+ SocketAddressUnixPath path -> unsafeUseAsCStringLen path $+ \(src, len) -> copyBytes (sun_path ptr) src len+ SocketAddressUnixAbstract path -> unsafeUseAsCStringLen path $+ \(src, len) -> copyBytes (sun_path ptr `plusPtr` 1) src len+ where+ sun_family = (#ptr struct sockaddr_un, sun_family)+ sun_path = (#ptr struct sockaddr_un, sun_path)
+ platform/unix/System/Socket/Family/Unix/Platform.hsc view
@@ -0,0 +1,76 @@+-- |+-- Stability : experimental+-- Portability : Unix++{-# options_ghc -fno-warn-orphans #-}+{-# language TypeFamilies #-}+{-# language FlexibleInstances #-}++module System.Socket.Family.Unix.Platform+ ( SocketAddress+ , socketAddressUnixPath+ , getUnixPath+ ) where++import Foreign.Ptr (castPtr, plusPtr)+import Foreign.Storable (Storable(..))+import Foreign.Marshal.Utils (fillBytes, copyBytes)++import Data.Word (Word16 )+import Data.ByteString (ByteString)+import Data.ByteString.Unsafe (unsafeUseAsCStringLen)+import qualified Data.ByteString as B++import System.Socket (SocketAddress)+import System.Socket.Family.Unix.Internal (Unix)++#include "hs_socket.h"++#if __GLASGOW_HASKELL__ < 800+#let alignment t = "%lu", (unsigned long)offsetof(struct {char x__; t (y__); }, y__)+#endif++-- | A Unix socket address+data instance SocketAddress Unix+ -- | Address is connected to a filesystem pathname. When used to bind+ -- a socket file with this name is created in the file system.+ = SocketAddressUnixPath ByteString+ deriving (Eq, Show)++-- | The maximal length of a address path.+-- SUSv3 doesn’t specify the size of the sun_path field. Early BSD+-- implementations used 108 and 104 bytes, and one contemporary implementation+-- (HP-UX 11) uses 92 bytes. On linux it is declared as+-- > char sun_path[108];+-- and 1 byte is reserved for null byte.+maxPathLength :: Int+maxPathLength = 107++-- | Creates address which is connected to a filesystem pathname.+-- Returns Nothing if @path@'s length exceeds maximal supported.+socketAddressUnixPath :: ByteString -> Maybe (SocketAddress Unix)+socketAddressUnixPath path+ | B.length path <= maxPathLength = Just $ SocketAddressUnixPath path+ | otherwise = Nothing++-- | Returns filesystem pathname where address is connected to.+getUnixPath :: SocketAddress Unix -> Maybe (ByteString)+getUnixPath (SocketAddressUnixPath path) = Just path++-- For implementation details see @man unix@+instance Storable (SocketAddress Unix) where+ sizeOf _ = (#size struct sockaddr_un)+ alignment _ = (#alignment struct sockaddr_un)++ peek ptr = SocketAddressUnixPath <$> B.packCString (castPtr $ sun_path ptr)+ where+ sun_path = (#ptr struct sockaddr_un, sun_path)++ poke ptr (SocketAddressUnixPath path) = do+ fillBytes ptr 0 (#const sizeof(struct sockaddr_un))+ poke (sun_family ptr) ((#const AF_UNIX) :: Word16)+ unsafeUseAsCStringLen path $+ \(src, len) -> copyBytes (sun_path ptr) src len+ where+ sun_family = (#ptr struct sockaddr_un, sun_family)+ sun_path = (#ptr struct sockaddr_un, sun_path)
+ platform_test/linux/Platform.hs view
@@ -0,0 +1,42 @@+module Platform where++import Data.Maybe (fromJust)+import Control.Exception (bracket, throwIO, try)+import Test.Tasty+import Test.Tasty.HUnit++import System.Socket+import System.Socket.Type.Stream+import System.Socket.Type.Datagram+import System.Socket.Family.Unix++import Internal++groupAbstractName :: TestTree+groupAbstractName = testGroup "Abstract path name"+ [ testCase "connect to non-existing path name" $ bracket+ unixSocketStream+ close+ (\s -> do+ r <- try $ connect s addr+ case r of+ Left e | e == eConnectionRefused -> return ()+ | otherwise -> throwIO e+ Right () -> assertFailure "connection should have failed"+ )+ , testCase "server\\client stream" $ bracket+ ( (,) <$> unixSocketStream <*> unixSocketStream)+ closeSockets+ (testServerClientStream addr)+ , testCase "server\\client datagram" $ bracket+ ((,) <$> unixSocketDatagram <*> unixSocketDatagram)+ closeSockets+ (testServerClientDatagram addr cAddr)+ ]+ where+ addr = fromJust $ socketAddressUnixAbstract abstractPath+ cAddr = fromJust $ socketAddressUnixAbstract clientAbstractPath+ closeSockets (server, client) = do+ close server+ close client+
+ platform_test/unix/Platform.hs view
@@ -0,0 +1,7 @@+module Platform where++import Test.Tasty++groupAbstractName :: TestTree+groupAbstractName = testGroup "Abstract path name" []+
socket-unix.cabal view
@@ -1,6 +1,6 @@ name: socket-unix-version: 0.1.0.0-synopsis: A Unix domain sockets+version: 0.1.1.0+synopsis: Unix domain sockets description: A Unix domain socket extension for the socket library homepage: https://github.com/vyacheslavhashov/haskell-socket-unix#readme license: MIT @@ -9,13 +9,20 @@ maintainer: vyacheslavhashov@gmail.com copyright: 2017 Vyacheslav Hashov category: System, Network+stability: Experimental build-type: Simple extra-source-files: README.md cabal-version: >=1.10 library hs-source-dirs: src+ if os(linux)+ hs-source-dirs: platform/linux+ if os(osx) || os(darwin) || os(freebsd) || os(openbsd) || os(netbsd) || os(solaris)+ hs-source-dirs: platform/unix exposed-modules: System.Socket.Family.Unix+ other-modules: System.Socket.Family.Unix.Internal+ System.Socket.Family.Unix.Platform build-depends: base >= 4.7 && < 5 , socket >= 0.6.0.0 && < 0.8.0.0 , bytestring >= 0.10.0.0 && < 0.11@@ -26,7 +33,13 @@ test-suite default type: exitcode-stdio-1.0 hs-source-dirs: test+ if os(linux)+ hs-source-dirs: platform_test/linux+ if os(osx) || os(darwin) || os(freebsd) || os(openbsd) || os(netbsd) || os(solaris)+ hs-source-dirs: platform_test/unix main-is: test.hs+ other-modules: Internal+ Platform build-depends: base >= 4.7 && < 5 , socket >= 0.6.0.0 && < 0.8.0.0 , socket-unix@@ -40,7 +53,13 @@ test-suite threaded type: exitcode-stdio-1.0 hs-source-dirs: test+ if os(linux)+ hs-source-dirs: platform_test/linux+ if os(osx) || os(darwin) || os(freebsd) || os(openbsd) || os(netbsd) || os(solaris)+ hs-source-dirs: platform_test/unix main-is: test.hs+ other-modules: Internal+ Platform build-depends: base >= 4.7 && < 5 , socket >= 0.6.0.0 && < 0.8.0.0 , socket-unix
+ src/System/Socket/Family/Unix.hs view
@@ -0,0 +1,14 @@+-- |+-- Stability : experimental+-- Portability : Linux, OS X++module System.Socket.Family.Unix+ ( Unix+ , module Exports+ -- * Exceptions+ , eNoEntry+ ) where++import System.Socket.Family.Unix.Internal+import System.Socket.Family.Unix.Platform as Exports+
− src/System/Socket/Family/Unix.hsc
@@ -1,108 +0,0 @@--- |--- Stability : experimental--- Portability : Linux--{-# language TypeFamilies #-}-{-# language FlexibleInstances #-}--module System.Socket.Family.Unix- ( Unix- , SocketAddress- , socketAddressUnixPath- , socketAddressUnixAbstract- , getUnixPath- ) where--import Foreign.Ptr (castPtr, plusPtr)-import Foreign.Storable (Storable(..))-import Foreign.Marshal.Utils (fillBytes, copyBytes)--import Data.Word (Word16, Word8)-import Data.ByteString (ByteString)-import Data.ByteString.Unsafe (unsafeUseAsCStringLen)-import qualified Data.ByteString as B--import System.Socket (Family(..), SocketAddress, Protocol(..))--#include "hs_socket.h"--#if __GLASGOW_HASKELL__ < 800-#let alignment t = "%lu", (unsigned long)offsetof(struct {char x__; t (y__); }, y__)-#endif---- | The [Unix domain socket]--- (https://en.wikipedia.org/wiki/Unix_domain_socket)-data Unix--instance Family Unix where- familyNumber _ = (#const AF_UNIX)--instance Protocol Unix where- protocolNumber _ = 0---- | A Unix socket address-data instance SocketAddress Unix- -- | Address is connected to a filesystem pathname. When used to bind- -- a socket file with this name is created in the file system.- = SocketAddressUnixPath ByteString- -- | Address is in abstract namespace which is a Linux-specific feature- -- that allows us to bind a UNIX domain socket to a name without that- -- name being created in the file system.- | SocketAddressUnixAbstract ByteString- deriving (Eq, Show)---- | The maximal length of a address path.--- SUSv3 doesn’t specify the size of the sun_path field. Early BSD--- implementations used 108 and 104 bytes, and one contemporary implementation--- (HP-UX 11) uses 92 bytes. On linux it is declared as--- > char sun_path[108];--- and 1 byte is reserved for null byte.-maxPathLength :: Int-maxPathLength = 107---- | Creates address which is connected to a filesystem pathname.--- Returns Nothing if @path@'s length exceeds maximal supported.-socketAddressUnixPath :: ByteString -> Maybe (SocketAddress Unix)-socketAddressUnixPath path- | B.length path <= maxPathLength = Just $ SocketAddressUnixPath path- | otherwise = Nothing---- | Creates address with name in abstract namespace.--- Returns Nothing if @path@'s length exceeds maximal supported.-socketAddressUnixAbstract :: ByteString -> Maybe (SocketAddress Unix)-socketAddressUnixAbstract path- | len <= maxPathLength = Just . SocketAddressUnixAbstract $- path `B.append` B.replicate (maxPathLength - len) 0- | otherwise = Nothing- where len = B.length path---- | Returns filesystem pathname where address is connected to.-getUnixPath :: SocketAddress Unix -> Maybe (ByteString)-getUnixPath (SocketAddressUnixPath path) = Just path-getUnixPath _ = Nothing---- For implementation details see @man unix@-instance Storable (SocketAddress Unix) where- sizeOf _ = (#size struct sockaddr_un)- alignment _ = (#alignment struct sockaddr_un)-- peek ptr = do- first <- peek (sun_path ptr) :: IO Word8- case first of- 0 -> SocketAddressUnixAbstract <$>- B.packCStringLen (castPtr $ sun_path ptr `plusPtr` 1, maxPathLength)- _ -> SocketAddressUnixPath <$> B.packCString (castPtr $ sun_path ptr)- where- sun_path = (#ptr struct sockaddr_un, sun_path)-- poke ptr socketAddress = do- fillBytes ptr 0 (#const sizeof(struct sockaddr_un))- poke (sun_family ptr) ((#const AF_UNIX) :: Word16)- case socketAddress of- SocketAddressUnixPath path -> unsafeUseAsCStringLen path $- \(src, len) -> copyBytes (sun_path ptr) src len- SocketAddressUnixAbstract path -> unsafeUseAsCStringLen path $- \(src, len) -> copyBytes (sun_path ptr `plusPtr` 1) src len- where- sun_family = (#ptr struct sockaddr_un, sun_family)- sun_path = (#ptr struct sockaddr_un, sun_path)
+ src/System/Socket/Family/Unix/Internal.hsc view
@@ -0,0 +1,32 @@+-- |+-- Stability : experimental+-- Portability : Linux, Unix++module System.Socket.Family.Unix.Internal+ ( Unix+ -- * Exceptions+ , eNoEntry+ ) where++import System.Socket (Family(..), Protocol(..), SocketException(..))++#include "hs_socket.h"++#if __GLASGOW_HASKELL__ < 800+#let alignment t = "%lu", (unsigned long)offsetof(struct {char x__; t (y__); }, y__)+#endif++-- | The [Unix domain socket]+-- (https://en.wikipedia.org/wiki/Unix_domain_socket)+data Unix++instance Family Unix where+ familyNumber _ = (#const AF_UNIX)++instance Protocol Unix where+ protocolNumber _ = 0++-- | > SocketException "No such file or directory"+eNoEntry :: SocketException+eNoEntry = SocketException (#const ENOENT)+
+ test/Internal.hs view
@@ -0,0 +1,115 @@+{-# language OverloadedStrings #-}+module Internal where++import Control.Concurrent.Async (async, wait)+import Control.Exception (bracket, throwIO, try)+import Control.Monad (when)+import Data.Maybe (fromJust)+import Data.String (IsString)+import Data.ByteString (ByteString)+import System.Posix.Files.ByteString (removeLink, fileExist)+import Test.Tasty+import Test.Tasty.HUnit++import System.Socket+import System.Socket.Type.Stream+import System.Socket.Type.Datagram+import System.Socket.Family.Unix++groupUnixPathname :: TestTree+groupUnixPathname = testGroup "Unix path name"+ [ testCase "connect to non-existing path name" $ bracket+ unixSocketStream+ close+ (\s -> do+ r <- try $ connect s addr+ case r of+ Left e | e == eNoEntry -> return ()+ | otherwise -> throwIO e+ Right () -> assertFailure "connection should have failed"+ )++ , testCase "server\\client stream" $ bracket+ ( (,) <$> unixSocketStream <*> unixSocketStream)+ closeSockets+ (testServerClientStream addr)++ , testCase "server\\client datagram" $ bracket+ ((,) <$> unixSocketDatagram <*> unixSocketDatagram)+ closeSockets+ (testServerClientDatagram addr cAddr)+ ]+ where+ addr = fromJust $ socketAddressUnixPath unixPath+ cAddr = fromJust $ socketAddressUnixPath clientUnixPath+ closeSockets (server, client) = do+ close server+ close client+ unlink unixPath+ unlink clientUnixPath+ -- Sockets with real pathname should be unlinked after closing+ unlink path = fileExist path >>= flip when (removeLink path)++clientMessage :: ByteString+clientMessage = "client message"++serverMessage :: ByteString+serverMessage = "server message"++unixPath :: ByteString+unixPath = "Woum5ag3oohuaLee.socket"++clientUnixPath :: ByteString+clientUnixPath = "Io4meo0epoquashi.socket"++abstractPath :: ByteString+abstractPath = "/tmp/uth4Aechiereejae.socket"++clientAbstractPath :: ByteString+clientAbstractPath = "/tmp/FieNg4shamo4Thie.socket"++unixSocketStream :: IO (Socket Unix Stream Unix)+unixSocketStream = socket++unixSocketDatagram :: IO (Socket Unix Datagram Unix)+unixSocketDatagram = socket++testServerClientStream+ :: SocketAddress Unix+ -> (Socket Unix Stream Unix, Socket Unix Stream Unix)+ -> IO ()+testServerClientStream addr (server, client) = do+ bind server addr+ listen server 5+ serverRecv <- async $ do+ (peerSock, peerAddr) <- accept server+ r <- receive peerSock 4096 mempty+ send peerSock serverMessage mempty+ pure r+ connect client addr+ send client clientMessage mempty++ clientMessageReceived <- wait serverRecv+ serverMessageReceived <- receive client 4096 mempty+ clientMessageReceived @?= clientMessage+ serverMessageReceived @?= serverMessage++testServerClientDatagram+ :: SocketAddress Unix+ -> SocketAddress Unix+ -> (Socket Unix Datagram Unix, Socket Unix Datagram Unix)+ -> IO ()+testServerClientDatagram sAddr cAddr (server, client) = do+ bind server sAddr+ bind client cAddr+ serverRecv <- async $ do+ (r, peerAddr) <- receiveFrom server 4096 mempty+ sendTo server serverMessage mempty peerAddr+ pure r+ sendTo client clientMessage mempty sAddr++ clientMessageReceived <- wait serverRecv+ serverMessageReceived <- receive client 4096 mempty+ clientMessageReceived @?= clientMessage+ serverMessageReceived @?= serverMessage+
test/test.hs view
@@ -1,150 +1,12 @@-{-# language OverloadedStrings #-} module Main where -import Control.Concurrent.Async (async, wait)-import Control.Exception (bracket, throwIO, try)-import Control.Monad (when)-import Data.Maybe (fromJust)-import Data.String (IsString)-import Data.ByteString (ByteString)-import System.Posix.Files (removeLink, fileExist)-import Test.Tasty-import Test.Tasty.HUnit--import System.Socket-import System.Socket.Type.Stream-import System.Socket.Type.Datagram-import System.Socket.Family.Unix+import Test.Tasty (defaultMain, testGroup) +import Internal+import Platform main :: IO () main = defaultMain $ testGroup "unix domain socket" [ groupUnixPathname , groupAbstractName ]--groupUnixPathname :: TestTree-groupUnixPathname = testGroup "Unix path name"- [ testCase "connect to non-existing path name" $ bracket- unixSocketStream- close- (\s -> do- r <- try $ connect s addr- case r of- Left e | e == SocketException 2 -> return ()- | otherwise -> throwIO e- Right () -> assertFailure "connection should have failed"- )-- , testCase "server\\client stream" $ bracket- ( (,) <$> unixSocketStream <*> unixSocketStream)- closeSockets- (testServerClientStream addr)-- , testCase "server\\client datagram" $ bracket- ((,) <$> unixSocketDatagram <*> unixSocketDatagram)- closeSockets- (testServerClientDatagram addr cAddr)- ]- where- addr = fromJust $ socketAddressUnixPath unixPath- cAddr = fromJust $ socketAddressUnixPath clientUnixPath- closeSockets (server, client) = do- close server- close client- unlink unixPath- unlink clientUnixPath- -- Sockets with real pathname should be unlinked after closing- unlink path = fileExist path >>= flip when (removeLink path)--groupAbstractName :: TestTree-groupAbstractName = testGroup "Abstract path name"- [ testCase "connect to non-existing path name" $ bracket- unixSocketStream- close- (\s -> do- r <- try $ connect s addr- case r of- Left e | e == eConnectionRefused -> return ()- | otherwise -> throwIO e- Right () -> assertFailure "connection should have failed"- )- , testCase "server\\client stream" $ bracket- ( (,) <$> unixSocketStream <*> unixSocketStream)- closeSockets- (testServerClientStream addr)- , testCase "server\\client datagram" $ bracket- ((,) <$> unixSocketDatagram <*> unixSocketDatagram)- closeSockets- (testServerClientDatagram addr cAddr)- ]- where- addr = fromJust $ socketAddressUnixAbstract abstractPath- cAddr = fromJust $ socketAddressUnixAbstract clientAbstractPath- closeSockets (server, client) = do- close server- close client---clientMessage :: ByteString-clientMessage = "client message"--serverMessage :: ByteString-serverMessage = "server message"--unixPath :: IsString a => a-unixPath = "Woum5ag3oohuaLee.socket"--clientUnixPath :: IsString a => a-clientUnixPath = "Io4meo0epoquashi.socket"--abstractPath :: ByteString-abstractPath = "/tmp/uth4Aechiereejae.socket"--clientAbstractPath :: ByteString-clientAbstractPath = "/tmp/FieNg4shamo4Thie.socket"--unixSocketStream :: IO (Socket Unix Stream Unix)-unixSocketStream = socket--unixSocketDatagram :: IO (Socket Unix Datagram Unix)-unixSocketDatagram = socket--testServerClientStream- :: SocketAddress Unix- -> (Socket Unix Stream Unix, Socket Unix Stream Unix)- -> IO ()-testServerClientStream addr (server, client) = do- bind server addr- listen server 5- serverRecv <- async $ do- (peerSock, peerAddr) <- accept server- r <- receive peerSock 4096 mempty- send peerSock serverMessage mempty- pure r- connect client addr- send client clientMessage mempty-- clientMessageReceived <- wait serverRecv- serverMessageReceived <- receive client 4096 mempty- clientMessageReceived @?= clientMessage- serverMessageReceived @?= serverMessage--testServerClientDatagram- :: SocketAddress Unix- -> SocketAddress Unix- -> (Socket Unix Datagram Unix, Socket Unix Datagram Unix)- -> IO ()-testServerClientDatagram sAddr cAddr (server, client) = do- bind server sAddr- bind client cAddr- serverRecv <- async $ do- (r, peerAddr) <- receiveFrom server 4096 mempty- sendTo server serverMessage mempty peerAddr- pure r- sendTo client clientMessage mempty sAddr-- clientMessageReceived <- wait serverRecv- serverMessageReceived <- receive client 4096 mempty- clientMessageReceived @?= clientMessage- serverMessageReceived @?= serverMessage