mptcpanalyzer-0.0.2.0: src/MptcpAnalyzer/Loader.hs
{-|
Module : MptcpAnalyzer.Loader
Description : Load pcap/csv into a @Frame@
Maintainer : matt
License : GPL-3
-}
module MptcpAnalyzer.Loader (
loadPcapIntoFrame
, loadPcapIntoFrameNoCache
, buildAFrameFromStreamIdTcp
, buildAFrameFromStreamIdMptcp
)
where
import MptcpAnalyzer.Cache
import MptcpAnalyzer.Frame
import MptcpAnalyzer.Pcap
import MptcpAnalyzer.Stream
import MptcpAnalyzer.Types
import MptcpAnalyzer.Utils.Text
import Tshark.Main
import Control.Monad.Trans (liftIO)
import Distribution.Simple.Utils (TempFileOptions(..), withTempFileEx)
import Frames
import Frames.CSV
import qualified Frames.InCore
import Net.Mptcp
import Net.Tcp
import Polysemy (Embed, Members, Sem)
import Polysemy.State as P
import Prelude hiding (log)
import System.Exit (ExitCode(..))
import qualified Data.Vinyl as V
import qualified Data.Vinyl.Class.Method as V
import GHC.IO.Handle (hClose)
import Polysemy.Log (Log)
import qualified Polysemy.Log as Log
loadPcapIntoFrameNoCache :: (
Frames.InCore.RecVec a
, Frames.CSV.ReadRec a
, ColumnHeaders a
)
=> TsharkParams
-> FilePath
-> IO (Either String (FrameRec a))
loadPcapIntoFrameNoCache params path = do
res <- liftIO $ withTempFileEx opts "/tmp" "mptcp.csv" $ \tmpPath handle -> do
res <- exportToCsv params path handle
case res of
(ExitSuccess, _ ) -> do
-- we have to close the handle else loadRows can't access the file !
hClose handle
loaded <- loadRows tmpPath
return $ Right loaded
(exitCode, stdErr) -> return $ Left $ "Error happened " ++ show exitCode ++ "\n" ++ show stdErr
return res
where
opts :: TempFileOptions
opts = TempFileOptions False
-- TODO return an Either or Maybe ?
-- return an either instead
loadPcapIntoFrame ::
(Frames.InCore.RecVec a
, Frames.CSV.ReadRec a
, ColumnHeaders a
, V.RecMapMethod Show ElField a, V.RecordToList a
, Members [Log, Cache, Embed IO ] m)
=> TsharkParams
-> FilePath
-> Sem m (Either String (FrameRec a))
loadPcapIntoFrame params path = do
Log.info $ "Start loading pcap " <> tshow path
x <- getCache cacheId
case x of
Right frame -> do
Log.debug $ tshow cacheId <> " in cache"
return $ Right frame
Left err -> do
Log.debug $ "cache miss: " <> tshow err
Log.debug "Calling tshark"
(tempPath , exitCode, stdErr) <- liftIO $ do
withTempFileEx opts "/tmp" "mptcp.csv" $ \tmpPath handle -> do
(exitCode, herr) <- exportToCsv params path handle
hClose handle
return (tmpPath, exitCode, herr)
if exitCode == ExitSuccess
then do
Log.debug $ "exported to file " <> tshow tempPath
frame <- liftIO $ loadRows tempPath
Log.debug $ "Number of rows after loading " <> tshow (frameLength frame)
cacheRes <- putCache cacheId frame
-- use ifThenElse instead
if cacheRes then
Log.info "Saved into cache"
else
pure ()
return $ Right frame
else do
Log.info $ "Error happened: " <> tshow exitCode
Log.info $ tshow stdErr
return $ Left stdErr
where
cacheId = CacheId [path] "" "csv"
opts :: TempFileOptions
opts = TempFileOptions True
-- buildTcpFrameFromFrame
-- \ Build a frame with only packets belonging to @streamId@
buildAFrameFromStreamIdTcp :: (Members [Log, Cache, Embed IO ] m)
=> TsharkParams
-> FilePath
-> StreamId Tcp
-> Sem m (Either String (FrameFiltered TcpConnection Packet))
buildAFrameFromStreamIdTcp params pcapFilename streamId = do
res <- loadPcapIntoFrame params pcapFilename
return $ case res of
Left err -> Left err
Right frame -> buildTcpConnectionFromStreamId frame streamId
buildAFrameFromStreamIdMptcp :: (Members [Log, Cache, Embed IO ] m)
=> TsharkParams
-> FilePath
-> StreamId Mptcp
-> Sem m (Either String (FrameFiltered MptcpConnection Packet))
buildAFrameFromStreamIdMptcp params pcapFilename streamId = do
Log.debug ("Building frame for mptcp stream " <> tshow streamId)
res <- loadPcapIntoFrame params pcapFilename
return $ case res of
Left err -> Left err
Right frame -> buildMptcpConnectionFromStreamId frame streamId