module Hans.Message.Dhcp4Codec where
import Control.Applicative
import Data.List (find)
import qualified Data.Serialize
import Data.Serialize.Get
import Data.Serialize.Put
import Data.Word (Word8, Word16, Word32)
import Hans.Address.IP4 (IP4,IP4Mask)
import Hans.Address.Mac (Mac)
import Hans.Address (Mask(..))
class CodecAtom a where
getAtom :: Get a
putAtom :: a -> Put
atomSize :: a -> Int
instance (CodecAtom a, CodecAtom b) => CodecAtom (a,b) where
getAtom = (,) <$> getAtom <*> getAtom
putAtom (a,b) = putAtom a *> putAtom b
atomSize (a,b)= atomSize a + atomSize b
instance CodecAtom Word8 where
getAtom = getWord8
putAtom n = putWord8 n
atomSize _ = 1
instance CodecAtom Word16 where
getAtom = getWord16be
putAtom n = putWord16be n
atomSize _ = 2
instance CodecAtom Word32 where
getAtom = getWord32be
putAtom n = putWord32be n
atomSize _ = 4
instance CodecAtom Bool where
getAtom = do b <- getWord8
case b of
0 -> return False
1 -> return True
_ -> fail "Expected 0/1 in boolean option"
putAtom False = putWord8 0
putAtom True = putWord8 1
atomSize _ = 1
instance CodecAtom IP4 where
getAtom = Data.Serialize.get
putAtom = Data.Serialize.put
atomSize _ = 4
instance CodecAtom IP4Mask where
getAtom = withMask <$> getAtom <*> (unmask <$> getAtom)
putAtom ip4mask = putAtom addr *> putAtom (SubnetMask mask)
where (addr, mask) = getMaskComponents ip4mask
atomSize _ = atomSize (undefined :: IP4)
+ atomSize (undefined :: SubnetMask)
instance CodecAtom Mac where
getAtom = Data.Serialize.get
putAtom = Data.Serialize.put
atomSize _ = 6
newtype SubnetMask = SubnetMask { unmask :: Int}
deriving (Show, Eq)
word32ToSubnetMask :: Word32 -> Maybe SubnetMask
word32ToSubnetMask mask =
SubnetMask <$> find (\ i -> computeMask i == mask) [0..32]
subnetMaskToWord32 :: SubnetMask -> Word32
subnetMaskToWord32 (SubnetMask n) = computeMask n
computeMask :: Int -> Word32
computeMask n = 02^(32n)
instance CodecAtom SubnetMask where
getAtom = do x <- getAtom
case word32ToSubnetMask x of
Just mask -> return mask
Nothing -> fail "Invalid subnet mask"
putAtom = putAtom . subnetMaskToWord32
atomSize _ = atomSize (undefined :: Word32)