I'm doing some Network capture with Network.Pcap
(pcap) and plan to do some inspection using Net.PacketParsing
(network-house). To do so, it looks like i have to put my packet parsing in either
Pcap.Callback :: PktHdr -> Ptr Word8 -> IO ()
or
Pcap.CallbackBS :: PktHdr -> ByteString -> IO ().
And work on the packet as either a 'Ptr Word8' or 'ByteString'. On the packet parsing side, I have:
Net.Packet.toInPack :: UArray Int Word8 -> InPacket
to get to the InPacket
type that's needed for the parsing. So, what's left for me is to convert the 'Ptr' or 'ByteString' to 'UArray'--either purely or in IO. I suppose I can unpack the ByteString
to [Word8]
, and from there to the UArray
, but there seems like there must be a better way.
I'm also concerned about my choice of libraries. I've used network-house in the past and found it quite nice, but it is getting old and uses UArray, which itself seems a little archaic. So suggestions for a better starting point are welcome.
ByteString
and Ptr Word8
point to external heap, while UArray
is on GHC heap, so any conversion function must copy over the data.
I have not found any direct conversion function in libraries, but fortunately there's a GHC primitive which does exactly what we want, called copyAddrToByteArray#
. This lets us convert with the bare minimum overhead:
{-# language MagicHash, UnboxedTuples #-}
import qualified Data.ByteString as B
import qualified Data.ByteString.Internal as B
import qualified Data.Array.Base as A
import GHC.Types
import GHC.Prim
import GHC.Magic (runRW#)
import GHC.ForeignPtr
import Data.Word
-- when using GHC 8.2.x or later:
byteStringToUArray :: B.ByteString -> A.UArray Int Word8
byteStringToUArray (B.PS (ForeignPtr addr _) (I# start) (I# len)) =
runRW# $ \s -> case newByteArray# len s of
(# s, marr #) -> case copyAddrToByteArray# (plusAddr# addr start) marr 0# len s of
s -> case unsafeFreezeByteArray# marr s of
(# _, arr #) -> A.UArray 0 (I# (len -# 1#)) (I# len) arr
{-# inline byteStringToUArray #-}
-- when using GHC 8.0.x:
byteStringToUArray :: B.ByteString -> A.UArray Int Word8
byteStringToUArray (B.PS (ForeignPtr addr _) (I# start) (I# len)) =
case (runRW# $ \s -> case newByteArray# len s of
(# s, marr #) -> case copyAddrToByteArray# (plusAddr# addr start) marr 0# len s of
s -> case unsafeFreezeByteArray# marr s of
(# s, arr #) -> (# s, A.UArray 0 (I# (len -# 1#)) (I# len) arr #)) of
(# _, res #) -> res
{-# inline byteStringToUArray #-}
But in general, you're right that array
is outdated and rarely used now.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With