{-# LINE 1 "Z/IO/Network/SocketAddr.hsc" #-}
{-|
Module      : Z.IO.Network.SocketAddr
Description : TCP/UDP socket address API
Copyright   : (c) Winterland, 2018
License     : BSD
Maintainer  : drkoster@qq.com
Stability   : experimental
Portability : non-portable

This module provides necessary types and constant for low level socket address manipulating.

-}

module Z.IO.Network.SocketAddr
  ( -- * name to address
    SocketAddr(..)
  , ipv4, ipv6
  , sockAddrFamily
  , withSocketAddr
  , withSocketAddrUnsafe
  , sizeOfSocketAddr
  , withSocketAddrStorage
  , withSocketAddrStorageUnsafe
  , sizeOfSocketAddrStorage
   -- ** IPv4 address
  , InetAddr(..)
  , inetAny
  , inetBroadcast
  , inetNone
  , inetLoopback
  , inetUnspecificGroup
  , inetAllHostsGroup
  , inetMaxLocalGroup
  , inetAddrToTuple
  , tupleToInetAddr
   -- ** IPv6 address
  , Inet6Addr(..)
  , inet6Any
  , inet6Loopback
  , inet6AddrToTuple
  , tupleToInet6Addr
  , FlowInfo
  , ScopeID
  -- * port numbber
  , PortNumber(..)
  , portAny
  -- * family, type, protocol
  , SocketFamily(AF_UNSPEC, AF_INET, AF_INET6)
  , SocketType(SOCK_DGRAM, SOCK_STREAM, SOCK_SEQPACKET, SOCK_RAW, SOCK_RDM, SOCK_ANY)
  , ProtocolNumber(IPPROTO_DEFAULT, IPPROTO_IP, IPPROTO_TCP, IPPROTO_UDP)
  -- * Internal helper
  , peekSocketAddr
  , pokeSocketAddr
  , peekSocketAddrMBA
  , pokeSocketAddrMBA
  , htons
  , ntohs
  , ntohl
  , htonl
  ) where

import           Data.Bits
import qualified Data.List                as List
import           Data.Typeable
import           Foreign
import           Foreign.C
import           GHC.Generics
import           Numeric                    (showHex)
import           System.IO.Unsafe
import           Z.Data.CBytes
import           Z.Data.Text.ShowT          (ShowT)
import           Z.IO.Exception
import           Z.IO.UV.Errno
import           Z.Foreign




{-# LINE 81 "Z/IO/Network/SocketAddr.hsc" #-}


{-# LINE 83 "Z/IO/Network/SocketAddr.hsc" #-}

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


{-# LINE 91 "Z/IO/Network/SocketAddr.hsc" #-}
type CSaFamily = (Word16)
{-# LINE 92 "Z/IO/Network/SocketAddr.hsc" #-}

{-# LINE 93 "Z/IO/Network/SocketAddr.hsc" #-}

-- | IPv4 or IPv6 socket address, i.e. the `sockaddr_in` or `sockaddr_in6` struct.
-- 
data SocketAddr
    = SocketAddrInet
        {-# UNPACK #-} !PortNumber  -- sin_port  (network byte order)
        {-# UNPACK #-} !InetAddr    -- sin_addr  (ditto)
    | SocketAddrInet6
        {-# UNPACK #-} !PortNumber  -- sin6_port (network byte order)
        {-# UNPACK #-} !FlowInfo    -- sin6_flowinfo (ditto)
        {-# UNPACK #-} !Inet6Addr   -- sin6_addr (ditto)
        {-# UNPACK #-} !ScopeID     -- sin6_scope_id (ditto)
  deriving (Eq, Ord, Typeable)

instance Show SocketAddr where
    showsPrec _ (SocketAddrInet port ia)
       = shows ia . showString ":" . shows port
    showsPrec _ (SocketAddrInet6 port _ ia6 _)
       = ('[':) . shows ia6 . showString "]:" . shows port

sockAddrFamily :: SocketAddr -> SocketFamily
sockAddrFamily (SocketAddrInet _ _) = AF_INET
sockAddrFamily (SocketAddrInet6 _ _ _ _) = AF_INET6

type FlowInfo = Word32
type ScopeID = Word32

-- | Convert a string containing an IPv4 addresses to a binary structure
--
-- This is partial function, wrong address will throw 'InvalidArgument' exception.
ipv4:: HasCallStack => CBytes -> PortNumber -> SocketAddr
ipv4 str (PortNumber port) = unsafeDupablePerformIO . withSocketAddrStorageUnsafe $ \ p ->
    withCBytesUnsafe str $ \ cstr -> throwUVIfMinus_ $ uv_ip4_addr cstr (fromIntegral port) p

-- | Convert a string containing an IPv6 addresses to a binary structure
--
-- This is partial function, wrong address will throw 'InvalidArgument' exception.
ipv6:: HasCallStack => CBytes -> PortNumber -> SocketAddr
ipv6 str (PortNumber port) = unsafeDupablePerformIO . withSocketAddrStorageUnsafe $ \ p ->
    withCBytesUnsafe str $ \ cstr -> throwUVIfMinus_ $ uv_ip6_addr cstr (fromIntegral port) p

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

-- | Independent of endianness. For example @127.0.0.1@ is stored as @(127, 0, 0, 1)@.
--
-- For direct manipulation prefer 'inetAddrToTuple' and 'tupleToInetAddr'.
--
newtype InetAddr = InetAddr { getInetAddr :: Word32 } deriving (Eq, Ord, Typeable)
instance Show InetAddr where
    showsPrec _ ia =
        let (a,b,c,d) = inetAddrToTuple ia
        in shows a . ('.':) . shows b . ('.':) . shows c . ('.':) . shows d

-- | @0.0.0.0@
inetAny             :: InetAddr
inetAny              = InetAddr 0

-- | @255.255.255.255@
inetBroadcast       :: InetAddr
inetBroadcast        = tupleToInetAddr (255,255,255,255)

-- | @255.255.255.255@
inetNone            :: InetAddr
inetNone             = tupleToInetAddr (255,255,255,255)

-- | @127.0.0.1@
inetLoopback        :: InetAddr
inetLoopback         = tupleToInetAddr (127,  0,  0,  1)

-- | @224.0.0.0@
inetUnspecificGroup :: InetAddr
inetUnspecificGroup  = tupleToInetAddr (224,  0,  0,  0)

-- | @224.0.0.1@
inetAllHostsGroup   :: InetAddr
inetAllHostsGroup    = tupleToInetAddr (224,  0,  0,  1)

-- | @224.0.0.255@
inetMaxLocalGroup   :: InetAddr
inetMaxLocalGroup    = tupleToInetAddr (224,  0,  0,255)

instance Storable InetAddr where
    sizeOf _ = 4
    alignment _ = alignment (undefined :: Word32)
    peek p = (InetAddr . ntohl) `fmap` peekByteOff p 0
    poke p (InetAddr ia) = pokeByteOff p 0 (htonl ia)

instance Unaligned InetAddr where
    unalignedSize _ = 4
    pokeMBA p off x = pokeMBA p off (htonl (getInetAddr x))
    peekMBA p off = InetAddr . ntohl <$> peekMBA p off
    indexBA p off = InetAddr (ntohl (indexBA p off))

-- | Converts 'InetAddr' to representation-independent IPv4 quadruple.
-- For example for @127.0.0.1@ the function will return @(127, 0, 0, 1)@
-- regardless of host endianness.
inetAddrToTuple :: InetAddr -> (Word8, Word8, Word8, Word8)
inetAddrToTuple (InetAddr ia) =
    let byte i = fromIntegral (ia `shiftR` i) :: Word8
    in (byte 24, byte 16, byte 8, byte 0)

-- | Converts IPv4 quadruple to 'InetAddr'.
tupleToInetAddr :: (Word8, Word8, Word8, Word8) -> InetAddr
tupleToInetAddr (b3, b2, b1, b0) =
    let x `sl` i = fromIntegral x `shiftL` i :: Word32
    in InetAddr $ (b3 `sl` 24) .|. (b2 `sl` 16) .|. (b1 `sl` 8) .|. (b0 `sl` 0)

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

-- | Independent of endianness. For example @::1@ is stored as @(0, 0, 0, 1)@.
--
-- For direct manipulation prefer 'inet6AddrToTuple' and 'tupleToInet6Addr'.
--
data Inet6Addr = Inet6Addr {-# UNPACK #-}!Word32
                           {-# UNPACK #-}!Word32
                           {-# UNPACK #-}!Word32
                           {-# UNPACK #-}!Word32 deriving (Eq, Ord, Typeable)


instance Show Inet6Addr where
    showsPrec _ ia6@(Inet6Addr a1 a2 a3 a4)
        -- IPv4-Mapped IPv6 Address
        | a1 == 0 && a2 == 0 && a3 == 0xffff =
          showString "::ffff:" . shows (InetAddr a4)
        -- IPv4-Compatible IPv6 Address (exclude IPRange ::/112)
        | a1 == 0 && a2 == 0 && a3 == 0 && a4 >= 0x10000 =
            showString "::" . shows (InetAddr a4)
        -- length of longest run > 1, replace it with "::"
        | end - begin > 1 =
            showFields prefix . showString "::" . showFields suffix
        | otherwise =
            showFields fields
      where
        fields =
            let (u7, u6, u5, u4, u3, u2, u1, u0) = inet6AddrToTuple ia6 in
            [u7, u6, u5, u4, u3, u2, u1, u0]
        showFields = foldr (.) id . List.intersperse (':':) . map showHex
        prefix = take begin fields  -- fields before "::"
        suffix = drop end fields    -- fields after "::"
        begin = end + diff          -- the longest run of zeros
        (diff, end) = minimum $
            scanl (\c i -> if i == 0 then c - 1 else 0) 0 fields `zip` [0..]

-- | @::@
inet6Any      :: Inet6Addr
inet6Any       = Inet6Addr 0 0 0 0

-- | @::1@
inet6Loopback :: Inet6Addr
inet6Loopback  = Inet6Addr 0 0 0 1

-- | convert 'Inet6Addr' to octets.
inet6AddrToTuple :: Inet6Addr -> (Word16, Word16, Word16, Word16,
                                        Word16, Word16, Word16, Word16)
inet6AddrToTuple (Inet6Addr w3 w2 w1 w0) =
    let high, low :: Word32 -> Word16
        high w = fromIntegral (w `shiftR` 16)
        low w = fromIntegral w
    in (high w3, low w3, high w2, low w2, high w1, low w1, high w0, low w0)

-- | convert 'Inet6Addr' from octets.
tupleToInet6Addr :: (Word16, Word16, Word16, Word16,
                        Word16, Word16, Word16, Word16) -> Inet6Addr
tupleToInet6Addr (w7, w6, w5, w4, w3, w2, w1, w0) =
    let add :: Word16 -> Word16 -> Word32
        high `add` low = (fromIntegral high `shiftL` 16) .|. (fromIntegral low)
    in  Inet6Addr (w7 `add` w6) (w5 `add` w4) (w3 `add` w2) (w1 `add` w0)

instance Storable Inet6Addr where
    sizeOf _    = (16)
{-# LINE 263 "Z/IO/Network/SocketAddr.hsc" #-}
    alignment _ = 4
{-# LINE 264 "Z/IO/Network/SocketAddr.hsc" #-}
    peek p = do
        a <- peek32 p 0
        b <- peek32 p 1
        c <- peek32 p 2
        d <- peek32 p 3
        return $ Inet6Addr a b c d
    poke p (Inet6Addr a b c d) = do
        poke32 p 0 a
        poke32 p 1 b
        poke32 p 2 c
        poke32 p 3 d


s6_addr_offset :: Int
s6_addr_offset = ((0))
{-# LINE 279 "Z/IO/Network/SocketAddr.hsc" #-}

peek32 :: Ptr a -> Int -> IO Word32
peek32 p i0 = do
    let i' = i0 * 4
        peekByte n = peekByteOff p (s6_addr_offset + i' + n) :: IO Word8
        a `sl` i = fromIntegral a `shiftL` i
    a0 <- peekByte 0
    a1 <- peekByte 1
    a2 <- peekByte 2
    a3 <- peekByte 3
    return ((a0 `sl` 24) .|. (a1 `sl` 16) .|. (a2 `sl` 8) .|. (a3 `sl` 0))

poke32 :: Ptr a -> Int -> Word32 -> IO ()
poke32 p i0 a = do
    let i' = i0 * 4
        pokeByte n = pokeByteOff p (s6_addr_offset + i' + n)
        x `sr` i = fromIntegral (x `shiftR` i) :: Word8
    pokeByte 0 (a `sr` 24)
    pokeByte 1 (a `sr` 16)
    pokeByte 2 (a `sr`  8)
    pokeByte 3 (a `sr`  0)

instance Unaligned Inet6Addr where
    unalignedSize _ = ((16))
{-# LINE 303 "Z/IO/Network/SocketAddr.hsc" #-}

    indexBA p off =
        let a = indexBA p (off + s6_addr_offset + 0)
            b = indexBA p  (off + s6_addr_offset + 4)
            c = indexBA p  (off + s6_addr_offset + 8)
            d = indexBA p  (off + s6_addr_offset + 12)
        in Inet6Addr (getBE a) (getBE b) (getBE c) (getBE d)

    peekMBA p off = do
        a <- peekMBA p (off + s6_addr_offset + 0)
        b <- peekMBA p  (off + s6_addr_offset + 4)
        c <- peekMBA p  (off + s6_addr_offset + 8)
        d <- peekMBA p  (off + s6_addr_offset + 12)
        return $ Inet6Addr (getBE a) (getBE b) (getBE c) (getBE d)

    pokeMBA p off (Inet6Addr a b c d) = do
        pokeMBA p (off + s6_addr_offset) (BE a)
        pokeMBA p (off + 4 + s6_addr_offset) (BE b)
        pokeMBA p (off + 8 + s6_addr_offset) (BE c)
        pokeMBA p (off + 12 + s6_addr_offset) (BE d)

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

peekSocketAddr :: HasCallStack => Ptr SocketAddr -> IO SocketAddr
peekSocketAddr p = do
    family <- ((\hsc_ptr -> peekByteOff hsc_ptr 0)) p
{-# LINE 329 "Z/IO/Network/SocketAddr.hsc" #-}
    case family :: CSaFamily of
        (2) -> do
{-# LINE 331 "Z/IO/Network/SocketAddr.hsc" #-}
            addr <- ((\hsc_ptr -> peekByteOff hsc_ptr 4)) p
{-# LINE 332 "Z/IO/Network/SocketAddr.hsc" #-}
            port <- ((\hsc_ptr -> peekByteOff hsc_ptr 2)) p
{-# LINE 333 "Z/IO/Network/SocketAddr.hsc" #-}
            return (SocketAddrInet port addr)
        (10) -> do
{-# LINE 335 "Z/IO/Network/SocketAddr.hsc" #-}
            port <- ((\hsc_ptr -> peekByteOff hsc_ptr 2)) p
{-# LINE 336 "Z/IO/Network/SocketAddr.hsc" #-}
            flow <- ((\hsc_ptr -> peekByteOff hsc_ptr 4)) p
{-# LINE 337 "Z/IO/Network/SocketAddr.hsc" #-}
            addr <- ((\hsc_ptr -> peekByteOff hsc_ptr 8)) p
{-# LINE 338 "Z/IO/Network/SocketAddr.hsc" #-}
            scope <- ((\hsc_ptr -> peekByteOff hsc_ptr 24)) p
{-# LINE 339 "Z/IO/Network/SocketAddr.hsc" #-}
            return (SocketAddrInet6 port flow addr scope)
        _ -> do let errno = UV_EAI_ADDRFAMILY
                name <- uvErrName errno
                desc <- uvStdError errno
                throwUVError errno (IOEInfo name desc callStack)

pokeSocketAddr :: Ptr SocketAddr -> SocketAddr -> IO ()
pokeSocketAddr p (SocketAddrInet port addr) =  do

{-# LINE 350 "Z/IO/Network/SocketAddr.hsc" #-}

{-# LINE 353 "Z/IO/Network/SocketAddr.hsc" #-}
    ((\hsc_ptr -> pokeByteOff hsc_ptr 0)) p ((2) :: CSaFamily)
{-# LINE 354 "Z/IO/Network/SocketAddr.hsc" #-}
    ((\hsc_ptr -> pokeByteOff hsc_ptr 2)) p port
{-# LINE 355 "Z/IO/Network/SocketAddr.hsc" #-}
    ((\hsc_ptr -> pokeByteOff hsc_ptr 4)) p addr
{-# LINE 356 "Z/IO/Network/SocketAddr.hsc" #-}
pokeSocketAddr p (SocketAddrInet6 port flow addr scope) =  do

{-# LINE 360 "Z/IO/Network/SocketAddr.hsc" #-}

{-# LINE 363 "Z/IO/Network/SocketAddr.hsc" #-}
    ((\hsc_ptr -> pokeByteOff hsc_ptr 0)) p ((10) :: CSaFamily)
{-# LINE 364 "Z/IO/Network/SocketAddr.hsc" #-}
    ((\hsc_ptr -> pokeByteOff hsc_ptr 2)) p port
{-# LINE 365 "Z/IO/Network/SocketAddr.hsc" #-}
    ((\hsc_ptr -> pokeByteOff hsc_ptr 4)) p flow
{-# LINE 366 "Z/IO/Network/SocketAddr.hsc" #-}
    ((\hsc_ptr -> pokeByteOff hsc_ptr 8)) p (addr)
{-# LINE 367 "Z/IO/Network/SocketAddr.hsc" #-}
    ((\hsc_ptr -> pokeByteOff hsc_ptr 24)) p scope
{-# LINE 368 "Z/IO/Network/SocketAddr.hsc" #-}


-- | Pass 'SocketAddr' to FFI as pointer.
--
withSocketAddr :: SocketAddr -> (Ptr SocketAddr -> IO a) -> IO a
withSocketAddr sa@(SocketAddrInet _ _) f = do
    allocaBytesAligned
        ((16))
{-# LINE 376 "Z/IO/Network/SocketAddr.hsc" #-}
        (4) $ \ p -> pokeSocketAddr p sa >> f p
{-# LINE 377 "Z/IO/Network/SocketAddr.hsc" #-}
withSocketAddr sa@(SocketAddrInet6 _ _ _ _) f = do
    allocaBytesAligned
        ((28))
{-# LINE 380 "Z/IO/Network/SocketAddr.hsc" #-}
        (4) $ \ p -> pokeSocketAddr p sa >> f p
{-# LINE 381 "Z/IO/Network/SocketAddr.hsc" #-}

-- | Pass 'SocketAddr' to FFI as pointer.
--
-- USE THIS FUNCTION WITH UNSAFE FFI CALL ONLY.
--
withSocketAddrUnsafe :: SocketAddr -> (MBA# SocketAddr -> IO a) -> IO a
withSocketAddrUnsafe sa@(SocketAddrInet _ _) f = do
    (MutableByteArray p) <- newByteArray ((16))
{-# LINE 389 "Z/IO/Network/SocketAddr.hsc" #-}
    pokeSocketAddrMBA p sa
    f p
withSocketAddrUnsafe sa@(SocketAddrInet6 _ _ _ _) f = do
    (MutableByteArray p) <- newByteArray ((28))
{-# LINE 393 "Z/IO/Network/SocketAddr.hsc" #-}
    pokeSocketAddrMBA p sa
    f p

sizeOfSocketAddr :: SocketAddr -> CSize
sizeOfSocketAddr (SocketAddrInet _ _) = (16)
{-# LINE 398 "Z/IO/Network/SocketAddr.hsc" #-}
sizeOfSocketAddr (SocketAddrInet6 _ _ _ _) = (28)
{-# LINE 399 "Z/IO/Network/SocketAddr.hsc" #-}

-- | Allocate space for 'sockaddr_storage' and pass to FFI.
withSocketAddrStorage :: (Ptr SocketAddr -> IO ()) -> IO SocketAddr
withSocketAddrStorage f = do
    allocaBytesAligned
        ((128))
{-# LINE 405 "Z/IO/Network/SocketAddr.hsc" #-}
        (8) $ \ p -> f p >> peekSocketAddr p
{-# LINE 406 "Z/IO/Network/SocketAddr.hsc" #-}

-- | Allocate space for 'sockaddr_storage' and pass to FFI.
--
-- USE THIS FUNCTION WITH UNSAFE FFI CALL ONLY.
--
withSocketAddrStorageUnsafe :: (MBA# SocketAddr -> IO ()) -> IO SocketAddr
withSocketAddrStorageUnsafe f = do
    (MutableByteArray p) <- newByteArray ((128))
{-# LINE 414 "Z/IO/Network/SocketAddr.hsc" #-}
    f p
    peekSocketAddrMBA p

sizeOfSocketAddrStorage :: CSize
sizeOfSocketAddrStorage = ((128))
{-# LINE 419 "Z/IO/Network/SocketAddr.hsc" #-}

peekSocketAddrMBA :: HasCallStack => MBA# SocketAddr -> IO SocketAddr
peekSocketAddrMBA p = do
    family <- peekMBA p ((0))
{-# LINE 423 "Z/IO/Network/SocketAddr.hsc" #-}
    case family :: CSaFamily of
        (2) -> do
{-# LINE 425 "Z/IO/Network/SocketAddr.hsc" #-}
            addr <- peekMBA p ((4))
{-# LINE 426 "Z/IO/Network/SocketAddr.hsc" #-}
            port <- peekMBA p ((2))
{-# LINE 427 "Z/IO/Network/SocketAddr.hsc" #-}
            return (SocketAddrInet port addr)
        (10) -> do
{-# LINE 429 "Z/IO/Network/SocketAddr.hsc" #-}
            port <- peekMBA p ((2))
{-# LINE 430 "Z/IO/Network/SocketAddr.hsc" #-}
            flow <- peekMBA p ((4))
{-# LINE 431 "Z/IO/Network/SocketAddr.hsc" #-}
            addr <- peekMBA p ((8))
{-# LINE 432 "Z/IO/Network/SocketAddr.hsc" #-}
            scope <- peekMBA p ((24))
{-# LINE 433 "Z/IO/Network/SocketAddr.hsc" #-}
            return (SocketAddrInet6 port flow addr scope)
        _ -> do let errno = UV_EAI_ADDRFAMILY
                name <- uvErrName errno
                desc <- uvStdError errno
                throwUVError errno (IOEInfo name desc callStack)

pokeSocketAddrMBA :: MBA# SocketAddr -> SocketAddr -> IO ()
pokeSocketAddrMBA p (SocketAddrInet port addr) =  do

{-# LINE 444 "Z/IO/Network/SocketAddr.hsc" #-}

{-# LINE 447 "Z/IO/Network/SocketAddr.hsc" #-}
    pokeMBA p ((0)) ((2) :: CSaFamily)
{-# LINE 448 "Z/IO/Network/SocketAddr.hsc" #-}
    pokeMBA p ((2)) port
{-# LINE 449 "Z/IO/Network/SocketAddr.hsc" #-}
    pokeMBA p ((4)) addr
{-# LINE 450 "Z/IO/Network/SocketAddr.hsc" #-}
pokeSocketAddrMBA p (SocketAddrInet6 port flow addr scope) =  do

{-# LINE 454 "Z/IO/Network/SocketAddr.hsc" #-}

{-# LINE 457 "Z/IO/Network/SocketAddr.hsc" #-}
    pokeMBA p ((0)) ((10) :: CSaFamily)
{-# LINE 458 "Z/IO/Network/SocketAddr.hsc" #-}
    pokeMBA p ((2)) port
{-# LINE 459 "Z/IO/Network/SocketAddr.hsc" #-}
    pokeMBA p ((4)) flow
{-# LINE 460 "Z/IO/Network/SocketAddr.hsc" #-}
    pokeMBA p ((8)) (addr)
{-# LINE 461 "Z/IO/Network/SocketAddr.hsc" #-}
    pokeMBA p ((24)) scope
{-# LINE 462 "Z/IO/Network/SocketAddr.hsc" #-}

--------------------------------------------------------------------------------
-- Port Numbers

-- | Port number.
--   Use the @Num@ instance (i.e. use a literal) to create a
--   @PortNumber@ value.
--
-- >>> 1 :: PortNumber
-- 1
-- >>> read "1" :: PortNumber
-- 1
-- >>> show (12345 :: PortNumber)
-- "12345"
-- >>> 50000 < (51000 :: PortNumber)
-- True
-- >>> 50000 < (52000 :: PortNumber)
-- True
-- >>> 50000 + (10000 :: PortNumber)
-- 60000
newtype PortNumber = PortNumber Word16 deriving (Eq, Ord, Enum, Generic)
                                        deriving newtype (Show, Read, Num, Bounded, Real, Integral)
                                        deriving anyclass ShowT

-- | @:0@
portAny :: PortNumber
portAny = PortNumber 0

instance Storable PortNumber where
   sizeOf    _ = sizeOf    (0 :: Word16)
   alignment _ = alignment (0 :: Word16)
   poke p (PortNumber po) = poke (castPtr p) (htons po)
   peek p = PortNumber . ntohs <$> peek (castPtr p)

instance Unaligned PortNumber where
   unalignedSize _ = 2
   indexBA p off = PortNumber . ntohs $ indexBA p off
   pokeMBA p off (PortNumber po) = pokeMBA p off (htons po)
   peekMBA p off = PortNumber . ntohs <$> peekMBA p off

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

newtype SocketFamily = SocketFamily CInt
    deriving (Eq, Ord, Read, Show, Typeable)
newtype SocketType = SocketType CInt
    deriving (Eq, Ord, Read, Show, Typeable)
newtype ProtocolNumber = ProtocolNumber CInt
    deriving (Eq, Ord, Read, Show, Typeable)

instance Storable SocketFamily where
    sizeOf _ = sizeOf (undefined :: CInt)
    alignment _ = alignment (undefined :: CInt)
    peek ptr = SocketFamily `fmap` peek (castPtr ptr)
    poke ptr (SocketFamily v) = poke (castPtr ptr) v

instance Storable SocketType where
    sizeOf _ = sizeOf (undefined :: CInt)
    alignment _ = alignment (undefined :: CInt)
    peek ptr = SocketType `fmap` peek (castPtr ptr)
    poke ptr (SocketType v) = poke (castPtr ptr) v

instance Storable ProtocolNumber where
    sizeOf _ = sizeOf (undefined :: CInt)
    alignment _ = alignment (undefined :: CInt)
    peek ptr = ProtocolNumber `fmap` peek (castPtr ptr)
    poke ptr (ProtocolNumber v) = poke (castPtr ptr) v

-- | unspecified
pattern AF_UNSPEC :: SocketFamily
pattern AF_UNSPEC = SocketFamily (0)
{-# LINE 532 "Z/IO/Network/SocketAddr.hsc" #-}
-- | internetwork: UDP, TCP, etc
pattern AF_INET :: SocketFamily
pattern AF_INET = SocketFamily (2)
{-# LINE 535 "Z/IO/Network/SocketAddr.hsc" #-}
-- | Internet Protocol version 6
pattern AF_INET6 :: SocketFamily
pattern AF_INET6 = SocketFamily (10)
{-# LINE 538 "Z/IO/Network/SocketAddr.hsc" #-}

pattern SOCK_STREAM :: SocketType
pattern SOCK_STREAM = SocketType (1)
{-# LINE 541 "Z/IO/Network/SocketAddr.hsc" #-}
pattern SOCK_DGRAM :: SocketType
pattern SOCK_DGRAM = SocketType (2)
{-# LINE 543 "Z/IO/Network/SocketAddr.hsc" #-}
pattern SOCK_RAW :: SocketType
pattern SOCK_RAW = SocketType (3)
{-# LINE 545 "Z/IO/Network/SocketAddr.hsc" #-}
pattern SOCK_RDM :: SocketType
pattern SOCK_RDM = SocketType (4)
{-# LINE 547 "Z/IO/Network/SocketAddr.hsc" #-}
pattern SOCK_SEQPACKET :: SocketType
pattern SOCK_SEQPACKET = SocketType (5)
{-# LINE 549 "Z/IO/Network/SocketAddr.hsc" #-}
-- | Used in getAddrInfo hints, for any type can be returned by getAddrInfo
pattern SOCK_ANY :: SocketType
pattern SOCK_ANY = SocketType 0

pattern IPPROTO_DEFAULT :: ProtocolNumber
pattern IPPROTO_DEFAULT = ProtocolNumber 0
pattern IPPROTO_IP :: ProtocolNumber
pattern IPPROTO_IP = ProtocolNumber (0)
{-# LINE 557 "Z/IO/Network/SocketAddr.hsc" #-}
pattern IPPROTO_TCP :: ProtocolNumber
pattern IPPROTO_TCP = ProtocolNumber (6)
{-# LINE 559 "Z/IO/Network/SocketAddr.hsc" #-}
pattern IPPROTO_UDP :: ProtocolNumber
pattern IPPROTO_UDP = ProtocolNumber (17)
{-# LINE 561 "Z/IO/Network/SocketAddr.hsc" #-}

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

foreign import ccall unsafe "ntohs" ntohs :: Word16 -> Word16
{-# LINE 565 "Z/IO/Network/SocketAddr.hsc" #-}
foreign import ccall unsafe "htons" htons :: Word16 -> Word16
{-# LINE 566 "Z/IO/Network/SocketAddr.hsc" #-}
foreign import ccall unsafe "ntohl" ntohl :: Word32 -> Word32
{-# LINE 567 "Z/IO/Network/SocketAddr.hsc" #-}
foreign import ccall unsafe "htonl" htonl :: Word32 -> Word32
{-# LINE 568 "Z/IO/Network/SocketAddr.hsc" #-}

foreign import ccall unsafe uv_ip4_addr :: BA# Word8 -> CInt -> MBA# SocketAddr -> IO CInt
foreign import ccall unsafe uv_ip6_addr :: BA# Word8 -> CInt -> MBA# SocketAddr -> IO CInt