1// Copyright (c) 2004-2013 Sergey Lyubka
2// Copyright (c) 2013-2022 Cesanta Software Limited
3// All rights reserved
4//
5// This software is dual-licensed: you can redistribute it and/or modify
6// it under the terms of the GNU General Public License version 2 as
7// published by the Free Software Foundation. For the terms of this
8// license, see http://www.gnu.org/licenses/
9//
10// You are free to use this software under the terms of the GNU General
11// Public License, but WITHOUT ANY WARRANTY; without even the implied
12// warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
13// See the GNU General Public License for more details.
14//
15// Alternatively, you can license this software under a commercial
16// license, as set out in https://www.mongoose.ws/licensing/
17//
18// SPDX-License-Identifier: GPL-2.0-only or commercial
19
20#include "mongoose.h"
21
22#if defined(__sunos__)
23 #include <alloca.h>
24#endif
25
26#ifdef MG_ENABLE_LINES
27#line 1 "src/base64.c"
28#endif
29
30
31
32static int mg_b64idx(int c) {
33 if (c < 26) {
34 return c + 'A';
35 } else if (c < 52) {
36 return c - 26 + 'a';
37 } else if (c < 62) {
38 return c - 52 + '0';
39 } else {
40 return c == 62 ? '+' : '/';
41 }
42}
43
44static int mg_b64rev(int c) {
45 if (c >= 'A' && c <= 'Z') {
46 return c - 'A';
47 } else if (c >= 'a' && c <= 'z') {
48 return c + 26 - 'a';
49 } else if (c >= '0' && c <= '9') {
50 return c + 52 - '0';
51 } else if (c == '+') {
52 return 62;
53 } else if (c == '/') {
54 return 63;
55 } else if (c == '=') {
56 return 64;
57 } else {
58 return -1;
59 }
60}
61
62int mg_base64_update(unsigned char ch, char *to, int n) {
63 int rem = (n & 3) % 3;
64 if (rem == 0) {
65 to[n] = (char) mg_b64idx(ch >> 2);
66 to[++n] = (char) ((ch & 3) << 4);
67 } else if (rem == 1) {
68 to[n] = (char) mg_b64idx(to[n] | (ch >> 4));
69 to[++n] = (char) ((ch & 15) << 2);
70 } else {
71 to[n] = (char) mg_b64idx(to[n] | (ch >> 6));
72 to[++n] = (char) mg_b64idx(ch & 63);
73 n++;
74 }
75 return n;
76}
77
78int mg_base64_final(char *to, int n) {
79 int saved = n;
80 // printf("---[%.*s]\n", n, to);
81 if (n & 3) n = mg_base64_update(0, to, n);
82 if ((saved & 3) == 2) n--;
83 // printf(" %d[%.*s]\n", n, n, to);
84 while (n & 3) to[n++] = '=';
85 to[n] = '\0';
86 return n;
87}
88
89int mg_base64_encode(const unsigned char *p, int n, char *to) {
90 int i, len = 0;
91 for (i = 0; i < n; i++) len = mg_base64_update(p[i], to, len);
92 len = mg_base64_final(to, len);
93 return len;
94}
95
96int mg_base64_decode(const char *src, int n, char *dst) {
97 const char *end = src == NULL ? NULL : src + n; // Cannot add to NULL
98 int len = 0;
99 while (src != NULL && src + 3 < end) {
100 int a = mg_b64rev(src[0]), b = mg_b64rev(src[1]), c = mg_b64rev(src[2]),
101 d = mg_b64rev(src[3]);
102 if (a == 64 || a < 0 || b == 64 || b < 0 || c < 0 || d < 0) return 0;
103 dst[len++] = (char) ((a << 2) | (b >> 4));
104 if (src[2] != '=') {
105 dst[len++] = (char) ((b << 4) | (c >> 2));
106 if (src[3] != '=') dst[len++] = (char) ((c << 6) | d);
107 }
108 src += 4;
109 }
110 dst[len] = '\0';
111 return len;
112}
113
114#ifdef MG_ENABLE_LINES
115#line 1 "src/dns.c"
116#endif
117
118
119
120
121
122
123
124
125struct dns_data {
126 struct dns_data *next;
127 struct mg_connection *c;
128 uint64_t expire;
129 uint16_t txnid;
130};
131
132static void mg_sendnsreq(struct mg_connection *, struct mg_str *, int,
133 struct mg_dns *, bool);
134
135static void mg_dns_free(struct mg_connection *c, struct dns_data *d) {
136 LIST_DELETE(struct dns_data,
137 (struct dns_data **) &c->mgr->active_dns_requests, d);
138 free(d);
139}
140
141void mg_resolve_cancel(struct mg_connection *c) {
142 struct dns_data *tmp, *d = (struct dns_data *) c->mgr->active_dns_requests;
143 for (; d != NULL; d = tmp) {
144 tmp = d->next;
145 if (d->c == c) mg_dns_free(c, d);
146 }
147}
148
149static size_t mg_dns_parse_name_depth(const uint8_t *s, size_t len, size_t ofs,
150 char *to, size_t tolen, size_t j,
151 int depth) {
152 size_t i = 0;
153 if (tolen > 0 && depth == 0) to[0] = '\0';
154 if (depth > 5) return 0;
155 // MG_INFO(("ofs %lx %x %x", (unsigned long) ofs, s[ofs], s[ofs + 1]));
156 while (ofs + i + 1 < len) {
157 size_t n = s[ofs + i];
158 if (n == 0) {
159 i++;
160 break;
161 }
162 if (n & 0xc0) {
163 size_t ptr = (((n & 0x3f) << 8) | s[ofs + i + 1]); // 12 is hdr len
164 // MG_INFO(("PTR %lx", (unsigned long) ptr));
165 if (ptr + 1 < len && (s[ptr] & 0xc0) == 0 &&
166 mg_dns_parse_name_depth(s, len, ptr, to, tolen, j, depth + 1) == 0)
167 return 0;
168 i += 2;
169 break;
170 }
171 if (ofs + i + n + 1 >= len) return 0;
172 if (j > 0) {
173 if (j < tolen) to[j] = '.';
174 j++;
175 }
176 if (j + n < tolen) memcpy(&to[j], &s[ofs + i + 1], n);
177 j += n;
178 i += n + 1;
179 if (j < tolen) to[j] = '\0'; // Zero-terminate this chunk
180 // MG_INFO(("--> [%s]", to));
181 }
182 if (tolen > 0) to[tolen - 1] = '\0'; // Make sure make sure it is nul-term
183 return i;
184}
185
186static size_t mg_dns_parse_name(const uint8_t *s, size_t n, size_t ofs,
187 char *dst, size_t dstlen) {
188 return mg_dns_parse_name_depth(s, n, ofs, dst, dstlen, 0, 0);
189}
190
191size_t mg_dns_parse_rr(const uint8_t *buf, size_t len, size_t ofs,
192 bool is_question, struct mg_dns_rr *rr) {
193 const uint8_t *s = buf + ofs, *e = &buf[len];
194
195 memset(rr, 0, sizeof(*rr));
196 if (len < sizeof(struct mg_dns_header)) return 0; // Too small
197 if (len > 512) return 0; // Too large, we don't expect that
198 if (s >= e) return 0; // Overflow
199
200 if ((rr->nlen = (uint16_t) mg_dns_parse_name(buf, len, ofs, NULL, 0)) == 0)
201 return 0;
202 s += rr->nlen + 4;
203 if (s > e) return 0;
204 rr->atype = (uint16_t) (((uint16_t) s[-4] << 8) | s[-3]);
205 rr->aclass = (uint16_t) (((uint16_t) s[-2] << 8) | s[-1]);
206 if (is_question) return (size_t) (rr->nlen + 4);
207
208 s += 6;
209 if (s > e) return 0;
210 rr->alen = (uint16_t) (((uint16_t) s[-2] << 8) | s[-1]);
211 if (s + rr->alen > e) return 0;
212 return (size_t) (rr->nlen + rr->alen + 10);
213}
214
215bool mg_dns_parse(const uint8_t *buf, size_t len, struct mg_dns_message *dm) {
216 const struct mg_dns_header *h = (struct mg_dns_header *) buf;
217 struct mg_dns_rr rr;
218 size_t i, n, ofs = sizeof(*h);
219 memset(dm, 0, sizeof(*dm));
220
221 if (len < sizeof(*h)) return 0; // Too small, headers dont fit
222 if (mg_ntohs(h->num_questions) > 1) return 0; // Sanity
223 if (mg_ntohs(h->num_answers) > 10) return 0; // Sanity
224 dm->txnid = mg_ntohs(h->txnid);
225
226 for (i = 0; i < mg_ntohs(h->num_questions); i++) {
227 if ((n = mg_dns_parse_rr(buf, len, ofs, true, &rr)) == 0) return false;
228 // MG_INFO(("Q %lu %lu %hu/%hu", ofs, n, rr.atype, rr.aclass));
229 ofs += n;
230 }
231 for (i = 0; i < mg_ntohs(h->num_answers); i++) {
232 if ((n = mg_dns_parse_rr(buf, len, ofs, false, &rr)) == 0) return false;
233 // MG_INFO(("A -- %lu %lu %hu/%hu %s", ofs, n, rr.atype, rr.aclass,
234 // dm->name));
235 mg_dns_parse_name(buf, len, ofs, dm->name, sizeof(dm->name));
236 ofs += n;
237
238 if (rr.alen == 4 && rr.atype == 1 && rr.aclass == 1) {
239 dm->addr.is_ip6 = false;
240 memcpy(&dm->addr.ip, &buf[ofs - 4], 4);
241 dm->resolved = true;
242 break; // Return success
243 } else if (rr.alen == 16 && rr.atype == 28 && rr.aclass == 1) {
244 dm->addr.is_ip6 = true;
245 memcpy(&dm->addr.ip, &buf[ofs - 16], 16);
246 dm->resolved = true;
247 break; // Return success
248 }
249 }
250 return true;
251}
252
253static void dns_cb(struct mg_connection *c, int ev, void *ev_data,
254 void *fn_data) {
255 struct dns_data *d, *tmp;
256 if (ev == MG_EV_POLL) {
257 uint64_t now = *(uint64_t *) ev_data;
258 for (d = (struct dns_data *) c->mgr->active_dns_requests; d != NULL;
259 d = tmp) {
260 tmp = d->next;
261 // MG_DEBUG ("%lu %lu dns poll", d->expire, now));
262 if (now > d->expire) mg_error(d->c, "DNS timeout");
263 }
264 } else if (ev == MG_EV_READ) {
265 struct mg_dns_message dm;
266 int resolved = 0;
267 if (mg_dns_parse(c->recv.buf, c->recv.len, &dm) == false) {
268 MG_ERROR(("Unexpected DNS response:"));
269 mg_hexdump(c->recv.buf, c->recv.len);
270 } else {
271 // MG_VERBOSE(("%s %d", dm.name, dm.resolved));
272 for (d = (struct dns_data *) c->mgr->active_dns_requests; d != NULL;
273 d = tmp) {
274 tmp = d->next;
275 // MG_INFO(("d %p %hu %hu", d, d->txnid, dm.txnid));
276 if (dm.txnid != d->txnid) continue;
277 if (d->c->is_resolving) {
278 if (dm.resolved) {
279 dm.addr.port = d->c->rem.port; // Save port
280 d->c->rem = dm.addr; // Copy resolved address
281 MG_DEBUG(
282 ("%lu %s is %M", d->c->id, dm.name, mg_print_ip, &d->c->rem));
283 mg_connect_resolved(d->c);
284#if MG_ENABLE_IPV6
285 } else if (dm.addr.is_ip6 == false && dm.name[0] != '\0' &&
286 c->mgr->use_dns6 == false) {
287 struct mg_str x = mg_str(dm.name);
288 mg_sendnsreq(d->c, &x, c->mgr->dnstimeout, &c->mgr->dns6, true);
289#endif
290 } else {
291 mg_error(d->c, "%s DNS lookup failed", dm.name);
292 }
293 } else {
294 MG_ERROR(("%lu already resolved", d->c->id));
295 }
296 mg_dns_free(c, d);
297 resolved = 1;
298 }
299 }
300 if (!resolved) MG_ERROR(("stray DNS reply"));
301 c->recv.len = 0;
302 } else if (ev == MG_EV_CLOSE) {
303 for (d = (struct dns_data *) c->mgr->active_dns_requests; d != NULL;
304 d = tmp) {
305 tmp = d->next;
306 mg_error(d->c, "DNS error");
307 mg_dns_free(c, d);
308 }
309 }
310 (void) fn_data;
311}
312
313static bool mg_dns_send(struct mg_connection *c, const struct mg_str *name,
314 uint16_t txnid, bool ipv6) {
315 struct {
316 struct mg_dns_header header;
317 uint8_t data[256];
318 } pkt;
319 size_t i, n;
320 memset(&pkt, 0, sizeof(pkt));
321 pkt.header.txnid = mg_htons(txnid);
322 pkt.header.flags = mg_htons(0x100);
323 pkt.header.num_questions = mg_htons(1);
324 for (i = n = 0; i < sizeof(pkt.data) - 5; i++) {
325 if (name->ptr[i] == '.' || i >= name->len) {
326 pkt.data[n] = (uint8_t) (i - n);
327 memcpy(&pkt.data[n + 1], name->ptr + n, i - n);
328 n = i + 1;
329 }
330 if (i >= name->len) break;
331 }
332 memcpy(&pkt.data[n], "\x00\x00\x01\x00\x01", 5); // A query
333 n += 5;
334 if (ipv6) pkt.data[n - 3] = 0x1c; // AAAA query
335 // memcpy(&pkt.data[n], "\xc0\x0c\x00\x1c\x00\x01", 6); // AAAA query
336 // n += 6;
337 return mg_send(c, &pkt, sizeof(pkt.header) + n);
338}
339
340static void mg_sendnsreq(struct mg_connection *c, struct mg_str *name, int ms,
341 struct mg_dns *dnsc, bool ipv6) {
342 struct dns_data *d = NULL;
343 if (dnsc->url == NULL) {
344 mg_error(c, "DNS server URL is NULL. Call mg_mgr_init()");
345 } else if (dnsc->c == NULL) {
346 dnsc->c = mg_connect(c->mgr, dnsc->url, NULL, NULL);
347 if (dnsc->c != NULL) {
348 dnsc->c->pfn = dns_cb;
349 // dnsc->c->is_hexdumping = 1;
350 }
351 }
352 if (dnsc->c == NULL) {
353 mg_error(c, "resolver");
354 } else if ((d = (struct dns_data *) calloc(1, sizeof(*d))) == NULL) {
355 mg_error(c, "resolve OOM");
356 } else {
357 struct dns_data *reqs = (struct dns_data *) c->mgr->active_dns_requests;
358 d->txnid = reqs ? (uint16_t) (reqs->txnid + 1) : 1;
359 d->next = (struct dns_data *) c->mgr->active_dns_requests;
360 c->mgr->active_dns_requests = d;
361 d->expire = mg_millis() + (uint64_t) ms;
362 d->c = c;
363 c->is_resolving = 1;
364 MG_VERBOSE(("%lu resolving %.*s @ %s, txnid %hu", c->id, (int) name->len,
365 name->ptr, dnsc->url, d->txnid));
366 if (!mg_dns_send(dnsc->c, name, d->txnid, ipv6)) {
367 mg_error(dnsc->c, "DNS send");
368 }
369 }
370}
371
372void mg_resolve(struct mg_connection *c, const char *url) {
373 struct mg_str host = mg_url_host(url);
374 c->rem.port = mg_htons(mg_url_port(url));
375 if (mg_aton(host, &c->rem)) {
376 // host is an IP address, do not fire name resolution
377 mg_connect_resolved(c);
378 } else {
379 // host is not an IP, send DNS resolution request
380 struct mg_dns *dns = c->mgr->use_dns6 ? &c->mgr->dns6 : &c->mgr->dns4;
381 mg_sendnsreq(c, &host, c->mgr->dnstimeout, dns, c->mgr->use_dns6);
382 }
383}
384
385#ifdef MG_ENABLE_LINES
386#line 1 "src/event.c"
387#endif
388
389
390
391
392
393void mg_call(struct mg_connection *c, int ev, void *ev_data) {
394 // Run user-defined handler first, in order to give it an ability
395 // to intercept processing (e.g. clean input buffer) before the
396 // protocol handler kicks in
397 if (c->fn != NULL) c->fn(c, ev, ev_data, c->fn_data);
398 if (c->pfn != NULL) c->pfn(c, ev, ev_data, c->pfn_data);
399}
400
401void mg_error(struct mg_connection *c, const char *fmt, ...) {
402 char buf[64];
403 va_list ap;
404 va_start(ap, fmt);
405 mg_vsnprintf(buf, sizeof(buf), fmt, &ap);
406 va_end(ap);
407 MG_ERROR(("%lu %p %s", c->id, c->fd, buf));
408 c->is_closing = 1; // Set is_closing before sending MG_EV_CALL
409 mg_call(c, MG_EV_ERROR, buf); // Let user handler to override it
410}
411
412#ifdef MG_ENABLE_LINES
413#line 1 "src/fmt.c"
414#endif
415
416
417
418
419static bool is_digit(int c) {
420 return c >= '0' && c <= '9';
421}
422
423static int addexp(char *buf, int e, int sign) {
424 int n = 0;
425 buf[n++] = 'e';
426 buf[n++] = (char) sign;
427 if (e > 400) return 0;
428 if (e < 10) buf[n++] = '0';
429 if (e >= 100) buf[n++] = (char) (e / 100 + '0'), e -= 100 * (e / 100);
430 if (e >= 10) buf[n++] = (char) (e / 10 + '0'), e -= 10 * (e / 10);
431 buf[n++] = (char) (e + '0');
432 return n;
433}
434
435static int xisinf(double x) {
436 union {
437 double f;
438 uint64_t u;
439 } ieee754 = {x};
440 return ((unsigned) (ieee754.u >> 32) & 0x7fffffff) == 0x7ff00000 &&
441 ((unsigned) ieee754.u == 0);
442}
443
444static int xisnan(double x) {
445 union {
446 double f;
447 uint64_t u;
448 } ieee754 = {x};
449 return ((unsigned) (ieee754.u >> 32) & 0x7fffffff) +
450 ((unsigned) ieee754.u != 0) >
451 0x7ff00000;
452}
453
454static size_t mg_dtoa(char *dst, size_t dstlen, double d, int width, bool tz) {
455 char buf[40];
456 int i, s = 0, n = 0, e = 0;
457 double t, mul, saved;
458 if (d == 0.0) return mg_snprintf(dst, dstlen, "%s", "0");
459 if (xisinf(d)) return mg_snprintf(dst, dstlen, "%s", d > 0 ? "inf" : "-inf");
460 if (xisnan(d)) return mg_snprintf(dst, dstlen, "%s", "nan");
461 if (d < 0.0) d = -d, buf[s++] = '-';
462
463 // Round
464 saved = d;
465 mul = 1.0;
466 while (d >= 10.0 && d / mul >= 10.0) mul *= 10.0;
467 while (d <= 1.0 && d / mul <= 1.0) mul /= 10.0;
468 for (i = 0, t = mul * 5; i < width; i++) t /= 10.0;
469 d += t;
470 // Calculate exponent, and 'mul' for scientific representation
471 mul = 1.0;
472 while (d >= 10.0 && d / mul >= 10.0) mul *= 10.0, e++;
473 while (d < 1.0 && d / mul < 1.0) mul /= 10.0, e--;
474 // printf(" --> %g %d %g %g\n", saved, e, t, mul);
475
476 if (e >= width && width > 1) {
477 n = (int) mg_dtoa(buf, sizeof(buf), saved / mul, width, tz);
478 // printf(" --> %.*g %d [%.*s]\n", 10, d / t, e, n, buf);
479 n += addexp(buf + s + n, e, '+');
480 return mg_snprintf(dst, dstlen, "%.*s", n, buf);
481 } else if (e <= -width && width > 1) {
482 n = (int) mg_dtoa(buf, sizeof(buf), saved / mul, width, tz);
483 // printf(" --> %.*g %d [%.*s]\n", 10, d / mul, e, n, buf);
484 n += addexp(buf + s + n, -e, '-');
485 return mg_snprintf(dst, dstlen, "%.*s", n, buf);
486 } else {
487 for (i = 0, t = mul; t >= 1.0 && s + n < (int) sizeof(buf); i++) {
488 int ch = (int) (d / t);
489 if (n > 0 || ch > 0) buf[s + n++] = (char) (ch + '0');
490 d -= ch * t;
491 t /= 10.0;
492 }
493 // printf(" --> [%g] -> %g %g (%d) [%.*s]\n", saved, d, t, n, s + n, buf);
494 if (n == 0) buf[s++] = '0';
495 while (t >= 1.0 && n + s < (int) sizeof(buf)) buf[n++] = '0', t /= 10.0;
496 if (s + n < (int) sizeof(buf)) buf[n + s++] = '.';
497 // printf(" 1--> [%g] -> [%.*s]\n", saved, s + n, buf);
498 for (i = 0, t = 0.1; s + n < (int) sizeof(buf) && n < width; i++) {
499 int ch = (int) (d / t);
500 buf[s + n++] = (char) (ch + '0');
501 d -= ch * t;
502 t /= 10.0;
503 }
504 }
505 while (tz && n > 0 && buf[s + n - 1] == '0') n--; // Trim trailing zeroes
506 if (n > 0 && buf[s + n - 1] == '.') n--; // Trim trailing dot
507 n += s;
508 if (n >= (int) sizeof(buf)) n = (int) sizeof(buf) - 1;
509 buf[n] = '\0';
510 return mg_snprintf(dst, dstlen, "%s", buf);
511}
512
513static size_t mg_lld(char *buf, int64_t val, bool is_signed, bool is_hex) {
514 const char *letters = "0123456789abcdef";
515 uint64_t v = (uint64_t) val;
516 size_t s = 0, n, i;
517 if (is_signed && val < 0) buf[s++] = '-', v = (uint64_t) (-val);
518 // This loop prints a number in reverse order. I guess this is because we
519 // write numbers from right to left: least significant digit comes last.
520 // Maybe because we use Arabic numbers, and Arabs write RTL?
521 if (is_hex) {
522 for (n = 0; v; v >>= 4) buf[s + n++] = letters[v & 15];
523 } else {
524 for (n = 0; v; v /= 10) buf[s + n++] = letters[v % 10];
525 }
526 // Reverse a string
527 for (i = 0; i < n / 2; i++) {
528 char t = buf[s + i];
529 buf[s + i] = buf[s + n - i - 1], buf[s + n - i - 1] = t;
530 }
531 if (val == 0) buf[n++] = '0'; // Handle special case
532 return n + s;
533}
534
535static size_t scpy(void (*out)(char, void *), void *ptr, char *buf,
536 size_t len) {
537 size_t i = 0;
538 while (i < len && buf[i] != '\0') out(buf[i++], ptr);
539 return i;
540}
541
542size_t mg_xprintf(void (*out)(char, void *), void *ptr, const char *fmt, ...) {
543 size_t len = 0;
544 va_list ap;
545 va_start(ap, fmt);
546 len = mg_vxprintf(out, ptr, fmt, &ap);
547 va_end(ap);
548 return len;
549}
550
551size_t mg_vxprintf(void (*out)(char, void *), void *param, const char *fmt,
552 va_list *ap) {
553 size_t i = 0, n = 0;
554 while (fmt[i] != '\0') {
555 if (fmt[i] == '%') {
556 size_t j, k, x = 0, is_long = 0, w = 0 /* width */, pr = ~0U /* prec */;
557 char pad = ' ', minus = 0, c = fmt[++i];
558 if (c == '#') x++, c = fmt[++i];
559 if (c == '-') minus++, c = fmt[++i];
560 if (c == '0') pad = '0', c = fmt[++i];
561 while (is_digit(c)) w *= 10, w += (size_t) (c - '0'), c = fmt[++i];
562 if (c == '.') {
563 c = fmt[++i];
564 if (c == '*') {
565 pr = (size_t) va_arg(*ap, int);
566 c = fmt[++i];
567 } else {
568 pr = 0;
569 while (is_digit(c)) pr *= 10, pr += (size_t) (c - '0'), c = fmt[++i];
570 }
571 }
572 while (c == 'h') c = fmt[++i]; // Treat h and hh as int
573 if (c == 'l') {
574 is_long++, c = fmt[++i];
575 if (c == 'l') is_long++, c = fmt[++i];
576 }
577 if (c == 'p') x = 1, is_long = 1;
578 if (c == 'd' || c == 'u' || c == 'x' || c == 'X' || c == 'p' ||
579 c == 'g' || c == 'f') {
580 bool s = (c == 'd'), h = (c == 'x' || c == 'X' || c == 'p');
581 char tmp[40];
582 size_t xl = x ? 2 : 0;
583 if (c == 'g' || c == 'f') {
584 double v = va_arg(*ap, double);
585 if (pr == ~0U) pr = 6;
586 k = mg_dtoa(tmp, sizeof(tmp), v, (int) pr, c == 'g');
587 } else if (is_long == 2) {
588 int64_t v = va_arg(*ap, int64_t);
589 k = mg_lld(tmp, v, s, h);
590 } else if (is_long == 1) {
591 long v = va_arg(*ap, long);
592 k = mg_lld(tmp, s ? (int64_t) v : (int64_t) (unsigned long) v, s, h);
593 } else {
594 int v = va_arg(*ap, int);
595 k = mg_lld(tmp, s ? (int64_t) v : (int64_t) (unsigned) v, s, h);
596 }
597 for (j = 0; j < xl && w > 0; j++) w--;
598 for (j = 0; pad == ' ' && !minus && k < w && j + k < w; j++)
599 n += scpy(out, param, &pad, 1);
600 n += scpy(out, param, (char *) "0x", xl);
601 for (j = 0; pad == '0' && k < w && j + k < w; j++)
602 n += scpy(out, param, &pad, 1);
603 n += scpy(out, param, tmp, k);
604 for (j = 0; pad == ' ' && minus && k < w && j + k < w; j++)
605 n += scpy(out, param, &pad, 1);
606 } else if (c == 'm' || c == 'M') {
607 mg_pm_t f = va_arg(*ap, mg_pm_t);
608 if (c == 'm') out('"', param);
609 n += f(out, param, ap);
610 if (c == 'm') n += 2, out('"', param);
611 } else if (c == 'c') {
612 int ch = va_arg(*ap, int);
613 out((char) ch, param);
614 n++;
615 } else if (c == 's') {
616 char *p = va_arg(*ap, char *);
617 if (pr == ~0U) pr = p == NULL ? 0 : strlen(p);
618 for (j = 0; !minus && pr < w && j + pr < w; j++)
619 n += scpy(out, param, &pad, 1);
620 n += scpy(out, param, p, pr);
621 for (j = 0; minus && pr < w && j + pr < w; j++)
622 n += scpy(out, param, &pad, 1);
623 } else if (c == '%') {
624 out('%', param);
625 n++;
626 } else {
627 out('%', param);
628 out(c, param);
629 n += 2;
630 }
631 i++;
632 } else {
633 out(fmt[i], param), n++, i++;
634 }
635 }
636 return n;
637}
638
639#ifdef MG_ENABLE_LINES
640#line 1 "src/fs.c"
641#endif
642
643
644
645struct mg_fd *mg_fs_open(struct mg_fs *fs, const char *path, int flags) {
646 struct mg_fd *fd = (struct mg_fd *) calloc(1, sizeof(*fd));
647 if (fd != NULL) {
648 fd->fd = fs->op(path, flags);
649 fd->fs = fs;
650 if (fd->fd == NULL) {
651 free(fd);
652 fd = NULL;
653 }
654 }
655 return fd;
656}
657
658void mg_fs_close(struct mg_fd *fd) {
659 if (fd != NULL) {
660 fd->fs->cl(fd->fd);
661 free(fd);
662 }
663}
664
665char *mg_file_read(struct mg_fs *fs, const char *path, size_t *sizep) {
666 struct mg_fd *fd;
667 char *data = NULL;
668 size_t size = 0;
669 fs->st(path, &size, NULL);
670 if ((fd = mg_fs_open(fs, path, MG_FS_READ)) != NULL) {
671 data = (char *) calloc(1, size + 1);
672 if (data != NULL) {
673 if (fs->rd(fd->fd, data, size) != size) {
674 free(data);
675 data = NULL;
676 } else {
677 data[size] = '\0';
678 if (sizep != NULL) *sizep = size;
679 }
680 }
681 mg_fs_close(fd);
682 }
683 return data;
684}
685
686bool mg_file_write(struct mg_fs *fs, const char *path, const void *buf,
687 size_t len) {
688 bool result = false;
689 struct mg_fd *fd;
690 char tmp[MG_PATH_MAX];
691 mg_snprintf(tmp, sizeof(tmp), "%s..%d", path, rand());
692 if ((fd = mg_fs_open(fs, tmp, MG_FS_WRITE)) != NULL) {
693 result = fs->wr(fd->fd, buf, len) == len;
694 mg_fs_close(fd);
695 if (result) {
696 fs->rm(path);
697 fs->mv(tmp, path);
698 } else {
699 fs->rm(tmp);
700 }
701 }
702 return result;
703}
704
705bool mg_file_printf(struct mg_fs *fs, const char *path, const char *fmt, ...) {
706 va_list ap;
707 char *data;
708 bool result = false;
709 va_start(ap, fmt);
710 data = mg_vmprintf(fmt, &ap);
711 va_end(ap);
712 result = mg_file_write(fs, path, data, strlen(data));
713 free(data);
714 return result;
715}
716
717#ifdef MG_ENABLE_LINES
718#line 1 "src/fs_fat.c"
719#endif
720
721
722
723#if MG_ENABLE_FATFS
724#include <ff.h>
725
726static int mg_days_from_epoch(int y, int m, int d) {
727 y -= m <= 2;
728 int era = y / 400;
729 int yoe = y - era * 400;
730 int doy = (153 * (m + (m > 2 ? -3 : 9)) + 2) / 5 + d - 1;
731 int doe = yoe * 365 + yoe / 4 - yoe / 100 + doy;
732 return era * 146097 + doe - 719468;
733}
734
735static time_t mg_timegm(const struct tm *t) {
736 int year = t->tm_year + 1900;
737 int month = t->tm_mon; // 0-11
738 if (month > 11) {
739 year += month / 12;
740 month %= 12;
741 } else if (month < 0) {
742 int years_diff = (11 - month) / 12;
743 year -= years_diff;
744 month += 12 * years_diff;
745 }
746 int x = mg_days_from_epoch(year, month + 1, t->tm_mday);
747 return 60 * (60 * (24L * x + t->tm_hour) + t->tm_min) + t->tm_sec;
748}
749
750static time_t ff_time_to_epoch(uint16_t fdate, uint16_t ftime) {
751 struct tm tm;
752 memset(&tm, 0, sizeof(struct tm));
753 tm.tm_sec = (ftime << 1) & 0x3e;
754 tm.tm_min = ((ftime >> 5) & 0x3f);
755 tm.tm_hour = ((ftime >> 11) & 0x1f);
756 tm.tm_mday = (fdate & 0x1f);
757 tm.tm_mon = ((fdate >> 5) & 0x0f) - 1;
758 tm.tm_year = ((fdate >> 9) & 0x7f) + 80;
759 return mg_timegm(&tm);
760}
761
762static int ff_stat(const char *path, size_t *size, time_t *mtime) {
763 FILINFO fi;
764 if (path[0] == '\0') {
765 if (size) *size = 0;
766 if (mtime) *mtime = 0;
767 return MG_FS_DIR;
768 } else if (f_stat(path, &fi) == 0) {
769 if (size) *size = (size_t) fi.fsize;
770 if (mtime) *mtime = ff_time_to_epoch(fi.fdate, fi.ftime);
771 return MG_FS_READ | MG_FS_WRITE | ((fi.fattrib & AM_DIR) ? MG_FS_DIR : 0);
772 } else {
773 return 0;
774 }
775}
776
777static void ff_list(const char *dir, void (*fn)(const char *, void *),
778 void *userdata) {
779 DIR d;
780 FILINFO fi;
781 if (f_opendir(&d, dir) == FR_OK) {
782 while (f_readdir(&d, &fi) == FR_OK && fi.fname[0] != '\0') {
783 if (!strcmp(fi.fname, ".") || !strcmp(fi.fname, "..")) continue;
784 fn(fi.fname, userdata);
785 }
786 f_closedir(&d);
787 }
788}
789
790static void *ff_open(const char *path, int flags) {
791 FIL f;
792 unsigned char mode = FA_READ;
793 if (flags & MG_FS_WRITE) mode |= FA_WRITE | FA_OPEN_ALWAYS | FA_OPEN_APPEND;
794 if (f_open(&f, path, mode) == 0) {
795 FIL *fp;
796 if ((fp = calloc(1, sizeof(*fp))) != NULL) {
797 memcpy(fp, &f, sizeof(*fp));
798 return fp;
799 }
800 }
801 return NULL;
802}
803
804static void ff_close(void *fp) {
805 if (fp != NULL) {
806 f_close((FIL *) fp);
807 free(fp);
808 }
809}
810
811static size_t ff_read(void *fp, void *buf, size_t len) {
812 UINT n = 0, misalign = ((size_t) buf) & 3;
813 if (misalign) {
814 char aligned[4];
815 f_read((FIL *) fp, aligned, len > misalign ? misalign : len, &n);
816 memcpy(buf, aligned, n);
817 } else {
818 f_read((FIL *) fp, buf, len, &n);
819 }
820 return n;
821}
822
823static size_t ff_write(void *fp, const void *buf, size_t len) {
824 UINT n = 0;
825 return f_write((FIL *) fp, (char *) buf, len, &n) == FR_OK ? n : 0;
826}
827
828static size_t ff_seek(void *fp, size_t offset) {
829 f_lseek((FIL *) fp, offset);
830 return offset;
831}
832
833static bool ff_rename(const char *from, const char *to) {
834 return f_rename(from, to) == FR_OK;
835}
836
837static bool ff_remove(const char *path) {
838 return f_unlink(path) == FR_OK;
839}
840
841static bool ff_mkdir(const char *path) {
842 return f_mkdir(path) == FR_OK;
843}
844
845struct mg_fs mg_fs_fat = {ff_stat, ff_list, ff_open, ff_close, ff_read,
846 ff_write, ff_seek, ff_rename, ff_remove, ff_mkdir};
847#endif
848
849#ifdef MG_ENABLE_LINES
850#line 1 "src/fs_packed.c"
851#endif
852
853
854
855
856struct packed_file {
857 const char *data;
858 size_t size;
859 size_t pos;
860};
861
862const char *mg_unpack(const char *path, size_t *size, time_t *mtime);
863const char *mg_unlist(size_t no);
864
865#if MG_ENABLE_PACKED_FS
866#else
867const char *mg_unpack(const char *path, size_t *size, time_t *mtime) {
868 (void) path, (void) size, (void) mtime;
869 return NULL;
870}
871const char *mg_unlist(size_t no) {
872 (void) no;
873 return NULL;
874}
875#endif
876
877static int is_dir_prefix(const char *prefix, size_t n, const char *path) {
878 // MG_INFO(("[%.*s] [%s] %c", (int) n, prefix, path, path[n]));
879 return n < strlen(path) && strncmp(prefix, path, n) == 0 &&
880 (n == 0 || path[n] == '/' || path[n - 1] == '/');
881}
882
883static int packed_stat(const char *path, size_t *size, time_t *mtime) {
884 const char *p;
885 size_t i, n = strlen(path);
886 if (mg_unpack(path, size, mtime)) return MG_FS_READ; // Regular file
887 // Scan all files. If `path` is a dir prefix for any of them, it's a dir
888 for (i = 0; (p = mg_unlist(i)) != NULL; i++) {
889 if (is_dir_prefix(path, n, p)) return MG_FS_DIR;
890 }
891 return 0;
892}
893
894static void packed_list(const char *dir, void (*fn)(const char *, void *),
895 void *userdata) {
896 char buf[MG_PATH_MAX], tmp[sizeof(buf)];
897 const char *path, *begin, *end;
898 size_t i, n = strlen(dir);
899 tmp[0] = '\0'; // Previously listed entry
900 for (i = 0; (path = mg_unlist(i)) != NULL; i++) {
901 if (!is_dir_prefix(dir, n, path)) continue;
902 begin = &path[n + 1];
903 end = strchr(begin, '/');
904 if (end == NULL) end = begin + strlen(begin);
905 mg_snprintf(buf, sizeof(buf), "%.*s", (int) (end - begin), begin);
906 buf[sizeof(buf) - 1] = '\0';
907 // If this entry has been already listed, skip
908 // NOTE: we're assuming that file list is sorted alphabetically
909 if (strcmp(buf, tmp) == 0) continue;
910 fn(buf, userdata); // Not yet listed, call user function
911 strcpy(tmp, buf); // And save this entry as listed
912 }
913}
914
915static void *packed_open(const char *path, int flags) {
916 size_t size = 0;
917 const char *data = mg_unpack(path, &size, NULL);
918 struct packed_file *fp = NULL;
919 if (data == NULL) return NULL;
920 if (flags & MG_FS_WRITE) return NULL;
921 if ((fp = (struct packed_file *) calloc(1, sizeof(*fp))) != NULL) {
922 fp->size = size;
923 fp->data = data;
924 }
925 return (void *) fp;
926}
927
928static void packed_close(void *fp) {
929 if (fp != NULL) free(fp);
930}
931
932static size_t packed_read(void *fd, void *buf, size_t len) {
933 struct packed_file *fp = (struct packed_file *) fd;
934 if (fp->pos + len > fp->size) len = fp->size - fp->pos;
935 memcpy(buf, &fp->data[fp->pos], len);
936 fp->pos += len;
937 return len;
938}
939
940static size_t packed_write(void *fd, const void *buf, size_t len) {
941 (void) fd, (void) buf, (void) len;
942 return 0;
943}
944
945static size_t packed_seek(void *fd, size_t offset) {
946 struct packed_file *fp = (struct packed_file *) fd;
947 fp->pos = offset;
948 if (fp->pos > fp->size) fp->pos = fp->size;
949 return fp->pos;
950}
951
952static bool packed_rename(const char *from, const char *to) {
953 (void) from, (void) to;
954 return false;
955}
956
957static bool packed_remove(const char *path) {
958 (void) path;
959 return false;
960}
961
962static bool packed_mkdir(const char *path) {
963 (void) path;
964 return false;
965}
966
967struct mg_fs mg_fs_packed = {
968 packed_stat, packed_list, packed_open, packed_close, packed_read,
969 packed_write, packed_seek, packed_rename, packed_remove, packed_mkdir};
970
971#ifdef MG_ENABLE_LINES
972#line 1 "src/fs_posix.c"
973#endif
974
975
976#if MG_ENABLE_FILE
977
978#ifndef MG_STAT_STRUCT
979#define MG_STAT_STRUCT stat
980#endif
981
982#ifndef MG_STAT_FUNC
983#define MG_STAT_FUNC stat
984#endif
985
986static int p_stat(const char *path, size_t *size, time_t *mtime) {
987#if !defined(S_ISDIR)
988 MG_ERROR(("stat() API is not supported. %p %p %p", path, size, mtime));
989 return 0;
990#else
991#if MG_ARCH == MG_ARCH_WIN32
992 struct _stati64 st;
993 wchar_t tmp[MG_PATH_MAX];
994 MultiByteToWideChar(CP_UTF8, 0, path, -1, tmp, sizeof(tmp) / sizeof(tmp[0]));
995 if (_wstati64(tmp, &st) != 0) return 0;
996 // If path is a symlink, windows reports 0 in st.st_size.
997 // Get a real file size by opening it and jumping to the end
998 if (st.st_size == 0 && (st.st_mode & _S_IFREG)) {
999 FILE *fp = _wfopen(tmp, L"rb");
1000 if (fp != NULL) {
1001 fseek(fp, 0, SEEK_END);
1002 if (ftell(fp) > 0) st.st_size = ftell(fp); // Use _ftelli64 on win10+
1003 fclose(fp);
1004 }
1005 }
1006#else
1007 struct MG_STAT_STRUCT st;
1008 if (MG_STAT_FUNC(path, &st) != 0) return 0;
1009#endif
1010 if (size) *size = (size_t) st.st_size;
1011 if (mtime) *mtime = st.st_mtime;
1012 return MG_FS_READ | MG_FS_WRITE | (S_ISDIR(st.st_mode) ? MG_FS_DIR : 0);
1013#endif
1014}
1015
1016#if MG_ARCH == MG_ARCH_WIN32
1017struct dirent {
1018 char d_name[MAX_PATH];
1019};
1020
1021typedef struct win32_dir {
1022 HANDLE handle;
1023 WIN32_FIND_DATAW info;
1024 struct dirent result;
1025} DIR;
1026
1027int gettimeofday(struct timeval *tv, void *tz) {
1028 FILETIME ft;
1029 unsigned __int64 tmpres = 0;
1030
1031 if (tv != NULL) {
1032 GetSystemTimeAsFileTime(&ft);
1033 tmpres |= ft.dwHighDateTime;
1034 tmpres <<= 32;
1035 tmpres |= ft.dwLowDateTime;
1036 tmpres /= 10; // convert into microseconds
1037 tmpres -= (int64_t) 11644473600000000;
1038 tv->tv_sec = (long) (tmpres / 1000000UL);
1039 tv->tv_usec = (long) (tmpres % 1000000UL);
1040 }
1041 (void) tz;
1042 return 0;
1043}
1044
1045static int to_wchar(const char *path, wchar_t *wbuf, size_t wbuf_len) {
1046 int ret;
1047 char buf[MAX_PATH * 2], buf2[MAX_PATH * 2], *p;
1048 strncpy(buf, path, sizeof(buf));
1049 buf[sizeof(buf) - 1] = '\0';
1050 // Trim trailing slashes. Leave backslash for paths like "X:\"
1051 p = buf + strlen(buf) - 1;
1052 while (p > buf && p[-1] != ':' && (p[0] == '\\' || p[0] == '/')) *p-- = '\0';
1053 memset(wbuf, 0, wbuf_len * sizeof(wchar_t));
1054 ret = MultiByteToWideChar(CP_UTF8, 0, buf, -1, wbuf, (int) wbuf_len);
1055 // Convert back to Unicode. If doubly-converted string does not match the
1056 // original, something is fishy, reject.
1057 WideCharToMultiByte(CP_UTF8, 0, wbuf, (int) wbuf_len, buf2, sizeof(buf2),
1058 NULL, NULL);
1059 if (strcmp(buf, buf2) != 0) {
1060 wbuf[0] = L'\0';
1061 ret = 0;
1062 }
1063 return ret;
1064}
1065
1066DIR *opendir(const char *name) {
1067 DIR *d = NULL;
1068 wchar_t wpath[MAX_PATH];
1069 DWORD attrs;
1070
1071 if (name == NULL) {
1072 SetLastError(ERROR_BAD_ARGUMENTS);
1073 } else if ((d = (DIR *) calloc(1, sizeof(*d))) == NULL) {
1074 SetLastError(ERROR_NOT_ENOUGH_MEMORY);
1075 } else {
1076 to_wchar(name, wpath, sizeof(wpath) / sizeof(wpath[0]));
1077 attrs = GetFileAttributesW(wpath);
1078 if (attrs != 0Xffffffff && (attrs & FILE_ATTRIBUTE_DIRECTORY)) {
1079 (void) wcscat(wpath, L"\\*");
1080 d->handle = FindFirstFileW(wpath, &d->info);
1081 d->result.d_name[0] = '\0';
1082 } else {
1083 free(d);
1084 d = NULL;
1085 }
1086 }
1087 return d;
1088}
1089
1090int closedir(DIR *d) {
1091 int result = 0;
1092 if (d != NULL) {
1093 if (d->handle != INVALID_HANDLE_VALUE)
1094 result = FindClose(d->handle) ? 0 : -1;
1095 free(d);
1096 } else {
1097 result = -1;
1098 SetLastError(ERROR_BAD_ARGUMENTS);
1099 }
1100 return result;
1101}
1102
1103struct dirent *readdir(DIR *d) {
1104 struct dirent *result = NULL;
1105 if (d != NULL) {
1106 memset(&d->result, 0, sizeof(d->result));
1107 if (d->handle != INVALID_HANDLE_VALUE) {
1108 result = &d->result;
1109 WideCharToMultiByte(CP_UTF8, 0, d->info.cFileName, -1, result->d_name,
1110 sizeof(result->d_name), NULL, NULL);
1111 if (!FindNextFileW(d->handle, &d->info)) {
1112 FindClose(d->handle);
1113 d->handle = INVALID_HANDLE_VALUE;
1114 }
1115 } else {
1116 SetLastError(ERROR_FILE_NOT_FOUND);
1117 }
1118 } else {
1119 SetLastError(ERROR_BAD_ARGUMENTS);
1120 }
1121 return result;
1122}
1123#endif
1124
1125static void p_list(const char *dir, void (*fn)(const char *, void *),
1126 void *userdata) {
1127#if MG_ENABLE_DIRLIST
1128 struct dirent *dp;
1129 DIR *dirp;
1130 if ((dirp = (opendir(dir))) == NULL) return;
1131 while ((dp = readdir(dirp)) != NULL) {
1132 if (!strcmp(dp->d_name, ".") || !strcmp(dp->d_name, "..")) continue;
1133 fn(dp->d_name, userdata);
1134 }
1135 closedir(dirp);
1136#else
1137 (void) dir, (void) fn, (void) userdata;
1138#endif
1139}
1140
1141static void *p_open(const char *path, int flags) {
1142 const char *mode = flags == MG_FS_READ ? "rb" : "a+b";
1143#if MG_ARCH == MG_ARCH_WIN32
1144 wchar_t b1[MG_PATH_MAX], b2[10];
1145 MultiByteToWideChar(CP_UTF8, 0, path, -1, b1, sizeof(b1) / sizeof(b1[0]));
1146 MultiByteToWideChar(CP_UTF8, 0, mode, -1, b2, sizeof(b2) / sizeof(b2[0]));
1147 return (void *) _wfopen(b1, b2);
1148#else
1149 return (void *) fopen(path, mode);
1150#endif
1151}
1152
1153static void p_close(void *fp) {
1154 fclose((FILE *) fp);
1155}
1156
1157static size_t p_read(void *fp, void *buf, size_t len) {
1158 return fread(buf, 1, len, (FILE *) fp);
1159}
1160
1161static size_t p_write(void *fp, const void *buf, size_t len) {
1162 return fwrite(buf, 1, len, (FILE *) fp);
1163}
1164
1165static size_t p_seek(void *fp, size_t offset) {
1166#if (defined(_FILE_OFFSET_BITS) && _FILE_OFFSET_BITS == 64) || \
1167 (defined(_POSIX_C_SOURCE) && _POSIX_C_SOURCE >= 200112L) || \
1168 (defined(_XOPEN_SOURCE) && _XOPEN_SOURCE >= 600)
1169 if (fseeko((FILE *) fp, (off_t) offset, SEEK_SET) != 0) (void) 0;
1170#else
1171 if (fseek((FILE *) fp, (long) offset, SEEK_SET) != 0) (void) 0;
1172#endif
1173 return (size_t) ftell((FILE *) fp);
1174}
1175
1176static bool p_rename(const char *from, const char *to) {
1177 return rename(from, to) == 0;
1178}
1179
1180static bool p_remove(const char *path) {
1181 return remove(path) == 0;
1182}
1183
1184static bool p_mkdir(const char *path) {
1185 return mkdir(path, 0775) == 0;
1186}
1187
1188#else
1189
1190static int p_stat(const char *path, size_t *size, time_t *mtime) {
1191 (void) path, (void) size, (void) mtime;
1192 return 0;
1193}
1194static void p_list(const char *path, void (*fn)(const char *, void *),
1195 void *userdata) {
1196 (void) path, (void) fn, (void) userdata;
1197}
1198static void *p_open(const char *path, int flags) {
1199 (void) path, (void) flags;
1200 return NULL;
1201}
1202static void p_close(void *fp) {
1203 (void) fp;
1204}
1205static size_t p_read(void *fd, void *buf, size_t len) {
1206 (void) fd, (void) buf, (void) len;
1207 return 0;
1208}
1209static size_t p_write(void *fd, const void *buf, size_t len) {
1210 (void) fd, (void) buf, (void) len;
1211 return 0;
1212}
1213static size_t p_seek(void *fd, size_t offset) {
1214 (void) fd, (void) offset;
1215 return (size_t) ~0;
1216}
1217static bool p_rename(const char *from, const char *to) {
1218 (void) from, (void) to;
1219 return false;
1220}
1221static bool p_remove(const char *path) {
1222 (void) path;
1223 return false;
1224}
1225static bool p_mkdir(const char *path) {
1226 (void) path;
1227 return false;
1228}
1229#endif
1230
1231struct mg_fs mg_fs_posix = {p_stat, p_list, p_open, p_close, p_read,
1232 p_write, p_seek, p_rename, p_remove, p_mkdir};
1233
1234#ifdef MG_ENABLE_LINES
1235#line 1 "src/http.c"
1236#endif
1237
1238
1239
1240
1241
1242
1243
1244
1245
1246
1247
1248
1249
1250bool mg_to_size_t(struct mg_str str, size_t *val);
1251bool mg_to_size_t(struct mg_str str, size_t *val) {
1252 uint64_t result = 0, max = 1844674407370955160 /* (UINT64_MAX-9)/10 */;
1253 size_t i = 0;
1254 while (i < str.len && (str.ptr[i] == ' ' || str.ptr[i] == '\t')) i++;
1255 if (i < str.len && str.ptr[i] == '-') return false;
1256 while (i < str.len && str.ptr[i] >= '0' && str.ptr[i] <= '9') {
1257 if (result > max) return false;
1258 result *= 10;
1259 result += (unsigned) (str.ptr[i] - '0');
1260 i++;
1261 }
1262 *val = (size_t) result;
1263 return true;
1264}
1265
1266// Chunk deletion marker is the MSB in the "processed" counter
1267#define MG_DMARK ((size_t) 1 << (sizeof(size_t) * 8 - 1))
1268
1269// Multipart POST example:
1270// --xyz
1271// Content-Disposition: form-data; name="val"
1272//
1273// abcdef
1274// --xyz
1275// Content-Disposition: form-data; name="foo"; filename="a.txt"
1276// Content-Type: text/plain
1277//
1278// hello world
1279//
1280// --xyz--
1281size_t mg_http_next_multipart(struct mg_str body, size_t ofs,
1282 struct mg_http_part *part) {
1283 struct mg_str cd = mg_str_n("Content-Disposition", 19);
1284 const char *s = body.ptr;
1285 size_t b = ofs, h1, h2, b1, b2, max = body.len;
1286
1287 // Init part params
1288 if (part != NULL) part->name = part->filename = part->body = mg_str_n(0, 0);
1289
1290 // Skip boundary
1291 while (b + 2 < max && s[b] != '\r' && s[b + 1] != '\n') b++;
1292 if (b <= ofs || b + 2 >= max) return 0;
1293 // MG_INFO(("B: %zu %zu [%.*s]", ofs, b - ofs, (int) (b - ofs), s));
1294
1295 // Skip headers
1296 h1 = h2 = b + 2;
1297 for (;;) {
1298 while (h2 + 2 < max && s[h2] != '\r' && s[h2 + 1] != '\n') h2++;
1299 if (h2 == h1) break;
1300 if (h2 + 2 >= max) return 0;
1301 // MG_INFO(("Header: [%.*s]", (int) (h2 - h1), &s[h1]));
1302 if (part != NULL && h1 + cd.len + 2 < h2 && s[h1 + cd.len] == ':' &&
1303 mg_ncasecmp(&s[h1], cd.ptr, cd.len) == 0) {
1304 struct mg_str v = mg_str_n(&s[h1 + cd.len + 2], h2 - (h1 + cd.len + 2));
1305 part->name = mg_http_get_header_var(v, mg_str_n("name", 4));
1306 part->filename = mg_http_get_header_var(v, mg_str_n("filename", 8));
1307 }
1308 h1 = h2 = h2 + 2;
1309 }
1310 b1 = b2 = h2 + 2;
1311 while (b2 + 2 + (b - ofs) + 2 < max && !(s[b2] == '\r' && s[b2 + 1] == '\n' &&
1312 memcmp(&s[b2 + 2], s, b - ofs) == 0))
1313 b2++;
1314
1315 if (b2 + 2 >= max) return 0;
1316 if (part != NULL) part->body = mg_str_n(&s[b1], b2 - b1);
1317 // MG_INFO(("Body: [%.*s]", (int) (b2 - b1), &s[b1]));
1318 return b2 + 2;
1319}
1320
1321void mg_http_bauth(struct mg_connection *c, const char *user,
1322 const char *pass) {
1323 struct mg_str u = mg_str(user), p = mg_str(pass);
1324 size_t need = c->send.len + 36 + (u.len + p.len) * 2;
1325 if (c->send.size < need) mg_iobuf_resize(&c->send, need);
1326 if (c->send.size >= need) {
1327 int i, n = 0;
1328 char *buf = (char *) &c->send.buf[c->send.len];
1329 memcpy(buf, "Authorization: Basic ", 21); // DON'T use mg_send!
1330 for (i = 0; i < (int) u.len; i++) {
1331 n = mg_base64_update(((unsigned char *) u.ptr)[i], buf + 21, n);
1332 }
1333 if (p.len > 0) {
1334 n = mg_base64_update(':', buf + 21, n);
1335 for (i = 0; i < (int) p.len; i++) {
1336 n = mg_base64_update(((unsigned char *) p.ptr)[i], buf + 21, n);
1337 }
1338 }
1339 n = mg_base64_final(buf + 21, n);
1340 c->send.len += 21 + (size_t) n + 2;
1341 memcpy(&c->send.buf[c->send.len - 2], "\r\n", 2);
1342 } else {
1343 MG_ERROR(("%lu oom %d->%d ", c->id, (int) c->send.size, (int) need));
1344 }
1345}
1346
1347struct mg_str mg_http_var(struct mg_str buf, struct mg_str name) {
1348 struct mg_str k, v, result = mg_str_n(NULL, 0);
1349 while (mg_split(&buf, &k, &v, '&')) {
1350 if (name.len == k.len && mg_ncasecmp(name.ptr, k.ptr, k.len) == 0) {
1351 result = v;
1352 break;
1353 }
1354 }
1355 return result;
1356}
1357
1358int mg_http_get_var(const struct mg_str *buf, const char *name, char *dst,
1359 size_t dst_len) {
1360 int len;
1361 if (dst == NULL || dst_len == 0) {
1362 len = -2; // Bad destination
1363 } else if (buf->ptr == NULL || name == NULL || buf->len == 0) {
1364 len = -1; // Bad source
1365 dst[0] = '\0';
1366 } else {
1367 struct mg_str v = mg_http_var(*buf, mg_str(name));
1368 if (v.ptr == NULL) {
1369 len = -4; // Name does not exist
1370 } else {
1371 len = mg_url_decode(v.ptr, v.len, dst, dst_len, 1);
1372 if (len < 0) len = -3; // Failed to decode
1373 }
1374 }
1375 return len;
1376}
1377
1378static bool isx(int c) {
1379 return (c >= '0' && c <= '9') || (c >= 'a' && c <= 'f') ||
1380 (c >= 'A' && c <= 'F');
1381}
1382
1383int mg_url_decode(const char *src, size_t src_len, char *dst, size_t dst_len,
1384 int is_form_url_encoded) {
1385 size_t i, j;
1386 for (i = j = 0; i < src_len && j + 1 < dst_len; i++, j++) {
1387 if (src[i] == '%') {
1388 // Use `i + 2 < src_len`, not `i < src_len - 2`, note small src_len
1389 if (i + 2 < src_len && isx(src[i + 1]) && isx(src[i + 2])) {
1390 mg_unhex(src + i + 1, 2, (uint8_t *) &dst[j]);
1391 i += 2;
1392 } else {
1393 return -1;
1394 }
1395 } else if (is_form_url_encoded && src[i] == '+') {
1396 dst[j] = ' ';
1397 } else {
1398 dst[j] = src[i];
1399 }
1400 }
1401 if (j < dst_len) dst[j] = '\0'; // Null-terminate the destination
1402 return i >= src_len && j < dst_len ? (int) j : -1;
1403}
1404
1405static bool isok(uint8_t c) {
1406 return c == '\n' || c == '\r' || c >= ' ';
1407}
1408
1409int mg_http_get_request_len(const unsigned char *buf, size_t buf_len) {
1410 size_t i;
1411 for (i = 0; i < buf_len; i++) {
1412 if (!isok(buf[i])) return -1;
1413 if ((i > 0 && buf[i] == '\n' && buf[i - 1] == '\n') ||
1414 (i > 3 && buf[i] == '\n' && buf[i - 1] == '\r' && buf[i - 2] == '\n'))
1415 return (int) i + 1;
1416 }
1417 return 0;
1418}
1419
1420static const char *skip(const char *s, const char *e, const char *d,
1421 struct mg_str *v) {
1422 v->ptr = s;
1423 while (s < e && *s != '\n' && strchr(d, *s) == NULL) s++;
1424 v->len = (size_t) (s - v->ptr);
1425 while (s < e && strchr(d, *s) != NULL) s++;
1426 return s;
1427}
1428
1429struct mg_str *mg_http_get_header(struct mg_http_message *h, const char *name) {
1430 size_t i, n = strlen(name), max = sizeof(h->headers) / sizeof(h->headers[0]);
1431 for (i = 0; i < max && h->headers[i].name.len > 0; i++) {
1432 struct mg_str *k = &h->headers[i].name, *v = &h->headers[i].value;
1433 if (n == k->len && mg_ncasecmp(k->ptr, name, n) == 0) return v;
1434 }
1435 return NULL;
1436}
1437
1438static bool mg_http_parse_headers(const char *s, const char *end,
1439 struct mg_http_header *h, int max_headers) {
1440 int i;
1441 for (i = 0; i < max_headers; i++) {
1442 struct mg_str k, v, tmp;
1443 const char *he = skip(s, end, "\r\n", &tmp);
1444 if (tmp.len == 0) break; // empty header = EOH
1445 s = skip(s, he, ": \r\n", &k);
1446 s = skip(s, he, "\r\n", &v);
1447 if (k.len == tmp.len) continue;
1448 while (v.len > 0 && v.ptr[v.len - 1] == ' ') v.len--; // Trim spaces
1449 if (k.len == 0) return false; // empty name
1450 // MG_INFO(("--HH [%.*s] [%.*s] [%.*s]", (int) tmp.len - 1, tmp.ptr,
1451 //(int) k.len, k.ptr, (int) v.len, v.ptr));
1452 h[i].name = k;
1453 h[i].value = v;
1454 }
1455 return true;
1456}
1457
1458int mg_http_parse(const char *s, size_t len, struct mg_http_message *hm) {
1459 int is_response, req_len = mg_http_get_request_len((unsigned char *) s, len);
1460 const char *end = s == NULL ? NULL : s + req_len, *qs; // Cannot add to NULL
1461 struct mg_str *cl;
1462
1463 memset(hm, 0, sizeof(*hm));
1464 if (req_len <= 0) return req_len;
1465
1466 hm->message.ptr = hm->head.ptr = s;
1467 hm->body.ptr = end;
1468 hm->head.len = (size_t) req_len;
1469 hm->chunk.ptr = end;
1470 hm->message.len = hm->body.len = (size_t) ~0; // Set body length to infinite
1471
1472 // Parse request line
1473 s = skip(s, end, " ", &hm->method);
1474 s = skip(s, end, " ", &hm->uri);
1475 s = skip(s, end, "\r\n", &hm->proto);
1476
1477 // Sanity check. Allow protocol/reason to be empty
1478 if (hm->method.len == 0 || hm->uri.len == 0) return -1;
1479
1480 // If URI contains '?' character, setup query string
1481 if ((qs = (const char *) memchr(hm->uri.ptr, '?', hm->uri.len)) != NULL) {
1482 hm->query.ptr = qs + 1;
1483 hm->query.len = (size_t) (&hm->uri.ptr[hm->uri.len] - (qs + 1));
1484 hm->uri.len = (size_t) (qs - hm->uri.ptr);
1485 }
1486
1487 if (!mg_http_parse_headers(s, end, hm->headers,
1488 sizeof(hm->headers) / sizeof(hm->headers[0])))
1489 return -1; // error when parsing
1490 if ((cl = mg_http_get_header(hm, "Content-Length")) != NULL) {
1491 if (mg_to_size_t(*cl, &hm->body.len) == false) return -1;
1492 hm->message.len = (size_t) req_len + hm->body.len;
1493 }
1494
1495 // mg_http_parse() is used to parse both HTTP requests and HTTP
1496 // responses. If HTTP response does not have Content-Length set, then
1497 // body is read until socket is closed, i.e. body.len is infinite (~0).
1498 //
1499 // For HTTP requests though, according to
1500 // http://tools.ietf.org/html/rfc7231#section-8.1.3,
1501 // only POST and PUT methods have defined body semantics.
1502 // Therefore, if Content-Length is not specified and methods are
1503 // not one of PUT or POST, set body length to 0.
1504 //
1505 // So, if it is HTTP request, and Content-Length is not set,
1506 // and method is not (PUT or POST) then reset body length to zero.
1507 is_response = mg_ncasecmp(hm->method.ptr, "HTTP/", 5) == 0;
1508 if (hm->body.len == (size_t) ~0 && !is_response &&
1509 mg_vcasecmp(&hm->method, "PUT") != 0 &&
1510 mg_vcasecmp(&hm->method, "POST") != 0) {
1511 hm->body.len = 0;
1512 hm->message.len = (size_t) req_len;
1513 }
1514
1515 // The 204 (No content) responses also have 0 body length
1516 if (hm->body.len == (size_t) ~0 && is_response &&
1517 mg_vcasecmp(&hm->uri, "204") == 0) {
1518 hm->body.len = 0;
1519 hm->message.len = (size_t) req_len;
1520 }
1521
1522 return req_len;
1523}
1524
1525static void mg_http_vprintf_chunk(struct mg_connection *c, const char *fmt,
1526 va_list *ap) {
1527 size_t len = c->send.len;
1528 mg_send(c, " \r\n", 10);
1529 mg_vxprintf(mg_pfn_iobuf, &c->send, fmt, ap);
1530 if (c->send.len >= len + 10) {
1531 mg_snprintf((char *) c->send.buf + len, 9, "%08lx", c->send.len - len - 10);
1532 c->send.buf[len + 8] = '\r';
1533 if (c->send.len == len + 10) c->is_resp = 0; // Last chunk, reset marker
1534 }
1535 mg_send(c, "\r\n", 2);
1536}
1537
1538void mg_http_printf_chunk(struct mg_connection *c, const char *fmt, ...) {
1539 va_list ap;
1540 va_start(ap, fmt);
1541 mg_http_vprintf_chunk(c, fmt, &ap);
1542 va_end(ap);
1543}
1544
1545void mg_http_write_chunk(struct mg_connection *c, const char *buf, size_t len) {
1546 mg_printf(c, "%lx\r\n", (unsigned long) len);
1547 mg_send(c, buf, len);
1548 mg_send(c, "\r\n", 2);
1549 if (len == 0) c->is_resp = 0;
1550}
1551
1552// clang-format off
1553static const char *mg_http_status_code_str(int status_code) {
1554 switch (status_code) {
1555 case 100: return "Continue";
1556 case 101: return "Switching Protocols";
1557 case 102: return "Processing";
1558 case 200: return "OK";
1559 case 201: return "Created";
1560 case 202: return "Accepted";
1561 case 203: return "Non-authoritative Information";
1562 case 204: return "No Content";
1563 case 205: return "Reset Content";
1564 case 206: return "Partial Content";
1565 case 207: return "Multi-Status";
1566 case 208: return "Already Reported";
1567 case 226: return "IM Used";
1568 case 300: return "Multiple Choices";
1569 case 301: return "Moved Permanently";
1570 case 302: return "Found";
1571 case 303: return "See Other";
1572 case 304: return "Not Modified";
1573 case 305: return "Use Proxy";
1574 case 307: return "Temporary Redirect";
1575 case 308: return "Permanent Redirect";
1576 case 400: return "Bad Request";
1577 case 401: return "Unauthorized";
1578 case 402: return "Payment Required";
1579 case 403: return "Forbidden";
1580 case 404: return "Not Found";
1581 case 405: return "Method Not Allowed";
1582 case 406: return "Not Acceptable";
1583 case 407: return "Proxy Authentication Required";
1584 case 408: return "Request Timeout";
1585 case 409: return "Conflict";
1586 case 410: return "Gone";
1587 case 411: return "Length Required";
1588 case 412: return "Precondition Failed";
1589 case 413: return "Payload Too Large";
1590 case 414: return "Request-URI Too Long";
1591 case 415: return "Unsupported Media Type";
1592 case 416: return "Requested Range Not Satisfiable";
1593 case 417: return "Expectation Failed";
1594 case 418: return "I'm a teapot";
1595 case 421: return "Misdirected Request";
1596 case 422: return "Unprocessable Entity";
1597 case 423: return "Locked";
1598 case 424: return "Failed Dependency";
1599 case 426: return "Upgrade Required";
1600 case 428: return "Precondition Required";
1601 case 429: return "Too Many Requests";
1602 case 431: return "Request Header Fields Too Large";
1603 case 444: return "Connection Closed Without Response";
1604 case 451: return "Unavailable For Legal Reasons";
1605 case 499: return "Client Closed Request";
1606 case 500: return "Internal Server Error";
1607 case 501: return "Not Implemented";
1608 case 502: return "Bad Gateway";
1609 case 503: return "Service Unavailable";
1610 case 504: return "Gateway Timeout";
1611 case 505: return "HTTP Version Not Supported";
1612 case 506: return "Variant Also Negotiates";
1613 case 507: return "Insufficient Storage";
1614 case 508: return "Loop Detected";
1615 case 510: return "Not Extended";
1616 case 511: return "Network Authentication Required";
1617 case 599: return "Network Connect Timeout Error";
1618 default: return "";
1619 }
1620}
1621// clang-format on
1622
1623void mg_http_reply(struct mg_connection *c, int code, const char *headers,
1624 const char *fmt, ...) {
1625 va_list ap;
1626 size_t len;
1627 mg_printf(c, "HTTP/1.1 %d %s\r\n%sContent-Length: \r\n\r\n", code,
1628 mg_http_status_code_str(code), headers == NULL ? "" : headers);
1629 len = c->send.len;
1630 va_start(ap, fmt);
1631 mg_vxprintf(mg_pfn_iobuf, &c->send, fmt, &ap);
1632 va_end(ap);
1633 if (c->send.len > 16) {
1634 size_t n = mg_snprintf((char *) &c->send.buf[len - 15], 11, "%-10lu",
1635 (unsigned long) (c->send.len - len));
1636 c->send.buf[len - 15 + n] = ' '; // Change ending 0 to space
1637 }
1638 c->is_resp = 0;
1639}
1640
1641static void http_cb(struct mg_connection *, int, void *, void *);
1642static void restore_http_cb(struct mg_connection *c) {
1643 mg_fs_close((struct mg_fd *) c->pfn_data);
1644 c->pfn_data = NULL;
1645 c->pfn = http_cb;
1646 c->is_resp = 0;
1647}
1648
1649char *mg_http_etag(char *buf, size_t len, size_t size, time_t mtime);
1650char *mg_http_etag(char *buf, size_t len, size_t size, time_t mtime) {
1651 mg_snprintf(buf, len, "\"%lld.%lld\"", (int64_t) mtime, (int64_t) size);
1652 return buf;
1653}
1654
1655static void static_cb(struct mg_connection *c, int ev, void *ev_data,
1656 void *fn_data) {
1657 if (ev == MG_EV_WRITE || ev == MG_EV_POLL) {
1658 struct mg_fd *fd = (struct mg_fd *) fn_data;
1659 // Read to send IO buffer directly, avoid extra on-stack buffer
1660 size_t n, max = MG_IO_SIZE, space;
1661 size_t *cl = (size_t *) &c->data[(sizeof(c->data) - sizeof(size_t)) /
1662 sizeof(size_t) * sizeof(size_t)];
1663 if (c->send.size < max) mg_iobuf_resize(&c->send, max);
1664 if (c->send.len >= c->send.size) return; // Rate limit
1665 if ((space = c->send.size - c->send.len) > *cl) space = *cl;
1666 n = fd->fs->rd(fd->fd, c->send.buf + c->send.len, space);
1667 c->send.len += n;
1668 *cl -= n;
1669 if (n == 0) restore_http_cb(c);
1670 } else if (ev == MG_EV_CLOSE) {
1671 restore_http_cb(c);
1672 }
1673 (void) ev_data;
1674}
1675
1676// Known mime types. Keep it outside guess_content_type() function, since
1677// some environments don't like it defined there.
1678// clang-format off
1679static struct mg_str s_known_types[] = {
1680 MG_C_STR("html"), MG_C_STR("text/html; charset=utf-8"),
1681 MG_C_STR("htm"), MG_C_STR("text/html; charset=utf-8"),
1682 MG_C_STR("css"), MG_C_STR("text/css; charset=utf-8"),
1683 MG_C_STR("js"), MG_C_STR("text/javascript; charset=utf-8"),
1684 MG_C_STR("gif"), MG_C_STR("image/gif"),
1685 MG_C_STR("png"), MG_C_STR("image/png"),
1686 MG_C_STR("jpg"), MG_C_STR("image/jpeg"),
1687 MG_C_STR("jpeg"), MG_C_STR("image/jpeg"),
1688 MG_C_STR("woff"), MG_C_STR("font/woff"),
1689 MG_C_STR("ttf"), MG_C_STR("font/ttf"),
1690 MG_C_STR("svg"), MG_C_STR("image/svg+xml"),
1691 MG_C_STR("txt"), MG_C_STR("text/plain; charset=utf-8"),
1692 MG_C_STR("avi"), MG_C_STR("video/x-msvideo"),
1693 MG_C_STR("csv"), MG_C_STR("text/csv"),
1694 MG_C_STR("doc"), MG_C_STR("application/msword"),
1695 MG_C_STR("exe"), MG_C_STR("application/octet-stream"),
1696 MG_C_STR("gz"), MG_C_STR("application/gzip"),
1697 MG_C_STR("ico"), MG_C_STR("image/x-icon"),
1698 MG_C_STR("json"), MG_C_STR("application/json"),
1699 MG_C_STR("mov"), MG_C_STR("video/quicktime"),
1700 MG_C_STR("mp3"), MG_C_STR("audio/mpeg"),
1701 MG_C_STR("mp4"), MG_C_STR("video/mp4"),
1702 MG_C_STR("mpeg"), MG_C_STR("video/mpeg"),
1703 MG_C_STR("pdf"), MG_C_STR("application/pdf"),
1704 MG_C_STR("shtml"), MG_C_STR("text/html; charset=utf-8"),
1705 MG_C_STR("tgz"), MG_C_STR("application/tar-gz"),
1706 MG_C_STR("wav"), MG_C_STR("audio/wav"),
1707 MG_C_STR("webp"), MG_C_STR("image/webp"),
1708 MG_C_STR("zip"), MG_C_STR("application/zip"),
1709 MG_C_STR("3gp"), MG_C_STR("video/3gpp"),
1710 {0, 0},
1711};
1712// clang-format on
1713
1714static struct mg_str guess_content_type(struct mg_str path, const char *extra) {
1715 struct mg_str k, v, s = mg_str(extra);
1716 size_t i = 0;
1717
1718 // Shrink path to its extension only
1719 while (i < path.len && path.ptr[path.len - i - 1] != '.') i++;
1720 path.ptr += path.len - i;
1721 path.len = i;
1722
1723 // Process user-provided mime type overrides, if any
1724 while (mg_commalist(&s, &k, &v)) {
1725 if (mg_strcmp(path, k) == 0) return v;
1726 }
1727
1728 // Process built-in mime types
1729 for (i = 0; s_known_types[i].ptr != NULL; i += 2) {
1730 if (mg_strcmp(path, s_known_types[i]) == 0) return s_known_types[i + 1];
1731 }
1732
1733 return mg_str("text/plain; charset=utf-8");
1734}
1735
1736static int getrange(struct mg_str *s, size_t *a, size_t *b) {
1737 size_t i, numparsed = 0;
1738 // MG_INFO(("%.*s", (int) s->len, s->ptr));
1739 for (i = 0; i + 6 < s->len; i++) {
1740 if (memcmp(&s->ptr[i], "bytes=", 6) == 0) {
1741 struct mg_str p = mg_str_n(s->ptr + i + 6, s->len - i - 6);
1742 if (p.len > 0 && p.ptr[0] >= '0' && p.ptr[0] <= '9') numparsed++;
1743 if (!mg_to_size_t(p, a)) return 0;
1744 // MG_INFO(("PPP [%.*s] %d", (int) p.len, p.ptr, numparsed));
1745 while (p.len && p.ptr[0] >= '0' && p.ptr[0] <= '9') p.ptr++, p.len--;
1746 if (p.len && p.ptr[0] == '-') p.ptr++, p.len--;
1747 if (!mg_to_size_t(p, b)) return 0;
1748 if (p.len > 0 && p.ptr[0] >= '0' && p.ptr[0] <= '9') numparsed++;
1749 // MG_INFO(("PPP [%.*s] %d", (int) p.len, p.ptr, numparsed));
1750 break;
1751 }
1752 }
1753 return (int) numparsed;
1754}
1755
1756void mg_http_serve_file(struct mg_connection *c, struct mg_http_message *hm,
1757 const char *path,
1758 const struct mg_http_serve_opts *opts) {
1759 char etag[64], tmp[MG_PATH_MAX];
1760 struct mg_fs *fs = opts->fs == NULL ? &mg_fs_posix : opts->fs;
1761 struct mg_fd *fd = NULL;
1762 size_t size = 0;
1763 time_t mtime = 0;
1764 struct mg_str *inm = NULL;
1765 struct mg_str mime = guess_content_type(mg_str(path), opts->mime_types);
1766 bool gzip = false;
1767
1768 if (path != NULL) {
1769 // If a browser sends us "Accept-Encoding: gzip", try to open .gz first
1770 struct mg_str *ae = mg_http_get_header(hm, "Accept-Encoding");
1771 if (ae != NULL && mg_strstr(*ae, mg_str("gzip")) != NULL) {
1772 mg_snprintf(tmp, sizeof(tmp), "%s.gz", path);
1773 fd = mg_fs_open(fs, tmp, MG_FS_READ);
1774 if (fd != NULL) gzip = true, path = tmp;
1775 }
1776 // No luck opening .gz? Open what we've told to open
1777 if (fd == NULL) fd = mg_fs_open(fs, path, MG_FS_READ);
1778 }
1779
1780 // Failed to open, and page404 is configured? Open it, then
1781 if (fd == NULL && opts->page404 != NULL) {
1782 fd = mg_fs_open(fs, opts->page404, MG_FS_READ);
1783 mime = guess_content_type(mg_str(path), opts->mime_types);
1784 path = opts->page404;
1785 }
1786
1787 if (fd == NULL || fs->st(path, &size, &mtime) == 0) {
1788 mg_http_reply(c, 404, opts->extra_headers, "Not found\n");
1789 mg_fs_close(fd);
1790 // NOTE: mg_http_etag() call should go first!
1791 } else if (mg_http_etag(etag, sizeof(etag), size, mtime) != NULL &&
1792 (inm = mg_http_get_header(hm, "If-None-Match")) != NULL &&
1793 mg_vcasecmp(inm, etag) == 0) {
1794 mg_fs_close(fd);
1795 mg_http_reply(c, 304, opts->extra_headers, "");
1796 } else {
1797 int n, status = 200;
1798 char range[100];
1799 size_t r1 = 0, r2 = 0, cl = size;
1800
1801 // Handle Range header
1802 struct mg_str *rh = mg_http_get_header(hm, "Range");
1803 range[0] = '\0';
1804 if (rh != NULL && (n = getrange(rh, &r1, &r2)) > 0) {
1805 // If range is specified like "400-", set second limit to content len
1806 if (n == 1) r2 = cl - 1;
1807 if (r1 > r2 || r2 >= cl) {
1808 status = 416;
1809 cl = 0;
1810 mg_snprintf(range, sizeof(range), "Content-Range: bytes */%lld\r\n",
1811 (int64_t) size);
1812 } else {
1813 status = 206;
1814 cl = r2 - r1 + 1;
1815 mg_snprintf(range, sizeof(range),
1816 "Content-Range: bytes %llu-%llu/%llu\r\n", (uint64_t) r1,
1817 (uint64_t) (r1 + cl - 1), (uint64_t) size);
1818 fs->sk(fd->fd, r1);
1819 }
1820 }
1821 mg_printf(c,
1822 "HTTP/1.1 %d %s\r\n"
1823 "Content-Type: %.*s\r\n"
1824 "Etag: %s\r\n"
1825 "Content-Length: %llu\r\n"
1826 "%s%s%s\r\n",
1827 status, mg_http_status_code_str(status), (int) mime.len, mime.ptr,
1828 etag, (uint64_t) cl, gzip ? "Content-Encoding: gzip\r\n" : "",
1829 range, opts->extra_headers ? opts->extra_headers : "");
1830 if (mg_vcasecmp(&hm->method, "HEAD") == 0) {
1831 c->is_draining = 1;
1832 c->is_resp = 0;
1833 mg_fs_close(fd);
1834 } else {
1835 // Track to-be-sent content length at the end of c->data, aligned
1836 size_t *clp = (size_t *) &c->data[(sizeof(c->data) - sizeof(size_t)) /
1837 sizeof(size_t) * sizeof(size_t)];
1838 c->pfn = static_cb;
1839 c->pfn_data = fd;
1840 *clp = cl;
1841 }
1842 }
1843}
1844
1845struct printdirentrydata {
1846 struct mg_connection *c;
1847 struct mg_http_message *hm;
1848 const struct mg_http_serve_opts *opts;
1849 const char *dir;
1850};
1851
1852static void printdirentry(const char *name, void *userdata) {
1853 struct printdirentrydata *d = (struct printdirentrydata *) userdata;
1854 struct mg_fs *fs = d->opts->fs == NULL ? &mg_fs_posix : d->opts->fs;
1855 size_t size = 0;
1856 time_t t = 0;
1857 char path[MG_PATH_MAX], sz[40], mod[40];
1858 int flags, n = 0;
1859
1860 // MG_DEBUG(("[%s] [%s]", d->dir, name));
1861 if (mg_snprintf(path, sizeof(path), "%s%c%s", d->dir, '/', name) >
1862 sizeof(path)) {
1863 MG_ERROR(("%s truncated", name));
1864 } else if ((flags = fs->st(path, &size, &t)) == 0) {
1865 MG_ERROR(("%lu stat(%s): %d", d->c->id, path, errno));
1866 } else {
1867 const char *slash = flags & MG_FS_DIR ? "/" : "";
1868 if (flags & MG_FS_DIR) {
1869 mg_snprintf(sz, sizeof(sz), "%s", "[DIR]");
1870 } else {
1871 mg_snprintf(sz, sizeof(sz), "%lld", (uint64_t) size);
1872 }
1873#if defined(MG_HTTP_DIRLIST_TIME_FMT)
1874 {
1875 char time_str[40];
1876 struct tm *time_info = localtime(&t);
1877 strftime(time_str, sizeof time_str, "%Y/%m/%d %H:%M:%S", time_info);
1878 mg_snprintf(mod, sizeof(mod), "%s", time_str);
1879 }
1880#else
1881 mg_snprintf(mod, sizeof(mod), "%lu", (unsigned long) t);
1882#endif
1883 n = (int) mg_url_encode(name, strlen(name), path, sizeof(path));
1884 mg_printf(d->c,
1885 " <tr><td><a href=\"%.*s%s\">%s%s</a></td>"
1886 "<td name=%lu>%s</td><td name=%lld>%s</td></tr>\n",
1887 n, path, slash, name, slash, (unsigned long) t, mod,
1888 flags & MG_FS_DIR ? (int64_t) -1 : (int64_t) size, sz);
1889 }
1890}
1891
1892static void listdir(struct mg_connection *c, struct mg_http_message *hm,
1893 const struct mg_http_serve_opts *opts, char *dir) {
1894 const char *sort_js_code =
1895 "<script>function srt(tb, sc, so, d) {"
1896 "var tr = Array.prototype.slice.call(tb.rows, 0),"
1897 "tr = tr.sort(function (a, b) { var c1 = a.cells[sc], c2 = b.cells[sc],"
1898 "n1 = c1.getAttribute('name'), n2 = c2.getAttribute('name'), "
1899 "t1 = a.cells[2].getAttribute('name'), "
1900 "t2 = b.cells[2].getAttribute('name'); "
1901 "return so * (t1 < 0 && t2 >= 0 ? -1 : t2 < 0 && t1 >= 0 ? 1 : "
1902 "n1 ? parseInt(n2) - parseInt(n1) : "
1903 "c1.textContent.trim().localeCompare(c2.textContent.trim())); });";
1904 const char *sort_js_code2 =
1905 "for (var i = 0; i < tr.length; i++) tb.appendChild(tr[i]); "
1906 "if (!d) window.location.hash = ('sc=' + sc + '&so=' + so); "
1907 "};"
1908 "window.onload = function() {"
1909 "var tb = document.getElementById('tb');"
1910 "var m = /sc=([012]).so=(1|-1)/.exec(window.location.hash) || [0, 2, 1];"
1911 "var sc = m[1], so = m[2]; document.onclick = function(ev) { "
1912 "var c = ev.target.rel; if (c) {if (c == sc) so *= -1; srt(tb, c, so); "
1913 "sc = c; ev.preventDefault();}};"
1914 "srt(tb, sc, so, true);"
1915 "}"
1916 "</script>";
1917 struct mg_fs *fs = opts->fs == NULL ? &mg_fs_posix : opts->fs;
1918 struct printdirentrydata d = {c, hm, opts, dir};
1919 char tmp[10], buf[MG_PATH_MAX];
1920 size_t off, n;
1921 int len = mg_url_decode(hm->uri.ptr, hm->uri.len, buf, sizeof(buf), 0);
1922 struct mg_str uri = len > 0 ? mg_str_n(buf, (size_t) len) : hm->uri;
1923
1924 mg_printf(c,
1925 "HTTP/1.1 200 OK\r\n"
1926 "Content-Type: text/html; charset=utf-8\r\n"
1927 "%s"
1928 "Content-Length: \r\n\r\n",
1929 opts->extra_headers == NULL ? "" : opts->extra_headers);
1930 off = c->send.len; // Start of body
1931 mg_printf(c,
1932 "<!DOCTYPE html><html><head><title>Index of %.*s</title>%s%s"
1933 "<style>th,td {text-align: left; padding-right: 1em; "
1934 "font-family: monospace; }</style></head>"
1935 "<body><h1>Index of %.*s</h1><table cellpadding=\"0\"><thead>"
1936 "<tr><th><a href=\"#\" rel=\"0\">Name</a></th><th>"
1937 "<a href=\"#\" rel=\"1\">Modified</a></th>"
1938 "<th><a href=\"#\" rel=\"2\">Size</a></th></tr>"
1939 "<tr><td colspan=\"3\"><hr></td></tr>"
1940 "</thead>"
1941 "<tbody id=\"tb\">\n",
1942 (int) uri.len, uri.ptr, sort_js_code, sort_js_code2, (int) uri.len,
1943 uri.ptr);
1944 mg_printf(c, "%s",
1945 " <tr><td><a href=\"..\">..</a></td>"
1946 "<td name=-1></td><td name=-1>[DIR]</td></tr>\n");
1947
1948 fs->ls(dir, printdirentry, &d);
1949 mg_printf(c,
1950 "</tbody><tfoot><tr><td colspan=\"3\"><hr></td></tr></tfoot>"
1951 "</table><address>Mongoose v.%s</address></body></html>\n",
1952 MG_VERSION);
1953 n = mg_snprintf(tmp, sizeof(tmp), "%lu", (unsigned long) (c->send.len - off));
1954 if (n > sizeof(tmp)) n = 0;
1955 memcpy(c->send.buf + off - 12, tmp, n); // Set content length
1956 c->is_resp = 0; // Mark response end
1957}
1958
1959// Resolve requested file into `path` and return its fs->st() result
1960static int uri_to_path2(struct mg_connection *c, struct mg_http_message *hm,
1961 struct mg_fs *fs, struct mg_str url, struct mg_str dir,
1962 char *path, size_t path_size) {
1963 int flags, tmp;
1964 // Append URI to the root_dir, and sanitize it
1965 size_t n = mg_snprintf(path, path_size, "%.*s", (int) dir.len, dir.ptr);
1966 if (n > path_size) n = path_size;
1967 path[path_size - 1] = '\0';
1968 if (n + 2 < path_size) path[n++] = '/', path[n] = '\0';
1969 mg_url_decode(hm->uri.ptr + url.len, hm->uri.len - url.len, path + n,
1970 path_size - n, 0);
1971 path[path_size - 1] = '\0'; // Double-check
1972 mg_remove_double_dots(path);
1973 n = strlen(path);
1974 while (n > 1 && path[n - 1] == '/') path[--n] = 0; // Trim trailing slashes
1975 flags = mg_vcmp(&hm->uri, "/") == 0 ? MG_FS_DIR : fs->st(path, NULL, NULL);
1976 MG_VERBOSE(("%lu %.*s -> %s %d", c->id, (int) hm->uri.len, hm->uri.ptr, path,
1977 flags));
1978 if (flags == 0) {
1979 // Do nothing - let's caller decide
1980 } else if ((flags & MG_FS_DIR) && hm->uri.len > 0 &&
1981 hm->uri.ptr[hm->uri.len - 1] != '/') {
1982 mg_printf(c,
1983 "HTTP/1.1 301 Moved\r\n"
1984 "Location: %.*s/\r\n"
1985 "Content-Length: 0\r\n"
1986 "\r\n",
1987 (int) hm->uri.len, hm->uri.ptr);
1988 c->is_resp = 0;
1989 flags = -1;
1990 } else if (flags & MG_FS_DIR) {
1991 if (((mg_snprintf(path + n, path_size - n, "/" MG_HTTP_INDEX) > 0 &&
1992 (tmp = fs->st(path, NULL, NULL)) != 0) ||
1993 (mg_snprintf(path + n, path_size - n, "/index.shtml") > 0 &&
1994 (tmp = fs->st(path, NULL, NULL)) != 0))) {
1995 flags = tmp;
1996 } else if ((mg_snprintf(path + n, path_size - n, "/" MG_HTTP_INDEX ".gz") >
1997 0 &&
1998 (tmp = fs->st(path, NULL, NULL)) !=
1999 0)) { // check for gzipped index
2000 flags = tmp;
2001 path[n + 1 + strlen(MG_HTTP_INDEX)] =
2002 '\0'; // Remove appended .gz in index file name
2003 } else {
2004 path[n] = '\0'; // Remove appended index file name
2005 }
2006 }
2007 return flags;
2008}
2009
2010static int uri_to_path(struct mg_connection *c, struct mg_http_message *hm,
2011 const struct mg_http_serve_opts *opts, char *path,
2012 size_t path_size) {
2013 struct mg_fs *fs = opts->fs == NULL ? &mg_fs_posix : opts->fs;
2014 struct mg_str k, v, s = mg_str(opts->root_dir), u = {0, 0}, p = {0, 0};
2015 while (mg_commalist(&s, &k, &v)) {
2016 if (v.len == 0) v = k, k = mg_str("/");
2017 if (hm->uri.len < k.len) continue;
2018 if (mg_strcmp(k, mg_str_n(hm->uri.ptr, k.len)) != 0) continue;
2019 u = k, p = v;
2020 }
2021 return uri_to_path2(c, hm, fs, u, p, path, path_size);
2022}
2023
2024void mg_http_serve_dir(struct mg_connection *c, struct mg_http_message *hm,
2025 const struct mg_http_serve_opts *opts) {
2026 char path[MG_PATH_MAX];
2027 const char *sp = opts->ssi_pattern;
2028 int flags = uri_to_path(c, hm, opts, path, sizeof(path));
2029 if (flags < 0) {
2030 // Do nothing: the response has already been sent by uri_to_path()
2031 } else if (flags & MG_FS_DIR) {
2032 listdir(c, hm, opts, path);
2033 } else if (flags && sp != NULL &&
2034 mg_globmatch(sp, strlen(sp), path, strlen(path))) {
2035 mg_http_serve_ssi(c, opts->root_dir, path);
2036 } else {
2037 mg_http_serve_file(c, hm, path, opts);
2038 }
2039}
2040
2041static bool mg_is_url_safe(int c) {
2042 return (c >= '0' && c <= '9') || (c >= 'a' && c <= 'z') ||
2043 (c >= 'A' && c <= 'Z') || c == '.' || c == '_' || c == '-' || c == '~';
2044}
2045
2046size_t mg_url_encode(const char *s, size_t sl, char *buf, size_t len) {
2047 size_t i, n = 0;
2048 for (i = 0; i < sl; i++) {
2049 int c = *(unsigned char *) &s[i];
2050 if (n + 4 >= len) return 0;
2051 if (mg_is_url_safe(c)) {
2052 buf[n++] = s[i];
2053 } else {
2054 buf[n++] = '%';
2055 mg_hex(&s[i], 1, &buf[n]);
2056 n += 2;
2057 }
2058 }
2059 if (len > 0 && n < len - 1) buf[n] = '\0'; // Null-terminate the destination
2060 if (len > 0) buf[len - 1] = '\0'; // Always.
2061 return n;
2062}
2063
2064void mg_http_creds(struct mg_http_message *hm, char *user, size_t userlen,
2065 char *pass, size_t passlen) {
2066 struct mg_str *v = mg_http_get_header(hm, "Authorization");
2067 user[0] = pass[0] = '\0';
2068 if (v != NULL && v->len > 6 && memcmp(v->ptr, "Basic ", 6) == 0) {
2069 char buf[256];
2070 int n = mg_base64_decode(v->ptr + 6, (int) v->len - 6, buf);
2071 const char *p = (const char *) memchr(buf, ':', n > 0 ? (size_t) n : 0);
2072 if (p != NULL) {
2073 mg_snprintf(user, userlen, "%.*s", (int) (p - buf), buf);
2074 mg_snprintf(pass, passlen, "%.*s", n - (int) (p - buf) - 1, p + 1);
2075 }
2076 } else if (v != NULL && v->len > 7 && memcmp(v->ptr, "Bearer ", 7) == 0) {
2077 mg_snprintf(pass, passlen, "%.*s", (int) v->len - 7, v->ptr + 7);
2078 } else if ((v = mg_http_get_header(hm, "Cookie")) != NULL) {
2079 struct mg_str t = mg_http_get_header_var(*v, mg_str_n("access_token", 12));
2080 if (t.len > 0) mg_snprintf(pass, passlen, "%.*s", (int) t.len, t.ptr);
2081 } else {
2082 mg_http_get_var(&hm->query, "access_token", pass, passlen);
2083 }
2084}
2085
2086static struct mg_str stripquotes(struct mg_str s) {
2087 return s.len > 1 && s.ptr[0] == '"' && s.ptr[s.len - 1] == '"'
2088 ? mg_str_n(s.ptr + 1, s.len - 2)
2089 : s;
2090}
2091
2092struct mg_str mg_http_get_header_var(struct mg_str s, struct mg_str v) {
2093 size_t i;
2094 for (i = 0; v.len > 0 && i + v.len + 2 < s.len; i++) {
2095 if (s.ptr[i + v.len] == '=' && memcmp(&s.ptr[i], v.ptr, v.len) == 0) {
2096 const char *p = &s.ptr[i + v.len + 1], *b = p, *x = &s.ptr[s.len];
2097 int q = p < x && *p == '"' ? 1 : 0;
2098 while (p < x &&
2099 (q ? p == b || *p != '"' : *p != ';' && *p != ' ' && *p != ','))
2100 p++;
2101 // MG_INFO(("[%.*s] [%.*s] [%.*s]", (int) s.len, s.ptr, (int) v.len,
2102 // v.ptr, (int) (p - b), b));
2103 return stripquotes(mg_str_n(b, (size_t) (p - b + q)));
2104 }
2105 }
2106 return mg_str_n(NULL, 0);
2107}
2108
2109bool mg_http_match_uri(const struct mg_http_message *hm, const char *glob) {
2110 return mg_match(hm->uri, mg_str(glob), NULL);
2111}
2112
2113long mg_http_upload(struct mg_connection *c, struct mg_http_message *hm,
2114 struct mg_fs *fs, const char *path, size_t max_size) {
2115 char buf[20] = "0";
2116 long res = 0, offset;
2117 mg_http_get_var(&hm->query, "offset", buf, sizeof(buf));
2118 offset = strtol(buf, NULL, 0);
2119 if (hm->body.len == 0) {
2120 mg_http_reply(c, 200, "", "%ld", res); // Nothing to write
2121 } else {
2122 struct mg_fd *fd;
2123 size_t current_size = 0;
2124 MG_DEBUG(("%s -> %d bytes @ %ld", path, (int) hm->body.len, offset));
2125 if (offset == 0) fs->rm(path); // If offset if 0, truncate file
2126 fs->st(path, &current_size, NULL);
2127 if (offset < 0) {
2128 mg_http_reply(c, 400, "", "offset required");
2129 res = -1;
2130 } else if (offset > 0 && current_size != (size_t) offset) {
2131 mg_http_reply(c, 400, "", "%s: offset mismatch", path);
2132 res = -2;
2133 } else if ((size_t) offset + hm->body.len > max_size) {
2134 mg_http_reply(c, 400, "", "%s: over max size of %lu", path,
2135 (unsigned long) max_size);
2136 res = -3;
2137 } else if ((fd = mg_fs_open(fs, path, MG_FS_WRITE)) == NULL) {
2138 mg_http_reply(c, 400, "", "open(%s): %d", path, errno);
2139 res = -4;
2140 } else {
2141 res = offset + (long) fs->wr(fd->fd, hm->body.ptr, hm->body.len);
2142 mg_fs_close(fd);
2143 mg_http_reply(c, 200, "", "%ld", res);
2144 }
2145 }
2146 return res;
2147}
2148
2149int mg_http_status(const struct mg_http_message *hm) {
2150 return atoi(hm->uri.ptr);
2151}
2152
2153// If a server sends data to the client using chunked encoding, Mongoose strips
2154// off the chunking prefix (hex length and \r\n) and suffix (\r\n), appends the
2155// stripped data to the body, and fires the MG_EV_HTTP_CHUNK event. When zero
2156// chunk is received, we fire MG_EV_HTTP_MSG, and the body already has all
2157// chunking prefixes/suffixes stripped.
2158//
2159// If a server sends data without chunked encoding, we also fire a series of
2160// MG_EV_HTTP_CHUNK events for every received piece of data, and then we fire
2161// MG_EV_HTTP_MSG event in the end.
2162//
2163// We track total processed length in the c->pfn_data, which is a void *
2164// pointer: we store a size_t value there.
2165static bool getchunk(struct mg_str s, size_t *prefixlen, size_t *datalen) {
2166 size_t i = 0, n;
2167 while (i < s.len && s.ptr[i] != '\r' && s.ptr[i] != '\n') i++;
2168 n = mg_unhexn(s.ptr, i);
2169 // MG_INFO(("%d %d", (int) (i + n + 4), (int) s.len));
2170 if (s.len < i + n + 4) return false; // Chunk not yet fully buffered
2171 if (s.ptr[i] != '\r' || s.ptr[i + 1] != '\n') return false;
2172 if (s.ptr[i + n + 2] != '\r' || s.ptr[i + n + 3] != '\n') return false;
2173 *prefixlen = i + 2;
2174 *datalen = n;
2175 return true;
2176}
2177
2178static bool mg_is_chunked(struct mg_http_message *hm) {
2179 const char *needle = "chunked";
2180 struct mg_str *te = mg_http_get_header(hm, "Transfer-Encoding");
2181 return te != NULL && mg_vcasecmp(te, needle) == 0;
2182}
2183
2184void mg_http_delete_chunk(struct mg_connection *c, struct mg_http_message *hm) {
2185 size_t ofs = (size_t) (hm->chunk.ptr - (char *) c->recv.buf);
2186 mg_iobuf_del(&c->recv, ofs, hm->chunk.len);
2187 c->pfn_data = (void *) ((size_t) c->pfn_data | MG_DMARK);
2188}
2189
2190static void deliver_chunked_chunks(struct mg_connection *c, size_t hlen,
2191 struct mg_http_message *hm, bool *next) {
2192 // | ... headers ... | HEXNUM\r\n ..data.. \r\n | ......
2193 // +------------------+--------------------------+----
2194 // | hlen | chunk1 | ......
2195 char *buf = (char *) &c->recv.buf[hlen], *p = buf;
2196 size_t len = c->recv.len - hlen;
2197 size_t processed = ((size_t) c->pfn_data) & ~MG_DMARK;
2198 size_t mark, pl, dl, del = 0, ofs = 0;
2199 bool last = false;
2200 if (processed <= len) len -= processed, buf += processed;
2201 while (!last && getchunk(mg_str_n(buf + ofs, len - ofs), &pl, &dl)) {
2202 size_t saved = c->recv.len;
2203 memmove(p + processed, buf + ofs + pl, dl);
2204 // MG_INFO(("P2 [%.*s]", (int) (processed + dl), p));
2205 hm->chunk = mg_str_n(p + processed, dl);
2206 mg_call(c, MG_EV_HTTP_CHUNK, hm);
2207 ofs += pl + dl + 2, del += pl + 2; // 2 is for \r\n suffix
2208 processed += dl;
2209 if (c->recv.len != saved) processed -= dl, buf -= dl;
2210 // mg_hexdump(c->recv.buf, hlen + processed);
2211 last = (dl == 0);
2212 }
2213 mg_iobuf_del(&c->recv, hlen + processed, del);
2214 mark = ((size_t) c->pfn_data) & MG_DMARK;
2215 c->pfn_data = (void *) (processed | mark);
2216 if (last) {
2217 hm->body.len = processed;
2218 hm->message.len = hlen + processed;
2219 c->pfn_data = NULL;
2220 if (mark) mg_iobuf_del(&c->recv, 0, hlen), *next = true;
2221 // MG_INFO(("LAST, mark: %lx", mark));
2222 // mg_hexdump(c->recv.buf, c->recv.len);
2223 }
2224}
2225
2226static void deliver_normal_chunks(struct mg_connection *c, size_t hlen,
2227 struct mg_http_message *hm, bool *next) {
2228 size_t left, processed = ((size_t) c->pfn_data) & ~MG_DMARK;
2229 size_t deleted = ((size_t) c->pfn_data) & MG_DMARK;
2230 hm->chunk = mg_str_n((char *) &c->recv.buf[hlen], c->recv.len - hlen);
2231 if (processed <= hm->chunk.len && !deleted) {
2232 hm->chunk.len -= processed;
2233 hm->chunk.ptr += processed;
2234 }
2235 left = hm->body.len < processed ? 0 : hm->body.len - processed;
2236 if (hm->chunk.len > left) hm->chunk.len = left;
2237 if (hm->chunk.len > 0) mg_call(c, MG_EV_HTTP_CHUNK, hm);
2238 processed += hm->chunk.len;
2239 deleted = ((size_t) c->pfn_data) & MG_DMARK; // Re-evaluate after user call
2240 if (processed >= hm->body.len) { // Last, 0-len chunk
2241 hm->chunk.len = 0; // Reset length
2242 mg_call(c, MG_EV_HTTP_CHUNK, hm); // Call user handler
2243 c->pfn_data = NULL; // Reset processed counter
2244 if (processed && deleted) mg_iobuf_del(&c->recv, 0, hlen), *next = true;
2245 } else {
2246 c->pfn_data = (void *) (processed | deleted); // if it is set
2247 }
2248}
2249
2250static void http_cb(struct mg_connection *c, int ev, void *evd, void *fnd) {
2251 if (ev == MG_EV_READ || ev == MG_EV_CLOSE) {
2252 struct mg_http_message hm;
2253 // mg_hexdump(c->recv.buf, c->recv.len);
2254 while (c->recv.buf != NULL && c->recv.len > 0) {
2255 bool next = false;
2256 int hlen = mg_http_parse((char *) c->recv.buf, c->recv.len, &hm);
2257 if (hlen < 0) {
2258 mg_error(c, "HTTP parse:\n%.*s", (int) c->recv.len, c->recv.buf);
2259 break;
2260 }
2261 if (c->is_resp) break; // Response is still generated
2262 if (hlen == 0) break; // Request is not buffered yet
2263 if (ev == MG_EV_CLOSE) { // If client did not set Content-Length
2264 hm.message.len = c->recv.len; // and closes now, deliver a MSG
2265 hm.body.len = hm.message.len - (size_t) (hm.body.ptr - hm.message.ptr);
2266 }
2267 if (mg_is_chunked(&hm)) {
2268 deliver_chunked_chunks(c, (size_t) hlen, &hm, &next);
2269 } else {
2270 deliver_normal_chunks(c, (size_t) hlen, &hm, &next);
2271 }
2272 if (next) continue; // Chunks & request were deleted
2273 // Chunk events are delivered. If we have full body, deliver MSG
2274 if (c->recv.len < hm.message.len) break;
2275 if (c->is_accepted) c->is_resp = 1; // Start generating response
2276 mg_call(c, MG_EV_HTTP_MSG, &hm); // User handler can clear is_resp
2277 mg_iobuf_del(&c->recv, 0, hm.message.len);
2278 }
2279 }
2280 (void) evd, (void) fnd;
2281}
2282
2283static void mg_hfn(struct mg_connection *c, int ev, void *ev_data, void *fnd) {
2284 if (ev == MG_EV_HTTP_MSG) {
2285 struct mg_http_message *hm = (struct mg_http_message *) ev_data;
2286 if (mg_http_match_uri(hm, "/quit")) {
2287 mg_http_reply(c, 200, "", "ok\n");
2288 c->is_draining = 1;
2289 c->data[0] = 'X';
2290 } else if (mg_http_match_uri(hm, "/debug")) {
2291 int level = (int) mg_json_get_long(hm->body, "$.level", MG_LL_DEBUG);
2292 mg_log_set(level);
2293 mg_http_reply(c, 200, "", "Debug level set to %d\n", level);
2294 } else {
2295 mg_http_reply(c, 200, "", "hi\n");
2296 }
2297 } else if (ev == MG_EV_CLOSE) {
2298 if (c->data[0] == 'X') *(bool *) fnd = true;
2299 }
2300}
2301
2302void mg_hello(const char *url) {
2303 struct mg_mgr mgr;
2304 bool done = false;
2305 mg_mgr_init(&mgr);
2306 if (mg_http_listen(&mgr, url, mg_hfn, &done) == NULL) done = true;
2307 while (done == false) mg_mgr_poll(&mgr, 100);
2308 mg_mgr_free(&mgr);
2309}
2310
2311struct mg_connection *mg_http_connect(struct mg_mgr *mgr, const char *url,
2312 mg_event_handler_t fn, void *fn_data) {
2313 struct mg_connection *c = mg_connect(mgr, url, fn, fn_data);
2314 if (c != NULL) c->pfn = http_cb;
2315 return c;
2316}
2317
2318struct mg_connection *mg_http_listen(struct mg_mgr *mgr, const char *url,
2319 mg_event_handler_t fn, void *fn_data) {
2320 struct mg_connection *c = mg_listen(mgr, url, fn, fn_data);
2321 if (c != NULL) c->pfn = http_cb;
2322 return c;
2323}
2324
2325#ifdef MG_ENABLE_LINES
2326#line 1 "src/iobuf.c"
2327#endif
2328
2329
2330
2331
2332// Not using memset for zeroing memory, cause it can be dropped by compiler
2333// See https://github.com/cesanta/mongoose/pull/1265
2334static void zeromem(volatile unsigned char *buf, size_t len) {
2335 if (buf != NULL) {
2336 while (len--) *buf++ = 0;
2337 }
2338}
2339
2340static size_t roundup(size_t size, size_t align) {
2341 return align == 0 ? size : (size + align - 1) / align * align;
2342}
2343
2344int mg_iobuf_resize(struct mg_iobuf *io, size_t new_size) {
2345 int ok = 1;
2346 new_size = roundup(new_size, io->align);
2347 if (new_size == 0) {
2348 zeromem(io->buf, io->size);
2349 free(io->buf);
2350 io->buf = NULL;
2351 io->len = io->size = 0;
2352 } else if (new_size != io->size) {
2353 // NOTE(lsm): do not use realloc here. Use calloc/free only, to ease the
2354 // porting to some obscure platforms like FreeRTOS
2355 void *p = calloc(1, new_size);
2356 if (p != NULL) {
2357 size_t len = new_size < io->len ? new_size : io->len;
2358 if (len > 0 && io->buf != NULL) memmove(p, io->buf, len);
2359 zeromem(io->buf, io->size);
2360 free(io->buf);
2361 io->buf = (unsigned char *) p;
2362 io->size = new_size;
2363 } else {
2364 ok = 0;
2365 MG_ERROR(("%lld->%lld", (uint64_t) io->size, (uint64_t) new_size));
2366 }
2367 }
2368 return ok;
2369}
2370
2371int mg_iobuf_init(struct mg_iobuf *io, size_t size, size_t align) {
2372 io->buf = NULL;
2373 io->align = align;
2374 io->size = io->len = 0;
2375 return mg_iobuf_resize(io, size);
2376}
2377
2378size_t mg_iobuf_add(struct mg_iobuf *io, size_t ofs, const void *buf,
2379 size_t len) {
2380 size_t new_size = roundup(io->len + len, io->align);
2381 mg_iobuf_resize(io, new_size); // Attempt to resize
2382 if (new_size != io->size) len = 0; // Resize failure, append nothing
2383 if (ofs < io->len) memmove(io->buf + ofs + len, io->buf + ofs, io->len - ofs);
2384 if (buf != NULL) memmove(io->buf + ofs, buf, len);
2385 if (ofs > io->len) io->len += ofs - io->len;
2386 io->len += len;
2387 return len;
2388}
2389
2390size_t mg_iobuf_del(struct mg_iobuf *io, size_t ofs, size_t len) {
2391 if (ofs > io->len) ofs = io->len;
2392 if (ofs + len > io->len) len = io->len - ofs;
2393 if (io->buf) memmove(io->buf + ofs, io->buf + ofs + len, io->len - ofs - len);
2394 if (io->buf) zeromem(io->buf + io->len - len, len);
2395 io->len -= len;
2396 return len;
2397}
2398
2399void mg_iobuf_free(struct mg_iobuf *io) {
2400 mg_iobuf_resize(io, 0);
2401}
2402
2403#ifdef MG_ENABLE_LINES
2404#line 1 "src/json.c"
2405#endif
2406
2407
2408
2409
2410static const char *escapeseq(int esc) {
2411 return esc ? "\b\f\n\r\t\\\"" : "bfnrt\\\"";
2412}
2413
2414static char json_esc(int c, int esc) {
2415 const char *p, *esc1 = escapeseq(esc), *esc2 = escapeseq(!esc);
2416 for (p = esc1; *p != '\0'; p++) {
2417 if (*p == c) return esc2[p - esc1];
2418 }
2419 return 0;
2420}
2421
2422static int mg_pass_string(const char *s, int len) {
2423 int i;
2424 for (i = 0; i < len; i++) {
2425 if (s[i] == '\\' && i + 1 < len && json_esc(s[i + 1], 1)) {
2426 i++;
2427 } else if (s[i] == '\0') {
2428 return MG_JSON_INVALID;
2429 } else if (s[i] == '"') {
2430 return i;
2431 }
2432 }
2433 return MG_JSON_INVALID;
2434}
2435
2436static double mg_atod(const char *p, int len, int *numlen) {
2437 double d = 0.0;
2438 int i = 0, sign = 1;
2439
2440 // Sign
2441 if (i < len && *p == '-') {
2442 sign = -1, i++;
2443 } else if (i < len && *p == '+') {
2444 i++;
2445 }
2446
2447 // Decimal
2448 for (; i < len && p[i] >= '0' && p[i] <= '9'; i++) {
2449 d *= 10.0;
2450 d += p[i] - '0';
2451 }
2452 d *= sign;
2453
2454 // Fractional
2455 if (i < len && p[i] == '.') {
2456 double frac = 0.0, base = 0.1;
2457 i++;
2458 for (; i < len && p[i] >= '0' && p[i] <= '9'; i++) {
2459 frac += base * (p[i] - '0');
2460 base /= 10.0;
2461 }
2462 d += frac * sign;
2463 }
2464
2465 // Exponential
2466 if (i < len && (p[i] == 'e' || p[i] == 'E')) {
2467 int j, exp = 0, minus = 0;
2468 i++;
2469 if (i < len && p[i] == '-') minus = 1, i++;
2470 if (i < len && p[i] == '+') i++;
2471 while (i < len && p[i] >= '0' && p[i] <= '9' && exp < 308)
2472 exp = exp * 10 + (p[i++] - '0');
2473 if (minus) exp = -exp;
2474 for (j = 0; j < exp; j++) d *= 10.0;
2475 for (j = 0; j < -exp; j++) d /= 10.0;
2476 }
2477
2478 if (numlen != NULL) *numlen = i;
2479 return d;
2480}
2481
2482int mg_json_get(struct mg_str json, const char *path, int *toklen) {
2483 const char *s = json.ptr;
2484 int len = (int) json.len;
2485 enum { S_VALUE, S_KEY, S_COLON, S_COMMA_OR_EOO } expecting = S_VALUE;
2486 unsigned char nesting[MG_JSON_MAX_DEPTH];
2487 int i = 0; // Current offset in `s`
2488 int j = 0; // Offset in `s` we're looking for (return value)
2489 int depth = 0; // Current depth (nesting level)
2490 int ed = 0; // Expected depth
2491 int pos = 1; // Current position in `path`
2492 int ci = -1, ei = -1; // Current and expected index in array
2493
2494 if (toklen) *toklen = 0;
2495 if (path[0] != '$') return MG_JSON_INVALID;
2496
2497#define MG_CHECKRET(x) \
2498 do { \
2499 if (depth == ed && path[pos] == '\0' && ci == ei) { \
2500 if (toklen) *toklen = i - j + 1; \
2501 return j; \
2502 } \
2503 } while (0)
2504
2505// In the ascii table, the distance between `[` and `]` is 2.
2506// Ditto for `{` and `}`. Hence +2 in the code below.
2507#define MG_EOO(x) \
2508 do { \
2509 if (depth == ed && ci != ei) return MG_JSON_NOT_FOUND; \
2510 if (c != nesting[depth - 1] + 2) return MG_JSON_INVALID; \
2511 depth--; \
2512 MG_CHECKRET(x); \
2513 } while (0)
2514
2515 for (i = 0; i < len; i++) {
2516 unsigned char c = ((unsigned char *) s)[i];
2517 if (c == ' ' || c == '\t' || c == '\n' || c == '\r') continue;
2518 switch (expecting) {
2519 case S_VALUE:
2520 // p("V %s [%.*s] %d %d %d %d\n", path, pos, path, depth, ed, ci, ei);
2521 if (depth == ed) j = i;
2522 if (c == '{') {
2523 if (depth >= (int) sizeof(nesting)) return MG_JSON_TOO_DEEP;
2524 if (depth == ed && path[pos] == '.' && ci == ei) {
2525 // If we start the object, reset array indices
2526 ed++, pos++, ci = ei = -1;
2527 }
2528 nesting[depth++] = c;
2529 expecting = S_KEY;
2530 break;
2531 } else if (c == '[') {
2532 if (depth >= (int) sizeof(nesting)) return MG_JSON_TOO_DEEP;
2533 if (depth == ed && path[pos] == '[' && ei == ci) {
2534 ed++, pos++, ci = 0;
2535 for (ei = 0; path[pos] != ']' && path[pos] != '\0'; pos++) {
2536 ei *= 10;
2537 ei += path[pos] - '0';
2538 }
2539 if (path[pos] != 0) pos++;
2540 }
2541 nesting[depth++] = c;
2542 break;
2543 } else if (c == ']' && depth > 0) { // Empty array
2544 MG_EOO(']');
2545 } else if (c == 't' && i + 3 < len && memcmp(&s[i], "true", 4) == 0) {
2546 i += 3;
2547 } else if (c == 'n' && i + 3 < len && memcmp(&s[i], "null", 4) == 0) {
2548 i += 3;
2549 } else if (c == 'f' && i + 4 < len && memcmp(&s[i], "false", 5) == 0) {
2550 i += 4;
2551 } else if (c == '-' || ((c >= '0' && c <= '9'))) {
2552 int numlen = 0;
2553 mg_atod(&s[i], len - i, &numlen);
2554 i += numlen - 1;
2555 } else if (c == '"') {
2556 int n = mg_pass_string(&s[i + 1], len - i - 1);
2557 if (n < 0) return n;
2558 i += n + 1;
2559 } else {
2560 return MG_JSON_INVALID;
2561 }
2562 MG_CHECKRET('V');
2563 if (depth == ed && ei >= 0) ci++;
2564 expecting = S_COMMA_OR_EOO;
2565 break;
2566
2567 case S_KEY:
2568 if (c == '"') {
2569 int n = mg_pass_string(&s[i + 1], len - i - 1);
2570 if (n < 0) return n;
2571 if (i + 1 + n >= len) return MG_JSON_NOT_FOUND;
2572 if (depth < ed) return MG_JSON_NOT_FOUND;
2573 if (depth == ed && path[pos - 1] != '.') return MG_JSON_NOT_FOUND;
2574 // printf("K %s [%.*s] [%.*s] %d %d %d\n", path, pos, path, n,
2575 // &s[i + 1], n, depth, ed);
2576 // NOTE(cpq): in the check sequence below is important.
2577 // strncmp() must go first: it fails fast if the remaining length of
2578 // the path is smaller than `n`.
2579 if (depth == ed && path[pos - 1] == '.' &&
2580 strncmp(&s[i + 1], &path[pos], (size_t) n) == 0 &&
2581 (path[pos + n] == '\0' || path[pos + n] == '.' ||
2582 path[pos + n] == '[')) {
2583 pos += n;
2584 }
2585 i += n + 1;
2586 expecting = S_COLON;
2587 } else if (c == '}') { // Empty object
2588 MG_EOO('}');
2589 expecting = S_COMMA_OR_EOO;
2590 if (depth == ed && ei >= 0) ci++;
2591 } else {
2592 return MG_JSON_INVALID;
2593 }
2594 break;
2595
2596 case S_COLON:
2597 if (c == ':') {
2598 expecting = S_VALUE;
2599 } else {
2600 return MG_JSON_INVALID;
2601 }
2602 break;
2603
2604 case S_COMMA_OR_EOO:
2605 if (depth <= 0) {
2606 return MG_JSON_INVALID;
2607 } else if (c == ',') {
2608 expecting = (nesting[depth - 1] == '{') ? S_KEY : S_VALUE;
2609 } else if (c == ']' || c == '}') {
2610 MG_EOO('O');
2611 if (depth == ed && ei >= 0) ci++;
2612 } else {
2613 return MG_JSON_INVALID;
2614 }
2615 break;
2616 }
2617 }
2618 return MG_JSON_NOT_FOUND;
2619}
2620
2621bool mg_json_get_num(struct mg_str json, const char *path, double *v) {
2622 int n, toklen, found = 0;
2623 if ((n = mg_json_get(json, path, &toklen)) >= 0 &&
2624 (json.ptr[n] == '-' || (json.ptr[n] >= '0' && json.ptr[n] <= '9'))) {
2625 if (v != NULL) *v = mg_atod(json.ptr + n, toklen, NULL);
2626 found = 1;
2627 }
2628 return found;
2629}
2630
2631bool mg_json_get_bool(struct mg_str json, const char *path, bool *v) {
2632 int found = 0, off = mg_json_get(json, path, NULL);
2633 if (off >= 0 && (json.ptr[off] == 't' || json.ptr[off] == 'f')) {
2634 if (v != NULL) *v = json.ptr[off] == 't';
2635 found = 1;
2636 }
2637 return found;
2638}
2639
2640bool mg_json_unescape(struct mg_str s, char *to, size_t n) {
2641 size_t i, j;
2642 for (i = 0, j = 0; i < s.len && j < n; i++, j++) {
2643 if (s.ptr[i] == '\\' && i + 5 < s.len && s.ptr[i + 1] == 'u') {
2644 // \uXXXX escape. We could process a simple one-byte chars
2645 // \u00xx from the ASCII range. More complex chars would require
2646 // dragging in a UTF8 library, which is too much for us
2647 if (s.ptr[i + 2] != '0' || s.ptr[i + 3] != '0') return false; // Give up
2648 ((unsigned char *) to)[j] = (unsigned char) mg_unhexn(s.ptr + i + 4, 2);
2649
2650 i += 5;
2651 } else if (s.ptr[i] == '\\' && i + 1 < s.len) {
2652 char c = json_esc(s.ptr[i + 1], 0);
2653 if (c == 0) return false;
2654 to[j] = c;
2655 i++;
2656 } else {
2657 to[j] = s.ptr[i];
2658 }
2659 }
2660 if (j >= n) return false;
2661 if (n > 0) to[j] = '\0';
2662 return true;
2663}
2664
2665char *mg_json_get_str(struct mg_str json, const char *path) {
2666 char *result = NULL;
2667 int len = 0, off = mg_json_get(json, path, &len);
2668 if (off >= 0 && len > 1 && json.ptr[off] == '"') {
2669 if ((result = (char *) calloc(1, (size_t) len)) != NULL &&
2670 !mg_json_unescape(mg_str_n(json.ptr + off + 1, (size_t) (len - 2)),
2671 result, (size_t) len)) {
2672 free(result);
2673 result = NULL;
2674 }
2675 }
2676 return result;
2677}
2678
2679char *mg_json_get_b64(struct mg_str json, const char *path, int *slen) {
2680 char *result = NULL;
2681 int len = 0, off = mg_json_get(json, path, &len);
2682 if (off >= 0 && json.ptr[off] == '"' && len > 1 &&
2683 (result = (char *) calloc(1, (size_t) len)) != NULL) {
2684 int k = mg_base64_decode(json.ptr + off + 1, len - 2, result);
2685 if (slen != NULL) *slen = k;
2686 }
2687 return result;
2688}
2689
2690char *mg_json_get_hex(struct mg_str json, const char *path, int *slen) {
2691 char *result = NULL;
2692 int len = 0, off = mg_json_get(json, path, &len);
2693 if (off >= 0 && json.ptr[off] == '"' && len > 1 &&
2694 (result = (char *) calloc(1, (size_t) len / 2)) != NULL) {
2695 mg_unhex(json.ptr + off + 1, (size_t) (len - 2), (uint8_t *) result);
2696 result[len / 2 - 1] = '\0';
2697 if (slen != NULL) *slen = len / 2 - 1;
2698 }
2699 return result;
2700}
2701
2702long mg_json_get_long(struct mg_str json, const char *path, long dflt) {
2703 double dv;
2704 long result = dflt;
2705 if (mg_json_get_num(json, path, &dv)) result = (long) dv;
2706 return result;
2707}
2708
2709#ifdef MG_ENABLE_LINES
2710#line 1 "src/log.c"
2711#endif
2712
2713
2714
2715
2716
2717static int s_level = MG_LL_INFO;
2718static mg_pfn_t s_log_func = mg_pfn_stdout;
2719static void *s_log_func_param = NULL;
2720
2721void mg_log_set_fn(mg_pfn_t fn, void *param) {
2722 s_log_func = fn;
2723 s_log_func_param = param;
2724}
2725
2726static void logc(unsigned char c) {
2727 s_log_func((char) c, s_log_func_param);
2728}
2729
2730static void logs(const char *buf, size_t len) {
2731 size_t i;
2732 for (i = 0; i < len; i++) logc(((unsigned char *) buf)[i]);
2733}
2734
2735void mg_log_set(int log_level) {
2736 MG_DEBUG(("Setting log level to %d", log_level));
2737 s_level = log_level;
2738}
2739
2740bool mg_log_prefix(int level, const char *file, int line, const char *fname) {
2741 if (level <= s_level) {
2742 const char *p = strrchr(file, '/');
2743 char buf[41];
2744 size_t n;
2745 if (p == NULL) p = strrchr(file, '\\');
2746 n = mg_snprintf(buf, sizeof(buf), "%-6llx %d %s:%d:%s", mg_millis(), level,
2747 p == NULL ? file : p + 1, line, fname);
2748 if (n > sizeof(buf) - 2) n = sizeof(buf) - 2;
2749 while (n < sizeof(buf)) buf[n++] = ' ';
2750 logs(buf, n - 1);
2751 return true;
2752 } else {
2753 return false;
2754 }
2755}
2756
2757void mg_log(const char *fmt, ...) {
2758 va_list ap;
2759 va_start(ap, fmt);
2760 mg_vxprintf(s_log_func, s_log_func_param, fmt, &ap);
2761 va_end(ap);
2762 logc((unsigned char) '\n');
2763}
2764
2765static unsigned char nibble(unsigned c) {
2766 return (unsigned char) (c < 10 ? c + '0' : c + 'W');
2767}
2768
2769#define ISPRINT(x) ((x) >= ' ' && (x) <= '~')
2770void mg_hexdump(const void *buf, size_t len) {
2771 const unsigned char *p = (const unsigned char *) buf;
2772 unsigned char ascii[16], alen = 0;
2773 size_t i;
2774 for (i = 0; i < len; i++) {
2775 if ((i % 16) == 0) {
2776 // Print buffered ascii chars
2777 if (i > 0) logs(" ", 2), logs((char *) ascii, 16), logc('\n'), alen = 0;
2778 // Print hex address, then \t
2779 logc(nibble((i >> 12) & 15)), logc(nibble((i >> 8) & 15)),
2780 logc(nibble((i >> 4) & 15)), logc('0'), logs(" ", 3);
2781 }
2782 logc(nibble(p[i] >> 4)), logc(nibble(p[i] & 15)); // Two nibbles, e.g. c5
2783 logc(' '); // Space after hex number
2784 ascii[alen++] = ISPRINT(p[i]) ? p[i] : '.'; // Add to the ascii buf
2785 }
2786 while (alen < 16) logs(" ", 3), ascii[alen++] = ' ';
2787 logs(" ", 2), logs((char *) ascii, 16), logc('\n');
2788}
2789
2790#ifdef MG_ENABLE_LINES
2791#line 1 "src/md5.c"
2792#endif
2793
2794
2795
2796#if defined(MG_ENABLE_MD5) && MG_ENABLE_MD5
2797
2798static void mg_byte_reverse(unsigned char *buf, unsigned longs) {
2799 if (MG_BIG_ENDIAN) {
2800 do {
2801 uint32_t t = (uint32_t) ((unsigned) buf[3] << 8 | buf[2]) << 16 |
2802 ((unsigned) buf[1] << 8 | buf[0]);
2803 *(uint32_t *) buf = t;
2804 buf += 4;
2805 } while (--longs);
2806 } else {
2807 (void) buf, (void) longs; // Little endian. Do nothing
2808 }
2809}
2810
2811#define F1(x, y, z) (z ^ (x & (y ^ z)))
2812#define F2(x, y, z) F1(z, x, y)
2813#define F3(x, y, z) (x ^ y ^ z)
2814#define F4(x, y, z) (y ^ (x | ~z))
2815
2816#define MD5STEP(f, w, x, y, z, data, s) \
2817 (w += f(x, y, z) + data, w = w << s | w >> (32 - s), w += x)
2818
2819/*
2820 * Start MD5 accumulation. Set bit count to 0 and buffer to mysterious
2821 * initialization constants.
2822 */
2823void mg_md5_init(mg_md5_ctx *ctx) {
2824 ctx->buf[0] = 0x67452301;
2825 ctx->buf[1] = 0xefcdab89;
2826 ctx->buf[2] = 0x98badcfe;
2827 ctx->buf[3] = 0x10325476;
2828
2829 ctx->bits[0] = 0;
2830 ctx->bits[1] = 0;
2831}
2832
2833static void mg_md5_transform(uint32_t buf[4], uint32_t const in[16]) {
2834 uint32_t a, b, c, d;
2835
2836 a = buf[0];
2837 b = buf[1];
2838 c = buf[2];
2839 d = buf[3];
2840
2841 MD5STEP(F1, a, b, c, d, in[0] + 0xd76aa478, 7);
2842 MD5STEP(F1, d, a, b, c, in[1] + 0xe8c7b756, 12);
2843 MD5STEP(F1, c, d, a, b, in[2] + 0x242070db, 17);
2844 MD5STEP(F1, b, c, d, a, in[3] + 0xc1bdceee, 22);
2845 MD5STEP(F1, a, b, c, d, in[4] + 0xf57c0faf, 7);
2846 MD5STEP(F1, d, a, b, c, in[5] + 0x4787c62a, 12);
2847 MD5STEP(F1, c, d, a, b, in[6] + 0xa8304613, 17);
2848 MD5STEP(F1, b, c, d, a, in[7] + 0xfd469501, 22);
2849 MD5STEP(F1, a, b, c, d, in[8] + 0x698098d8, 7);
2850 MD5STEP(F1, d, a, b, c, in[9] + 0x8b44f7af, 12);
2851 MD5STEP(F1, c, d, a, b, in[10] + 0xffff5bb1, 17);
2852 MD5STEP(F1, b, c, d, a, in[11] + 0x895cd7be, 22);
2853 MD5STEP(F1, a, b, c, d, in[12] + 0x6b901122, 7);
2854 MD5STEP(F1, d, a, b, c, in[13] + 0xfd987193, 12);
2855 MD5STEP(F1, c, d, a, b, in[14] + 0xa679438e, 17);
2856 MD5STEP(F1, b, c, d, a, in[15] + 0x49b40821, 22);
2857
2858 MD5STEP(F2, a, b, c, d, in[1] + 0xf61e2562, 5);
2859 MD5STEP(F2, d, a, b, c, in[6] + 0xc040b340, 9);
2860 MD5STEP(F2, c, d, a, b, in[11] + 0x265e5a51, 14);
2861 MD5STEP(F2, b, c, d, a, in[0] + 0xe9b6c7aa, 20);
2862 MD5STEP(F2, a, b, c, d, in[5] + 0xd62f105d, 5);
2863 MD5STEP(F2, d, a, b, c, in[10] + 0x02441453, 9);
2864 MD5STEP(F2, c, d, a, b, in[15] + 0xd8a1e681, 14);
2865 MD5STEP(F2, b, c, d, a, in[4] + 0xe7d3fbc8, 20);
2866 MD5STEP(F2, a, b, c, d, in[9] + 0x21e1cde6, 5);
2867 MD5STEP(F2, d, a, b, c, in[14] + 0xc33707d6, 9);
2868 MD5STEP(F2, c, d, a, b, in[3] + 0xf4d50d87, 14);
2869 MD5STEP(F2, b, c, d, a, in[8] + 0x455a14ed, 20);
2870 MD5STEP(F2, a, b, c, d, in[13] + 0xa9e3e905, 5);
2871 MD5STEP(F2, d, a, b, c, in[2] + 0xfcefa3f8, 9);
2872 MD5STEP(F2, c, d, a, b, in[7] + 0x676f02d9, 14);
2873 MD5STEP(F2, b, c, d, a, in[12] + 0x8d2a4c8a, 20);
2874
2875 MD5STEP(F3, a, b, c, d, in[5] + 0xfffa3942, 4);
2876 MD5STEP(F3, d, a, b, c, in[8] + 0x8771f681, 11);
2877 MD5STEP(F3, c, d, a, b, in[11] + 0x6d9d6122, 16);
2878 MD5STEP(F3, b, c, d, a, in[14] + 0xfde5380c, 23);
2879 MD5STEP(F3, a, b, c, d, in[1] + 0xa4beea44, 4);
2880 MD5STEP(F3, d, a, b, c, in[4] + 0x4bdecfa9, 11);
2881 MD5STEP(F3, c, d, a, b, in[7] + 0xf6bb4b60, 16);
2882 MD5STEP(F3, b, c, d, a, in[10] + 0xbebfbc70, 23);
2883 MD5STEP(F3, a, b, c, d, in[13] + 0x289b7ec6, 4);
2884 MD5STEP(F3, d, a, b, c, in[0] + 0xeaa127fa, 11);
2885 MD5STEP(F3, c, d, a, b, in[3] + 0xd4ef3085, 16);
2886 MD5STEP(F3, b, c, d, a, in[6] + 0x04881d05, 23);
2887 MD5STEP(F3, a, b, c, d, in[9] + 0xd9d4d039, 4);
2888 MD5STEP(F3, d, a, b, c, in[12] + 0xe6db99e5, 11);
2889 MD5STEP(F3, c, d, a, b, in[15] + 0x1fa27cf8, 16);
2890 MD5STEP(F3, b, c, d, a, in[2] + 0xc4ac5665, 23);
2891
2892 MD5STEP(F4, a, b, c, d, in[0] + 0xf4292244, 6);
2893 MD5STEP(F4, d, a, b, c, in[7] + 0x432aff97, 10);
2894 MD5STEP(F4, c, d, a, b, in[14] + 0xab9423a7, 15);
2895 MD5STEP(F4, b, c, d, a, in[5] + 0xfc93a039, 21);
2896 MD5STEP(F4, a, b, c, d, in[12] + 0x655b59c3, 6);
2897 MD5STEP(F4, d, a, b, c, in[3] + 0x8f0ccc92, 10);
2898 MD5STEP(F4, c, d, a, b, in[10] + 0xffeff47d, 15);
2899 MD5STEP(F4, b, c, d, a, in[1] + 0x85845dd1, 21);
2900 MD5STEP(F4, a, b, c, d, in[8] + 0x6fa87e4f, 6);
2901 MD5STEP(F4, d, a, b, c, in[15] + 0xfe2ce6e0, 10);
2902 MD5STEP(F4, c, d, a, b, in[6] + 0xa3014314, 15);
2903 MD5STEP(F4, b, c, d, a, in[13] + 0x4e0811a1, 21);
2904 MD5STEP(F4, a, b, c, d, in[4] + 0xf7537e82, 6);
2905 MD5STEP(F4, d, a, b, c, in[11] + 0xbd3af235, 10);
2906 MD5STEP(F4, c, d, a, b, in[2] + 0x2ad7d2bb, 15);
2907 MD5STEP(F4, b, c, d, a, in[9] + 0xeb86d391, 21);
2908
2909 buf[0] += a;
2910 buf[1] += b;
2911 buf[2] += c;
2912 buf[3] += d;
2913}
2914
2915void mg_md5_update(mg_md5_ctx *ctx, const unsigned char *buf, size_t len) {
2916 uint32_t t;
2917
2918 t = ctx->bits[0];
2919 if ((ctx->bits[0] = t + ((uint32_t) len << 3)) < t) ctx->bits[1]++;
2920 ctx->bits[1] += (uint32_t) len >> 29;
2921
2922 t = (t >> 3) & 0x3f;
2923
2924 if (t) {
2925 unsigned char *p = (unsigned char *) ctx->in + t;
2926
2927 t = 64 - t;
2928 if (len < t) {
2929 memcpy(p, buf, len);
2930 return;
2931 }
2932 memcpy(p, buf, t);
2933 mg_byte_reverse(ctx->in, 16);
2934 mg_md5_transform(ctx->buf, (uint32_t *) ctx->in);
2935 buf += t;
2936 len -= t;
2937 }
2938
2939 while (len >= 64) {
2940 memcpy(ctx->in, buf, 64);
2941 mg_byte_reverse(ctx->in, 16);
2942 mg_md5_transform(ctx->buf, (uint32_t *) ctx->in);
2943 buf += 64;
2944 len -= 64;
2945 }
2946
2947 memcpy(ctx->in, buf, len);
2948}
2949
2950void mg_md5_final(mg_md5_ctx *ctx, unsigned char digest[16]) {
2951 unsigned count;
2952 unsigned char *p;
2953 uint32_t *a;
2954
2955 count = (ctx->bits[0] >> 3) & 0x3F;
2956
2957 p = ctx->in + count;
2958 *p++ = 0x80;
2959 count = 64 - 1 - count;
2960 if (count < 8) {
2961 memset(p, 0, count);
2962 mg_byte_reverse(ctx->in, 16);
2963 mg_md5_transform(ctx->buf, (uint32_t *) ctx->in);
2964 memset(ctx->in, 0, 56);
2965 } else {
2966 memset(p, 0, count - 8);
2967 }
2968 mg_byte_reverse(ctx->in, 14);
2969
2970 a = (uint32_t *) ctx->in;
2971 a[14] = ctx->bits[0];
2972 a[15] = ctx->bits[1];
2973
2974 mg_md5_transform(ctx->buf, (uint32_t *) ctx->in);
2975 mg_byte_reverse((unsigned char *) ctx->buf, 4);
2976 memcpy(digest, ctx->buf, 16);
2977 memset((char *) ctx, 0, sizeof(*ctx));
2978}
2979#endif
2980
2981#ifdef MG_ENABLE_LINES
2982#line 1 "src/mqtt.c"
2983#endif
2984
2985
2986
2987
2988
2989
2990
2991
2992#define MQTT_CLEAN_SESSION 0x02
2993#define MQTT_HAS_WILL 0x04
2994#define MQTT_WILL_RETAIN 0x20
2995#define MQTT_HAS_PASSWORD 0x40
2996#define MQTT_HAS_USER_NAME 0x80
2997
2998struct mg_mqtt_pmap {
2999 uint8_t id;
3000 uint8_t type;
3001};
3002
3003static const struct mg_mqtt_pmap s_prop_map[] = {
3004 {MQTT_PROP_PAYLOAD_FORMAT_INDICATOR, MQTT_PROP_TYPE_BYTE},
3005 {MQTT_PROP_MESSAGE_EXPIRY_INTERVAL, MQTT_PROP_TYPE_INT},
3006 {MQTT_PROP_CONTENT_TYPE, MQTT_PROP_TYPE_STRING},
3007 {MQTT_PROP_RESPONSE_TOPIC, MQTT_PROP_TYPE_STRING},
3008 {MQTT_PROP_CORRELATION_DATA, MQTT_PROP_TYPE_BINARY_DATA},
3009 {MQTT_PROP_SUBSCRIPTION_IDENTIFIER, MQTT_PROP_TYPE_VARIABLE_INT},
3010 {MQTT_PROP_SESSION_EXPIRY_INTERVAL, MQTT_PROP_TYPE_INT},
3011 {MQTT_PROP_ASSIGNED_CLIENT_IDENTIFIER, MQTT_PROP_TYPE_STRING},
3012 {MQTT_PROP_SERVER_KEEP_ALIVE, MQTT_PROP_TYPE_SHORT},
3013 {MQTT_PROP_AUTHENTICATION_METHOD, MQTT_PROP_TYPE_STRING},
3014 {MQTT_PROP_AUTHENTICATION_DATA, MQTT_PROP_TYPE_BINARY_DATA},
3015 {MQTT_PROP_REQUEST_PROBLEM_INFORMATION, MQTT_PROP_TYPE_BYTE},
3016 {MQTT_PROP_WILL_DELAY_INTERVAL, MQTT_PROP_TYPE_INT},
3017 {MQTT_PROP_REQUEST_RESPONSE_INFORMATION, MQTT_PROP_TYPE_BYTE},
3018 {MQTT_PROP_RESPONSE_INFORMATION, MQTT_PROP_TYPE_STRING},
3019 {MQTT_PROP_SERVER_REFERENCE, MQTT_PROP_TYPE_STRING},
3020 {MQTT_PROP_REASON_STRING, MQTT_PROP_TYPE_STRING},
3021 {MQTT_PROP_RECEIVE_MAXIMUM, MQTT_PROP_TYPE_SHORT},
3022 {MQTT_PROP_TOPIC_ALIAS_MAXIMUM, MQTT_PROP_TYPE_SHORT},
3023 {MQTT_PROP_TOPIC_ALIAS, MQTT_PROP_TYPE_SHORT},
3024 {MQTT_PROP_MAXIMUM_QOS, MQTT_PROP_TYPE_BYTE},
3025 {MQTT_PROP_RETAIN_AVAILABLE, MQTT_PROP_TYPE_BYTE},
3026 {MQTT_PROP_USER_PROPERTY, MQTT_PROP_TYPE_STRING_PAIR},
3027 {MQTT_PROP_MAXIMUM_PACKET_SIZE, MQTT_PROP_TYPE_INT},
3028 {MQTT_PROP_WILDCARD_SUBSCRIPTION_AVAILABLE, MQTT_PROP_TYPE_BYTE},
3029 {MQTT_PROP_SUBSCRIPTION_IDENTIFIER_AVAILABLE, MQTT_PROP_TYPE_BYTE},
3030 {MQTT_PROP_SHARED_SUBSCRIPTION_AVAILABLE, MQTT_PROP_TYPE_BYTE}};
3031
3032void mg_mqtt_send_header(struct mg_connection *c, uint8_t cmd, uint8_t flags,
3033 uint32_t len) {
3034 uint8_t buf[1 + sizeof(len)], *vlen = &buf[1];
3035 buf[0] = (uint8_t) ((cmd << 4) | flags);
3036 do {
3037 *vlen = len % 0x80;
3038 len /= 0x80;
3039 if (len > 0) *vlen |= 0x80;
3040 vlen++;
3041 } while (len > 0 && vlen < &buf[sizeof(buf)]);
3042 mg_send(c, buf, (size_t) (vlen - buf));
3043}
3044
3045static void mg_send_u16(struct mg_connection *c, uint16_t value) {
3046 mg_send(c, &value, sizeof(value));
3047}
3048
3049static void mg_send_u32(struct mg_connection *c, uint32_t value) {
3050 mg_send(c, &value, sizeof(value));
3051}
3052
3053static uint8_t compute_variable_length_size(size_t length) {
3054 uint8_t bytes_needed = 0;
3055 do {
3056 bytes_needed++;
3057 length /= 0x80;
3058 } while (length > 0);
3059 return bytes_needed;
3060}
3061
3062static int encode_variable_length(uint8_t *buf, size_t value) {
3063 int len = 0;
3064
3065 do {
3066 uint8_t byte = (uint8_t) (value % 128);
3067 value /= 128;
3068 if (value > 0) byte |= 0x80;
3069 buf[len++] = byte;
3070 } while (value > 0);
3071
3072 return len;
3073}
3074
3075static size_t decode_varint(const uint8_t *buf, size_t len, size_t *value) {
3076 uint32_t multiplier = 1;
3077 size_t offset;
3078 *value = 0;
3079
3080 for (offset = 0; offset < 4 && offset < len; offset++) {
3081 uint8_t encoded_byte = buf[offset];
3082 *value += (encoded_byte & 0x7F) * multiplier;
3083 multiplier *= 128;
3084
3085 if (!(encoded_byte & 0x80)) return offset + 1;
3086 }
3087
3088 return 0;
3089}
3090
3091static int mqtt_prop_type_by_id(uint8_t prop_id) {
3092 size_t i, num_properties = sizeof(s_prop_map) / sizeof(s_prop_map[0]);
3093 for (i = 0; i < num_properties; ++i) {
3094 if (s_prop_map[i].id == prop_id) return s_prop_map[i].type;
3095 }
3096 return -1; // Property ID not found
3097}
3098
3099// Returns the size of the properties section, without the
3100// size of the content's length
3101static size_t get_properties_length(struct mg_mqtt_prop *props, size_t count) {
3102 size_t i, size = 0;
3103 for (i = 0; i < count; i++) {
3104 size++; // identifier
3105 switch (mqtt_prop_type_by_id(props[i].id)) {
3106 case MQTT_PROP_TYPE_STRING_PAIR:
3107 size += (uint32_t) (props[i].val.len + props[i].key.len +
3108 2 * sizeof(uint16_t));
3109 break;
3110 case MQTT_PROP_TYPE_STRING:
3111 size += (uint32_t) (props[i].val.len + sizeof(uint16_t));
3112 break;
3113 case MQTT_PROP_TYPE_BINARY_DATA:
3114 size += (uint32_t) (props[i].val.len + sizeof(uint16_t));
3115 break;
3116 case MQTT_PROP_TYPE_VARIABLE_INT:
3117 size += compute_variable_length_size((uint32_t) props[i].iv);
3118 break;
3119 case MQTT_PROP_TYPE_INT:
3120 size += (uint32_t) sizeof(uint32_t);
3121 break;
3122 case MQTT_PROP_TYPE_SHORT:
3123 size += (uint32_t) sizeof(uint16_t);
3124 break;
3125 case MQTT_PROP_TYPE_BYTE:
3126 size += (uint32_t) sizeof(uint8_t);
3127 break;
3128 default:
3129 return size; // cannot parse further down
3130 }
3131 }
3132
3133 return size;
3134}
3135
3136// returns the entire size of the properties section, including the
3137// size of the variable length of the content
3138static size_t get_props_size(struct mg_mqtt_prop *props, size_t count) {
3139 size_t size = get_properties_length(props, count);
3140 size += compute_variable_length_size(size);
3141 return size;
3142}
3143
3144static void mg_send_mqtt_properties(struct mg_connection *c,
3145 struct mg_mqtt_prop *props, size_t nprops) {
3146 size_t total_size = get_properties_length(props, nprops);
3147 uint8_t buf_v[4] = {0, 0, 0, 0};
3148 uint8_t buf[4] = {0, 0, 0, 0};
3149 int i, len = encode_variable_length(buf, total_size);
3150
3151 mg_send(c, buf, (size_t) len);
3152 for (i = 0; i < (int) nprops; i++) {
3153 mg_send(c, &props[i].id, sizeof(props[i].id));
3154 switch (mqtt_prop_type_by_id(props[i].id)) {
3155 case MQTT_PROP_TYPE_STRING_PAIR:
3156 mg_send_u16(c, mg_htons((uint16_t) props[i].key.len));
3157 mg_send(c, props[i].key.ptr, props[i].key.len);
3158 mg_send_u16(c, mg_htons((uint16_t) props[i].val.len));
3159 mg_send(c, props[i].val.ptr, props[i].val.len);
3160 break;
3161 case MQTT_PROP_TYPE_BYTE:
3162 mg_send(c, &props[i].iv, sizeof(uint8_t));
3163 break;
3164 case MQTT_PROP_TYPE_SHORT:
3165 mg_send_u16(c, mg_htons((uint16_t) props[i].iv));
3166 break;
3167 case MQTT_PROP_TYPE_INT:
3168 mg_send_u32(c, mg_htonl((uint32_t) props[i].iv));
3169 break;
3170 case MQTT_PROP_TYPE_STRING:
3171 mg_send_u16(c, mg_htons((uint16_t) props[i].val.len));
3172 mg_send(c, props[i].val.ptr, props[i].val.len);
3173 break;
3174 case MQTT_PROP_TYPE_BINARY_DATA:
3175 mg_send_u16(c, mg_htons((uint16_t) props[i].val.len));
3176 mg_send(c, props[i].val.ptr, props[i].val.len);
3177 break;
3178 case MQTT_PROP_TYPE_VARIABLE_INT:
3179 len = encode_variable_length(buf_v, props[i].iv);
3180 mg_send(c, buf_v, (size_t) len);
3181 break;
3182 }
3183 }
3184}
3185
3186size_t mg_mqtt_next_prop(struct mg_mqtt_message *msg, struct mg_mqtt_prop *prop,
3187 size_t ofs) {
3188 uint8_t *i = (uint8_t *) msg->dgram.ptr + msg->props_start + ofs;
3189 uint8_t *end = (uint8_t *) msg->dgram.ptr + msg->dgram.len;
3190 size_t new_pos = ofs, len;
3191 prop->id = i[0];
3192
3193 if (ofs >= msg->dgram.len || ofs >= msg->props_start + msg->props_size)
3194 return 0;
3195 i++, new_pos++;
3196
3197 switch (mqtt_prop_type_by_id(prop->id)) {
3198 case MQTT_PROP_TYPE_STRING_PAIR:
3199 prop->key.len = (uint16_t) ((((uint16_t) i[0]) << 8) | i[1]);
3200 prop->key.ptr = (char *) i + 2;
3201 i += 2 + prop->key.len;
3202 prop->val.len = (uint16_t) ((((uint16_t) i[0]) << 8) | i[1]);
3203 prop->val.ptr = (char *) i + 2;
3204 new_pos += 2 * sizeof(uint16_t) + prop->val.len + prop->key.len;
3205 break;
3206 case MQTT_PROP_TYPE_BYTE:
3207 prop->iv = (uint8_t) i[0];
3208 new_pos++;
3209 break;
3210 case MQTT_PROP_TYPE_SHORT:
3211 prop->iv = (uint16_t) ((((uint16_t) i[0]) << 8) | i[1]);
3212 new_pos += sizeof(uint16_t);
3213 break;
3214 case MQTT_PROP_TYPE_INT:
3215 prop->iv = ((uint32_t) i[0] << 24) | ((uint32_t) i[1] << 16) |
3216 ((uint32_t) i[2] << 8) | i[3];
3217 new_pos += sizeof(uint32_t);
3218 break;
3219 case MQTT_PROP_TYPE_STRING:
3220 prop->val.len = (uint16_t) ((((uint16_t) i[0]) << 8) | i[1]);
3221 prop->val.ptr = (char *) i + 2;
3222 new_pos += 2 + prop->val.len;
3223 break;
3224 case MQTT_PROP_TYPE_BINARY_DATA:
3225 prop->val.len = (uint16_t) ((((uint16_t) i[0]) << 8) | i[1]);
3226 prop->val.ptr = (char *) i + 2;
3227 new_pos += 2 + prop->val.len;
3228 break;
3229 case MQTT_PROP_TYPE_VARIABLE_INT:
3230 len = decode_varint(i, (size_t) (end - i), (size_t *) &prop->iv);
3231 new_pos = (!len) ? 0 : new_pos + len;
3232 break;
3233 default:
3234 new_pos = 0;
3235 }
3236
3237 return new_pos;
3238}
3239
3240void mg_mqtt_login(struct mg_connection *c, const struct mg_mqtt_opts *opts) {
3241 char rnd[10], client_id[21];
3242 struct mg_str cid = opts->client_id;
3243 size_t total_len = 7 + 1 + 2 + 2;
3244 uint8_t hdr[8] = {0, 4, 'M', 'Q', 'T', 'T', opts->version, 0};
3245
3246 if (cid.len == 0) {
3247 mg_random(rnd, sizeof(rnd));
3248 mg_hex(rnd, sizeof(rnd), client_id);
3249 client_id[sizeof(client_id) - 1] = '\0';
3250 cid = mg_str(client_id);
3251 }
3252
3253 if (hdr[6] == 0) hdr[6] = 4; // If version is not set, use 4 (3.1.1)
3254 c->is_mqtt5 = hdr[6] == 5; // Set version 5 flag
3255 hdr[7] = (uint8_t) ((opts->qos & 3) << 3); // Connection flags
3256 if (opts->user.len > 0) {
3257 total_len += 2 + (uint32_t) opts->user.len;
3258 hdr[7] |= MQTT_HAS_USER_NAME;
3259 }
3260 if (opts->pass.len > 0) {
3261 total_len += 2 + (uint32_t) opts->pass.len;
3262 hdr[7] |= MQTT_HAS_PASSWORD;
3263 }
3264 if (opts->topic.len > 0 && opts->message.len > 0) {
3265 total_len += 4 + (uint32_t) opts->topic.len + (uint32_t) opts->message.len;
3266 hdr[7] |= MQTT_HAS_WILL;
3267 }
3268 if (opts->clean || cid.len == 0) hdr[7] |= MQTT_CLEAN_SESSION;
3269 if (opts->retain) hdr[7] |= MQTT_WILL_RETAIN;
3270 total_len += (uint32_t) cid.len;
3271 if (c->is_mqtt5) {
3272 total_len += get_props_size(opts->props, opts->num_props);
3273 if (hdr[7] & MQTT_HAS_WILL)
3274 total_len += get_props_size(opts->will_props, opts->num_will_props);
3275 }
3276
3277 mg_mqtt_send_header(c, MQTT_CMD_CONNECT, 0, (uint32_t) total_len);
3278 mg_send(c, hdr, sizeof(hdr));
3279 // keepalive == 0 means "do not disconnect us!"
3280 mg_send_u16(c, mg_htons((uint16_t) opts->keepalive));
3281
3282 if (c->is_mqtt5) mg_send_mqtt_properties(c, opts->props, opts->num_props);
3283
3284 mg_send_u16(c, mg_htons((uint16_t) cid.len));
3285 mg_send(c, cid.ptr, cid.len);
3286
3287 if (hdr[7] & MQTT_HAS_WILL) {
3288 if (c->is_mqtt5)
3289 mg_send_mqtt_properties(c, opts->will_props, opts->num_will_props);
3290
3291 mg_send_u16(c, mg_htons((uint16_t) opts->topic.len));
3292 mg_send(c, opts->topic.ptr, opts->topic.len);
3293 mg_send_u16(c, mg_htons((uint16_t) opts->message.len));
3294 mg_send(c, opts->message.ptr, opts->message.len);
3295 }
3296 if (opts->user.len > 0) {
3297 mg_send_u16(c, mg_htons((uint16_t) opts->user.len));
3298 mg_send(c, opts->user.ptr, opts->user.len);
3299 }
3300 if (opts->pass.len > 0) {
3301 mg_send_u16(c, mg_htons((uint16_t) opts->pass.len));
3302 mg_send(c, opts->pass.ptr, opts->pass.len);
3303 }
3304}
3305
3306void mg_mqtt_pub(struct mg_connection *c, const struct mg_mqtt_opts *opts) {
3307 uint8_t flags = (uint8_t) (((opts->qos & 3) << 1) | (opts->retain ? 1 : 0));
3308 size_t len = 2 + opts->topic.len + opts->message.len;
3309 MG_DEBUG(("%lu [%.*s] -> [%.*s]", c->id, (int) opts->topic.len,
3310 (char *) opts->topic.ptr, (int) opts->message.len,
3311 (char *) opts->message.ptr));
3312 if (opts->qos > 0) len += 2;
3313 if (c->is_mqtt5) len += get_props_size(opts->props, opts->num_props);
3314
3315 mg_mqtt_send_header(c, MQTT_CMD_PUBLISH, flags, (uint32_t) len);
3316 mg_send_u16(c, mg_htons((uint16_t) opts->topic.len));
3317 mg_send(c, opts->topic.ptr, opts->topic.len);
3318 if (opts->qos > 0) {
3319 if (++c->mgr->mqtt_id == 0) ++c->mgr->mqtt_id;
3320 mg_send_u16(c, mg_htons(c->mgr->mqtt_id));
3321 }
3322
3323 if (c->is_mqtt5) mg_send_mqtt_properties(c, opts->props, opts->num_props);
3324
3325 mg_send(c, opts->message.ptr, opts->message.len);
3326}
3327
3328void mg_mqtt_sub(struct mg_connection *c, const struct mg_mqtt_opts *opts) {
3329 uint8_t qos_ = opts->qos & 3;
3330 size_t plen = c->is_mqtt5 ? get_props_size(opts->props, opts->num_props) : 0;
3331 size_t len = 2 + opts->topic.len + 2 + 1 + plen;
3332
3333 mg_mqtt_send_header(c, MQTT_CMD_SUBSCRIBE, 2, (uint32_t) len);
3334 if (++c->mgr->mqtt_id == 0) ++c->mgr->mqtt_id;
3335 mg_send_u16(c, mg_htons(c->mgr->mqtt_id));
3336 if (c->is_mqtt5) mg_send_mqtt_properties(c, opts->props, opts->num_props);
3337
3338 mg_send_u16(c, mg_htons((uint16_t) opts->topic.len));
3339 mg_send(c, opts->topic.ptr, opts->topic.len);
3340 mg_send(c, &qos_, sizeof(qos_));
3341}
3342
3343int mg_mqtt_parse(const uint8_t *buf, size_t len, uint8_t version,
3344 struct mg_mqtt_message *m) {
3345 uint8_t lc = 0, *p, *end;
3346 uint32_t n = 0, len_len = 0;
3347
3348 memset(m, 0, sizeof(*m));
3349 m->dgram.ptr = (char *) buf;
3350 if (len < 2) return MQTT_INCOMPLETE;
3351 m->cmd = (uint8_t) (buf[0] >> 4);
3352 m->qos = (buf[0] >> 1) & 3;
3353
3354 n = len_len = 0;
3355 p = (uint8_t *) buf + 1;
3356 while ((size_t) (p - buf) < len) {
3357 lc = *((uint8_t *) p++);
3358 n += (uint32_t) ((lc & 0x7f) << 7 * len_len);
3359 len_len++;
3360 if (!(lc & 0x80)) break;
3361 if (len_len >= 4) return MQTT_MALFORMED;
3362 }
3363 end = p + n;
3364 if ((lc & 0x80) || (end > buf + len)) return MQTT_INCOMPLETE;
3365 m->dgram.len = (size_t) (end - buf);
3366
3367 switch (m->cmd) {
3368 case MQTT_CMD_CONNACK:
3369 if (end - p < 2) return MQTT_MALFORMED;
3370 m->ack = p[1];
3371 break;
3372 case MQTT_CMD_PUBACK:
3373 case MQTT_CMD_PUBREC:
3374 case MQTT_CMD_PUBREL:
3375 case MQTT_CMD_PUBCOMP:
3376 case MQTT_CMD_SUBSCRIBE:
3377 case MQTT_CMD_SUBACK:
3378 case MQTT_CMD_UNSUBSCRIBE:
3379 case MQTT_CMD_UNSUBACK:
3380 if (p + 2 > end) return MQTT_MALFORMED;
3381 m->id = (uint16_t) ((((uint16_t) p[0]) << 8) | p[1]);
3382 p += 2;
3383 break;
3384 case MQTT_CMD_PUBLISH: {
3385 if (p + 2 > end) return MQTT_MALFORMED;
3386 m->topic.len = (uint16_t) ((((uint16_t) p[0]) << 8) | p[1]);
3387 m->topic.ptr = (char *) p + 2;
3388 p += 2 + m->topic.len;
3389 if (p > end) return MQTT_MALFORMED;
3390 if (m->qos > 0) {
3391 if (p + 2 > end) return MQTT_MALFORMED;
3392 m->id = (uint16_t) ((((uint16_t) p[0]) << 8) | p[1]);
3393 p += 2;
3394 }
3395 if (p > end) return MQTT_MALFORMED;
3396 if (version == 5 && p + 2 < end) {
3397 len_len = (uint32_t) decode_varint(p, (size_t) (end - p), &m->props_size);
3398 if (!len_len) return MQTT_MALFORMED;
3399 m->props_start = (size_t) (p + len_len - buf);
3400 p += len_len + m->props_size;
3401 }
3402 if (p > end) return MQTT_MALFORMED;
3403 m->data.ptr = (char *) p;
3404 m->data.len = (size_t) (end - p);
3405 break;
3406 }
3407 default:
3408 break;
3409 }
3410 return MQTT_OK;
3411}
3412
3413static void mqtt_cb(struct mg_connection *c, int ev, void *ev_data,
3414 void *fn_data) {
3415 if (ev == MG_EV_READ) {
3416 for (;;) {
3417 uint8_t version = c->is_mqtt5 ? 5 : 4;
3418 struct mg_mqtt_message mm;
3419 int rc = mg_mqtt_parse(c->recv.buf, c->recv.len, version, &mm);
3420 if (rc == MQTT_MALFORMED) {
3421 MG_ERROR(("%lu MQTT malformed message", c->id));
3422 c->is_closing = 1;
3423 break;
3424 } else if (rc == MQTT_OK) {
3425 MG_VERBOSE(("%lu MQTT CMD %d len %d [%.*s]", c->id, mm.cmd,
3426 (int) mm.dgram.len, (int) mm.data.len, mm.data.ptr));
3427 switch (mm.cmd) {
3428 case MQTT_CMD_CONNACK:
3429 mg_call(c, MG_EV_MQTT_OPEN, &mm.ack);
3430 if (mm.ack == 0) {
3431 MG_DEBUG(("%lu Connected", c->id));
3432 } else {
3433 MG_ERROR(("%lu MQTT auth failed, code %d", c->id, mm.ack));
3434 c->is_closing = 1;
3435 }
3436 break;
3437 case MQTT_CMD_PUBLISH: {
3438 MG_DEBUG(("%lu [%.*s] -> [%.*s]", c->id, (int) mm.topic.len,
3439 mm.topic.ptr, (int) mm.data.len, mm.data.ptr));
3440 if (mm.qos > 0) {
3441 uint16_t id = mg_ntohs(mm.id);
3442 uint32_t remaining_len = sizeof(id);
3443 if (c->is_mqtt5) remaining_len += 2; // 3.4.2
3444
3445 mg_mqtt_send_header(
3446 c, mm.qos == 2 ? MQTT_CMD_PUBREC : MQTT_CMD_PUBACK, 0,
3447 remaining_len);
3448 mg_send(c, &id, sizeof(id));
3449
3450 if (c->is_mqtt5) {
3451 uint16_t zero = 0;
3452 mg_send(c, &zero, sizeof(zero));
3453 }
3454 }
3455 mg_call(c, MG_EV_MQTT_MSG, &mm); // let the app handle qos stuff
3456 break;
3457 }
3458 case MQTT_CMD_PUBREC: { // MQTT5: 3.5.2-1 TODO(): variable header rc
3459 uint16_t id = mg_ntohs(mm.id);
3460 uint32_t remaining_len = sizeof(id); // MQTT5 3.6.2-1
3461 mg_mqtt_send_header(c, MQTT_CMD_PUBREL, 2, remaining_len);
3462 mg_send(c, &id, sizeof(id)); // MQTT5 3.6.1-1, flags = 2
3463 break;
3464 }
3465 case MQTT_CMD_PUBREL: { // MQTT5: 3.6.2-1 TODO(): variable header rc
3466 uint16_t id = mg_ntohs(mm.id);
3467 uint32_t remaining_len = sizeof(id); // MQTT5 3.7.2-1
3468 mg_mqtt_send_header(c, MQTT_CMD_PUBCOMP, 0, remaining_len);
3469 mg_send(c, &id, sizeof(id));
3470 break;
3471 }
3472 }
3473 mg_call(c, MG_EV_MQTT_CMD, &mm);
3474 mg_iobuf_del(&c->recv, 0, mm.dgram.len);
3475 } else {
3476 break;
3477 }
3478 }
3479 }
3480 (void) ev_data;
3481 (void) fn_data;
3482}
3483
3484void mg_mqtt_ping(struct mg_connection *nc) {
3485 mg_mqtt_send_header(nc, MQTT_CMD_PINGREQ, 0, 0);
3486}
3487
3488void mg_mqtt_pong(struct mg_connection *nc) {
3489 mg_mqtt_send_header(nc, MQTT_CMD_PINGRESP, 0, 0);
3490}
3491
3492void mg_mqtt_disconnect(struct mg_connection *c,
3493 const struct mg_mqtt_opts *opts) {
3494 size_t len = 0;
3495 if (c->is_mqtt5) len = 1 + get_props_size(opts->props, opts->num_props);
3496 mg_mqtt_send_header(c, MQTT_CMD_DISCONNECT, 0, (uint32_t) len);
3497
3498 if (c->is_mqtt5) {
3499 uint8_t zero = 0;
3500 mg_send(c, &zero, sizeof(zero)); // reason code
3501 mg_send_mqtt_properties(c, opts->props, opts->num_props);
3502 }
3503}
3504
3505struct mg_connection *mg_mqtt_connect(struct mg_mgr *mgr, const char *url,
3506 const struct mg_mqtt_opts *opts,
3507 mg_event_handler_t fn, void *fn_data) {
3508 struct mg_connection *c = mg_connect(mgr, url, fn, fn_data);
3509 if (c != NULL) {
3510 struct mg_mqtt_opts empty;
3511 memset(&empty, 0, sizeof(empty));
3512 mg_mqtt_login(c, opts == NULL ? &empty : opts);
3513 c->pfn = mqtt_cb;
3514 }
3515 return c;
3516}
3517
3518struct mg_connection *mg_mqtt_listen(struct mg_mgr *mgr, const char *url,
3519 mg_event_handler_t fn, void *fn_data) {
3520 struct mg_connection *c = mg_listen(mgr, url, fn, fn_data);
3521 if (c != NULL) c->pfn = mqtt_cb, c->pfn_data = mgr;
3522 return c;
3523}
3524
3525#ifdef MG_ENABLE_LINES
3526#line 1 "src/net.c"
3527#endif
3528
3529
3530
3531
3532
3533
3534
3535
3536size_t mg_vprintf(struct mg_connection *c, const char *fmt, va_list *ap) {
3537 size_t old = c->send.len;
3538 mg_vxprintf(mg_pfn_iobuf, &c->send, fmt, ap);
3539 return c->send.len - old;
3540}
3541
3542size_t mg_printf(struct mg_connection *c, const char *fmt, ...) {
3543 size_t len = 0;
3544 va_list ap;
3545 va_start(ap, fmt);
3546 len = mg_vprintf(c, fmt, &ap);
3547 va_end(ap);
3548 return len;
3549}
3550
3551static bool mg_atonl(struct mg_str str, struct mg_addr *addr) {
3552 uint32_t localhost = mg_htonl(0x7f000001);
3553 if (mg_vcasecmp(&str, "localhost") != 0) return false;
3554 memcpy(addr->ip, &localhost, sizeof(uint32_t));
3555 addr->is_ip6 = false;
3556 return true;
3557}
3558
3559static bool mg_atone(struct mg_str str, struct mg_addr *addr) {
3560 if (str.len > 0) return false;
3561 memset(addr->ip, 0, sizeof(addr->ip));
3562 addr->is_ip6 = false;
3563 return true;
3564}
3565
3566static bool mg_aton4(struct mg_str str, struct mg_addr *addr) {
3567 uint8_t data[4] = {0, 0, 0, 0};
3568 size_t i, num_dots = 0;
3569 for (i = 0; i < str.len; i++) {
3570 if (str.ptr[i] >= '0' && str.ptr[i] <= '9') {
3571 int octet = data[num_dots] * 10 + (str.ptr[i] - '0');
3572 if (octet > 255) return false;
3573 data[num_dots] = (uint8_t) octet;
3574 } else if (str.ptr[i] == '.') {
3575 if (num_dots >= 3 || i == 0 || str.ptr[i - 1] == '.') return false;
3576 num_dots++;
3577 } else {
3578 return false;
3579 }
3580 }
3581 if (num_dots != 3 || str.ptr[i - 1] == '.') return false;
3582 memcpy(&addr->ip, data, sizeof(data));
3583 addr->is_ip6 = false;
3584 return true;
3585}
3586
3587static bool mg_v4mapped(struct mg_str str, struct mg_addr *addr) {
3588 int i;
3589 uint32_t ipv4;
3590 if (str.len < 14) return false;
3591 if (str.ptr[0] != ':' || str.ptr[1] != ':' || str.ptr[6] != ':') return false;
3592 for (i = 2; i < 6; i++) {
3593 if (str.ptr[i] != 'f' && str.ptr[i] != 'F') return false;
3594 }
3595 //struct mg_str s = mg_str_n(&str.ptr[7], str.len - 7);
3596 if (!mg_aton4(mg_str_n(&str.ptr[7], str.len - 7), addr)) return false;
3597 memcpy(&ipv4, addr->ip, sizeof(ipv4));
3598 memset(addr->ip, 0, sizeof(addr->ip));
3599 addr->ip[10] = addr->ip[11] = 255;
3600 memcpy(&addr->ip[12], &ipv4, 4);
3601 addr->is_ip6 = true;
3602 return true;
3603}
3604
3605static bool mg_aton6(struct mg_str str, struct mg_addr *addr) {
3606 size_t i, j = 0, n = 0, dc = 42;
3607 if (str.len > 2 && str.ptr[0] == '[') str.ptr++, str.len -= 2;
3608 if (mg_v4mapped(str, addr)) return true;
3609 for (i = 0; i < str.len; i++) {
3610 if ((str.ptr[i] >= '0' && str.ptr[i] <= '9') ||
3611 (str.ptr[i] >= 'a' && str.ptr[i] <= 'f') ||
3612 (str.ptr[i] >= 'A' && str.ptr[i] <= 'F')) {
3613 unsigned long val;
3614 if (i > j + 3) return false;
3615 // MG_DEBUG(("%zu %zu [%.*s]", i, j, (int) (i - j + 1), &str.ptr[j]));
3616 val = mg_unhexn(&str.ptr[j], i - j + 1);
3617 addr->ip[n] = (uint8_t) ((val >> 8) & 255);
3618 addr->ip[n + 1] = (uint8_t) (val & 255);
3619 } else if (str.ptr[i] == ':') {
3620 j = i + 1;
3621 if (i > 0 && str.ptr[i - 1] == ':') {
3622 dc = n; // Double colon
3623 if (i > 1 && str.ptr[i - 2] == ':') return false;
3624 } else if (i > 0) {
3625 n += 2;
3626 }
3627 if (n > 14) return false;
3628 addr->ip[n] = addr->ip[n + 1] = 0; // For trailing ::
3629 } else {
3630 return false;
3631 }
3632 }
3633 if (n < 14 && dc == 42) return false;
3634 if (n < 14) {
3635 memmove(&addr->ip[dc + (14 - n)], &addr->ip[dc], n - dc + 2);
3636 memset(&addr->ip[dc], 0, 14 - n);
3637 }
3638
3639 addr->is_ip6 = true;
3640 return true;
3641}
3642
3643bool mg_aton(struct mg_str str, struct mg_addr *addr) {
3644 // MG_INFO(("[%.*s]", (int) str.len, str.ptr));
3645 return mg_atone(str, addr) || mg_atonl(str, addr) || mg_aton4(str, addr) ||
3646 mg_aton6(str, addr);
3647}
3648
3649struct mg_connection *mg_alloc_conn(struct mg_mgr *mgr) {
3650 struct mg_connection *c =
3651 (struct mg_connection *) calloc(1, sizeof(*c) + mgr->extraconnsize);
3652 if (c != NULL) {
3653 c->mgr = mgr;
3654 c->send.align = c->recv.align = MG_IO_SIZE;
3655 c->id = ++mgr->nextid;
3656 }
3657 return c;
3658}
3659
3660void mg_close_conn(struct mg_connection *c) {
3661 mg_resolve_cancel(c); // Close any pending DNS query
3662 LIST_DELETE(struct mg_connection, &c->mgr->conns, c);
3663 if (c == c->mgr->dns4.c) c->mgr->dns4.c = NULL;
3664 if (c == c->mgr->dns6.c) c->mgr->dns6.c = NULL;
3665 // Order of operations is important. `MG_EV_CLOSE` event must be fired
3666 // before we deallocate received data, see #1331
3667 mg_call(c, MG_EV_CLOSE, NULL);
3668 MG_DEBUG(("%lu %p closed", c->id, c->fd));
3669
3670 mg_tls_free(c);
3671 mg_iobuf_free(&c->recv);
3672 mg_iobuf_free(&c->send);
3673 memset(c, 0, sizeof(*c));
3674 free(c);
3675}
3676
3677struct mg_connection *mg_connect(struct mg_mgr *mgr, const char *url,
3678 mg_event_handler_t fn, void *fn_data) {
3679 struct mg_connection *c = NULL;
3680 if (url == NULL || url[0] == '\0') {
3681 MG_ERROR(("null url"));
3682 } else if ((c = mg_alloc_conn(mgr)) == NULL) {
3683 MG_ERROR(("OOM"));
3684 } else {
3685 LIST_ADD_HEAD(struct mg_connection, &mgr->conns, c);
3686 c->is_udp = (strncmp(url, "udp:", 4) == 0);
3687 c->fd = (void *) (size_t) MG_INVALID_SOCKET;
3688 c->fn = fn;
3689 c->is_client = true;
3690 c->fn_data = fn_data;
3691 MG_DEBUG(("%lu %p %s", c->id, c->fd, url));
3692 mg_call(c, MG_EV_OPEN, NULL);
3693 mg_resolve(c, url);
3694 }
3695 return c;
3696}
3697
3698struct mg_connection *mg_listen(struct mg_mgr *mgr, const char *url,
3699 mg_event_handler_t fn, void *fn_data) {
3700 struct mg_connection *c = NULL;
3701 if ((c = mg_alloc_conn(mgr)) == NULL) {
3702 MG_ERROR(("OOM %s", url));
3703 } else if (!mg_open_listener(c, url)) {
3704 MG_ERROR(("Failed: %s, errno %d", url, errno));
3705 free(c);
3706 c = NULL;
3707 } else {
3708 c->is_listening = 1;
3709 c->is_udp = strncmp(url, "udp:", 4) == 0;
3710 LIST_ADD_HEAD(struct mg_connection, &mgr->conns, c);
3711 c->fn = fn;
3712 c->fn_data = fn_data;
3713 mg_call(c, MG_EV_OPEN, NULL);
3714 MG_DEBUG(("%lu %p %s", c->id, c->fd, url));
3715 }
3716 return c;
3717}
3718
3719struct mg_connection *mg_wrapfd(struct mg_mgr *mgr, int fd,
3720 mg_event_handler_t fn, void *fn_data) {
3721 struct mg_connection *c = mg_alloc_conn(mgr);
3722 if (c != NULL) {
3723 c->fd = (void *) (size_t) fd;
3724 c->fn = fn;
3725 c->fn_data = fn_data;
3726 MG_EPOLL_ADD(c);
3727 mg_call(c, MG_EV_OPEN, NULL);
3728 LIST_ADD_HEAD(struct mg_connection, &mgr->conns, c);
3729 }
3730 return c;
3731}
3732
3733struct mg_timer *mg_timer_add(struct mg_mgr *mgr, uint64_t milliseconds,
3734 unsigned flags, void (*fn)(void *), void *arg) {
3735 struct mg_timer *t = (struct mg_timer *) calloc(1, sizeof(*t));
3736 if (t != NULL) {
3737 mg_timer_init(&mgr->timers, t, milliseconds, flags, fn, arg);
3738 t->id = mgr->timerid++;
3739 }
3740 return t;
3741}
3742
3743void mg_mgr_free(struct mg_mgr *mgr) {
3744 struct mg_connection *c;
3745 struct mg_timer *tmp, *t = mgr->timers;
3746 while (t != NULL) tmp = t->next, free(t), t = tmp;
3747 mgr->timers = NULL; // Important. Next call to poll won't touch timers
3748 for (c = mgr->conns; c != NULL; c = c->next) c->is_closing = 1;
3749 mg_mgr_poll(mgr, 0);
3750#if MG_ENABLE_FREERTOS_TCP
3751 FreeRTOS_DeleteSocketSet(mgr->ss);
3752#endif
3753 MG_DEBUG(("All connections closed"));
3754#if MG_ENABLE_EPOLL
3755 if (mgr->epoll_fd >= 0) close(mgr->epoll_fd), mgr->epoll_fd = -1;
3756#endif
3757}
3758
3759void mg_mgr_init(struct mg_mgr *mgr) {
3760 memset(mgr, 0, sizeof(*mgr));
3761#if MG_ENABLE_EPOLL
3762 if ((mgr->epoll_fd = epoll_create1(0)) < 0) MG_ERROR(("epoll: %d", errno));
3763#else
3764 mgr->epoll_fd = -1;
3765#endif
3766#if MG_ARCH == MG_ARCH_WIN32 && MG_ENABLE_WINSOCK
3767 // clang-format off
3768 { WSADATA data; WSAStartup(MAKEWORD(2, 2), &data); }
3769 // clang-format on
3770#elif MG_ENABLE_FREERTOS_TCP
3771 mgr->ss = FreeRTOS_CreateSocketSet();
3772#elif defined(__unix) || defined(__unix__) || defined(__APPLE__)
3773 // Ignore SIGPIPE signal, so if client cancels the request, it
3774 // won't kill the whole process.
3775 signal(SIGPIPE, SIG_IGN);
3776#endif
3777 mgr->dnstimeout = 3000;
3778 mgr->dns4.url = "udp://8.8.8.8:53";
3779 mgr->dns6.url = "udp://[2001:4860:4860::8888]:53";
3780}
3781
3782#ifdef MG_ENABLE_LINES
3783#line 1 "src/printf.c"
3784#endif
3785
3786
3787
3788
3789size_t mg_queue_vprintf(struct mg_queue *q, const char *fmt, va_list *ap) {
3790 size_t len = mg_snprintf(NULL, 0, fmt, ap);
3791 char *buf;
3792 if (len == 0 || mg_queue_book(q, &buf, len + 1) < len + 1) {
3793 len = 0; // Nah. Not enough space
3794 } else {
3795 len = mg_vsnprintf((char *) buf, len + 1, fmt, ap);
3796 mg_queue_add(q, len);
3797 }
3798 return len;
3799}
3800
3801size_t mg_queue_printf(struct mg_queue *q, const char *fmt, ...) {
3802 va_list ap;
3803 size_t len;
3804 va_start(ap, fmt);
3805 len = mg_queue_vprintf(q, fmt, &ap);
3806 va_end(ap);
3807 return len;
3808}
3809
3810static void mg_pfn_iobuf_private(char ch, void *param, bool expand) {
3811 struct mg_iobuf *io = (struct mg_iobuf *) param;
3812 if (expand && io->len + 2 > io->size) mg_iobuf_resize(io, io->len + 2);
3813 if (io->len + 2 <= io->size) {
3814 io->buf[io->len++] = (uint8_t) ch;
3815 io->buf[io->len] = 0;
3816 } else if (io->len < io->size) {
3817 io->buf[io->len++] = 0; // Guarantee to 0-terminate
3818 }
3819}
3820
3821static void mg_putchar_iobuf_static(char ch, void *param) {
3822 mg_pfn_iobuf_private(ch, param, false);
3823}
3824
3825void mg_pfn_iobuf(char ch, void *param) {
3826 mg_pfn_iobuf_private(ch, param, true);
3827}
3828
3829size_t mg_vsnprintf(char *buf, size_t len, const char *fmt, va_list *ap) {
3830 struct mg_iobuf io = {(uint8_t *) buf, len, 0, 0};
3831 size_t n = mg_vxprintf(mg_putchar_iobuf_static, &io, fmt, ap);
3832 if (n < len) buf[n] = '\0';
3833 return n;
3834}
3835
3836size_t mg_snprintf(char *buf, size_t len, const char *fmt, ...) {
3837 va_list ap;
3838 size_t n;
3839 va_start(ap, fmt);
3840 n = mg_vsnprintf(buf, len, fmt, &ap);
3841 va_end(ap);
3842 return n;
3843}
3844
3845char *mg_vmprintf(const char *fmt, va_list *ap) {
3846 struct mg_iobuf io = {0, 0, 0, 256};
3847 mg_vxprintf(mg_pfn_iobuf, &io, fmt, ap);
3848 return (char *) io.buf;
3849}
3850
3851char *mg_mprintf(const char *fmt, ...) {
3852 char *s;
3853 va_list ap;
3854 va_start(ap, fmt);
3855 s = mg_vmprintf(fmt, &ap);
3856 va_end(ap);
3857 return s;
3858}
3859
3860void mg_pfn_stdout(char c, void *param) {
3861 putchar(c);
3862 (void) param;
3863}
3864
3865static size_t print_ip4(void (*out)(char, void *), void *arg, uint8_t *p) {
3866 return mg_xprintf(out, arg, "%d.%d.%d.%d", p[0], p[1], p[2], p[3]);
3867}
3868
3869static size_t print_ip6(void (*out)(char, void *), void *arg, uint16_t *p) {
3870 return mg_xprintf(out, arg, "[%x:%x:%x:%x:%x:%x:%x:%x]", mg_ntohs(p[0]),
3871 mg_ntohs(p[1]), mg_ntohs(p[2]), mg_ntohs(p[3]),
3872 mg_ntohs(p[4]), mg_ntohs(p[5]), mg_ntohs(p[6]),
3873 mg_ntohs(p[7]));
3874}
3875
3876size_t mg_print_ip4(void (*out)(char, void *), void *arg, va_list *ap) {
3877 uint8_t *p = va_arg(*ap, uint8_t *);
3878 return print_ip4(out, arg, p);
3879}
3880
3881size_t mg_print_ip6(void (*out)(char, void *), void *arg, va_list *ap) {
3882 uint16_t *p = va_arg(*ap, uint16_t *);
3883 return print_ip6(out, arg, p);
3884}
3885
3886size_t mg_print_ip(void (*out)(char, void *), void *arg, va_list *ap) {
3887 struct mg_addr *addr = va_arg(*ap, struct mg_addr *);
3888 if (addr->is_ip6) return print_ip6(out, arg, (uint16_t *) addr->ip);
3889 return print_ip4(out, arg, (uint8_t *) &addr->ip);
3890}
3891
3892size_t mg_print_ip_port(void (*out)(char, void *), void *arg, va_list *ap) {
3893 struct mg_addr *a = va_arg(*ap, struct mg_addr *);
3894 return mg_xprintf(out, arg, "%M:%hu", mg_print_ip, a, mg_ntohs(a->port));
3895}
3896
3897size_t mg_print_mac(void (*out)(char, void *), void *arg, va_list *ap) {
3898 uint8_t *p = va_arg(*ap, uint8_t *);
3899 return mg_xprintf(out, arg, "%02x:%02x:%02x:%02x:%02x:%02x", p[0], p[1], p[2],
3900 p[3], p[4], p[5]);
3901}
3902
3903static char mg_esc(int c, bool esc) {
3904 const char *p, *esc1 = "\b\f\n\r\t\\\"", *esc2 = "bfnrt\\\"";
3905 for (p = esc ? esc1 : esc2; *p != '\0'; p++) {
3906 if (*p == c) return esc ? esc2[p - esc1] : esc1[p - esc2];
3907 }
3908 return 0;
3909}
3910
3911static char mg_escape(int c) {
3912 return mg_esc(c, true);
3913}
3914
3915static size_t qcpy(void (*out)(char, void *), void *ptr, char *buf,
3916 size_t len) {
3917 size_t i = 0, extra = 0;
3918 for (i = 0; i < len && buf[i] != '\0'; i++) {
3919 char c = mg_escape(buf[i]);
3920 if (c) {
3921 out('\\', ptr), out(c, ptr), extra++;
3922 } else {
3923 out(buf[i], ptr);
3924 }
3925 }
3926 return i + extra;
3927}
3928
3929static size_t bcpy(void (*out)(char, void *), void *arg, uint8_t *buf,
3930 size_t len) {
3931 size_t i, j, n = 0;
3932 const char *t =
3933 "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
3934 for (i = 0; i < len; i += 3) {
3935 uint8_t c1 = buf[i], c2 = i + 1 < len ? buf[i + 1] : 0,
3936 c3 = i + 2 < len ? buf[i + 2] : 0;
3937 char tmp[4] = {t[c1 >> 2], t[(c1 & 3) << 4 | (c2 >> 4)], '=', '='};
3938 if (i + 1 < len) tmp[2] = t[(c2 & 15) << 2 | (c3 >> 6)];
3939 if (i + 2 < len) tmp[3] = t[c3 & 63];
3940 for (j = 0; j < sizeof(tmp) && tmp[j] != '\0'; j++) out(tmp[j], arg);
3941 n += j;
3942 }
3943 return n;
3944}
3945
3946size_t mg_print_hex(void (*out)(char, void *), void *arg, va_list *ap) {
3947 size_t bl = (size_t) va_arg(*ap, int);
3948 uint8_t *p = va_arg(*ap, uint8_t *);
3949 const char *hex = "0123456789abcdef";
3950 size_t j;
3951 for (j = 0; j < bl; j++) {
3952 out(hex[(p[j] >> 4) & 0x0F], arg);
3953 out(hex[p[j] & 0x0F], arg);
3954 }
3955 return 2 * bl;
3956}
3957size_t mg_print_base64(void (*out)(char, void *), void *arg, va_list *ap) {
3958 size_t len = (size_t) va_arg(*ap, int);
3959 uint8_t *buf = va_arg(*ap, uint8_t *);
3960 return bcpy(out, arg, buf, len);
3961}
3962
3963size_t mg_print_esc(void (*out)(char, void *), void *arg, va_list *ap) {
3964 size_t len = (size_t) va_arg(*ap, int);
3965 char *p = va_arg(*ap, char *);
3966 if (len == 0) len = p == NULL ? 0 : strlen(p);
3967 return qcpy(out, arg, p, len);
3968}
3969
3970#ifdef MG_ENABLE_LINES
3971#line 1 "src/queue.c"
3972#endif
3973
3974
3975
3976#if defined(__GNUC__) || defined(__clang__)
3977#define MG_MEMORY_BARRIER() __sync_synchronize()
3978#elif defined(_MSC_VER) && _MSC_VER >= 1700
3979#define MG_MEMORY_BARRIER() MemoryBarrier()
3980#elif !defined(MG_MEMORY_BARRIER)
3981#define MG_MEMORY_BARRIER()
3982#endif
3983
3984// Every message in a queue is prepended by a 32-bit message length (ML).
3985// If ML is 0, then it is the end, and reader must wrap to the beginning.
3986//
3987// Queue when q->tail <= q->head:
3988// |----- free -----| ML | message1 | ML | message2 | ----- free ------|
3989// ^ ^ ^ ^
3990// buf tail head len
3991//
3992// Queue when q->tail > q->head:
3993// | ML | message2 |----- free ------| ML | message1 | 0 |---- free ----|
3994// ^ ^ ^ ^
3995// buf head tail len
3996
3997void mg_queue_init(struct mg_queue *q, char *buf, size_t size) {
3998 q->size = size;
3999 q->buf = buf;
4000 q->head = q->tail = 0;
4001}
4002
4003static size_t mg_queue_read_len(struct mg_queue *q) {
4004 uint32_t n = 0;
4005 MG_MEMORY_BARRIER();
4006 memcpy(&n, q->buf + q->tail, sizeof(n));
4007 assert(q->tail + n + sizeof(n) <= q->size);
4008 return n;
4009}
4010
4011static void mg_queue_write_len(struct mg_queue *q, size_t len) {
4012 uint32_t n = (uint32_t) len;
4013 memcpy(q->buf + q->head, &n, sizeof(n));
4014 MG_MEMORY_BARRIER();
4015}
4016
4017size_t mg_queue_book(struct mg_queue *q, char **buf, size_t len) {
4018 size_t space = 0, hs = sizeof(uint32_t) * 2; // *2 is for the 0 marker
4019 if (q->head >= q->tail && q->head + len + hs <= q->size) {
4020 space = q->size - q->head - hs; // There is enough space
4021 } else if (q->head >= q->tail && q->tail > hs) {
4022 mg_queue_write_len(q, 0); // Not enough space ahead
4023 q->head = 0; // Wrap head to the beginning
4024 }
4025 if (q->head + hs + len < q->tail) space = q->tail - q->head - hs;
4026 if (buf != NULL) *buf = q->buf + q->head + sizeof(uint32_t);
4027 return space;
4028}
4029
4030size_t mg_queue_next(struct mg_queue *q, char **buf) {
4031 size_t len = 0;
4032 if (q->tail != q->head) {
4033 len = mg_queue_read_len(q);
4034 if (len == 0) { // Zero (head wrapped) ?
4035 q->tail = 0; // Reset tail to the start
4036 if (q->head > q->tail) len = mg_queue_read_len(q); // Read again
4037 }
4038 }
4039 if (buf != NULL) *buf = q->buf + q->tail + sizeof(uint32_t);
4040 assert(q->tail + len <= q->size);
4041 return len;
4042}
4043
4044void mg_queue_add(struct mg_queue *q, size_t len) {
4045 assert(len > 0);
4046 mg_queue_write_len(q, len);
4047 assert(q->head + sizeof(uint32_t) * 2 + len <= q->size);
4048 q->head += len + sizeof(uint32_t);
4049}
4050
4051void mg_queue_del(struct mg_queue *q, size_t len) {
4052 q->tail += len + sizeof(uint32_t);
4053 assert(q->tail + sizeof(uint32_t) <= q->size);
4054}
4055
4056#ifdef MG_ENABLE_LINES
4057#line 1 "src/rpc.c"
4058#endif
4059
4060
4061
4062void mg_rpc_add(struct mg_rpc **head, struct mg_str method,
4063 void (*fn)(struct mg_rpc_req *), void *fn_data) {
4064 struct mg_rpc *rpc = (struct mg_rpc *) calloc(1, sizeof(*rpc));
4065 if (rpc != NULL) {
4066 rpc->method = mg_strdup(method), rpc->fn = fn, rpc->fn_data = fn_data;
4067 rpc->next = *head, *head = rpc;
4068 }
4069}
4070
4071void mg_rpc_del(struct mg_rpc **head, void (*fn)(struct mg_rpc_req *)) {
4072 struct mg_rpc *r;
4073 while ((r = *head) != NULL) {
4074 if (r->fn == fn || fn == NULL) {
4075 *head = r->next;
4076 free((void *) r->method.ptr);
4077 free(r);
4078 } else {
4079 head = &(*head)->next;
4080 }
4081 }
4082}
4083
4084static void mg_rpc_call(struct mg_rpc_req *r, struct mg_str method) {
4085 struct mg_rpc *h = r->head == NULL ? NULL : *r->head;
4086 while (h != NULL && !mg_match(method, h->method, NULL)) h = h->next;
4087 if (h != NULL) {
4088 r->rpc = h;
4089 h->fn(r);
4090 } else {
4091 mg_rpc_err(r, -32601, "\"%.*s not found\"", (int) method.len, method.ptr);
4092 }
4093}
4094
4095void mg_rpc_process(struct mg_rpc_req *r) {
4096 int len, off = mg_json_get(r->frame, "$.method", &len);
4097 if (off > 0 && r->frame.ptr[off] == '"') {
4098 struct mg_str method = mg_str_n(&r->frame.ptr[off + 1], (size_t) len - 2);
4099 mg_rpc_call(r, method);
4100 } else if ((off = mg_json_get(r->frame, "$.result", &len)) > 0 ||
4101 (off = mg_json_get(r->frame, "$.error", &len)) > 0) {
4102 mg_rpc_call(r, mg_str("")); // JSON response! call "" method handler
4103 } else {
4104 mg_rpc_err(r, -32700, "%m", mg_print_esc, (int) r->frame.len,
4105 r->frame.ptr); // Invalid
4106 }
4107}
4108
4109void mg_rpc_vok(struct mg_rpc_req *r, const char *fmt, va_list *ap) {
4110 int len, off = mg_json_get(r->frame, "$.id", &len);
4111 if (off > 0) {
4112 mg_xprintf(r->pfn, r->pfn_data, "{%m:%.*s,%m:", mg_print_esc, 0, "id", len,
4113 &r->frame.ptr[off], mg_print_esc, 0, "result");
4114 mg_vxprintf(r->pfn, r->pfn_data, fmt == NULL ? "null" : fmt, ap);
4115 mg_xprintf(r->pfn, r->pfn_data, "}");
4116 }
4117}
4118
4119void mg_rpc_ok(struct mg_rpc_req *r, const char *fmt, ...) {
4120 va_list ap;
4121 va_start(ap, fmt);
4122 mg_rpc_vok(r, fmt, &ap);
4123 va_end(ap);
4124}
4125
4126void mg_rpc_verr(struct mg_rpc_req *r, int code, const char *fmt, va_list *ap) {
4127 int len, off = mg_json_get(r->frame, "$.id", &len);
4128 mg_xprintf(r->pfn, r->pfn_data, "{");
4129 if (off > 0) {
4130 mg_xprintf(r->pfn, r->pfn_data, "%m:%.*s,", mg_print_esc, 0, "id", len,
4131 &r->frame.ptr[off]);
4132 }
4133 mg_xprintf(r->pfn, r->pfn_data, "%m:{%m:%d,%m:", mg_print_esc, 0, "error",
4134 mg_print_esc, 0, "code", code, mg_print_esc, 0, "message");
4135 mg_vxprintf(r->pfn, r->pfn_data, fmt == NULL ? "null" : fmt, ap);
4136 mg_xprintf(r->pfn, r->pfn_data, "}}");
4137}
4138
4139void mg_rpc_err(struct mg_rpc_req *r, int code, const char *fmt, ...) {
4140 va_list ap;
4141 va_start(ap, fmt);
4142 mg_rpc_verr(r, code, fmt, &ap);
4143 va_end(ap);
4144}
4145
4146static size_t print_methods(mg_pfn_t pfn, void *pfn_data, va_list *ap) {
4147 struct mg_rpc *h, **head = (struct mg_rpc **) va_arg(*ap, void **);
4148 size_t len = 0;
4149 for (h = *head; h != NULL; h = h->next) {
4150 if (h->method.len == 0) continue; // Ignore response handler
4151 len += mg_xprintf(pfn, pfn_data, "%s%m", h == *head ? "" : ",",
4152 mg_print_esc, (int) h->method.len, h->method.ptr);
4153 }
4154 return len;
4155}
4156
4157void mg_rpc_list(struct mg_rpc_req *r) {
4158 mg_rpc_ok(r, "[%M]", print_methods, r->head);
4159}
4160
4161#ifdef MG_ENABLE_LINES
4162#line 1 "src/sha1.c"
4163#endif
4164/* Copyright(c) By Steve Reid <steve@edmweb.com> */
4165/* 100% Public Domain */
4166
4167
4168
4169union char64long16 {
4170 unsigned char c[64];
4171 uint32_t l[16];
4172};
4173
4174#define rol(value, bits) (((value) << (bits)) | ((value) >> (32 - (bits))))
4175
4176static uint32_t blk0(union char64long16 *block, int i) {
4177 if (MG_BIG_ENDIAN) {
4178 } else {
4179 block->l[i] = (rol(block->l[i], 24) & 0xFF00FF00) |
4180 (rol(block->l[i], 8) & 0x00FF00FF);
4181 }
4182 return block->l[i];
4183}
4184
4185/* Avoid redefine warning (ARM /usr/include/sys/ucontext.h define R0~R4) */
4186#undef blk
4187#undef R0
4188#undef R1
4189#undef R2
4190#undef R3
4191#undef R4
4192
4193#define blk(i) \
4194 (block->l[i & 15] = rol(block->l[(i + 13) & 15] ^ block->l[(i + 8) & 15] ^ \
4195 block->l[(i + 2) & 15] ^ block->l[i & 15], \
4196 1))
4197#define R0(v, w, x, y, z, i) \
4198 z += ((w & (x ^ y)) ^ y) + blk0(block, i) + 0x5A827999 + rol(v, 5); \
4199 w = rol(w, 30);
4200#define R1(v, w, x, y, z, i) \
4201 z += ((w & (x ^ y)) ^ y) + blk(i) + 0x5A827999 + rol(v, 5); \
4202 w = rol(w, 30);
4203#define R2(v, w, x, y, z, i) \
4204 z += (w ^ x ^ y) + blk(i) + 0x6ED9EBA1 + rol(v, 5); \
4205 w = rol(w, 30);
4206#define R3(v, w, x, y, z, i) \
4207 z += (((w | x) & y) | (w & x)) + blk(i) + 0x8F1BBCDC + rol(v, 5); \
4208 w = rol(w, 30);
4209#define R4(v, w, x, y, z, i) \
4210 z += (w ^ x ^ y) + blk(i) + 0xCA62C1D6 + rol(v, 5); \
4211 w = rol(w, 30);
4212
4213static void mg_sha1_transform(uint32_t state[5],
4214 const unsigned char *buffer) {
4215 uint32_t a, b, c, d, e;
4216 union char64long16 block[1];
4217
4218 memcpy(block, buffer, 64);
4219 a = state[0];
4220 b = state[1];
4221 c = state[2];
4222 d = state[3];
4223 e = state[4];
4224 R0(a, b, c, d, e, 0);
4225 R0(e, a, b, c, d, 1);
4226 R0(d, e, a, b, c, 2);
4227 R0(c, d, e, a, b, 3);
4228 R0(b, c, d, e, a, 4);
4229 R0(a, b, c, d, e, 5);
4230 R0(e, a, b, c, d, 6);
4231 R0(d, e, a, b, c, 7);
4232 R0(c, d, e, a, b, 8);
4233 R0(b, c, d, e, a, 9);
4234 R0(a, b, c, d, e, 10);
4235 R0(e, a, b, c, d, 11);
4236 R0(d, e, a, b, c, 12);
4237 R0(c, d, e, a, b, 13);
4238 R0(b, c, d, e, a, 14);
4239 R0(a, b, c, d, e, 15);
4240 R1(e, a, b, c, d, 16);
4241 R1(d, e, a, b, c, 17);
4242 R1(c, d, e, a, b, 18);
4243 R1(b, c, d, e, a, 19);
4244 R2(a, b, c, d, e, 20);
4245 R2(e, a, b, c, d, 21);
4246 R2(d, e, a, b, c, 22);
4247 R2(c, d, e, a, b, 23);
4248 R2(b, c, d, e, a, 24);
4249 R2(a, b, c, d, e, 25);
4250 R2(e, a, b, c, d, 26);
4251 R2(d, e, a, b, c, 27);
4252 R2(c, d, e, a, b, 28);
4253 R2(b, c, d, e, a, 29);
4254 R2(a, b, c, d, e, 30);
4255 R2(e, a, b, c, d, 31);
4256 R2(d, e, a, b, c, 32);
4257 R2(c, d, e, a, b, 33);
4258 R2(b, c, d, e, a, 34);
4259 R2(a, b, c, d, e, 35);
4260 R2(e, a, b, c, d, 36);
4261 R2(d, e, a, b, c, 37);
4262 R2(c, d, e, a, b, 38);
4263 R2(b, c, d, e, a, 39);
4264 R3(a, b, c, d, e, 40);
4265 R3(e, a, b, c, d, 41);
4266 R3(d, e, a, b, c, 42);
4267 R3(c, d, e, a, b, 43);
4268 R3(b, c, d, e, a, 44);
4269 R3(a, b, c, d, e, 45);
4270 R3(e, a, b, c, d, 46);
4271 R3(d, e, a, b, c, 47);
4272 R3(c, d, e, a, b, 48);
4273 R3(b, c, d, e, a, 49);
4274 R3(a, b, c, d, e, 50);
4275 R3(e, a, b, c, d, 51);
4276 R3(d, e, a, b, c, 52);
4277 R3(c, d, e, a, b, 53);
4278 R3(b, c, d, e, a, 54);
4279 R3(a, b, c, d, e, 55);
4280 R3(e, a, b, c, d, 56);
4281 R3(d, e, a, b, c, 57);
4282 R3(c, d, e, a, b, 58);
4283 R3(b, c, d, e, a, 59);
4284 R4(a, b, c, d, e, 60);
4285 R4(e, a, b, c, d, 61);
4286 R4(d, e, a, b, c, 62);
4287 R4(c, d, e, a, b, 63);
4288 R4(b, c, d, e, a, 64);
4289 R4(a, b, c, d, e, 65);
4290 R4(e, a, b, c, d, 66);
4291 R4(d, e, a, b, c, 67);
4292 R4(c, d, e, a, b, 68);
4293 R4(b, c, d, e, a, 69);
4294 R4(a, b, c, d, e, 70);
4295 R4(e, a, b, c, d, 71);
4296 R4(d, e, a, b, c, 72);
4297 R4(c, d, e, a, b, 73);
4298 R4(b, c, d, e, a, 74);
4299 R4(a, b, c, d, e, 75);
4300 R4(e, a, b, c, d, 76);
4301 R4(d, e, a, b, c, 77);
4302 R4(c, d, e, a, b, 78);
4303 R4(b, c, d, e, a, 79);
4304 state[0] += a;
4305 state[1] += b;
4306 state[2] += c;
4307 state[3] += d;
4308 state[4] += e;
4309 /* Erase working structures. The order of operations is important,
4310 * used to ensure that compiler doesn't optimize those out. */
4311 memset(block, 0, sizeof(block));
4312 a = b = c = d = e = 0;
4313 (void) a;
4314 (void) b;
4315 (void) c;
4316 (void) d;
4317 (void) e;
4318}
4319
4320void mg_sha1_init(mg_sha1_ctx *context) {
4321 context->state[0] = 0x67452301;
4322 context->state[1] = 0xEFCDAB89;
4323 context->state[2] = 0x98BADCFE;
4324 context->state[3] = 0x10325476;
4325 context->state[4] = 0xC3D2E1F0;
4326 context->count[0] = context->count[1] = 0;
4327}
4328
4329void mg_sha1_update(mg_sha1_ctx *context, const unsigned char *data,
4330 size_t len) {
4331 size_t i, j;
4332
4333 j = context->count[0];
4334 if ((context->count[0] += (uint32_t) len << 3) < j) context->count[1]++;
4335 context->count[1] += (uint32_t) (len >> 29);
4336 j = (j >> 3) & 63;
4337 if ((j + len) > 63) {
4338 memcpy(&context->buffer[j], data, (i = 64 - j));
4339 mg_sha1_transform(context->state, context->buffer);
4340 for (; i + 63 < len; i += 64) {
4341 mg_sha1_transform(context->state, &data[i]);
4342 }
4343 j = 0;
4344 } else
4345 i = 0;
4346 memcpy(&context->buffer[j], &data[i], len - i);
4347}
4348
4349void mg_sha1_final(unsigned char digest[20], mg_sha1_ctx *context) {
4350 unsigned i;
4351 unsigned char finalcount[8], c;
4352
4353 for (i = 0; i < 8; i++) {
4354 finalcount[i] = (unsigned char) ((context->count[(i >= 4 ? 0 : 1)] >>
4355 ((3 - (i & 3)) * 8)) &
4356 255);
4357 }
4358 c = 0200;
4359 mg_sha1_update(context, &c, 1);
4360 while ((context->count[0] & 504) != 448) {
4361 c = 0000;
4362 mg_sha1_update(context, &c, 1);
4363 }
4364 mg_sha1_update(context, finalcount, 8);
4365 for (i = 0; i < 20; i++) {
4366 digest[i] =
4367 (unsigned char) ((context->state[i >> 2] >> ((3 - (i & 3)) * 8)) & 255);
4368 }
4369 memset(context, '\0', sizeof(*context));
4370 memset(&finalcount, '\0', sizeof(finalcount));
4371}
4372
4373#ifdef MG_ENABLE_LINES
4374#line 1 "src/sntp.c"
4375#endif
4376
4377
4378
4379
4380
4381
4382#define SNTP_TIME_OFFSET 2208988800U // (1970 - 1900) in seconds
4383#define SNTP_MAX_FRAC 4294967295.0 // 2 ** 32 - 1
4384
4385static int64_t gettimestamp(const uint32_t *data) {
4386 uint32_t sec = mg_ntohl(data[0]), frac = mg_ntohl(data[1]);
4387 if (sec) sec -= SNTP_TIME_OFFSET;
4388 return ((int64_t) sec) * 1000 + (int64_t) (frac / SNTP_MAX_FRAC * 1000.0);
4389}
4390
4391int64_t mg_sntp_parse(const unsigned char *buf, size_t len) {
4392 int64_t res = -1;
4393 int mode = len > 0 ? buf[0] & 7 : 0;
4394 int version = len > 0 ? (buf[0] >> 3) & 7 : 0;
4395 if (len < 48) {
4396 MG_ERROR(("%s", "corrupt packet"));
4397 } else if (mode != 4 && mode != 5) {
4398 MG_ERROR(("%s", "not a server reply"));
4399 } else if (buf[1] == 0) {
4400 MG_ERROR(("%s", "server sent a kiss of death"));
4401 } else if (version == 4 || version == 3) {
4402 // int64_t ref = gettimestamp((uint32_t *) &buf[16]);
4403 int64_t t0 = gettimestamp((uint32_t *) &buf[24]);
4404 int64_t t1 = gettimestamp((uint32_t *) &buf[32]);
4405 int64_t t2 = gettimestamp((uint32_t *) &buf[40]);
4406 int64_t t3 = (int64_t) mg_millis();
4407 int64_t delta = (t3 - t0) - (t2 - t1);
4408 MG_VERBOSE(("%lld %lld %lld %lld delta:%lld", t0, t1, t2, t3, delta));
4409 res = t2 + delta / 2;
4410 } else {
4411 MG_ERROR(("unexpected version: %d", version));
4412 }
4413 return res;
4414}
4415
4416static void sntp_cb(struct mg_connection *c, int ev, void *evd, void *fnd) {
4417 if (ev == MG_EV_READ) {
4418 int64_t milliseconds = mg_sntp_parse(c->recv.buf, c->recv.len);
4419 if (milliseconds > 0) {
4420 MG_INFO(("%lu got time: %lld ms from epoch", c->id, milliseconds));
4421 mg_call(c, MG_EV_SNTP_TIME, (uint64_t *) &milliseconds);
4422 MG_VERBOSE(("%u.%u", (unsigned) (milliseconds / 1000),
4423 (unsigned) (milliseconds % 1000)));
4424 }
4425 mg_iobuf_del(&c->recv, 0, c->recv.len); // Free receive buffer
4426 } else if (ev == MG_EV_CONNECT) {
4427 mg_sntp_request(c);
4428 } else if (ev == MG_EV_CLOSE) {
4429 }
4430 (void) fnd;
4431 (void) evd;
4432}
4433
4434void mg_sntp_request(struct mg_connection *c) {
4435 if (c->is_resolving) {
4436 MG_ERROR(("%lu wait until resolved", c->id));
4437 } else {
4438 int64_t now = (int64_t) mg_millis(); // Use int64_t, for vc98
4439 uint8_t buf[48] = {0};
4440 uint32_t *t = (uint32_t *) &buf[40];
4441 double frac = ((double) (now % 1000)) / 1000.0 * SNTP_MAX_FRAC;
4442 buf[0] = (0 << 6) | (4 << 3) | 3;
4443 t[0] = mg_htonl((uint32_t) (now / 1000) + SNTP_TIME_OFFSET);
4444 t[1] = mg_htonl((uint32_t) frac);
4445 mg_send(c, buf, sizeof(buf));
4446 }
4447}
4448
4449struct mg_connection *mg_sntp_connect(struct mg_mgr *mgr, const char *url,
4450 mg_event_handler_t fn, void *fnd) {
4451 struct mg_connection *c = NULL;
4452 if (url == NULL) url = "udp://time.google.com:123";
4453 if ((c = mg_connect(mgr, url, fn, fnd)) != NULL) c->pfn = sntp_cb;
4454 return c;
4455}
4456
4457#ifdef MG_ENABLE_LINES
4458#line 1 "src/sock.c"
4459#endif
4460
4461
4462
4463
4464
4465
4466
4467
4468
4469
4470
4471#if MG_ENABLE_SOCKET
4472
4473#ifndef closesocket
4474#define closesocket(x) close(x)
4475#endif
4476
4477#define FD(c_) ((MG_SOCKET_TYPE) (size_t) (c_)->fd)
4478#define S2PTR(s_) ((void *) (size_t) (s_))
4479
4480#ifndef MSG_NONBLOCKING
4481#define MSG_NONBLOCKING 0
4482#endif
4483
4484#ifndef AF_INET6
4485#define AF_INET6 10
4486#endif
4487
4488#ifndef MG_SOCK_ERR
4489#define MG_SOCK_ERR(errcode) ((errcode) < 0 ? errno : 0)
4490#endif
4491
4492#ifndef MG_SOCK_INTR
4493#define MG_SOCK_INTR(fd) (fd == MG_INVALID_SOCKET && MG_SOCK_ERR(-1) == EINTR)
4494#endif
4495
4496#ifndef MG_SOCK_PENDING
4497#define MG_SOCK_PENDING(errcode) \
4498 (((errcode) < 0) && (errno == EINPROGRESS || errno == EWOULDBLOCK))
4499#endif
4500
4501#ifndef MG_SOCK_RESET
4502#define MG_SOCK_RESET(errcode) \
4503 (((errcode) < 0) && (errno == EPIPE || errno == ECONNRESET))
4504#endif
4505
4506union usa {
4507 struct sockaddr sa;
4508 struct sockaddr_in sin;
4509#if MG_ENABLE_IPV6
4510 struct sockaddr_in6 sin6;
4511#endif
4512};
4513
4514static socklen_t tousa(struct mg_addr *a, union usa *usa) {
4515 socklen_t len = sizeof(usa->sin);
4516 memset(usa, 0, sizeof(*usa));
4517 usa->sin.sin_family = AF_INET;
4518 usa->sin.sin_port = a->port;
4519 memcpy(&usa->sin.sin_addr, a->ip, sizeof(uint32_t));
4520#if MG_ENABLE_IPV6
4521 if (a->is_ip6) {
4522 usa->sin.sin_family = AF_INET6;
4523 usa->sin6.sin6_port = a->port;
4524 memcpy(&usa->sin6.sin6_addr, a->ip, sizeof(a->ip));
4525 len = sizeof(usa->sin6);
4526 }
4527#endif
4528 return len;
4529}
4530
4531static void tomgaddr(union usa *usa, struct mg_addr *a, bool is_ip6) {
4532 a->is_ip6 = is_ip6;
4533 a->port = usa->sin.sin_port;
4534 memcpy(&a->ip, &usa->sin.sin_addr, sizeof(uint32_t));
4535#if MG_ENABLE_IPV6
4536 if (is_ip6) {
4537 memcpy(a->ip, &usa->sin6.sin6_addr, sizeof(a->ip));
4538 a->port = usa->sin6.sin6_port;
4539 }
4540#endif
4541}
4542
4543static void setlocaddr(MG_SOCKET_TYPE fd, struct mg_addr *addr) {
4544 union usa usa;
4545 socklen_t n = sizeof(usa);
4546 if (getsockname(fd, &usa.sa, &n) == 0) {
4547 tomgaddr(&usa, addr, n != sizeof(usa.sin));
4548 }
4549}
4550
4551static void iolog(struct mg_connection *c, char *buf, long n, bool r) {
4552 if (n == MG_IO_WAIT) {
4553 // Do nothing
4554 } else if (n <= 0) {
4555 c->is_closing = 1; // Termination. Don't call mg_error(): #1529
4556 } else if (n > 0) {
4557 if (c->is_hexdumping) {
4558 union usa usa;
4559 socklen_t slen = sizeof(usa.sin);
4560 if (getsockname(FD(c), &usa.sa, &slen) < 0) (void) 0; // Ignore result
4561 MG_INFO(("\n-- %lu %M %s %M %ld", c->id, mg_print_ip_port, &c->loc,
4562 r ? "<-" : "->", mg_print_ip_port, &c->rem, n));
4563
4564 mg_hexdump(buf, (size_t) n);
4565 }
4566 if (r) {
4567 c->recv.len += (size_t) n;
4568 mg_call(c, MG_EV_READ, &n);
4569 } else {
4570 mg_iobuf_del(&c->send, 0, (size_t) n);
4571 // if (c->send.len == 0) mg_iobuf_resize(&c->send, 0);
4572 if (c->send.len == 0) {
4573 MG_EPOLL_MOD(c, 0);
4574 }
4575 mg_call(c, MG_EV_WRITE, &n);
4576 }
4577 }
4578}
4579
4580long mg_io_send(struct mg_connection *c, const void *buf, size_t len) {
4581 long n;
4582 if (c->is_udp) {
4583 union usa usa;
4584 socklen_t slen = tousa(&c->rem, &usa);
4585 n = sendto(FD(c), (char *) buf, len, 0, &usa.sa, slen);
4586 if (n > 0) setlocaddr(FD(c), &c->loc);
4587 } else {
4588 n = send(FD(c), (char *) buf, len, MSG_NONBLOCKING);
4589 }
4590 if (MG_SOCK_PENDING(n)) return MG_IO_WAIT;
4591 if (MG_SOCK_RESET(n)) return MG_IO_RESET;
4592 if (n <= 0) return MG_IO_ERR;
4593 return n;
4594}
4595
4596bool mg_send(struct mg_connection *c, const void *buf, size_t len) {
4597 if (c->is_udp) {
4598 long n = mg_io_send(c, buf, len);
4599 MG_DEBUG(("%lu %p %d:%d %ld err %d", c->id, c->fd, (int) c->send.len,
4600 (int) c->recv.len, n, MG_SOCK_ERR(n)));
4601 iolog(c, (char *) buf, n, false);
4602 return n > 0;
4603 } else {
4604 return mg_iobuf_add(&c->send, c->send.len, buf, len);
4605 }
4606}
4607
4608static void mg_set_non_blocking_mode(MG_SOCKET_TYPE fd) {
4609#if defined(MG_CUSTOM_NONBLOCK)
4610 MG_CUSTOM_NONBLOCK(fd);
4611#elif MG_ARCH == MG_ARCH_WIN32 && MG_ENABLE_WINSOCK
4612 unsigned long on = 1;
4613 ioctlsocket(fd, FIONBIO, &on);
4614#elif MG_ENABLE_RL
4615 unsigned long on = 1;
4616 ioctlsocket(fd, FIONBIO, &on);
4617#elif MG_ENABLE_FREERTOS_TCP
4618 const BaseType_t off = 0;
4619 if (setsockopt(fd, 0, FREERTOS_SO_RCVTIMEO, &off, sizeof(off)) != 0) (void) 0;
4620 if (setsockopt(fd, 0, FREERTOS_SO_SNDTIMEO, &off, sizeof(off)) != 0) (void) 0;
4621#elif MG_ENABLE_LWIP
4622 lwip_fcntl(fd, F_SETFL, O_NONBLOCK);
4623#elif MG_ARCH == MG_ARCH_AZURERTOS
4624 fcntl(fd, F_SETFL, O_NONBLOCK);
4625#elif MG_ARCH == MG_ARCH_TIRTOS
4626 int val = 0;
4627 setsockopt(fd, SOL_SOCKET, SO_BLOCKING, &val, sizeof(val));
4628 // SPRU524J section 3.3.3 page 63, SO_SNDLOWAT
4629 int sz = sizeof(val);
4630 getsockopt(fd, SOL_SOCKET, SO_SNDBUF, &val, &sz);
4631 val /= 2; // set send low-water mark at half send buffer size
4632 setsockopt(fd, SOL_SOCKET, SO_SNDLOWAT, &val, sizeof(val));
4633#else
4634 fcntl(fd, F_SETFL, fcntl(fd, F_GETFL, 0) | O_NONBLOCK); // Non-blocking mode
4635 fcntl(fd, F_SETFD, FD_CLOEXEC); // Set close-on-exec
4636#endif
4637}
4638
4639bool mg_open_listener(struct mg_connection *c, const char *url) {
4640 MG_SOCKET_TYPE fd = MG_INVALID_SOCKET;
4641 bool success = false;
4642 c->loc.port = mg_htons(mg_url_port(url));
4643 if (!mg_aton(mg_url_host(url), &c->loc)) {
4644 MG_ERROR(("invalid listening URL: %s", url));
4645 } else {
4646 union usa usa;
4647 socklen_t slen = tousa(&c->loc, &usa);
4648 int rc, on = 1, af = c->loc.is_ip6 ? AF_INET6 : AF_INET;
4649 int type = strncmp(url, "udp:", 4) == 0 ? SOCK_DGRAM : SOCK_STREAM;
4650 int proto = type == SOCK_DGRAM ? IPPROTO_UDP : IPPROTO_TCP;
4651 (void) on;
4652
4653 if ((fd = socket(af, type, proto)) == MG_INVALID_SOCKET) {
4654 MG_ERROR(("socket: %d", MG_SOCK_ERR(-1)));
4655#if defined(SO_EXCLUSIVEADDRUSE)
4656 } else if ((rc = setsockopt(fd, SOL_SOCKET, SO_EXCLUSIVEADDRUSE,
4657 (char *) &on, sizeof(on))) != 0) {
4658 // "Using SO_REUSEADDR and SO_EXCLUSIVEADDRUSE"
4659 MG_ERROR(("setsockopt(SO_EXCLUSIVEADDRUSE): %d %d", on, MG_SOCK_ERR(rc)));
4660#elif defined(SO_REUSEADDR) && (!defined(LWIP_SOCKET) || SO_REUSE)
4661 } else if ((rc = setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, (char *) &on,
4662 sizeof(on))) != 0) {
4663 // 1. SO_REUSEADDR semantics on UNIX and Windows is different. On
4664 // Windows, SO_REUSEADDR allows to bind a socket to a port without error
4665 // even if the port is already open by another program. This is not the
4666 // behavior SO_REUSEADDR was designed for, and leads to hard-to-track
4667 // failure scenarios.
4668 //
4669 // 2. For LWIP, SO_REUSEADDR should be explicitly enabled by defining
4670 // SO_REUSE = 1 in lwipopts.h, otherwise the code below will compile but
4671 // won't work! (setsockopt will return EINVAL)
4672 MG_ERROR(("setsockopt(SO_REUSEADDR): %d", MG_SOCK_ERR(rc)));
4673#endif
4674#if defined(IPV6_V6ONLY)
4675 } else if (c->loc.is_ip6 &&
4676 (rc = setsockopt(fd, IPPROTO_IPV6, IPV6_V6ONLY, (char *) &on,
4677 sizeof(on))) != 0) {
4678 // See #2089. Allow to bind v4 and v6 sockets on the same port
4679 MG_ERROR(("setsockopt(IPV6_V6ONLY): %d", MG_SOCK_ERR(rc)));
4680#endif
4681 } else if ((rc = bind(fd, &usa.sa, slen)) != 0) {
4682 MG_ERROR(("bind: %d", MG_SOCK_ERR(rc)));
4683 } else if ((type == SOCK_STREAM &&
4684 (rc = listen(fd, MG_SOCK_LISTEN_BACKLOG_SIZE)) != 0)) {
4685 // NOTE(lsm): FreeRTOS uses backlog value as a connection limit
4686 // In case port was set to 0, get the real port number
4687 MG_ERROR(("listen: %d", MG_SOCK_ERR(rc)));
4688 } else {
4689 setlocaddr(fd, &c->loc);
4690 mg_set_non_blocking_mode(fd);
4691 c->fd = S2PTR(fd);
4692 MG_EPOLL_ADD(c);
4693 success = true;
4694 }
4695 }
4696 if (success == false && fd != MG_INVALID_SOCKET) closesocket(fd);
4697 return success;
4698}
4699
4700long mg_io_recv(struct mg_connection *c, void *buf, size_t len) {
4701 long n = 0;
4702 if (c->is_udp) {
4703 union usa usa;
4704 socklen_t slen = tousa(&c->rem, &usa);
4705 n = recvfrom(FD(c), (char *) buf, len, 0, &usa.sa, &slen);
4706 if (n > 0) tomgaddr(&usa, &c->rem, slen != sizeof(usa.sin));
4707 } else {
4708 n = recv(FD(c), (char *) buf, len, MSG_NONBLOCKING);
4709 }
4710 if (MG_SOCK_PENDING(n)) return MG_IO_WAIT;
4711 if (MG_SOCK_RESET(n)) return MG_IO_RESET;
4712 if (n <= 0) return MG_IO_ERR;
4713 return n;
4714}
4715
4716// NOTE(lsm): do only one iteration of reads, cause some systems
4717// (e.g. FreeRTOS stack) return 0 instead of -1/EWOULDBLOCK when no data
4718static void read_conn(struct mg_connection *c) {
4719 long n = -1;
4720 if (c->recv.len >= MG_MAX_RECV_SIZE) {
4721 mg_error(c, "max_recv_buf_size reached");
4722 } else if (c->recv.size <= c->recv.len &&
4723 !mg_iobuf_resize(&c->recv, c->recv.size + MG_IO_SIZE)) {
4724 mg_error(c, "oom");
4725 } else {
4726 char *buf = (char *) &c->recv.buf[c->recv.len];
4727 size_t len = c->recv.size - c->recv.len;
4728 n = c->is_tls ? mg_tls_recv(c, buf, len) : mg_io_recv(c, buf, len);
4729 MG_DEBUG(("%lu %p snd %ld/%ld rcv %ld/%ld n=%ld err=%d", c->id, c->fd,
4730 (long) c->send.len, (long) c->send.size, (long) c->recv.len,
4731 (long) c->recv.size, n, MG_SOCK_ERR(n)));
4732 iolog(c, buf, n, true);
4733 }
4734}
4735
4736static void write_conn(struct mg_connection *c) {
4737 char *buf = (char *) c->send.buf;
4738 size_t len = c->send.len;
4739 long n = c->is_tls ? mg_tls_send(c, buf, len) : mg_io_send(c, buf, len);
4740 MG_DEBUG(("%lu %p snd %ld/%ld rcv %ld/%ld n=%ld err=%d", c->id, c->fd,
4741 (long) c->send.len, (long) c->send.size, (long) c->recv.len,
4742 (long) c->recv.size, n, MG_SOCK_ERR(n)));
4743 iolog(c, buf, n, false);
4744}
4745
4746static void close_conn(struct mg_connection *c) {
4747 if (FD(c) != MG_INVALID_SOCKET) {
4748#if MG_ENABLE_EPOLL
4749 epoll_ctl(c->mgr->epoll_fd, EPOLL_CTL_DEL, FD(c), NULL);
4750#endif
4751 closesocket(FD(c));
4752#if MG_ENABLE_FREERTOS_TCP
4753 FreeRTOS_FD_CLR(c->fd, c->mgr->ss, eSELECT_ALL);
4754#endif
4755 }
4756 mg_close_conn(c);
4757}
4758
4759static void connect_conn(struct mg_connection *c) {
4760 union usa usa;
4761 socklen_t n = sizeof(usa);
4762 // Use getpeername() to test whether we have connected
4763 if (getpeername(FD(c), &usa.sa, &n) == 0) {
4764 c->is_connecting = 0;
4765 mg_call(c, MG_EV_CONNECT, NULL);
4766 MG_EPOLL_MOD(c, 0);
4767 if (c->is_tls_hs) mg_tls_handshake(c);
4768 } else {
4769 mg_error(c, "socket error");
4770 }
4771}
4772
4773static void setsockopts(struct mg_connection *c) {
4774#if MG_ENABLE_FREERTOS_TCP || MG_ARCH == MG_ARCH_AZURERTOS || \
4775 MG_ARCH == MG_ARCH_TIRTOS
4776 (void) c;
4777#else
4778 int on = 1;
4779#if !defined(SOL_TCP)
4780#define SOL_TCP IPPROTO_TCP
4781#endif
4782 if (setsockopt(FD(c), SOL_TCP, TCP_NODELAY, (char *) &on, sizeof(on)) != 0)
4783 (void) 0;
4784 if (setsockopt(FD(c), SOL_SOCKET, SO_KEEPALIVE, (char *) &on, sizeof(on)) !=
4785 0)
4786 (void) 0;
4787#endif
4788}
4789
4790void mg_connect_resolved(struct mg_connection *c) {
4791 int type = c->is_udp ? SOCK_DGRAM : SOCK_STREAM;
4792 int rc, af = c->rem.is_ip6 ? AF_INET6 : AF_INET; // c->rem has resolved IP
4793 c->fd = S2PTR(socket(af, type, 0)); // Create outbound socket
4794 c->is_resolving = 0; // Clear resolving flag
4795 if (FD(c) == MG_INVALID_SOCKET) {
4796 mg_error(c, "socket(): %d", MG_SOCK_ERR(-1));
4797 } else if (c->is_udp) {
4798 MG_EPOLL_ADD(c);
4799#if MG_ARCH == MG_ARCH_TIRTOS
4800 union usa usa; // TI-RTOS NDK requires binding to receive on UDP sockets
4801 socklen_t slen = tousa(&c->loc, &usa);
4802 if ((rc = bind(c->fd, &usa.sa, slen)) != 0)
4803 MG_ERROR(("bind: %d", MG_SOCK_ERR(rc)));
4804#endif
4805 mg_call(c, MG_EV_RESOLVE, NULL);
4806 mg_call(c, MG_EV_CONNECT, NULL);
4807 } else {
4808 union usa usa;
4809 socklen_t slen = tousa(&c->rem, &usa);
4810 mg_set_non_blocking_mode(FD(c));
4811 setsockopts(c);
4812 MG_EPOLL_ADD(c);
4813 mg_call(c, MG_EV_RESOLVE, NULL);
4814 rc = connect(FD(c), &usa.sa, slen); // Attempt to connect
4815 if (rc == 0) { // Success
4816 mg_call(c, MG_EV_CONNECT, NULL); // Send MG_EV_CONNECT to the user
4817 } else if (MG_SOCK_PENDING(rc)) { // Need to wait for TCP handshake
4818 MG_DEBUG(("%lu %p -> %M pend", c->id, c->fd, mg_print_ip_port, &c->rem));
4819 c->is_connecting = 1;
4820 } else {
4821 mg_error(c, "connect: %d", MG_SOCK_ERR(rc));
4822 }
4823 }
4824}
4825
4826static MG_SOCKET_TYPE raccept(MG_SOCKET_TYPE sock, union usa *usa,
4827 socklen_t *len) {
4828 MG_SOCKET_TYPE fd = MG_INVALID_SOCKET;
4829 do {
4830 memset(usa, 0, sizeof(*usa));
4831 fd = accept(sock, &usa->sa, len);
4832 } while (MG_SOCK_INTR(fd));
4833 return fd;
4834}
4835
4836static void accept_conn(struct mg_mgr *mgr, struct mg_connection *lsn) {
4837 struct mg_connection *c = NULL;
4838 union usa usa;
4839 socklen_t sa_len = sizeof(usa);
4840 MG_SOCKET_TYPE fd = raccept(FD(lsn), &usa, &sa_len);
4841 if (fd == MG_INVALID_SOCKET) {
4842#if MG_ARCH == MG_ARCH_AZURERTOS
4843 // AzureRTOS, in non-block socket mode can mark listening socket readable
4844 // even it is not. See comment for 'select' func implementation in
4845 // nx_bsd.c That's not an error, just should try later
4846 if (errno != EAGAIN)
4847#endif
4848 MG_ERROR(("%lu accept failed, errno %d", lsn->id, MG_SOCK_ERR(-1)));
4849#if (MG_ARCH != MG_ARCH_WIN32) && !MG_ENABLE_FREERTOS_TCP && \
4850 (MG_ARCH != MG_ARCH_TIRTOS) && !MG_ENABLE_POLL && !MG_ENABLE_EPOLL
4851 } else if ((long) fd >= FD_SETSIZE) {
4852 MG_ERROR(("%ld > %ld", (long) fd, (long) FD_SETSIZE));
4853 closesocket(fd);
4854#endif
4855 } else if ((c = mg_alloc_conn(mgr)) == NULL) {
4856 MG_ERROR(("%lu OOM", lsn->id));
4857 closesocket(fd);
4858 } else {
4859 tomgaddr(&usa, &c->rem, sa_len != sizeof(usa.sin));
4860 LIST_ADD_HEAD(struct mg_connection, &mgr->conns, c);
4861 c->fd = S2PTR(fd);
4862 MG_EPOLL_ADD(c);
4863 mg_set_non_blocking_mode(FD(c));
4864 setsockopts(c);
4865 c->is_accepted = 1;
4866 c->is_hexdumping = lsn->is_hexdumping;
4867 c->loc = lsn->loc;
4868 c->pfn = lsn->pfn;
4869 c->pfn_data = lsn->pfn_data;
4870 c->fn = lsn->fn;
4871 c->fn_data = lsn->fn_data;
4872 MG_DEBUG(("%lu %p accepted %M -> %M", c->id, c->fd, mg_print_ip_port,
4873 &c->rem, mg_print_ip_port, &c->loc));
4874 mg_call(c, MG_EV_OPEN, NULL);
4875 mg_call(c, MG_EV_ACCEPT, NULL);
4876 }
4877}
4878
4879static bool mg_socketpair(MG_SOCKET_TYPE sp[2], union usa usa[2], bool udp) {
4880 MG_SOCKET_TYPE sock;
4881 socklen_t n = sizeof(usa[0].sin);
4882 bool success = false;
4883
4884 sock = sp[0] = sp[1] = MG_INVALID_SOCKET;
4885 (void) memset(&usa[0], 0, sizeof(usa[0]));
4886 usa[0].sin.sin_family = AF_INET;
4887 *(uint32_t *) &usa->sin.sin_addr = mg_htonl(0x7f000001U); // 127.0.0.1
4888 usa[1] = usa[0];
4889
4890 if (udp && (sp[0] = socket(AF_INET, SOCK_DGRAM, 0)) != MG_INVALID_SOCKET &&
4891 (sp[1] = socket(AF_INET, SOCK_DGRAM, 0)) != MG_INVALID_SOCKET &&
4892 bind(sp[0], &usa[0].sa, n) == 0 && bind(sp[1], &usa[1].sa, n) == 0 &&
4893 getsockname(sp[0], &usa[0].sa, &n) == 0 &&
4894 getsockname(sp[1], &usa[1].sa, &n) == 0 &&
4895 connect(sp[0], &usa[1].sa, n) == 0 &&
4896 connect(sp[1], &usa[0].sa, n) == 0) {
4897 success = true;
4898 } else if (!udp &&
4899 (sock = socket(AF_INET, SOCK_STREAM, 0)) != MG_INVALID_SOCKET &&
4900 bind(sock, &usa[0].sa, n) == 0 &&
4901 listen(sock, MG_SOCK_LISTEN_BACKLOG_SIZE) == 0 &&
4902 getsockname(sock, &usa[0].sa, &n) == 0 &&
4903 (sp[0] = socket(AF_INET, SOCK_STREAM, 0)) != MG_INVALID_SOCKET &&
4904 connect(sp[0], &usa[0].sa, n) == 0 &&
4905 (sp[1] = raccept(sock, &usa[1], &n)) != MG_INVALID_SOCKET) {
4906 success = true;
4907 }
4908 if (success) {
4909 mg_set_non_blocking_mode(sp[1]);
4910 } else {
4911 if (sp[0] != MG_INVALID_SOCKET) closesocket(sp[0]);
4912 if (sp[1] != MG_INVALID_SOCKET) closesocket(sp[1]);
4913 sp[0] = sp[1] = MG_INVALID_SOCKET;
4914 }
4915 if (sock != MG_INVALID_SOCKET) closesocket(sock);
4916 return success;
4917}
4918
4919int mg_mkpipe(struct mg_mgr *mgr, mg_event_handler_t fn, void *fn_data,
4920 bool udp) {
4921 union usa usa[2];
4922 MG_SOCKET_TYPE sp[2] = {MG_INVALID_SOCKET, MG_INVALID_SOCKET};
4923 struct mg_connection *c = NULL;
4924 if (!mg_socketpair(sp, usa, udp)) {
4925 MG_ERROR(("Cannot create socket pair"));
4926 } else if ((c = mg_wrapfd(mgr, (int) sp[1], fn, fn_data)) == NULL) {
4927 closesocket(sp[0]);
4928 closesocket(sp[1]);
4929 sp[0] = sp[1] = MG_INVALID_SOCKET;
4930 } else {
4931 tomgaddr(&usa[0], &c->rem, false);
4932 MG_DEBUG(("%lu %p pipe %lu", c->id, c->fd, (unsigned long) sp[0]));
4933 }
4934 return (int) sp[0];
4935}
4936
4937static bool can_read(const struct mg_connection *c) {
4938 return c->is_full == false;
4939}
4940
4941static bool can_write(const struct mg_connection *c) {
4942 return c->is_connecting || (c->send.len > 0 && c->is_tls_hs == 0);
4943}
4944
4945static bool skip_iotest(const struct mg_connection *c) {
4946 return (c->is_closing || c->is_resolving || FD(c) == MG_INVALID_SOCKET) ||
4947 (can_read(c) == false && can_write(c) == false);
4948}
4949
4950static void mg_iotest(struct mg_mgr *mgr, int ms) {
4951#if MG_ENABLE_FREERTOS_TCP
4952 struct mg_connection *c;
4953 for (c = mgr->conns; c != NULL; c = c->next) {
4954 c->is_readable = c->is_writable = 0;
4955 if (skip_iotest(c)) continue;
4956 if (can_read(c))
4957 FreeRTOS_FD_SET(c->fd, mgr->ss, eSELECT_READ | eSELECT_EXCEPT);
4958 if (can_write(c)) FreeRTOS_FD_SET(c->fd, mgr->ss, eSELECT_WRITE);
4959 }
4960 FreeRTOS_select(mgr->ss, pdMS_TO_TICKS(ms));
4961 for (c = mgr->conns; c != NULL; c = c->next) {
4962 EventBits_t bits = FreeRTOS_FD_ISSET(c->fd, mgr->ss);
4963 c->is_readable = bits & (eSELECT_READ | eSELECT_EXCEPT) ? 1U : 0;
4964 c->is_writable = bits & eSELECT_WRITE ? 1U : 0;
4965 if (c->fd != MG_INVALID_SOCKET)
4966 FreeRTOS_FD_CLR(c->fd, mgr->ss,
4967 eSELECT_READ | eSELECT_EXCEPT | eSELECT_WRITE);
4968 }
4969#elif MG_ENABLE_EPOLL
4970 size_t max = 1;
4971 for (struct mg_connection *c = mgr->conns; c != NULL; c = c->next) {
4972 c->is_readable = c->is_writable = 0;
4973 if (mg_tls_pending(c) > 0) ms = 1, c->is_readable = 1;
4974 if (can_write(c)) MG_EPOLL_MOD(c, 1);
4975 max++;
4976 }
4977 struct epoll_event *evs = (struct epoll_event *) alloca(max * sizeof(evs[0]));
4978 int n = epoll_wait(mgr->epoll_fd, evs, (int) max, ms);
4979 for (int i = 0; i < n; i++) {
4980 struct mg_connection *c = (struct mg_connection *) evs[i].data.ptr;
4981 if (evs[i].events & EPOLLERR) {
4982 mg_error(c, "socket error");
4983 } else if (c->is_readable == 0) {
4984 bool rd = evs[i].events & (EPOLLIN | EPOLLHUP);
4985 bool wr = evs[i].events & EPOLLOUT;
4986 c->is_readable = can_read(c) && rd ? 1U : 0;
4987 c->is_writable = can_write(c) && wr ? 1U : 0;
4988 }
4989 }
4990 (void) skip_iotest;
4991#elif MG_ENABLE_POLL
4992 nfds_t n = 0;
4993 for (struct mg_connection *c = mgr->conns; c != NULL; c = c->next) n++;
4994 struct pollfd *fds = (struct pollfd *) alloca(n * sizeof(fds[0]));
4995 memset(fds, 0, n * sizeof(fds[0]));
4996 n = 0;
4997 for (struct mg_connection *c = mgr->conns; c != NULL; c = c->next) {
4998 c->is_readable = c->is_writable = 0;
4999 if (skip_iotest(c)) {
5000 // Socket not valid, ignore
5001 } else if (mg_tls_pending(c) > 0) {
5002 ms = 1; // Don't wait if TLS is ready
5003 } else {
5004 fds[n].fd = FD(c);
5005 if (can_read(c)) fds[n].events |= POLLIN;
5006 if (can_write(c)) fds[n].events |= POLLOUT;
5007 n++;
5008 }
5009 }
5010
5011 // MG_INFO(("poll n=%d ms=%d", (int) n, ms));
5012 if (poll(fds, n, ms) < 0) {
5013#if MG_ARCH == MG_ARCH_WIN32
5014 if (n == 0) Sleep(ms); // On Windows, poll fails if no sockets
5015#endif
5016 memset(fds, 0, n * sizeof(fds[0]));
5017 }
5018 n = 0;
5019 for (struct mg_connection *c = mgr->conns; c != NULL; c = c->next) {
5020 if (skip_iotest(c)) {
5021 // Socket not valid, ignore
5022 } else if (mg_tls_pending(c) > 0) {
5023 c->is_readable = 1;
5024 } else {
5025 if (fds[n].revents & POLLERR) {
5026 mg_error(c, "socket error");
5027 } else {
5028 c->is_readable =
5029 (unsigned) (fds[n].revents & (POLLIN | POLLHUP) ? 1 : 0);
5030 c->is_writable = (unsigned) (fds[n].revents & POLLOUT ? 1 : 0);
5031 }
5032 n++;
5033 }
5034 }
5035#else
5036 struct timeval tv = {ms / 1000, (ms % 1000) * 1000}, tv_zero = {0, 0}, *tvp;
5037 struct mg_connection *c;
5038 fd_set rset, wset, eset;
5039 MG_SOCKET_TYPE maxfd = 0;
5040 int rc;
5041
5042 FD_ZERO(&rset);
5043 FD_ZERO(&wset);
5044 FD_ZERO(&eset);
5045 tvp = ms < 0 ? NULL : &tv;
5046 for (c = mgr->conns; c != NULL; c = c->next) {
5047 c->is_readable = c->is_writable = 0;
5048 if (skip_iotest(c)) continue;
5049 FD_SET(FD(c), &eset);
5050 if (can_read(c)) FD_SET(FD(c), &rset);
5051 if (can_write(c)) FD_SET(FD(c), &wset);
5052 if (mg_tls_pending(c) > 0) tvp = &tv_zero;
5053 if (FD(c) > maxfd) maxfd = FD(c);
5054 }
5055
5056 if ((rc = select((int) maxfd + 1, &rset, &wset, &eset, tvp)) < 0) {
5057#if MG_ARCH == MG_ARCH_WIN32
5058 if (maxfd == 0) Sleep(ms); // On Windows, select fails if no sockets
5059#else
5060 MG_ERROR(("select: %d %d", rc, MG_SOCK_ERR(rc)));
5061#endif
5062 FD_ZERO(&rset);
5063 FD_ZERO(&wset);
5064 FD_ZERO(&eset);
5065 }
5066
5067 for (c = mgr->conns; c != NULL; c = c->next) {
5068 if (FD(c) != MG_INVALID_SOCKET && FD_ISSET(FD(c), &eset)) {
5069 mg_error(c, "socket error");
5070 } else {
5071 c->is_readable = FD(c) != MG_INVALID_SOCKET && FD_ISSET(FD(c), &rset);
5072 c->is_writable = FD(c) != MG_INVALID_SOCKET && FD_ISSET(FD(c), &wset);
5073 if (mg_tls_pending(c) > 0) c->is_readable = 1;
5074 }
5075 }
5076#endif
5077}
5078
5079void mg_mgr_poll(struct mg_mgr *mgr, int ms) {
5080 struct mg_connection *c, *tmp;
5081 uint64_t now;
5082
5083 mg_iotest(mgr, ms);
5084 now = mg_millis();
5085 mg_timer_poll(&mgr->timers, now);
5086
5087 for (c = mgr->conns; c != NULL; c = tmp) {
5088 bool is_resp = c->is_resp;
5089 tmp = c->next;
5090 mg_call(c, MG_EV_POLL, &now);
5091 if (is_resp && !c->is_resp) {
5092 long n = 0;
5093 mg_call(c, MG_EV_READ, &n);
5094 }
5095 MG_VERBOSE(("%lu %c%c %c%c%c%c%c", c->id, c->is_readable ? 'r' : '-',
5096 c->is_writable ? 'w' : '-', c->is_tls ? 'T' : 't',
5097 c->is_connecting ? 'C' : 'c', c->is_tls_hs ? 'H' : 'h',
5098 c->is_resolving ? 'R' : 'r', c->is_closing ? 'C' : 'c'));
5099 if (c->is_resolving || c->is_closing) {
5100 // Do nothing
5101 } else if (c->is_listening && c->is_udp == 0) {
5102 if (c->is_readable) accept_conn(mgr, c);
5103 } else if (c->is_connecting) {
5104 if (c->is_readable || c->is_writable) connect_conn(c);
5105 } else if (c->is_tls_hs) {
5106 if ((c->is_readable || c->is_writable)) mg_tls_handshake(c);
5107 } else {
5108 if (c->is_readable) read_conn(c);
5109 if (c->is_writable) write_conn(c);
5110 }
5111
5112 if (c->is_draining && c->send.len == 0) c->is_closing = 1;
5113 if (c->is_closing) close_conn(c);
5114 }
5115}
5116#endif
5117
5118#ifdef MG_ENABLE_LINES
5119#line 1 "src/ssi.c"
5120#endif
5121
5122
5123
5124
5125#ifndef MG_MAX_SSI_DEPTH
5126#define MG_MAX_SSI_DEPTH 5
5127#endif
5128
5129#ifndef MG_SSI_BUFSIZ
5130#define MG_SSI_BUFSIZ 1024
5131#endif
5132
5133#if MG_ENABLE_SSI
5134static char *mg_ssi(const char *path, const char *root, int depth) {
5135 struct mg_iobuf b = {NULL, 0, 0, MG_IO_SIZE};
5136 FILE *fp = fopen(path, "rb");
5137 if (fp != NULL) {
5138 char buf[MG_SSI_BUFSIZ], arg[sizeof(buf)];
5139 int ch, intag = 0;
5140 size_t len = 0;
5141 buf[0] = arg[0] = '\0';
5142 while ((ch = fgetc(fp)) != EOF) {
5143 if (intag && ch == '>' && buf[len - 1] == '-' && buf[len - 2] == '-') {
5144 buf[len++] = (char) (ch & 0xff);
5145 buf[len] = '\0';
5146 if (sscanf(buf, "<!--#include file=\"%[^\"]", arg)) {
5147 char tmp[MG_PATH_MAX + MG_SSI_BUFSIZ + 10],
5148 *p = (char *) path + strlen(path), *data;
5149 while (p > path && p[-1] != MG_DIRSEP && p[-1] != '/') p--;
5150 mg_snprintf(tmp, sizeof(tmp), "%.*s%s", (int) (p - path), path, arg);
5151 if (depth < MG_MAX_SSI_DEPTH &&
5152 (data = mg_ssi(tmp, root, depth + 1)) != NULL) {
5153 mg_iobuf_add(&b, b.len, data, strlen(data));
5154 free(data);
5155 } else {
5156 MG_ERROR(("%s: file=%s error or too deep", path, arg));
5157 }
5158 } else if (sscanf(buf, "<!--#include virtual=\"%[^\"]", arg)) {
5159 char tmp[MG_PATH_MAX + MG_SSI_BUFSIZ + 10], *data;
5160 mg_snprintf(tmp, sizeof(tmp), "%s%s", root, arg);
5161 if (depth < MG_MAX_SSI_DEPTH &&
5162 (data = mg_ssi(tmp, root, depth + 1)) != NULL) {
5163 mg_iobuf_add(&b, b.len, data, strlen(data));
5164 free(data);
5165 } else {
5166 MG_ERROR(("%s: virtual=%s error or too deep", path, arg));
5167 }
5168 } else {
5169 // Unknown SSI tag
5170 MG_ERROR(("Unknown SSI tag: %.*s", (int) len, buf));
5171 mg_iobuf_add(&b, b.len, buf, len);
5172 }
5173 intag = 0;
5174 len = 0;
5175 } else if (ch == '<') {
5176 intag = 1;
5177 if (len > 0) mg_iobuf_add(&b, b.len, buf, len);
5178 len = 0;
5179 buf[len++] = (char) (ch & 0xff);
5180 } else if (intag) {
5181 if (len == 5 && strncmp(buf, "<!--#", 5) != 0) {
5182 intag = 0;
5183 } else if (len >= sizeof(buf) - 2) {
5184 MG_ERROR(("%s: SSI tag is too large", path));
5185 len = 0;
5186 }
5187 buf[len++] = (char) (ch & 0xff);
5188 } else {
5189 buf[len++] = (char) (ch & 0xff);
5190 if (len >= sizeof(buf)) {
5191 mg_iobuf_add(&b, b.len, buf, len);
5192 len = 0;
5193 }
5194 }
5195 }
5196 if (len > 0) mg_iobuf_add(&b, b.len, buf, len);
5197 if (b.len > 0) mg_iobuf_add(&b, b.len, "", 1); // nul-terminate
5198 fclose(fp);
5199 }
5200 (void) depth;
5201 (void) root;
5202 return (char *) b.buf;
5203}
5204
5205void mg_http_serve_ssi(struct mg_connection *c, const char *root,
5206 const char *fullpath) {
5207 const char *headers = "Content-Type: text/html; charset=utf-8\r\n";
5208 char *data = mg_ssi(fullpath, root, 0);
5209 mg_http_reply(c, 200, headers, "%s", data == NULL ? "" : data);
5210 free(data);
5211}
5212#else
5213void mg_http_serve_ssi(struct mg_connection *c, const char *root,
5214 const char *fullpath) {
5215 mg_http_reply(c, 501, NULL, "SSI not enabled");
5216 (void) root, (void) fullpath;
5217}
5218#endif
5219
5220#ifdef MG_ENABLE_LINES
5221#line 1 "src/str.c"
5222#endif
5223
5224
5225struct mg_str mg_str_s(const char *s) {
5226 struct mg_str str = {s, s == NULL ? 0 : strlen(s)};
5227 return str;
5228}
5229
5230struct mg_str mg_str_n(const char *s, size_t n) {
5231 struct mg_str str = {s, n};
5232 return str;
5233}
5234
5235int mg_lower(const char *s) {
5236 int c = *s;
5237 if (c >= 'A' && c <= 'Z') c += 'a' - 'A';
5238 return c;
5239}
5240
5241int mg_ncasecmp(const char *s1, const char *s2, size_t len) {
5242 int diff = 0;
5243 if (len > 0) do {
5244 diff = mg_lower(s1++) - mg_lower(s2++);
5245 } while (diff == 0 && s1[-1] != '\0' && --len > 0);
5246 return diff;
5247}
5248
5249int mg_casecmp(const char *s1, const char *s2) {
5250 return mg_ncasecmp(s1, s2, (size_t) ~0);
5251}
5252
5253int mg_vcmp(const struct mg_str *s1, const char *s2) {
5254 size_t n2 = strlen(s2), n1 = s1->len;
5255 int r = strncmp(s1->ptr, s2, (n1 < n2) ? n1 : n2);
5256 if (r == 0) return (int) (n1 - n2);
5257 return r;
5258}
5259
5260int mg_vcasecmp(const struct mg_str *str1, const char *str2) {
5261 size_t n2 = strlen(str2), n1 = str1->len;
5262 int r = mg_ncasecmp(str1->ptr, str2, (n1 < n2) ? n1 : n2);
5263 if (r == 0) return (int) (n1 - n2);
5264 return r;
5265}
5266
5267struct mg_str mg_strdup(const struct mg_str s) {
5268 struct mg_str r = {NULL, 0};
5269 if (s.len > 0 && s.ptr != NULL) {
5270 char *sc = (char *) calloc(1, s.len + 1);
5271 if (sc != NULL) {
5272 memcpy(sc, s.ptr, s.len);
5273 sc[s.len] = '\0';
5274 r.ptr = sc;
5275 r.len = s.len;
5276 }
5277 }
5278 return r;
5279}
5280
5281int mg_strcmp(const struct mg_str str1, const struct mg_str str2) {
5282 size_t i = 0;
5283 while (i < str1.len && i < str2.len) {
5284 int c1 = str1.ptr[i];
5285 int c2 = str2.ptr[i];
5286 if (c1 < c2) return -1;
5287 if (c1 > c2) return 1;
5288 i++;
5289 }
5290 if (i < str1.len) return 1;
5291 if (i < str2.len) return -1;
5292 return 0;
5293}
5294
5295const char *mg_strstr(const struct mg_str haystack,
5296 const struct mg_str needle) {
5297 size_t i;
5298 if (needle.len > haystack.len) return NULL;
5299 if (needle.len == 0) return haystack.ptr;
5300 for (i = 0; i <= haystack.len - needle.len; i++) {
5301 if (memcmp(haystack.ptr + i, needle.ptr, needle.len) == 0) {
5302 return haystack.ptr + i;
5303 }
5304 }
5305 return NULL;
5306}
5307
5308static bool is_space(int c) {
5309 return c == ' ' || c == '\r' || c == '\n' || c == '\t';
5310}
5311
5312struct mg_str mg_strstrip(struct mg_str s) {
5313 while (s.len > 0 && is_space((int) *s.ptr)) s.ptr++, s.len--;
5314 while (s.len > 0 && is_space((int) *(s.ptr + s.len - 1))) s.len--;
5315 return s;
5316}
5317
5318bool mg_match(struct mg_str s, struct mg_str p, struct mg_str *caps) {
5319 size_t i = 0, j = 0, ni = 0, nj = 0;
5320 if (caps) caps->ptr = NULL, caps->len = 0;
5321 while (i < p.len || j < s.len) {
5322 if (i < p.len && j < s.len && (p.ptr[i] == '?' || s.ptr[j] == p.ptr[i])) {
5323 if (caps == NULL) {
5324 } else if (p.ptr[i] == '?') {
5325 caps->ptr = &s.ptr[j], caps->len = 1; // Finalize `?` cap
5326 caps++, caps->ptr = NULL, caps->len = 0; // Init next cap
5327 } else if (caps->ptr != NULL && caps->len == 0) {
5328 caps->len = (size_t) (&s.ptr[j] - caps->ptr); // Finalize current cap
5329 caps++, caps->len = 0, caps->ptr = NULL; // Init next cap
5330 }
5331 i++, j++;
5332 } else if (i < p.len && (p.ptr[i] == '*' || p.ptr[i] == '#')) {
5333 if (caps && !caps->ptr) caps->len = 0, caps->ptr = &s.ptr[j]; // Init cap
5334 ni = i++, nj = j + 1;
5335 } else if (nj > 0 && nj <= s.len && (p.ptr[ni] == '#' || s.ptr[j] != '/')) {
5336 i = ni, j = nj;
5337 if (caps && caps->ptr == NULL && caps->len == 0) {
5338 caps--, caps->len = 0; // Restart previous cap
5339 }
5340 } else {
5341 return false;
5342 }
5343 }
5344 if (caps && caps->ptr && caps->len == 0) {
5345 caps->len = (size_t) (&s.ptr[j] - caps->ptr);
5346 }
5347 return true;
5348}
5349
5350bool mg_globmatch(const char *s1, size_t n1, const char *s2, size_t n2) {
5351 return mg_match(mg_str_n(s2, n2), mg_str_n(s1, n1), NULL);
5352}
5353
5354static size_t mg_nce(const char *s, size_t n, size_t ofs, size_t *koff,
5355 size_t *klen, size_t *voff, size_t *vlen, char delim) {
5356 size_t kvlen, kl;
5357 for (kvlen = 0; ofs + kvlen < n && s[ofs + kvlen] != delim;) kvlen++;
5358 for (kl = 0; kl < kvlen && s[ofs + kl] != '=';) kl++;
5359 if (koff != NULL) *koff = ofs;
5360 if (klen != NULL) *klen = kl;
5361 if (voff != NULL) *voff = kl < kvlen ? ofs + kl + 1 : 0;
5362 if (vlen != NULL) *vlen = kl < kvlen ? kvlen - kl - 1 : 0;
5363 ofs += kvlen + 1;
5364 return ofs > n ? n : ofs;
5365}
5366
5367bool mg_split(struct mg_str *s, struct mg_str *k, struct mg_str *v, char sep) {
5368 size_t koff = 0, klen = 0, voff = 0, vlen = 0, off = 0;
5369 if (s->ptr == NULL || s->len == 0) return 0;
5370 off = mg_nce(s->ptr, s->len, 0, &koff, &klen, &voff, &vlen, sep);
5371 if (k != NULL) *k = mg_str_n(s->ptr + koff, klen);
5372 if (v != NULL) *v = mg_str_n(s->ptr + voff, vlen);
5373 *s = mg_str_n(s->ptr + off, s->len - off);
5374 return off > 0;
5375}
5376
5377bool mg_commalist(struct mg_str *s, struct mg_str *k, struct mg_str *v) {
5378 return mg_split(s, k, v, ',');
5379}
5380
5381char *mg_hex(const void *buf, size_t len, char *to) {
5382 const unsigned char *p = (const unsigned char *) buf;
5383 const char *hex = "0123456789abcdef";
5384 size_t i = 0;
5385 for (; len--; p++) {
5386 to[i++] = hex[p[0] >> 4];
5387 to[i++] = hex[p[0] & 0x0f];
5388 }
5389 to[i] = '\0';
5390 return to;
5391}
5392
5393static unsigned char mg_unhex_nimble(unsigned char c) {
5394 return (c >= '0' && c <= '9') ? (unsigned char) (c - '0')
5395 : (c >= 'A' && c <= 'F') ? (unsigned char) (c - '7')
5396 : (unsigned char) (c - 'W');
5397}
5398
5399unsigned long mg_unhexn(const char *s, size_t len) {
5400 unsigned long i = 0, v = 0;
5401 for (i = 0; i < len; i++) v <<= 4, v |= mg_unhex_nimble(((uint8_t *) s)[i]);
5402 return v;
5403}
5404
5405void mg_unhex(const char *buf, size_t len, unsigned char *to) {
5406 size_t i;
5407 for (i = 0; i < len; i += 2) {
5408 to[i >> 1] = (unsigned char) mg_unhexn(&buf[i], 2);
5409 }
5410}
5411
5412char *mg_remove_double_dots(char *s) {
5413 char *saved = s, *p = s;
5414 while (*s != '\0') {
5415 *p++ = *s++;
5416 if (s[-1] == '/' || s[-1] == '\\') {
5417 while (s[0] != '\0') {
5418 if (s[0] == '/' || s[0] == '\\') {
5419 s++;
5420 } else if (s[0] == '.' && s[1] == '.' &&
5421 (s[2] == '/' || s[2] == '\\')) {
5422 s += 2;
5423 } else {
5424 break;
5425 }
5426 }
5427 }
5428 }
5429 *p = '\0';
5430 return saved;
5431}
5432
5433#ifdef MG_ENABLE_LINES
5434#line 1 "src/timer.c"
5435#endif
5436
5437
5438
5439#define MG_TIMER_CALLED 4
5440
5441void mg_timer_init(struct mg_timer **head, struct mg_timer *t, uint64_t ms,
5442 unsigned flags, void (*fn)(void *), void *arg) {
5443 t->id = 0, t->period_ms = ms, t->expire = 0;
5444 t->flags = flags, t->fn = fn, t->arg = arg, t->next = *head;
5445 *head = t;
5446}
5447
5448void mg_timer_free(struct mg_timer **head, struct mg_timer *t) {
5449 while (*head && *head != t) head = &(*head)->next;
5450 if (*head) *head = t->next;
5451}
5452
5453// t: expiration time, prd: period, now: current time. Return true if expired
5454bool mg_timer_expired(uint64_t *t, uint64_t prd, uint64_t now) {
5455 if (now + prd < *t) *t = 0; // Time wrapped? Reset timer
5456 if (*t == 0) *t = now + prd; // Firt poll? Set expiration
5457 if (*t > now) return false; // Not expired yet, return
5458 *t = (now - *t) > prd ? now + prd : *t + prd; // Next expiration time
5459 return true; // Expired, return true
5460}
5461
5462void mg_timer_poll(struct mg_timer **head, uint64_t now_ms) {
5463 struct mg_timer *t, *tmp;
5464 for (t = *head; t != NULL; t = tmp) {
5465 bool once = t->expire == 0 && (t->flags & MG_TIMER_RUN_NOW) &&
5466 !(t->flags & MG_TIMER_CALLED); // Handle MG_TIMER_NOW only once
5467 bool expired = mg_timer_expired(&t->expire, t->period_ms, now_ms);
5468 tmp = t->next;
5469 if (!once && !expired) continue;
5470 if ((t->flags & MG_TIMER_REPEAT) || !(t->flags & MG_TIMER_CALLED)) {
5471 t->fn(t->arg);
5472 }
5473 t->flags |= MG_TIMER_CALLED;
5474 }
5475}
5476
5477#ifdef MG_ENABLE_LINES
5478#line 1 "src/tls_dummy.c"
5479#endif
5480
5481
5482#if !MG_ENABLE_MBEDTLS && !MG_ENABLE_OPENSSL && !MG_ENABLE_CUSTOM_TLS
5483void mg_tls_init(struct mg_connection *c, const struct mg_tls_opts *opts) {
5484 (void) opts;
5485 mg_error(c, "TLS is not enabled");
5486}
5487void mg_tls_handshake(struct mg_connection *c) {
5488 (void) c;
5489}
5490void mg_tls_free(struct mg_connection *c) {
5491 (void) c;
5492}
5493long mg_tls_recv(struct mg_connection *c, void *buf, size_t len) {
5494 return c == NULL || buf == NULL || len == 0 ? 0 : -1;
5495}
5496long mg_tls_send(struct mg_connection *c, const void *buf, size_t len) {
5497 return c == NULL || buf == NULL || len == 0 ? 0 : -1;
5498}
5499size_t mg_tls_pending(struct mg_connection *c) {
5500 (void) c;
5501 return 0;
5502}
5503#endif
5504
5505#ifdef MG_ENABLE_LINES
5506#line 1 "src/tls_mbed.c"
5507#endif
5508
5509
5510
5511
5512#if MG_ENABLE_MBEDTLS
5513
5514#if defined(MBEDTLS_VERSION_NUMBER) && MBEDTLS_VERSION_NUMBER >= 0x03000000
5515#define MGRNG , rng_get, NULL
5516#else
5517#define MGRNG
5518#endif
5519
5520void mg_tls_free(struct mg_connection *c) {
5521 struct mg_tls *tls = (struct mg_tls *) c->tls;
5522 if (tls != NULL) {
5523 free(tls->cafile);
5524 mbedtls_ssl_free(&tls->ssl);
5525 mbedtls_pk_free(&tls->pk);
5526 mbedtls_x509_crt_free(&tls->ca);
5527 mbedtls_x509_crt_free(&tls->cert);
5528 mbedtls_ssl_config_free(&tls->conf);
5529 free(tls);
5530 c->tls = NULL;
5531 }
5532}
5533
5534static int mg_net_send(void *ctx, const unsigned char *buf, size_t len) {
5535 long n = mg_io_send((struct mg_connection *) ctx, buf, len);
5536 MG_VERBOSE(("%lu n=%ld e=%d", ((struct mg_connection *) ctx)->id, n, errno));
5537 if (n == MG_IO_WAIT) return MBEDTLS_ERR_SSL_WANT_WRITE;
5538 if (n == MG_IO_RESET) return MBEDTLS_ERR_NET_CONN_RESET;
5539 if (n == MG_IO_ERR) return MBEDTLS_ERR_NET_SEND_FAILED;
5540 return (int) n;
5541}
5542
5543static int mg_net_recv(void *ctx, unsigned char *buf, size_t len) {
5544 long n = mg_io_recv((struct mg_connection *) ctx, buf, len);
5545 MG_VERBOSE(("%lu n=%ld", ((struct mg_connection *) ctx)->id, n));
5546 if (n == MG_IO_WAIT) return MBEDTLS_ERR_SSL_WANT_WRITE;
5547 if (n == MG_IO_RESET) return MBEDTLS_ERR_NET_CONN_RESET;
5548 if (n == MG_IO_ERR) return MBEDTLS_ERR_NET_RECV_FAILED;
5549 return (int) n;
5550}
5551
5552void mg_tls_handshake(struct mg_connection *c) {
5553 struct mg_tls *tls = (struct mg_tls *) c->tls;
5554 int rc = mbedtls_ssl_handshake(&tls->ssl);
5555 if (rc == 0) { // Success
5556 MG_DEBUG(("%lu success", c->id));
5557 c->is_tls_hs = 0;
5558 mg_call(c, MG_EV_TLS_HS, NULL);
5559 } else if (rc == MBEDTLS_ERR_SSL_WANT_READ ||
5560 rc == MBEDTLS_ERR_SSL_WANT_WRITE) { // Still pending
5561 MG_VERBOSE(("%lu pending, %d%d %d (-%#x)", c->id, c->is_connecting,
5562 c->is_tls_hs, rc, -rc));
5563 } else {
5564 mg_error(c, "TLS handshake: -%#x", -rc); // Error
5565 }
5566}
5567
5568static int mbed_rng(void *ctx, unsigned char *buf, size_t len) {
5569 mg_random(buf, len);
5570 (void) ctx;
5571 return 0;
5572}
5573
5574static void debug_cb(void *c, int lev, const char *s, int n, const char *s2) {
5575 n = (int) strlen(s2) - 1;
5576 MG_INFO(("%lu %d %.*s", ((struct mg_connection *) c)->id, lev, n, s2));
5577 (void) s;
5578}
5579
5580#if defined(MBEDTLS_VERSION_NUMBER) && MBEDTLS_VERSION_NUMBER >= 0x03000000
5581static int rng_get(void *p_rng, unsigned char *buf, size_t len) {
5582 (void) p_rng;
5583 mg_random(buf, len);
5584 return 0;
5585}
5586#endif
5587
5588static struct mg_str mg_loadfile(struct mg_fs *fs, const char *path) {
5589 size_t n = 0;
5590 if (path[0] == '-') return mg_str(path);
5591 char *p = mg_file_read(fs, path, &n);
5592 return mg_str_n(p, n);
5593}
5594
5595void mg_tls_init(struct mg_connection *c, const struct mg_tls_opts *opts) {
5596 struct mg_fs *fs = opts->fs == NULL ? &mg_fs_posix : opts->fs;
5597 struct mg_tls *tls = (struct mg_tls *) calloc(1, sizeof(*tls));
5598 int rc = 0;
5599 c->tls = tls;
5600 if (c->tls == NULL) {
5601 mg_error(c, "TLS OOM");
5602 goto fail;
5603 }
5604 MG_DEBUG(("%lu Setting TLS", c->id));
5605 mbedtls_ssl_init(&tls->ssl);
5606 mbedtls_ssl_config_init(&tls->conf);
5607 mbedtls_x509_crt_init(&tls->ca);
5608 mbedtls_x509_crt_init(&tls->cert);
5609 mbedtls_pk_init(&tls->pk);
5610 mbedtls_ssl_conf_dbg(&tls->conf, debug_cb, c);
5611#if defined(MG_MBEDTLS_DEBUG_LEVEL)
5612 mbedtls_debug_set_threshold(MG_MBEDTLS_DEBUG_LEVEL);
5613#endif
5614 if ((rc = mbedtls_ssl_config_defaults(
5615 &tls->conf,
5616 c->is_client ? MBEDTLS_SSL_IS_CLIENT : MBEDTLS_SSL_IS_SERVER,
5617 MBEDTLS_SSL_TRANSPORT_STREAM, MBEDTLS_SSL_PRESET_DEFAULT)) != 0) {
5618 mg_error(c, "tls defaults %#x", -rc);
5619 goto fail;
5620 }
5621 mbedtls_ssl_conf_rng(&tls->conf, mbed_rng, c);
5622 if (opts->ca == NULL || strcmp(opts->ca, "*") == 0) {
5623 mbedtls_ssl_conf_authmode(&tls->conf, MBEDTLS_SSL_VERIFY_NONE);
5624 } else if (opts->ca != NULL && opts->ca[0] != '\0') {
5625#if defined(MBEDTLS_X509_CA_CHAIN_ON_DISK)
5626 tls->cafile = strdup(opts->ca);
5627 rc = mbedtls_ssl_conf_ca_chain_file(&tls->conf, tls->cafile, NULL);
5628 if (rc != 0) {
5629 mg_error(c, "parse on-disk chain(%s) err %#x", tls->cafile, -rc);
5630 goto fail;
5631 }
5632#else
5633 struct mg_str s = mg_loadfile(fs, opts->ca);
5634 rc = mbedtls_x509_crt_parse(&tls->ca, (uint8_t *) s.ptr, s.len + 1);
5635 if (opts->ca[0] != '-') free((char *) s.ptr);
5636 if (rc != 0) {
5637 mg_error(c, "parse(%s) err %#x", opts->ca, -rc);
5638 goto fail;
5639 }
5640 mbedtls_ssl_conf_ca_chain(&tls->conf, &tls->ca, NULL);
5641#endif
5642 if (opts->srvname.len > 0) {
5643 char *x = mg_mprintf("%.*s", (int) opts->srvname.len, opts->srvname.ptr);
5644 mbedtls_ssl_set_hostname(&tls->ssl, x);
5645 free(x);
5646 }
5647 mbedtls_ssl_conf_authmode(&tls->conf, MBEDTLS_SSL_VERIFY_REQUIRED);
5648 }
5649 if (opts->cert != NULL && opts->cert[0] != '\0') {
5650 struct mg_str s = mg_loadfile(fs, opts->cert);
5651 const char *key = opts->certkey == NULL ? opts->cert : opts->certkey;
5652 rc = mbedtls_x509_crt_parse(&tls->cert, (uint8_t *) s.ptr, s.len + 1);
5653 if (opts->cert[0] != '-') free((char *) s.ptr);
5654 if (rc != 0) {
5655 mg_error(c, "parse(%s) err %#x", opts->cert, -rc);
5656 goto fail;
5657 }
5658 s = mg_loadfile(fs, key);
5659 rc = mbedtls_pk_parse_key(&tls->pk, (uint8_t *) s.ptr, s.len + 1, NULL,
5660 0 MGRNG);
5661 if (key[0] != '-') free((char *) s.ptr);
5662 if (rc != 0) {
5663 mg_error(c, "tls key(%s) %#x", key, -rc);
5664 goto fail;
5665 }
5666 rc = mbedtls_ssl_conf_own_cert(&tls->conf, &tls->cert, &tls->pk);
5667 if (rc != 0) {
5668 mg_error(c, "own cert %#x", -rc);
5669 goto fail;
5670 }
5671 }
5672 if ((rc = mbedtls_ssl_setup(&tls->ssl, &tls->conf)) != 0) {
5673 mg_error(c, "setup err %#x", -rc);
5674 goto fail;
5675 }
5676 c->tls = tls;
5677 c->is_tls = 1;
5678 c->is_tls_hs = 1;
5679 mbedtls_ssl_set_bio(&tls->ssl, c, mg_net_send, mg_net_recv, 0);
5680 if (c->is_client && c->is_resolving == 0 && c->is_connecting == 0) {
5681 mg_tls_handshake(c);
5682 }
5683 return;
5684fail:
5685 mg_tls_free(c);
5686}
5687
5688size_t mg_tls_pending(struct mg_connection *c) {
5689 struct mg_tls *tls = (struct mg_tls *) c->tls;
5690 return tls == NULL ? 0 : mbedtls_ssl_get_bytes_avail(&tls->ssl);
5691}
5692
5693long mg_tls_recv(struct mg_connection *c, void *buf, size_t len) {
5694 struct mg_tls *tls = (struct mg_tls *) c->tls;
5695 long n = mbedtls_ssl_read(&tls->ssl, (unsigned char *) buf, len);
5696 if (n == MBEDTLS_ERR_SSL_WANT_READ || n == MBEDTLS_ERR_SSL_WANT_WRITE)
5697 return MG_IO_WAIT;
5698 if (n <= 0) return MG_IO_ERR;
5699 return n;
5700}
5701
5702long mg_tls_send(struct mg_connection *c, const void *buf, size_t len) {
5703 struct mg_tls *tls = (struct mg_tls *) c->tls;
5704 long n = mbedtls_ssl_write(&tls->ssl, (unsigned char *) buf, len);
5705 if (n == MBEDTLS_ERR_SSL_WANT_READ || n == MBEDTLS_ERR_SSL_WANT_WRITE)
5706 return MG_IO_WAIT;
5707 if (n <= 0) return MG_IO_ERR;
5708 return n;
5709}
5710#endif
5711
5712#ifdef MG_ENABLE_LINES
5713#line 1 "src/tls_openssl.c"
5714#endif
5715
5716
5717
5718#if MG_ENABLE_OPENSSL
5719static int mg_tls_err(struct mg_tls *tls, int res) {
5720 int err = SSL_get_error(tls->ssl, res);
5721 // We've just fetched the last error from the queue.
5722 // Now we need to clear the error queue. If we do not, then the following
5723 // can happen (actually reported):
5724 // - A new connection is accept()-ed with cert error (e.g. self-signed cert)
5725 // - Since all accept()-ed connections share listener's context,
5726 // - *ALL* SSL accepted connection report read error on the next poll cycle.
5727 // Thus a single errored connection can close all the rest, unrelated ones.
5728 // Clearing the error keeps the shared SSL_CTX in an OK state.
5729
5730 if (err != 0) ERR_print_errors_fp(stderr);
5731 ERR_clear_error();
5732 if (err == SSL_ERROR_WANT_READ) return 0;
5733 if (err == SSL_ERROR_WANT_WRITE) return 0;
5734 return err;
5735}
5736
5737void mg_tls_init(struct mg_connection *c, const struct mg_tls_opts *opts) {
5738 struct mg_tls *tls = (struct mg_tls *) calloc(1, sizeof(*tls));
5739 const char *id = "mongoose";
5740 static unsigned char s_initialised = 0;
5741 int rc;
5742
5743 if (tls == NULL) {
5744 mg_error(c, "TLS OOM");
5745 goto fail;
5746 }
5747
5748 if (!s_initialised) {
5749 SSL_library_init();
5750 s_initialised++;
5751 }
5752 MG_DEBUG(("%lu Setting TLS, CA: %s, cert: %s, key: %s", c->id,
5753 opts->ca == NULL ? "null" : opts->ca,
5754 opts->cert == NULL ? "null" : opts->cert,
5755 opts->certkey == NULL ? "null" : opts->certkey));
5756 tls->ctx = c->is_client ? SSL_CTX_new(SSLv23_client_method())
5757 : SSL_CTX_new(SSLv23_server_method());
5758 if ((tls->ssl = SSL_new(tls->ctx)) == NULL) {
5759 mg_error(c, "SSL_new");
5760 goto fail;
5761 }
5762 SSL_set_session_id_context(tls->ssl, (const uint8_t *) id,
5763 (unsigned) strlen(id));
5764 // Disable deprecated protocols
5765 SSL_set_options(tls->ssl, SSL_OP_NO_SSLv2);
5766 SSL_set_options(tls->ssl, SSL_OP_NO_SSLv3);
5767 SSL_set_options(tls->ssl, SSL_OP_NO_TLSv1);
5768 SSL_set_options(tls->ssl, SSL_OP_NO_TLSv1_1);
5769#ifdef MG_ENABLE_OPENSSL_NO_COMPRESSION
5770 SSL_set_options(tls->ssl, SSL_OP_NO_COMPRESSION);
5771#endif
5772#ifdef MG_ENABLE_OPENSSL_CIPHER_SERVER_PREFERENCE
5773 SSL_set_options(tls->ssl, SSL_OP_CIPHER_SERVER_PREFERENCE);
5774#endif
5775
5776 if (opts->ca != NULL && opts->ca[0] != '\0') {
5777 SSL_set_verify(tls->ssl, SSL_VERIFY_PEER | SSL_VERIFY_FAIL_IF_NO_PEER_CERT,
5778 NULL);
5779 if ((rc = SSL_CTX_load_verify_locations(tls->ctx, opts->ca, NULL)) != 1) {
5780 mg_error(c, "load('%s') %d err %d", opts->ca, rc, mg_tls_err(tls, rc));
5781 goto fail;
5782 }
5783 }
5784 if (opts->cert != NULL && opts->cert[0] != '\0') {
5785 const char *key = opts->certkey;
5786 if (key == NULL) key = opts->cert;
5787 if ((rc = SSL_use_certificate_file(tls->ssl, opts->cert, 1)) != 1) {
5788 mg_error(c, "Invalid SSL cert, err %d", mg_tls_err(tls, rc));
5789 goto fail;
5790 } else if ((rc = SSL_use_PrivateKey_file(tls->ssl, key, 1)) != 1) {
5791 mg_error(c, "Invalid SSL key, err %d", mg_tls_err(tls, rc));
5792 goto fail;
5793#if OPENSSL_VERSION_NUMBER > 0x10100000L
5794 } else if ((rc = SSL_use_certificate_chain_file(tls->ssl, opts->cert)) !=
5795 1) {
5796 mg_error(c, "Invalid chain, err %d", mg_tls_err(tls, rc));
5797 goto fail;
5798#endif
5799 } else {
5800 SSL_set_mode(tls->ssl, SSL_MODE_ACCEPT_MOVING_WRITE_BUFFER);
5801#if OPENSSL_VERSION_NUMBER > 0x10002000L
5802 SSL_set_ecdh_auto(tls->ssl, 1);
5803#endif
5804 }
5805 }
5806 if (opts->ciphers != NULL) SSL_set_cipher_list(tls->ssl, opts->ciphers);
5807#if OPENSSL_VERSION_NUMBER >= 0x10100000L
5808 if (opts->srvname.len > 0) {
5809 char *s = mg_mprintf("%.*s", (int) opts->srvname.len, opts->srvname.ptr);
5810 SSL_set1_host(tls->ssl, s);
5811 SSL_set_tlsext_host_name(tls->ssl, s);
5812 free(s);
5813 }
5814#endif
5815 c->tls = tls;
5816 c->is_tls = 1;
5817 c->is_tls_hs = 1;
5818 if (c->is_client && c->is_resolving == 0 && c->is_connecting == 0) {
5819 mg_tls_handshake(c);
5820 }
5821 MG_DEBUG(("%lu SSL %s OK", c->id, c->is_accepted ? "accept" : "client"));
5822 return;
5823fail:
5824 c->is_closing = 1;
5825 free(tls);
5826}
5827
5828void mg_tls_handshake(struct mg_connection *c) {
5829 struct mg_tls *tls = (struct mg_tls *) c->tls;
5830 int rc;
5831 SSL_set_fd(tls->ssl, (int) (size_t) c->fd);
5832 rc = c->is_client ? SSL_connect(tls->ssl) : SSL_accept(tls->ssl);
5833 if (rc == 1) {
5834 MG_DEBUG(("%lu success", c->id));
5835 c->is_tls_hs = 0;
5836 mg_call(c, MG_EV_TLS_HS, NULL);
5837 } else {
5838 int code = mg_tls_err(tls, rc);
5839 if (code != 0) mg_error(c, "tls hs: rc %d, err %d", rc, code);
5840 }
5841}
5842
5843void mg_tls_free(struct mg_connection *c) {
5844 struct mg_tls *tls = (struct mg_tls *) c->tls;
5845 if (tls == NULL) return;
5846 SSL_free(tls->ssl);
5847 SSL_CTX_free(tls->ctx);
5848 free(tls);
5849 c->tls = NULL;
5850}
5851
5852size_t mg_tls_pending(struct mg_connection *c) {
5853 struct mg_tls *tls = (struct mg_tls *) c->tls;
5854 return tls == NULL ? 0 : (size_t) SSL_pending(tls->ssl);
5855}
5856
5857long mg_tls_recv(struct mg_connection *c, void *buf, size_t len) {
5858 struct mg_tls *tls = (struct mg_tls *) c->tls;
5859 int n = SSL_read(tls->ssl, buf, (int) len);
5860 if (n < 0 && mg_tls_err(tls, n) == 0) return MG_IO_WAIT;
5861 if (n <= 0) return MG_IO_ERR;
5862 return n;
5863}
5864
5865long mg_tls_send(struct mg_connection *c, const void *buf, size_t len) {
5866 struct mg_tls *tls = (struct mg_tls *) c->tls;
5867 int n = SSL_write(tls->ssl, buf, (int) len);
5868 if (n < 0 && mg_tls_err(tls, n) == 0) return MG_IO_WAIT;
5869 if (n <= 0) return MG_IO_ERR;
5870 return n;
5871}
5872#endif
5873
5874#ifdef MG_ENABLE_LINES
5875#line 1 "src/url.c"
5876#endif
5877
5878
5879struct url {
5880 size_t key, user, pass, host, port, uri, end;
5881};
5882
5883int mg_url_is_ssl(const char *url) {
5884 return strncmp(url, "wss:", 4) == 0 || strncmp(url, "https:", 6) == 0 ||
5885 strncmp(url, "mqtts:", 6) == 0 || strncmp(url, "ssl:", 4) == 0 ||
5886 strncmp(url, "tls:", 4) == 0;
5887}
5888
5889static struct url urlparse(const char *url) {
5890 size_t i;
5891 struct url u;
5892 memset(&u, 0, sizeof(u));
5893 for (i = 0; url[i] != '\0'; i++) {
5894 if (url[i] == '/' && i > 0 && u.host == 0 && url[i - 1] == '/') {
5895 u.host = i + 1;
5896 u.port = 0;
5897 } else if (url[i] == ']') {
5898 u.port = 0; // IPv6 URLs, like http://[::1]/bar
5899 } else if (url[i] == ':' && u.port == 0 && u.uri == 0) {
5900 u.port = i + 1;
5901 } else if (url[i] == '@' && u.user == 0 && u.pass == 0 && u.uri == 0) {
5902 u.user = u.host;
5903 u.pass = u.port;
5904 u.host = i + 1;
5905 u.port = 0;
5906 } else if (url[i] == '/' && u.host && u.uri == 0) {
5907 u.uri = i;
5908 }
5909 }
5910 u.end = i;
5911#if 0
5912 printf("[%s] %d %d %d %d %d\n", url, u.user, u.pass, u.host, u.port, u.uri);
5913#endif
5914 return u;
5915}
5916
5917struct mg_str mg_url_host(const char *url) {
5918 struct url u = urlparse(url);
5919 size_t n = u.port ? u.port - u.host - 1
5920 : u.uri ? u.uri - u.host
5921 : u.end - u.host;
5922 struct mg_str s = mg_str_n(url + u.host, n);
5923 return s;
5924}
5925
5926const char *mg_url_uri(const char *url) {
5927 struct url u = urlparse(url);
5928 return u.uri ? url + u.uri : "/";
5929}
5930
5931unsigned short mg_url_port(const char *url) {
5932 struct url u = urlparse(url);
5933 unsigned short port = 0;
5934 if (strncmp(url, "http:", 5) == 0 || strncmp(url, "ws:", 3) == 0) port = 80;
5935 if (strncmp(url, "wss:", 4) == 0 || strncmp(url, "https:", 6) == 0)
5936 port = 443;
5937 if (strncmp(url, "mqtt:", 5) == 0) port = 1883;
5938 if (strncmp(url, "mqtts:", 6) == 0) port = 8883;
5939 if (u.port) port = (unsigned short) atoi(url + u.port);
5940 return port;
5941}
5942
5943struct mg_str mg_url_user(const char *url) {
5944 struct url u = urlparse(url);
5945 struct mg_str s = mg_str("");
5946 if (u.user && (u.pass || u.host)) {
5947 size_t n = u.pass ? u.pass - u.user - 1 : u.host - u.user - 1;
5948 s = mg_str_n(url + u.user, n);
5949 }
5950 return s;
5951}
5952
5953struct mg_str mg_url_pass(const char *url) {
5954 struct url u = urlparse(url);
5955 struct mg_str s = mg_str_n("", 0UL);
5956 if (u.pass && u.host) {
5957 size_t n = u.host - u.pass - 1;
5958 s = mg_str_n(url + u.pass, n);
5959 }
5960 return s;
5961}
5962
5963#ifdef MG_ENABLE_LINES
5964#line 1 "src/util.c"
5965#endif
5966
5967
5968#if MG_ENABLE_CUSTOM_RANDOM
5969#else
5970void mg_random(void *buf, size_t len) {
5971 bool done = false;
5972 unsigned char *p = (unsigned char *) buf;
5973#if MG_ARCH == MG_ARCH_ESP32
5974 while (len--) *p++ = (unsigned char) (esp_random() & 255);
5975 done = true;
5976#elif MG_ARCH == MG_ARCH_WIN32
5977#elif MG_ARCH == MG_ARCH_UNIX
5978 FILE *fp = fopen("/dev/urandom", "rb");
5979 if (fp != NULL) {
5980 if (fread(buf, 1, len, fp) == len) done = true;
5981 fclose(fp);
5982 }
5983#endif
5984 // If everything above did not work, fallback to a pseudo random generator
5985 while (!done && len--) *p++ = (unsigned char) (rand() & 255);
5986}
5987#endif
5988
5989char *mg_random_str(char *buf, size_t len) {
5990 size_t i;
5991 mg_random(buf, len);
5992 for (i = 0; i < len; i++) {
5993 uint8_t c = ((uint8_t *) buf)[i] % 62U;
5994 buf[i] = i == len - 1 ? (char) '\0' // 0-terminate last byte
5995 : c < 26 ? (char) ('a' + c) // lowercase
5996 : c < 52 ? (char) ('A' + c - 26) // uppercase
5997 : (char) ('0' + c - 52); // numeric
5998 }
5999 return buf;
6000}
6001
6002uint32_t mg_ntohl(uint32_t net) {
6003 uint8_t data[4] = {0, 0, 0, 0};
6004 memcpy(&data, &net, sizeof(data));
6005 return (((uint32_t) data[3]) << 0) | (((uint32_t) data[2]) << 8) |
6006 (((uint32_t) data[1]) << 16) | (((uint32_t) data[0]) << 24);
6007}
6008
6009uint16_t mg_ntohs(uint16_t net) {
6010 uint8_t data[2] = {0, 0};
6011 memcpy(&data, &net, sizeof(data));
6012 return (uint16_t) ((uint16_t) data[1] | (((uint16_t) data[0]) << 8));
6013}
6014
6015uint32_t mg_crc32(uint32_t crc, const char *buf, size_t len) {
6016 static const uint32_t crclut[16] = {
6017 // table for polynomial 0xEDB88320 (reflected)
6018 0x00000000, 0x1DB71064, 0x3B6E20C8, 0x26D930AC, 0x76DC4190, 0x6B6B51F4,
6019 0x4DB26158, 0x5005713C, 0xEDB88320, 0xF00F9344, 0xD6D6A3E8, 0xCB61B38C,
6020 0x9B64C2B0, 0x86D3D2D4, 0xA00AE278, 0xBDBDF21C};
6021 crc = ~crc;
6022 while (len--) {
6023 uint8_t byte = *(uint8_t *)buf++;
6024 crc = crclut[(crc ^ byte) & 0x0F] ^ (crc >> 4);
6025 crc = crclut[(crc ^ (byte >> 4)) & 0x0F] ^ (crc >> 4);
6026 }
6027 return ~crc;
6028}
6029
6030static int isbyte(int n) {
6031 return n >= 0 && n <= 255;
6032}
6033
6034static int parse_net(const char *spec, uint32_t *net, uint32_t *mask) {
6035 int n, a, b, c, d, slash = 32, len = 0;
6036 if ((sscanf(spec, "%d.%d.%d.%d/%d%n", &a, &b, &c, &d, &slash, &n) == 5 ||
6037 sscanf(spec, "%d.%d.%d.%d%n", &a, &b, &c, &d, &n) == 4) &&
6038 isbyte(a) && isbyte(b) && isbyte(c) && isbyte(d) && slash >= 0 &&
6039 slash < 33) {
6040 len = n;
6041 *net = ((uint32_t) a << 24) | ((uint32_t) b << 16) | ((uint32_t) c << 8) |
6042 (uint32_t) d;
6043 *mask = slash ? (uint32_t) (0xffffffffU << (32 - slash)) : (uint32_t) 0;
6044 }
6045 return len;
6046}
6047
6048int mg_check_ip_acl(struct mg_str acl, uint32_t remote_ip) {
6049 struct mg_str k, v;
6050 int allowed = acl.len == 0 ? '+' : '-'; // If any ACL is set, deny by default
6051 while (mg_commalist(&acl, &k, &v)) {
6052 uint32_t net, mask;
6053 if (k.ptr[0] != '+' && k.ptr[0] != '-') return -1;
6054 if (parse_net(&k.ptr[1], &net, &mask) == 0) return -2;
6055 if ((mg_ntohl(remote_ip) & mask) == net) allowed = k.ptr[0];
6056 }
6057 return allowed == '+';
6058}
6059
6060#if MG_ENABLE_CUSTOM_MILLIS
6061#else
6062uint64_t mg_millis(void) {
6063#if MG_ARCH == MG_ARCH_WIN32
6064 return GetTickCount();
6065#elif MG_ARCH == MG_ARCH_RP2040
6066 return time_us_64() / 1000;
6067#elif MG_ARCH == MG_ARCH_ESP32
6068 return esp_timer_get_time() / 1000;
6069#elif MG_ARCH == MG_ARCH_ESP8266 || MG_ARCH == MG_ARCH_FREERTOS
6070 return xTaskGetTickCount() * portTICK_PERIOD_MS;
6071#elif MG_ARCH == MG_ARCH_AZURERTOS
6072 return tx_time_get() * (1000 /* MS per SEC */ / TX_TIMER_TICKS_PER_SECOND);
6073#elif MG_ARCH == MG_ARCH_TIRTOS
6074 return (uint64_t) Clock_getTicks();
6075#elif MG_ARCH == MG_ARCH_ZEPHYR
6076 return (uint64_t) k_uptime_get();
6077#elif MG_ARCH == MG_ARCH_CMSIS_RTOS1
6078 return (uint64_t)rt_time_get();
6079#elif MG_ARCH == MG_ARCH_CMSIS_RTOS2
6080 return (uint64_t)((osKernelGetTickCount() * 1000) / osKernelGetTickFreq());
6081#elif MG_ARCH == MG_ARCH_RTTHREAD
6082 return (uint64_t) ((rt_tick_get() * 1000) / RT_TICK_PER_SECOND);
6083#elif MG_ARCH == MG_ARCH_UNIX && defined(__APPLE__)
6084 // Apple CLOCK_MONOTONIC_RAW is equivalent to CLOCK_BOOTTIME on linux
6085 // Apple CLOCK_UPTIME_RAW is equivalent to CLOCK_MONOTONIC_RAW on linux
6086 return clock_gettime_nsec_np(CLOCK_UPTIME_RAW) / 1000000;
6087#elif MG_ARCH == MG_ARCH_UNIX
6088 struct timespec ts = {0, 0};
6089 // See #1615 - prefer monotonic clock
6090#if defined(CLOCK_MONOTONIC_RAW)
6091 // Raw hardware-based time that is not subject to NTP adjustment
6092 clock_gettime(CLOCK_MONOTONIC_RAW, &ts);
6093#elif defined(CLOCK_MONOTONIC)
6094 // Affected by the incremental adjustments performed by adjtime and NTP
6095 clock_gettime(CLOCK_MONOTONIC, &ts);
6096#else
6097 // Affected by discontinuous jumps in the system time and by the incremental
6098 // adjustments performed by adjtime and NTP
6099 clock_gettime(CLOCK_REALTIME, &ts);
6100#endif
6101 return ((uint64_t) ts.tv_sec * 1000 + (uint64_t) ts.tv_nsec / 1000000);
6102#elif defined(ARDUINO)
6103 return (uint64_t) millis();
6104#else
6105 return (uint64_t) (time(NULL) * 1000);
6106#endif
6107}
6108#endif
6109
6110#ifdef MG_ENABLE_LINES
6111#line 1 "src/ws.c"
6112#endif
6113
6114
6115
6116
6117
6118
6119
6120
6121
6122
6123
6124struct ws_msg {
6125 uint8_t flags;
6126 size_t header_len;
6127 size_t data_len;
6128};
6129
6130size_t mg_ws_vprintf(struct mg_connection *c, int op, const char *fmt,
6131 va_list *ap) {
6132 size_t len = c->send.len;
6133 size_t n = mg_vxprintf(mg_pfn_iobuf, &c->send, fmt, ap);
6134 mg_ws_wrap(c, c->send.len - len, op);
6135 return n;
6136}
6137
6138size_t mg_ws_printf(struct mg_connection *c, int op, const char *fmt, ...) {
6139 size_t len = 0;
6140 va_list ap;
6141 va_start(ap, fmt);
6142 len = mg_ws_vprintf(c, op, fmt, &ap);
6143 va_end(ap);
6144 return len;
6145}
6146
6147static void ws_handshake(struct mg_connection *c, const struct mg_str *wskey,
6148 const struct mg_str *wsproto, const char *fmt,
6149 va_list *ap) {
6150 const char *magic = "258EAFA5-E914-47DA-95CA-C5AB0DC85B11";
6151 unsigned char sha[20], b64_sha[30];
6152
6153 mg_sha1_ctx sha_ctx;
6154 mg_sha1_init(&sha_ctx);
6155 mg_sha1_update(&sha_ctx, (unsigned char *) wskey->ptr, wskey->len);
6156 mg_sha1_update(&sha_ctx, (unsigned char *) magic, 36);
6157 mg_sha1_final(sha, &sha_ctx);
6158 mg_base64_encode(sha, sizeof(sha), (char *) b64_sha);
6159 mg_xprintf(mg_pfn_iobuf, &c->send,
6160 "HTTP/1.1 101 Switching Protocols\r\n"
6161 "Upgrade: websocket\r\n"
6162 "Connection: Upgrade\r\n"
6163 "Sec-WebSocket-Accept: %s\r\n",
6164 b64_sha);
6165 if (fmt != NULL) mg_vxprintf(mg_pfn_iobuf, &c->send, fmt, ap);
6166 if (wsproto != NULL) {
6167 mg_printf(c, "Sec-WebSocket-Protocol: %.*s\r\n", (int) wsproto->len,
6168 wsproto->ptr);
6169 }
6170 mg_send(c, "\r\n", 2);
6171}
6172
6173static uint32_t be32(const uint8_t *p) {
6174 return (((uint32_t) p[3]) << 0) | (((uint32_t) p[2]) << 8) |
6175 (((uint32_t) p[1]) << 16) | (((uint32_t) p[0]) << 24);
6176}
6177
6178static size_t ws_process(uint8_t *buf, size_t len, struct ws_msg *msg) {
6179 size_t i, n = 0, mask_len = 0;
6180 memset(msg, 0, sizeof(*msg));
6181 if (len >= 2) {
6182 n = buf[1] & 0x7f; // Frame length
6183 mask_len = buf[1] & 128 ? 4 : 0; // last bit is a mask bit
6184 msg->flags = buf[0];
6185 if (n < 126 && len >= mask_len) {
6186 msg->data_len = n;
6187 msg->header_len = 2 + mask_len;
6188 } else if (n == 126 && len >= 4 + mask_len) {
6189 msg->header_len = 4 + mask_len;
6190 msg->data_len = (((size_t) buf[2]) << 8) | buf[3];
6191 } else if (len >= 10 + mask_len) {
6192 msg->header_len = 10 + mask_len;
6193 msg->data_len =
6194 (size_t) (((uint64_t) be32(buf + 2) << 32) + be32(buf + 6));
6195 }
6196 }
6197 // Sanity check, and integer overflow protection for the boundary check below
6198 // data_len should not be larger than 1 Gb
6199 if (msg->data_len > 1024 * 1024 * 1024) return 0;
6200 if (msg->header_len + msg->data_len > len) return 0;
6201 if (mask_len > 0) {
6202 uint8_t *p = buf + msg->header_len, *m = p - mask_len;
6203 for (i = 0; i < msg->data_len; i++) p[i] ^= m[i & 3];
6204 }
6205 return msg->header_len + msg->data_len;
6206}
6207
6208static size_t mkhdr(size_t len, int op, bool is_client, uint8_t *buf) {
6209 size_t n = 0;
6210 buf[0] = (uint8_t) (op | 128);
6211 if (len < 126) {
6212 buf[1] = (unsigned char) len;
6213 n = 2;
6214 } else if (len < 65536) {
6215 uint16_t tmp = mg_htons((uint16_t) len);
6216 buf[1] = 126;
6217 memcpy(&buf[2], &tmp, sizeof(tmp));
6218 n = 4;
6219 } else {
6220 uint32_t tmp;
6221 buf[1] = 127;
6222 tmp = mg_htonl((uint32_t) (((uint64_t) len) >> 32));
6223 memcpy(&buf[2], &tmp, sizeof(tmp));
6224 tmp = mg_htonl((uint32_t) (len & 0xffffffffU));
6225 memcpy(&buf[6], &tmp, sizeof(tmp));
6226 n = 10;
6227 }
6228 if (is_client) {
6229 buf[1] |= 1 << 7; // Set masking flag
6230 mg_random(&buf[n], 4);
6231 n += 4;
6232 }
6233 return n;
6234}
6235
6236static void mg_ws_mask(struct mg_connection *c, size_t len) {
6237 if (c->is_client && c->send.buf != NULL) {
6238 size_t i;
6239 uint8_t *p = c->send.buf + c->send.len - len, *mask = p - 4;
6240 for (i = 0; i < len; i++) p[i] ^= mask[i & 3];
6241 }
6242}
6243
6244size_t mg_ws_send(struct mg_connection *c, const void *buf, size_t len,
6245 int op) {
6246 uint8_t header[14];
6247 size_t header_len = mkhdr(len, op, c->is_client, header);
6248 mg_send(c, header, header_len);
6249 MG_VERBOSE(("WS out: %d [%.*s]", (int) len, (int) len, buf));
6250 mg_send(c, buf, len);
6251 mg_ws_mask(c, len);
6252 return header_len + len;
6253}
6254
6255static bool mg_ws_client_handshake(struct mg_connection *c) {
6256 int n = mg_http_get_request_len(c->recv.buf, c->recv.len);
6257 if (n < 0) {
6258 mg_error(c, "not http"); // Some just, not an HTTP request
6259 } else if (n > 0) {
6260 if (n < 15 || memcmp(c->recv.buf + 9, "101", 3) != 0) {
6261 mg_error(c, "handshake error");
6262 } else {
6263 struct mg_http_message hm;
6264 mg_http_parse((char *) c->recv.buf, c->recv.len, &hm);
6265 c->is_websocket = 1;
6266 mg_call(c, MG_EV_WS_OPEN, &hm);
6267 }
6268 mg_iobuf_del(&c->recv, 0, (size_t) n);
6269 } else {
6270 return true; // Request is not yet received, quit event handler
6271 }
6272 return false; // Continue event handler
6273}
6274
6275static void mg_ws_cb(struct mg_connection *c, int ev, void *ev_data,
6276 void *fn_data) {
6277 struct ws_msg msg;
6278 size_t ofs = (size_t) c->pfn_data;
6279
6280 // assert(ofs < c->recv.len);
6281 if (ev == MG_EV_READ) {
6282 if (c->is_client && !c->is_websocket && mg_ws_client_handshake(c)) return;
6283
6284 while (ws_process(c->recv.buf + ofs, c->recv.len - ofs, &msg) > 0) {
6285 char *s = (char *) c->recv.buf + ofs + msg.header_len;
6286 struct mg_ws_message m = {{s, msg.data_len}, msg.flags};
6287 size_t len = msg.header_len + msg.data_len;
6288 uint8_t final = msg.flags & 128, op = msg.flags & 15;
6289 // MG_VERBOSE ("fin %d op %d len %d [%.*s]", final, op,
6290 // (int) m.data.len, (int) m.data.len, m.data.ptr));
6291 switch (op) {
6292 case WEBSOCKET_OP_CONTINUE:
6293 mg_call(c, MG_EV_WS_CTL, &m);
6294 break;
6295 case WEBSOCKET_OP_PING:
6296 MG_DEBUG(("%s", "WS PONG"));
6297 mg_ws_send(c, s, msg.data_len, WEBSOCKET_OP_PONG);
6298 mg_call(c, MG_EV_WS_CTL, &m);
6299 break;
6300 case WEBSOCKET_OP_PONG:
6301 mg_call(c, MG_EV_WS_CTL, &m);
6302 break;
6303 case WEBSOCKET_OP_TEXT:
6304 case WEBSOCKET_OP_BINARY:
6305 if (final) mg_call(c, MG_EV_WS_MSG, &m);
6306 break;
6307 case WEBSOCKET_OP_CLOSE:
6308 MG_DEBUG(("%lu WS CLOSE", c->id));
6309 mg_call(c, MG_EV_WS_CTL, &m);
6310 // Echo the payload of the received CLOSE message back to the sender
6311 mg_ws_send(c, m.data.ptr, m.data.len, WEBSOCKET_OP_CLOSE);
6312 c->is_draining = 1;
6313 break;
6314 default:
6315 // Per RFC6455, close conn when an unknown op is recvd
6316 mg_error(c, "unknown WS op %d", op);
6317 break;
6318 }
6319
6320 // Handle fragmented frames: strip header, keep in c->recv
6321 if (final == 0 || op == 0) {
6322 if (op) ofs++, len--, msg.header_len--; // First frame
6323 mg_iobuf_del(&c->recv, ofs, msg.header_len); // Strip header
6324 len -= msg.header_len;
6325 ofs += len;
6326 c->pfn_data = (void *) ofs;
6327 // MG_INFO(("FRAG %d [%.*s]", (int) ofs, (int) ofs, c->recv.buf));
6328 }
6329 // Remove non-fragmented frame
6330 if (final && op) mg_iobuf_del(&c->recv, ofs, len);
6331 // Last chunk of the fragmented frame
6332 if (final && !op) {
6333 m.flags = c->recv.buf[0];
6334 m.data = mg_str_n((char *) &c->recv.buf[1], (size_t) (ofs - 1));
6335 mg_call(c, MG_EV_WS_MSG, &m);
6336 mg_iobuf_del(&c->recv, 0, ofs);
6337 ofs = 0;
6338 c->pfn_data = NULL;
6339 }
6340 }
6341 }
6342 (void) fn_data;
6343 (void) ev_data;
6344}
6345
6346struct mg_connection *mg_ws_connect(struct mg_mgr *mgr, const char *url,
6347 mg_event_handler_t fn, void *fn_data,
6348 const char *fmt, ...) {
6349 struct mg_connection *c = mg_connect(mgr, url, fn, fn_data);
6350 if (c != NULL) {
6351 char nonce[16], key[30];
6352 struct mg_str host = mg_url_host(url);
6353 mg_random(nonce, sizeof(nonce));
6354 mg_base64_encode((unsigned char *) nonce, sizeof(nonce), key);
6355 mg_xprintf(mg_pfn_iobuf, &c->send,
6356 "GET %s HTTP/1.1\r\n"
6357 "Upgrade: websocket\r\n"
6358 "Host: %.*s\r\n"
6359 "Connection: Upgrade\r\n"
6360 "Sec-WebSocket-Version: 13\r\n"
6361 "Sec-WebSocket-Key: %s\r\n",
6362 mg_url_uri(url), (int) host.len, host.ptr, key);
6363 if (fmt != NULL) {
6364 va_list ap;
6365 va_start(ap, fmt);
6366 mg_vxprintf(mg_pfn_iobuf, &c->send, fmt, &ap);
6367 va_end(ap);
6368 }
6369 mg_xprintf(mg_pfn_iobuf, &c->send, "\r\n");
6370 c->pfn = mg_ws_cb;
6371 c->pfn_data = NULL;
6372 }
6373 return c;
6374}
6375
6376void mg_ws_upgrade(struct mg_connection *c, struct mg_http_message *hm,
6377 const char *fmt, ...) {
6378 struct mg_str *wskey = mg_http_get_header(hm, "Sec-WebSocket-Key");
6379 c->pfn = mg_ws_cb;
6380 c->pfn_data = NULL;
6381 if (wskey == NULL) {
6382 mg_http_reply(c, 426, "", "WS upgrade expected\n");
6383 c->is_draining = 1;
6384 } else {
6385 struct mg_str *wsproto = mg_http_get_header(hm, "Sec-WebSocket-Protocol");
6386 va_list ap;
6387 va_start(ap, fmt);
6388 ws_handshake(c, wskey, wsproto, fmt, &ap);
6389 va_end(ap);
6390 c->is_websocket = 1;
6391 c->is_resp = 0;
6392 mg_call(c, MG_EV_WS_OPEN, hm);
6393 }
6394}
6395
6396size_t mg_ws_wrap(struct mg_connection *c, size_t len, int op) {
6397 uint8_t header[14], *p;
6398 size_t header_len = mkhdr(len, op, c->is_client, header);
6399
6400 // NOTE: order of operations is important!
6401 mg_iobuf_add(&c->send, c->send.len, NULL, header_len);
6402 p = &c->send.buf[c->send.len - len]; // p points to data
6403 memmove(p, p - header_len, len); // Shift data
6404 memcpy(p - header_len, header, header_len); // Prepend header
6405 mg_ws_mask(c, len); // Mask data
6406
6407 return c->send.len;
6408}
6409
6410#ifdef MG_ENABLE_LINES
6411#line 1 "src/tcpip/driver_nxpimxrt1020.c"
6412#endif
6413
6414
6415/*
6416 * Todo
6417 * This driver doesn't support 10M line autoconfiguration yet.
6418 * Packets aren't sent if the link negociated 10M line.
6419 * todo: MAC back auto reconfiguration.
6420 */
6421
6422#if MG_ENABLE_TCPIP && defined(MG_ENABLE_DRIVER_IMXRT1020)
6423struct imx_rt1020_enet {
6424volatile uint32_t RESERVED0, EIR, EIMR, RESERVED1, RDAR, TDAR, RESERVED2[3], ECR, RESERVED3[6], MMFR, MSCR, RESERVED4[7], MIBC, RESERVED5[7], RCR, RESERVED6[15], TCR, RESERVED7[7], PALR, PAUR, OPD, TXIC0, TXIC1, TXIC2, RESERVED8, RXIC0, RXIC1, RXIC2, RESERVED9[3], IAUR, IALR, GAUR, GALR, RESERVED10[7], TFWR, RESERVED11[14], RDSR, TDSR, MRBR[2], RSFL, RSEM, RAEM, RAFL, TSEM, TAEM, TAFL, TIPG, FTRL, RESERVED12[3], TACC, RACC, RESERVED13[15], RMON_T_PACKETS, RMON_T_BC_PKT, RMON_T_MC_PKT, RMON_T_CRC_ALIGN, RMON_T_UNDERSIZE, RMON_T_OVERSIZE, RMON_T_FRAG, RMON_T_JAB, RMON_T_COL, RMON_T_P64, RMON_T_P65TO127, RMON_T_P128TO255, RMON_T_P256TO511, RMON_T_P512TO1023, RMON_T_P1024TO2048, RMON_T_GTE2048, RMON_T_OCTETS, IEEE_T_DROP, IEEE_T_FRAME_OK, IEEE_T_1COL, IEEE_T_MCOL, IEEE_T_DEF, IEEE_T_LCOL, IEEE_T_EXCOL, IEEE_T_MACERR, IEEE_T_CSERR, IEEE_T_SQE, IEEE_T_FDXFC, IEEE_T_OCTETS_OK, RESERVED14[3], RMON_R_PACKETS, RMON_R_BC_PKT, RMON_R_MC_PKT, RMON_R_CRC_ALIGN, RMON_R_UNDERSIZE, RMON_R_OVERSIZE, RMON_R_FRAG, RMON_R_JAB, RESERVED15, RMON_R_P64, RMON_R_P65TO127, RMON_R_P128TO255, RMON_R_P256TO511, RMON_R_P512TO1023, RMON_R_P1024TO2047, RMON_R_GTE2048, RMON_R_OCTETS, IEEE_R_DROP, IEEE_R_FRAME_OK, IEEE_R_CRC, IEEE_R_ALIGN, IEEE_R_MACERR, IEEE_R_FDXFC, IEEE_R_OCTETS_OK, RESERVED16[71], ATCR, ATVR, ATOFF, ATPER, ATCOR, ATINC, ATSTMP, RESERVED17[122], TGSR, TCSR0, TCCR0, TCSR1, TCCR1, TCSR2, TCCR2, TCSR3;
6425};
6426
6427#undef ENET
6428#define ENET ((struct imx_rt1020_enet *) (uintptr_t) 0x402D8000u)
6429
6430#undef BIT
6431#define BIT(x) ((uint32_t) 1 << (x))
6432
6433#define ENET_RXBUFF_SIZE 1536 // 1522 Buffer must be 64bits aligned
6434#define ENET_TXBUFF_SIZE 1536 // 1522 hence set to 0x600 (1536)
6435#define ENET_RXBD_NUM (4)
6436#define ENET_TXBD_NUM (4)
6437
6438const uint32_t EIMR_RX_ERR = 0x2400000; // Intr mask RXF+EBERR
6439
6440void ETH_IRQHandler(void);
6441static bool mg_tcpip_driver_imxrt1020_init(struct mg_tcpip_if *ifp);
6442static void wait_phy_complete(void);
6443static struct mg_tcpip_if *s_ifp; // MIP interface
6444
6445static size_t mg_tcpip_driver_imxrt1020_tx(const void *, size_t , struct mg_tcpip_if *);
6446static bool mg_tcpip_driver_imxrt1020_up(struct mg_tcpip_if *ifp);
6447
6448enum { IMXRT1020_PHY_ADDR = 0x02, IMXRT1020_PHY_BCR = 0, IMXRT1020_PHY_BSR = 1 }; // PHY constants
6449
6450void delay(uint32_t);
6451void delay (uint32_t di) {
6452 volatile int dno = 0; // Prevent optimization
6453 for (uint32_t i = 0; i < di; i++)
6454 for (int j=0; j<20; j++) // PLLx20 (500 MHz/24MHz)
6455 dno++;
6456}
6457
6458static void wait_phy_complete(void) {
6459 delay(0x00010000);
6460 const uint32_t delay_max = 0x00100000;
6461 uint32_t delay_cnt = 0;
6462 while (!(ENET->EIR & BIT(23)) && (delay_cnt < delay_max))
6463 {delay_cnt++;}
6464 ENET->EIR |= BIT(23); // MII interrupt clear
6465}
6466
6467static uint32_t imxrt1020_eth_read_phy(uint8_t addr, uint8_t reg) {
6468 ENET->EIR |= BIT(23); // MII interrupt clear
6469 uint32_t mask_phy_adr_reg = 0x1f; // 0b00011111: Ensure we write 5 bits (Phy address & register)
6470 uint32_t phy_transaction = 0x00;
6471 phy_transaction = (0x1 << 30) \
6472 | (0x2 << 28) \
6473 | ((uint32_t)(addr & mask_phy_adr_reg) << 23) \
6474 | ((uint32_t)(reg & mask_phy_adr_reg) << 18) \
6475 | (0x2 << 16);
6476
6477 ENET->MMFR = phy_transaction;
6478 wait_phy_complete();
6479
6480 return (ENET->MMFR & 0x0000ffff);
6481}
6482
6483static void imxrt1020_eth_write_phy(uint8_t addr, uint8_t reg, uint32_t val) {
6484 ENET->EIR |= BIT(23); // MII interrupt clear
6485 uint8_t mask_phy_adr_reg = 0x1f; // 0b00011111: Ensure we write 5 bits (Phy address & register)
6486 uint32_t mask_phy_data = 0x0000ffff; // Ensure we write 16 bits (data)
6487 addr &= mask_phy_adr_reg;
6488 reg &= mask_phy_adr_reg;
6489 val &= mask_phy_data;
6490 uint32_t phy_transaction = 0x00;
6491 phy_transaction = (uint32_t)(0x1 << 30) \
6492 | (uint32_t)(0x1 << 28) \
6493 | (uint32_t)(addr << 23) \
6494 | (uint32_t)(reg << 18) \
6495 | (uint32_t)(0x2 << 16) \
6496 | (uint32_t)(val);
6497 ENET->MMFR = phy_transaction;
6498 wait_phy_complete();
6499}
6500
6501// FEC RX/TX descriptors (Enhanced descriptor not enabled)
6502// Descriptor buffer structure, little endian
6503
6504typedef struct enet_bd_struct_def
6505{
6506 uint16_t length; // Data length
6507 uint16_t control; // Control and status
6508 uint32_t *buffer; // Data ptr
6509} enet_bd_struct_t;
6510
6511// Descriptor and buffer globals, in non-cached area, 64 bits aligned.
6512
6513__attribute__((section("NonCacheable,\"aw\",%nobits @"))) enet_bd_struct_t rx_buffer_descriptor[(ENET_RXBD_NUM)] __attribute__((aligned((64U))));
6514__attribute__((section("NonCacheable,\"aw\",%nobits @"))) enet_bd_struct_t tx_buffer_descriptor[(ENET_TXBD_NUM)] __attribute__((aligned((64U))));
6515
6516uint8_t rx_data_buffer[(ENET_RXBD_NUM)][((unsigned int)(((ENET_RXBUFF_SIZE)) + (((64U))-1U)) & (unsigned int)(~(unsigned int)(((64U))-1U)))] __attribute__((aligned((64U))));
6517uint8_t tx_data_buffer[(ENET_TXBD_NUM)][((unsigned int)(((ENET_TXBUFF_SIZE)) + (((64U))-1U)) & (unsigned int)(~(unsigned int)(((64U))-1U)))] __attribute__((aligned((64U))));
6518
6519// Initialise driver imx_rt1020
6520
6521// static bool mg_tcpip_driver_imxrt1020_init(uint8_t *mac, void *data) { // VO
6522static bool mg_tcpip_driver_imxrt1020_init(struct mg_tcpip_if *ifp) {
6523
6524 struct mg_tcpip_driver_imxrt1020_data *d = (struct mg_tcpip_driver_imxrt1020_data *) ifp->driver_data;
6525 s_ifp = ifp;
6526
6527 // ENET Reset, wait complete
6528 ENET->ECR |= BIT(0);
6529 while((ENET->ECR & BIT(0)) != 0) {}
6530
6531 // Re-latches the pin strapping pin values
6532 ENET->ECR |= BIT(0);
6533 while((ENET->ECR & BIT(0)) != 0) {}
6534
6535 // Setup MII/RMII MDC clock divider (<= 2.5MHz).
6536 ENET->MSCR = 0x130; // HOLDTIME 2 clk, Preamble enable, MDC MII_Speed Div 0x30
6537 imxrt1020_eth_write_phy(IMXRT1020_PHY_ADDR, IMXRT1020_PHY_BCR, 0x8000); // PHY W @0x00 D=0x8000 Soft reset
6538 while (imxrt1020_eth_read_phy(IMXRT1020_PHY_ADDR, IMXRT1020_PHY_BSR) & BIT(15)) {delay(0x5000);} // Wait finished poll 10ms
6539
6540 // PHY: Start Link
6541 {
6542 imxrt1020_eth_write_phy(IMXRT1020_PHY_ADDR, IMXRT1020_PHY_BCR, 0x1200); // PHY W @0x00 D=0x1200 Autonego enable + start
6543 imxrt1020_eth_write_phy(IMXRT1020_PHY_ADDR, 0x1f, 0x8180); // PHY W @0x1f D=0x8180 Ref clock 50 MHz at XI input
6544
6545 uint32_t bcr = imxrt1020_eth_read_phy(IMXRT1020_PHY_ADDR, IMXRT1020_PHY_BCR);
6546 bcr &= ~BIT(10); // Isolation -> Normal
6547 imxrt1020_eth_write_phy(IMXRT1020_PHY_ADDR, IMXRT1020_PHY_BCR, bcr);
6548 }
6549
6550 // Disable ENET
6551 ENET->ECR = 0x0; // Disable before configuration
6552
6553 // Configure ENET
6554 ENET->RCR = 0x05ee0104; // #CRCFWD=0 (CRC kept in frame) + RMII + MII Enable
6555
6556 ENET->TCR = BIT(8) | BIT(2); // Addins (MAC address from PAUR+PALR) + Full duplex enable
6557 //ENET->TFWR = BIT(8); // Store And Forward Enable, 64 bytes (minimize tx latency)
6558
6559 // Configure descriptors and buffers
6560 // RX
6561 for (int i = 0; i < ENET_RXBD_NUM; i++) {
6562 // Wrap last descriptor buffer ptr
6563 rx_buffer_descriptor[i].control = (BIT(15) | ((i<(ENET_RXBD_NUM-1))?0:BIT(13))); // E+(W*)
6564 rx_buffer_descriptor[i].buffer = (uint32_t *)rx_data_buffer[i];
6565 }
6566
6567 // TX
6568 for (int i = 0; i < ENET_TXBD_NUM; i++) {
6569 // Wrap last descriptor buffer ptr
6570 tx_buffer_descriptor[i].control = ((i<(ENET_RXBD_NUM-1))?0:BIT(13)) | BIT(10); // (W*)+TC
6571 tx_buffer_descriptor[i].buffer = (uint32_t *)tx_data_buffer[i];
6572 }
6573
6574 // Continue ENET configuration
6575 ENET->RDSR = (uint32_t)(uintptr_t)rx_buffer_descriptor;
6576 ENET->TDSR = (uint32_t)(uintptr_t)tx_buffer_descriptor;
6577 ENET->MRBR[0] = ENET_RXBUFF_SIZE; // Same size for RX/TX buffers
6578
6579 // MAC address filtering (bytes in reversed order)
6580 ENET->PAUR = ((uint32_t) ifp->mac[4] << 24U) | (uint32_t) ifp->mac[5] << 16U;
6581 ENET->PALR = (uint32_t) (ifp->mac[0] << 24U) | ((uint32_t) ifp->mac[1] << 16U) |
6582 ((uint32_t) ifp->mac[2] << 8U) | ifp->mac[3];
6583
6584 // Init Hash tables (mac filtering)
6585 ENET->IAUR = 0; // Unicast
6586 ENET->IALR = 0;
6587 ENET->GAUR = 0; // Multicast
6588 ENET->GALR = 0;
6589
6590 // Set ENET Online
6591 ENET->ECR |= BIT(8); // ENET Set Little-endian + (FEC buffer desc.)
6592 ENET->ECR |= BIT(1); // Enable
6593
6594 // Set interrupt mask
6595 ENET->EIMR = EIMR_RX_ERR;
6596
6597 // RX Descriptor activation
6598 ENET->RDAR = BIT(24); // Activate Receive Descriptor
6599 return true;
6600}
6601
6602// Transmit frame
6603static uint32_t s_rt1020_txno;
6604
6605static size_t mg_tcpip_driver_imxrt1020_tx(const void *buf, size_t len, struct mg_tcpip_if *ifp) {
6606
6607 if (len > sizeof(tx_data_buffer[ENET_TXBD_NUM])) {
6608 // MG_ERROR(("Frame too big, %ld", (long) len));
6609 len = 0; // Frame is too big
6610 } else if ((tx_buffer_descriptor[s_rt1020_txno].control & BIT(15))) {
6611 MG_ERROR(("No free descriptors"));
6612 // printf("D0 %lx SR %lx\n", (long) s_txdesc[0][0], (long) ETH->DMASR);
6613 len = 0; // All descriptors are busy, fail
6614 } else {
6615 memcpy(tx_data_buffer[s_rt1020_txno], buf, len); // Copy data
6616 tx_buffer_descriptor[s_rt1020_txno].length = (uint16_t) len; // Set data len
6617 tx_buffer_descriptor[s_rt1020_txno].control |= (uint16_t)(BIT(10)); // TC (transmit CRC)
6618 // tx_buffer_descriptor[s_rt1020_txno].control &= (uint16_t)(BIT(14) | BIT(12)); // Own doesn't affect HW
6619 tx_buffer_descriptor[s_rt1020_txno].control |= (uint16_t)(BIT(15) | BIT(11)); // R+L (ready+last)
6620 ENET->TDAR = BIT(24); // Descriptor updated. Hand over to DMA.
6621 // INFO
6622 // Relevant Descriptor bits: 15(R) Ready
6623 // 11(L) last in frame
6624 // 10(TC) transmis CRC
6625 // __DSB(); // ARM errata 838869 Cortex-M4, M4F, M7, M7F: "store immediate overlapping
6626 // exception" return might vector to incorrect interrupt.
6627 if (++s_rt1020_txno >= ENET_TXBD_NUM) s_rt1020_txno = 0;
6628 }
6629 (void) ifp;
6630 return len;
6631}
6632
6633// IRQ (RX)
6634static uint32_t s_rt1020_rxno;
6635
6636void ENET_IRQHandler(void) {
6637 ENET->EIMR = 0; // Mask interrupts.
6638 uint32_t eir = ENET->EIR; // Read EIR
6639 ENET->EIR = 0xffffffff; // Clear interrupts
6640
6641 if (eir & EIMR_RX_ERR) // Global mask used
6642 {
6643 if (rx_buffer_descriptor[s_rt1020_rxno].control & BIT(15)) {
6644 ENET->EIMR = EIMR_RX_ERR; // Enable interrupts
6645 return; // Empty? -> exit.
6646 }
6647 // Read inframes
6648 else { // Frame received, loop
6649 for (uint32_t i = 0; i < 10; i++) { // read as they arrive but not forever
6650 if (rx_buffer_descriptor[s_rt1020_rxno].control & BIT(15)) break; // exit when done
6651 // Process if CRC OK and frame not truncated
6652 if (!(rx_buffer_descriptor[s_rt1020_rxno].control & (BIT(2) | BIT(0)))) {
6653 uint32_t len = (rx_buffer_descriptor[s_rt1020_rxno].length);
6654 mg_tcpip_qwrite(rx_buffer_descriptor[s_rt1020_rxno].buffer, len > 4 ? len - 4 : len, s_ifp);
6655 }
6656 rx_buffer_descriptor[s_rt1020_rxno].control |= BIT(15); // Inform DMA RX is empty
6657 if (++s_rt1020_rxno >= ENET_RXBD_NUM) s_rt1020_rxno = 0;
6658 }
6659 }
6660 }
6661 ENET->EIMR = EIMR_RX_ERR; // Enable interrupts
6662}
6663
6664// Up/down status
6665static bool mg_tcpip_driver_imxrt1020_up(struct mg_tcpip_if *ifp) {
6666 uint32_t bsr = imxrt1020_eth_read_phy(IMXRT1020_PHY_ADDR, IMXRT1020_PHY_BSR);
6667 (void) ifp;
6668 return bsr & BIT(2) ? 1 : 0;
6669}
6670
6671// API
6672struct mg_tcpip_driver mg_tcpip_driver_imxrt1020 = {
6673 mg_tcpip_driver_imxrt1020_init, mg_tcpip_driver_imxrt1020_tx, NULL,
6674 mg_tcpip_driver_imxrt1020_up};
6675
6676#endif
6677
6678#ifdef MG_ENABLE_LINES
6679#line 1 "src/tcpip/driver_stm32.c"
6680#endif
6681
6682
6683#if MG_ENABLE_TCPIP && MG_ENABLE_DRIVER_STM32
6684struct stm32_eth {
6685 volatile uint32_t MACCR, MACFFR, MACHTHR, MACHTLR, MACMIIAR, MACMIIDR, MACFCR,
6686 MACVLANTR, RESERVED0[2], MACRWUFFR, MACPMTCSR, RESERVED1, MACDBGR, MACSR,
6687 MACIMR, MACA0HR, MACA0LR, MACA1HR, MACA1LR, MACA2HR, MACA2LR, MACA3HR,
6688 MACA3LR, RESERVED2[40], MMCCR, MMCRIR, MMCTIR, MMCRIMR, MMCTIMR,
6689 RESERVED3[14], MMCTGFSCCR, MMCTGFMSCCR, RESERVED4[5], MMCTGFCR,
6690 RESERVED5[10], MMCRFCECR, MMCRFAECR, RESERVED6[10], MMCRGUFCR,
6691 RESERVED7[334], PTPTSCR, PTPSSIR, PTPTSHR, PTPTSLR, PTPTSHUR, PTPTSLUR,
6692 PTPTSAR, PTPTTHR, PTPTTLR, RESERVED8, PTPTSSR, PTPPPSCR, RESERVED9[564],
6693 DMABMR, DMATPDR, DMARPDR, DMARDLAR, DMATDLAR, DMASR, DMAOMR, DMAIER,
6694 DMAMFBOCR, DMARSWTR, RESERVED10[8], DMACHTDR, DMACHRDR, DMACHTBAR,
6695 DMACHRBAR;
6696};
6697#undef ETH
6698#define ETH ((struct stm32_eth *) (uintptr_t) 0x40028000)
6699
6700#undef DSB
6701#if defined(__CC_ARM)
6702#define DSB() __dsb(0xF)
6703#elif defined(__ARMCC_VERSION)
6704#define DSB() __builtin_arm_dsb(0xF)
6705#elif defined(__GNUC__) && defined(__arm__) && defined(__thumb__)
6706#define DSB() asm("DSB 0xF")
6707#elif defined(__ICCARM__)
6708#define DSB() __iar_builtin_DSB()
6709#else
6710#define DSB()
6711#endif
6712
6713#undef BIT
6714#define BIT(x) ((uint32_t) 1 << (x))
6715#define ETH_PKT_SIZE 1540 // Max frame size
6716#define ETH_DESC_CNT 4 // Descriptors count
6717#define ETH_DS 4 // Descriptor size (words)
6718
6719static uint32_t s_rxdesc[ETH_DESC_CNT][ETH_DS]; // RX descriptors
6720static uint32_t s_txdesc[ETH_DESC_CNT][ETH_DS]; // TX descriptors
6721static uint8_t s_rxbuf[ETH_DESC_CNT][ETH_PKT_SIZE]; // RX ethernet buffers
6722static uint8_t s_txbuf[ETH_DESC_CNT][ETH_PKT_SIZE]; // TX ethernet buffers
6723static uint8_t s_txno; // Current TX descriptor
6724static uint8_t s_rxno; // Current RX descriptor
6725
6726static struct mg_tcpip_if *s_ifp; // MIP interface
6727enum { PHY_ADDR = 0, PHY_BCR = 0, PHY_BSR = 1, PHY_CSCR = 31 };
6728
6729static uint32_t eth_read_phy(uint8_t addr, uint8_t reg) {
6730 ETH->MACMIIAR &= (7 << 2);
6731 ETH->MACMIIAR |= ((uint32_t) addr << 11) | ((uint32_t) reg << 6);
6732 ETH->MACMIIAR |= BIT(0);
6733 while (ETH->MACMIIAR & BIT(0)) (void) 0;
6734 return ETH->MACMIIDR;
6735}
6736
6737static void eth_write_phy(uint8_t addr, uint8_t reg, uint32_t val) {
6738 ETH->MACMIIDR = val;
6739 ETH->MACMIIAR &= (7 << 2);
6740 ETH->MACMIIAR |= ((uint32_t) addr << 11) | ((uint32_t) reg << 6) | BIT(1);
6741 ETH->MACMIIAR |= BIT(0);
6742 while (ETH->MACMIIAR & BIT(0)) (void) 0;
6743}
6744
6745static uint32_t get_hclk(void) {
6746 struct rcc {
6747 volatile uint32_t CR, PLLCFGR, CFGR;
6748 } *rcc = (struct rcc *) 0x40023800;
6749 uint32_t clk = 0, hsi = 16000000 /* 16 MHz */, hse = 8000000 /* 8MHz */;
6750
6751 if (rcc->CFGR & (1 << 2)) {
6752 clk = hse;
6753 } else if (rcc->CFGR & (1 << 3)) {
6754 uint32_t vco, m, n, p;
6755 m = (rcc->PLLCFGR & (0x3f << 0)) >> 0;
6756 n = (rcc->PLLCFGR & (0x1ff << 6)) >> 6;
6757 p = (((rcc->PLLCFGR & (3 << 16)) >> 16) + 1) * 2;
6758 clk = (rcc->PLLCFGR & (1 << 22)) ? hse : hsi;
6759 vco = (uint32_t) ((uint64_t) clk * n / m);
6760 clk = vco / p;
6761 } else {
6762 clk = hsi;
6763 }
6764 uint32_t hpre = (rcc->CFGR & (15 << 4)) >> 4;
6765 if (hpre < 8) return clk;
6766
6767 uint8_t ahbptab[8] = {1, 2, 3, 4, 6, 7, 8, 9}; // log2(div)
6768 return ((uint32_t) clk) >> ahbptab[hpre - 8];
6769}
6770
6771// Guess CR from HCLK. MDC clock is generated from HCLK (AHB); as per 802.3,
6772// it must not exceed 2.5MHz As the AHB clock can be (and usually is) derived
6773// from the HSI (internal RC), and it can go above specs, the datasheets
6774// specify a range of frequencies and activate one of a series of dividers to
6775// keep the MDC clock safely below 2.5MHz. We guess a divider setting based on
6776// HCLK with a +5% drift. If the user uses a different clock from our
6777// defaults, needs to set the macros on top Valid for STM32F74xxx/75xxx
6778// (38.8.1) and STM32F42xxx/43xxx (33.8.1) (both 4.5% worst case drift)
6779static int guess_mdc_cr(void) {
6780 uint8_t crs[] = {2, 3, 0, 1, 4, 5}; // ETH->MACMIIAR::CR values
6781 uint8_t div[] = {16, 26, 42, 62, 102, 124}; // Respective HCLK dividers
6782 uint32_t hclk = get_hclk(); // Guess system HCLK
6783 int result = -1; // Invalid CR value
6784 if (hclk < 25000000) {
6785 MG_ERROR(("HCLK too low"));
6786 } else {
6787 for (int i = 0; i < 6; i++) {
6788 if (hclk / div[i] <= 2375000UL /* 2.5MHz - 5% */) {
6789 result = crs[i];
6790 break;
6791 }
6792 }
6793 if (result < 0) MG_ERROR(("HCLK too high"));
6794 }
6795 MG_DEBUG(("HCLK: %u, CR: %d", hclk, result));
6796 return result;
6797}
6798
6799static bool mg_tcpip_driver_stm32_init(struct mg_tcpip_if *ifp) {
6800 struct mg_tcpip_driver_stm32_data *d =
6801 (struct mg_tcpip_driver_stm32_data *) ifp->driver_data;
6802 s_ifp = ifp;
6803
6804 // Init RX descriptors
6805 for (int i = 0; i < ETH_DESC_CNT; i++) {
6806 s_rxdesc[i][0] = BIT(31); // Own
6807 s_rxdesc[i][1] = sizeof(s_rxbuf[i]) | BIT(14); // 2nd address chained
6808 s_rxdesc[i][2] = (uint32_t) (uintptr_t) s_rxbuf[i]; // Point to data buffer
6809 s_rxdesc[i][3] =
6810 (uint32_t) (uintptr_t) s_rxdesc[(i + 1) % ETH_DESC_CNT]; // Chain
6811 }
6812
6813 // Init TX descriptors
6814 for (int i = 0; i < ETH_DESC_CNT; i++) {
6815 s_txdesc[i][2] = (uint32_t) (uintptr_t) s_txbuf[i]; // Buf pointer
6816 s_txdesc[i][3] =
6817 (uint32_t) (uintptr_t) s_txdesc[(i + 1) % ETH_DESC_CNT]; // Chain
6818 }
6819
6820 ETH->DMABMR |= BIT(0); // Software reset
6821 while ((ETH->DMABMR & BIT(0)) != 0) (void) 0; // Wait until done
6822
6823 // Set MDC clock divider. If user told us the value, use it. Otherwise, guess
6824 int cr = (d == NULL || d->mdc_cr < 0) ? guess_mdc_cr() : d->mdc_cr;
6825 ETH->MACMIIAR = ((uint32_t) cr & 7) << 2;
6826
6827 // NOTE(cpq): we do not use extended descriptor bit 7, and do not use
6828 // hardware checksum. Therefore, descriptor size is 4, not 8
6829 // ETH->DMABMR = BIT(13) | BIT(16) | BIT(22) | BIT(23) | BIT(25);
6830 ETH->MACIMR = BIT(3) | BIT(9); // Mask timestamp & PMT IT
6831 ETH->MACFCR = BIT(7); // Disable zero quarta pause
6832 // ETH->MACFFR = BIT(31); // Receive all
6833 eth_write_phy(PHY_ADDR, PHY_BCR, BIT(15)); // Reset PHY
6834 eth_write_phy(PHY_ADDR, PHY_BCR, BIT(12)); // Set autonegotiation
6835 ETH->DMARDLAR = (uint32_t) (uintptr_t) s_rxdesc; // RX descriptors
6836 ETH->DMATDLAR = (uint32_t) (uintptr_t) s_txdesc; // RX descriptors
6837 ETH->DMAIER = BIT(6) | BIT(16); // RIE, NISE
6838 ETH->MACCR = BIT(2) | BIT(3) | BIT(11) | BIT(14); // RE, TE, Duplex, Fast
6839 ETH->DMAOMR = BIT(1) | BIT(13) | BIT(21) | BIT(25); // SR, ST, TSF, RSF
6840
6841 // MAC address filtering
6842 ETH->MACA0HR = ((uint32_t) ifp->mac[5] << 8U) | ifp->mac[4];
6843 ETH->MACA0LR = (uint32_t) (ifp->mac[3] << 24) |
6844 ((uint32_t) ifp->mac[2] << 16) |
6845 ((uint32_t) ifp->mac[1] << 8) | ifp->mac[0];
6846 return true;
6847}
6848
6849static size_t mg_tcpip_driver_stm32_tx(const void *buf, size_t len,
6850 struct mg_tcpip_if *ifp) {
6851 if (len > sizeof(s_txbuf[s_txno])) {
6852 MG_ERROR(("Frame too big, %ld", (long) len));
6853 len = 0; // Frame is too big
6854 } else if ((s_txdesc[s_txno][0] & BIT(31))) {
6855 ifp->nerr++;
6856 MG_ERROR(("No free descriptors"));
6857 // printf("D0 %lx SR %lx\n", (long) s_txdesc[0][0], (long) ETH->DMASR);
6858 len = 0; // All descriptors are busy, fail
6859 } else {
6860 memcpy(s_txbuf[s_txno], buf, len); // Copy data
6861 s_txdesc[s_txno][1] = (uint32_t) len; // Set data len
6862 s_txdesc[s_txno][0] = BIT(20) | BIT(28) | BIT(29); // Chain,FS,LS
6863 s_txdesc[s_txno][0] |= BIT(31); // Set OWN bit - let DMA take over
6864 if (++s_txno >= ETH_DESC_CNT) s_txno = 0;
6865 }
6866 DSB(); // ensure descriptors have been written
6867 ETH->DMASR = BIT(2) | BIT(5); // Clear any prior TBUS/TUS
6868 ETH->DMATPDR = 0; // and resume
6869 return len;
6870}
6871
6872static bool mg_tcpip_driver_stm32_up(struct mg_tcpip_if *ifp) {
6873 uint32_t bsr = eth_read_phy(PHY_ADDR, PHY_BSR);
6874 bool up = bsr & BIT(2) ? 1 : 0;
6875 if ((ifp->state == MG_TCPIP_STATE_DOWN) && up) { // link state just went up
6876 uint32_t scsr = eth_read_phy(PHY_ADDR, PHY_CSCR);
6877 uint32_t maccr = ETH->MACCR | BIT(14) | BIT(11); // 100M, Full-duplex
6878 if ((scsr & BIT(3)) == 0) maccr &= ~BIT(14); // 10M
6879 if ((scsr & BIT(4)) == 0) maccr &= ~BIT(11); // Half-duplex
6880 ETH->MACCR = maccr; // IRQ handler does not fiddle with this register
6881 MG_DEBUG(("Link is %uM %s-duplex", maccr & BIT(14) ? 100 : 10,
6882 maccr & BIT(11) ? "full" : "half"));
6883 }
6884 return up;
6885}
6886
6887void ETH_IRQHandler(void);
6888void ETH_IRQHandler(void) {
6889 if (ETH->DMASR & BIT(6)) { // Frame received, loop
6890 ETH->DMASR = BIT(16) | BIT(6); // Clear flag
6891 for (uint32_t i = 0; i < 10; i++) { // read as they arrive but not forever
6892 if (s_rxdesc[s_rxno][0] & BIT(31)) break; // exit when done
6893 if (((s_rxdesc[s_rxno][0] & (BIT(8) | BIT(9))) == (BIT(8) | BIT(9))) &&
6894 !(s_rxdesc[s_rxno][0] & BIT(15))) { // skip partial/errored frames
6895 uint32_t len = ((s_rxdesc[s_rxno][0] >> 16) & (BIT(14) - 1));
6896 // printf("%lx %lu %lx %.8lx\n", s_rxno, len, s_rxdesc[s_rxno][0],
6897 // ETH->DMASR);
6898 mg_tcpip_qwrite(s_rxbuf[s_rxno], len > 4 ? len - 4 : len, s_ifp);
6899 }
6900 s_rxdesc[s_rxno][0] = BIT(31);
6901 if (++s_rxno >= ETH_DESC_CNT) s_rxno = 0;
6902 }
6903 }
6904 ETH->DMASR = BIT(7); // Clear possible RBUS while processing
6905 ETH->DMARPDR = 0; // and resume RX
6906}
6907
6908struct mg_tcpip_driver mg_tcpip_driver_stm32 = {mg_tcpip_driver_stm32_init,
6909 mg_tcpip_driver_stm32_tx, NULL,
6910 mg_tcpip_driver_stm32_up};
6911#endif
6912
6913#ifdef MG_ENABLE_LINES
6914#line 1 "src/tcpip/driver_stm32h.c"
6915#endif
6916
6917
6918#if MG_ENABLE_TCPIP && defined(MG_ENABLE_DRIVER_STM32H) && \
6919 MG_ENABLE_DRIVER_STM32H
6920struct stm32h_eth {
6921 volatile uint32_t MACCR, MACECR, MACPFR, MACWTR, MACHT0R, MACHT1R,
6922 RESERVED1[14], MACVTR, RESERVED2, MACVHTR, RESERVED3, MACVIR, MACIVIR,
6923 RESERVED4[2], MACTFCR, RESERVED5[7], MACRFCR, RESERVED6[7], MACISR,
6924 MACIER, MACRXTXSR, RESERVED7, MACPCSR, MACRWKPFR, RESERVED8[2], MACLCSR,
6925 MACLTCR, MACLETR, MAC1USTCR, RESERVED9[12], MACVR, MACDR, RESERVED10,
6926 MACHWF0R, MACHWF1R, MACHWF2R, RESERVED11[54], MACMDIOAR, MACMDIODR,
6927 RESERVED12[2], MACARPAR, RESERVED13[59], MACA0HR, MACA0LR, MACA1HR,
6928 MACA1LR, MACA2HR, MACA2LR, MACA3HR, MACA3LR, RESERVED14[248], MMCCR,
6929 MMCRIR, MMCTIR, MMCRIMR, MMCTIMR, RESERVED15[14], MMCTSCGPR, MMCTMCGPR,
6930 RESERVED16[5], MMCTPCGR, RESERVED17[10], MMCRCRCEPR, MMCRAEPR,
6931 RESERVED18[10], MMCRUPGR, RESERVED19[9], MMCTLPIMSTR, MMCTLPITCR,
6932 MMCRLPIMSTR, MMCRLPITCR, RESERVED20[65], MACL3L4C0R, MACL4A0R,
6933 RESERVED21[2], MACL3A0R0R, MACL3A1R0R, MACL3A2R0R, MACL3A3R0R,
6934 RESERVED22[4], MACL3L4C1R, MACL4A1R, RESERVED23[2], MACL3A0R1R,
6935 MACL3A1R1R, MACL3A2R1R, MACL3A3R1R, RESERVED24[108], MACTSCR, MACSSIR,
6936 MACSTSR, MACSTNR, MACSTSUR, MACSTNUR, MACTSAR, RESERVED25, MACTSSR,
6937 RESERVED26[3], MACTTSSNR, MACTTSSSR, RESERVED27[2], MACACR, RESERVED28,
6938 MACATSNR, MACATSSR, MACTSIACR, MACTSEACR, MACTSICNR, MACTSECNR,
6939 RESERVED29[4], MACPPSCR, RESERVED30[3], MACPPSTTSR, MACPPSTTNR, MACPPSIR,
6940 MACPPSWR, RESERVED31[12], MACPOCR, MACSPI0R, MACSPI1R, MACSPI2R, MACLMIR,
6941 RESERVED32[11], MTLOMR, RESERVED33[7], MTLISR, RESERVED34[55], MTLTQOMR,
6942 MTLTQUR, MTLTQDR, RESERVED35[8], MTLQICSR, MTLRQOMR, MTLRQMPOCR, MTLRQDR,
6943 RESERVED36[177], DMAMR, DMASBMR, DMAISR, DMADSR, RESERVED37[60], DMACCR,
6944 DMACTCR, DMACRCR, RESERVED38[2], DMACTDLAR, RESERVED39, DMACRDLAR,
6945 DMACTDTPR, RESERVED40, DMACRDTPR, DMACTDRLR, DMACRDRLR, DMACIER,
6946 DMACRIWTR, DMACSFCSR, RESERVED41, DMACCATDR, RESERVED42, DMACCARDR,
6947 RESERVED43, DMACCATBR, RESERVED44, DMACCARBR, DMACSR, RESERVED45[2],
6948 DMACMFCR;
6949};
6950#undef ETH
6951#define ETH \
6952 ((struct stm32h_eth *) (uintptr_t) (0x40000000UL + 0x00020000UL + 0x8000UL))
6953
6954#undef BIT
6955#define BIT(x) ((uint32_t) 1 << (x))
6956#define ETH_PKT_SIZE 1540 // Max frame size
6957#define ETH_DESC_CNT 4 // Descriptors count
6958#define ETH_DS 4 // Descriptor size (words)
6959
6960static volatile uint32_t s_rxdesc[ETH_DESC_CNT][ETH_DS]; // RX descriptors
6961static volatile uint32_t s_txdesc[ETH_DESC_CNT][ETH_DS]; // TX descriptors
6962static uint8_t s_rxbuf[ETH_DESC_CNT][ETH_PKT_SIZE]; // RX ethernet buffers
6963static uint8_t s_txbuf[ETH_DESC_CNT][ETH_PKT_SIZE]; // TX ethernet buffers
6964static struct mg_tcpip_if *s_ifp; // MIP interface
6965enum {
6966 PHY_ADDR = 0,
6967 PHY_BCR = 0,
6968 PHY_BSR = 1,
6969 PHY_CSCR = 31
6970}; // PHY constants
6971
6972static uint32_t eth_read_phy(uint8_t addr, uint8_t reg) {
6973 ETH->MACMDIOAR &= (0xF << 8);
6974 ETH->MACMDIOAR |= ((uint32_t) addr << 21) | ((uint32_t) reg << 16) | 3 << 2;
6975 ETH->MACMDIOAR |= BIT(0);
6976 while (ETH->MACMDIOAR & BIT(0)) (void) 0;
6977 return ETH->MACMDIODR;
6978}
6979
6980static void eth_write_phy(uint8_t addr, uint8_t reg, uint32_t val) {
6981 ETH->MACMDIODR = val;
6982 ETH->MACMDIOAR &= (0xF << 8);
6983 ETH->MACMDIOAR |= ((uint32_t) addr << 21) | ((uint32_t) reg << 16) | 1 << 2;
6984 ETH->MACMDIOAR |= BIT(0);
6985 while (ETH->MACMDIOAR & BIT(0)) (void) 0;
6986}
6987
6988static uint32_t get_hclk(void) {
6989 struct rcc {
6990 volatile uint32_t CR, HSICFGR, CRRCR, CSICFGR, CFGR, RESERVED1, D1CFGR,
6991 D2CFGR, D3CFGR, RESERVED2, PLLCKSELR, PLLCFGR, PLL1DIVR, PLL1FRACR,
6992 PLL2DIVR, PLL2FRACR, PLL3DIVR, PLL3FRACR, RESERVED3, D1CCIPR, D2CCIP1R,
6993 D2CCIP2R, D3CCIPR, RESERVED4, CIER, CIFR, CICR, RESERVED5, BDCR, CSR,
6994 RESERVED6, AHB3RSTR, AHB1RSTR, AHB2RSTR, AHB4RSTR, APB3RSTR, APB1LRSTR,
6995 APB1HRSTR, APB2RSTR, APB4RSTR, GCR, RESERVED8, D3AMR, RESERVED11[9],
6996 RSR, AHB3ENR, AHB1ENR, AHB2ENR, AHB4ENR, APB3ENR, APB1LENR, APB1HENR,
6997 APB2ENR, APB4ENR, RESERVED12, AHB3LPENR, AHB1LPENR, AHB2LPENR,
6998 AHB4LPENR, APB3LPENR, APB1LLPENR, APB1HLPENR, APB2LPENR, APB4LPENR,
6999 RESERVED13[4];
7000 } *rcc = ((struct rcc *) (0x40000000 + 0x18020000 + 0x4400));
7001 uint32_t clk = 0, hsi = 64000000 /* 64 MHz */, hse = 8000000 /* 8MHz */,
7002 csi = 4000000 /* 4MHz */;
7003 unsigned int sel = (rcc->CFGR & (7 << 3)) >> 3;
7004
7005 if (sel == 1) {
7006 clk = csi;
7007 } else if (sel == 2) {
7008 clk = hse;
7009 } else if (sel == 3) {
7010 uint32_t vco, m, n, p;
7011 unsigned int src = (rcc->PLLCKSELR & (3 << 0)) >> 0;
7012 m = ((rcc->PLLCKSELR & (0x3F << 4)) >> 4);
7013 n = ((rcc->PLL1DIVR & (0x1FF << 0)) >> 0) + 1 +
7014 ((rcc->PLLCFGR & BIT(0)) ? 1 : 0); // round-up in fractional mode
7015 p = ((rcc->PLL1DIVR & (0x7F << 9)) >> 9) + 1;
7016 if (src == 1) {
7017 clk = csi;
7018 } else if (src == 2) {
7019 clk = hse;
7020 } else {
7021 clk = hsi;
7022 clk >>= ((rcc->CR & 3) >> 3);
7023 }
7024 vco = (uint32_t) ((uint64_t) clk * n / m);
7025 clk = vco / p;
7026 } else {
7027 clk = hsi;
7028 clk >>= ((rcc->CR & 3) >> 3);
7029 }
7030 const uint8_t cptab[12] = {1, 2, 3, 4, 6, 7, 8, 9}; // log2(div)
7031 uint32_t d1cpre = (rcc->D1CFGR & (0x0F << 8)) >> 8;
7032 if (d1cpre >= 8) clk >>= cptab[d1cpre - 8];
7033 MG_DEBUG(("D1 CLK: %u", clk));
7034 uint32_t hpre = (rcc->D1CFGR & (0x0F << 0)) >> 0;
7035 if (hpre < 8) return clk;
7036 return ((uint32_t) clk) >> cptab[hpre - 8];
7037}
7038
7039// Guess CR from AHB1 clock. MDC clock is generated from the ETH peripheral
7040// clock (AHB1); as per 802.3, it must not exceed 2. As the AHB clock can
7041// be derived from HSI or CSI (internal RC) clocks, and those can go above
7042// specs, the datasheets specify a range of frequencies and activate one of a
7043// series of dividers to keep the MDC clock safely below 2.5MHz. We guess a
7044// divider setting based on HCLK with some drift. If the user uses a different
7045// clock from our defaults, needs to set the macros on top. Valid for
7046// STM32H74xxx/75xxx (58.11.4)(4.5% worst case drift)(CSI clock has a 7.5 %
7047// worst case drift @ max temp)
7048static int guess_mdc_cr(void) {
7049 const uint8_t crs[] = {2, 3, 0, 1, 4, 5}; // ETH->MACMDIOAR::CR values
7050 const uint8_t div[] = {16, 26, 42, 62, 102, 124}; // Respective HCLK dividers
7051 uint32_t hclk = get_hclk(); // Guess system HCLK
7052 int result = -1; // Invalid CR value
7053 for (int i = 0; i < 6; i++) {
7054 if (hclk / div[i] <= 2375000UL /* 2.5MHz - 5% */) {
7055 result = crs[i];
7056 break;
7057 }
7058 }
7059 if (result < 0) MG_ERROR(("HCLK too high"));
7060 MG_DEBUG(("HCLK: %u, CR: %d", hclk, result));
7061 return result;
7062}
7063
7064static bool mg_tcpip_driver_stm32h_init(struct mg_tcpip_if *ifp) {
7065 struct mg_tcpip_driver_stm32h_data *d =
7066 (struct mg_tcpip_driver_stm32h_data *) ifp->driver_data;
7067 s_ifp = ifp;
7068
7069 // Init RX descriptors
7070 for (int i = 0; i < ETH_DESC_CNT; i++) {
7071 s_rxdesc[i][0] = (uint32_t) (uintptr_t) s_rxbuf[i]; // Point to data buffer
7072 s_rxdesc[i][3] = BIT(31) | BIT(30) | BIT(24); // OWN, IOC, BUF1V
7073 }
7074
7075 // Init TX descriptors
7076 for (int i = 0; i < ETH_DESC_CNT; i++) {
7077 s_txdesc[i][0] = (uint32_t) (uintptr_t) s_txbuf[i]; // Buf pointer
7078 }
7079
7080 ETH->DMAMR |= BIT(0); // Software reset
7081 while ((ETH->DMAMR & BIT(0)) != 0) (void) 0; // Wait until done
7082
7083 // Set MDC clock divider. If user told us the value, use it. Otherwise, guess
7084 int cr = (d == NULL || d->mdc_cr < 0) ? guess_mdc_cr() : d->mdc_cr;
7085 ETH->MACMDIOAR = ((uint32_t) cr & 0xF) << 8;
7086
7087 // NOTE(scaprile): We do not use timing facilities so the DMA engine does not
7088 // re-write buffer address
7089 ETH->DMAMR = 0 << 16; // use interrupt mode 0 (58.8.1) (reset value)
7090 ETH->DMASBMR |= BIT(12); // AAL NOTE(scaprile): is this actually needed
7091 ETH->MACIER = 0; // Do not enable additional irq sources (reset value)
7092 ETH->MACTFCR = BIT(7); // Disable zero-quanta pause
7093 // ETH->MACPFR = BIT(31); // Receive all
7094 eth_write_phy(PHY_ADDR, PHY_BCR, BIT(15)); // Reset PHY
7095 eth_write_phy(PHY_ADDR, PHY_BCR, BIT(12)); // Set autonegotiation
7096 ETH->DMACRDLAR =
7097 (uint32_t) (uintptr_t) s_rxdesc; // RX descriptors start address
7098 ETH->DMACRDRLR = ETH_DESC_CNT - 1; // ring length
7099 ETH->DMACRDTPR =
7100 (uint32_t) (uintptr_t) &s_rxdesc[ETH_DESC_CNT -
7101 1]; // last valid descriptor address
7102 ETH->DMACTDLAR =
7103 (uint32_t) (uintptr_t) s_txdesc; // TX descriptors start address
7104 ETH->DMACTDRLR = ETH_DESC_CNT - 1; // ring length
7105 ETH->DMACTDTPR =
7106 (uint32_t) (uintptr_t) s_txdesc; // first available descriptor address
7107 ETH->DMACCR = 0; // DSL = 0 (contiguous descriptor table) (reset value)
7108 ETH->DMACIER = BIT(6) | BIT(15); // RIE, NIE
7109 ETH->MACCR = BIT(0) | BIT(1) | BIT(13) | BIT(14) |
7110 BIT(15); // RE, TE, Duplex, Fast, Reserved
7111 ETH->MTLTQOMR |= BIT(1); // TSF
7112 ETH->MTLRQOMR |= BIT(5); // RSF
7113 ETH->DMACTCR |= BIT(0); // ST
7114 ETH->DMACRCR |= BIT(0); // SR
7115
7116 // MAC address filtering
7117 ETH->MACA0HR = ((uint32_t) ifp->mac[5] << 8U) | ifp->mac[4];
7118 ETH->MACA0LR = (uint32_t) (ifp->mac[3] << 24) |
7119 ((uint32_t) ifp->mac[2] << 16) |
7120 ((uint32_t) ifp->mac[1] << 8) | ifp->mac[0];
7121 return true;
7122}
7123
7124static uint32_t s_txno;
7125static size_t mg_tcpip_driver_stm32h_tx(const void *buf, size_t len,
7126 struct mg_tcpip_if *ifp) {
7127 if (len > sizeof(s_txbuf[s_txno])) {
7128 MG_ERROR(("Frame too big, %ld", (long) len));
7129 len = 0; // Frame is too big
7130 } else if ((s_txdesc[s_txno][3] & BIT(31))) {
7131 MG_ERROR(("No free descriptors: %u %08X %08X %08X", s_txno,
7132 s_txdesc[s_txno][3], ETH->DMACSR, ETH->DMACTCR));
7133 for (int i = 0; i < ETH_DESC_CNT; i++) MG_ERROR(("%08X", s_txdesc[i][3]));
7134 len = 0; // All descriptors are busy, fail
7135 } else {
7136 memcpy(s_txbuf[s_txno], buf, len); // Copy data
7137 s_txdesc[s_txno][2] = (uint32_t) len; // Set data len
7138 s_txdesc[s_txno][3] = BIT(28) | BIT(29); // FD, LD
7139 s_txdesc[s_txno][3] |= BIT(31); // Set OWN bit - let DMA take over
7140 if (++s_txno >= ETH_DESC_CNT) s_txno = 0;
7141 }
7142 ETH->DMACSR |= BIT(2) | BIT(1); // Clear any prior TBU, TPS
7143 ETH->DMACTDTPR = (uint32_t) (uintptr_t) &s_txdesc[s_txno]; // and resume
7144 return len;
7145 (void) ifp;
7146}
7147
7148static bool mg_tcpip_driver_stm32h_up(struct mg_tcpip_if *ifp) {
7149 uint32_t bsr = eth_read_phy(PHY_ADDR, PHY_BSR);
7150 bool up = bsr & BIT(2) ? 1 : 0;
7151 if ((ifp->state == MG_TCPIP_STATE_DOWN) && up) { // link state just went up
7152 uint32_t scsr = eth_read_phy(PHY_ADDR, PHY_CSCR);
7153 uint32_t maccr = ETH->MACCR | BIT(14) | BIT(13); // 100M, Full-duplex
7154 if ((scsr & BIT(3)) == 0) maccr &= ~BIT(14); // 10M
7155 if ((scsr & BIT(4)) == 0) maccr &= ~BIT(13); // Half-duplex
7156 ETH->MACCR = maccr; // IRQ handler does not fiddle with this register
7157 MG_DEBUG(("Link is %uM %s-duplex", maccr & BIT(14) ? 100 : 10,
7158 maccr & BIT(13) ? "full" : "half"));
7159 }
7160 return up;
7161}
7162
7163void ETH_IRQHandler(void);
7164static uint32_t s_rxno;
7165void ETH_IRQHandler(void) {
7166 if (ETH->DMACSR & BIT(6)) { // Frame received, loop
7167 ETH->DMACSR = BIT(15) | BIT(6); // Clear flag
7168 for (uint32_t i = 0; i < 10; i++) { // read as they arrive but not forever
7169 if (s_rxdesc[s_rxno][3] & BIT(31)) break; // exit when done
7170 if (((s_rxdesc[s_rxno][3] & (BIT(28) | BIT(29))) ==
7171 (BIT(28) | BIT(29))) &&
7172 !(s_rxdesc[s_rxno][3] & BIT(15))) { // skip partial/errored frames
7173 uint32_t len = s_rxdesc[s_rxno][3] & (BIT(15) - 1);
7174 // MG_DEBUG(("%lx %lu %lx %08lx", s_rxno, len, s_rxdesc[s_rxno][3],
7175 // ETH->DMACSR));
7176 mg_tcpip_qwrite(s_rxbuf[s_rxno], len > 4 ? len - 4 : len, s_ifp);
7177 }
7178 s_rxdesc[s_rxno][3] = BIT(31) | BIT(30) | BIT(24); // OWN, IOC, BUF1V
7179 if (++s_rxno >= ETH_DESC_CNT) s_rxno = 0;
7180 }
7181 }
7182 ETH->DMACSR = BIT(7) | BIT(8); // Clear possible RBU RPS while processing
7183 ETH->DMACRDTPR =
7184 (uint32_t) (uintptr_t) &s_rxdesc[ETH_DESC_CNT - 1]; // and resume RX
7185}
7186
7187struct mg_tcpip_driver mg_tcpip_driver_stm32h = {
7188 mg_tcpip_driver_stm32h_init, mg_tcpip_driver_stm32h_tx, NULL,
7189 mg_tcpip_driver_stm32h_up};
7190#endif
7191
7192#ifdef MG_ENABLE_LINES
7193#line 1 "src/tcpip/driver_tm4c.c"
7194#endif
7195
7196
7197#if MG_ENABLE_TCPIP && defined(MG_ENABLE_DRIVER_TM4C) && MG_ENABLE_DRIVER_TM4C
7198struct tm4c_emac {
7199 volatile uint32_t EMACCFG, EMACFRAMEFLTR, EMACHASHTBLH, EMACHASHTBLL,
7200 EMACMIIADDR, EMACMIIDATA, EMACFLOWCTL, EMACVLANTG, RESERVED0, EMACSTATUS,
7201 EMACRWUFF, EMACPMTCTLSTAT, RESERVED1[2], EMACRIS, EMACIM, EMACADDR0H,
7202 EMACADDR0L, EMACADDR1H, EMACADDR1L, EMACADDR2H, EMACADDR2L, EMACADDR3H,
7203 EMACADDR3L, RESERVED2[31], EMACWDOGTO, RESERVED3[8], EMACMMCCTRL,
7204 EMACMMCRXRIS, EMACMMCTXRIS, EMACMMCRXIM, EMACMMCTXIM, RESERVED4,
7205 EMACTXCNTGB, RESERVED5[12], EMACTXCNTSCOL, EMACTXCNTMCOL, RESERVED6[4],
7206 EMACTXOCTCNTG, RESERVED7[6], EMACRXCNTGB, RESERVED8[4], EMACRXCNTCRCERR,
7207 EMACRXCNTALGNERR, RESERVED9[10], EMACRXCNTGUNI, RESERVED10[239],
7208 EMACVLNINCREP, EMACVLANHASH, RESERVED11[93], EMACTIMSTCTRL, EMACSUBSECINC,
7209 EMACTIMSEC, EMACTIMNANO, EMACTIMSECU, EMACTIMNANOU, EMACTIMADD,
7210 EMACTARGSEC, EMACTARGNANO, EMACHWORDSEC, EMACTIMSTAT, EMACPPSCTRL,
7211 RESERVED12[12], EMACPPS0INTVL, EMACPPS0WIDTH, RESERVED13[294],
7212 EMACDMABUSMOD, EMACTXPOLLD, EMACRXPOLLD, EMACRXDLADDR, EMACTXDLADDR,
7213 EMACDMARIS, EMACDMAOPMODE, EMACDMAIM, EMACMFBOC, EMACRXINTWDT,
7214 RESERVED14[8], EMACHOSTXDESC, EMACHOSRXDESC, EMACHOSTXBA, EMACHOSRXBA,
7215 RESERVED15[218], EMACPP, EMACPC, EMACCC, RESERVED16, EMACEPHYRIS,
7216 EMACEPHYIM, EMACEPHYIMSC;
7217};
7218#undef EMAC
7219#define EMAC ((struct tm4c_emac *) (uintptr_t) 0x400EC000)
7220
7221#undef BIT
7222#define BIT(x) ((uint32_t) 1 << (x))
7223#define ETH_PKT_SIZE 1540 // Max frame size
7224#define ETH_DESC_CNT 4 // Descriptors count
7225#define ETH_DS 4 // Descriptor size (words)
7226
7227static uint32_t s_rxdesc[ETH_DESC_CNT][ETH_DS]; // RX descriptors
7228static uint32_t s_txdesc[ETH_DESC_CNT][ETH_DS]; // TX descriptors
7229static uint8_t s_rxbuf[ETH_DESC_CNT][ETH_PKT_SIZE]; // RX ethernet buffers
7230static uint8_t s_txbuf[ETH_DESC_CNT][ETH_PKT_SIZE]; // TX ethernet buffers
7231static struct mg_tcpip_if *s_ifp; // MIP interface
7232enum {
7233 EPHY_ADDR = 0,
7234 EPHYBMCR = 0,
7235 EPHYBMSR = 1,
7236 EPHYSTS = 16
7237}; // PHY constants
7238
7239static inline void tm4cspin(volatile uint32_t count) {
7240 while (count--) (void) 0;
7241}
7242
7243static uint32_t emac_read_phy(uint8_t addr, uint8_t reg) {
7244 EMAC->EMACMIIADDR &= (0xf << 2);
7245 EMAC->EMACMIIADDR |= ((uint32_t) addr << 11) | ((uint32_t) reg << 6);
7246 EMAC->EMACMIIADDR |= BIT(0);
7247 while (EMAC->EMACMIIADDR & BIT(0)) tm4cspin(1);
7248 return EMAC->EMACMIIDATA;
7249}
7250
7251static void emac_write_phy(uint8_t addr, uint8_t reg, uint32_t val) {
7252 EMAC->EMACMIIDATA = val;
7253 EMAC->EMACMIIADDR &= (0xf << 2);
7254 EMAC->EMACMIIADDR |= ((uint32_t) addr << 11) | ((uint32_t) reg << 6) | BIT(1);
7255 EMAC->EMACMIIADDR |= BIT(0);
7256 while (EMAC->EMACMIIADDR & BIT(0)) tm4cspin(1);
7257}
7258
7259static uint32_t get_sysclk(void) {
7260 struct sysctl {
7261 volatile uint32_t DONTCARE0[44], RSCLKCFG, DONTCARE1[43], PLLFREQ0,
7262 PLLFREQ1;
7263 } *sysctl = (struct sysctl *) 0x400FE000;
7264 uint32_t clk = 0, piosc = 16000000 /* 16 MHz */, mosc = 25000000 /* 25MHz */;
7265 if (sysctl->RSCLKCFG & (1 << 28)) { // USEPLL
7266 uint32_t fin, vco, mdiv, n, q, psysdiv;
7267 uint32_t pllsrc = (sysctl->RSCLKCFG & (0xf << 24)) >> 24;
7268 if (pllsrc == 0) {
7269 clk = piosc;
7270 } else if (pllsrc == 3) {
7271 clk = mosc;
7272 } else {
7273 MG_ERROR(("Unsupported clock source"));
7274 }
7275 q = (sysctl->PLLFREQ1 & (0x1f << 8)) >> 8;
7276 n = (sysctl->PLLFREQ1 & (0x1f << 0)) >> 0;
7277 fin = clk / ((q + 1) * (n + 1));
7278 mdiv = (sysctl->PLLFREQ0 & (0x3ff << 0)) >>
7279 0; // mint + (mfrac / 1024); MFRAC not supported
7280 psysdiv = (sysctl->RSCLKCFG & (0x3f << 0)) >> 0;
7281 vco = (uint32_t) ((uint64_t) fin * mdiv);
7282 return vco / (psysdiv + 1);
7283 }
7284 uint32_t oscsrc = (sysctl->RSCLKCFG & (0xf << 20)) >> 20;
7285 if (oscsrc == 0) {
7286 clk = piosc;
7287 } else if (oscsrc == 3) {
7288 clk = mosc;
7289 } else {
7290 MG_ERROR(("Unsupported clock source"));
7291 }
7292 uint32_t osysdiv = (sysctl->RSCLKCFG & (0xf << 16)) >> 16;
7293 return clk / (osysdiv + 1);
7294}
7295
7296// Guess CR from SYSCLK. MDC clock is generated from SYSCLK (AHB); as per
7297// 802.3, it must not exceed 2.5MHz (also 20.4.2.6) As the AHB clock can be
7298// derived from the PIOSC (internal RC), and it can go above specs, the
7299// datasheets specify a range of frequencies and activate one of a series of
7300// dividers to keep the MDC clock safely below 2.5MHz. We guess a divider
7301// setting based on SYSCLK with a +5% drift. If the user uses a different clock
7302// from our defaults, needs to set the macros on top Valid for TM4C129x (20.7)
7303// (4.5% worst case drift)
7304// The PHY receives the main oscillator (MOSC) (20.3.1)
7305static int guess_mdc_cr(void) {
7306 uint8_t crs[] = {2, 3, 0, 1}; // EMAC->MACMIIAR::CR values
7307 uint8_t div[] = {16, 26, 42, 62}; // Respective HCLK dividers
7308 uint32_t sysclk = get_sysclk(); // Guess system SYSCLK
7309 int result = -1; // Invalid CR value
7310 if (sysclk < 25000000) {
7311 MG_ERROR(("SYSCLK too low"));
7312 } else {
7313 for (int i = 0; i < 4; i++) {
7314 if (sysclk / div[i] <= 2375000UL /* 2.5MHz - 5% */) {
7315 result = crs[i];
7316 break;
7317 }
7318 }
7319 if (result < 0) MG_ERROR(("SYSCLK too high"));
7320 }
7321 MG_DEBUG(("SYSCLK: %u, CR: %d", sysclk, result));
7322 return result;
7323}
7324
7325static bool mg_tcpip_driver_tm4c_init(struct mg_tcpip_if *ifp) {
7326 struct mg_tcpip_driver_tm4c_data *d =
7327 (struct mg_tcpip_driver_tm4c_data *) ifp->driver_data;
7328 s_ifp = ifp;
7329
7330 // Init RX descriptors
7331 for (int i = 0; i < ETH_DESC_CNT; i++) {
7332 s_rxdesc[i][0] = BIT(31); // Own
7333 s_rxdesc[i][1] = sizeof(s_rxbuf[i]) | BIT(14); // 2nd address chained
7334 s_rxdesc[i][2] = (uint32_t) (uintptr_t) s_rxbuf[i]; // Point to data buffer
7335 s_rxdesc[i][3] =
7336 (uint32_t) (uintptr_t) s_rxdesc[(i + 1) % ETH_DESC_CNT]; // Chain
7337 // MG_DEBUG(("%d %p", i, s_rxdesc[i]));
7338 }
7339
7340 // Init TX descriptors
7341 for (int i = 0; i < ETH_DESC_CNT; i++) {
7342 s_txdesc[i][2] = (uint32_t) (uintptr_t) s_txbuf[i]; // Buf pointer
7343 s_txdesc[i][3] =
7344 (uint32_t) (uintptr_t) s_txdesc[(i + 1) % ETH_DESC_CNT]; // Chain
7345 }
7346
7347 EMAC->EMACDMABUSMOD |= BIT(0); // Software reset
7348 while ((EMAC->EMACDMABUSMOD & BIT(0)) != 0) tm4cspin(1); // Wait until done
7349
7350 // Set MDC clock divider. If user told us the value, use it. Otherwise, guess
7351 int cr = (d == NULL || d->mdc_cr < 0) ? guess_mdc_cr() : d->mdc_cr;
7352 EMAC->EMACMIIADDR = ((uint32_t) cr & 0xf) << 2;
7353
7354 // NOTE(cpq): we do not use extended descriptor bit 7, and do not use
7355 // hardware checksum. Therefore, descriptor size is 4, not 8
7356 // EMAC->EMACDMABUSMOD = BIT(13) | BIT(16) | BIT(22) | BIT(23) | BIT(25);
7357 EMAC->EMACIM = BIT(3) | BIT(9); // Mask timestamp & PMT IT
7358 EMAC->EMACFLOWCTL = BIT(7); // Disable zero-quanta pause
7359 // EMAC->EMACFRAMEFLTR = BIT(31); // Receive all
7360 // EMAC->EMACPC defaults to internal PHY (EPHY) in MMI mode
7361 emac_write_phy(EPHY_ADDR, EPHYBMCR, BIT(15)); // Reset internal PHY (EPHY)
7362 emac_write_phy(EPHY_ADDR, EPHYBMCR, BIT(12)); // Set autonegotiation
7363 EMAC->EMACRXDLADDR = (uint32_t) (uintptr_t) s_rxdesc; // RX descriptors
7364 EMAC->EMACTXDLADDR = (uint32_t) (uintptr_t) s_txdesc; // TX descriptors
7365 EMAC->EMACDMAIM = BIT(6) | BIT(16); // RIE, NIE
7366 EMAC->EMACCFG = BIT(2) | BIT(3) | BIT(11) | BIT(14); // RE, TE, Duplex, Fast
7367 EMAC->EMACDMAOPMODE =
7368 BIT(1) | BIT(13) | BIT(21) | BIT(25); // SR, ST, TSF, RSF
7369 EMAC->EMACADDR0H = ((uint32_t) ifp->mac[5] << 8U) | ifp->mac[4];
7370 EMAC->EMACADDR0L = (uint32_t) (ifp->mac[3] << 24) |
7371 ((uint32_t) ifp->mac[2] << 16) |
7372 ((uint32_t) ifp->mac[1] << 8) | ifp->mac[0];
7373 // NOTE(scaprile) There are 3 additional slots for filtering, disabled by
7374 // default. This also applies to the STM32 driver (at least for F7)
7375 return true;
7376}
7377
7378static uint32_t s_txno;
7379static size_t mg_tcpip_driver_tm4c_tx(const void *buf, size_t len,
7380 struct mg_tcpip_if *ifp) {
7381 if (len > sizeof(s_txbuf[s_txno])) {
7382 MG_ERROR(("Frame too big, %ld", (long) len));
7383 len = 0; // fail
7384 } else if ((s_txdesc[s_txno][0] & BIT(31))) {
7385 MG_ERROR(("No descriptors available"));
7386 // printf("D0 %lx SR %lx\n", (long) s_txdesc[0][0], (long)
7387 // EMAC->EMACDMARIS);
7388 len = 0; // fail
7389 } else {
7390 memcpy(s_txbuf[s_txno], buf, len); // Copy data
7391 s_txdesc[s_txno][1] = (uint32_t) len; // Set data len
7392 s_txdesc[s_txno][0] =
7393 BIT(20) | BIT(28) | BIT(29) | BIT(30); // Chain,FS,LS,IC
7394 s_txdesc[s_txno][0] |= BIT(31); // Set OWN bit - let DMA take over
7395 if (++s_txno >= ETH_DESC_CNT) s_txno = 0;
7396 }
7397 EMAC->EMACDMARIS = BIT(2) | BIT(5); // Clear any prior TU/UNF
7398 EMAC->EMACTXPOLLD = 0; // and resume
7399 return len;
7400 (void) ifp;
7401}
7402
7403static bool mg_tcpip_driver_tm4c_up(struct mg_tcpip_if *ifp) {
7404 uint32_t bmsr = emac_read_phy(EPHY_ADDR, EPHYBMSR);
7405 bool up = (bmsr & BIT(2)) ? 1 : 0;
7406 if ((ifp->state == MG_TCPIP_STATE_DOWN) && up) { // link state just went up
7407 uint32_t sts = emac_read_phy(EPHY_ADDR, EPHYSTS);
7408 uint32_t emaccfg = EMAC->EMACCFG | BIT(14) | BIT(11); // 100M, Full-duplex
7409 if (sts & BIT(1)) emaccfg &= ~BIT(14); // 10M
7410 if ((sts & BIT(2)) == 0) emaccfg &= ~BIT(11); // Half-duplex
7411 EMAC->EMACCFG = emaccfg; // IRQ handler does not fiddle with this register
7412 MG_DEBUG(("Link is %uM %s-duplex", emaccfg & BIT(14) ? 100 : 10,
7413 emaccfg & BIT(11) ? "full" : "half"));
7414 }
7415 return up;
7416}
7417
7418void EMAC0_IRQHandler(void);
7419static uint32_t s_rxno;
7420void EMAC0_IRQHandler(void) {
7421 if (EMAC->EMACDMARIS & BIT(6)) { // Frame received, loop
7422 EMAC->EMACDMARIS = BIT(16) | BIT(6); // Clear flag
7423 for (uint32_t i = 0; i < 10; i++) { // read as they arrive but not forever
7424 if (s_rxdesc[s_rxno][0] & BIT(31)) break; // exit when done
7425 if (((s_rxdesc[s_rxno][0] & (BIT(8) | BIT(9))) == (BIT(8) | BIT(9))) &&
7426 !(s_rxdesc[s_rxno][0] & BIT(15))) { // skip partial/errored frames
7427 uint32_t len = ((s_rxdesc[s_rxno][0] >> 16) & (BIT(14) - 1));
7428 // printf("%lx %lu %lx %.8lx\n", s_rxno, len, s_rxdesc[s_rxno][0],
7429 // EMAC->EMACDMARIS);
7430 mg_tcpip_qwrite(s_rxbuf[s_rxno], len > 4 ? len - 4 : len, s_ifp);
7431 }
7432 s_rxdesc[s_rxno][0] = BIT(31);
7433 if (++s_rxno >= ETH_DESC_CNT) s_rxno = 0;
7434 }
7435 }
7436 EMAC->EMACDMARIS = BIT(7); // Clear possible RU while processing
7437 EMAC->EMACRXPOLLD = 0; // and resume RX
7438}
7439
7440struct mg_tcpip_driver mg_tcpip_driver_tm4c = {mg_tcpip_driver_tm4c_init,
7441 mg_tcpip_driver_tm4c_tx, NULL,
7442 mg_tcpip_driver_tm4c_up};
7443#endif
7444
7445#ifdef MG_ENABLE_LINES
7446#line 1 "src/tcpip/driver_w5500.c"
7447#endif
7448
7449
7450#if MG_ENABLE_TCPIP
7451
7452enum { W5500_CR = 0, W5500_S0 = 1, W5500_TX0 = 2, W5500_RX0 = 3 };
7453
7454static void w5500_txn(struct mg_tcpip_spi *s, uint8_t block, uint16_t addr, bool wr,
7455 void *buf, size_t len) {
7456 uint8_t *p = (uint8_t *) buf;
7457 uint8_t cmd[] = {(uint8_t) (addr >> 8), (uint8_t) (addr & 255),
7458 (uint8_t) ((block << 3) | (wr ? 4 : 0))};
7459 s->begin(s->spi);
7460 for (size_t i = 0; i < sizeof(cmd); i++) s->txn(s->spi, cmd[i]);
7461 for (size_t i = 0; i < len; i++) {
7462 uint8_t r = s->txn(s->spi, p[i]);
7463 if (!wr) p[i] = r;
7464 }
7465 s->end(s->spi);
7466}
7467
7468// clang-format off
7469static void w5500_wn(struct mg_tcpip_spi *s, uint8_t block, uint16_t addr, void *buf, size_t len) { w5500_txn(s, block, addr, true, buf, len); }
7470static void w5500_w1(struct mg_tcpip_spi *s, uint8_t block, uint16_t addr, uint8_t val) { w5500_wn(s, block, addr, &val, 1); }
7471static void w5500_w2(struct mg_tcpip_spi *s, uint8_t block, uint16_t addr, uint16_t val) { uint8_t buf[2] = {(uint8_t) (val >> 8), (uint8_t) (val & 255)}; w5500_wn(s, block, addr, buf, sizeof(buf)); }
7472static void w5500_rn(struct mg_tcpip_spi *s, uint8_t block, uint16_t addr, void *buf, size_t len) { w5500_txn(s, block, addr, false, buf, len); }
7473static uint8_t w5500_r1(struct mg_tcpip_spi *s, uint8_t block, uint16_t addr) { uint8_t r = 0; w5500_rn(s, block, addr, &r, 1); return r; }
7474static uint16_t w5500_r2(struct mg_tcpip_spi *s, uint8_t block, uint16_t addr) { uint8_t buf[2] = {0, 0}; w5500_rn(s, block, addr, buf, sizeof(buf)); return (uint16_t) ((buf[0] << 8) | buf[1]); }
7475// clang-format on
7476
7477static size_t w5500_rx(void *buf, size_t buflen, struct mg_tcpip_if *ifp) {
7478 struct mg_tcpip_spi *s = (struct mg_tcpip_spi *) ifp->driver_data;
7479 uint16_t r = 0, n = 0, len = (uint16_t) buflen, n2; // Read recv len
7480 while ((n2 = w5500_r2(s, W5500_S0, 0x26)) > n) n = n2; // Until it is stable
7481 // printf("RSR: %d\n", (int) n);
7482 if (n > 0) {
7483 uint16_t ptr = w5500_r2(s, W5500_S0, 0x28); // Get read pointer
7484 n = w5500_r2(s, W5500_RX0, ptr); // Read frame length
7485 if (n <= len + 2 && n > 1) {
7486 r = (uint16_t) (n - 2);
7487 w5500_rn(s, W5500_RX0, (uint16_t) (ptr + 2), buf, r);
7488 }
7489 w5500_w2(s, W5500_S0, 0x28, (uint16_t) (ptr + n)); // Advance read pointer
7490 w5500_w1(s, W5500_S0, 1, 0x40); // Sock0 CR -> RECV
7491 // printf(" RX_RD: tot=%u n=%u r=%u\n", n2, n, r);
7492 }
7493 return r;
7494}
7495
7496static size_t w5500_tx(const void *buf, size_t buflen, struct mg_tcpip_if *ifp) {
7497 struct mg_tcpip_spi *s = (struct mg_tcpip_spi *) ifp->driver_data;
7498 uint16_t n = 0, len = (uint16_t) buflen;
7499 while (n < len) n = w5500_r2(s, W5500_S0, 0x20); // Wait for space
7500 uint16_t ptr = w5500_r2(s, W5500_S0, 0x24); // Get write pointer
7501 w5500_wn(s, W5500_TX0, ptr, (void *) buf, len); // Write data
7502 w5500_w2(s, W5500_S0, 0x24, (uint16_t) (ptr + len)); // Advance write pointer
7503 w5500_w1(s, W5500_S0, 1, 0x20); // Sock0 CR -> SEND
7504 for (int i = 0; i < 40; i++) {
7505 uint8_t ir = w5500_r1(s, W5500_S0, 2); // Read S0 IR
7506 if (ir == 0) continue;
7507 // printf("IR %d, len=%d, free=%d, ptr %d\n", ir, (int) len, (int) n, ptr);
7508 w5500_w1(s, W5500_S0, 2, ir); // Write S0 IR: clear it!
7509 if (ir & 8) len = 0; // Timeout. Report error
7510 if (ir & (16 | 8)) break; // Stop on SEND_OK or timeout
7511 }
7512 return len;
7513}
7514
7515static bool w5500_init(struct mg_tcpip_if *ifp) {
7516 struct mg_tcpip_spi *s = (struct mg_tcpip_spi *) ifp->driver_data;
7517 s->end(s->spi);
7518 w5500_w1(s, W5500_CR, 0, 0x80); // Reset chip: CR -> 0x80
7519 w5500_w1(s, W5500_CR, 0x2e, 0); // CR PHYCFGR -> reset
7520 w5500_w1(s, W5500_CR, 0x2e, 0xf8); // CR PHYCFGR -> set
7521 // w5500_wn(s, W5500_CR, 9, s->mac, 6); // Set source MAC
7522 w5500_w1(s, W5500_S0, 0x1e, 16); // Sock0 RX buf size
7523 w5500_w1(s, W5500_S0, 0x1f, 16); // Sock0 TX buf size
7524 w5500_w1(s, W5500_S0, 0, 4); // Sock0 MR -> MACRAW
7525 w5500_w1(s, W5500_S0, 1, 1); // Sock0 CR -> OPEN
7526 return w5500_r1(s, W5500_S0, 3) == 0x42; // Sock0 SR == MACRAW
7527}
7528
7529static bool w5500_up(struct mg_tcpip_if *ifp) {
7530 struct mg_tcpip_spi *spi = (struct mg_tcpip_spi *) ifp->driver_data;
7531 uint8_t phycfgr = w5500_r1(spi, W5500_CR, 0x2e);
7532 return phycfgr & 1; // Bit 0 of PHYCFGR is LNK (0 - down, 1 - up)
7533}
7534
7535struct mg_tcpip_driver mg_tcpip_driver_w5500 = {w5500_init, w5500_tx, w5500_rx, w5500_up};
7536#endif
7537
7538#ifdef MG_ENABLE_LINES
7539#line 1 "src/tcpip/tcpip.c"
7540#endif
7541
7542
7543#if MG_ENABLE_TCPIP
7544
7545#define MG_EPHEMERAL_PORT_BASE 32768
7546#define PDIFF(a, b) ((size_t) (((char *) (b)) - ((char *) (a))))
7547
7548#ifndef MIP_TCP_KEEPALIVE_MS
7549#define MIP_TCP_KEEPALIVE_MS 45000 // TCP keep-alive period, ms
7550#endif
7551
7552#define MIP_TCP_ACK_MS 150 // Timeout for ACKing
7553
7554struct connstate {
7555 uint32_t seq, ack; // TCP seq/ack counters
7556 uint64_t timer; // TCP keep-alive / ACK timer
7557 uint8_t mac[6]; // Peer MAC address
7558 uint8_t ttype; // Timer type. 0: ack, 1: keep-alive
7559#define MIP_TTYPE_KEEPALIVE 0 // Connection is idle for long, send keepalive
7560#define MIP_TTYPE_ACK 1 // Peer sent us data, we have to ack it soon
7561 uint8_t tmiss; // Number of keep-alive misses
7562 struct mg_iobuf raw; // For TLS only. Incoming raw data
7563};
7564
7565#pragma pack(push, 1)
7566
7567struct lcp {
7568 uint8_t addr, ctrl, proto[2], code, id, len[2];
7569};
7570
7571struct eth {
7572 uint8_t dst[6]; // Destination MAC address
7573 uint8_t src[6]; // Source MAC address
7574 uint16_t type; // Ethernet type
7575};
7576
7577struct ip {
7578 uint8_t ver; // Version
7579 uint8_t tos; // Unused
7580 uint16_t len; // Length
7581 uint16_t id; // Unused
7582 uint16_t frag; // Fragmentation
7583 uint8_t ttl; // Time to live
7584 uint8_t proto; // Upper level protocol
7585 uint16_t csum; // Checksum
7586 uint32_t src; // Source IP
7587 uint32_t dst; // Destination IP
7588};
7589
7590struct ip6 {
7591 uint8_t ver; // Version
7592 uint8_t opts[3]; // Options
7593 uint16_t len; // Length
7594 uint8_t proto; // Upper level protocol
7595 uint8_t ttl; // Time to live
7596 uint8_t src[16]; // Source IP
7597 uint8_t dst[16]; // Destination IP
7598};
7599
7600struct icmp {
7601 uint8_t type;
7602 uint8_t code;
7603 uint16_t csum;
7604};
7605
7606struct arp {
7607 uint16_t fmt; // Format of hardware address
7608 uint16_t pro; // Format of protocol address
7609 uint8_t hlen; // Length of hardware address
7610 uint8_t plen; // Length of protocol address
7611 uint16_t op; // Operation
7612 uint8_t sha[6]; // Sender hardware address
7613 uint32_t spa; // Sender protocol address
7614 uint8_t tha[6]; // Target hardware address
7615 uint32_t tpa; // Target protocol address
7616};
7617
7618struct tcp {
7619 uint16_t sport; // Source port
7620 uint16_t dport; // Destination port
7621 uint32_t seq; // Sequence number
7622 uint32_t ack; // Acknowledgement number
7623 uint8_t off; // Data offset
7624 uint8_t flags; // TCP flags
7625#define TH_FIN 0x01
7626#define TH_SYN 0x02
7627#define TH_RST 0x04
7628#define TH_PUSH 0x08
7629#define TH_ACK 0x10
7630#define TH_URG 0x20
7631#define TH_ECE 0x40
7632#define TH_CWR 0x80
7633 uint16_t win; // Window
7634 uint16_t csum; // Checksum
7635 uint16_t urp; // Urgent pointer
7636};
7637
7638struct udp {
7639 uint16_t sport; // Source port
7640 uint16_t dport; // Destination port
7641 uint16_t len; // UDP length
7642 uint16_t csum; // UDP checksum
7643};
7644
7645struct dhcp {
7646 uint8_t op, htype, hlen, hops;
7647 uint32_t xid;
7648 uint16_t secs, flags;
7649 uint32_t ciaddr, yiaddr, siaddr, giaddr;
7650 uint8_t hwaddr[208];
7651 uint32_t magic;
7652 uint8_t options[32];
7653};
7654
7655#pragma pack(pop)
7656
7657struct pkt {
7658 struct mg_str raw; // Raw packet data
7659 struct mg_str pay; // Payload data
7660 struct eth *eth;
7661 struct llc *llc;
7662 struct arp *arp;
7663 struct ip *ip;
7664 struct ip6 *ip6;
7665 struct icmp *icmp;
7666 struct tcp *tcp;
7667 struct udp *udp;
7668 struct dhcp *dhcp;
7669};
7670
7671static void mkpay(struct pkt *pkt, void *p) {
7672 pkt->pay =
7673 mg_str_n((char *) p, (size_t) (&pkt->raw.ptr[pkt->raw.len] - (char *) p));
7674}
7675
7676static uint32_t csumup(uint32_t sum, const void *buf, size_t len) {
7677 const uint8_t *p = (const uint8_t *) buf;
7678 for (size_t i = 0; i < len; i++) sum += i & 1 ? p[i] : (uint32_t) (p[i] << 8);
7679 return sum;
7680}
7681
7682static uint16_t csumfin(uint32_t sum) {
7683 while (sum >> 16) sum = (sum & 0xffff) + (sum >> 16);
7684 return mg_htons(~sum & 0xffff);
7685}
7686
7687static uint16_t ipcsum(const void *buf, size_t len) {
7688 uint32_t sum = csumup(0, buf, len);
7689 return csumfin(sum);
7690}
7691
7692static size_t ether_output(struct mg_tcpip_if *ifp, size_t len) {
7693 // size_t min = 64; // Pad short frames to 64 bytes (minimum Ethernet size)
7694 // if (len < min) memset(ifp->tx.ptr + len, 0, min - len), len = min;
7695 // mg_hexdump(ifp->tx.ptr, len);
7696 size_t n = ifp->driver->tx(ifp->tx.ptr, len, ifp);
7697 if (n == len) ifp->nsent++;
7698 return n;
7699}
7700
7701static void arp_ask(struct mg_tcpip_if *ifp, uint32_t ip) {
7702 struct eth *eth = (struct eth *) ifp->tx.ptr;
7703 struct arp *arp = (struct arp *) (eth + 1);
7704 memset(eth->dst, 255, sizeof(eth->dst));
7705 memcpy(eth->src, ifp->mac, sizeof(eth->src));
7706 eth->type = mg_htons(0x806);
7707 memset(arp, 0, sizeof(*arp));
7708 arp->fmt = mg_htons(1), arp->pro = mg_htons(0x800), arp->hlen = 6,
7709 arp->plen = 4;
7710 arp->op = mg_htons(1), arp->tpa = ip, arp->spa = ifp->ip;
7711 memcpy(arp->sha, ifp->mac, sizeof(arp->sha));
7712 ether_output(ifp, PDIFF(eth, arp + 1));
7713}
7714
7715static void onstatechange(struct mg_tcpip_if *ifp) {
7716 if (ifp->state == MG_TCPIP_STATE_READY) {
7717 MG_INFO(("READY, IP: %M", mg_print_ip4, &ifp->ip));
7718 MG_INFO((" GW: %M", mg_print_ip4, &ifp->gw));
7719 MG_INFO((" MAC: %M", mg_print_mac, &ifp->mac));
7720 arp_ask(ifp, ifp->gw);
7721 } else if (ifp->state == MG_TCPIP_STATE_UP) {
7722 MG_ERROR(("Link up"));
7723 srand((unsigned int) mg_millis());
7724 } else if (ifp->state == MG_TCPIP_STATE_DOWN) {
7725 MG_ERROR(("Link down"));
7726 }
7727}
7728
7729static struct ip *tx_ip(struct mg_tcpip_if *ifp, uint8_t *mac_dst,
7730 uint8_t proto, uint32_t ip_src, uint32_t ip_dst,
7731 size_t plen) {
7732 struct eth *eth = (struct eth *) ifp->tx.ptr;
7733 struct ip *ip = (struct ip *) (eth + 1);
7734 memcpy(eth->dst, mac_dst, sizeof(eth->dst));
7735 memcpy(eth->src, ifp->mac, sizeof(eth->src)); // Use our MAC
7736 eth->type = mg_htons(0x800);
7737 memset(ip, 0, sizeof(*ip));
7738 ip->ver = 0x45; // Version 4, header length 5 words
7739 ip->frag = 0x40; // Don't fragment
7740 ip->len = mg_htons((uint16_t) (sizeof(*ip) + plen));
7741 ip->ttl = 64;
7742 ip->proto = proto;
7743 ip->src = ip_src;
7744 ip->dst = ip_dst;
7745 ip->csum = ipcsum(ip, sizeof(*ip));
7746 return ip;
7747}
7748
7749static void tx_udp(struct mg_tcpip_if *ifp, uint8_t *mac_dst, uint32_t ip_src,
7750 uint16_t sport, uint32_t ip_dst, uint16_t dport,
7751 const void *buf, size_t len) {
7752 struct ip *ip =
7753 tx_ip(ifp, mac_dst, 17, ip_src, ip_dst, len + sizeof(struct udp));
7754 struct udp *udp = (struct udp *) (ip + 1);
7755 // MG_DEBUG(("UDP XX LEN %d %d", (int) len, (int) ifp->tx.len));
7756 udp->sport = sport;
7757 udp->dport = dport;
7758 udp->len = mg_htons((uint16_t) (sizeof(*udp) + len));
7759 udp->csum = 0;
7760 uint32_t cs = csumup(0, udp, sizeof(*udp));
7761 cs = csumup(cs, buf, len);
7762 cs = csumup(cs, &ip->src, sizeof(ip->src));
7763 cs = csumup(cs, &ip->dst, sizeof(ip->dst));
7764 cs += (uint32_t) (ip->proto + sizeof(*udp) + len);
7765 udp->csum = csumfin(cs);
7766 memmove(udp + 1, buf, len);
7767 // MG_DEBUG(("UDP LEN %d %d", (int) len, (int) ifp->frame_len));
7768 ether_output(ifp, sizeof(struct eth) + sizeof(*ip) + sizeof(*udp) + len);
7769}
7770
7771static void tx_dhcp(struct mg_tcpip_if *ifp, uint8_t *mac_dst, uint32_t ip_src,
7772 uint32_t ip_dst, uint8_t *opts, size_t optslen,
7773 bool ciaddr) {
7774 // https://datatracker.ietf.org/doc/html/rfc2132#section-9.6
7775 struct dhcp dhcp = {1, 1, 6, 0, 0, 0, 0, 0, 0, 0, 0, {0}, 0, {0}};
7776 dhcp.magic = mg_htonl(0x63825363);
7777 memcpy(&dhcp.hwaddr, ifp->mac, sizeof(ifp->mac));
7778 memcpy(&dhcp.xid, ifp->mac + 2, sizeof(dhcp.xid));
7779 memcpy(&dhcp.options, opts, optslen);
7780 if (ciaddr) dhcp.ciaddr = ip_src;
7781 tx_udp(ifp, mac_dst, ip_src, mg_htons(68), ip_dst, mg_htons(67), &dhcp,
7782 sizeof(dhcp));
7783}
7784
7785static const uint8_t broadcast[] = {255, 255, 255, 255, 255, 255};
7786
7787// RFC-2131 #4.3.6, #4.4.1
7788static void tx_dhcp_request_sel(struct mg_tcpip_if *ifp, uint32_t ip_req,
7789 uint32_t ip_srv) {
7790 uint8_t opts[] = {
7791 53, 1, 3, // Type: DHCP request
7792 55, 2, 1, 3, // GW and mask
7793 12, 3, 'm', 'i', 'p', // Host name: "mip"
7794 54, 4, 0, 0, 0, 0, // DHCP server ID
7795 50, 4, 0, 0, 0, 0, // Requested IP
7796 255 // End of options
7797 };
7798 memcpy(opts + 14, &ip_srv, sizeof(ip_srv));
7799 memcpy(opts + 20, &ip_req, sizeof(ip_req));
7800 tx_dhcp(ifp, (uint8_t *) broadcast, 0, 0xffffffff, opts, sizeof(opts), false);
7801 MG_DEBUG(("DHCP req sent"));
7802}
7803
7804// RFC-2131 #4.3.6, #4.4.5 (renewing: unicast, rebinding: bcast)
7805static void tx_dhcp_request_re(struct mg_tcpip_if *ifp, uint8_t *mac_dst,
7806 uint32_t ip_src, uint32_t ip_dst) {
7807 uint8_t opts[] = {
7808 53, 1, 3, // Type: DHCP request
7809 255 // End of options
7810 };
7811 tx_dhcp(ifp, mac_dst, ip_src, ip_dst, opts, sizeof(opts), true);
7812 MG_DEBUG(("DHCP req sent"));
7813}
7814
7815static void tx_dhcp_discover(struct mg_tcpip_if *ifp) {
7816 uint8_t opts[] = {
7817 53, 1, 1, // Type: DHCP discover
7818 55, 2, 1, 3, // Parameters: ip, mask
7819 255 // End of options
7820 };
7821 tx_dhcp(ifp, (uint8_t *) broadcast, 0, 0xffffffff, opts, sizeof(opts), false);
7822 MG_DEBUG(("DHCP discover sent. Our MAC: %M", mg_print_mac, ifp->mac));
7823}
7824
7825static struct mg_connection *getpeer(struct mg_mgr *mgr, struct pkt *pkt,
7826 bool lsn) {
7827 struct mg_connection *c = NULL;
7828 for (c = mgr->conns; c != NULL; c = c->next) {
7829 if (c->is_udp && pkt->udp && c->loc.port == pkt->udp->dport) break;
7830 if (!c->is_udp && pkt->tcp && c->loc.port == pkt->tcp->dport &&
7831 lsn == c->is_listening && (lsn || c->rem.port == pkt->tcp->sport))
7832 break;
7833 }
7834 return c;
7835}
7836
7837static void rx_arp(struct mg_tcpip_if *ifp, struct pkt *pkt) {
7838 if (pkt->arp->op == mg_htons(1) && pkt->arp->tpa == ifp->ip) {
7839 // ARP request. Make a response, then send
7840 // MG_DEBUG(("ARP op %d %M: %M", mg_ntohs(pkt->arp->op), mg_print_ip4,
7841 // &pkt->arp->spa, mg_print_ip4, &pkt->arp->tpa));
7842 struct eth *eth = (struct eth *) ifp->tx.ptr;
7843 struct arp *arp = (struct arp *) (eth + 1);
7844 memcpy(eth->dst, pkt->eth->src, sizeof(eth->dst));
7845 memcpy(eth->src, ifp->mac, sizeof(eth->src));
7846 eth->type = mg_htons(0x806);
7847 *arp = *pkt->arp;
7848 arp->op = mg_htons(2);
7849 memcpy(arp->tha, pkt->arp->sha, sizeof(pkt->arp->tha));
7850 memcpy(arp->sha, ifp->mac, sizeof(pkt->arp->sha));
7851 arp->tpa = pkt->arp->spa;
7852 arp->spa = ifp->ip;
7853 MG_DEBUG(("ARP: tell %M we're %M", mg_print_ip4, &arp->tpa, mg_print_ip4,
7854 &ifp->ip));
7855 ether_output(ifp, PDIFF(eth, arp + 1));
7856 } else if (pkt->arp->op == mg_htons(2)) {
7857 if (memcmp(pkt->arp->tha, ifp->mac, sizeof(pkt->arp->tha)) != 0) return;
7858 if (pkt->arp->spa == ifp->gw) {
7859 // Got response for the GW ARP request. Set ifp->gwmac
7860 memcpy(ifp->gwmac, pkt->arp->sha, sizeof(ifp->gwmac));
7861 } else {
7862 struct mg_connection *c = getpeer(ifp->mgr, pkt, false);
7863 if (c != NULL && c->is_arplooking) {
7864 struct connstate *s = (struct connstate *) (c + 1);
7865 memcpy(s->mac, pkt->arp->sha, sizeof(s->mac));
7866 MG_DEBUG(("%lu ARP resolved %M -> %M", c->id, mg_print_ip4, c->rem.ip,
7867 mg_print_mac, s->mac));
7868 c->is_arplooking = 0;
7869 }
7870 }
7871 }
7872}
7873
7874static void rx_icmp(struct mg_tcpip_if *ifp, struct pkt *pkt) {
7875 // MG_DEBUG(("ICMP %d", (int) len));
7876 if (pkt->icmp->type == 8 && pkt->ip != NULL && pkt->ip->dst == ifp->ip) {
7877 size_t hlen = sizeof(struct eth) + sizeof(struct ip) + sizeof(struct icmp);
7878 size_t space = ifp->tx.len - hlen, plen = pkt->pay.len;
7879 if (plen > space) plen = space;
7880 struct ip *ip = tx_ip(ifp, pkt->eth->src, 1, ifp->ip, pkt->ip->src,
7881 sizeof(struct icmp) + plen);
7882 struct icmp *icmp = (struct icmp *) (ip + 1);
7883 memset(icmp, 0, sizeof(*icmp)); // Set csum to 0
7884 memcpy(icmp + 1, pkt->pay.ptr, plen); // Copy RX payload to TX
7885 icmp->csum = ipcsum(icmp, sizeof(*icmp) + plen);
7886 ether_output(ifp, hlen + plen);
7887 }
7888}
7889
7890static void rx_dhcp_client(struct mg_tcpip_if *ifp, struct pkt *pkt) {
7891 uint32_t ip = 0, gw = 0, mask = 0, lease = 0;
7892 uint8_t msgtype = 0, state = ifp->state;
7893 // perform size check first, then access fields
7894 uint8_t *p = pkt->dhcp->options,
7895 *end = (uint8_t *) &pkt->raw.ptr[pkt->raw.len];
7896 if (end < (uint8_t *) (pkt->dhcp + 1)) return;
7897 if (memcmp(&pkt->dhcp->xid, ifp->mac + 2, sizeof(pkt->dhcp->xid))) return;
7898 while (p + 1 < end && p[0] != 255) { // Parse options RFC-1533 #9
7899 if (p[0] == 1 && p[1] == sizeof(ifp->mask) && p + 6 < end) { // Mask
7900 memcpy(&mask, p + 2, sizeof(mask));
7901 } else if (p[0] == 3 && p[1] == sizeof(ifp->gw) && p + 6 < end) { // GW
7902 memcpy(&gw, p + 2, sizeof(gw));
7903 ip = pkt->dhcp->yiaddr;
7904 } else if (p[0] == 51 && p[1] == 4 && p + 6 < end) { // Lease
7905 memcpy(&lease, p + 2, sizeof(lease));
7906 lease = mg_ntohl(lease);
7907 } else if (p[0] == 53 && p[1] == 1 && p + 6 < end) { // Msg Type
7908 msgtype = p[2];
7909 }
7910 p += p[1] + 2;
7911 }
7912 // Process message type, RFC-1533 (9.4); RFC-2131 (3.1, 4)
7913 if (msgtype == 6 && ifp->ip == ip) { // DHCPNACK, release IP
7914 ifp->state = MG_TCPIP_STATE_UP, ifp->ip = 0;
7915 } else if (msgtype == 2 && ifp->state == MG_TCPIP_STATE_UP && ip && gw &&
7916 lease) { // DHCPOFFER
7917 tx_dhcp_request_sel(ifp, ip, pkt->dhcp->siaddr); // select IP, (4.4.1)
7918 ifp->state = MG_TCPIP_STATE_REQ; // REQUESTING state
7919 } else if (msgtype == 5) { // DHCPACK
7920 if (ifp->state == MG_TCPIP_STATE_REQ && ip && gw && lease) { // got an IP
7921 ifp->lease_expire = ifp->now + lease * 1000;
7922 MG_INFO(("Lease: %u sec (%lld)", lease, ifp->lease_expire / 1000));
7923 // assume DHCP server = router until ARP resolves
7924 memcpy(ifp->gwmac, pkt->eth->src, sizeof(ifp->gwmac));
7925 ifp->ip = ip, ifp->gw = gw, ifp->mask = mask;
7926 ifp->state = MG_TCPIP_STATE_READY; // BOUND state
7927 uint64_t rand;
7928 mg_random(&rand, sizeof(rand));
7929 srand((unsigned int) (rand + mg_millis()));
7930 } else if (ifp->state == MG_TCPIP_STATE_READY && ifp->ip == ip) { // renew
7931 ifp->lease_expire = ifp->now + lease * 1000;
7932 MG_INFO(("Lease: %u sec (%lld)", lease, ifp->lease_expire / 1000));
7933 } // TODO(): accept provided T1/T2 and store server IP for renewal (4.4)
7934 }
7935 if (ifp->state != state) onstatechange(ifp);
7936}
7937
7938// Simple DHCP server that assigns a next IP address: ifp->ip + 1
7939static void rx_dhcp_server(struct mg_tcpip_if *ifp, struct pkt *pkt) {
7940 uint8_t op = 0, *p = pkt->dhcp->options,
7941 *end = (uint8_t *) &pkt->raw.ptr[pkt->raw.len];
7942 if (end < (uint8_t *) (pkt->dhcp + 1)) return;
7943 // struct dhcp *req = pkt->dhcp;
7944 struct dhcp res = {2, 1, 6, 0, 0, 0, 0, 0, 0, 0, 0, {0}, 0, {0}};
7945 res.yiaddr = ifp->ip;
7946 ((uint8_t *) (&res.yiaddr))[3]++; // Offer our IP + 1
7947 while (p + 1 < end && p[0] != 255) { // Parse options
7948 if (p[0] == 53 && p[1] == 1 && p + 2 < end) { // Message type
7949 op = p[2];
7950 }
7951 p += p[1] + 2;
7952 }
7953 if (op == 1 || op == 3) { // DHCP Discover or DHCP Request
7954 uint8_t msg = op == 1 ? 2 : 5; // Message type: DHCP OFFER or DHCP ACK
7955 uint8_t opts[] = {
7956 53, 1, msg, // Message type
7957 1, 4, 0, 0, 0, 0, // Subnet mask
7958 54, 4, 0, 0, 0, 0, // Server ID
7959 12, 3, 'm', 'i', 'p', // Host name: "mip"
7960 51, 4, 255, 255, 255, 255, // Lease time
7961 255 // End of options
7962 };
7963 memcpy(&res.hwaddr, pkt->dhcp->hwaddr, 6);
7964 memcpy(opts + 5, &ifp->mask, sizeof(ifp->mask));
7965 memcpy(opts + 11, &ifp->ip, sizeof(ifp->ip));
7966 memcpy(&res.options, opts, sizeof(opts));
7967 res.magic = pkt->dhcp->magic;
7968 res.xid = pkt->dhcp->xid;
7969 // memcpy(ifp->gwmac, pkt->eth->src, sizeof(ifp->gwmac));
7970 tx_udp(ifp, pkt->eth->src, ifp->ip, mg_htons(67),
7971 op == 1 ? ~0U : res.yiaddr, mg_htons(68), &res, sizeof(res));
7972 }
7973}
7974
7975static void rx_udp(struct mg_tcpip_if *ifp, struct pkt *pkt) {
7976 struct mg_connection *c = getpeer(ifp->mgr, pkt, true);
7977 if (c == NULL) {
7978 // No UDP listener on this port. Should send ICMP, but keep silent.
7979 } else {
7980 c->rem.port = pkt->udp->sport;
7981 memcpy(c->rem.ip, &pkt->ip->src, sizeof(uint32_t));
7982 struct connstate *s = (struct connstate *) (c + 1);
7983 memcpy(s->mac, pkt->eth->src, sizeof(s->mac));
7984 if (c->recv.len >= MG_MAX_RECV_SIZE) {
7985 mg_error(c, "max_recv_buf_size reached");
7986 } else if (c->recv.size - c->recv.len < pkt->pay.len &&
7987 !mg_iobuf_resize(&c->recv, c->recv.len + pkt->pay.len)) {
7988 mg_error(c, "oom");
7989 } else {
7990 memcpy(&c->recv.buf[c->recv.len], pkt->pay.ptr, pkt->pay.len);
7991 c->recv.len += pkt->pay.len;
7992 mg_call(c, MG_EV_READ, &pkt->pay.len);
7993 }
7994 }
7995}
7996
7997static size_t tx_tcp(struct mg_tcpip_if *ifp, uint8_t *dst_mac, uint32_t dst_ip,
7998 uint8_t flags, uint16_t sport, uint16_t dport,
7999 uint32_t seq, uint32_t ack, const void *buf, size_t len) {
8000 struct ip *ip =
8001 tx_ip(ifp, dst_mac, 6, ifp->ip, dst_ip, sizeof(struct tcp) + len);
8002 struct tcp *tcp = (struct tcp *) (ip + 1);
8003 memset(tcp, 0, sizeof(*tcp));
8004 if (buf != NULL && len) memmove(tcp + 1, buf, len);
8005 tcp->sport = sport;
8006 tcp->dport = dport;
8007 tcp->seq = seq;
8008 tcp->ack = ack;
8009 tcp->flags = flags;
8010 tcp->win = mg_htons(8192);
8011 tcp->off = (uint8_t) (sizeof(*tcp) / 4 << 4);
8012 uint32_t cs = 0;
8013 uint16_t n = (uint16_t) (sizeof(*tcp) + len);
8014 uint8_t pseudo[] = {0, ip->proto, (uint8_t) (n >> 8), (uint8_t) (n & 255)};
8015 cs = csumup(cs, tcp, n);
8016 cs = csumup(cs, &ip->src, sizeof(ip->src));
8017 cs = csumup(cs, &ip->dst, sizeof(ip->dst));
8018 cs = csumup(cs, pseudo, sizeof(pseudo));
8019 tcp->csum = csumfin(cs);
8020 MG_DEBUG(("TCP %M:%hu -> %M:%hu fl %x len %u", mg_print_ip4, &ip->src,
8021 mg_ntohs(tcp->sport), mg_print_ip4, &ip->dst, mg_ntohs(tcp->dport),
8022 tcp->flags, (int) len));
8023 return ether_output(ifp, PDIFF(ifp->tx.ptr, tcp + 1) + len);
8024}
8025
8026static size_t tx_tcp_pkt(struct mg_tcpip_if *ifp, struct pkt *pkt,
8027 uint8_t flags, uint32_t seq, const void *buf,
8028 size_t len) {
8029 uint32_t delta = (pkt->tcp->flags & (TH_SYN | TH_FIN)) ? 1 : 0;
8030 return tx_tcp(ifp, pkt->eth->src, pkt->ip->src, flags, pkt->tcp->dport,
8031 pkt->tcp->sport, seq, mg_htonl(mg_ntohl(pkt->tcp->seq) + delta),
8032 buf, len);
8033}
8034
8035static void settmout(struct mg_connection *c, uint8_t type) {
8036 struct mg_tcpip_if *ifp = (struct mg_tcpip_if *) c->mgr->priv;
8037 struct connstate *s = (struct connstate *) (c + 1);
8038 unsigned n = type == MIP_TTYPE_ACK ? MIP_TCP_ACK_MS : MIP_TCP_KEEPALIVE_MS;
8039 s->timer = ifp->now + n;
8040 s->ttype = type;
8041 MG_VERBOSE(("%lu %d -> %llx", c->id, type, s->timer));
8042}
8043
8044static struct mg_connection *accept_conn(struct mg_connection *lsn,
8045 struct pkt *pkt) {
8046 struct mg_connection *c = mg_alloc_conn(lsn->mgr);
8047 if (c == NULL) {
8048 MG_ERROR(("OOM"));
8049 return NULL;
8050 }
8051 struct connstate *s = (struct connstate *) (c + 1);
8052 s->seq = mg_ntohl(pkt->tcp->ack), s->ack = mg_ntohl(pkt->tcp->seq);
8053 memcpy(s->mac, pkt->eth->src, sizeof(s->mac));
8054 settmout(c, MIP_TTYPE_KEEPALIVE);
8055 memcpy(c->rem.ip, &pkt->ip->src, sizeof(uint32_t));
8056 c->rem.port = pkt->tcp->sport;
8057 MG_DEBUG(("%lu accepted %M", c->id, mg_print_ip_port, &c->rem));
8058 LIST_ADD_HEAD(struct mg_connection, &lsn->mgr->conns, c);
8059 c->is_accepted = 1;
8060 c->is_hexdumping = lsn->is_hexdumping;
8061 c->pfn = lsn->pfn;
8062 c->loc = lsn->loc;
8063 c->pfn_data = lsn->pfn_data;
8064 c->fn = lsn->fn;
8065 c->fn_data = lsn->fn_data;
8066 mg_call(c, MG_EV_OPEN, NULL);
8067 mg_call(c, MG_EV_ACCEPT, NULL);
8068 return c;
8069}
8070
8071long mg_io_send(struct mg_connection *c, const void *buf, size_t len) {
8072 struct mg_tcpip_if *ifp = (struct mg_tcpip_if *) c->mgr->priv;
8073 struct connstate *s = (struct connstate *) (c + 1);
8074 uint32_t rem_ip;
8075 memcpy(&rem_ip, c->rem.ip, sizeof(uint32_t));
8076 if (c->is_udp) {
8077 size_t max_headers_len = 14 + 24 /* max IP */ + 8 /* UDP */;
8078 if (len + max_headers_len > ifp->tx.len) {
8079 len = ifp->tx.len - max_headers_len;
8080 }
8081 tx_udp(ifp, s->mac, ifp->ip, c->loc.port, rem_ip, c->rem.port, buf, len);
8082 } else {
8083 size_t max_headers_len = 14 + 24 /* max IP */ + 60 /* max TCP */;
8084 if (len + max_headers_len > ifp->tx.len)
8085 len = ifp->tx.len - max_headers_len;
8086 if (tx_tcp(ifp, s->mac, rem_ip, TH_PUSH | TH_ACK, c->loc.port, c->rem.port,
8087 mg_htonl(s->seq), mg_htonl(s->ack), buf, len) > 0) {
8088 s->seq += (uint32_t) len;
8089 if (s->ttype == MIP_TTYPE_ACK) settmout(c, MIP_TTYPE_KEEPALIVE);
8090 } else {
8091 return MG_IO_ERR;
8092 }
8093 }
8094 return (long) len;
8095}
8096
8097long mg_io_recv(struct mg_connection *c, void *buf, size_t len) {
8098 struct connstate *s = (struct connstate *) (c + 1);
8099 if (s->raw.len == 0) return MG_IO_WAIT;
8100 if (len > s->raw.len) len = s->raw.len;
8101 memcpy(buf, s->raw.buf, len);
8102 mg_iobuf_del(&s->raw, 0, len);
8103 MG_DEBUG(("%lu", len));
8104 return (long) len;
8105}
8106
8107static void read_conn(struct mg_connection *c, struct pkt *pkt) {
8108 struct connstate *s = (struct connstate *) (c + 1);
8109 struct mg_iobuf *io = c->is_tls ? &s->raw : &c->recv;
8110 uint32_t seq = mg_ntohl(pkt->tcp->seq);
8111 s->raw.align = c->recv.align;
8112 if (pkt->tcp->flags & TH_FIN) {
8113 s->ack = mg_htonl(pkt->tcp->seq) + 1, s->seq = mg_htonl(pkt->tcp->ack);
8114 c->is_closing = 1;
8115 } else if (pkt->pay.len == 0) {
8116 // TODO(cpq): handle this peer's ACK
8117 } else if (seq != s->ack) {
8118 uint32_t ack = (uint32_t) (mg_htonl(pkt->tcp->seq) + pkt->pay.len);
8119 if (s->ack == ack) {
8120 MG_VERBOSE(("ignoring duplicate pkt"));
8121 } else {
8122 // TODO(cpq): peer sent us SEQ which we don't expect. Retransmit
8123 // rather than close this connection
8124 mg_error(c, "SEQ != ACK: %x %x %x", seq, s->ack, ack);
8125 }
8126 } else if (io->size - io->len < pkt->pay.len &&
8127 !mg_iobuf_resize(io, io->len + pkt->pay.len)) {
8128 mg_error(c, "oom");
8129 } else {
8130 // Copy TCP payload into the IO buffer. If the connection is plain text,
8131 // we copy to c->recv. If the connection is TLS, this data is encrypted,
8132 // therefore we copy that encrypted data to the s->raw iobuffer instead,
8133 // and then call mg_tls_recv() to decrypt it. NOTE: mg_tls_recv() will
8134 // call back mg_io_recv() which grabs raw data from s->raw
8135 memcpy(&io->buf[io->len], pkt->pay.ptr, pkt->pay.len);
8136 io->len += pkt->pay.len;
8137
8138 MG_DEBUG(("%lu SEQ %x -> %x", c->id, mg_htonl(pkt->tcp->seq), s->ack));
8139 // Advance ACK counter
8140 s->ack = (uint32_t) (mg_htonl(pkt->tcp->seq) + pkt->pay.len);
8141#if 0
8142 // Send ACK immediately
8143 MG_DEBUG((" imm ACK", c->id, mg_htonl(pkt->tcp->seq), s->ack));
8144 tx_tcp((struct mg_tcpip_if *) c->mgr->priv, c->rem.ip, TH_ACK, c->loc.port,
8145 c->rem.port, mg_htonl(s->seq), mg_htonl(s->ack), "", 0);
8146#else
8147 // if not already running, setup a timer to send an ACK later
8148 if (s->ttype != MIP_TTYPE_ACK) settmout(c, MIP_TTYPE_ACK);
8149#endif
8150
8151 if (c->is_tls) {
8152 // TLS connection. Make room for decrypted data in c->recv
8153 io = &c->recv;
8154 if (io->size - io->len < pkt->pay.len &&
8155 !mg_iobuf_resize(io, io->len + pkt->pay.len)) {
8156 mg_error(c, "oom");
8157 } else {
8158 // Decrypt data directly into c->recv
8159 long n = mg_tls_recv(c, &io->buf[io->len], io->size - io->len);
8160 if (n == MG_IO_ERR) {
8161 mg_error(c, "TLS recv error");
8162 } else if (n > 0) {
8163 // Decrypted successfully - trigger MG_EV_READ
8164 io->len += (size_t) n;
8165 mg_call(c, MG_EV_READ, &n);
8166 }
8167 }
8168 } else {
8169 // Plain text connection, data is already in c->recv, trigger
8170 // MG_EV_READ
8171 mg_call(c, MG_EV_READ, &pkt->pay.len);
8172 }
8173 }
8174}
8175
8176static void rx_tcp(struct mg_tcpip_if *ifp, struct pkt *pkt) {
8177 struct mg_connection *c = getpeer(ifp->mgr, pkt, false);
8178 struct connstate *s = c == NULL ? NULL : (struct connstate *) (c + 1);
8179#if 0
8180 MG_INFO(("%lu %hhu %d", c ? c->id : 0, pkt->tcp->flags, (int) pkt->pay.len));
8181#endif
8182 if (c != NULL && c->is_connecting && pkt->tcp->flags & (TH_SYN | TH_ACK)) {
8183 s->seq = mg_ntohl(pkt->tcp->ack), s->ack = mg_ntohl(pkt->tcp->seq) + 1;
8184 tx_tcp_pkt(ifp, pkt, TH_ACK, pkt->tcp->ack, NULL, 0);
8185 c->is_connecting = 0; // Client connected
8186 settmout(c, MIP_TTYPE_KEEPALIVE);
8187 mg_call(c, MG_EV_CONNECT, NULL); // Let user know
8188 } else if (c != NULL && c->is_connecting) {
8189 tx_tcp_pkt(ifp, pkt, TH_RST | TH_ACK, pkt->tcp->ack, NULL, 0);
8190 } else if (c != NULL && pkt->tcp->flags & TH_RST) {
8191 mg_error(c, "peer RST"); // RFC-1122 4.2.2.13
8192 } else if (c != NULL) {
8193#if 0
8194 MG_DEBUG(("%lu %d %M:%hu -> %M:%hu", c->id, (int) pkt->raw.len,
8195 mg_print_ip4, &pkt->ip->src, mg_ntohs(pkt->tcp->sport),
8196 mg_print_ip4, &pkt->ip->dst, mg_ntohs(pkt->tcp->dport)));
8197 mg_hexdump(pkt->pay.buf, pkt->pay.len);
8198#endif
8199 s->tmiss = 0; // Reset missed keep-alive counter
8200 if (s->ttype == MIP_TTYPE_KEEPALIVE) // Advance keep-alive timer
8201 settmout(c,
8202 MIP_TTYPE_KEEPALIVE); // unless a former ACK timeout is pending
8203 read_conn(c, pkt); // Override timer with ACK timeout if needed
8204 } else if ((c = getpeer(ifp->mgr, pkt, true)) == NULL) {
8205 tx_tcp_pkt(ifp, pkt, TH_RST | TH_ACK, pkt->tcp->ack, NULL, 0);
8206 } else if (pkt->tcp->flags & TH_RST) {
8207 if (c->is_accepted) mg_error(c, "peer RST"); // RFC-1122 4.2.2.13
8208 // ignore RST if not connected
8209 } else if (pkt->tcp->flags & TH_SYN) {
8210 // Use peer's source port as ISN, in order to recognise the handshake
8211 uint32_t isn = mg_htonl((uint32_t) mg_ntohs(pkt->tcp->sport));
8212 tx_tcp_pkt(ifp, pkt, TH_SYN | TH_ACK, isn, NULL, 0);
8213 } else if (pkt->tcp->flags & TH_FIN) {
8214 tx_tcp_pkt(ifp, pkt, TH_FIN | TH_ACK, pkt->tcp->ack, NULL, 0);
8215 } else if (mg_htonl(pkt->tcp->ack) == mg_htons(pkt->tcp->sport) + 1U) {
8216 accept_conn(c, pkt);
8217 } else if (!c->is_accepted) { // no peer
8218 tx_tcp_pkt(ifp, pkt, TH_RST | TH_ACK, pkt->tcp->ack, NULL, 0);
8219 } else {
8220 // MG_DEBUG(("dropped silently.."));
8221 }
8222}
8223
8224static void rx_ip(struct mg_tcpip_if *ifp, struct pkt *pkt) {
8225 if (pkt->ip->proto == 1) {
8226 pkt->icmp = (struct icmp *) (pkt->ip + 1);
8227 if (pkt->pay.len < sizeof(*pkt->icmp)) return;
8228 mkpay(pkt, pkt->icmp + 1);
8229 rx_icmp(ifp, pkt);
8230 } else if (pkt->ip->proto == 17) {
8231 pkt->udp = (struct udp *) (pkt->ip + 1);
8232 if (pkt->pay.len < sizeof(*pkt->udp)) return;
8233 mkpay(pkt, pkt->udp + 1);
8234 MG_DEBUG(("UDP %M:%hu -> %M:%hu len %u", mg_print_ip4, &pkt->ip->src,
8235 mg_ntohs(pkt->udp->sport), mg_print_ip4, &pkt->ip->dst,
8236 mg_ntohs(pkt->udp->dport), (int) pkt->pay.len));
8237 if (pkt->udp->dport == mg_htons(68)) {
8238 pkt->dhcp = (struct dhcp *) (pkt->udp + 1);
8239 mkpay(pkt, pkt->dhcp + 1);
8240 rx_dhcp_client(ifp, pkt);
8241 } else if (ifp->enable_dhcp_server && pkt->udp->dport == mg_htons(67)) {
8242 pkt->dhcp = (struct dhcp *) (pkt->udp + 1);
8243 mkpay(pkt, pkt->dhcp + 1);
8244 rx_dhcp_server(ifp, pkt);
8245 } else {
8246 rx_udp(ifp, pkt);
8247 }
8248 } else if (pkt->ip->proto == 6) {
8249 pkt->tcp = (struct tcp *) (pkt->ip + 1);
8250 if (pkt->pay.len < sizeof(*pkt->tcp)) return;
8251 mkpay(pkt, pkt->tcp + 1);
8252 uint16_t iplen = mg_ntohs(pkt->ip->len);
8253 uint16_t off = (uint16_t) (sizeof(*pkt->ip) + ((pkt->tcp->off >> 4) * 4U));
8254 if (iplen >= off) pkt->pay.len = (size_t) (iplen - off);
8255 MG_DEBUG(("TCP %M:%hu -> %M:%hu len %u", mg_print_ip4, &pkt->ip->src,
8256 mg_ntohs(pkt->tcp->sport), mg_print_ip4, &pkt->ip->dst,
8257 mg_ntohs(pkt->tcp->dport), (int) pkt->pay.len));
8258 rx_tcp(ifp, pkt);
8259 }
8260}
8261
8262static void rx_ip6(struct mg_tcpip_if *ifp, struct pkt *pkt) {
8263 // MG_DEBUG(("IP %d", (int) len));
8264 if (pkt->ip6->proto == 1 || pkt->ip6->proto == 58) {
8265 pkt->icmp = (struct icmp *) (pkt->ip6 + 1);
8266 if (pkt->pay.len < sizeof(*pkt->icmp)) return;
8267 mkpay(pkt, pkt->icmp + 1);
8268 rx_icmp(ifp, pkt);
8269 } else if (pkt->ip6->proto == 17) {
8270 pkt->udp = (struct udp *) (pkt->ip6 + 1);
8271 if (pkt->pay.len < sizeof(*pkt->udp)) return;
8272 // MG_DEBUG((" UDP %u %u -> %u", len, mg_htons(udp->sport),
8273 // mg_htons(udp->dport)));
8274 mkpay(pkt, pkt->udp + 1);
8275 }
8276}
8277
8278static void mg_tcpip_rx(struct mg_tcpip_if *ifp, void *buf, size_t len) {
8279 struct pkt pkt;
8280 memset(&pkt, 0, sizeof(pkt));
8281 pkt.raw.ptr = (char *) buf;
8282 pkt.raw.len = len;
8283 pkt.eth = (struct eth *) buf;
8284 if (pkt.raw.len < sizeof(*pkt.eth)) return; // Truncated - runt?
8285 if (ifp->enable_mac_check &&
8286 memcmp(pkt.eth->dst, ifp->mac, sizeof(pkt.eth->dst)) != 0 &&
8287 memcmp(pkt.eth->dst, broadcast, sizeof(pkt.eth->dst)) != 0)
8288 return;
8289 if (ifp->enable_crc32_check && len > 4) {
8290 len -= 4; // TODO(scaprile): check on bigendian
8291 uint32_t crc = mg_crc32(0, (const char *) buf, len);
8292 if (memcmp((void *) ((size_t) buf + len), &crc, sizeof(crc))) return;
8293 }
8294 if (pkt.eth->type == mg_htons(0x806)) {
8295 pkt.arp = (struct arp *) (pkt.eth + 1);
8296 if (sizeof(*pkt.eth) + sizeof(*pkt.arp) > pkt.raw.len) return; // Truncated
8297 rx_arp(ifp, &pkt);
8298 } else if (pkt.eth->type == mg_htons(0x86dd)) {
8299 pkt.ip6 = (struct ip6 *) (pkt.eth + 1);
8300 if (pkt.raw.len < sizeof(*pkt.eth) + sizeof(*pkt.ip6)) return; // Truncated
8301 if ((pkt.ip6->ver >> 4) != 0x6) return; // Not IP
8302 mkpay(&pkt, pkt.ip6 + 1);
8303 rx_ip6(ifp, &pkt);
8304 } else if (pkt.eth->type == mg_htons(0x800)) {
8305 pkt.ip = (struct ip *) (pkt.eth + 1);
8306 if (pkt.raw.len < sizeof(*pkt.eth) + sizeof(*pkt.ip)) return; // Truncated
8307 // Truncate frame to what IP header tells us
8308 if ((size_t) mg_ntohs(pkt.ip->len) + sizeof(struct eth) < pkt.raw.len) {
8309 pkt.raw.len = (size_t) mg_ntohs(pkt.ip->len) + sizeof(struct eth);
8310 }
8311 if (pkt.raw.len < sizeof(*pkt.eth) + sizeof(*pkt.ip)) return; // Truncated
8312 if ((pkt.ip->ver >> 4) != 4) return; // Not IP
8313 mkpay(&pkt, pkt.ip + 1);
8314 rx_ip(ifp, &pkt);
8315 } else {
8316 MG_DEBUG((" Unknown eth type %x", mg_htons(pkt.eth->type)));
8317 mg_hexdump(buf, len >= 16 ? 16 : len);
8318 }
8319}
8320
8321static void mg_tcpip_poll(struct mg_tcpip_if *ifp, uint64_t uptime_ms) {
8322 if (ifp == NULL || ifp->driver == NULL) return;
8323 bool expired_1000ms = mg_timer_expired(&ifp->timer_1000ms, 1000, uptime_ms);
8324 ifp->now = uptime_ms;
8325
8326 // Handle physical interface up/down status
8327 if (expired_1000ms && ifp->driver->up) {
8328 bool up = ifp->driver->up(ifp);
8329 bool current = ifp->state != MG_TCPIP_STATE_DOWN;
8330 if (up != current) {
8331 ifp->state = up == false ? MG_TCPIP_STATE_DOWN
8332 : ifp->enable_dhcp_client ? MG_TCPIP_STATE_UP
8333 : MG_TCPIP_STATE_READY;
8334 if (!up && ifp->enable_dhcp_client) ifp->ip = 0;
8335 onstatechange(ifp);
8336 }
8337 }
8338 if (ifp->state == MG_TCPIP_STATE_DOWN) return;
8339
8340 // DHCP RFC-2131 (4.4)
8341 if (ifp->state == MG_TCPIP_STATE_UP && expired_1000ms) {
8342 tx_dhcp_discover(ifp); // INIT (4.4.1)
8343 } else if (expired_1000ms && ifp->state == MG_TCPIP_STATE_READY &&
8344 ifp->lease_expire > 0) { // BOUND / RENEWING / REBINDING
8345 if (ifp->now >= ifp->lease_expire) {
8346 ifp->state = MG_TCPIP_STATE_UP, ifp->ip = 0; // expired, release IP
8347 onstatechange(ifp);
8348 } else if (ifp->now + 30 * 60 * 1000 > ifp->lease_expire &&
8349 ((ifp->now / 1000) % 60) == 0) {
8350 // hack: 30 min before deadline, try to rebind (4.3.6) every min
8351 tx_dhcp_request_re(ifp, (uint8_t *) broadcast, ifp->ip, 0xffffffff);
8352 } // TODO(): Handle T1 (RENEWING) and T2 (REBINDING) (4.4.5)
8353 }
8354
8355 // Read data from the network
8356 if (ifp->driver->rx != NULL) { // Polling driver. We must call it
8357 size_t len =
8358 ifp->driver->rx(ifp->recv_queue.buf, ifp->recv_queue.size, ifp);
8359 if (len > 0) mg_tcpip_rx(ifp, ifp->recv_queue.buf, len);
8360 } else { // Interrupt-based driver. Fills recv queue itself
8361 char *buf;
8362 size_t len = mg_queue_next(&ifp->recv_queue, &buf);
8363 if (len > 0) {
8364 mg_tcpip_rx(ifp, buf, len);
8365 mg_queue_del(&ifp->recv_queue, len);
8366 }
8367 }
8368
8369 // Process timeouts
8370 for (struct mg_connection *c = ifp->mgr->conns; c != NULL; c = c->next) {
8371 if (c->is_udp || c->is_listening) continue;
8372 if (c->is_connecting || c->is_resolving) continue;
8373 struct connstate *s = (struct connstate *) (c + 1);
8374 uint32_t rem_ip;
8375 memcpy(&rem_ip, c->rem.ip, sizeof(uint32_t));
8376 if (uptime_ms > s->timer) {
8377 if (s->ttype == MIP_TTYPE_ACK) {
8378 MG_DEBUG(("%lu ack %x %x", c->id, s->seq, s->ack));
8379 tx_tcp(ifp, s->mac, rem_ip, TH_ACK, c->loc.port, c->rem.port,
8380 mg_htonl(s->seq), mg_htonl(s->ack), "", 0);
8381 } else {
8382 if (s->tmiss++ > 2) {
8383 mg_error(c, "keepalive");
8384 } else {
8385 MG_DEBUG(("%lu keepalive", c->id));
8386 tx_tcp(ifp, s->mac, rem_ip, TH_ACK, c->loc.port, c->rem.port,
8387 mg_htonl(s->seq - 1), mg_htonl(s->ack), "", 0);
8388 }
8389 }
8390 settmout(c, MIP_TTYPE_KEEPALIVE);
8391 }
8392 }
8393}
8394
8395// This function executes in interrupt context, thus it should copy data
8396// somewhere fast. Note that newlib's malloc is not thread safe, thus use
8397// our lock-free queue with preallocated buffer to copy data and return asap
8398void mg_tcpip_qwrite(void *buf, size_t len, struct mg_tcpip_if *ifp) {
8399 char *p;
8400 if (mg_queue_book(&ifp->recv_queue, &p, len) >= len) {
8401 memcpy(p, buf, len);
8402 mg_queue_add(&ifp->recv_queue, len);
8403 ifp->nrecv++;
8404 } else {
8405 ifp->ndrop++;
8406 }
8407}
8408
8409void mg_tcpip_init(struct mg_mgr *mgr, struct mg_tcpip_if *ifp) {
8410 // If MAC address is not set, make a random one
8411 if (ifp->mac[0] == 0 && ifp->mac[1] == 0 && ifp->mac[2] == 0 &&
8412 ifp->mac[3] == 0 && ifp->mac[4] == 0 && ifp->mac[5] == 0) {
8413 ifp->mac[0] = 0x02; // Locally administered, unicast
8414 mg_random(&ifp->mac[1], sizeof(ifp->mac) - 1);
8415 MG_INFO(("MAC not set. Generated random: %M", mg_print_mac, ifp->mac));
8416 }
8417
8418 if (ifp->driver->init && !ifp->driver->init(ifp)) {
8419 MG_ERROR(("driver init failed"));
8420 } else {
8421 size_t framesize = 1540;
8422 ifp->tx.ptr = (char *) calloc(1, framesize), ifp->tx.len = framesize;
8423 if (ifp->recv_queue.size == 0)
8424 ifp->recv_queue.size = ifp->driver->rx ? framesize : 8192;
8425 ifp->recv_queue.buf = (char *) calloc(1, ifp->recv_queue.size);
8426 ifp->timer_1000ms = mg_millis();
8427 mgr->priv = ifp;
8428 ifp->mgr = mgr;
8429 mgr->extraconnsize = sizeof(struct connstate);
8430 if (ifp->ip == 0) ifp->enable_dhcp_client = true;
8431 memset(ifp->gwmac, 255, sizeof(ifp->gwmac)); // Set to broadcast
8432 mg_random(&ifp->eport, sizeof(ifp->eport)); // Random from 0 to 65535
8433 ifp->eport |= MG_EPHEMERAL_PORT_BASE; // Random from
8434 // MG_EPHEMERAL_PORT_BASE to 65535
8435 if (ifp->tx.ptr == NULL || ifp->recv_queue.buf == NULL) MG_ERROR(("OOM"));
8436 }
8437}
8438
8439void mg_tcpip_free(struct mg_tcpip_if *ifp) {
8440 free(ifp->recv_queue.buf);
8441 free((char *) ifp->tx.ptr);
8442}
8443
8444int mg_mkpipe(struct mg_mgr *m, mg_event_handler_t fn, void *d, bool udp) {
8445 (void) m, (void) fn, (void) d, (void) udp;
8446 MG_ERROR(("Not implemented"));
8447 return -1;
8448}
8449
8450static void send_syn(struct mg_connection *c) {
8451 struct connstate *s = (struct connstate *) (c + 1);
8452 uint32_t isn = mg_htonl((uint32_t) mg_ntohs(c->loc.port));
8453 struct mg_tcpip_if *ifp = (struct mg_tcpip_if *) c->mgr->priv;
8454 uint32_t rem_ip;
8455 memcpy(&rem_ip, c->rem.ip, sizeof(uint32_t));
8456 tx_tcp(ifp, s->mac, rem_ip, TH_SYN, c->loc.port, c->rem.port, isn, 0, NULL,
8457 0);
8458}
8459
8460void mg_connect_resolved(struct mg_connection *c) {
8461 struct mg_tcpip_if *ifp = (struct mg_tcpip_if *) c->mgr->priv;
8462 uint32_t rem_ip;
8463 memcpy(&rem_ip, c->rem.ip, sizeof(uint32_t));
8464 c->is_resolving = 0;
8465 if (ifp->eport < MG_EPHEMERAL_PORT_BASE) ifp->eport = MG_EPHEMERAL_PORT_BASE;
8466 memcpy(c->loc.ip, &ifp->ip, sizeof(uint32_t));
8467 c->loc.port = mg_htons(ifp->eport++);
8468 MG_DEBUG(("%lu %M -> %M", c->id, mg_print_ip_port, &c->loc, mg_print_ip_port,
8469 &c->rem));
8470 mg_call(c, MG_EV_RESOLVE, NULL);
8471 if (((rem_ip & ifp->mask) == (ifp->ip & ifp->mask))) {
8472 // If we're in the same LAN, fire an ARP lookup. TODO(cpq): handle this!
8473 MG_DEBUG(("%lu ARP lookup...", c->id));
8474 arp_ask(ifp, rem_ip);
8475 c->is_arplooking = 1;
8476 } else if (rem_ip == (ifp->ip | ~ifp->mask)) {
8477 struct connstate *s = (struct connstate *) (c + 1);
8478 memset(s->mac, 0xFF, sizeof(s->mac)); // local broadcast
8479 } else if ((*((uint8_t *) &rem_ip) & 0xE0) == 0xE0) {
8480 struct connstate *s = (struct connstate *) (c + 1); // 224 to 239, E0 to EF
8481 uint8_t mcastp[3] = {0x01, 0x00, 0x5E}; // multicast group
8482 memcpy(s->mac, mcastp, 3);
8483 memcpy(s->mac + 3, ((uint8_t *) &rem_ip) + 1, 3); // 23 LSb
8484 s->mac[3] &= 0x7F;
8485 } else {
8486 struct connstate *s = (struct connstate *) (c + 1);
8487 memcpy(s->mac, ifp->gwmac, sizeof(ifp->gwmac));
8488 if (c->is_udp) {
8489 mg_call(c, MG_EV_CONNECT, NULL);
8490 } else {
8491 send_syn(c);
8492 c->is_connecting = 1;
8493 }
8494 }
8495}
8496
8497bool mg_open_listener(struct mg_connection *c, const char *url) {
8498 c->loc.port = mg_htons(mg_url_port(url));
8499 return true;
8500}
8501
8502static void write_conn(struct mg_connection *c) {
8503 long len = c->is_tls ? mg_tls_send(c, c->send.buf, c->send.len)
8504 : mg_io_send(c, c->send.buf, c->send.len);
8505 if (len > 0) {
8506 mg_iobuf_del(&c->send, 0, (size_t) len);
8507 mg_call(c, MG_EV_WRITE, &len);
8508 }
8509}
8510
8511static void close_conn(struct mg_connection *c) {
8512 struct connstate *s = (struct connstate *) (c + 1);
8513 uint32_t rem_ip;
8514 memcpy(&rem_ip, c->rem.ip, sizeof(uint32_t));
8515 mg_iobuf_free(&s->raw); // For TLS connections, release raw data
8516 if (c->is_udp == false && c->is_listening == false) { // For TCP conns,
8517 struct mg_tcpip_if *ifp =
8518 (struct mg_tcpip_if *) c->mgr->priv; // send TCP FIN
8519 tx_tcp(ifp, s->mac, rem_ip, TH_FIN | TH_ACK, c->loc.port, c->rem.port,
8520 mg_htonl(s->seq), mg_htonl(s->ack), NULL, 0);
8521 }
8522 mg_close_conn(c);
8523}
8524
8525static bool can_write(struct mg_connection *c) {
8526 return c->is_connecting == 0 && c->is_resolving == 0 && c->send.len > 0 &&
8527 c->is_tls_hs == 0 && c->is_arplooking == 0;
8528}
8529
8530void mg_mgr_poll(struct mg_mgr *mgr, int ms) {
8531 struct mg_connection *c, *tmp;
8532 uint64_t now = mg_millis();
8533 mg_tcpip_poll((struct mg_tcpip_if *) mgr->priv, now);
8534 mg_timer_poll(&mgr->timers, now);
8535 for (c = mgr->conns; c != NULL; c = tmp) {
8536 tmp = c->next;
8537 mg_call(c, MG_EV_POLL, &now);
8538 MG_VERBOSE(("%lu .. %c%c%c%c%c", c->id, c->is_tls ? 'T' : 't',
8539 c->is_connecting ? 'C' : 'c', c->is_tls_hs ? 'H' : 'h',
8540 c->is_resolving ? 'R' : 'r', c->is_closing ? 'C' : 'c'));
8541 if (c->is_tls_hs) mg_tls_handshake(c);
8542 if (can_write(c)) write_conn(c);
8543 if (c->is_draining && c->send.len == 0) c->is_closing = 1;
8544 if (c->is_closing) close_conn(c);
8545 }
8546 (void) ms;
8547}
8548
8549bool mg_send(struct mg_connection *c, const void *buf, size_t len) {
8550 struct mg_tcpip_if *ifp = (struct mg_tcpip_if *) c->mgr->priv;
8551 bool res = false;
8552 uint32_t rem_ip;
8553 memcpy(&rem_ip, c->rem.ip, sizeof(uint32_t));
8554 if (ifp->ip == 0 || ifp->state != MG_TCPIP_STATE_READY) {
8555 mg_error(c, "net down");
8556 } else if (c->is_udp) {
8557 struct connstate *s = (struct connstate *) (c + 1);
8558 tx_udp(ifp, s->mac, ifp->ip, c->loc.port, rem_ip, c->rem.port, buf, len);
8559 res = true;
8560 } else {
8561 res = mg_iobuf_add(&c->send, c->send.len, buf, len);
8562 }
8563 return res;
8564}
8565#endif // MG_ENABLE_TCPIP
8566