File Extractor¶
pcapkit.foundation.extraction contains
Extractor only,
which synthesises file I/O and protocol analysis,
coordinates information exchange in all network layers,
and extracts parameters from a PCAP file.
See also
pypcap, pcap-ct and pypcapfile are supported by
pcapkit.foundation.engines.pypcap.PyPCAP (engine='pypcap'),
pcapkit.foundation.engines.pcap_ct.PCAP_CT (engine='pcap_ct')
and pcapkit.foundation.engines.pypcapfile.PyPCAPFile
(engine='pypcapfile'). Each supports less than the
default engine does; Engine Support tabulates the gaps, and
Engine Prerequisites gives what each needs installed.
- class pcapkit.foundation.extraction.Extractor[_P](fin=None, fout=None, format=None, auto=True, extension=True, store=True, files=False, nofile=False, verbose=False, engine=None, layer=None, protocol=None, reassembly=False, reasm_strict=True, reasm_store=True, reasm_timeout=None, trace=False, trace_fout=None, trace_format=None, trace_byteorder=sys.byteorder, trace_nanosecond=False, trace_bidirectional=True, trace_analyse=False, ip=False, ipv4=False, ipv6=False, tcp=False, buffer_size=io.DEFAULT_BUFFER_SIZE, buffer_save=False, buffer_path=None, no_eof=False, context=None)[source]¶
-
Extractor for PCAP files.
Notes
For supported engines, please refer to
run().Changed in version 1.1.1.post2:
strictis renamedreasm_strict, with no alias, andreasm_storeis inserted after it, so a positional argument fromtraceonwards moves one place along.Changed in version 1.5.0:
layerandprotocolstop the dissection where they say, which 1.4.x ignored (#356). A stream given asfinis left open: only a file the extractor opened itself is closed (#610).reasm_timeout,trace_bidirectionalandtrace_analyseare inserted among the positional parameters andcontextis appended, so a positional argument afterreasm_storehas to move to a keyword. Flows are traced bidirectionally by default.engineis typedEngineBase, the base every engine derives from (#1022). A callback given asverboseis called on every engine, where the third-party engines replaced it with their own printer (#1874).- __init__(fin=None, fout=None, format=None, auto=True, extension=True, store=True, files=False, nofile=False, verbose=False, engine=None, layer=None, protocol=None, reassembly=False, reasm_strict=True, reasm_store=True, reasm_timeout=None, trace=False, trace_fout=None, trace_format=None, trace_byteorder=sys.byteorder, trace_nanosecond=False, trace_bidirectional=True, trace_analyse=False, ip=False, ipv4=False, ipv6=False, tcp=False, buffer_size=io.DEFAULT_BUFFER_SIZE, buffer_save=False, buffer_path=None, no_eof=False, context=None)[source]¶
Initialise PCAP Reader.
- Parameters:
fin (
str|IO[bytes] |None) – file name to be read or a binary IO object; if file not exist, raiseFileNotFoundformat (
Literal['pcap','cap','json','tree','text','txt','plist','xml'] |None) – file format of outputauto (
bool) – if automatically run till EOFextension (
bool) – if check and append extensions to output filestore (
bool) – if store extracted packet infofiles (
bool) – if split each frame into different filesnofile (
bool) – if no output file is to be dumpedverbose (
bool|Callable[[Extractor,Frame|PCAPNG|scapy.packet.Packet|dpkt.dpkt.Packet|pyshark.packet.packet.Packet|pcap_packet|Tuple[float,bytes]],Any]) – aboolvalue or a function takes theExtractorinstance and current parsed frame (depends on engine selected) as parameters to print verbose output informationengine (
Literal['default','pcapkit','dpkt','scapy','pyshark','pypcap','pcap_ct','pypcapfile'] |None) – extraction engine to be usedlayer (
Literal['link','internet','transport','application','none'] |None) – extract til which layerprotocol (
str|ProtocolBase|Type[ProtocolBase] |None) – extract til which protocolreassembly (
bool) – if perform reassemblyreasm_strict (
bool) – if set strict flag for reassemblyreasm_store (
bool) – if store reassembled datagramsreasm_timeout (
float|None) – reassembly timeout in seconds, measured on the capture’s own clock rather than the host’s, since an offline parser has no other notion of time passing;Noneselects each protocol’s own default – 60 seconds for IPv4 (RFC 1122 Section 3.3.2) and IPv6 (RFC 8200 Section 4.5), disabled for TCP, which no specification gives a deadline. Passmath.infto disable it everywheretrace (
bool) – if trace TCP traffic flowstrace_fout (
str|None) – path name for flow tracer if necessarytrace_format (
Literal['pcap','cap','json','tree','text','txt','plist','xml'] |None) – output file format of flow tracertrace_byteorder (
Literal['big','little']) – output file byte ordertrace_nanosecond (
bool) – output nanosecond-resolution file flagtrace_bidirectional (
bool) – whether both halves of a conversation are traced as one flow, which is the default;Falsetraces a flow per directiontrace_analyse (
bool) – whether each traced flow reassembles its application layer, so that itspacketcan be read. Off by default, because it buffers every traced payload – a cost tracing does not otherwise pay. Unavailable on thepysharkengine, which reports dissected fields rather than the octets behind themip (
bool) – if record data for IPv4 & IPv6 reassembly (must be used withreassembly=True)ipv4 (
bool) – if perform IPv4 reassembly (must be used withreassembly=True)ipv6 (
bool) – if perform IPv6 reassembly (must be used withreassembly=True)tcp (
bool) – if perform TCP reassembly and/or flow tracing (must be used withreassembly=Trueortrace=True)buffer_size (
int) – buffer size for reading input file (forSeekableReaderonly)buffer_save (
bool) – if save buffer to file (forSeekableReaderonly)buffer_path (
str|None) – path name for buffer file if necessary (forSeekableReaderonly)no_eof (
bool) – if not raiseEOFErrorwhen reach EOF – retry instead, which is what a live capture on a pipe or on standard input wants, since a read there blocks until the writer produces more or closes. Retrying stops as soon as one retry finds nothing new, so an exhausted input finishes rather than spinning; on a seekable input, where nothing blocks, that means a file still being appended to ends at the data present when the extraction reached itcontext (
ContextRegistry|ProtocolContext|Mapping[str,ProtocolContext] |Iterable[ProtocolContext] |None) – caller supplied parsing context for protocols that need information not carried on the wire, keyed by protocol index ID – cf.pcapkit.corekit.context. Accepts aContextRegistry, a singleProtocolContext, a mapping, or any iterable of contexts. The channel is honoured by thedefault,pcapandpcapngengines, which parse withpcapkit’s own protocol implementations; the third party engines ignore it.
- Warns:
pcapkit.utilities.warnings.FormatWarning– Warns under the following circumstances:If using PCAP output for TCP flow tracing while the extraction engine is PyShark or PyPCAPFile.
If using PCAP output while the extraction engine is a third-party one, i.e. DPKT, Scapy, PyShark, PyPCAP, pcap-ct or PyPCAPFile.
If output file format is not supported.
In each case the engine is the one that will actually run: a requested engine that is unavailable falls back to the default engine first, which supports PCAP output.
pcapkit.utilities.warnings.EngineWarning– If the requested extraction engine is not available, cf.run().pcapkit.utilities.warnings.AttributeWarning– Iftrace_analyseis requested while the extraction engine is PyShark.
- Raises:
UnsupportedCall – If
finis a stream without astrnameand the engine that will run – Scapy, PyShark, PyPCAP or pcap-ct – opens its input by path.
- property format: Literal['pcap', 'cap', 'json', 'tree', 'text', 'txt', 'plist', 'xml']¶
Format of output file.
- Raises:
UnsupportedCall – If
self._flag_qis set asTrue, as output is disabled by initialisation parameter.
- property input: str¶
Name of input PCAP file.
For a binary IO object without a
strname, a placeholder naming its type, e.g.<BytesIO>.
- property output: str¶
Name of output file.
- Raises:
UnsupportedCall – If
self._flag_qis set asTrue, as output is disabled by initialisation parameter.
- property frame: tuple[Frame | PCAPNG | scapy.packet.Packet | dpkt.dpkt.Packet | pyshark.packet.packet.Packet | pcap_packet | Tuple[float, bytes], ...]¶
Extracted frames.
- Raises:
UnsupportedCall – If
self._flag_disFalse, as storing frame data is disabled.
- property reassembly: ReassemblyData¶
Frame record for reassembly.
ipv4– tuple of IPv4 payload fragment (reasm.ipv4.datagram)ipv6– tuple of IPv6 payload fragment (reasm.ipv6.datagram)tcp– tuple of TCP payload fragment (reasm.tcp.datagram)
- Raises:
UnsupportedCall – If
self._flag_risFalse, as reassembly is disabled.
Changed in version 1.1.1: Raises
UnsupportedCallwhen reassembly is disabled, where 1.1.0 built the record regardless.
- property trace: TraceFlowData¶
Index table for traced flow.
tcp– tuple of TCP flows (trace.tcp.index)
- Raises:
UnsupportedCall – If
self._flag_tisFalse, as flow tracing is disabled.
Changed in version 1.1.1: Raises
UnsupportedCallwhen flow tracing is disabled, where 1.1.0 built the record regardless.
- property engine: EngineBase[_P]¶
PCAP extraction engine.
- classmethod register_dumper(format, dumper, ext)[source]¶
Register a new dumper class.
Notes
The fully qualified class name of the new dumper class should be
{dumper.module}.{dumper.name}.The overwrite guard fires only when the incumbent dumper differs from the replacement, so re-registering the exact same object is a silent no-op rather than a warning about nothing displaced – the identity guard of the code-keyed registrars (#718, #739).
__output__maps each format to a(dumper, ext)pair, so the identity check compares the incumbent dumper (index0), not the pair – a re-registration that only changesextis still identity-equal on the dumper and stays silent, since the dumper is what “the same object” means here, not the pair as a whole.__output__is also acollections.defaultdict, unlike the engine, reassembly and flow tracing registries;dict.get()does not invoke the default factory the waycls.__output__[format]would, so it stays non-inserting here as well.The dumper
formatshipped with, as its descriptor or as the class it names, restores the shipped entry rather than storing the class, so an override can be undone and the deferred import is kept (#1363, #1364).- Parameters:
format (
str) – format namedumper (
ModuleDescriptor[dictdumper.dumper.Dumper] |Type[dictdumper.dumper.Dumper]) – module descriptor or adictdumper.dumper.Dumpersubclassext (
str) – file extension
- Raises:
RegistryError – If
dumperis not a class, or not aDumpersubclass.- Warns:
RegistryWarning– If a different dumper is already registered forformat; it is overwritten.
Changed in version 1.3.0:
dumper, a module descriptor or a class, replaces themoduleandclass_name pair, with no alias.
- classmethod register_engine(name, engine)[source]¶
Register a new extraction engine.
Notes
The fully qualified class name of the new extraction engine should be
{engine.module}.{engine.name}.The overwrite guard fires only when the incumbent differs from the replacement, so re-registering the exact same object is a silent no-op rather than a warning about nothing displaced – the identity guard of the code-keyed registrars (#718, #739).
The one built-in admitted is the engine
nameshipped with, as its descriptor or as the class it names: it restores the shipped entry, so an override can be undone (#1363).- Parameters:
name (
str) – engine nameengine (
ModuleDescriptor[Engine] |Type[Engine]) – module descriptor or anEnginesubclass; a class deriving only fromEngineBaseis refused, as that is the base for pcapkit’s own engines, which the library registers itself (GitHub issue #1016), unless it is the enginenameshipped with
- Raises:
RegistryError – If
engineis not a class, or not anEnginesubclass.- Warns:
RegistryWarning– If a different class is already registered undername; it is overwritten.
Changed in version 1.3.0:
engine, a module descriptor or a class, replaces themoduleandclass_name pair, with no alias, and the engine name it took asengineisname.
- classmethod register_reassembly(protocol, reassembly)[source]¶
Register a new reassembly engine.
Notes
The fully qualified class name of the new reassembly engine should be
{reassembly.module}.{reassembly.name}.The overwrite guard fires only when the incumbent differs from the replacement, so re-registering the exact same object is a silent no-op rather than a warning about nothing displaced – the identity guard of the code-keyed registrars (#718, #739).
The one built-in admitted is the class
protocolshipped with, as its descriptor or as the class it names: it restores the shipped entry, so an override can be undone (#1363).- Parameters:
protocol (
str) – protocol namereassembly (
ModuleDescriptor[Reassembly] |Type[Reassembly]) – module descriptor or aReassemblysubclass; a class deriving only fromReassemblyBaseis refused, as that is the base for pcapkit’s own classes, which the library registers itself (GitHub issue #1016), unless it is the classprotocolshipped with
- Raises:
RegistryError – If
reassemblyis not a class, or not aReassemblysubclass.- Warns:
RegistryWarning– If a different class is already registered underprotocol; it is overwritten.
Changed in version 1.3.0:
reassembly, a module descriptor or a class, replaces themoduleandclass_name pair, with no alias.
- classmethod register_traceflow(protocol, traceflow)[source]¶
Register a new flow tracing engine.
Notes
The fully qualified class name of the new flow tracing engine should be
{traceflow.module}.{traceflow.name}.The overwrite guard fires only when the incumbent differs from the replacement, so re-registering the exact same object is a silent no-op rather than a warning about nothing displaced – the identity guard of the code-keyed registrars (#718, #739).
The one built-in admitted is the class
protocolshipped with, as its descriptor or as the class it names: it restores the shipped entry, so an override can be undone (#1363).- Parameters:
protocol (
str) – protocol nametraceflow (
ModuleDescriptor[TraceFlow] |Type[TraceFlow]) – module descriptor or aTraceFlowsubclass; a class deriving only fromTraceFlowBaseis refused, as that is the base for pcapkit’s own classes, which the library registers itself (GitHub issue #1016), unless it is the classprotocolshipped with
- Raises:
RegistryError – If
traceflowis not a class, or not aTraceFlowsubclass.- Warns:
RegistryWarning– If a different class is already registered underprotocol; it is overwritten.
Changed in version 1.3.0:
traceflow, a module descriptor or a class, replaces themoduleandclass_name pair, with no alias.
- run()[source]¶
Start extraction.
We use
import_test()to check if a certain engine is available or not. For supported engines, each engine has different driver method:Default drivers:
PCAP Format:
pcapkit.foundation.engines.pcap.PCAPPCAP-NG Format:
pcapkit.foundation.engines.pcapng.PCAPNG
DPKT driver:
pcapkit.foundation.engines.dpkt.DPKTScapy driver:
pcapkit.foundation.engines.scapy.ScapyPyShark driver:
pcapkit.foundation.engines.pyshark.PySharkPyPCAP driver:
pcapkit.foundation.engines.pypcap.PyPCAPpcap-ct driver:
pcapkit.foundation.engines.pcap_ct.PCAP_CTPyPCAPFile driver:
pcapkit.foundation.engines.pypcapfile.PyPCAPFile
- Warns:
pcapkit.utilities.warnings.EngineWarning– If the extraction engine is not available: its dependency is not installed, itsunsupported_reason()rules it out, or the supplied engine is unknown.- Raises:
FormatError – If the selected engine cannot read the input’s format – for the default engine, if it is neither PCAP nor PCAP-NG – or if the built-in PCAP-NG engine reads a PCAP-NG input to PCAP output.
- Return type:
None
- static import_test(engine, *, name=None)[source]¶
Test import for extraction engine.
- Parameters:
- Warns:
pcapkit.utilities.warnings.EngineWarning– If the engine module is not installed.- Return type:
- Returns:
If succeeded, returns the module; otherwise, returns
None.
- classmethod make_name(fin='in.pcap', fout='out', fmt='tree', extension=True, *, files=False, nofile=False)[source]¶
Generate input and output filenames.
The method will perform following processing:
sanitise
finas the input PCAP filename;in.pcapas default value and append.pcapextension if needed andextensionisTrue; as well as test if the file exists; for a binary IO object, use itsname, or a placeholder such as<BytesIO>if it has nostrone;if
nofileisTrue, skips following processing;look up the output file extension registered for
fmt; should none be registered, then it raisesFormatError;create the parent directory of
fout, and withfilesthefoutdirectory itself;it will also append corresponding file extension to the output file name if needed and
extensionisTrue.
And the method returns the generated input and output filenames as follows:
input filename
output filename / directory name
output format
output file extension, bare, i.e. without the leading
., so that a caller composing a per-frame filename writesf'{name}.{ext}'if split each frame into different files
- Parameters:
fin (
str|IO[bytes]) – Input filename or a binary IO object.fout (
str) – Output filename.fmt (
Literal['pcap','cap','json','tree','text','txt','plist','xml']) – Output file format.extension (
bool) – If append.pcapfile extension to the input filename iffindoes not have such file extension; if check and append extensions to output file.files (
bool) – If split each frame into different files.nofile (
bool) – If no output file is to be dumped.
- Return type:
tuple[str,str|None,Literal['pcap','cap','json','tree','text','txt','plist','xml'],str|None,bool]- Returns:
Generated input and output filenames.
- Raises:
FileNotFound – If input file does not exist.
FormatError – If no file extension is registered for
fmt.
- record_header()[source]¶
Read global header.
The method parses the global header with the matching built-in engine –
PCAPfor a PCAP file, orPCAPNGfor the first section header block of a PCAP-NG file – rewinds the input to its start, and returns that engine, which holds the parsed header.Unless output is disabled, the engine also dumps the parsed header, under the name of
Global Headerfor PCAP andSection Header 1for PCAP-NG, and setsself._offmtto the output format.This is the shared global-header step of the third-party engines –
DPKT,ScapyandPyShark– which call it at setup, so their output opens with the header record dumped above andformatis set even for a capture with no frames.- Raises:
FormatError – If the input is neither a PCAP nor a PCAP-NG file.
- Return type:
EngineBase[_P]
- _open_output(**kwargs)[source]¶
Create the output writer.
The built-in engines call this at their global-header step. The PCAP engine passes the header’s fields as
protocol,byteorder,nanosecond,thiszone,sigfigsandsnaplen:PCAPIOwrites its own global header from them, and the other writers ignore them. The PCAP-NG engine passes none.run()calls it again, without arguments, after the engine has started, for the engines that have no such step. Only the first call has an effect.Under split mode, i.e.
self._flag_fisTrue,self._ofilestays a factory, withkwargsbound, that the engines call once per output file.- Parameters:
**kwargs (
Any) – Global header fields for the writer.
- record_frames()[source]¶
Read packet frames.
The method calls
self._exeng.read_frameto parse each frame from the input PCAP file; and performs cleanup by callingself._exeng.closeupon completion of the parsing process.Notes
Under non-auto mode, i.e.
self._flag_aisFalse, the method performs no action.
- __output__: DefaultDict[str, tuple[ModuleDescriptor[dictdumper.dumper.Dumper] | Type[dictdumper.dumper.Dumper], str | None]]¶
Format dumper mapping for writing output files. Each value pairs the dumper, as a module descriptor or a
dictdumper.dumper.Dumpersubclass, with the file extension of its format.
- __engine__: dict[str, ModuleDescriptor[EngineBase] | Type[EngineBase]]¶
Engine mapping for extracting frames. The values should be a module descriptor or an
EngineBasesubclass: every built-in derives from the base directly, and the publicregister_engineadditionally admits onlyEnginesubclasses.
- __reassembly__: dict[str, ModuleDescriptor[ReassemblyBase] | Type[ReassemblyBase]]¶
Reassembly support mapping for extracting frames. The values should be a module descriptor or a
ReassemblyBasesubclass: every built-in derives from the base directly, and the publicregister_reassemblyadditionally admits onlyReassemblysubclasses.
- __traceflow__: dict[str, ModuleDescriptor[TraceFlowBase] | Type[TraceFlowBase]]¶
Flow tracing support mapping for extracting frames. The values should be a module descriptor or a
TraceFlowBasesubclass: every built-in derives from the base directly, and the publicregister_traceflowadditionally admits onlyTraceFlowsubclasses.
- _cleanup(*, failed=False)[source]¶
Cleanup after extraction & analysis.
The method sets
self._flag_easTrueand then calls_release(), which closes the input file if this class opened it and callsself._exeng.close.That proviso is the whole of it: a handle opened here –
fingiven as a path, i.e.self._flag_sset – is closed, and a stream the caller supplied is left alone for the caller to close when it is done with it.It also tells the flow tracer the capture has ended, via
TraceFlow.finish. That is the point at which a traced flow nothing has superseded can be said to be over, so it is where such a flow is finalised and its callbacks run. This method can run more than once for one extraction – each call to__next__()or__call__()that reaches the end of a caller-supplied stream runs it again – sofinishis required to be idempotent rather than guarded here.- Parameters:
failed (
bool) – whether the extraction stopped on an error instead, which is the constructor raising (#2100, #2107). The input and the engine are still released, but the capture has not ended, so the flow tracer is not finished – its callbacks would report flows of a capture that was never read to its end – and_flag_eis not set. The constructor may have failed before choosing an engine, as an unknown format does, and then there is none to close. AnExceptionfrom the engine’s close is logged rather than raised, so it cannot replace the error that stopped the constructor.- Return type:
- _release(*, failed=False)[source]¶
Close the input this class owns, and the engine.
The one close path, shared by
_cleanup()and__exit__(), so that the two cannot drift apart on what is released or in which order.- Parameters:
failed (
bool) – see_cleanup(). When set, a missing engine is skipped and anExceptionfrom its close is logged rather than raised.- Return type:
- _flag_a: bool¶
Auto extract flag. It indicates if the extraction process should continue automatically until the EOF is reached.
- _flag_o: bool¶
Output opened flag. It indicates if
_open_output()has replaced the writer class in_ofilewith the writer.
- _flag_r: bool¶
Reassembly flag. It indicates if datagram reassembly is enabled. Every engine reads it to decide whether to feed
_reasm, and the engines that cannot reassemble clear it on startup.
- _flag_v: bool¶
Verbose flag. It indicates if verbose output is enabled, whether by
verbose=Trueor by a callback, which_vfunc_defaulttells apart.
- _flag_n: bool¶
No EOF flag. It is useful when the input is a live capture on a pipe or on standard input, where reaching the end of what has arrived so far does not mean the capture is over: the extraction retries instead of stopping. It retries only while the input is still producing, though – see
_note_eof_progress()for the rule and for what it narrows, without which an exhausted stream spins forever (#620).
- _flag_s: bool¶
Input filename flag. It indicates if the input file is a file name or a binary IO object. For the latter, we should not close the file object after extraction.
- _ifile: BufferedReader¶
Input file object.
- _finalizer: finalize | None¶
Backstop that closes
_ifilewhen the extractor is collected before_cleanup()has run, registered only when the stream is this class’s own to close (#1997), elseNone.__del__()alone is not enough, as GraalPy never calls it; aweakref.finalizeruns there and on CPython alike.
- _ofile: dictdumper.dumper.Dumper | Type[dictdumper.dumper.Dumper]¶
Output writer. It holds the writer class until
_open_output()replaces it with the writer, or under split mode with a factory.
- _fext: str | None¶
Output file extension, bare, i.e. without the leading
.–'json', not'.json'. Normalised bymake_name(), whose docstring is the contract; the engines compose a per-frame filename asf'{name}.{ext._fext}'and supply the dot themselves.
- _frame: list[Frame | PCAPNG | scapy.packet.Packet | dpkt.dpkt.Packet | pyshark.packet.packet.Packet | pcap_packet | Tuple[float, bytes]]¶
Frame records.
- _reasm: ReassemblyManager¶
Frame record for reassembly.
- _trace: TraceFlowManager¶
Frame record for flow tracing.
- _eof_mark: int | None¶
Position of the input stream at the previous end of stream, or
Nonebefore the first one. Comparing it against the position at the next end of stream is what tells a live capture that has paused – retry, more may arrive – from one that is finished, which is the termination condition forno_eof(#620).
- _vfunc: Callable[[Extractor, Frame | PCAPNG | scapy.packet.Packet | dpkt.dpkt.Packet | pyshark.packet.packet.Packet | pcap_packet | Tuple[float, bytes]], Any]¶
Verbose callback function.
- _vfunc_default: bool¶
Default verbose printer flag. It is set only by
verbose=True, which asks for the default output, and an engine whose frames are not PyPCAPKit’s own replaces_vfuncwith its own printer only when it is set. A callback given asverboseleaves it unset, so every engine keeps that callback (#1874).
- _exnam: Literal['default', 'pcapkit', 'dpkt', 'scapy', 'pyshark', 'pypcap', 'pcap_ct', 'pypcapfile']¶
Extraction engine name.
- _exeng: EngineBase[_P]¶
Extraction engine instance.
- _exptl: str | ProtocolBase | Type[ProtocolBase]¶
Extract til protocol.
- _exctx: ContextRegistry¶
Caller supplied parsing context, cf.
pcapkit.corekit.context.
- __iter__()[source]¶
Iterate and parse PCAP frame.
- Raises:
IterableError – If
self._flag_aisTrue, as such operation is not applicable.- Return type:
- __next__()[source]¶
Iterate and parse next PCAP frame.
It will call
self._exeng.read_frameto parse next PCAP frame internally, until the EOF reached; then it callsself._cleanupfor the aftermath.- Return type:
_P
- __call__()[source]¶
Works as a simple wrapper for the iteration protocol.
- Raises:
CallableError – If
self._flag_aisTrue, as such operation is not applicable.- Return type:
_P
- __exit__(exc_type, exc_value, traceback)[source]¶
Release what this class holds when the
withblock exits.The engine is always closed. The input stream is closed only if this class owns it – the rule of #610, as
_owns_input()writes it down and_cleanup()and the backstops already follow. A stream the caller supplied stays open for the caller to close, so leaving the block no longer closes it behind the caller’s back (#1999).For a caller’s non-seekable stream, the stream this class owns is the
SeekableReaderwrapped around it, and that wrapper is closed; it was built withstream_closingoff, so closing it leaves the caller’s stream underneath open.Both go through
_release(), the close path_cleanup()shares. Unlike_cleanup(), this neither finishes the flow tracer nor sets_flag_e: leaving the block is not the end of the capture – an extraction withauto=Falsemay be left before end of file, or on an error – so there is nothing it can truthfully report as over, and an extraction that did reach the end has already been through_cleanup(). An error from the engine’s close propagates.
- __del__()[source]¶
Release the input stream if this class still owns an open one.
A backstop for the extraction that is abandoned rather than finished: with
auto=Falsethe caller drives__next__()itself, and one that stops before end of file never reaches_cleanup()at all, so the ownership rule there never gets to run. The handle then survives until the interpreter collects it, and CPython announces that with aResourceWarningraised wherever collection happens to run, which can be far from the code that abandoned the handle (#606).GraalPy never calls this method, so the same close is also registered as the
weakref.finalizein_finalizer, which runs on either interpreter (#1997). This method stays for whoever calls it directly, a subclass extending it throughsuper()among them, and both are safe to run for one stream: whichever comes second finds it already closed.This is a backstop and not the recommended route: collection is not deterministic, and
Extractortakes part in a reference cycle through its engine, so a handle can outlive its last reference until the cyclic collector runs. UseExtractoras a context manager – see__enter__()– where the moment of release matters.Note
A finaliser must not raise, so this reads through
__dict__rather than attribute access. That matters for more than tidiness:_flag_sis assigned early in__init__()and_ifileonly much later, so a constructor that fails in between – an unreadable path, an unknown format – leaves an instance whose flag says “mine” and which has no stream at all. The close itself is guarded too, that being what a close during interpreter shutdown can fail at.
- classmethod _register_internal_engine(name, engine)[source]¶
Register an engine for pcapkit’s own use, bypassing the public guard.
Unlike
register_engine(), accepts a class deriving only fromEngineBase, which is how every built-in engine is written. Not part of the public API.- Parameters:
name (
str) – engine nameengine (
ModuleDescriptor[EngineBase] |Type[EngineBase]) – module descriptor or anEngineBasesubclass
- Raises:
RegistryError – If
engineis not anEngineBasesubclass.- Warns:
RegistryWarning– If a different class is already registered undername; it is overwritten.
- _owns_input()[source]¶
Whether the input stream is this class’s to close.
The one place the ownership rule of #610 is written down, so that
_cleanup(),__exit__(),__del__()and the registration of_finalizercannot drift apart on it.- Return type:
- Returns:
Truewhen the input stream was opened by this class and is therefore its to release –fingiven as a path, i.e.self._flag_sset, or aSeekableReaderthis class wrapped around a caller’s non-seekable stream.Falsefor a stream the caller supplied and still owns, andFalsewhen there is no stream at all.
Note
The
Truecases are written as separate tests rather than folded together because they can in principle coincide – a path naming something non-seekable would be opened here and then wrapped – and the answer has to beTruefor both halves of it. That cannot arise, sincemake_name()admits a path only throughos.path.isfile(), which isFalsefor a FIFO or a device, and a regular file is always seekable. The second test is therefore defensive rather than dead, and is the reasonSeekableReader(..., stream_closing=self._flag_s)passes the flag instead ofFalse.
- _note_eof_progress()[source]¶
Record this end of stream, and say whether the input advanced to reach it.
This is the termination condition for
no_eof. The flag means “end of stream is not necessarily the end of the capture” – which is true of a live capture, and is whypcapkit.__main__sets it forfin='-'– so the extraction retries rather than stopping. Without a way to decide when the stream is genuinely finished, an exhausted one raises end of stream again on every retry, which is the spin #620 reported.The signal is the input’s own position. End of stream is raised by
prepare()when the bytes remaining in the stream measure zero, and it restores the position before raising, so the position at end of stream is stable. Two consecutive ends of stream at the same position therefore mean nothing arrived between them.What “between them” covers, exactly¶
For a pipe, everything, and the live-capture case is safe. A blocking read on a pipe whose writer is open but idle blocks; it does not report end of stream. So a pipe reports it only once the writer has closed – permanently – and a capture that merely pauses never reaches here at all. Measured: a pipe paused mid-capture for 1.5s blocked for the whole pause and then delivered its remaining frames, with this method not consulted until after the writer closed.
For a seekable regular file, only the microseconds between two immediately consecutive probes, because such a file does not block – it reports end of stream at once. So an extraction over a file that is still being appended to ends at the data present when it got there, rather than following the writer. That is a deliberate narrowing, and it is measured: a file gaining its last record 0.6s in yields five of its six frames here, where the unbounded retry of
6c3d1b0d9yielded all six. Unbounded retrying is the defect #620 reports, so some stopping rule had to be chosen, and a timed grace period would only make the cut-off intermittent rather than absent. Following a growing file wants a deliberate policy of its own; see the note indocs/source/changelog/1.5.0.rst.Warning
Not idempotent. Each call consumes one end-of-stream observation by overwriting
_eof_mark, so calling it twice for one end of stream spends the retry it would have granted. Call it exactly once per handler, which is what each call site does.