    -- | Converting an address in 'SockAddr'.

    module Network.SockAddr (
        showSockAddr
      , showSockAddrBS
      ) where

    import Data.Bits (shift, (.&.))
    import Data.ByteString (ByteString)
    import qualified Data.ByteString.Char8 as BS (pack)
    import Network.Socket (SockAddr(..), HostAddress, HostAddress6)
    import System.ByteOrder
    import Text.Printf

    isReversed :: Bool
    isReversed :: Bool
    isReversed = ByteOrder
    byteOrder ByteOrder -> ByteOrder -> Bool
    forall a. Eq a => a -> a -> Bool
    == ByteOrder
    LittleEndian

    ----------------------------------------------------------------

    -- | Convert 'SockAddr' to 'String'. If the address is
    --   an IPv4-embedded IPv6 address, the IPv4 is extracted.
    --
    -- >>> import Network.Socket
    -- >>> as <- getAddrInfo (Just defaultHints) (Just "example.org") (Just "http")
    -- >>> map (showSockAddr.addrAddress) as
    -- ["93.184.216.119","93.184.216.119","2606:2800:220:6d:26bf:1447:1097:aa7","2606:2800:220:6d:26bf:1447:1097:aa7"]
    showSockAddr :: SockAddr -> String
    showSockAddr :: SockAddr -> String
    showSockAddr (SockAddrInet _ addr4 :: HostAddress
    addr4)                       = HostAddress -> Bool -> String
    showIPv4 HostAddress
    addr4 Bool
    isReversed
    showSockAddr (SockAddrInet6 _ _ (0,0,0x0000ffff,addr4 :: HostAddress
    addr4) _) = HostAddress -> Bool -> String
    showIPv4 HostAddress
    addr4 Bool
    False
    showSockAddr (SockAddrInet6 _ _ (0,0,0,1) _)              = "::1"
    showSockAddr (SockAddrInet6 _ _ addr6 :: HostAddress6
    addr6 _)                  = HostAddress6 -> String
    showIPv6 HostAddress6
    addr6
    showSockAddr _                                            = "unknownSocket"

    ----------------------------------------------------------------

    -- HostAddress is network byte order.
    showIPv4 :: HostAddress -> Bool-> String
    showIPv4 :: HostAddress -> Bool -> String
    showIPv4 w32 :: HostAddress
    w32 reversed :: Bool
    reversed
      | Bool
    reversed  = HostAddress -> String
    forall a. Show a => a -> String
    show HostAddress
    b1 String -> String -> String
    forall a. [a] -> [a] -> [a]
    ++ "." String -> String -> String
    forall a. [a] -> [a] -> [a]
    ++ HostAddress -> String
    forall a. Show a => a -> String
    show HostAddress
    b2 String -> String -> String
    forall a. [a] -> [a] -> [a]
    ++ "." String -> String -> String
    forall a. [a] -> [a] -> [a]
    ++ HostAddress -> String
    forall a. Show a => a -> String
    show HostAddress
    b3 String -> String -> String
    forall a. [a] -> [a] -> [a]
    ++ "." String -> String -> String
    forall a. [a] -> [a] -> [a]
    ++ HostAddress -> String
    forall a. Show a => a -> String
    show HostAddress
    b4
      | Bool
    otherwise = HostAddress -> String
    forall a. Show a => a -> String
    show HostAddress
    b4 String -> String -> String
    forall a. [a] -> [a] -> [a]
    ++ "." String -> String -> String
    forall a. [a] -> [a] -> [a]
    ++ HostAddress -> String
    forall a. Show a => a -> String
    show HostAddress
    b3 String -> String -> String
    forall a. [a] -> [a] -> [a]
    ++ "." String -> String -> String
    forall a. [a] -> [a] -> [a]
    ++ HostAddress -> String
    forall a. Show a => a -> String
    show HostAddress
    b2 String -> String -> String
    forall a. [a] -> [a] -> [a]
    ++ "." String -> String -> String
    forall a. [a] -> [a] -> [a]
    ++ HostAddress -> String
    forall a. Show a => a -> String
    show HostAddress
    b1
      where
        t1 :: HostAddress
    t1 = HostAddress
    w32
        t2 :: HostAddress
    t2 = HostAddress -> Int -> HostAddress
    forall a. Bits a => a -> Int -> a
    shift HostAddress
    t1 (-8)
        t3 :: HostAddress
    t3 = HostAddress -> Int -> HostAddress
    forall a. Bits a => a -> Int -> a
    shift HostAddress
    t2 (-8)
        t4 :: HostAddress
    t4 = HostAddress -> Int -> HostAddress
    forall a. Bits a => a -> Int -> a
    shift HostAddress
    t3 (-8)
        b1 :: HostAddress
    b1 = HostAddress
    t1 HostAddress -> HostAddress -> HostAddress
    forall a. Bits a => a -> a -> a
    .&. 0x000000ff
        b2 :: HostAddress
    b2 = HostAddress
    t2 HostAddress -> HostAddress -> HostAddress
    forall a. Bits a => a -> a -> a
    .&. 0x000000ff
        b3 :: HostAddress
    b3 = HostAddress
    t3 HostAddress -> HostAddress -> HostAddress
    forall a. Bits a => a -> a -> a
    .&. 0x000000ff
        b4 :: HostAddress
    b4 = HostAddress
    t4 HostAddress -> HostAddress -> HostAddress
    forall a. Bits a => a -> a -> a
    .&. 0x000000ff

    -- HostAddress6 is host byte order.
    showIPv6 :: HostAddress6 -> String
    showIPv6 :: HostAddress6 -> String
    showIPv6 (w1 :: HostAddress
    w1,w2 :: HostAddress
    w2,w3 :: HostAddress
    w3,w4 :: HostAddress
    w4) =
        String
    -> HostAddress
    -> HostAddress
    -> HostAddress
    -> HostAddress
    -> HostAddress
    -> HostAddress
    -> HostAddress
    -> HostAddress
    -> String
    forall r. PrintfType r => String -> r
    printf "%x:%x:%x:%x:%x:%x:%x:%x" HostAddress
    s1 HostAddress
    s2 HostAddress
    s3 HostAddress
    s4 HostAddress
    s5 HostAddress
    s6 HostAddress
    s7 HostAddress
    s8
      where
        (s1 :: HostAddress
    s1,s2 :: HostAddress
    s2) = HostAddress -> (HostAddress, HostAddress)
    forall a. (Bits a, Num a) => a -> (a, a)
    split16 HostAddress
    w1
        (s3 :: HostAddress
    s3,s4 :: HostAddress
    s4) = HostAddress -> (HostAddress, HostAddress)
    forall a. (Bits a, Num a) => a -> (a, a)
    split16 HostAddress
    w2
        (s5 :: HostAddress
    s5,s6 :: HostAddress
    s6) = HostAddress -> (HostAddress, HostAddress)
    forall a. (Bits a, Num a) => a -> (a, a)
    split16 HostAddress
    w3
        (s7 :: HostAddress
    s7,s8 :: HostAddress
    s8) = HostAddress -> (HostAddress, HostAddress)
    forall a. (Bits a, Num a) => a -> (a, a)
    split16 HostAddress
    w4
        split16 :: a -> (a, a)
    split16 w :: a
    w = (a
    h1,a
    h2)
          where
            h1 :: a
    h1 = a -> Int -> a
    forall a. Bits a => a -> Int -> a
    shift a
    w (-16) a -> a -> a
    forall a. Bits a => a -> a -> a
    .&. 0x0000ffff
            h2 :: a
    h2 = a
    w a -> a -> a
    forall a. Bits a => a -> a -> a
    .&. 0x0000ffff

    ----------------------------------------------------------------

    -- | Convert 'SockAddr' to 'ByteString'. If the address is
    --   an IPv4-embedded IPv6 address, the IPv4 is extracted.
    --
    -- >>> import Network.Socket
    -- >>> as <- getAddrInfo (Just defaultHints) (Just "localhost") (Just "http")
    -- >>> map (showSockAddrBS.addrAddress) as
    -- ["127.0.0.1","::1","fe80:0:0:0:0:0:0:1"]

    showSockAddrBS :: SockAddr -> ByteString
    showSockAddrBS :: SockAddr -> ByteString
    showSockAddrBS = String -> ByteString
    BS.pack (String -> ByteString)
    -> (SockAddr -> String) -> SockAddr -> ByteString
    forall b c a. (b -> c) -> (a -> b) -> a -> c
    . SockAddr -> String
    showSockAddr