Standalone FidoNet mailer daemon implementing the Comet protocol (TCP variant of the Nova protocol family) with BinkP/1.1 fallback. Written in Free Pascal for DOS/Win/OS2/Linux/FreeBSD. 15 source files, ~10K lines: - Protocol: length-prefixed frames, SHA-256/384/512, CRC-32, bidirectional transfer with sliding window, adaptive block sizing - Session: own TCP handshake with BinkP auto-detection on port 26638 - Outbound: BSO (Binkley), FrontDoor, D'Bridge format support - Daemon: multi-session with thread pool, outbound scanner - Paths: DOS<->Linux bridge with case-insensitive lookup, drive mapping - Config: INI-style with heavily documented sample (COMET.SAM) All 17 Nova interop bug fixes baked in from the start. 18/18 tests passing (CRC-32, SHA-256/384/512, frame encode/decode).
160 lines
4.3 KiB
ObjectPascal
160 lines
4.3 KiB
ObjectPascal
{
|
|
Frame layer test - verify encode/decode round-trip via loopback TCP.
|
|
Creates a listening socket, connects to it, sends frames, receives them.
|
|
}
|
|
program test_frame;
|
|
|
|
{$mode objfpc}{$H+}
|
|
|
|
uses
|
|
SysUtils, cometdef, cometcrc, comettcp, cometfrm, cometlog;
|
|
|
|
var
|
|
ListenSock, ClientSock, ServerSock: TCometSocket;
|
|
Info: TCometConnInfo;
|
|
Rx, ClientRx: TCometFrameRx;
|
|
Frame: TCometFrame;
|
|
Payload: array[0..255] of Byte;
|
|
I: Integer;
|
|
Ret: Integer;
|
|
Tests, Passed: Integer;
|
|
Port: Word;
|
|
begin
|
|
Tests := 0;
|
|
Passed := 0;
|
|
Port := 47391; { Arbitrary test port }
|
|
|
|
CometLogSetConsole(True);
|
|
CometLogSetDebug(True);
|
|
|
|
{ Create listener }
|
|
ListenSock := CometTcpListen('127.0.0.1', Port);
|
|
if ListenSock = COMET_TCP_INVALID then
|
|
begin
|
|
WriteLn('FAIL: Cannot create listener on port ', Port);
|
|
Halt(1);
|
|
end;
|
|
WriteLn('Listener on port ', Port);
|
|
|
|
{ Connect client }
|
|
ClientSock := CometTcpConnect('127.0.0.1', Port, 5000);
|
|
if ClientSock = COMET_TCP_INVALID then
|
|
begin
|
|
WriteLn('FAIL: Cannot connect to listener');
|
|
CometTcpClose(ListenSock);
|
|
Halt(1);
|
|
end;
|
|
WriteLn('Client connected');
|
|
|
|
{ Accept on server side }
|
|
if not CometTcpAccept(ListenSock, Info) then
|
|
begin
|
|
WriteLn('FAIL: Accept failed');
|
|
CometTcpClose(ClientSock);
|
|
CometTcpClose(ListenSock);
|
|
Halt(1);
|
|
end;
|
|
ServerSock := Info.Socket;
|
|
WriteLn('Server accepted from ', Info.RemoteIP, ':', Info.RemotePort);
|
|
|
|
{ Initialize receiver }
|
|
CometFrameRxInit(Rx);
|
|
|
|
{ Test 1: Empty payload (IDLE packet) }
|
|
Inc(Tests);
|
|
Write('Test 1: IDLE (empty payload)... ');
|
|
if CometFrameSend(ClientSock, NPKT_IDLE, 0, nil, 0) then
|
|
begin
|
|
CometTcpWaitData(ServerSock, 1000);
|
|
Ret := CometFrameRecv(ServerSock, Rx, Frame);
|
|
if (Ret = NPKT_IDLE) and (Frame.Seq = 0) and (Frame.PayLen = 0) then
|
|
begin
|
|
WriteLn('OK');
|
|
Inc(Passed);
|
|
end
|
|
else
|
|
WriteLn('FAIL: ret=', Ret, ' seq=', Frame.Seq, ' paylen=', Frame.PayLen);
|
|
end
|
|
else
|
|
WriteLn('FAIL: send error');
|
|
|
|
{ Test 2: Small payload (INIT packet with 10 bytes) }
|
|
Inc(Tests);
|
|
Write('Test 2: INIT (10 bytes)... ');
|
|
for I := 0 to 9 do Payload[I] := Byte(I + $41); { 'A'..'J' }
|
|
if CometFrameSend(ClientSock, NPKT_INIT, 1, @Payload[0], 10) then
|
|
begin
|
|
CometTcpWaitData(ServerSock, 1000);
|
|
Ret := CometFrameRecv(ServerSock, Rx, Frame);
|
|
if (Ret = NPKT_INIT) and (Frame.Seq = 1) and (Frame.PayLen = 10) and
|
|
(Frame.Payload[0] = $41) and (Frame.Payload[9] = $4A) then
|
|
begin
|
|
WriteLn('OK');
|
|
Inc(Passed);
|
|
end
|
|
else
|
|
WriteLn('FAIL: ret=', Ret, ' seq=', Frame.Seq, ' paylen=', Frame.PayLen);
|
|
end
|
|
else
|
|
WriteLn('FAIL: send error');
|
|
|
|
{ Test 3: 256 byte payload (DATA packet) }
|
|
Inc(Tests);
|
|
Write('Test 3: DATA (256 bytes)... ');
|
|
for I := 0 to 255 do Payload[I] := Byte(I);
|
|
if CometFrameSend(ClientSock, NPKT_DATA, 42, @Payload[0], 256) then
|
|
begin
|
|
{ May need multiple recv calls for larger frames }
|
|
CometTcpWaitData(ServerSock, 1000);
|
|
Ret := N_NOPKT;
|
|
for I := 0 to 9 do
|
|
begin
|
|
Ret := CometFrameRecv(ServerSock, Rx, Frame);
|
|
if Ret <> N_NOPKT then Break;
|
|
CometTcpWaitData(ServerSock, 100);
|
|
end;
|
|
if (Ret = NPKT_DATA) and (Frame.Seq = 42) and (Frame.PayLen = 256) and
|
|
(Frame.Payload[0] = 0) and (Frame.Payload[255] = 255) then
|
|
begin
|
|
WriteLn('OK');
|
|
Inc(Passed);
|
|
end
|
|
else
|
|
WriteLn('FAIL: ret=', Ret, ' seq=', Frame.Seq, ' paylen=', Frame.PayLen);
|
|
end
|
|
else
|
|
WriteLn('FAIL: send error');
|
|
|
|
{ Test 4: Bidirectional - server sends back to client }
|
|
Inc(Tests);
|
|
Write('Test 4: Bidirectional... ');
|
|
if CometFrameSend(ServerSock, NPKT_INITACK, 99, @Payload[0], 5) then
|
|
begin
|
|
CometFrameRxReset(Rx); { Reset for new direction }
|
|
CometTcpWaitData(ClientSock, 1000);
|
|
|
|
CometFrameRxInit(ClientRx);
|
|
Ret := CometFrameRecv(ClientSock, ClientRx, Frame);
|
|
if (Ret = NPKT_INITACK) and (Frame.Seq = 99) and (Frame.PayLen = 5) then
|
|
begin
|
|
WriteLn('OK');
|
|
Inc(Passed);
|
|
end
|
|
else
|
|
WriteLn('FAIL: ret=', Ret);
|
|
CometFrameRxDone(ClientRx);
|
|
end
|
|
else
|
|
WriteLn('FAIL: send error');
|
|
|
|
{ Cleanup }
|
|
CometFrameRxDone(Rx);
|
|
CometTcpClose(ServerSock);
|
|
CometTcpClose(ClientSock);
|
|
CometTcpClose(ListenSock);
|
|
|
|
WriteLn;
|
|
WriteLn(Passed, '/', Tests, ' frame tests passed.');
|
|
if Passed <> Tests then Halt(1);
|
|
end.
|