AMIBINKD
Native AmigaOS 3.x port of binkd, the FTN mailer
===============================================================================
DESCRIPTION
===============================================================================
AmiBinkD is a native AmigaOS 3.x build of binkd, the FidoNet Technology
Network (FTN) mailer, used to send and receive FTN echomail/netmail
packets over TCP/IP using the BinkP protocol.
Unlike every prior Amiga build of binkd, this one does not require
ixemul.library or ixnet.library. It talks to bsdsocket.library directly,
and every place the historical Amiga port depended on ixemul's vfork()-
based process model has been replaced with a native AmigaOS equivalent:
each BinkP session (inbound or outbound) runs as its own real AmigaOS
process, spawned via CreateNewProcTags() -- genuine concurrent sessions,
not one session at a time.
This is a from-scratch reconstruction, not a recompile of the old ixemul
Amiga port. It was built by tracing every ixemul/ixnet dependency in
upstream binkd's own historical Amiga support and replacing each one with
a direct AmigaOS/bsdsocket.library equivalent, then hardening the result
against several real behavioral differences between Amiberry's
bsdsocket_emu and genuine Roadshow/BSD sockets that only showed up under
live testing, not at compile time. See manual.txt section 15 for the
full list, if you're maintaining this on a different TCP/IP stack.
If you carry several FTN networks, one config file and one command line
cover all of them:
AmiBinkD:AmiBinkD -p -PALL AmiBinkD:AmiBinkD.cfg
"-P ALL" polls every node listed in the config, instead of naming each
uplink with its own -P switch or keeping a separate config and script
per network. See manual.txt section 07.
For full installation notes, configuration reference, known real-hardware
findings, and version history, see manual.txt.
FILES INCLUDED
===============================================================================
AmiBinkD Compiled AmigaOS executable (m68k, AmigaOS 3.0+)
AmiBinkD.info Workbench icon (colour image needs AmigaOS 3.5+)
readme.txt Quick overview and install notes
manual.txt Full SysOp documentation
amibinkd-example.cfg Example configuration file
amibinkd.scr Example AmigaDOS poll-all driver script
Copy amibinkd-example.cfg to a name of your choosing (e.g. AmiBinkD.cfg,
or one file per network -- see manual.txt section 07) and edit it for
your system before running.
amibinkd.scr is a ready-to-edit "-P ALL" poll script -- point it at your
config name and schedule it from your BBS's event system.
REQUIREMENTS
===============================================================================
* Commodore Amiga or compatible/emulated Amiga system, AmigaOS 3.0+ (m68k)
* bsdsocket.library -- Roadshow, AmiTCP, or (as tested) Amiberry's
bsdsocket_emu
* An FTN-aware BBS engine or tosser to hand packets to/from (built and
tested against C-Net/5 Amiga Pro, but AmiBinkD itself only reads/writes
standard FTN packet and outbound-flow files -- it doesn't call into
C-Net/5 directly)
* At least one FTN address and an uplink/hub willing to carry your mail
AmiBinkD is a standalone compiled executable. It has no ixemul.library or
ixnet.library dependency of any kind -- confirmed via string search on
the built binary.
CONCURRENCY
===============================================================================
Classic AmigaOS has no fork()/pthreads without ixemul, but it does have
CreateNewProcTags() (dos.library) -- the native primitive this port uses
to spawn each BinkP session as its own real process. An inbound
connection arriving while an outbound poll is already in flight, or
several networks polled back-to-back, no longer have to wait their turn.
See manual.txt section 05 for the full technical writeup of how this
works and what it took to get right on classic AmigaOS specifically.
QUICK INSTALL
===============================================================================
1. Copy the AmiBinkD folder to your BBS mail directory.
Example:
Mail:AmiBinkD/AmiBinkD
2. Copy amibinkd-example.cfg to AmiBinkD.cfg (or a per-network name --
see manual.txt section 07) and edit it: your domain(s), your FTN
address(es), sysname/location/sysop, log path, inbound directories,
and your node/hub line(s) with the real host, port, and password.
3. Create the directories your config references if they don't already
exist: the outbound directory named in each "domain" line, the
inbound/temp-inbound directories, and the log directory.
4. Test an outbound poll manually first, from a Shell:
AmiBinkD:AmiBinkD -p -P<address> AmiBinkD:AmiBinkD.cfg
Once that works, "-P ALL" in place of "-P<address>" polls every node
in the config in one go.
5. Review the log, then set up your regular polling schedule and/or
inbound server (see manual.txt sections 09-10).
BASIC MAIL FLOW
===============================================================================
1. AmiBinkD polls (outbound) or accepts a connection (inbound), performs
the BinkP handshake, and exchanges queued files/packets over TCP.
2. Received .pkt files land in your configured inbound directory.
3. Your tosser (e.g. C-Net/5's Toss) processes them into your message
bases.
4. Outbound mail queued by your BBS/tosser into the domain's outbound
directory gets picked up and sent on the next poll.
===============================================================================
VERSION HISTORY
===============================================================================
v10.18 - Inbound Sessions Stop Hanging, Readable Session Log
-----------------------------------------------------------
* The session log was rewritten to be readable on an 80-column screen --
a blank line between sessions, an explicit END marker, and shorter
messages. "BEGIN" alone went from 120 columns to 68; it had been the
only line in a poll that wrapped twice. Lines over 80 per poll dropped
from nine to four.
Everything else is done from configuration, not code: "loglevel"
controls detail (level 3 is what carries the remote's SYS/ZYZ/LOC/VER
identity block -- at level 2 your sessions are logged anonymously), and
"nolog" masks hide individual messages. See the sample config and
manual section 06. Note "nolog" takes ONE MASK PER WORD: a mask written
with spaces is split, and a stray bare "*" among the pieces silences
the log completely.
* AmiBinkD no longer identifies itself as part of any BBS package. The
VER string sent to every node you poll is now "AmiBinkd v10.18-binkp/1.1",
matching the form other mailers use. It previously named a specific BBS,
which was wrong for a general AmigaOS mailer.
* Upgrade from v10.15, which is the previous public release. v10.16 and
v10.17 were never released -- they are listed further down because
they explain the version jump and because the AmigaOS problems they
uncovered are worth passing on to anyone else porting to this
platform. Nothing shipped between v10.15 and this release.
* The root cause, after three releases of narrowing it down, was
setting a file's datestamp. On AmigaOS that is SetFileDate(), and
when another Process holds the file it does not return an error --
it never returns. No timeout bounds it, nothing watches the session,
so the session is gone: it keeps its server slot, socket and .bsy
locks forever. Enough of those and the server hits "maxservers" and
refuses all inbound.
It only bites when something else is touching the same directories.
On the author's system that is C-Net/5's own overnight file-catalog
jobs, which is why it looked like a night-time-only fault: 66 of 66
inbound commits succeeded during the day, and 7 of 7 hung after
21:00. One of those hangs landed inside a poll client, so the BBS
event that launched it never finished and outbound mail was dead
for seventeen hours.
* Fix: new "set-file-dates" setting, defaulting OFF on this port (see
the manual, section 06). Every other binkd platform defaults it on;
this is the one place AmiBinkD deliberately differs. What you give
up is cosmetic -- received files carry their arrival time rather
than the sender's timestamp. Nothing in BinkP, tossing or duplicate
detection depends on it. Turn it on only if you are certain nothing
else touches your inbound/outbound directories while the mailer
runs.
* Verified over an 18-hour run spanning the overnight window that
broke the previous release: 89 inbound sessions started, 89 closed,
nothing leaked, 351 file commits, concurrent-session count peaking
at 5 and returning to zero between polls, and all 59 scheduled BBS
mail events completing. For comparison, v10.16 saturated in 13
hours and v10.17 had leaked 55 sessions by 26 hours.
* Also fixed: "unknown domain" errors and silently-skipped polls. Not
a bug you could have hit -- it existed only in an unreleased build
-- but the cause is worth passing on, because the build system, not
the code, was at fault. Object files did not depend on headers, so
changing a shared struct rebuilt only some of the program and left
the rest reading the old field offsets. The binary linked, ran, and
quietly stopped calling out on six of seven networks. If you build
this yourself from an older Makefile, do a full "make clean" after
touching any header.
v10.17 - One Hung Session No Longer Takes The Others With It (unreleased)
------------------------------------------------------------------------
* Never released; superseded by v10.18. Sessions refresh their
.bsy datestamps on every pass of the protocol loop, and that work
was done holding a single global lock across file I/O. One session
blocking in there pinned the lock and every other concurrent session
piled up behind it -- so a single stuck file operation took down
every session on the system, and the pile-up fed itself. v10.17
stopped the cascade (the lock is never held across I/O now, and is
never waited on), but a session could still hang on its own. v10.18
removes the hanging call entirely.
v10.16 - Inbound Socket Handoff (unreleased; fix retained in v10.18)
-------------------------------------------------------------------
* Never released. Its inbound fix was real and is retained in v10.18,
but on test it traded one failure for another: sessions that hung
leaked permanently and piled up until inbound stopped, which in
practice was worse than v10.15's quieter failure. That leak is what
v10.17 and v10.18 went on to fix. The notes below are kept because
the underlying problem is instructive for anyone porting to AmigaOS.
* Worth doing whatever mailer you run: if your BBS event script
deletes .bsy/.csy files before polling, make sure a failed delete
cannot abort the script -- on AmigaDOS, wrap them in "FAILAT 21"
and "FAILAT 10". A lock file held by a live session is otherwise
enough to kill the whole event, and your mailer never runs. The
"kill-old-bsy" setting already removes stale locks for you.
* Inbound BinkP sessions never worked at all, in any release from
v10.5 through v10.15.
The symptom was easy to blame on the other end. Your log recorded
"incoming session with <peer>" and then nothing further - no error,
no timeout, no session close - while the caller gave up reporting
"Session timeout" and "Authorization failed". Worse, a stuck session
never freed its server slot, so the next caller was refused outright
and inbound mail stopped within minutes of every startup. Restarting
appeared to help, which made it look like an intermittent fault.
Outbound polling was completely unaffected, so mail you fetched
yourself kept arriving normally and the problem was easy to miss.
Cause: AmigaOS gives each Process its own bsdsocket.library context.
Since v10.5 every session runs as its own Process, and inbound
sessions were using the parent's shared library base for a socket
they did not own. Socket readiness is delivered by signal, and those
signals never reached the child - so an inbound session could neither
send nor receive, and simply sat there. v10.12 fixed the same class
of problem for outbound connections but did not cover inbound.
AmiBinkD now transfers the socket to the session's own private
library base (ReleaseSocket/ObtainSocket), which is the documented
AmigaOS way to hand a socket between Processes.
* Also resolved by the same fix: sessions ignoring the "timeout"
setting. A stalled session used to linger indefinitely; it now closes
on schedule. No configuration change is needed - if you added
settings while working around the old behaviour, you can remove them.
* Do NOT set "maxservers" as a workaround for the old symptom. On this
port a rejection can take the server manager down with it. Leaving it
unset (default 100) is correct.
* Verified live: five consecutive inbound sessions from a network hub
in 44 seconds - full handshake, CRAM-MD5 authentication, packets
received, clean teardown each time, listener still accepting
afterwards. Outbound polling unchanged in the same period.
v10.15 - Poll Every Network From One Config ("-P ALL"), Custom Icon
------------------------------------------------------------------
* New: "-P ALL" polls every node in the config in a single invocation:
AmiBinkD:AmiBinkD -p -PALL AmiBinkD:AmiBinkD.cfg
Stock binkd's -P takes one FTN address per switch, so carrying
several networks meant either repeating -P once per uplink or
keeping a separate config and driver script for each. One config
and one command line now cover all of them; the inbound server
("-s") already used the combined config, so both sides finally read
the same file. Nodes with no host to call, and your own addresses,
are skipped rather than polled, and the log summarizes what was
created ("ALL: created 7 poll(s)"). See manual.txt sections 07-09.
* Worth checking alongside it: "maxclients" now decides something it
never did before. With every uplink pollable in one run, its default
of 100 means all of them are called at once, where the one-script-
per-network pattern was strictly sequential. See manual.txt section
06.
* Confirmed live: a scheduled poll cycle logged "ALL: created 7
poll(s)" and completed clean sessions with all seven networks.
* The icon work below was briefly released on its own as a
packaging-only 10.15 carrying the v10.14 binary. "-P ALL" was folded
into the same version number rather than becoming 10.16, so that
10.15 isn't a version with nothing to point at. If your AmiBinkD10_15
archive holds a binary that reports v10.14 at startup, it's that
earlier cut -- replace it with this one.
* Replaced AmiBinkD.info -- previously a reused copy of another local
project's icon -- with a purpose-made one: the Reign of Fire
dragon-head badge, cropped to its circular emblem, quantized to a
64-colour palette-mapped image, and alpha-masked to a circle so it
sits cleanly on the Workbench desktop instead of carrying a black
square background. Includes a distinct brighter "selected" image for
the icon's clicked state.
* Built with icon.library's own V44+ API (NewDiskObject/IconControlA/
PutIconTagList) instead of a hand-rolled on-disk format, so the OS's
own code produces the file. See manual.txt section 18 for the full
writeup and where the build tooling lives.
Requires AmigaOS 3.5+ (icon.library V44) to render the colour image;
older Workbench versions fall back to a generic tool icon.
v10.5-v10.14 - Real Concurrency, and the Hang It Exposed
-----------------------------------------------------------
Thirteen point releases' worth of work, summarized here; see manual.txt's
own Version History (section 18) for the full technical writeup of each.
* v10.5 added real concurrency: each BinkP session now runs as its own
AmigaOS process via CreateNewProcTags(), instead of one session at a
time synchronously. See manual.txt section 05.
* v10.6-v10.7 fixed two bugs concurrency itself exposed: a stale-lock
give-up/backoff that wasn't actually being honored, and an errno race
at a critical logging section under real concurrent inbound load.
* v10.8-v10.12 chased down and fixed the hardest bug in this project:
every outbound poll would hang indefinitely, even though the real TCP
connection completed in under a second every time. Two plausible-
looking fixes (different techniques for detecting when a non-blocking
connect() finishes) both failed live before the real cause was found:
a blocking bsdsocket.library call's internal completion notification
never reaches a spawned, non-opener AmigaOS process. Fixed by giving
each outbound-connecting session its own private bsdsocket.library
instance. See manual.txt section 05 and readme's counterpart, this
project's README.md, "Real-hardware findings" #10, for the full story.
* v10.9/v10.13/v10.14 dealt with the same root cause showing up in
gethostbyname() too. v10.9 worked around it with a host-side DNS
cache; once v10.12's real fix landed, v10.13 confirmed (over a
two-day, two-reboot soak) that the cache was no longer needed, and
v10.14 removed it for good -- hostname resolution is a plain
gethostbyname() call again, same as every other platform binkd
supports.
v10.1 - .csy/.bsy Unlink Fix
------------------------------
* Fixed the .csy/.bsy busy-flag file occasionally failing to clean up
after a session ("Text file busy") -- the cleanup now retries instead
of giving up after one attempt. Cosmetic in v10.0 (never blocked a
session either way), but the retry is more robust and matches how the
rest of the codebase already handles this class of transient Amiga
file-lock race. Verified live on production. See manual.txt section
18 for the full technical writeup.
v10.0 - Native AmigaOS Port
----------------------------
* Rebuilt from a clean upstream binkd checkout with every ixemul/ixnet
dependency replaced by native AmigaOS/bsdsocket.library equivalents,
rather than patching an incomplete existing Amiga port.
* Runs each BinkP session synchronously (no fork()/pthreads needed) --
a genuine, working single-session-at-a-time design.
* Found and fixed several real behavioral differences between
Amiberry's bsdsocket_emu and genuine BSD sockets that only surfaced
under live testing (getaddrinfo(), non-blocking I/O, accept()
blocking after a ready select(), WaitSelect() signal handling) -- see
manual.txt section 15 for the full list.
* Verified two ways before shipping: cross-compiled clean (zero
warnings) with the bebbo/amiga-gcc toolchain, and run live on a
production Amiberry instance -- confirmed both outbound (client/poll)
and inbound (server) sessions, including a full multi-network polling
run (7 networks) with real inbound file reception and successful
tosser import, not just clean-looking session logs.
* Soak-tested unattended overnight across all 7 configured networks with
no hangs, no gaps, and no recurrence of any fixed bug.
For the full technical history -- every ixemul-era assumption replaced,
every real-hardware finding, and why each fix works the way it does --
see manual.txt sections 15 and 18.
SECURITY NOTES
===============================================================================
AmiBinkD accepts inbound TCP connections and moves files onto your
system based on what a remote FTN node sends it.
Recommended precautions:
* Set a real per-node password (areafix password) for every "node" line
-- don't leave a node unauthenticated unless you mean to.
* Use send-if-pwd (on by default in the example config) so an
unauthenticated session can only receive, not pull mail from you.
* Keep your inbound/outbound directories separate from directories your
BBS treats as directly executable or auto-processed without review.
* Review your log regularly.
* Keep backups.
DISCLAIMER
===============================================================================
AmiBinkD is provided as-is. It is a from-scratch reconstruction of
ixemul-dependent Amiga binkd behavior verified against one real system
(Amiberry-emulated AmigaOS 3.x, bsdsocket_emu) -- other bsdsocket.library
implementations (real Roadshow, AmiTCP) have not been tested and may
behave differently; see manual.txt section 15 before assuming a finding
there applies to your setup.
Every FTN network and BBS system is different. Test carefully before
using this on a live system carrying real mail.
The author is not responsible for lost mail, misconfigured domains/
addresses, missing passwords, or damage caused by improper setup.
Always keep backups.
CREDITS
===============================================================================
AmiBinkD is a native AmigaOS port of binkd
(https://github.com/pgul/binkd), originally written by Dima Maloff and
maintained by the binkd project. All BinkP protocol logic, FTN packet
handling, and configuration semantics are upstream binkd's; this port's
own work is the AmigaOS/bsdsocket.library integration layer and the
real-hardware fixes documented in manual.txt.
Earlier Amiga port (AmiBinkd v5.00 - v9.02, 2012-2013):
Rudi Timmermans, X-TReMe BBS
AmiBinkD carried this name on the Amiga long before the present release.
Rudi Timmermans built and maintained it through v9.02, made it freeware
at v5.00, and got a working BinkP mailer onto classic AmigaOS at a time
when that meant living with ixemul.library. This port is a from-scratch
reconstruction rather than a recompile of his -- the ixemul dependency is
gone and every session now runs as a native AmigaOS process -- but the
program's name, its configuration file format, and the shape of its
session log all come from his work, and the log is still recognisably the
same one his v9.01 produced in 2013. Credit where it is due.
Built and tested for:
Reign of Fire BBS
C-Net/5 Amiga Pro
call.rofbbs.com:6800
Website:
https://www.rofbbs.com
SysOp / Author (Amiga port):
Gary "Spitfire" McCulloch
Networks tested against:
AmigaNet, ArakNet, CommodoreNet, DiscipleNet, FidoNet, PiNet, RetroNet
===============================================================================
END OF README.TXT SpitfireTN Entertainment
===============================================================================
|