{- Bustle.Reader: Haskell binding for pcap-reader.c Copyright © 2020 Will Thompson This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA -} {-# LANGUAGE ForeignFunctionInterface #-} module Bustle.Reader ( -- * Types Reader -- * Methods , readerOpen , readerReadOne , readerClose , withReader ) where import Control.Exception (bracket) import Foreign.C import Foreign.ForeignPtr import Foreign.Marshal.Alloc import Foreign.Ptr import Foreign.Storable import System.Glib.GObject import System.Glib.GError import Bustle.GDBusMessage import Bustle.Types (Microseconds) -- Gtk2HS boilerplate newtype Reader = Reader { unReader :: ForeignPtr Reader } deriving (Eq, Ord) mkReader :: (ForeignPtr Reader -> Reader, FinalizerPtr a) mkReader = (Reader, objectUnref) instance GObjectClass Reader where toGObject = GObject . castForeignPtr . unReader unsafeCastGObject = Reader . castForeignPtr . unGObject -- Foreign imports foreign import ccall "bustle_pcap_reader_open" bustle_pcap_reader_open :: CString -> Ptr (Ptr ()) -> IO (Ptr Reader) -- Foreign imports foreign import ccall "bustle_pcap_reader_read_one" bustle_pcap_reader_read_one :: Ptr Reader -> Ptr CLong -> Ptr CLong -> Ptr (Ptr CChar) -> Ptr CUInt -> Ptr (Ptr GDBusMessage) -> Ptr (Ptr ()) -> IO CInt foreign import ccall "bustle_pcap_reader_close" bustle_pcap_reader_close :: Ptr Reader -> IO () -- Throws a GError if the file can't be opened readerOpen :: FilePath -> IO Reader readerOpen filename = wrapNewGObject mkReader $ propagateGError $ \gerrorPtr -> withCString filename $ \c_filename -> bustle_pcap_reader_open c_filename gerrorPtr readerReadOne :: Reader -> IO (Maybe (Microseconds, Int, GDBusMessage)) readerReadOne reader = withForeignPtr (unReader reader) $ \c_reader -> alloca $ \secPtr -> alloca $ \usecPtr -> alloca $ \blobPtrPtr -> alloca $ \lengthPtr -> alloca $ \messagePtr -> do poke messagePtr nullPtr propagateGError $ bustle_pcap_reader_read_one c_reader secPtr usecPtr blobPtrPtr lengthPtr messagePtr blob <- peek blobPtrPtr if blob == nullPtr then return Nothing else do sec <- peek secPtr usec <- peek usecPtr blobLength <- peek lengthPtr let µsec = fromIntegral sec * (10 ^ (6 :: Int)) + fromIntegral usec message <- wrapNewGDBusMessage $ peek messagePtr return $ Just (µsec, fromIntegral blobLength, message) readerClose :: Reader -> IO () readerClose reader = withForeignPtr (unReader reader) bustle_pcap_reader_close withReader :: FilePath -> (Reader -> IO a) -> IO a withReader filename f = do bracket (readerOpen filename) readerClose f