When tcp_conn_count > 0, the auth OK response includes a session
token in bytes 1-2: [01, HI, LO, 00] instead of [01, 00, 00, 00].
MikroTik checks these bytes to determine multi-connection support.
Primary connection: full handshake, receives session token
Secondary connections: auth with same token, join the session
Server waits up to 10s for all connections to join before starting.
This fixes MikroTik showing "test unsupported" for TCP multi-conn.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Root cause found via pcap analysis: MikroTik with connection-count=N
sends UDP from N different source ports (2257, 2258, 2259, ...) all
to our single server port 2001. A connect()'d UDP socket only accepts
packets from the one connected address, silently dropping ~75% of
traffic with conn_count=4.
Fix: when tcp_conn_count > 0, leave the UDP socket unconnected and
use send_to()/recv_from() instead of send()/recv(). This accepts
packets from all MikroTik source ports.
This bug also exists in the original C btest-opensource.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- Dockerfile.static: takes pre-built binary, no compilation
- push-docker.sh: downloads x86_64 from CI release, builds arm64
natively, creates multi-arch manifest and pushes both
- docker pull works on both Intel and Apple Silicon / RPi
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Multi-connection mode is not supported and causes near-zero throughput.
Updated README, user guide, MikroTik CLI examples, and troubleshooting.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
crane can't pull scratch in CI. Docker images are built locally
on Mac where Docker is available, then pushed to Gitea registry.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
crane append doesn't support --set-entrypoint. Use crane mutate
as a separate step to set entrypoint and cmd on the pushed image.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Uses crane (no Docker daemon needed) to build a minimal scratch-based
OCI image from the static musl binary and push it to the Gitea
container registry. Tags both vX.Y.Z and latest.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Uses gcc-mingw-w64 to cross-compile btest.exe from Linux.
Release now includes 4 targets: Linux x86_64/aarch64/armv7 + Windows x86_64.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
The act runner has no Node.js in container jobs. Replace
actions/upload-artifact and actions/download-artifact with
direct Gitea API uploads from a single job that builds all
three architectures sequentially.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
The act runner already mounts the repo at the workspace path.
Removed manual git clone and working_directory overrides.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
The act runner executes actions/checkout inside the job container,
but that action is a Node.js script and rust:1.86-slim has no node.
Use plain git clone instead.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- .gitea/workflows/ci.yml: run tests on every push/PR
- .gitea/workflows/release.yml: build Linux binaries on tag push
- x86_64 (musl static)
- aarch64 / RPi 64-bit (musl static)
- armv7 / RPi 32-bit (musl static)
- Auto-creates Gitea release with all artifacts
- scripts/build-macos-release.sh: build macOS binary locally and
upload to an existing Gitea release
Release flow:
git tag v0.1.0 && git push origin v0.1.0
# CI builds Linux + RPi, creates release
# Then on Mac: ./scripts/build-macos-release.sh --upload v0.1.0
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- Rename package to btest-rs (Rust convention for reimplementations)
- MIT license matching the original btest-opensource license
- LICENSE explicitly credits Alex Samorukov's original work
- Comprehensive README with usage, performance numbers, and credits
- CLI --help references the original project
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- Dockerfile.cross: builds static x86_64 musl binary from macOS via Docker
- scripts/build-linux.sh: one-command cross-compilation
- scripts/install-service.sh: systemd service with security hardening
- Bump Rust Docker images to 1.86 for edition2024 support
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Full reimplementation of the MikroTik Bandwidth Test protocol:
- Server mode: accepts connections from MikroTik devices on port 2000
- Client mode: connects to MikroTik btest servers
- TCP and UDP protocols with bidirectional support
- MD5 challenge-response authentication
- Dynamic speed adjustment (1.5x algorithm)
- Status exchange matching original C pselect() behavior
- Docker support with multi-stage build
Tested against MikroTik RouterOS achieving:
- 1.05 Gbps server RX (single connection)
- 530 Mbps client TCP download
- 840 Mbps client TCP upload
- 433 Mbps client UDP download
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>