    {-# LINE 1 "Network/Socket/Posix/CmsgHdr.hsc" #-}
    {-# OPTIONS_GHC -funbox-strict-fields #-}

    module Network.Socket.Posix.CmsgHdr (
        Cmsg(..)
      , withCmsgs
      , parseCmsgs
      ) where

    import Foreign.ForeignPtr
    import Foreign.Marshal.Alloc (allocaBytes)
    import Foreign.Marshal.Utils (copyBytes)
    import qualified Data.ByteString as B
    import Data.ByteString.Internal

    import Network.Socket.Imports
    import Network.Socket.Posix.Cmsg
    import Network.Socket.Posix.MsgHdr
    import Network.Socket.Types

    data CmsgHdr = CmsgHdr {

    {-# LINE 27 "Network/Socket/Posix/CmsgHdr.hsc" #-}
        cmsgHdrLen   :: CSize

    {-# LINE 31 "Network/Socket/Posix/CmsgHdr.hsc" #-}
      , CmsgHdr -> CInt
    cmsgHdrLevel :: CInt
      , CmsgHdr -> CInt
    cmsgHdrType  :: CInt
      } deriving (CmsgHdr -> CmsgHdr -> Bool
    (CmsgHdr -> CmsgHdr -> Bool)
    -> (CmsgHdr -> CmsgHdr -> Bool) -> Eq CmsgHdr
    forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
    $c== :: CmsgHdr -> CmsgHdr -> Bool
    == :: CmsgHdr -> CmsgHdr -> Bool
    $c/= :: CmsgHdr -> CmsgHdr -> Bool
    /= :: CmsgHdr -> CmsgHdr -> Bool
    Eq, Int -> CmsgHdr -> ShowS
    [CmsgHdr] -> ShowS
    CmsgHdr -> String
    (Int -> CmsgHdr -> ShowS)
    -> (CmsgHdr -> String) -> ([CmsgHdr] -> ShowS) -> Show CmsgHdr
    forall a.
    (Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a
    $cshowsPrec :: Int -> CmsgHdr -> ShowS
    showsPrec :: Int -> CmsgHdr -> ShowS
    $cshow :: CmsgHdr -> String
    show :: CmsgHdr -> String
    $cshowList :: [CmsgHdr] -> ShowS
    showList :: [CmsgHdr] -> ShowS
    Show)

    instance Storable CmsgHdr where
      sizeOf :: CmsgHdr -> Int
    sizeOf    ~CmsgHdr
    _ = ((Int
    16))
    {-# LINE 37 "Network/Socket/Posix/CmsgHdr.hsc" #-}
      alignment ~_ = alignment (0 :: CInt)

      peek :: Ptr CmsgHdr -> IO CmsgHdr
    peek Ptr CmsgHdr
    p = do
        len <- ((\Ptr CmsgHdr
    hsc_ptr -> Ptr CmsgHdr -> Int -> IO CSize
    forall b. Ptr b -> Int -> IO CSize
    forall a b. Storable a => Ptr b -> Int -> IO a
    peekByteOff Ptr CmsgHdr
    hsc_ptr Int
    0))   Ptr CmsgHdr
    p
    {-# LINE 41 "Network/Socket/Posix/CmsgHdr.hsc" #-}
        lvl <- ((\hsc_ptr -> peekByteOff hsc_ptr 8)) p
    {-# LINE 42 "Network/Socket/Posix/CmsgHdr.hsc" #-}
        typ <- ((\hsc_ptr -> peekByteOff hsc_ptr 12))  p
    {-# LINE 43 "Network/Socket/Posix/CmsgHdr.hsc" #-}
        return $ CmsgHdr len lvl typ

      poke :: Ptr CmsgHdr -> CmsgHdr -> IO ()
    poke Ptr CmsgHdr
    p (CmsgHdr CSize
    len CInt
    lvl CInt
    typ) = do
        Ptr CmsgHdr -> CSize -> IO ()
    forall a. Ptr a -> CSize -> IO ()
    zeroMemory Ptr CmsgHdr
    p ((CSize
    16))
    {-# LINE 47 "Network/Socket/Posix/CmsgHdr.hsc" #-}
        ((\hsc_ptr -> pokeByteOff hsc_ptr 0))   p len
    {-# LINE 48 "Network/Socket/Posix/CmsgHdr.hsc" #-}
        ((\hsc_ptr -> pokeByteOff hsc_ptr 8)) p lvl
    {-# LINE 49 "Network/Socket/Posix/CmsgHdr.hsc" #-}
        ((\hsc_ptr -> pokeByteOff hsc_ptr 12))  p typ
    {-# LINE 50 "Network/Socket/Posix/CmsgHdr.hsc" #-}

    withCmsgs :: [Cmsg] -> (Ptr CmsgHdr -> Int -> IO a) -> IO a
    withCmsgs :: forall a. [Cmsg] -> (Ptr CmsgHdr -> Int -> IO a) -> IO a
    withCmsgs [Cmsg]
    cmsgs0 Ptr CmsgHdr -> Int -> IO a
    action
      | Int
    total Int -> Int -> Bool
    forall a. Eq a => a -> a -> Bool
    == Int
    0 = Ptr CmsgHdr -> Int -> IO a
    action Ptr CmsgHdr
    forall a. Ptr a
    nullPtr Int
    0
      | Bool
    otherwise  = Int -> (Ptr CmsgHdr -> IO a) -> IO a
    forall a b. Int -> (Ptr a -> IO b) -> IO b
    allocaBytes Int
    total ((Ptr CmsgHdr -> IO a) -> IO a) -> (Ptr CmsgHdr -> IO a) -> IO a
    forall a b. (a -> b) -> a -> b
    $ \Ptr CmsgHdr
    ctrlPtr -> do
            Ptr CmsgHdr -> [Cmsg] -> [Int] -> IO ()
    loop Ptr CmsgHdr
    ctrlPtr [Cmsg]
    cmsgs0 [Int]
    spaces
            Ptr CmsgHdr -> Int -> IO a
    action Ptr CmsgHdr
    ctrlPtr Int
    total
      where
        loop :: Ptr CmsgHdr -> [Cmsg] -> [Int] -> IO ()
    loop Ptr CmsgHdr
    ctrlPtr (Cmsg
    cmsg:[Cmsg]
    cmsgs) (Int
    s:[Int]
    ss) = do
            Cmsg -> Ptr CmsgHdr -> IO ()
    toCmsgHdr Cmsg
    cmsg Ptr CmsgHdr
    ctrlPtr
            let nextPtr :: Ptr b
    nextPtr = Ptr CmsgHdr
    ctrlPtr Ptr CmsgHdr -> Int -> Ptr b
    forall a b. Ptr a -> Int -> Ptr b
    `plusPtr` Int
    s
            Ptr CmsgHdr -> [Cmsg] -> [Int] -> IO ()
    loop Ptr CmsgHdr
    forall a. Ptr a
    nextPtr [Cmsg]
    cmsgs [Int]
    ss
        loop Ptr CmsgHdr
    _ [Cmsg]
    _ [Int]
    _ = () -> IO ()
    forall a. a -> IO a
    forall (m :: * -> *) a. Monad m => a -> m a
    return ()
        cmsg_space :: Int -> Int
    cmsg_space = CSize -> Int
    forall a b. (Integral a, Num b) => a -> b
    fromIntegral (CSize -> Int) -> (Int -> CSize) -> Int -> Int
    forall b c a. (b -> c) -> (a -> b) -> a -> c
    . CSize -> CSize
    c_cmsg_space (CSize -> CSize) -> (Int -> CSize) -> Int -> CSize
    forall b c a. (b -> c) -> (a -> b) -> a -> c
    . Int -> CSize
    forall a b. (Integral a, Num b) => a -> b
    fromIntegral
        spaces :: [Int]
    spaces = (Cmsg -> Int) -> [Cmsg] -> [Int]
    forall a b. (a -> b) -> [a] -> [b]
    map (Int -> Int
    cmsg_space (Int -> Int) -> (Cmsg -> Int) -> Cmsg -> Int
    forall b c a. (b -> c) -> (a -> b) -> a -> c
    . ByteString -> Int
    B.length (ByteString -> Int) -> (Cmsg -> ByteString) -> Cmsg -> Int
    forall b c a. (b -> c) -> (a -> b) -> a -> c
    . Cmsg -> ByteString
    cmsgData) [Cmsg]
    cmsgs0
        total :: Int
    total = [Int] -> Int
    forall a. Num a => [a] -> a
    forall (t :: * -> *) a. (Foldable t, Num a) => t a -> a
    sum [Int]
    spaces

    toCmsgHdr :: Cmsg -> Ptr CmsgHdr -> IO ()
    toCmsgHdr :: Cmsg -> Ptr CmsgHdr -> IO ()
    toCmsgHdr (Cmsg (CmsgId CInt
    lvl CInt
    typ) (PS ForeignPtr Word8
    fptr Int
    off Int
    len)) Ptr CmsgHdr
    ctrlPtr = do
        Ptr CmsgHdr -> CmsgHdr -> IO ()
    forall a. Storable a => Ptr a -> a -> IO ()
    poke Ptr CmsgHdr
    ctrlPtr (CmsgHdr -> IO ()) -> CmsgHdr -> IO ()
    forall a b. (a -> b) -> a -> b
    $ CSize -> CInt -> CInt -> CmsgHdr
    CmsgHdr (CSize -> CSize
    forall a b. (Integral a, Num b) => a -> b
    fromIntegral (CSize -> CSize) -> CSize -> CSize
    forall a b. (a -> b) -> a -> b
    $ CSize -> CSize
    c_cmsg_len (Int -> CSize
    forall a b. (Integral a, Num b) => a -> b
    fromIntegral Int
    len)) CInt
    lvl CInt
    typ
        ForeignPtr Word8 -> (Ptr Word8 -> IO ()) -> IO ()
    forall a b. ForeignPtr a -> (Ptr a -> IO b) -> IO b
    withForeignPtr ForeignPtr Word8
    fptr ((Ptr Word8 -> IO ()) -> IO ()) -> (Ptr Word8 -> IO ()) -> IO ()
    forall a b. (a -> b) -> a -> b
    $ \Ptr Word8
    src0 -> do
            let src :: Ptr b
    src = Ptr Word8
    src0 Ptr Word8 -> Int -> Ptr b
    forall a b. Ptr a -> Int -> Ptr b
    `plusPtr` Int
    off
            dst <- Ptr CmsgHdr -> IO (Ptr Word8)
    c_cmsg_data Ptr CmsgHdr
    ctrlPtr
            copyBytes dst src len

    parseCmsgs :: SocketAddress sa => Ptr (MsgHdr sa) -> IO [Cmsg]
    parseCmsgs :: forall sa. SocketAddress sa => Ptr (MsgHdr sa) -> IO [Cmsg]
    parseCmsgs Ptr (MsgHdr sa)
    msgptr = do
        ptr <- Ptr (MsgHdr sa) -> IO (Ptr CmsgHdr)
    forall sa. Ptr (MsgHdr sa) -> IO (Ptr CmsgHdr)
    c_cmsg_firsthdr Ptr (MsgHdr sa)
    msgptr
        loop ptr id
      where
        loop :: Ptr CmsgHdr -> ([Cmsg] -> c) -> IO c
    loop Ptr CmsgHdr
    ptr [Cmsg] -> c
    build
          | Ptr CmsgHdr
    ptr Ptr CmsgHdr -> Ptr CmsgHdr -> Bool
    forall a. Eq a => a -> a -> Bool
    == Ptr CmsgHdr
    forall a. Ptr a
    nullPtr = c -> IO c
    forall a. a -> IO a
    forall (m :: * -> *) a. Monad m => a -> m a
    return (c -> IO c) -> c -> IO c
    forall a b. (a -> b) -> a -> b
    $ [Cmsg] -> c
    build []
          | Bool
    otherwise = do
                cmsg <- Ptr CmsgHdr -> IO Cmsg
    fromCmsgHdr Ptr CmsgHdr
    ptr
                nextPtr <- c_cmsg_nxthdr msgptr ptr
                loop nextPtr (build . (cmsg :))

    fromCmsgHdr :: Ptr CmsgHdr -> IO Cmsg
    fromCmsgHdr :: Ptr CmsgHdr -> IO Cmsg
    fromCmsgHdr Ptr CmsgHdr
    ptr = do
        CmsgHdr len lvl typ <- Ptr CmsgHdr -> IO CmsgHdr
    forall a. Storable a => Ptr a -> IO a
    peek Ptr CmsgHdr
    ptr
        src <- c_cmsg_data ptr
        let siz = CSize -> Int
    forall a b. (Integral a, Num b) => a -> b
    fromIntegral CSize
    len Int -> Int -> Int
    forall a. Num a => a -> a -> a
    - (Ptr Word8
    src Ptr Word8 -> Ptr CmsgHdr -> Int
    forall a b. Ptr a -> Ptr b -> Int
    `minusPtr` Ptr CmsgHdr
    ptr)
        Cmsg (CmsgId lvl typ) <$> create (fromIntegral siz) (\Ptr Word8
    dst -> Ptr Word8 -> Ptr Word8 -> Int -> IO ()
    forall a. Ptr a -> Ptr a -> Int -> IO ()
    copyBytes Ptr Word8
    dst Ptr Word8
    src Int
    siz)

    foreign import ccall unsafe "cmsg_firsthdr"
      c_cmsg_firsthdr :: Ptr (MsgHdr sa) -> IO (Ptr CmsgHdr)

    foreign import ccall unsafe "cmsg_nxthdr"
      c_cmsg_nxthdr :: Ptr (MsgHdr sa) -> Ptr CmsgHdr -> IO (Ptr CmsgHdr)

    foreign import ccall unsafe "cmsg_data"
      c_cmsg_data :: Ptr CmsgHdr -> IO (Ptr Word8)

    foreign import ccall unsafe "cmsg_space"
      c_cmsg_space :: CSize -> CSize

    foreign import ccall unsafe "cmsg_len"
      c_cmsg_len :: CSize -> CSize