ltp#
Pure OCaml implementation of Licklider Transmission Protocol (RFC 5326) for reliable data delivery over high-delay and disruption-prone links.
Overview#
LTP is designed for deep-space communications where round-trip times can be minutes to hours. It provides selective acknowledgment and retransmission with support for both reliable and unreliable data segments.
Packages#
- ltp -- Core protocol: segment types, SDNV codecs, session management
- ltp-eio -- Eio-based LTP segment transport
Installation#
Install with opam:
$ opam install ltp ltp-eio
If opam cannot find the packages, they may not yet be released in the public
opam-repository. Add the overlay repository, then install them:
$ opam repo add samoht https://tangled.org/gazagnaire.org/opam-overlay.git
$ opam update
$ opam install ltp ltp-eio
Usage#
Send a block#
A block is delivered as a chain of data segments on a shared session, ending
with is_eob:true:
let send_block ~host ~port ~block =
Eio_main.run @@ fun env ->
Eio.Switch.run @@ fun sw ->
let net = (env#net :> [`Generic] Eio.Net.ty Eio.Resource.t) in
let conn = Ltp_eio.connect ~sw ~net ~host ~port in
let session = { Ltp.originator = 1L; number = 42L } in
let chunk_size = 1024 in
let len = String.length block in
let rec send offset =
if offset >= len then ()
else
let size = min chunk_size (len - offset) in
let data = String.sub block offset size in
let last = offset + size = len in
let seg =
Ltp.data_segment
~session_id:session
~client_service_id:1L
~block_offset:(Int64.of_int offset)
~is_eob:last
data
in
Ltp_eio.send conn seg;
send (offset + size)
in
send 0;
Ltp_eio.close conn
Receive a block#
Read segments until one with is_eob seg and concatenate their payloads:
let recv_block ~host ~port =
Eio_main.run @@ fun env ->
Eio.Switch.run @@ fun sw ->
let net = (env#net :> [`Generic] Eio.Net.ty Eio.Resource.t) in
let conn = Ltp_eio.connect ~sw ~net ~host ~port in
let buf = Buffer.create 4096 in
let rec loop () =
match Ltp_eio.recv conn with
| Ok seg ->
(match seg.Ltp.content with
| Ltp.Data d -> Buffer.add_string buf d.Ltp.data
| _ -> ());
if Ltp.is_eob seg then () else loop ()
| Error msg -> Fmt.epr "Error: %s@." msg
in
loop ();
Ltp_eio.close conn;
Fmt.pr "received %d bytes@." (Buffer.length buf)
Features#
- SDNV (Self-Delimiting Numeric Value) encoding/decoding
- Session management with engine/session IDs
- Data segment types:
- Red segments - reliable with acknowledgment
- Green segments - best-effort delivery
- Control segments:
- Report segments (acknowledge received ranges)
- Report-ack segments
- Cancel segments
- Checkpoint and report-based flow control
Segment-level API#
For protocol-level work (checkpoints, reports, cancel flow), construct and inspect segments directly.
Build and encode#
open Ltp
let session = { originator = 1L; number = 42L }
let segment =
data_segment
~session_id:session
~client_service_id:1L
~block_offset:0L
"hello"
let wire = encode_segment segment
SDNV#
let encoded = Ltp.encode_sdnv 127L
let () =
match Ltp.decode_sdnv encoded 0 with
| Ok (value, _offset) -> Fmt.pr "Value: %Ld@." value
| Error msg -> Fmt.pr "Error: %s@." msg
Predicates#
is_data_segment,is_red_segment,is_green_segmentis_checkpoint,is_eorp,is_eob
Report and cancel#
Ltp.report_segment ~session_id ~report_serial ~checkpoint_serial ~upper_bound claimsLtp.report_ack ~session_id ~report_serialLtp.cancel ~session_id ~from_sender reasonLtp.cancel_ack ~session_id ~to_sender
Related Work#
References#
Licence#
ISC License. See LICENSE.md for details.