zapret2-fork/nfq2/winnative/batch.c
loop-uh 24ac52ccae winws2 native: windows control events, persistent log handle, unlimited config file, host tests
- unix signals are replaced by named events Global\winws2_sig_<pid>_<hup|usr1|usr2|term>,
  'winws2 --wn-signal=<name>[:<pid>]' sends them. term is a graceful stop
- append mode files stay open, fclose only flushes (upstream reopens the log for every line)
- $file and unexpanded @file are read completely instead of the first 16K
- argument parsing moved to args.c and covered by tests/run.sh (includes cases recorded
  from the cygwin build). sync-upstream.sh runs the tests before pushing
- luajit is built with -Os

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-07 17:22:13 +03:00

73 lines
2.8 KiB
C

// Batched reinjection of unmodified packets.
// winws2 receives packets from windivert in bulk but reinjects them one by one : one syscall per packet.
// Here consecutive unmodified packets of the received bulk are collected and sent by one WinDivertSendEx call.
// Order of packets on the wire is preserved : anything else that is sent (modified packet, fake from lua)
// flushes the collected run first. Next receive flushes it too.
// Upstream sources are not changed. WinDivertRecvEx/WinDivertSend are redirected here by macros in compat.h.
// Set environment variable WINWS2_NO_BATCH=1 to turn batching off.
#include "windivert/windivert.h"
#undef WinDivertRecvEx
#undef WinDivertSend
static const uint8_t *rcv_buf = NULL; // last receive buffer
static size_t rcv_size = 0;
static const WINDIVERT_ADDRESS *rcv_addr = NULL; // last receive address array
static unsigned int rcv_addr_count = 0;
static HANDLE run_handle = NULL; // collected run
static const uint8_t *run_pkt = NULL;
static size_t run_len = 0;
static const WINDIVERT_ADDRESS *run_addr = NULL;
static unsigned int run_count = 0;
static int batch_off = -1;
static void wn_batch_flush(void)
{
if (run_count)
{
UINT sent;
WinDivertSendEx(run_handle, run_pkt, (UINT)run_len, &sent, 0, run_addr, run_count * sizeof(WINDIVERT_ADDRESS), NULL);
run_count = 0;
run_len = 0;
}
}
BOOL wn_WinDivertRecvEx(HANDLE handle, VOID *pPacket, UINT packetLen, UINT *pRecvLen, UINT64 flags, WINDIVERT_ADDRESS *pAddr, UINT *pAddrLen, LPOVERLAPPED lpOverlapped)
{
// receive buffer is about to be overwritten
wn_batch_flush();
wn_control_poll();
if (batch_off < 0) batch_off = getenv("WINWS2_NO_BATCH") != NULL;
rcv_buf = (const uint8_t*)pPacket;
rcv_size = packetLen;
rcv_addr = pAddr;
rcv_addr_count = (pAddr && pAddrLen) ? *pAddrLen / sizeof(WINDIVERT_ADDRESS) : 0;
return WinDivertRecvEx(handle, pPacket, packetLen, pRecvLen, flags, pAddr, pAddrLen, lpOverlapped);
}
BOOL wn_WinDivertSend(HANDLE handle, const VOID *pPacket, UINT packetLen, UINT *pSendLen, const WINDIVERT_ADDRESS *pAddr)
{
const uint8_t *pkt = (const uint8_t*)pPacket;
// packet that lives inside the receive buffer and has its original address is a reinject of unmodified packet.
// both buffers stay valid until the next receive
if (!batch_off && rcv_buf && pkt >= rcv_buf && pkt + packetLen <= rcv_buf + rcv_size &&
rcv_addr && pAddr >= rcv_addr && pAddr < rcv_addr + rcv_addr_count)
{
if (run_count && (handle != run_handle || pkt != run_pkt + run_len || pAddr != run_addr + run_count || run_count >= WINDIVERT_BATCH_MAX))
wn_batch_flush();
if (!run_count)
{
run_handle = handle;
run_pkt = pkt;
run_addr = pAddr;
}
run_len += packetLen;
run_count++;
if (pSendLen) *pSendLen = packetLen;
return TRUE;
}
wn_batch_flush();
return WinDivertSend(handle, pPacket, packetLen, pSendLen, pAddr);
}