NetworkInspector.Sessions
0.6.0
dotnet add package NetworkInspector.Sessions --version 0.6.0
NuGet\Install-Package NetworkInspector.Sessions -Version 0.6.0
<PackageReference Include="NetworkInspector.Sessions" Version="0.6.0" />
<PackageVersion Include="NetworkInspector.Sessions" Version="0.6.0" />
<PackageReference Include="NetworkInspector.Sessions" />
paket add NetworkInspector.Sessions --version 0.6.0
#r "nuget: NetworkInspector.Sessions, 0.6.0"
#:package NetworkInspector.Sessions@0.6.0
#addin nuget:?package=NetworkInspector.Sessions&version=0.6.0
#tool nuget:?package=NetworkInspector.Sessions&version=0.6.0
NetworkInspector.Sessions
Session orchestration library for NetworkInspector.
What This Is
NetworkInspector.Sessions coordinates frame sources, the protocol stack, pull-based listeners, and background jobs. It provides thread-safe packet access, a packet store with re-parse fallback, and Roaring-bitmap indexing during parsing.
Each frame source runs on a dedicated thread. Parsed packets are stored once in a shared PacketStore; listeners pull data on notification instead of receiving pushed copies.
Lifecycle
graph TD
Idle["Idle<br/>sources/listeners registered"]
Running["Running<br/>source jobs active"]
Restarting["Restarting<br/>stack swap + reparse"]
Stopped["Stopped<br/>all sources finished"]
ShuttingDown["ShuttingDown<br/>teardown in progress"]
Idle -->|"TryStart()"| Running
Running -->|"last source completes"| Stopped
Running -->|"Restart()"| Restarting
Stopped -->|"Restart()"| Restarting
Restarting -->|"reparse done, sources active"| Running
Restarting -->|"reparse done, no sources"| Stopped
Running -->|"Shutdown()"| ShuttingDown
Stopped -->|"Shutdown()"| ShuttingDown
ShuttingDown -->|"cleanup complete"| Stopped
Typical flow:
- Create
Sessionwith aStack. TryAddFrameSource(Idle only) andTryAddListener(Idle, Running, or Restarting).TryStart()— launches source and listener threads.WaitForCompletion()— blocks until all source jobs finish.Shutdown()orDispose()— cancels listeners, disposes jobs and sources.
Key Types
| Type | Role |
|---|---|
Session |
Lifecycle orchestration and shared stores |
ISession |
Mutable session API (TryAddFrameSource, TryAddListener, TryStart, Restart, Shutdown) |
ISessionReader |
Read-only view for listeners (PacketCount, TryGetPacket, GetJobs) |
ISessionListener |
Pull-based notification callbacks |
JobInfo |
Public view of a background job (source, listener, or user job) |
ListenerInfo |
Public view of a listener subscription |
FrameSourceInfo |
Public view of a registered frame source |
PacketStore |
Chunked store retaining all parsed packets until restart or shutdown |
PacketRef |
A PacketId paired with its packet, so a filtered pull can report gapped ids |
PacketReadMode |
All or Matching — whether a pull applies the listener's filter |
PacketIdLayout |
Contiguous or Gapped — whether returned ids are consecutive |
SessionException |
Typed errors with SessionErrorCode |
Pull-Based Listeners
Producers set atomic NotifyFlags on each ListenerSlot and wake the listener thread via ManualResetEventSlim. The listener clears flags, then pulls data from ISessionReader:
| Flag | Callback |
|---|---|
NewPackets |
OnNewPackets(session, fromIndex, toIndexExclusive) |
SourceAdded / SourceCompleted |
OnSourcesChanged |
AllSourcesCompleted |
OnAllSourcesCompleted |
JobAdded / JobStatusChanged / JobRemoved |
OnJobsChanged |
StackChanged |
OnStackChanged — discard cached protocol state |
PhaseChanged |
OnPhaseChanged |
ShuttingDown |
OnShuttingDown |
Multiple events between two wake cycles coalesce into a single flag read.
Per-Listener Filters
A listener can register a filter, which then applies to that listener's pulls only:
session.TryAddListener(listener, "tcp.port == 443", out ListenerInfo? info, out FilterError? failure);
// Or hand over a filter you compiled yourself against the session stack:
session.TryAddListener(listener, myFilter, out info);
// No filter at all — every packet:
session.TryAddListener(listener, out info);
An empty or whitespace-only expression compiles to the always-match filter. A bad expression
leaves the session untouched: no listener is registered and failure explains why. Filters are
single-threaded and are only evaluated on their own listener thread.
Filtered Pulls
ISessionReader offers three read shapes. All of them fill a caller-owned buffer and allocate
nothing:
// 1. Packets only, contiguous ids implied by the start index.
int n = reader.ReadPackets(fromIndex, packetBuffer);
// 2. Packets paired with their ids; always contiguous.
PacketRef[] buffer = new PacketRef[256];
int n = reader.ReadPackets(startId, buffer, out PacketIdLayout layout);
// 3. Listener-bound, optionally filtered.
bool read = reader.TryReadPackets(
listenerId,
startId,
buffer,
PacketReadMode.Matching,
out int count,
out PacketIdLayout layout,
out FilterError? failure);
Matching scans from startId to the current PacketCount and keeps only what the filter
accepts, so layout becomes Gapped as soon as an id in the range is skipped. A listener without
a filter, or one whose filter is always-match, takes the unfiltered fast path and does no
per-packet work. Otherwise the filter's presence-index candidate set prunes the range first, and
only the survivors are evaluated.
TryReadPackets returns false with count == 0 when the filter refuses to produce a verdict:
it is poisoned by an earlier failure, a packet failed to evaluate, or the filter could not be
re-bound after a stack swap. All reads keep working in every one of those cases. An unknown
ListenerId throws SessionException(SessionErrorCode.ListenerNotFound).
Filtering never affects notifications: OnNewPackets always reports the raw, unfiltered id
window.
Restart (Stack Swap)
Restart(stackFactory) replaces the protocol stack without stopping running sources:
- Source threads are gated on a parse gate while existing frames are re-parsed in PacketId order (0 … N−1).
- The factory receives the session's internal
FrameInterfaceRegistry; the returned stack must use the same registry instance. - Listeners receive
OnStackChangedfollowed byOnNewPacketswith the cursor reset to 0. - Every listener filter is re-bound to the new stack via
TryDerivebefore pulls are re-enabled, yielding a fresh instance with empty flank state, an empty match cache, and no poison. A filter that cannot be re-bound — for example because the new stack no longer defines a referenced field — is dropped, and that listener'sMatchingpulls report the bind error instead of silently returning everything.
session.Restart(registry =>
{
StackBuilder builder = new(newSettings, registry);
builder.RegisterStandardProtocols();
return builder.Build();
});
TryUnsubscribe vs Shutdown
| Operation | Source job | Listener job | User job |
|---|---|---|---|
TryUnsubscribe(job) |
Cancels read loop; source stays for random access until Shutdown |
Cancels slot, calls OnUnsubscribed, removes from registry |
Cancels via CancellationToken |
Shutdown() |
Cancels all sources, waits, disposes everything | Cancels all listeners, sets SessionEnded status |
Cancels all jobs |
Convenience APIs: FrameSourceInfo.Stop() and ListenerInfo.Unsubscribe() delegate to TryUnsubscribe.
TryUnsubscribe returns false for foreign jobs, terminal jobs, or when the session is Idle/ShuttingDown.
TryRemoveJob
Removes a terminal job (Completed, Cancelled, or Failed) from the job list. Returns false if the job is not registered or was already removed. Throws SessionException if the job is still pending or running.
Error Handling
- Validation and state errors throw
SessionExceptionwith aSessionErrorCode. Shutdown()throwsAggregateExceptionwhen cleanup (dispose) fails for one or more items.Dispose()captures shutdown failures inSession.ShutdownErrorsinstead of throwing (standard .NET dispose pattern).
Thread Safety
All public Session methods are thread-safe. Counters use Interlocked; phase and flags use Volatile. Parsing is serialised under a shared SpinLock across source threads.
Dependencies
NetworkInspector.Core— stack, parsing,PacketIndexNetworkInspector.Filter— per-listener filters (FILTER_GUIDE.md)NetworkInspector.Sources—IFrameSourceimplementations
| Product | Versions Compatible and additional computed target framework versions. |
|---|---|
| .NET | net10.0 is compatible. net10.0-android was computed. net10.0-browser was computed. net10.0-ios was computed. net10.0-maccatalyst was computed. net10.0-macos was computed. net10.0-tvos was computed. net10.0-windows was computed. |
-
net10.0
- NetworkInspector.Core (>= 0.6.0)
- NetworkInspector.Filter (>= 0.6.0)
- NetworkInspector.Sources (>= 0.6.0)
- ZeroAlloc (>= 0.5.2)
NuGet packages
This package is not used by any NuGet packages.
GitHub repositories
This package is not used by any popular GitHub repositories.