Ken Johnson d724a12332 v0.4.0: HasPendingTx accessor for write-aware driver loops
Add public read-only TBPSession.HasPendingTx returning True iff
the session has outbound work pending right now (bytes already
in the send buffer, queued messages awaiting flatten, or an
active TX file with more data).  Lets driver loops choose
whether Transport.WaitReady should also wait for socket
WRITE-readiness in addition to read.

Recommended pattern:

  while Session.NextStep do
    Transport.WaitReady(True, Session.HasPendingTx, 50);

Matches Argus's CanSend socket-buffer pacing model
(p_binkp.pas:1129-1131).  Previous fpc-binkp drivers
unintentionally followed binkd's poll-with-timeout model and
paid a 50 ms idle wait per frame.

Live measurement on a 10 MB BinkP outbound (Comet 1.2.2 daemon
driving fpc-binkp against a Comet 1.2.2 BinkP-fallback
responder) before/after wiring the new flag:
  bbsnode2 (FreeBSD/LAN):  134 s -> 2.7 s   (~50x)
  sea-vps11 (Linux/WAN):   134 s -> 1.7 s   (~80x)

Wire protocol unchanged.  Consumers pinned to 0.3.0 can
upgrade in place; HasPendingTx is purely additive and callers
that don't use it keep the old behaviour.
BP_MIN_COMPATIBLE_VERSION stays at 0.2.0.
2026-04-25 10:32:47 -07:00
2026-04-21 12:45:41 -07:00
2026-04-21 12:45:41 -07:00
2026-04-21 12:45:41 -07:00
2026-04-21 12:45:41 -07:00

fpc-binkp

A Free Pascal library for the BinkP/1.1 mailer protocol (FTS-1026, FTS-1027) with support for the widely-deployed vendor extensions (NR, ND, MBT, PLZ, CRYPT, DES-CBC, ED25519).

Sibling library to fpc-msgbase (message storage), fpc-ftn-transport (PKT, ArcMail, queues), and comet (the mailer daemon that consumes all three). Same vendoring model: each library is its own repo with its own tests; consumers cp / rsync units from units/ into their build; bug fix → commit here → consumers pull at their own cadence → rebuild → deploy.

Scope

Concern Owned by
BinkP/1.1 wire protocol (frames, commands, state machine) fpc-binkp
CRAM-MD5, CRYPT, DES-CBC, ED25519 auth fpc-binkp
PLZ (zlib per-frame) compression fpc-binkp
NR (resume), ND (non-destructive), MBT (multi-batch) fpc-binkp
PKT / ArcMail / BSO queue fpc-ftn-transport
Message storage (JAM, Squish, ...) fpc-msgbase
Session dispatch, config, UI, logging backends consumer
Dialup / EMSI / modem framing out of scope — separate library

The library handles the wire. Consumers own everything above and below: the socket, the filesystem, the logging sink, the decision of which file to send next, what "secure" means for an inbound directory.

Status

Current: 0.1.0 — initial release. Core library compiles on all five targets (Linux, FreeBSD, Windows, OS/2, DOS go32v2). Reference TCP transport is UNIX-only; DOS has a dedicated Watt-32 transport; Windows / OS/2 consumers plug in their own IBPTransport.

Seven test programs green including a full two-session round-trip self-test. End-to-end smoke-tested on localhost (outbound ↔ inbound, 10 KB binary transferred with identical SHA-256, full CRAM-MD5 + CRYPT + MBT).

Naming

Unit prefix: bp.<category>.<name>.pasbp = "binkp". All units use {$mode objfpc}{$H+}{$modeswitch advancedrecords}.

Architecture

Step-based engine (modeled on Argus, not binkd):

Session := TBPSession.Create(bpsOutbound, Transport, Provider, Events);
Session.Config.LocalAddress := FTNAddr('1:218/720');
Session.Config.Advertise    := [bpOptNR, bpOptND, bpOptPLZ, bpOptMBT];
Session.Config.OnPostAuth   := @MyPostAuthHook;

while Session.NextStep do
begin
  // embedder is in control between every tick.
  // can cancel, inspect state, swap provider, etc.
end;

writeln('Result: ', Session.Result.Description);
Session.Free;

The embedder drives the loop. Each call to NextStep does a bounded unit of I/O + state-machine work and returns. This gives:

  • Testability. Replace Transport with a TMemoryStream- backed mock; feed in canned bytes; assert on emitted frames. No sockets required.
  • Cancellation. Stop calling NextStep; free the session.
  • Multiplexing. An event loop can drive N sessions on a single thread if the Transport implementation supports non-blocking I/O.
  • Observability. Inspect Session.Phase, Session.RemoteInfo between ticks. Hooks fire at every policy decision.

See docs/architecture.md for the full design, docs/api.md for the consumer-facing API reference, and docs/spec.md for the FTSC / FSP spec cheat sheet and wire-format notes.

Building

Once units land:

./build.sh                # all targets
./build.sh x86_64-linux   # just one
./run_tests.sh            # run test suite

Supported targets (matches fpc-ftn-transport): x86_64-linux, i386-go32v2, i386-os2, i386-win32, i386-linux, i386-freebsd.

License

GPL-2.0 — same as comet.

Layout

fpc-binkp/
├── build.sh              — multi-target build driver
├── CHANGELOG.md          — release notes, tagged vX.Y.Z
├── README.md             — this file
├── run_tests.sh          — test runner
├── fpc.cfg               — FPC search paths
├── docs/
│   ├── architecture.md   — engine design, hook taxonomy
│   ├── api.md            — public API reference
│   └── spec.md           — FTS-1026/1027 + FSP cheat sheet
├── examples/
│   ├── example_outbound.pas    — embed as originator
│   ├── example_inbound.pas     — embed as answerer
│   ├── example_mock.pas        — replay a captured session
│   └── example_multiplex.pas   — N sessions one thread
├── src/
│   ├── bp.version.pas         — BP_VERSION constant
│   ├── bp.types.pas           — enums, records, forward decls
│   ├── bp.frame.pas           — TBPFrame, read/write helpers
│   ├── bp.opt.pas             — OPT keyword parser / builder
│   ├── bp.cram.pas            — CRAM-MD5 (HMAC-MD5 RFC 2104)
│   ├── bp.crypt.pas           — FSP-1037 password-derived cipher
│   ├── bp.des.pas             — Argus DES-CBC stream
│   ├── bp.plz.pas             — zlib per-frame compression
│   ├── bp.transport.pas       — IBPTransport interface
│   ├── bp.provider.pas        — IBPFileProvider interface
│   ├── bp.events.pas          — IBPEventSink, event records
│   ├── bp.config.pas          — TBPSessionConfig record
│   └── bp.session.pas         — TBPSession engine (NextStep)
├── tests/
│   ├── test_frame.pas
│   ├── test_cram.pas
│   ├── test_crypt.pas
│   ├── test_des.pas
│   ├── test_plz.pas
│   ├── test_opt.pas
│   ├── test_session_outbound.pas
│   ├── test_session_inbound.pas
│   ├── vectors/               — captured traffic, one file per case
│   └── testutil.pas           — test harness helpers
└── units/                    — compiled output (.ppu/.o), per target
Description
FPC/FreePascal BinkP (FTS-1026/1027) library — Argus/binkd-compatible mailer protocol
Readme 743 KiB
Languages
Pascal 98.4%
Shell 1.6%