{-# LINE 1 "src/System/Socket/Family/Inet.hsc" #-}
{-# LANGUAGE TypeFamilies, GeneralizedNewtypeDeriving #-}
{-# LINE 2 "src/System/Socket/Family/Inet.hsc" #-}
module System.Socket.Family.Inet
  ( Inet
  -- * Addresses
  , SocketAddressInet (..)
  , Address ()
  , Port (..)
  -- ** Special Address Constants
  -- *** allHostsGroup
  , allHostsGroup
  -- *** any
  , System.Socket.Family.Inet.any
  -- *** broadcast
  , broadcast
  -- *** loopback
  , loopback
  -- *** maxLocalGroup
  , maxLocalGroup
  -- *** none
  , none
  -- *** unspecificGroup
  , unspecificGroup
  -- * Socket Options
  ) where

import Data.Word
import Data.List
import qualified Data.ByteString as BS
import qualified Data.ByteString.Unsafe as BS

import Control.Applicative

import Foreign.Ptr
import Foreign.Storable
import Foreign.Marshal.Utils

import System.Socket.Family
import System.Socket.Internal.Platform


{-# LINE 41 "src/System/Socket/Family/Inet.hsc" #-}

{-# LINE 42 "src/System/Socket/Family/Inet.hsc" #-}

data Inet

instance Family Inet where
  type SocketAddress Inet = SocketAddressInet
  familyNumber _ = (2)
{-# LINE 48 "src/System/Socket/Family/Inet.hsc" #-}

data SocketAddressInet
   = SocketAddressInet
     { address   :: Address
     , port      :: Port
     } deriving (Eq, Show)

newtype Port
      = Port Word16
      deriving (Eq, Ord, Num)

instance Show Port where
  show (Port p) = show p

-- | To avoid errors with endianess it was decided to keep this type abstract.
--
--   Hint: Use the `Foreign.Storable.Storable` instance if you really need to access. It exposes it
--   exactly as found within an IP packet (big endian if you insist
--   on interpreting it as a number).
--
--   Another hint: Use `System.Socket.getAddressInfo` for parsing and suppress
--   nameserver lookups:
--
--   > > getAddressInfo (Just "127.0.0.1") Nothing aiNumericHost :: IO [AddressInfo Inet Stream TCP]
--   > [AddressInfo {addressInfoFlags = AddressInfoFlags 4, socketAddress = SocketAddressInet { address = 127.0.0.1, port = 0}, canonicalName = Nothing}]
newtype Address
      = Address BS.ByteString
      deriving (Eq)

-- | @0.0.0.0@
any             :: Address
any              = Address $ BS.pack [  0,  0,  0,  0]

-- | @255.255.255.255@
broadcast       :: Address
broadcast        = Address $ BS.pack [255,255,255,255]

-- | @255.255.255.255@
none            :: Address
none             = Address $ BS.pack [255,255,255,255]

-- | @127.0.0.1@
loopback        :: Address
loopback         = Address $ BS.pack [127,  0,  0,  1]

-- | @224.0.0.0@
unspecificGroup :: Address
unspecificGroup  = Address $ BS.pack [224,  0,  0,  0]

-- | @224.0.0.1@
allHostsGroup   :: Address
allHostsGroup    = Address $ BS.pack [224,  0,  0,  1]

-- | @224.0.0.255@
maxLocalGroup   :: Address
maxLocalGroup    = Address $ BS.pack [224,  0,  0,255]

instance Show Address where
  show (Address a) =
    concat $ intersperse "." $ map show $ BS.unpack a

instance Storable Address where
  sizeOf   _  = ((4))
{-# LINE 111 "src/System/Socket/Family/Inet.hsc" #-}
  alignment _ = (4)
{-# LINE 112 "src/System/Socket/Family/Inet.hsc" #-}
  peek ptr    =
    Address <$> BS.packCStringLen (castPtr ptr, 4)
  poke ptr (Address a) =
    BS.unsafeUseAsCString a $ \aPtr-> do
      copyBytes ptr (castPtr aPtr) (min 4 $ BS.length a)

instance Storable SocketAddressInet where
  sizeOf    _ = ((16))
{-# LINE 120 "src/System/Socket/Family/Inet.hsc" #-}
  alignment _ = (4)
{-# LINE 121 "src/System/Socket/Family/Inet.hsc" #-}
  peek ptr    = do
    ph  <- peekByteOff (sin_port ptr)  0 :: IO Word8
    pl  <- peekByteOff (sin_port ptr)  1 :: IO Word8
    a   <- peek        (sin_addr ptr)    :: IO Address
    return (SocketAddressInet a (Port $ fromIntegral ph * 256 + fromIntegral pl))
    where
      sin_port     = ((\hsc_ptr -> hsc_ptr `plusPtr` 2))
{-# LINE 128 "src/System/Socket/Family/Inet.hsc" #-}
      sin_addr     = ((\hsc_ptr -> hsc_ptr `plusPtr` 0)) . ((\hsc_ptr -> hsc_ptr `plusPtr` 4))
{-# LINE 129 "src/System/Socket/Family/Inet.hsc" #-}
  poke ptr (SocketAddressInet a (Port p)) = do
    c_memset ptr 0 (16)
{-# LINE 131 "src/System/Socket/Family/Inet.hsc" #-}
    poke        (sin_family   ptr) ((2) :: Word16)
{-# LINE 132 "src/System/Socket/Family/Inet.hsc" #-}
    pokeByteOff (sin_port     ptr)  0 (fromIntegral $ rem (quot p 256) 256 :: Word8)
    pokeByteOff (sin_port     ptr)  1 (fromIntegral $ rem       p      256 :: Word8)
    poke        (sin_addr     ptr) a
    where
      sin_family   = ((\hsc_ptr -> hsc_ptr `plusPtr` 0))
{-# LINE 137 "src/System/Socket/Family/Inet.hsc" #-}
      sin_port     = ((\hsc_ptr -> hsc_ptr `plusPtr` 2))
{-# LINE 138 "src/System/Socket/Family/Inet.hsc" #-}
      sin_addr     = ((\hsc_ptr -> hsc_ptr `plusPtr` 0)) . ((\hsc_ptr -> hsc_ptr `plusPtr` 4))