Releases: OrangeTide/netchan
Release list
v0.8.0
The wire protocol is untouched. Everything here is source level, so a peer
built from this tree still talks to one built from 0.7.0. The minor version
moves because the source API does.
Added
docs/coding-style.md, the project's written C conventions, linked from the
README. It is written to drop into another project unchanged.make lint, which checks the tree against that document: tabs, trailing
whitespace, non-ASCII, missing final newline,#pragma once, per-file
licence lines in C and in scripts,externon a function declaration, bare
-1returns, lines over 100 columns, a definition with its body on the
signature line, a missing tag line, and declarations below the first
statement of a block. It runs as its own CI job, so the conventions hold
without a manual sweep.make analyze, agcc -fanalyzerbuild that fails on a warning in the
project's own code. The analyzer walks execution paths rather than matching
patterns, so it catches what a review misses: it found a descriptor leaked
down a failure branch in the secure-link test and abindon an unchecked
socketresult in the UDP test, both fixed here.- The manual is a multi-page site rather than one assembled HTML page:
introduction, architecture, protocol overview, four tutorials, message
encoding, protocol reference, testing and analysis, and the API reference.
The prose was converted, not rewritten. The API reference is still generated
fromsrc/netchan.h, andcheck-symbols.shstill fails the build when prose
names a function the header no longer declares, now across every page. - Every documentation page carries the version it was built from. At a release
tag that is the bare version; away from one it is the version, the commit
count, and the abbreviated sha, so a page from an untagged build says which
commit produced it. - A fuzz harness for
netchan_feed, the core's entire untrusted surface, with
a checked-in corpus.make run-testsreplays the corpus on every platform,
which turns any input the fuzzer once crashed on into a regression test, and
a CI job fuzzes for two minutes on top of that to explore new ground. Half a
million executions found no crash.
Changed
- Every layer now names its success and failure returns instead of returning a
bare0and-1:NETCHAN_OK/NETCHAN_ERR, and the same pair under the
MC_,NC_UDP_,NC_CRYPTO_,NC_AUTH_,KS_andMEML_prefixes. They
are#define, so the return type stays a plainintand a caller that tests
< 0without including the header is still correct. The values are
unchanged.netchan.handmicrochan.hkept their error causes as an enum,
starting at-2. nc_wsandmicrosername only a failure value,NC_WS_ERRandMS_ERR.
Their calls return a position or a length, where0is a real answer rather
than success.- Functions that answer a question return
bool:nc_crypto_ready,
nc_crypto_failed,ks_authorized_key,ks_check_password,
ks_user_exists,ks_keyfile_encrypted,mc_ipx_available,
secure_link_upandauth_link_up. - No file carries a licence line any more, C or shell or awk. The root
LICENSEis the one place the terms live, so relicensing is one edit rather
than a sweep. The IDL compiler stopped emitting one into generated code too,
so a regenerated codec matches. - Declarations sit at the top of the block that uses them. Where the value
came from a call whose order matters, or from a read a guard clause proves
is in bounds, the type moved up and the assignment stayed put. - Doc comments in the public headers open with
/**, so an API description is
distinguishable from the prose that explains a file.
Breaking
- The
nc_authconversation states are renamed toNC_AUTH_STATE_PENDING,
NC_AUTH_STATE_OKandNC_AUTH_STATE_DENIED.NC_AUTH_OKnow means a call
succeeded, which is what it means in every other layer. Code that compared
nc_auth_state()against the old names has to follow, and it will not fail
quietly: the old spellings no longer exist. - The
nc_auth_server_cbcallbackscheck_keyandcheck_passwordreturn
boolrather thanint. An existing implementation keeps working once its
own signature changes; the compiler flags the mismatch. auth/keystore.hguards withKS_KEYSTORE_Handexamples/common/sockutil.h
withSU_SOCKUTIL_H, so a vendored copy cannot collide with a host project's
ownKEYSTORE_HorSOCKUTIL_H.microchan/tests/mc_memlink.{c,h}is renamed tomemlink.{c,h}, matching
thememl_symbols it exports, and its guard isMEML_MEMLINK_H. The build
library ismemlink. This is test-only and ships to nobody, but a project
that vendored microchan's tests has a file to rename.
Vendoring
curl -fsSL https://raw.githubusercontent.com/OrangeTide/netchan/v0.8.0/tools/vendor.sh | sh -s -- --version v0.8.0The source snapshot below is what that fetches. See
VENDORING.md.
v0.7.0
Added
- An
idl/layer, which brings microser back as a message encoder for a
channel's payload.microser.his the runtime, a header-only reader and
writer for tagged fields, andmicroser-gen.shcompiles an.idlfile into
a C struct with an encode and a decode function. The core still names neither
a socket nor a serialiser: netchan moves opaque bytes, and this says what
they mean. - A dispatch table generated from the same
.idl, so a program routes an
incoming datagram to a typed handler instead of switching on a tag itself. A
channel'scontent_typeis the topic, read back from its OPEN, so a channel
can be routed before a byte of payload is read. - A manual, built by
docs/build.shinto one self-contained page and deployed
to GitHub Pages on a push to main. The prose is hand written, the API
reference is generated fromsrc/netchan.h, andcheck-symbols.shfails the
build if the prose calls anetchan_function the header no longer declares.
Diagrams are rendered to SVG at build time by mscgen and graphviz, with their
colors swapped forcurrentColorso one file serves light and dark.
Fixed
- The IDL compiler folded two variant fields sharing a tag number into a single
struct member, so a union that reused a number generated code that did not
compile. Every variant field now gets its own member and its own decode case.
The field-number check also compared only plain fields against each other, so
a plain field colliding with a variant or with the discriminant reached the C
compiler as a duplicate case value. The full field set is checked now, and a
collision is reported by name. - A generator run with no output base wrote empty
.cand.hfiles. The
guard was inBEGIN, whereexitstill runsEND. It is inENDnow,
whereexitis terminal. - The chat server polled a peer it had just freed.
Changed
- The IDL compiler and the API-reference generator moved out of shell
single-quoted strings intomicroser-gen.awkandgen-api.awk, invoked with
awk -f. Every apostrophe and quote in them was a quoting hazard, and one
such apostrophe had already spilled part of the program to the shell. As
ordinary source files they parse-check and passgawk --lint. Generated
output is unchanged. A vendored copy needs both files of each pair.
Vendoring
curl -fsSL https://raw.githubusercontent.com/OrangeTide/netchan/v0.7.0/tools/vendor.sh | sh -s -- --version v0.7.0The source snapshot below is what that fetches. See
VENDORING.md.
v0.6.0
Added
netchan_disconnect(): queue a DISCONNECT for the peer and enter CLOSING,
without freeing. netchan has no socket of its own, so a caller must run one
netchan_send_nextcycle to put the frame on the wire, thennetchan_close
to free. This is the graceful-shutdown counterpart tonetchan_close, which
frees without telling the peer anything. It does nothing unless the session
is CONNECTED, and the frame is best effort: it goes out once, unreliably,
and is not retransmitted, so a lost datagram leaves the peer waiting out its
idle timeout as before.
Changed
netchan_closeno longer queues a DISCONNECT. It wrote the frame into a
buffer the same call then freed, so nothing ever reached the wire, and the
dead write made close read like a graceful shutdown.
Fixed
- The transport wrappers closed a live connection with
netchan_closealone,
so nothing told the peer the link had ended and it waited out its idle
timeout, seconds later, to notice.secure_link_close,auth_link_close,
and the chat example now callnetchan_disconnect, flush, then
netchan_close, so a peer sees a clean shutdown at once. A program that
copied one of these wrappers as its starting point inherited the delay; that
is exactly how it was found downstream.
Vendoring
curl -fsSL https://raw.githubusercontent.com/OrangeTide/netchan/v0.6.0/tools/vendor.sh | sh -s -- --version v0.6.0The source snapshot below is what that fetches. See
VENDORING.md.
v0.5.0
The first tagged release. Earlier versions here describe the tree as it was
developed, not as anything anyone could name and fetch.
Fixed
- The build passed
ar rvD, whoseDflag is GNU binutils only, so building
any archive failed on macOS, and with the archiver's stderr discarded it
failed with no message. Fixed upstream in modular-make 1.8.5, which probes
for the flag, addscso the archiver is silent unless something is wrong,
and no longer discards its stderr. The vendoredGNUmakefilemoves from
1.8.0 to 1.8.5. nc_cryptoandkeystorecalledgetrandom(2)unconditionally, so
neither compiled anywhere but Linux. Both now select a backend at compile
time:arc4random_bufon macOS and the BSDs,getrandom(2)on Linux with
a retry onEINTR, and/dev/urandomotherwise, which also covers a Linux
kernel too old for the syscall. macOS is now built and tested in CI, which
is how this was found.nc_random_id()fell back to an unseededrand()whenever it could not
read/dev/urandom, so every process produced the identical sequence of
connection ids. That was the normal path on Windows, where the file does not
exist, and reachable anywhere/devis missing. It now asks the platform
for real entropy, and the last-resort path mixes the clock with a stack
address instead of callingrand()at all.- Three tests read from a loopback socket without ever waiting and treated an
empty queue as no traffic. Linux queues a loopback datagram inside
sendto(), so the read always found it; macOS delivers through a separate
context, so the reads came back empty and the tests gave up early. That
failed the macOS CI job innc_udp_testandtest_gnet, and left
test_microchanpassing on a few microseconds of luck. The socket tests now
wait for the datagram, and the protocol tests no longer use a socket at all.
Added
-
A version, and a way to get one. The project is SemVer from 0.5.0 on, the
version is insrc/netchan.hasNETCHAN_VERSION_MAJOR,_MINOR,_PATCH,
_STRING, and a comparableNETCHAN_VERSIONinteger, and releases are git
tags of the formv0.5.0. A release workflow refuses to publish a tag that
disagrees with the header. -
tools/vendor.sh, which copies a release into another project's tree. It
takes the layers you name plus the ones they depend on, from the source
snapshot GitHub serves for the tag, and records what it took. It runs
standalone or piped:curl -fsSL https://raw.githubusercontent.com/OrangeTide/netchan/v0.5.0/tools/vendor.sh \ | sh -s -- --version v0.5.0 --layer auth -
tests/netchan_test: the channel accessors, including a receiver
identifying channels by the content type carried in the peer's OPEN, and
the truncation seam where the 64-byte field meets the 63-byte wire cap. -
Windows support for the library. The core takes its monotonic clock from
GetTickCount64and its connection ids fromrand_s;nc_cryptoand
keystoretake entropy fromBCryptGenRandom;nc_udp.hincludes winsock2
instead of<sys/socket.h>.crypto/andauth/need-lbcrypt, which
the build now exports to their dependents. The core needs nothing on the
link line, which is why it usesrand_srather than the same call: a
vendoredsrc/still builds with nothing but a compiler.The examples are unchanged and remain POSIX. They own sockets, an event
loop, and a terminal. -
A CI job that cross-compiles for Windows with mingw-w64 and runs every
socket-free test binary under wine, so the entropy and clock backends are
executed rather than merely linked. Without it this would rot unnoticed,
which is exactly what happened to macOS. -
netchan_chan_content_type(), the accessor for the string given to
netchan_chan_open()or carried in the peer's OPEN. It tells apart channels
that share a netchan type, such as two reliable streams named "control" and
"events". Never NULL; a channel opened without one reads back as "". -
microchan/tests/mc_memlink, an in-memory datagram link for tests:
delivery is a function call, and loss, duplication, and reordering happen on
a fixed count.test_microchangains a check that the Go-Back-N window
holds its line through reordering and duplication, which loopback UDP could
not produce on demand. -
microchan/tests/test_mc_udp, covering the host UDP transport on its own:
the ephemeral bind, the address packing, the return convention of a
non-blocking recv, and that the address a datagram arrives with is usable as
a destination.
Changed
-
test_microchanandtest_gnetrun overmc_memlinkinstead of loopback
UDP. Neither the core nor the game net layer touches a socket, so the
socket was testing nothing about them while making both tests
platform-dependent. They are now deterministic everywhere, andtest_gnet
went from 1.2s to 0.3s. -
microchan/, a second library: the same idea with one allocation per
connection and none after it, every buffer inside it fixed at compile time,
Go-Back-N over an 8-message window instead of selective ack, and a core that
fits in a 16-bit large-model DOS binary.
Transports are IPX for MS-DOS and UDP for a host. It brings its own tests,
the four-playerthorgame the variant exists for, and an Open Watcom
makefilefor the DOS target.It is a separate library, not a build option. Its API was renamed on import
fromnc_*/NC_*/struct netchantomc_*/MC_*/struct microchan,
because the two trees otherwise both definestruct nc_addrwith different
layouts and both ship annc_addr.h,nc_udp.c/h, andnetchan.c/h. Same
names, different meanings, one repository. Nothing links both.
Vendoring
curl -fsSL https://raw.githubusercontent.com/OrangeTide/netchan/v0.5.0/tools/vendor.sh | sh -s -- --version v0.5.0The source snapshot below is what that fetches. See
VENDORING.md.