SpaceOS wire protocol codecs for host-guest communication
1open Wire
2
3let max_value_len = 240
4
5type t = {
6 param_id : int;
7 len : int;
8 generation : int;
9 value : string;
10 crc32 : int;
11}
12
13let codec =
14 let open Codec in
15 record "ParamEntry" (fun param_id len generation value crc32 ->
16 { param_id; len; generation; value; crc32 })
17 |+ field "param_id" uint32be (fun t -> t.param_id)
18 |+ field "len" uint16be (fun t -> t.len)
19 |+ field "generation" uint16be (fun t -> t.generation)
20 |+ field "value" (byte_array ~size:(int max_value_len)) (fun t -> t.value)
21 |+ field "crc32" uint32be (fun t -> t.crc32)
22 |> seal
23
24let crc32c data =
25 Optint.to_unsigned_int
26 (Checkseum.Crc32c.digest_string data 0 (String.length data)
27 Checkseum.Crc32c.default)
28
29let compute_crc t =
30 let wire_size = Codec.wire_size codec in
31 let buf = Bytes.create wire_size in
32 Codec.encode codec t buf 0;
33 (* CRC covers everything before the CRC field *)
34 crc32c (Bytes.sub_string buf 0 (wire_size - 4))
35
36let pad_to n s =
37 let slen = String.length s in
38 if slen >= n then String.sub s 0 n
39 else
40 let b = Bytes.make n '\x00' in
41 Bytes.blit_string s 0 b 0 slen;
42 Bytes.unsafe_to_string b
43
44let v ~param_id ~generation value =
45 let len = min max_value_len (String.length value) in
46 let value = pad_to max_value_len value in
47 let t = { param_id; len; generation; value; crc32 = 0 } in
48 { t with crc32 = compute_crc t }
49
50let value_bytes t = String.sub t.value 0 (min t.len (String.length t.value))
51
52let check_crc t =
53 let expected = compute_crc { t with crc32 = 0 } in
54 t.crc32 = expected
55
56let pp ppf t =
57 Fmt.pf ppf "@[<h>param(id=%d gen=%d len=%d crc=0x%08x)@]" t.param_id
58 t.generation t.len t.crc32
59
60let equal a b =
61 a.param_id = b.param_id && a.len = b.len
62 && a.generation = b.generation
63 && String.equal a.value b.value
64 && a.crc32 = b.crc32