portwait is a C17 command-line readiness probe for waiting on network endpoint availability.
portwait provides a compact, POSIX-friendly utility that can:
- parse target and probe mode inputs
- perform TCP connectivity checks with timeout and deadline handling
- classify outcomes using stable exit codes
- emit results in multiple output formats, including JSON
The current implementation includes:
- CLI parsing and validation for core options
- retry scheduling controls: --backoff, --max-interval, and --jitter
- HTTP options: method, path override, repeatable headers, and expect-status parsing/validation
- HTTPS readiness probing in TLS-enabled builds (OpenSSL-backed)
- TCP payload options: --send and --expect with literal-byte send and substring expect matching
- target parsing for host/port and scheme forms
- TCP connect probing with deadline-aware budgeting
- minimal HTTP probing (request send plus status-line readiness)
- DNS retry and once-mode behavior
- JSON, text, dots, and silent output modes, including conditional JSON fields
Build:
makeBuild with TLS-enabled HTTPS probing (requires OpenSSL development headers/libs):
make TLS=1Run all tests:
make testRun the canonical CI gate (unit + integration with TLS disabled and enabled):
make ci-test-gateSynopsis:
portwait [OPTIONS] TARGETGet built-in help:
./build/portwait --helpHOST:PORT(example:db:5432)PORTor:PORT(host defaults tolocalhost)tcp://HOST:PORThttp://HOST:PORT/pathhttps://HOST:PORT/path
Examples:
./build/portwait db:5432
./build/portwait :8080
./build/portwait http://127.0.0.1:8080/health
./build/portwait https://127.0.0.1:8443/readyNote: HTTPS examples require TLS support in the build (make TLS=1 or TLS=auto with
OpenSSL available).
Wait for TCP readiness once:
./build/portwait --once 127.0.0.1:5432Wait for HTTP readiness with custom status range:
./build/portwait --once --expect-status 200-399 http://127.0.0.1:8080/healthWait with bounded global timeout and interval control:
./build/portwait --timeout 10s --interval 250ms --backoff exp --max-interval 2s 127.0.0.1:5432Emit JSON result:
./build/portwait --once --output json http://127.0.0.1:8080/healthTCP payload probe:
./build/portwait --once --send "PING" --expect "READY" 127.0.0.1:9000--timeout DURATION: global deadline (0means infinite)--interval DURATION: base retry interval--backoff none|exp: retry backoff strategy--max-interval DURATION: cap for retry interval--jitter none|full: sleep jitter mode--connect-timeout DURATION: per-connect timeout budget--read-timeout DURATION: read timeout budget after connect--wait-dns: retry DNS failures until deadline--once: perform one terminal classification instead of retrying to timeout--output dots|text|silent|json: output mode--tcp/--http: force probe mode--method GET|HEAD,--path,--header,--expect-status: HTTP/HTTPS options--send,--expect: TCP payload probe options
Duration examples: 250ms, 2s, 1m.
- TLS-enabled build:
make TLS=1 - Default
makeusesTLS=auto(enables TLS when OpenSSL headers/libs are available) - Non-TLS build (
TLS=0) rejectshttps://targets with exit code2and a clear diagnostic
| Code | Meaning |
|---|---|
| 0 | Ready / success |
| 1 | Timed out waiting for readiness |
| 2 | Invalid usage / invalid target / unsupported feature |
| 3 | DNS failure (--once) |
| 4 | Connect failed (--once) |
| 5 | Protocol check failed (--once) |
| 6 | Internal error |
Notes:
- Without
--once, retryable failures continue until deadline and end with exit code1. - In HTTP/HTTPS modes, protocol failure usually means status mismatch or probe failure after connect.
Licensed under the MIT License. See LICENSE for details.