packages feed

netw-0.1.0.0: src/Netw/Internal/Type.hsc

{-# LANGUAGE ForeignFunctionInterface #-}
module Netw.Internal.Type 
( Iovec(..)
, sizeofSockaddrStorage
, Protoent(..), protoents
, Servent(..), servents
, _IPPORT_RESERVED, _IPPORT_USERRESERVED
) where
#include <netdb.h>
#include <sys/socket.h>

import Foreign
import Foreign.C

import Data.Primitive
import Data.Function

import Data.Word
import GHC.ByteOrder

data Iovec = Iovec { iovBase :: !(Ptr ()), iovLen :: !CSize }
instance Storable Iovec where
  sizeOf   _ = #{size struct iovec}
  alignment _ = #{alignment struct iovec}

  peek ptr = Iovec <$> #{peek struct iovec, iov_base} ptr <*> #{peek struct iovec, iov_len} ptr
  poke ptr iovec = #{poke struct iovec, iov_base} ptr (iovBase iovec)
                >> #{poke struct iovec, iov_len}  ptr (iovLen  iovec)

sizeofSockaddrStorage :: Int
sizeofSockaddrStorage = #{size struct sockaddr_storage}

data Protoent = Protoent
  { pName    :: String
  , pAliases :: [String]
  , pProto   :: CInt
  }

peekProtoent :: Ptr Protoent -> IO Protoent
peekProtoent ptr = do
  name    <- peekCString =<< #{peek struct protoent, p_name} ptr
  proto   <- #{peek struct protoent, p_proto} ptr
  aliases <- mapM peekCString =<< peekArray0 nullPtr =<< #{peek struct protoent, p_aliases} ptr
  return (Protoent name aliases proto)

foreign import ccall unsafe "getprotoent"
  getprotoent :: IO (Ptr Protoent)
foreign import ccall unsafe "endprotoent"
  endprotoent :: IO ()

protoents :: IO [Protoent]
protoents = do
  endprotoent
  fix (\ loop -> do
    proto' <- getprotoent
    if proto' == nullPtr
    then do
      endprotoent
      return []
    else do
      proto <- peekProtoent proto'
      (proto:) <$> loop
    )

data Servent = Servent
  { sName    :: String
  , sAliases :: [String]
  , sPort    :: Word16  -- NOTE: This is in host byte order
  , sProto   :: String
  }

peekServent :: Ptr Servent -> IO Servent
peekServent ptr = do
  name    <- peekCString =<< #{peek struct servent, s_name} ptr
  aliases <- mapM peekCString =<< peekArray0 nullPtr =<< #{peek struct servent, s_aliases} ptr
  port :: CInt
          <- #{peek struct servent, s_port} ptr
  proto   <- peekCString =<< #{peek struct servent, s_proto} ptr
  return (Servent name aliases (ntoh $ fromIntegral port) proto)
  where ntoh :: Word16 -> Word16
        ntoh = case targetByteOrder of LittleEndian -> byteSwap16; BigEndian -> id

foreign import ccall unsafe "getservent"
  getservent :: IO (Ptr Servent)
foreign import ccall unsafe "endservent"
  endservent :: IO ()

servents :: IO [Servent]
servents = do
  endservent
  fix (\ loop -> do
    serv' <- getservent
    if serv' == nullPtr
    then do
      endservent
      return []
    else do
      serv <- peekServent serv'
      (serv:) <$> loop
    )

_IPPORT_RESERVED :: Word16
_IPPORT_RESERVED = #{const IPPORT_RESERVED}

_IPPORT_USERRESERVED :: Word16
_IPPORT_USERRESERVED = #{const IPPORT_USERRESERVED}