NetworkInspector.Sessions 0.7.0

dotnet add package NetworkInspector.Sessions --version 0.7.0
                    
NuGet\Install-Package NetworkInspector.Sessions -Version 0.7.0
                    
This command is intended to be used within the Package Manager Console in Visual Studio, as it uses the NuGet module's version of Install-Package.
<PackageReference Include="NetworkInspector.Sessions" Version="0.7.0" />
                    
For projects that support PackageReference, copy this XML node into the project file to reference the package.
<PackageVersion Include="NetworkInspector.Sessions" Version="0.7.0" />
                    
Directory.Packages.props
<PackageReference Include="NetworkInspector.Sessions" />
                    
Project file
For projects that support Central Package Management (CPM), copy this XML node into the solution Directory.Packages.props file to version the package.
paket add NetworkInspector.Sessions --version 0.7.0
                    
#r "nuget: NetworkInspector.Sessions, 0.7.0"
                    
#r directive can be used in F# Interactive and Polyglot Notebooks. Copy this into the interactive tool or source code of the script to reference the package.
#:package NetworkInspector.Sessions@0.7.0
                    
#:package directive can be used in C# file-based apps starting in .NET 10 preview 4. Copy this into a .cs file before any lines of code to reference the package.
#addin nuget:?package=NetworkInspector.Sessions&version=0.7.0
                    
Install as a Cake Addin
#tool nuget:?package=NetworkInspector.Sessions&version=0.7.0
                    
Install as a Cake Tool

NetworkInspector.Sessions

NuGet

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:

  1. Create Session with a Stack.
  2. TryAddFrameSource (Idle only) and TryAddListener (Idle, Running, or Restarting).
  3. TryStart() — launches source and listener threads.
  4. WaitForCompletion() — blocks until all source jobs finish.
  5. Shutdown() or Dispose() — 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 OnStackChanged followed by OnNewPackets with the cursor reset to 0.
  • Every listener filter is re-bound to the new stack via TryDerive before 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's Matching pulls 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 SessionException with a SessionErrorCode.
  • Shutdown() throws AggregateException when cleanup (dispose) fails for one or more items.
  • Dispose() captures shutdown failures in Session.ShutdownErrors instead 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, PacketIndex
  • NetworkInspector.Filter — per-listener filters (FILTER_GUIDE.md)
  • NetworkInspector.SourcesIFrameSource implementations
Product 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. 
Compatible target framework(s)
Included target framework(s) (in package)
Learn more about Target Frameworks and .NET Standard.

NuGet packages

This package is not used by any NuGet packages.

GitHub repositories

This package is not used by any popular GitHub repositories.

Version Downloads Last Updated
0.7.0 0 8/27/2026
0.6.0 81 8/21/2026
0.5.0 106 7/11/2026