src/
Coverage:
low: ≥ 0%
medium: ≥ 75.0%
high: ≥ 90.0%
Lines:
3 / 3
100.0%
Branches:
-
-%
Functions:
3 / 3
100.0%

ProtoAssembly.h
Line Branch Exec Source
1 #ifndef PROTO_ASSEMBLY_H
2 #define PROTO_ASSEMBLY_H
3 #include <stddef.h>
4 #include <stdint.h>
5
6 // Putting a protocol 2 message back together from the pieces the web server
7 // hands over: a frame larger than a TCP segment, or a message sent as several
8 // frames (docs/PROTOCOL.md). One message at a time across every client, in
9 // one buffer taken when its first piece arrives and given up when it is whole,
10 // refused or stalled, so nothing is held while no long message is on its way.
11 // Not thread safe: the caller locks it. Kept free of the web server so it can
12 // be unit tested on the PC (pio test -e native).
13
14 // How long a message may take to arrive in full.
15 #define PROTO_ASSEMBLY_TIMEOUT_MS 10000
16
17 // One piece of a message.
18 struct proto_piece_t {
19 uint32_t clientId = 0;
20 bool first = false; // its first piece: the start of its first frame
21 bool last = false; // its last piece: the end of its final frame
22 bool text = true; // a text message rather than binary
23 const uint8_t *data = nullptr;
24 size_t len = 0;
25 };
26 enum class assembly_t : uint8_t {
27 more, // wait for the next piece
28 complete, // the message is whole: take() it
29 ignored, // a piece of a message that was already answered
30 busy, // another client's message holds the buffer
31 tooLarge, // over the limit: the rest of it is ignored
32 notText, // a binary message: the rest of it is ignored
33 noMemory // the buffer couldn't be had: the rest of it is ignored
34 };
35 class MessageAssembler {
36 public:
37 9 explicit MessageAssembler(size_t limit) : limit(limit) {}
38 9 ~MessageAssembler() { this->release(); }
39 // Each refusal (busy, tooLarge, notText, noMemory) comes once per message,
40 // from the piece that caused it, so the client gets one reply.
41 assembly_t add(const proto_piece_t &piece, uint32_t now);
42 // The complete message, terminated, for the caller to free(): the
43 // assembler holds nothing after it.
44 char *take(size_t &len);
45 // The client has gone: its part of a message goes with it.
46 void drop(uint32_t clientId);
47 // Gives up a message that has taken too long, returning its client, which
48 // is owed a reply; 0 when none has. The rest of it is ignored.
49 uint32_t expire(uint32_t now);
50 7 bool holding() const { return this->owner != 0; }
51 private:
52 size_t limit;
53 uint32_t owner = 0;
54 uint32_t startedAt = 0;
55 char *buf = nullptr;
56 size_t len = 0;
57 void release();
58 };
59 #endif
60