posix-api-0.2.1.0: src/Linux/Socket/Types.hsc
{-# language DataKinds #-}
{-# language DerivingStrategies #-}
{-# language DuplicateRecordFields #-}
{-# language GeneralizedNewtypeDeriving #-}
{-# language BinaryLiterals #-}
{-# language TypeApplications #-}
-- This is needed because hsc2hs does not currently handle ticked
-- promoted data constructors correctly.
{-# OPTIONS_GHC -fno-warn-unticked-promoted-constructors #-}
#define _GNU_SOURCE
#include <sys/socket.h>
#include <netinet/in.h>
#include <netinet/ip.h>
#include <netinet/udp.h>
#include <asm/byteorder.h>
#include "custom.h"
-- | All of the data constructors provided by this module are unsafe.
-- Only use them if you really know what you are doing.
module Linux.Socket.Types
( SocketFlags(..)
, dontWait
, truncate
, controlTruncate
, closeOnExec
, nonblocking
, headerInclude
-- * Multiple Message Header
, pokeMultipleMessageHeaderName
, pokeMultipleMessageHeaderNameLength
, pokeMultipleMessageHeaderIOVector
, pokeMultipleMessageHeaderIOVectorLength
, pokeMultipleMessageHeaderControl
, pokeMultipleMessageHeaderControlLength
, pokeMultipleMessageHeaderFlags
, pokeMultipleMessageHeaderLength
, peekMultipleMessageHeaderLength
, peekMultipleMessageHeaderNameLength
, sizeofMultipleMessageHeader
-- * UDP Header
, sizeofUdpHeader
, pokeUdpHeaderSourcePort
, pokeUdpHeaderDestinationPort
, pokeUdpHeaderLength
, pokeUdpHeaderChecksum
-- * IPv4 Header
, sizeofIpHeader
, pokeIpHeaderVersionIhl
, pokeIpHeaderTypeOfService
, pokeIpHeaderTotalLength
, pokeIpHeaderIdentifier
, pokeIpHeaderFragmentOffset
, pokeIpHeaderTimeToLive
, pokeIpHeaderProtocol
, pokeIpHeaderChecksum
, pokeIpHeaderSourceAddress
, pokeIpHeaderDestinationAddress
) where
import Prelude hiding (truncate)
import Data.Bits (Bits((.|.)),unsafeShiftL,unsafeShiftR)
import Data.Word (Word8,Word16,Word32)
import Data.Primitive (Addr(..),MutableByteArray,writeByteArray)
import Foreign.C.Types (CInt(..),CSize,CUInt)
import Posix.Socket (MessageFlags(..),Message(Receive),OptionName(..))
import Foreign.Storable (peekByteOff,pokeByteOff)
import GHC.Ptr (Ptr(..))
import GHC.Exts (RealWorld)
import qualified Data.Primitive as PM
newtype SocketFlags = SocketFlags CInt
deriving stock (Eq)
deriving newtype (Bits)
-- newtype Collection :: Type -> Type where
-- Collection :: !(Ptr a) -> Collection a
--
-- indexCollection :: Ptr a
-- => Collection a -> Int -> IO (Ptr a)
-- indexCollection (Collection p) n = advancePtr p n
-- data MessageHeader = MessageHeader
-- { name :: !Addr
-- , nameLength :: !CInt
-- , vector :: !(Ptr InputOutputVector)
-- , vectorLength :: !CSize
-- , control :: !(Ptr ControlMessageHeader)
-- , controlLength :: !CSize
-- , flags :: !(MessageFlags Receive)
-- }
--
-- data IOVector = IOVector
-- { base :: !Addr
-- , length :: !CSize
-- }
--
-- data ControlMessageHeader = ControlMessageHeader
-- { length :: !CInt
-- , level :: !CInt
-- , type_ :: !CInt
-- , data_ :: !Addr
-- }
instance Semigroup SocketFlags where (<>) = (.|.)
instance Monoid SocketFlags where mempty = SocketFlags 0
-- | The @MSG_DONTWAIT@ receive flag or send flag.
dontWait :: MessageFlags m
dontWait = MessageFlags #{const MSG_DONTWAIT}
-- | The @MSG_TRUNC@ receive flag.
truncate :: MessageFlags Receive
truncate = MessageFlags #{const MSG_DONTWAIT}
-- | The @MSG_CTRUNC@ receive flag.
controlTruncate :: MessageFlags Receive
controlTruncate = MessageFlags #{const MSG_CTRUNC}
-- | The @SOCK_CLOEXEC@ receive flag or send flag.
closeOnExec :: SocketFlags
closeOnExec = SocketFlags #{const SOCK_CLOEXEC}
-- | The @SOCK_NONBLOCK@ receive flag or send flag.
nonblocking :: SocketFlags
nonblocking = SocketFlags #{const SOCK_NONBLOCK}
-- | If enabled, the user supplies an IP header in front of the
-- user data. Valid only for @SOCK_RAW@ sockets.
headerInclude :: OptionName
headerInclude = OptionName #{const IP_HDRINCL}
-- | The size of a @mmsghdr@ struct.
sizeofMultipleMessageHeader :: CInt
sizeofMultipleMessageHeader = #{size struct mmsghdr}
pokeMultipleMessageHeaderName :: Addr -> Addr -> IO ()
pokeMultipleMessageHeaderName (Addr p) (Addr x) = #{poke struct mmsghdr, msg_hdr.msg_name} (Ptr p) (Ptr x)
pokeMultipleMessageHeaderNameLength :: Addr -> CInt -> IO ()
pokeMultipleMessageHeaderNameLength (Addr p) = #{poke struct mmsghdr, msg_hdr.msg_namelen} (Ptr p)
pokeMultipleMessageHeaderIOVector :: Addr -> Addr -> IO ()
pokeMultipleMessageHeaderIOVector (Addr p) (Addr x) = #{poke struct mmsghdr, msg_hdr.msg_iov} (Ptr p) (Ptr x)
pokeMultipleMessageHeaderIOVectorLength :: Addr -> CSize -> IO ()
pokeMultipleMessageHeaderIOVectorLength (Addr p) = #{poke struct mmsghdr, msg_hdr.msg_iovlen} (Ptr p)
pokeMultipleMessageHeaderControl :: Addr -> Addr -> IO ()
pokeMultipleMessageHeaderControl (Addr p) (Addr x) = #{poke struct mmsghdr, msg_hdr.msg_control} (Ptr p) (Ptr x)
pokeMultipleMessageHeaderControlLength :: Addr -> CSize -> IO ()
pokeMultipleMessageHeaderControlLength (Addr p) = #{poke struct mmsghdr, msg_hdr.msg_controllen} (Ptr p)
pokeMultipleMessageHeaderFlags :: Addr -> MessageFlags Receive -> IO ()
pokeMultipleMessageHeaderFlags (Addr p) (MessageFlags i) = #{poke struct mmsghdr, msg_hdr.msg_flags} (Ptr p) i
pokeMultipleMessageHeaderLength :: Addr -> CUInt -> IO ()
pokeMultipleMessageHeaderLength (Addr p) i = #{poke struct mmsghdr, msg_len} (Ptr p) i
peekMultipleMessageHeaderNameLength :: Addr -> IO CInt
peekMultipleMessageHeaderNameLength (Addr p) = #{peek struct mmsghdr, msg_hdr.msg_namelen} (Ptr p)
peekMultipleMessageHeaderLength :: Addr -> IO CUInt
peekMultipleMessageHeaderLength (Addr p) = #{peek struct mmsghdr, msg_len} (Ptr p)
-- | The size of a @udphdr@ struct.
sizeofUdpHeader :: CInt
sizeofUdpHeader = #{size struct udphdr}
pokeUdpHeaderSourcePort :: Addr -> Word16 -> IO ()
pokeUdpHeaderSourcePort (Addr p) = #{poke struct udphdr, source} (Ptr p)
pokeUdpHeaderDestinationPort :: Addr -> Word16 -> IO ()
pokeUdpHeaderDestinationPort (Addr p) = #{poke struct udphdr, dest} (Ptr p)
pokeUdpHeaderLength :: Addr -> Word16 -> IO ()
pokeUdpHeaderLength (Addr p) = #{poke struct udphdr, len} (Ptr p)
pokeUdpHeaderChecksum :: Addr -> Word16 -> IO ()
pokeUdpHeaderChecksum (Addr p) = #{poke struct udphdr, check} (Ptr p)
-- | The size of an @iphdr@ struct.
sizeofIpHeader :: CInt
sizeofIpHeader = #{size struct iphdr}
-- | This poke function requires the user to pack the version and the
-- internet header length (IHL), each 4 bits, into a single 8-bit word.
-- The version should be in the most significant bits. This function
-- will marshal the value appropriately depending on the platform's
-- bit-endianness.
pokeIpHeaderVersionIhl :: Addr -> Word8 -> IO ()
-- TODO: Verify if this is correct.
#if defined(__LITTLE_ENDIAN_BITFIELD)
pokeIpHeaderVersionIhl p _ = PM.writeOffAddr p 0 (0b01000101 :: Word8)
-- PM.writeOffAddr p 0 (unsafeShiftL w 4 .|. unsafeShiftR w 4)
-- where
-- rev =
#elif defined (__BIG_ENDIAN_BITFIELD)
pokeIpHeaderVersionIhl p w = PM.writeOffAddr p 0 w
#else
ERROR_BITFIELD_ENDIANNESS_NOT_SET
#endif
pokeIpHeaderTypeOfService :: Addr -> Word8 -> IO ()
pokeIpHeaderTypeOfService (Addr p) = #{poke struct iphdr, tos} (Ptr p)
pokeIpHeaderTotalLength :: Addr -> Word16 -> IO ()
pokeIpHeaderTotalLength (Addr p) = #{poke struct iphdr, tot_len} (Ptr p)
pokeIpHeaderIdentifier :: Addr -> Word16 -> IO ()
pokeIpHeaderIdentifier (Addr p) = #{poke struct iphdr, id} (Ptr p)
pokeIpHeaderFragmentOffset :: Addr -> Word16 -> IO ()
pokeIpHeaderFragmentOffset (Addr p) = #{poke struct iphdr, frag_off} (Ptr p)
pokeIpHeaderTimeToLive :: Addr -> Word8 -> IO ()
pokeIpHeaderTimeToLive (Addr p) = #{poke struct iphdr, ttl} (Ptr p)
pokeIpHeaderProtocol :: Addr -> Word8 -> IO ()
pokeIpHeaderProtocol (Addr p) = #{poke struct iphdr, protocol} (Ptr p)
pokeIpHeaderChecksum :: Addr -> Word16 -> IO ()
pokeIpHeaderChecksum (Addr p) = #{poke struct iphdr, check} (Ptr p)
pokeIpHeaderSourceAddress :: Addr -> Word32 -> IO ()
pokeIpHeaderSourceAddress (Addr p) = #{poke struct iphdr, saddr} (Ptr p)
pokeIpHeaderDestinationAddress :: Addr -> Word32 -> IO ()
pokeIpHeaderDestinationAddress (Addr p) = #{poke struct iphdr, daddr} (Ptr p)