diff --git a/src/Fluxzy.Core.Pcap/OutOfProcessCaptureContext.cs b/src/Fluxzy.Core.Pcap/OutOfProcessCaptureContext.cs index 63bf9d4c..a99e7a36 100644 --- a/src/Fluxzy.Core.Pcap/OutOfProcessCaptureContext.cs +++ b/src/Fluxzy.Core.Pcap/OutOfProcessCaptureContext.cs @@ -124,6 +124,7 @@ public void Flush() lock (this) { _writer.Write((byte) MessageType.Flush); + _writer.Flush(); } } diff --git a/src/Fluxzy/Commands/StartCommandBuilder.cs b/src/Fluxzy/Commands/StartCommandBuilder.cs index 30ec24b4..082bc665 100644 --- a/src/Fluxzy/Commands/StartCommandBuilder.cs +++ b/src/Fluxzy/Commands/StartCommandBuilder.cs @@ -308,7 +308,11 @@ public async Task Run(InvocationContext invocationContext, CancellationToken pro var uaParserProvider = parseUserAgent ? new UaParserUserAgentInfoProvider() : null; var systemProxyManager = new SystemProxyRegistrationManager(new NativeProxySetterManager().Get()); - await using var scope = new ProxyScope(() => new FluxzyNetOutOfProcessHost(), a => new OutOfProcessCaptureContext(a)); + // Scope owns the out-of-proc capture subprocess lifetime. It must be disposed + // BEFORE PackDirectoryToFile runs so the subprocess closes its pcapng FileStreams + // and flushes all buffered packet data to disk; otherwise small captures can sit + // in the 4 KB FileStream buffer and the packager's Length==0 skip drops them. + await using (var scope = new ProxyScope(() => new FluxzyNetOutOfProcessHost(), a => new OutOfProcessCaptureContext(a))) { if (!ValidateSetting(invocationContext, proxyStartUpSetting)) { invocationContext.ExitCode = 1; @@ -390,6 +394,8 @@ public async Task Run(InvocationContext invocationContext, CancellationToken pro } } + } // scope dispose: subprocess exits, pcapng FileStreams closed + flushed + invocationContext.Console.Out.WriteLine("Proxy ended, gracefully"); if (outFileInfo != null) { diff --git a/test/Fluxzy.Tests/Cli/CliTestBase.cs b/test/Fluxzy.Tests/Cli/CliTestBase.cs index 3660e20d..54cfa839 100644 --- a/test/Fluxzy.Tests/Cli/CliTestBase.cs +++ b/test/Fluxzy.Tests/Cli/CliTestBase.cs @@ -132,7 +132,8 @@ protected async Task Run_Cli_Output(string proto, CaptureType rawCap, if (rawCap != CaptureType.None) { var rawCapStream = archiveReader.GetRawCaptureStream(connection.Id); - Assert.True(await rawCapStream!.DrainAsync(disposeStream: true) > 0); + Assert.NotNull(rawCapStream); + Assert.True(await rawCapStream.DrainAsync(disposeStream: true) > 0); } if (rule)