Skip to content

Commit

Permalink
Add Read instances for SockAddr/SockEndpoint, make Show instances fol…
Browse files Browse the repository at this point in the history
…low contract

The old Show behaviour is moved into the 'showSockAddr' function, with a new
function 'readSockAddr' that acts as its opposite.
  • Loading branch information
infinity0 committed May 26, 2020
1 parent d25c4c3 commit 19217bd
Show file tree
Hide file tree
Showing 5 changed files with 26 additions and 15 deletions.
2 changes: 2 additions & 0 deletions Network/Socket.hs
Original file line number Diff line number Diff line change
Expand Up @@ -190,6 +190,8 @@ module Network.Socket
, resolveEndpoint
-- * Basic socket address type
, SockAddr(..)
, readSockAddr
, showSockAddr
, sockAddrFamily
, isSupportedSockAddr
, getPeerName
Expand Down
25 changes: 17 additions & 8 deletions Network/Socket/Info.hsc
Original file line number Diff line number Diff line change
Expand Up @@ -242,7 +242,9 @@ defaultHints = AddrInfo {
--
-- >>> addr:_ <- getAddrInfo (Just hints) (Just "127.0.0.1") (Just "http")
-- >>> addrAddress addr
-- 127.0.0.1:80
-- SockAddrInet 80 16777343
-- >>> showSockAddr (addrAddress addr)
-- "127.0.0.1:80"

getAddrInfo
:: Maybe AddrInfo -- ^ preferred socket type or protocol
Expand Down Expand Up @@ -415,22 +417,29 @@ unpackBits ((k,v):xs) r
-----------------------------------------------------------------------------
-- SockAddr

instance Show SockAddr where
-- | Read a string representing a socket address.
readSockAddr :: PortNumber -> String -> Either String SockAddr
readSockAddr defPort hostport = readSockEndpoint defPort hostport >>= \r -> case r of
EndpointByName h _ -> Left $ "expected address but got hostname: " <> h
EndpointByAddr a -> Right a

showSockAddr :: SockAddr -> String
#if defined(DOMAIN_SOCKET_SUPPORT)
showsPrec _ (SockAddrUnix str) = showString str
showSockAddr (SockAddrUnix str) = showString str ""
#else
showsPrec _ SockAddrUnix{} = error "showsPrec: not supported"
showSockAddr SockAddrUnix{} = error "showsPrec: not supported"
#endif
showsPrec _ (SockAddrInet port ha)
showSockAddr (SockAddrInet port ha)
= showHostAddress ha
. showString ":"
. shows port
showsPrec _ (SockAddrInet6 port _ ha6 _)
$ ""
showSockAddr (SockAddrInet6 port _ ha6 _)
= showChar '['
. showHostAddress6 ha6
. showString "]:"
. shows port

$ ""

-- Taken from on the implementation of showIPv4 in Data.IP.Addr
showHostAddress :: HostAddress -> ShowS
Expand Down Expand Up @@ -512,7 +521,7 @@ readSockEndpoint defPort hostport = case hostport of
showSockEndpoint :: SockEndpoint -> String
showSockEndpoint n = case n of
EndpointByName h p -> h <> ":" <> show p
EndpointByAddr a -> show a
EndpointByAddr a -> showSockAddr a

-- | Resolve a socket endpoint into a list of socket addresses.
-- The result is always non-empty; Haskell throws an exception if name
Expand Down
2 changes: 1 addition & 1 deletion Network/Socket/Syscall.hs
Original file line number Diff line number Diff line change
Expand Up @@ -68,7 +68,7 @@ import Network.Socket.Types
-- >>> sock <- socket (addrFamily addr) (addrSocketType addr) (addrProtocol addr)
-- >>> Network.Socket.bind sock (addrAddress addr)
-- >>> getSocketName sock
-- 127.0.0.1:5000
-- SockAddrInet 5000 16777343
socket :: Family -- Family Name (usually AF_INET)
-> SocketType -- Socket Type (usually Stream)
-> ProtocolNumber -- Protocol Number (getProtocolByName to find value)
Expand Down
4 changes: 2 additions & 2 deletions Network/Socket/Types.hsc
Original file line number Diff line number Diff line change
Expand Up @@ -1058,7 +1058,7 @@ type ScopeID = Word32
data SockEndpoint
= EndpointByName !String !PortNumber
| EndpointByAddr !SockAddr
deriving (Eq, Ord)
deriving (Eq, Ord, Read, Show)

-- | Socket addresses.
-- The existence of a constructor does not necessarily imply that
Expand All @@ -1076,7 +1076,7 @@ data SockAddr
-- | The path must have fewer than 104 characters. All of these characters must have code points less than 256.
| SockAddrUnix
String -- sun_path
deriving (Eq, Ord)
deriving (Eq, Ord, Read, Show)

instance NFData SockAddr where
rnf (SockAddrInet _ _) = ()
Expand Down
8 changes: 4 additions & 4 deletions tests/Network/SocketSpec.hs
Original file line number Diff line number Diff line change
Expand Up @@ -320,20 +320,20 @@ spec = do
describe "show SocketAddr" $ do
it "works for IPv4 address" $
let addr = SockAddrInet 80 (tupleToHostAddress (127, 0, 0, 1)) in
show addr `shouldBe` "127.0.0.1:80"
showSockAddr addr `shouldBe` "127.0.0.1:80"

it "works for IPv6 address" $
let addr = SockAddrInet6 80 0
(tupleToHostAddress6 (0x2001, 0x0db8, 0x2, 0x3, 0x4, 0x5, 0x6, 0x7)) 0 in
show addr `shouldBe` "[2001:db8:2:3:4:5:6:7]:80"
showSockAddr addr `shouldBe` "[2001:db8:2:3:4:5:6:7]:80"

it "works for IPv6 address with zeros" $
let addr = SockAddrInet6 80 0
(tupleToHostAddress6 (0x2001, 0x0db8, 0x2, 0x3, 0x0, 0x0, 0x0, 0x7)) 0 in
show addr `shouldBe` "[2001:db8:2:3::7]:80"
showSockAddr addr `shouldBe` "[2001:db8:2:3::7]:80"

it "works for multicast IPv6 address with reserved scope" $ do
let addr = SockAddrInet6 80 0
(tupleToHostAddress6 (0xff01, 0x1234, 0x2, 0x3, 0x4, 0x5, 0x6, 0x7)) 0
show addr `shouldBe` "[ff01:1234:2:3:4:5:6:7]:80"
showSockAddr addr `shouldBe` "[ff01:1234:2:3:4:5:6:7]:80"

0 comments on commit 19217bd

Please sign in to comment.