{-# LINE 1 "src/System/Socket/Family/INET.hsc" #-}
{-# LANGUAGE TypeFamilies #-}
{-# LINE 2 "src/System/Socket/Family/INET.hsc" #-}
module System.Socket.Family.INET
  ( INET
  , AddrIn ()
  , SockAddrIn (..)
  , inaddrANY
  , inaddrBROADCAST
  , inaddrNONE
  , inaddrLOOPBACK
  , inaddrUNSPEC_GROUP
  , inaddrALLHOSTS_GROUP
  , inaddrALLRTS_GROUP
  , inaddrMAXLOCAL_GROUP
  ) 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 31 "src/System/Socket/Family/INET.hsc" #-}

{-# LINE 32 "src/System/Socket/Family/INET.hsc" #-}

data INET

instance Family INET where
  type SockAddr INET = SockAddrIn
  familyNumber _ = (2)
{-# LINE 38 "src/System/Socket/Family/INET.hsc" #-}

data SockAddrIn
   = SockAddrIn
     { sinPort      :: Word16
     , sinAddr      :: AddrIn
     } deriving (Eq)

-- | 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.getAddrInfo` for parsing and suppress
--   nameserver lookups:
--
--   > > getAddrInfo (Just "127.0.0.1") Nothing aiNUMERICHOST :: IO [AddrInfo SockAddrIn STREAM TCP]
--   > [AddrInfo {addrInfoFlags = AddrInfoFlags 4, addrAddress = "127.0.0.1:0", addrCanonName = Nothing}]
newtype AddrIn
      = AddrIn BS.ByteString
      deriving (Eq)

-- | @0.0.0.0@
inaddrANY             :: AddrIn
inaddrANY              = AddrIn $ BS.pack [  0,  0,  0,  0]

-- | @255.255.255.0@
inaddrBROADCAST       :: AddrIn
inaddrBROADCAST        = AddrIn $ BS.pack [255,255,255,255]

-- | @255.255.255.0@
inaddrNONE            :: AddrIn
inaddrNONE             = AddrIn $ BS.pack [255,255,255,255]

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

-- | @224.0.0.0@
inaddrUNSPEC_GROUP    :: AddrIn
inaddrUNSPEC_GROUP     = AddrIn $ BS.pack [224,  0,  0,  0]

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

-- | @224.0.0.2@
inaddrALLRTS_GROUP    :: AddrIn
inaddrALLRTS_GROUP     = AddrIn $ BS.pack [224,  0,  0,  2]

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

instance Show SockAddrIn where
  show (SockAddrIn p a) =
    show a ++ ":" ++ show p

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

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

instance Storable SockAddrIn where
  sizeOf    _ = ((16))
{-# LINE 111 "src/System/Socket/Family/INET.hsc" #-}
  alignment _ = (4)
{-# LINE 112 "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 AddrIn
    return (SockAddrIn (fromIntegral ph * 256 + fromIntegral pl) a)
    where
      sin_port     = ((\hsc_ptr -> hsc_ptr `plusPtr` 2))
{-# LINE 119 "src/System/Socket/Family/INET.hsc" #-}
      sin_addr     = ((\hsc_ptr -> hsc_ptr `plusPtr` 0)) . ((\hsc_ptr -> hsc_ptr `plusPtr` 4))
{-# LINE 120 "src/System/Socket/Family/INET.hsc" #-}
  poke ptr (SockAddrIn p a) = do
    c_memset ptr 0 (16)
{-# LINE 122 "src/System/Socket/Family/INET.hsc" #-}
    poke        (sin_family   ptr) ((2) :: Word16)
{-# LINE 123 "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 128 "src/System/Socket/Family/INET.hsc" #-}
      sin_port     = ((\hsc_ptr -> hsc_ptr `plusPtr` 2))
{-# LINE 129 "src/System/Socket/Family/INET.hsc" #-}
      sin_addr     = ((\hsc_ptr -> hsc_ptr `plusPtr` 0)) . ((\hsc_ptr -> hsc_ptr `plusPtr` 4))