ProvSQL C/C++ API
Adding support for provenance and uncertainty management to PostgreSQL databases
Loading...
Searching...
No Matches
kcmcp_protocol.h
Go to the documentation of this file.
1/**
2 * @file kcmcp_protocol.h
3 * @brief Wire codec for KCMCP, the Knowledge Compiler / Model Counter
4 * Protocol (see doc/source/dev/kc-server-protocol.rst).
5 *
6 * A small, dependency-free C++ layer over a connected stream socket: the
7 * 10-byte frame header, MORE-chunked message reassembly, and pack/unpack of
8 * the REQUEST / RESULT / ERROR payloads and the operation / format / error
9 * registries. It is used by the @c tdkc reference server and is written to
10 * be reusable by a future ProvSQL client. No PostgreSQL dependency.
11 */
12#ifndef PROVSQL_KCMCP_PROTOCOL_H
13#define PROVSQL_KCMCP_PROTOCOL_H
14
15#include <cstdint>
16#include <stdexcept>
17#include <string>
18
19namespace kcmcp {
20
21/// Frame type (header byte 0).
22enum class Type : uint8_t {
23 HELLO = 0x00,
24 REQUEST = 0x01,
25 RESULT = 0x02,
26 ERROR = 0x03,
27 PROGRESS = 0x04,
28 CANCEL = 0x05,
29 PING = 0x06,
30 PONG = 0x07,
31 BYE = 0x08,
32};
33
34/// Frame flags (header byte 1).
35enum Flag : uint8_t {
36 FLAG_MORE = 0x01, ///< payload continues in the next frame
37 FLAG_COMPRESSED = 0x02, ///< payload is zstd-compressed (unused here)
38};
39
40/// Operation registry (REQUEST byte 0 / HELLO @c operations names).
41enum class Operation : uint8_t { COUNT = 0, WMC = 1, COMPILE = 2 };
42
43/// Input-format registry (REQUEST byte 1).
44enum class InputFormat : uint8_t { DIMACS_CNF = 0, CIRCUIT_BCS12 = 1 };
45
46/// Output-format registry (REQUEST byte 2 / RESULT byte 0; one shared space).
47enum class OutputFormat : uint8_t {
48 DECIMAL = 0, RATIONAL = 1, DOUBLE = 2, BIGINT = 3, DDNNF_NNF = 4 };
49
50/// ERROR codes.
51enum class ErrorCode : uint16_t {
52 UNSUPPORTED_OPERATION = 1, ///< unsupported operation or unknown frame type
54 PARSE = 3,
59 UNSUPPORTED_VERSION = 8, ///< client requires a KCMCP major this server lacks
60 COMPRESSION_UNSUPPORTED = 9, ///< COMPRESSED frame flag set, but unsupported
61};
62
63const char *operation_name(Operation op);
64const char *input_format_name(InputFormat fmt);
65const char *output_format_name(OutputFormat fmt);
66
67/// Thrown by Connection on a protocol violation that warrants an ERROR frame
68/// (e.g. an oversize incoming frame); @ref code is the KCMCP error code.
69/// @ref fatal is false when the stream stayed synchronised (the offending
70/// message was fully consumed), so the caller may answer with an ERROR and
71/// keep serving the connection; true when the stream is desynchronised and
72/// the connection must be closed.
73struct ProtocolError : std::runtime_error {
75 bool fatal;
76 ProtocolError(ErrorCode c, const std::string &what, bool fatal_ = true)
77 : std::runtime_error(what), code(c), fatal(fatal_) {}
78};
79
80/// A fully reassembled inbound message (MORE frames concatenated).
81struct Message {
83 uint32_t request_id{};
84 std::string payload;
85};
86
87/// Decoded REQUEST payload.
88struct Request {
92 std::string options; ///< UTF-8 JSON (may be empty == {})
93 std::string problem; ///< the formula bytes
94};
95
96/**
97 * @brief Framed message transport over one connected socket fd.
98 *
99 * @c recv_max is the largest single-frame payload this side accepts (its
100 * advertised @c max_payload); @c send_max is the peer's accept limit, used to
101 * split outbound payloads into MORE-flagged frames. Blocking I/O.
102 */
104public:
105 Connection(int fd, uint32_t recv_max, uint32_t send_max)
106 : fd_(fd), recv_max_(recv_max), send_max_(send_max) {}
107
108 /// Read one logical message (concatenating MORE frames). Returns false on
109 /// a clean peer close at a frame boundary. Throws ProtocolError on an
110 /// oversize frame, std::runtime_error on an I/O error or truncation.
111 bool recv(Message &out);
112
113 /// Send a message, splitting @p payload across MORE-flagged frames no larger
114 /// than the peer's limit.
115 void send(Type type, uint32_t request_id, const std::string &payload);
116 void send(Type type, uint32_t request_id) { send(type, request_id, std::string()); }
117
118 int fd() const { return fd_; }
119
120private:
121 int fd_;
122 uint32_t recv_max_;
123 uint32_t send_max_;
124};
125
126/// Decode a REQUEST payload; returns false if structurally malformed.
127bool parse_request(const std::string &payload, Request &out);
128
129/// Build a RESULT payload (result_format byte + meta JSON + result bytes).
130std::string build_result(OutputFormat fmt, const std::string &meta_json,
131 const std::string &result);
132
133/// Build an ERROR payload (u16 code + UTF-8 message).
134std::string build_error(ErrorCode code, const std::string &message);
135
136} // namespace kcmcp
137
138#endif
bool recv(Message &out)
Read one logical message (concatenating MORE frames).
void send(Type type, uint32_t request_id, const std::string &payload)
Send a message, splitting payload across MORE-flagged frames no larger than the peer's limit.
void send(Type type, uint32_t request_id)
Connection(int fd, uint32_t recv_max, uint32_t send_max)
std::string build_result(OutputFormat fmt, const std::string &meta_json, const std::string &result)
Build a RESULT payload (result_format byte + meta JSON + result bytes).
Flag
Frame flags (header byte 1).
@ FLAG_MORE
payload continues in the next frame
@ FLAG_COMPRESSED
payload is zstd-compressed (unused here)
InputFormat
Input-format registry (REQUEST byte 1).
Type
Frame type (header byte 0).
const char * input_format_name(InputFormat fmt)
const char * output_format_name(OutputFormat fmt)
Operation
Operation registry (REQUEST byte 0 / HELLO operations names).
ErrorCode
ERROR codes.
@ UNSUPPORTED_VERSION
client requires a KCMCP major this server lacks
@ COMPRESSION_UNSUPPORTED
COMPRESSED frame flag set, but unsupported.
@ UNSUPPORTED_OPERATION
unsupported operation or unknown frame type
const char * operation_name(Operation op)
OutputFormat
Output-format registry (REQUEST byte 2 / RESULT byte 0; one shared space).
std::string build_error(ErrorCode code, const std::string &message)
Build an ERROR payload (u16 code + UTF-8 message).
bool parse_request(const std::string &payload, Request &out)
Decode a REQUEST payload; returns false if structurally malformed.
A fully reassembled inbound message (MORE frames concatenated).
uint32_t request_id
std::string payload
ProtocolError(ErrorCode c, const std::string &what, bool fatal_=true)
Decoded REQUEST payload.
InputFormat input_format
std::string problem
the formula bytes
Operation operation
std::string options
UTF-8 JSON (may be empty == {}).
OutputFormat output_format