- 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>
73 lines
2.8 KiB
C
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);
|
|
}
|