我正在使用Network.Pcap(pcap)进行一些网络捕获,并计划使用Net.PacketParsing(network-house)做一些检查。为此,好像我必须将数据包解析放在

Pcap.Callback :: PktHdr -> Ptr Word8 -> IO ()

或者
Pcap.CallbackBS :: PktHdr -> ByteString -> IO ().

并以“Ptr Word8”或“ByteString”的形式处理数据包。在数据包解析方面,我有:
Net.Packet.toInPack :: UArray Int Word8 -> InPacket

以获得解析所需的InPacket类型。因此,剩下的就是将'Ptr'或'ByteString'转换为'UArray'-完全或在IO中进行。我想我可以将ByteString解压缩为[Word8],然后从那里解压缩为UArray,但是似乎必须有一个更好的方法。

我还担心我对库的选择。我过去使用过网络房屋,发现它相当不错,但是它已经变老并使用了UArray,而UArray本身似乎有点陈旧。因此,欢迎提出一个更好的起点的建议。

最佳答案

ByteStringPtr Word8指向外部堆,而UArray在GHC堆上,因此任何转换函数都必须复制数据。

我没有在库中找到任何直接转换函数,但是幸运的是,有一个GHC原语正好可以实现我们想要的功能,称为 copyAddrToByteArray# 。这样我们就可以以最少的开销进行转换:

{-# 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 #-}

但是总的来说,您说对了,array已经过时了,现在很少使用了。

10-04 16:59