+ // Done.
+ if(buf.len < 0) {
+ return 0;
+ } else {
+ return buf.ptr - data;
+ }
+}
+
+bool parse_request(const void *vdata, size_t size, const char *protocol, const char *transport) {
+ const uint8_t *data = vdata;
+ cbuf_t buf = {data, size};
+
+ // Header
+ buf_get_uint16(&buf); // TX ID
+ buf_check_uint16(&buf, 0); // flags
+ buf_check_uint16(&buf, 1); // 1 question
+ buf_get_uint16(&buf); // ? answer RR
+ buf_get_uint16(&buf); // ? authority RRs
+ buf_get_uint16(&buf); // ? additional RR
+
+ if(buf.len == -1) {
+ return false;
+ }
+
+ // Question section: _protocol._transport.local PTR IN
+ buf_check_ulabel(&buf, protocol);
+ buf_check_ulabel(&buf, transport);
+ buf_check_label(&buf, "local");
+ buf_check_uint8(&buf, 0);
+ buf_check_uint16(&buf, 0xc); // PTR
+ buf_check_uint16(&buf, 0x1); // IN
+
+ if(buf.len == -1) {
+ return false;
+ }
+
+ // Done.
+ return buf.len != -1;
+}
+
+size_t prepare_response(void *vdata, size_t size, const char *name, const char *protocol, const char *transport, uint16_t port, int nkeys, const char **keys, const char **values) {
+ uint8_t *data = vdata;
+ buf_t buf = {data, size};
+
+ // Header
+ buf_add_uint16(&buf, 0); // TX ID
+ buf_add_uint16(&buf, 0x8400); // flags
+ buf_add_uint16(&buf, 0); // 1 question
+ buf_add_uint16(&buf, 3); // 1 answer RR
+ buf_add_uint16(&buf, 0); // 0 authority RRs
+ buf_add_uint16(&buf, 0); // 1 additional RR
+
+ // Add the TXT record: _protocol._transport local TXT IN 3600 name._protocol._transport key=value...
+ uint16_t full_name = buf.ptr - data; // remember start of full name
+ buf_add_label(&buf, name);
+ uint16_t protocol_offset = buf.ptr - data; // remember start of _protocol
+ buf_add_ulabel(&buf, protocol);
+ buf_add_ulabel(&buf, transport);
+ uint16_t local_offset = buf.ptr - data; // remember start of local
+ buf_add_label(&buf, "local");
+ buf_add_uint8(&buf, 0);
+ buf_add_uint16(&buf, 0x10); // TXT