socket-0.4.0.0: src/System/Socket/Family/INET.hsc
{-# LANGUAGE TypeFamilies #-}
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
#include "hs_socket.h"
#let alignment t = "%lu", (unsigned long)offsetof(struct {char x__; t (y__); }, y__)
data INET
instance Family INET where
type SockAddr INET = SockAddrIn
familyNumber _ = (#const AF_INET)
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 _ = (#size uint32_t)
alignment _ = (#alignment uint32_t)
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 _ = (#size struct sockaddr_in)
alignment _ = (#alignment struct sockaddr_in)
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 = (#ptr struct sockaddr_in, sin_port)
sin_addr = (#ptr struct in_addr, s_addr) . (#ptr struct sockaddr_in, sin_addr)
poke ptr (SockAddrIn p a) = do
c_memset ptr 0 (#const sizeof(struct sockaddr_in))
poke (sin_family ptr) ((#const AF_INET) :: Word16)
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 = (#ptr struct sockaddr_in, sin_family)
sin_port = (#ptr struct sockaddr_in, sin_port)
sin_addr = (#ptr struct in_addr, s_addr) . (#ptr struct sockaddr_in, sin_addr)