11#if PC_ENABLE_EDGE_MESH
17void put_u16(uint8_t *p, uint16_t v)
19 p[0] = (uint8_t)(v & 0xFF);
20 p[1] = (uint8_t)(v >> 8);
22uint16_t get_u16(
const uint8_t *p)
24 return (uint16_t)((uint16_t)p[0] | ((uint16_t)p[1] << 8));
26void put_u32(uint8_t *p, uint32_t v)
29 p[1] = (uint8_t)(v >> 8);
30 p[2] = (uint8_t)(v >> 16);
31 p[3] = (uint8_t)(v >> 24);
33uint32_t get_u32(
const uint8_t *p)
35 return (uint32_t)p[0] | ((uint32_t)p[1] << 8) | ((uint32_t)p[2] << 16) | ((uint32_t)p[3] << 24);
37void put_i64(uint8_t *p, int64_t v)
39 uint64_t u = (uint64_t)v;
40 for (
int i = 0; i < 8; i++)
42 p[i] = (uint8_t)(u >> (8 * i));
45int64_t get_i64(
const uint8_t *p)
48 for (
int i = 0; i < 8; i++)
50 u |= (uint64_t)p[i] << (8 * i);
56bool magic_bad(
const uint8_t *buf,
size_t len)
58 if (len >= 1 && buf[0] != PC_EDGE_MESH_MAGIC0)
62 if (len >= 2 && buf[1] != PC_EDGE_MESH_MAGIC1)
66 if (len >= 3 && buf[2] != PC_EDGE_MESH_VERSION)
76size_t edge_mesh_build_request(
const uint8_t digest[32],
const char *canon,
const char *req_hdrs, uint8_t *out,
79 if (!digest || !canon || !out)
83 const char *hdrs = req_hdrs ? req_hdrs :
"";
90 if (kl > 0xFFFFu || hl > 0xFFFFu)
94 size_t need = 2 + 1 + 1 + 32 + 2 + kl + 2 + hl;
100 out[pos++] = PC_EDGE_MESH_MAGIC0;
101 out[pos++] = PC_EDGE_MESH_MAGIC1;
102 out[pos++] = PC_EDGE_MESH_VERSION;
103 out[pos++] = PC_EDGE_MESH_OP_GET;
104 memcpy(out + pos, digest, 32);
106 put_u16(out + pos, (uint16_t)kl);
108 memcpy(out + pos, canon, kl);
110 put_u16(out + pos, (uint16_t)hl);
112 memcpy(out + pos, hdrs, hl);
117EdgeMeshParse edge_mesh_parse_request(
const uint8_t *buf,
size_t len, uint8_t digest_out[32],
char *canon_out,
118 size_t canon_cap,
char *hdrs_out,
size_t hdrs_cap)
120 if (magic_bad(buf, len))
122 return EdgeMeshParse::MALFORMED;
126 return EdgeMeshParse::INCOMPLETE;
128 if (buf[3] != PC_EDGE_MESH_OP_GET)
130 return EdgeMeshParse::MALFORMED;
135 return EdgeMeshParse::INCOMPLETE;
137 size_t digest_off = pos;
141 return EdgeMeshParse::INCOMPLETE;
143 uint16_t kl = get_u16(buf + pos);
147 return EdgeMeshParse::MALFORMED;
151 return EdgeMeshParse::INCOMPLETE;
153 size_t key_off = pos;
157 return EdgeMeshParse::INCOMPLETE;
159 uint16_t hl = get_u16(buf + pos);
163 return EdgeMeshParse::MALFORMED;
167 return EdgeMeshParse::INCOMPLETE;
169 size_t hdrs_off = pos;
172 memcpy(digest_out, buf + digest_off, 32);
176 memcpy(canon_out, buf + key_off, kl);
177 canon_out[kl] =
'\0';
181 memcpy(hdrs_out, buf + hdrs_off, hl);
184 return EdgeMeshParse::HIT;
187size_t edge_mesh_serialize_entry(
const EdgeEntry *e,
long current_age, uint8_t *out,
size_t cap)
197 put_i64(out + 0, e->date_epoch);
198 put_i64(out + 8, e->expires_epoch);
199 put_u32(out + 16, (uint32_t)(e->lifetime_s < 0 ? 0 : e->lifetime_s));
200 put_u32(out + 20, (uint32_t)(e->age_hdr < 0 ? 0 : e->age_hdr));
201 put_u32(out + 24, (uint32_t)current_age);
210bool edge_mesh_deserialize_entry(
const uint8_t *buf,
size_t len, EdgeEntry *e, uint32_t now_ms)
216 int64_t date = get_i64(buf + 0);
217 int64_t expires = get_i64(buf + 8);
218 uint32_t lifetime = get_u32(buf + 16);
219 uint32_t age_hdr = get_u32(buf + 20);
220 uint32_t current_age = get_u32(buf + 24);
225 e->date_epoch = date;
226 e->expires_epoch = expires;
227 e->lifetime_s = (long)lifetime;
228 e->age_hdr = (int32_t)age_hdr;
229 e->initial_age = (long)current_age;
230 e->insert_ms = now_ms;
231 e->last_used_ms = now_ms;
235size_t edge_mesh_build_response(
bool hit,
const uint8_t *entry,
size_t entry_len, uint8_t *out,
size_t cap)
242 out[pos++] = PC_EDGE_MESH_MAGIC0;
243 out[pos++] = PC_EDGE_MESH_MAGIC1;
244 out[pos++] = PC_EDGE_MESH_VERSION;
245 out[pos++] = hit ? 1 : 0;
248 if (!entry || entry_len == 0 || entry_len > 0xFFFFu || pos + 2 + entry_len > cap)
252 put_u16(out + pos, (uint16_t)entry_len);
254 memcpy(out + pos, entry, entry_len);
260EdgeMeshParse edge_mesh_parse_response(
const uint8_t *buf,
size_t len,
size_t *entry_off,
size_t *entry_len)
262 if (magic_bad(buf, len))
264 return EdgeMeshParse::MALFORMED;
268 return EdgeMeshParse::INCOMPLETE;
270 uint8_t status = buf[3];
273 return EdgeMeshParse::MISS;
277 return EdgeMeshParse::MALFORMED;
281 return EdgeMeshParse::INCOMPLETE;
283 uint16_t el = get_u16(buf + 4);
286 return EdgeMeshParse::MALFORMED;
288 if (len < (
size_t)6 + el)
290 return EdgeMeshParse::INCOMPLETE;
300 return EdgeMeshParse::HIT;
305void edge_mesh_fetch_begin(EdgeMeshFetch *m,
const EdgeFetchTransport *t,
const char *host, uint16_t port,
306 const uint8_t *request,
size_t req_len, uint8_t *buf,
size_t cap, uint32_t now_ms)
308 m->st = EdgeMeshStatus::PENDING;
310 m->start_ms = now_ms;
318 m->st = EdgeMeshStatus::FAILED;
324 m->st = EdgeMeshStatus::FAILED;
328 if (!t->send(t->ctx, cid, request, req_len))
330 t->close(t->ctx, cid);
332 m->st = EdgeMeshStatus::FAILED;
336EdgeMeshStatus edge_mesh_fetch_pump(EdgeMeshFetch *m,
const EdgeFetchTransport *t, uint32_t now_ms)
338 if (m->st != EdgeMeshStatus::PENDING)
342 if (!t || m->cid < 0)
344 m->st = EdgeMeshStatus::FAILED;
349 m->st = EdgeMeshStatus::FAILED;
355 m->got += t->read(t->ctx, m->cid, m->buf + m->got, m->cap - m->got);
360 EdgeMeshParse p = edge_mesh_parse_response(m->buf, m->got, &eoff, &elen);
361 if (p == EdgeMeshParse::HIT)
365 m->st = EdgeMeshStatus::HIT;
367 else if (p == EdgeMeshParse::MISS)
369 m->st = EdgeMeshStatus::MISS;
371 else if (p == EdgeMeshParse::MALFORMED)
373 m->st = EdgeMeshStatus::FAILED;
375 else if (m->got >= m->cap || t->closed(t->ctx, m->cid))
377 m->st = EdgeMeshStatus::FAILED;
382void edge_mesh_fetch_end(EdgeMeshFetch *m,
const EdgeFetchTransport *t)
384 if (m->cid >= 0 && t)
386 t->close(t->ctx, m->cid);
CDN edge-cache tier - mesh (sibling-cache) wire codec + async peer-query engine (PC_ENABLE_EDGE_MESH)...
#define PC_EDGE_MESH_TRAILER
Fixed timing trailer prepended to a mesh entry frame (age propagation).
#define PC_EDGE_MESH_RESP_MAX
Worst-case mesh response frame (header + entry on a HIT).