1 // Copyright (c) 2004-2013 Sergey Lyubka
2 // Copyright (c) 2013-2022 Cesanta Software Limited
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/
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.
15 // Alternatively, you can license this software under a commercial
16 // license, as set out in https://www.mongoose.ws/licensing/
18 // SPDX-License-Identifier: GPL-2.0-only or commercial
22 #ifdef MG_ENABLE_LINES
23 #line 1 "src/base64.c"
28 static int mg_b64idx(int c) {
36 return c == 62 ? '+' : '/';
40 static int mg_b64rev(int c) {
41 if (c >= 'A' && c <= 'Z') {
43 } else if (c >= 'a' && c <= 'z') {
45 } else if (c >= '0' && c <= '9') {
47 } else if (c == '+') {
49 } else if (c == '/') {
51 } else if (c == '=') {
58 int mg_base64_update(unsigned char ch, char *to, int n) {
59 int rem = (n & 3) % 3;
61 to[n] = (char) mg_b64idx(ch >> 2);
62 to[++n] = (char) ((ch & 3) << 4);
63 } else if (rem == 1) {
64 to[n] = (char) mg_b64idx(to[n] | (ch >> 4));
65 to[++n] = (char) ((ch & 15) << 2);
67 to[n] = (char) mg_b64idx(to[n] | (ch >> 6));
68 to[++n] = (char) mg_b64idx(ch & 63);
74 int mg_base64_final(char *to, int n) {
76 // printf("---[%.*s]\n", n, to);
77 if (n & 3) n = mg_base64_update(0, to, n);
78 if ((saved & 3) == 2) n--;
79 // printf(" %d[%.*s]\n", n, n, to);
80 while (n & 3) to[n++] = '=';
85 int mg_base64_encode(const unsigned char *p, int n, char *to) {
87 for (i = 0; i < n; i++) len = mg_base64_update(p[i], to, len);
88 len = mg_base64_final(to, len);
92 int mg_base64_decode(const char *src, int n, char *dst) {
93 const char *end = src == NULL ? NULL : src + n; // Cannot add to NULL
95 while (src != NULL && src + 3 < end) {
96 int a = mg_b64rev(src[0]), b = mg_b64rev(src[1]), c = mg_b64rev(src[2]),
97 d = mg_b64rev(src[3]);
98 if (a == 64 || a < 0 || b == 64 || b < 0 || c < 0 || d < 0) return 0;
99 dst[len++] = (char) ((a << 2) | (b >> 4));
101 dst[len++] = (char) ((b << 4) | (c >> 2));
102 if (src[3] != '=') dst[len++] = (char) ((c << 6) | d);
110 #ifdef MG_ENABLE_LINES
122 struct dns_data *next;
123 struct mg_connection *c;
128 static void mg_sendnsreq(struct mg_connection *, struct mg_str *, int,
129 struct mg_dns *, bool);
131 static void mg_dns_free(struct mg_connection *c, struct dns_data *d) {
132 LIST_DELETE(struct dns_data,
133 (struct dns_data **) &c->mgr->active_dns_requests, d);
137 void mg_resolve_cancel(struct mg_connection *c) {
138 struct dns_data *tmp, *d = (struct dns_data *) c->mgr->active_dns_requests;
139 for (; d != NULL; d = tmp) {
141 if (d->c == c) mg_dns_free(c, d);
145 static size_t mg_dns_parse_name_depth(const uint8_t *s, size_t len, size_t ofs,
146 char *to, size_t tolen, size_t j,
149 if (tolen > 0 && depth == 0) to[0] = '\0';
150 if (depth > 5) return 0;
151 // MG_INFO(("ofs %lx %x %x", (unsigned long) ofs, s[ofs], s[ofs + 1]));
152 while (ofs + i + 1 < len) {
153 size_t n = s[ofs + i];
159 size_t ptr = (((n & 0x3f) << 8) | s[ofs + i + 1]); // 12 is hdr len
160 // MG_INFO(("PTR %lx", (unsigned long) ptr));
161 if (ptr + 1 < len && (s[ptr] & 0xc0) == 0 &&
162 mg_dns_parse_name_depth(s, len, ptr, to, tolen, j, depth + 1) == 0)
167 if (ofs + i + n + 1 >= len) return 0;
169 if (j < tolen) to[j] = '.';
172 if (j + n < tolen) memcpy(&to[j], &s[ofs + i + 1], n);
175 if (j < tolen) to[j] = '\0'; // Zero-terminate this chunk
176 // MG_INFO(("--> [%s]", to));
178 if (tolen > 0) to[tolen - 1] = '\0'; // Make sure make sure it is nul-term
182 static size_t mg_dns_parse_name(const uint8_t *s, size_t n, size_t ofs,
183 char *dst, size_t dstlen) {
184 return mg_dns_parse_name_depth(s, n, ofs, dst, dstlen, 0, 0);
187 size_t mg_dns_parse_rr(const uint8_t *buf, size_t len, size_t ofs,
188 bool is_question, struct mg_dns_rr *rr) {
189 const uint8_t *s = buf + ofs, *e = &buf[len];
191 memset(rr, 0, sizeof(*rr));
192 if (len < sizeof(struct mg_dns_header)) return 0; // Too small
193 if (len > 512) return 0; // Too large, we don't expect that
194 if (s >= e) return 0; // Overflow
196 if ((rr->nlen = (uint16_t) mg_dns_parse_name(buf, len, ofs, NULL, 0)) == 0)
200 rr->atype = (uint16_t) (((uint16_t) s[-4] << 8) | s[-3]);
201 rr->aclass = (uint16_t) (((uint16_t) s[-2] << 8) | s[-1]);
202 if (is_question) return (size_t) (rr->nlen + 4);
206 rr->alen = (uint16_t) (((uint16_t) s[-2] << 8) | s[-1]);
207 if (s + rr->alen > e) return 0;
208 return (size_t) (rr->nlen + rr->alen + 10);
211 bool mg_dns_parse(const uint8_t *buf, size_t len, struct mg_dns_message *dm) {
212 const struct mg_dns_header *h = (struct mg_dns_header *) buf;
214 size_t i, n, ofs = sizeof(*h);
215 memset(dm, 0, sizeof(*dm));
217 if (len < sizeof(*h)) return 0; // Too small, headers dont fit
218 if (mg_ntohs(h->num_questions) > 1) return 0; // Sanity
219 if (mg_ntohs(h->num_answers) > 10) return 0; // Sanity
220 dm->txnid = mg_ntohs(h->txnid);
222 for (i = 0; i < mg_ntohs(h->num_questions); i++) {
223 if ((n = mg_dns_parse_rr(buf, len, ofs, true, &rr)) == 0) return false;
224 // MG_INFO(("Q %lu %lu %hu/%hu", ofs, n, rr.atype, rr.aclass));
227 for (i = 0; i < mg_ntohs(h->num_answers); i++) {
228 if ((n = mg_dns_parse_rr(buf, len, ofs, false, &rr)) == 0) return false;
229 // MG_INFO(("A -- %lu %lu %hu/%hu %s", ofs, n, rr.atype, rr.aclass,
231 mg_dns_parse_name(buf, len, ofs, dm->name, sizeof(dm->name));
234 if (rr.alen == 4 && rr.atype == 1 && rr.aclass == 1) {
235 dm->addr.is_ip6 = false;
236 memcpy(&dm->addr.ip, &buf[ofs - 4], 4);
238 break; // Return success
239 } else if (rr.alen == 16 && rr.atype == 28 && rr.aclass == 1) {
240 dm->addr.is_ip6 = true;
241 memcpy(&dm->addr.ip6, &buf[ofs - 16], 16);
243 break; // Return success
249 static void dns_cb(struct mg_connection *c, int ev, void *ev_data,
251 struct dns_data *d, *tmp;
252 if (ev == MG_EV_POLL) {
253 uint64_t now = *(uint64_t *) ev_data;
254 for (d = (struct dns_data *) c->mgr->active_dns_requests; d != NULL;
257 // MG_DEBUG ("%lu %lu dns poll", d->expire, now));
258 if (now > d->expire) mg_error(d->c, "DNS timeout");
260 } else if (ev == MG_EV_READ) {
261 struct mg_dns_message dm;
263 if (mg_dns_parse(c->recv.buf, c->recv.len, &dm) == false) {
264 MG_ERROR(("Unexpected DNS response:"));
265 mg_hexdump(c->recv.buf, c->recv.len);
267 // MG_VERBOSE(("%s %d", dm.name, dm.resolved));
268 for (d = (struct dns_data *) c->mgr->active_dns_requests; d != NULL;
271 // MG_INFO(("d %p %hu %hu", d, d->txnid, dm.txnid));
272 if (dm.txnid != d->txnid) continue;
273 if (d->c->is_resolving) {
275 dm.addr.port = d->c->rem.port; // Save port
276 d->c->rem = dm.addr; // Copy resolved address
278 ("%lu %s is %M", d->c->id, dm.name, mg_print_ip, &d->c->rem));
279 mg_connect_resolved(d->c);
281 } else if (dm.addr.is_ip6 == false && dm.name[0] != '\0' &&
282 c->mgr->use_dns6 == false) {
283 struct mg_str x = mg_str(dm.name);
284 mg_sendnsreq(d->c, &x, c->mgr->dnstimeout, &c->mgr->dns6, true);
287 mg_error(d->c, "%s DNS lookup failed", dm.name);
290 MG_ERROR(("%lu already resolved", d->c->id));
296 if (!resolved) MG_ERROR(("stray DNS reply"));
298 } else if (ev == MG_EV_CLOSE) {
299 for (d = (struct dns_data *) c->mgr->active_dns_requests; d != NULL;
302 mg_error(d->c, "DNS error");
309 static bool mg_dns_send(struct mg_connection *c, const struct mg_str *name,
310 uint16_t txnid, bool ipv6) {
312 struct mg_dns_header header;
316 memset(&pkt, 0, sizeof(pkt));
317 pkt.header.txnid = mg_htons(txnid);
318 pkt.header.flags = mg_htons(0x100);
319 pkt.header.num_questions = mg_htons(1);
320 for (i = n = 0; i < sizeof(pkt.data) - 5; i++) {
321 if (name->ptr[i] == '.' || i >= name->len) {
322 pkt.data[n] = (uint8_t) (i - n);
323 memcpy(&pkt.data[n + 1], name->ptr + n, i - n);
326 if (i >= name->len) break;
328 memcpy(&pkt.data[n], "\x00\x00\x01\x00\x01", 5); // A query
330 if (ipv6) pkt.data[n - 3] = 0x1c; // AAAA query
331 // memcpy(&pkt.data[n], "\xc0\x0c\x00\x1c\x00\x01", 6); // AAAA query
333 return mg_send(c, &pkt, sizeof(pkt.header) + n);
336 static void mg_sendnsreq(struct mg_connection *c, struct mg_str *name, int ms,
337 struct mg_dns *dnsc, bool ipv6) {
338 struct dns_data *d = NULL;
339 if (dnsc->url == NULL) {
340 mg_error(c, "DNS server URL is NULL. Call mg_mgr_init()");
341 } else if (dnsc->c == NULL) {
342 dnsc->c = mg_connect(c->mgr, dnsc->url, NULL, NULL);
343 if (dnsc->c != NULL) {
344 dnsc->c->pfn = dns_cb;
345 // dnsc->c->is_hexdumping = 1;
348 if (dnsc->c == NULL) {
349 mg_error(c, "resolver");
350 } else if ((d = (struct dns_data *) calloc(1, sizeof(*d))) == NULL) {
351 mg_error(c, "resolve OOM");
353 struct dns_data *reqs = (struct dns_data *) c->mgr->active_dns_requests;
354 d->txnid = reqs ? (uint16_t) (reqs->txnid + 1) : 1;
355 d->next = (struct dns_data *) c->mgr->active_dns_requests;
356 c->mgr->active_dns_requests = d;
357 d->expire = mg_millis() + (uint64_t) ms;
360 MG_VERBOSE(("%lu resolving %.*s @ %s, txnid %hu", c->id, (int) name->len,
361 name->ptr, dnsc->url, d->txnid));
362 if (!mg_dns_send(dnsc->c, name, d->txnid, ipv6)) {
363 mg_error(dnsc->c, "DNS send");
368 void mg_resolve(struct mg_connection *c, const char *url) {
369 struct mg_str host = mg_url_host(url);
370 c->rem.port = mg_htons(mg_url_port(url));
371 if (mg_aton(host, &c->rem)) {
372 // host is an IP address, do not fire name resolution
373 mg_connect_resolved(c);
375 // host is not an IP, send DNS resolution request
376 struct mg_dns *dns = c->mgr->use_dns6 ? &c->mgr->dns6 : &c->mgr->dns4;
377 mg_sendnsreq(c, &host, c->mgr->dnstimeout, dns, c->mgr->use_dns6);
381 #ifdef MG_ENABLE_LINES
382 #line 1 "src/event.c"
389 void mg_call(struct mg_connection *c, int ev, void *ev_data) {
390 // Run user-defined handler first, in order to give it an ability
391 // to intercept processing (e.g. clean input buffer) before the
392 // protocol handler kicks in
393 if (c->fn != NULL) c->fn(c, ev, ev_data, c->fn_data);
394 if (c->pfn != NULL) c->pfn(c, ev, ev_data, c->pfn_data);
397 void mg_error(struct mg_connection *c, const char *fmt, ...) {
401 mg_vsnprintf(buf, sizeof(buf), fmt, &ap);
403 MG_ERROR(("%lu %p %s", c->id, c->fd, buf));
404 c->is_closing = 1; // Set is_closing before sending MG_EV_CALL
405 mg_call(c, MG_EV_ERROR, buf); // Let user handler to override it
408 #ifdef MG_ENABLE_LINES
415 static bool is_digit(int c) {
416 return c >= '0' && c <= '9';
419 static int addexp(char *buf, int e, int sign) {
422 buf[n++] = (char) sign;
423 if (e > 400) return 0;
424 if (e < 10) buf[n++] = '0';
425 if (e >= 100) buf[n++] = (char) (e / 100 + '0'), e -= 100 * (e / 100);
426 if (e >= 10) buf[n++] = (char) (e / 10 + '0'), e -= 10 * (e / 10);
427 buf[n++] = (char) (e + '0');
431 static int xisinf(double x) {
436 return ((unsigned) (ieee754.u >> 32) & 0x7fffffff) == 0x7ff00000 &&
437 ((unsigned) ieee754.u == 0);
440 static int xisnan(double x) {
445 return ((unsigned) (ieee754.u >> 32) & 0x7fffffff) +
446 ((unsigned) ieee754.u != 0) >
450 static size_t mg_dtoa(char *dst, size_t dstlen, double d, int width, bool tz) {
452 int i, s = 0, n = 0, e = 0;
453 double t, mul, saved;
454 if (d == 0.0) return mg_snprintf(dst, dstlen, "%s", "0");
455 if (xisinf(d)) return mg_snprintf(dst, dstlen, "%s", d > 0 ? "inf" : "-inf");
456 if (xisnan(d)) return mg_snprintf(dst, dstlen, "%s", "nan");
457 if (d < 0.0) d = -d, buf[s++] = '-';
462 while (d >= 10.0 && d / mul >= 10.0) mul *= 10.0;
463 while (d <= 1.0 && d / mul <= 1.0) mul /= 10.0;
464 for (i = 0, t = mul * 5; i < width; i++) t /= 10.0;
466 // Calculate exponent, and 'mul' for scientific representation
468 while (d >= 10.0 && d / mul >= 10.0) mul *= 10.0, e++;
469 while (d < 1.0 && d / mul < 1.0) mul /= 10.0, e--;
470 // printf(" --> %g %d %g %g\n", saved, e, t, mul);
472 if (e >= width && width > 1) {
473 n = (int) mg_dtoa(buf, sizeof(buf), saved / mul, width, tz);
474 // printf(" --> %.*g %d [%.*s]\n", 10, d / t, e, n, buf);
475 n += addexp(buf + s + n, e, '+');
476 return mg_snprintf(dst, dstlen, "%.*s", n, buf);
477 } else if (e <= -width && width > 1) {
478 n = (int) mg_dtoa(buf, sizeof(buf), saved / mul, width, tz);
479 // printf(" --> %.*g %d [%.*s]\n", 10, d / mul, e, n, buf);
480 n += addexp(buf + s + n, -e, '-');
481 return mg_snprintf(dst, dstlen, "%.*s", n, buf);
483 for (i = 0, t = mul; t >= 1.0 && s + n < (int) sizeof(buf); i++) {
484 int ch = (int) (d / t);
485 if (n > 0 || ch > 0) buf[s + n++] = (char) (ch + '0');
489 // printf(" --> [%g] -> %g %g (%d) [%.*s]\n", saved, d, t, n, s + n, buf);
490 if (n == 0) buf[s++] = '0';
491 while (t >= 1.0 && n + s < (int) sizeof(buf)) buf[n++] = '0', t /= 10.0;
492 if (s + n < (int) sizeof(buf)) buf[n + s++] = '.';
493 // printf(" 1--> [%g] -> [%.*s]\n", saved, s + n, buf);
494 for (i = 0, t = 0.1; s + n < (int) sizeof(buf) && n < width; i++) {
495 int ch = (int) (d / t);
496 buf[s + n++] = (char) (ch + '0');
501 while (tz && n > 0 && buf[s + n - 1] == '0') n--; // Trim trailing zeroes
502 if (n > 0 && buf[s + n - 1] == '.') n--; // Trim trailing dot
504 if (n >= (int) sizeof(buf)) n = (int) sizeof(buf) - 1;
506 return mg_snprintf(dst, dstlen, "%s", buf);
509 static size_t mg_lld(char *buf, int64_t val, bool is_signed, bool is_hex) {
510 const char *letters = "0123456789abcdef";
511 uint64_t v = (uint64_t) val;
513 if (is_signed && val < 0) buf[s++] = '-', v = (uint64_t) (-val);
514 // This loop prints a number in reverse order. I guess this is because we
515 // write numbers from right to left: least significant digit comes last.
516 // Maybe because we use Arabic numbers, and Arabs write RTL?
518 for (n = 0; v; v >>= 4) buf[s + n++] = letters[v & 15];
520 for (n = 0; v; v /= 10) buf[s + n++] = letters[v % 10];
523 for (i = 0; i < n / 2; i++) {
525 buf[s + i] = buf[s + n - i - 1], buf[s + n - i - 1] = t;
527 if (val == 0) buf[n++] = '0'; // Handle special case
531 static size_t scpy(void (*out)(char, void *), void *ptr, char *buf,
534 while (i < len && buf[i] != '\0') out(buf[i++], ptr);
538 size_t mg_xprintf(void (*out)(char, void *), void *ptr, const char *fmt, ...) {
542 len = mg_vxprintf(out, ptr, fmt, &ap);
547 size_t mg_vxprintf(void (*out)(char, void *), void *param, const char *fmt,
550 while (fmt[i] != '\0') {
552 size_t j, k, x = 0, is_long = 0, w = 0 /* width */, pr = ~0U /* prec */;
553 char pad = ' ', minus = 0, c = fmt[++i];
554 if (c == '#') x++, c = fmt[++i];
555 if (c == '-') minus++, c = fmt[++i];
556 if (c == '0') pad = '0', c = fmt[++i];
557 while (is_digit(c)) w *= 10, w += (size_t) (c - '0'), c = fmt[++i];
561 pr = (size_t) va_arg(*ap, int);
565 while (is_digit(c)) pr *= 10, pr += (size_t) (c - '0'), c = fmt[++i];
568 while (c == 'h') c = fmt[++i]; // Treat h and hh as int
570 is_long++, c = fmt[++i];
571 if (c == 'l') is_long++, c = fmt[++i];
573 if (c == 'p') x = 1, is_long = 1;
574 if (c == 'd' || c == 'u' || c == 'x' || c == 'X' || c == 'p' ||
575 c == 'g' || c == 'f') {
576 bool s = (c == 'd'), h = (c == 'x' || c == 'X' || c == 'p');
578 size_t xl = x ? 2 : 0;
579 if (c == 'g' || c == 'f') {
580 double v = va_arg(*ap, double);
581 if (pr == ~0U) pr = 6;
582 k = mg_dtoa(tmp, sizeof(tmp), v, (int) pr, c == 'g');
583 } else if (is_long == 2) {
584 int64_t v = va_arg(*ap, int64_t);
585 k = mg_lld(tmp, v, s, h);
586 } else if (is_long == 1) {
587 long v = va_arg(*ap, long);
588 k = mg_lld(tmp, s ? (int64_t) v : (int64_t) (unsigned long) v, s, h);
590 int v = va_arg(*ap, int);
591 k = mg_lld(tmp, s ? (int64_t) v : (int64_t) (unsigned) v, s, h);
593 for (j = 0; j < xl && w > 0; j++) w--;
594 for (j = 0; pad == ' ' && !minus && k < w && j + k < w; j++)
595 n += scpy(out, param, &pad, 1);
596 n += scpy(out, param, (char *) "0x", xl);
597 for (j = 0; pad == '0' && k < w && j + k < w; j++)
598 n += scpy(out, param, &pad, 1);
599 n += scpy(out, param, tmp, k);
600 for (j = 0; pad == ' ' && minus && k < w && j + k < w; j++)
601 n += scpy(out, param, &pad, 1);
602 } else if (c == 'm' || c == 'M') {
603 mg_pm_t f = va_arg(*ap, mg_pm_t);
604 if (c == 'm') out('"', param);
605 n += f(out, param, ap);
606 if (c == 'm') n += 2, out('"', param);
607 } else if (c == 'c') {
608 int ch = va_arg(*ap, int);
609 out((char) ch, param);
611 } else if (c == 's') {
612 char *p = va_arg(*ap, char *);
613 if (pr == ~0U) pr = p == NULL ? 0 : strlen(p);
614 for (j = 0; !minus && pr < w && j + pr < w; j++)
615 n += scpy(out, param, &pad, 1);
616 n += scpy(out, param, p, pr);
617 for (j = 0; minus && pr < w && j + pr < w; j++)
618 n += scpy(out, param, &pad, 1);
619 } else if (c == '%') {
629 out(fmt[i], param), n++, i++;
635 #ifdef MG_ENABLE_LINES
641 struct mg_fd *mg_fs_open(struct mg_fs *fs, const char *path, int flags) {
642 struct mg_fd *fd = (struct mg_fd *) calloc(1, sizeof(*fd));
644 fd->fd = fs->op(path, flags);
646 if (fd->fd == NULL) {
654 void mg_fs_close(struct mg_fd *fd) {
661 char *mg_file_read(struct mg_fs *fs, const char *path, size_t *sizep) {
665 fs->st(path, &size, NULL);
666 if ((fd = mg_fs_open(fs, path, MG_FS_READ)) != NULL) {
667 data = (char *) calloc(1, size + 1);
669 if (fs->rd(fd->fd, data, size) != size) {
674 if (sizep != NULL) *sizep = size;
682 bool mg_file_write(struct mg_fs *fs, const char *path, const void *buf,
686 char tmp[MG_PATH_MAX];
687 mg_snprintf(tmp, sizeof(tmp), "%s..%d", path, rand());
688 if ((fd = mg_fs_open(fs, tmp, MG_FS_WRITE)) != NULL) {
689 result = fs->wr(fd->fd, buf, len) == len;
701 bool mg_file_printf(struct mg_fs *fs, const char *path, const char *fmt, ...) {
706 data = mg_vmprintf(fmt, &ap);
708 result = mg_file_write(fs, path, data, strlen(data));
713 #ifdef MG_ENABLE_LINES
714 #line 1 "src/fs_fat.c"
722 static int mg_days_from_epoch(int y, int m, int d) {
725 int yoe = y - era * 400;
726 int doy = (153 * (m + (m > 2 ? -3 : 9)) + 2) / 5 + d - 1;
727 int doe = yoe * 365 + yoe / 4 - yoe / 100 + doy;
728 return era * 146097 + doe - 719468;
731 static time_t mg_timegm(const struct tm *t) {
732 int year = t->tm_year + 1900;
733 int month = t->tm_mon; // 0-11
737 } else if (month < 0) {
738 int years_diff = (11 - month) / 12;
740 month += 12 * years_diff;
742 int x = mg_days_from_epoch(year, month + 1, t->tm_mday);
743 return 60 * (60 * (24L * x + t->tm_hour) + t->tm_min) + t->tm_sec;
746 static time_t ff_time_to_epoch(uint16_t fdate, uint16_t ftime) {
748 memset(&tm, 0, sizeof(struct tm));
749 tm.tm_sec = (ftime << 1) & 0x3e;
750 tm.tm_min = ((ftime >> 5) & 0x3f);
751 tm.tm_hour = ((ftime >> 11) & 0x1f);
752 tm.tm_mday = (fdate & 0x1f);
753 tm.tm_mon = ((fdate >> 5) & 0x0f) - 1;
754 tm.tm_year = ((fdate >> 9) & 0x7f) + 80;
755 return mg_timegm(&tm);
758 static int ff_stat(const char *path, size_t *size, time_t *mtime) {
760 if (path[0] == '\0') {
762 if (mtime) *mtime = 0;
764 } else if (f_stat(path, &fi) == 0) {
765 if (size) *size = (size_t) fi.fsize;
766 if (mtime) *mtime = ff_time_to_epoch(fi.fdate, fi.ftime);
767 return MG_FS_READ | MG_FS_WRITE | ((fi.fattrib & AM_DIR) ? MG_FS_DIR : 0);
773 static void ff_list(const char *dir, void (*fn)(const char *, void *),
777 if (f_opendir(&d, dir) == FR_OK) {
778 while (f_readdir(&d, &fi) == FR_OK && fi.fname[0] != '\0') {
779 if (!strcmp(fi.fname, ".") || !strcmp(fi.fname, "..")) continue;
780 fn(fi.fname, userdata);
786 static void *ff_open(const char *path, int flags) {
788 unsigned char mode = FA_READ;
789 if (flags & MG_FS_WRITE) mode |= FA_WRITE | FA_OPEN_ALWAYS | FA_OPEN_APPEND;
790 if (f_open(&f, path, mode) == 0) {
792 if ((fp = calloc(1, sizeof(*fp))) != NULL) {
793 memcpy(fp, &f, sizeof(*fp));
800 static void ff_close(void *fp) {
807 static size_t ff_read(void *fp, void *buf, size_t len) {
808 UINT n = 0, misalign = ((size_t) buf) & 3;
811 f_read((FIL *) fp, aligned, len > misalign ? misalign : len, &n);
812 memcpy(buf, aligned, n);
814 f_read((FIL *) fp, buf, len, &n);
819 static size_t ff_write(void *fp, const void *buf, size_t len) {
821 return f_write((FIL *) fp, (char *) buf, len, &n) == FR_OK ? n : 0;
824 static size_t ff_seek(void *fp, size_t offset) {
825 f_lseek((FIL *) fp, offset);
829 static bool ff_rename(const char *from, const char *to) {
830 return f_rename(from, to) == FR_OK;
833 static bool ff_remove(const char *path) {
834 return f_unlink(path) == FR_OK;
837 static bool ff_mkdir(const char *path) {
838 return f_mkdir(path) == FR_OK;
841 struct mg_fs mg_fs_fat = {ff_stat, ff_list, ff_open, ff_close, ff_read,
842 ff_write, ff_seek, ff_rename, ff_remove, ff_mkdir};
845 #ifdef MG_ENABLE_LINES
846 #line 1 "src/fs_packed.c"
858 const char *mg_unpack(const char *path, size_t *size, time_t *mtime);
859 const char *mg_unlist(size_t no);
861 #if MG_ENABLE_PACKED_FS
863 const char *mg_unpack(const char *path, size_t *size, time_t *mtime) {
864 (void) path, (void) size, (void) mtime;
867 const char *mg_unlist(size_t no) {
873 static int is_dir_prefix(const char *prefix, size_t n, const char *path) {
874 // MG_INFO(("[%.*s] [%s] %c", (int) n, prefix, path, path[n]));
875 return n < strlen(path) && strncmp(prefix, path, n) == 0 &&
876 (n == 0 || path[n] == '/' || path[n - 1] == '/');
879 static int packed_stat(const char *path, size_t *size, time_t *mtime) {
881 size_t i, n = strlen(path);
882 if (mg_unpack(path, size, mtime)) return MG_FS_READ; // Regular file
883 // Scan all files. If `path` is a dir prefix for any of them, it's a dir
884 for (i = 0; (p = mg_unlist(i)) != NULL; i++) {
885 if (is_dir_prefix(path, n, p)) return MG_FS_DIR;
890 static void packed_list(const char *dir, void (*fn)(const char *, void *),
892 char buf[MG_PATH_MAX], tmp[sizeof(buf)];
893 const char *path, *begin, *end;
894 size_t i, n = strlen(dir);
895 tmp[0] = '\0'; // Previously listed entry
896 for (i = 0; (path = mg_unlist(i)) != NULL; i++) {
897 if (!is_dir_prefix(dir, n, path)) continue;
898 begin = &path[n + 1];
899 end = strchr(begin, '/');
900 if (end == NULL) end = begin + strlen(begin);
901 mg_snprintf(buf, sizeof(buf), "%.*s", (int) (end - begin), begin);
902 buf[sizeof(buf) - 1] = '\0';
903 // If this entry has been already listed, skip
904 // NOTE: we're assuming that file list is sorted alphabetically
905 if (strcmp(buf, tmp) == 0) continue;
906 fn(buf, userdata); // Not yet listed, call user function
907 strcpy(tmp, buf); // And save this entry as listed
911 static void *packed_open(const char *path, int flags) {
913 const char *data = mg_unpack(path, &size, NULL);
914 struct packed_file *fp = NULL;
915 if (data == NULL) return NULL;
916 if (flags & MG_FS_WRITE) return NULL;
917 if ((fp = (struct packed_file *) calloc(1, sizeof(*fp))) != NULL) {
924 static void packed_close(void *fp) {
925 if (fp != NULL) free(fp);
928 static size_t packed_read(void *fd, void *buf, size_t len) {
929 struct packed_file *fp = (struct packed_file *) fd;
930 if (fp->pos + len > fp->size) len = fp->size - fp->pos;
931 memcpy(buf, &fp->data[fp->pos], len);
936 static size_t packed_write(void *fd, const void *buf, size_t len) {
937 (void) fd, (void) buf, (void) len;
941 static size_t packed_seek(void *fd, size_t offset) {
942 struct packed_file *fp = (struct packed_file *) fd;
944 if (fp->pos > fp->size) fp->pos = fp->size;
948 static bool packed_rename(const char *from, const char *to) {
949 (void) from, (void) to;
953 static bool packed_remove(const char *path) {
958 static bool packed_mkdir(const char *path) {
963 struct mg_fs mg_fs_packed = {
964 packed_stat, packed_list, packed_open, packed_close, packed_read,
965 packed_write, packed_seek, packed_rename, packed_remove, packed_mkdir};
967 #ifdef MG_ENABLE_LINES
968 #line 1 "src/fs_posix.c"
974 #ifndef MG_STAT_STRUCT
975 #define MG_STAT_STRUCT stat
979 #define MG_STAT_FUNC stat
982 static int p_stat(const char *path, size_t *size, time_t *mtime) {
983 #if !defined(S_ISDIR)
984 MG_ERROR(("stat() API is not supported. %p %p %p", path, size, mtime));
987 #if MG_ARCH == MG_ARCH_WIN32
989 wchar_t tmp[MG_PATH_MAX];
990 MultiByteToWideChar(CP_UTF8, 0, path, -1, tmp, sizeof(tmp) / sizeof(tmp[0]));
991 if (_wstati64(tmp, &st) != 0) return 0;
992 // If path is a symlink, windows reports 0 in st.st_size.
993 // Get a real file size by opening it and jumping to the end
994 if (st.st_size == 0 && (st.st_mode & _S_IFREG)) {
995 FILE *fp = _wfopen(tmp, L"rb");
997 fseek(fp, 0, SEEK_END);
998 if (ftell(fp) > 0) st.st_size = ftell(fp); // Use _ftelli64 on win10+
1003 struct MG_STAT_STRUCT st;
1004 if (MG_STAT_FUNC(path, &st) != 0) return 0;
1006 if (size) *size = (size_t) st.st_size;
1007 if (mtime) *mtime = st.st_mtime;
1008 return MG_FS_READ | MG_FS_WRITE | (S_ISDIR(st.st_mode) ? MG_FS_DIR : 0);
1012 #if MG_ARCH == MG_ARCH_WIN32
1014 char d_name[MAX_PATH];
1017 typedef struct win32_dir {
1019 WIN32_FIND_DATAW info;
1020 struct dirent result;
1023 int gettimeofday(struct timeval *tv, void *tz) {
1025 unsigned __int64 tmpres = 0;
1028 GetSystemTimeAsFileTime(&ft);
1029 tmpres |= ft.dwHighDateTime;
1031 tmpres |= ft.dwLowDateTime;
1032 tmpres /= 10; // convert into microseconds
1033 tmpres -= (int64_t) 11644473600000000;
1034 tv->tv_sec = (long) (tmpres / 1000000UL);
1035 tv->tv_usec = (long) (tmpres % 1000000UL);
1041 static int to_wchar(const char *path, wchar_t *wbuf, size_t wbuf_len) {
1043 char buf[MAX_PATH * 2], buf2[MAX_PATH * 2], *p;
1044 strncpy(buf, path, sizeof(buf));
1045 buf[sizeof(buf) - 1] = '\0';
1046 // Trim trailing slashes. Leave backslash for paths like "X:\"
1047 p = buf + strlen(buf) - 1;
1048 while (p > buf && p[-1] != ':' && (p[0] == '\\' || p[0] == '/')) *p-- = '\0';
1049 memset(wbuf, 0, wbuf_len * sizeof(wchar_t));
1050 ret = MultiByteToWideChar(CP_UTF8, 0, buf, -1, wbuf, (int) wbuf_len);
1051 // Convert back to Unicode. If doubly-converted string does not match the
1052 // original, something is fishy, reject.
1053 WideCharToMultiByte(CP_UTF8, 0, wbuf, (int) wbuf_len, buf2, sizeof(buf2),
1055 if (strcmp(buf, buf2) != 0) {
1062 DIR *opendir(const char *name) {
1064 wchar_t wpath[MAX_PATH];
1068 SetLastError(ERROR_BAD_ARGUMENTS);
1069 } else if ((d = (DIR *) calloc(1, sizeof(*d))) == NULL) {
1070 SetLastError(ERROR_NOT_ENOUGH_MEMORY);
1072 to_wchar(name, wpath, sizeof(wpath) / sizeof(wpath[0]));
1073 attrs = GetFileAttributesW(wpath);
1074 if (attrs != 0Xffffffff && (attrs & FILE_ATTRIBUTE_DIRECTORY)) {
1075 (void) wcscat(wpath, L"\\*");
1076 d->handle = FindFirstFileW(wpath, &d->info);
1077 d->result.d_name[0] = '\0';
1086 int closedir(DIR *d) {
1089 if (d->handle != INVALID_HANDLE_VALUE)
1090 result = FindClose(d->handle) ? 0 : -1;
1094 SetLastError(ERROR_BAD_ARGUMENTS);
1099 struct dirent *readdir(DIR *d) {
1100 struct dirent *result = NULL;
1102 memset(&d->result, 0, sizeof(d->result));
1103 if (d->handle != INVALID_HANDLE_VALUE) {
1104 result = &d->result;
1105 WideCharToMultiByte(CP_UTF8, 0, d->info.cFileName, -1, result->d_name,
1106 sizeof(result->d_name), NULL, NULL);
1107 if (!FindNextFileW(d->handle, &d->info)) {
1108 FindClose(d->handle);
1109 d->handle = INVALID_HANDLE_VALUE;
1112 SetLastError(ERROR_FILE_NOT_FOUND);
1115 SetLastError(ERROR_BAD_ARGUMENTS);
1121 static void p_list(const char *dir, void (*fn)(const char *, void *),
1123 #if MG_ENABLE_DIRLIST
1126 if ((dirp = (opendir(dir))) == NULL) return;
1127 while ((dp = readdir(dirp)) != NULL) {
1128 if (!strcmp(dp->d_name, ".") || !strcmp(dp->d_name, "..")) continue;
1129 fn(dp->d_name, userdata);
1133 (void) dir, (void) fn, (void) userdata;
1137 static void *p_open(const char *path, int flags) {
1138 const char *mode = flags == MG_FS_READ ? "rb" : "a+b";
1139 #if MG_ARCH == MG_ARCH_WIN32
1140 wchar_t b1[MG_PATH_MAX], b2[10];
1141 MultiByteToWideChar(CP_UTF8, 0, path, -1, b1, sizeof(b1) / sizeof(b1[0]));
1142 MultiByteToWideChar(CP_UTF8, 0, mode, -1, b2, sizeof(b2) / sizeof(b2[0]));
1143 return (void *) _wfopen(b1, b2);
1145 return (void *) fopen(path, mode);
1149 static void p_close(void *fp) {
1150 fclose((FILE *) fp);
1153 static size_t p_read(void *fp, void *buf, size_t len) {
1154 return fread(buf, 1, len, (FILE *) fp);
1157 static size_t p_write(void *fp, const void *buf, size_t len) {
1158 return fwrite(buf, 1, len, (FILE *) fp);
1161 static size_t p_seek(void *fp, size_t offset) {
1162 #if (defined(_FILE_OFFSET_BITS) && _FILE_OFFSET_BITS == 64) || \
1163 (defined(_POSIX_C_SOURCE) && _POSIX_C_SOURCE >= 200112L) || \
1164 (defined(_XOPEN_SOURCE) && _XOPEN_SOURCE >= 600)
1165 if (fseeko((FILE *) fp, (off_t) offset, SEEK_SET) != 0) (void) 0;
1167 if (fseek((FILE *) fp, (long) offset, SEEK_SET) != 0) (void) 0;
1169 return (size_t) ftell((FILE *) fp);
1172 static bool p_rename(const char *from, const char *to) {
1173 return rename(from, to) == 0;
1176 static bool p_remove(const char *path) {
1177 return remove(path) == 0;
1180 static bool p_mkdir(const char *path) {
1181 return mkdir(path, 0775) == 0;
1186 static int p_stat(const char *path, size_t *size, time_t *mtime) {
1187 (void) path, (void) size, (void) mtime;
1190 static void p_list(const char *path, void (*fn)(const char *, void *),
1192 (void) path, (void) fn, (void) userdata;
1194 static void *p_open(const char *path, int flags) {
1195 (void) path, (void) flags;
1198 static void p_close(void *fp) {
1201 static size_t p_read(void *fd, void *buf, size_t len) {
1202 (void) fd, (void) buf, (void) len;
1205 static size_t p_write(void *fd, const void *buf, size_t len) {
1206 (void) fd, (void) buf, (void) len;
1209 static size_t p_seek(void *fd, size_t offset) {
1210 (void) fd, (void) offset;
1213 static bool p_rename(const char *from, const char *to) {
1214 (void) from, (void) to;
1217 static bool p_remove(const char *path) {
1221 static bool p_mkdir(const char *path) {
1227 struct mg_fs mg_fs_posix = {p_stat, p_list, p_open, p_close, p_read,
1228 p_write, p_seek, p_rename, p_remove, p_mkdir};
1230 #ifdef MG_ENABLE_LINES
1231 #line 1 "src/http.c"
1246 bool mg_to_size_t(struct mg_str str, size_t *val);
1247 bool mg_to_size_t(struct mg_str str, size_t *val) {
1248 uint64_t result = 0, max = 1844674407370955160 /* (UINT64_MAX-9)/10 */;
1250 while (i < str.len && (str.ptr[i] == ' ' || str.ptr[i] == '\t')) i++;
1251 if (i < str.len && str.ptr[i] == '-') return false;
1252 while (i < str.len && str.ptr[i] >= '0' && str.ptr[i] <= '9') {
1253 if (result > max) return false;
1255 result += (unsigned) (str.ptr[i] - '0');
1258 *val = (size_t) result;
1262 // Chunk deletion marker is the MSB in the "processed" counter
1263 #define MG_DMARK ((size_t) 1 << (sizeof(size_t) * 8 - 1))
1265 // Multipart POST example:
1267 // Content-Disposition: form-data; name="val"
1271 // Content-Disposition: form-data; name="foo"; filename="a.txt"
1272 // Content-Type: text/plain
1277 size_t mg_http_next_multipart(struct mg_str body, size_t ofs,
1278 struct mg_http_part *part) {
1279 struct mg_str cd = mg_str_n("Content-Disposition", 19);
1280 const char *s = body.ptr;
1281 size_t b = ofs, h1, h2, b1, b2, max = body.len;
1284 if (part != NULL) part->name = part->filename = part->body = mg_str_n(0, 0);
1287 while (b + 2 < max && s[b] != '\r' && s[b + 1] != '\n') b++;
1288 if (b <= ofs || b + 2 >= max) return 0;
1289 // MG_INFO(("B: %zu %zu [%.*s]", ofs, b - ofs, (int) (b - ofs), s));
1294 while (h2 + 2 < max && s[h2] != '\r' && s[h2 + 1] != '\n') h2++;
1295 if (h2 == h1) break;
1296 if (h2 + 2 >= max) return 0;
1297 // MG_INFO(("Header: [%.*s]", (int) (h2 - h1), &s[h1]));
1298 if (part != NULL && h1 + cd.len + 2 < h2 && s[h1 + cd.len] == ':' &&
1299 mg_ncasecmp(&s[h1], cd.ptr, cd.len) == 0) {
1300 struct mg_str v = mg_str_n(&s[h1 + cd.len + 2], h2 - (h1 + cd.len + 2));
1301 part->name = mg_http_get_header_var(v, mg_str_n("name", 4));
1302 part->filename = mg_http_get_header_var(v, mg_str_n("filename", 8));
1307 while (b2 + 2 + (b - ofs) + 2 < max && !(s[b2] == '\r' && s[b2 + 1] == '\n' &&
1308 memcmp(&s[b2 + 2], s, b - ofs) == 0))
1311 if (b2 + 2 >= max) return 0;
1312 if (part != NULL) part->body = mg_str_n(&s[b1], b2 - b1);
1313 // MG_INFO(("Body: [%.*s]", (int) (b2 - b1), &s[b1]));
1317 void mg_http_bauth(struct mg_connection *c, const char *user,
1319 struct mg_str u = mg_str(user), p = mg_str(pass);
1320 size_t need = c->send.len + 36 + (u.len + p.len) * 2;
1321 if (c->send.size < need) mg_iobuf_resize(&c->send, need);
1322 if (c->send.size >= need) {
1324 char *buf = (char *) &c->send.buf[c->send.len];
1325 memcpy(buf, "Authorization: Basic ", 21); // DON'T use mg_send!
1326 for (i = 0; i < (int) u.len; i++) {
1327 n = mg_base64_update(((unsigned char *) u.ptr)[i], buf + 21, n);
1330 n = mg_base64_update(':', buf + 21, n);
1331 for (i = 0; i < (int) p.len; i++) {
1332 n = mg_base64_update(((unsigned char *) p.ptr)[i], buf + 21, n);
1335 n = mg_base64_final(buf + 21, n);
1336 c->send.len += 21 + (size_t) n + 2;
1337 memcpy(&c->send.buf[c->send.len - 2], "\r\n", 2);
1339 MG_ERROR(("%lu oom %d->%d ", c->id, (int) c->send.size, (int) need));
1343 struct mg_str mg_http_var(struct mg_str buf, struct mg_str name) {
1344 struct mg_str k, v, result = mg_str_n(NULL, 0);
1345 while (mg_split(&buf, &k, &v, '&')) {
1346 if (name.len == k.len && mg_ncasecmp(name.ptr, k.ptr, k.len) == 0) {
1354 int mg_http_get_var(const struct mg_str *buf, const char *name, char *dst,
1357 if (dst == NULL || dst_len == 0) {
1358 len = -2; // Bad destination
1359 } else if (buf->ptr == NULL || name == NULL || buf->len == 0) {
1360 len = -1; // Bad source
1363 struct mg_str v = mg_http_var(*buf, mg_str(name));
1364 if (v.ptr == NULL) {
1365 len = -4; // Name does not exist
1367 len = mg_url_decode(v.ptr, v.len, dst, dst_len, 1);
1368 if (len < 0) len = -3; // Failed to decode
1374 static bool isx(int c) {
1375 return (c >= '0' && c <= '9') || (c >= 'a' && c <= 'f') ||
1376 (c >= 'A' && c <= 'F');
1379 int mg_url_decode(const char *src, size_t src_len, char *dst, size_t dst_len,
1380 int is_form_url_encoded) {
1382 for (i = j = 0; i < src_len && j + 1 < dst_len; i++, j++) {
1383 if (src[i] == '%') {
1384 // Use `i + 2 < src_len`, not `i < src_len - 2`, note small src_len
1385 if (i + 2 < src_len && isx(src[i + 1]) && isx(src[i + 2])) {
1386 mg_unhex(src + i + 1, 2, (uint8_t *) &dst[j]);
1391 } else if (is_form_url_encoded && src[i] == '+') {
1397 if (j < dst_len) dst[j] = '\0'; // Null-terminate the destination
1398 return i >= src_len && j < dst_len ? (int) j : -1;
1401 static bool isok(uint8_t c) {
1402 return c == '\n' || c == '\r' || c >= ' ';
1405 int mg_http_get_request_len(const unsigned char *buf, size_t buf_len) {
1407 for (i = 0; i < buf_len; i++) {
1408 if (!isok(buf[i])) return -1;
1409 if ((i > 0 && buf[i] == '\n' && buf[i - 1] == '\n') ||
1410 (i > 3 && buf[i] == '\n' && buf[i - 1] == '\r' && buf[i - 2] == '\n'))
1416 static const char *skip(const char *s, const char *e, const char *d,
1419 while (s < e && *s != '\n' && strchr(d, *s) == NULL) s++;
1420 v->len = (size_t) (s - v->ptr);
1421 while (s < e && strchr(d, *s) != NULL) s++;
1425 struct mg_str *mg_http_get_header(struct mg_http_message *h, const char *name) {
1426 size_t i, n = strlen(name), max = sizeof(h->headers) / sizeof(h->headers[0]);
1427 for (i = 0; i < max && h->headers[i].name.len > 0; i++) {
1428 struct mg_str *k = &h->headers[i].name, *v = &h->headers[i].value;
1429 if (n == k->len && mg_ncasecmp(k->ptr, name, n) == 0) return v;
1434 static void mg_http_parse_headers(const char *s, const char *end,
1435 struct mg_http_header *h, int max_headers) {
1437 for (i = 0; i < max_headers; i++) {
1438 struct mg_str k, v, tmp;
1439 const char *he = skip(s, end, "\n", &tmp);
1440 s = skip(s, he, ": \r\n", &k);
1441 s = skip(s, he, "\r\n", &v);
1442 if (k.len == tmp.len) continue;
1443 while (v.len > 0 && v.ptr[v.len - 1] == ' ') v.len--; // Trim spaces
1444 if (k.len == 0) break;
1445 // MG_INFO(("--HH [%.*s] [%.*s] [%.*s]", (int) tmp.len - 1, tmp.ptr,
1446 //(int) k.len, k.ptr, (int) v.len, v.ptr));
1452 int mg_http_parse(const char *s, size_t len, struct mg_http_message *hm) {
1453 int is_response, req_len = mg_http_get_request_len((unsigned char *) s, len);
1454 const char *end = s == NULL ? NULL : s + req_len, *qs; // Cannot add to NULL
1457 memset(hm, 0, sizeof(*hm));
1458 if (req_len <= 0) return req_len;
1460 hm->message.ptr = hm->head.ptr = s;
1462 hm->head.len = (size_t) req_len;
1463 hm->chunk.ptr = end;
1464 hm->message.len = hm->body.len = (size_t) ~0; // Set body length to infinite
1466 // Parse request line
1467 s = skip(s, end, " ", &hm->method);
1468 s = skip(s, end, " ", &hm->uri);
1469 s = skip(s, end, "\r\n", &hm->proto);
1471 // Sanity check. Allow protocol/reason to be empty
1472 if (hm->method.len == 0 || hm->uri.len == 0) return -1;
1474 // If URI contains '?' character, setup query string
1475 if ((qs = (const char *) memchr(hm->uri.ptr, '?', hm->uri.len)) != NULL) {
1476 hm->query.ptr = qs + 1;
1477 hm->query.len = (size_t) (&hm->uri.ptr[hm->uri.len] - (qs + 1));
1478 hm->uri.len = (size_t) (qs - hm->uri.ptr);
1481 mg_http_parse_headers(s, end, hm->headers,
1482 sizeof(hm->headers) / sizeof(hm->headers[0]));
1483 if ((cl = mg_http_get_header(hm, "Content-Length")) != NULL) {
1484 if (mg_to_size_t(*cl, &hm->body.len) == false) return -1;
1485 hm->message.len = (size_t) req_len + hm->body.len;
1488 // mg_http_parse() is used to parse both HTTP requests and HTTP
1489 // responses. If HTTP response does not have Content-Length set, then
1490 // body is read until socket is closed, i.e. body.len is infinite (~0).
1492 // For HTTP requests though, according to
1493 // http://tools.ietf.org/html/rfc7231#section-8.1.3,
1494 // only POST and PUT methods have defined body semantics.
1495 // Therefore, if Content-Length is not specified and methods are
1496 // not one of PUT or POST, set body length to 0.
1498 // So, if it is HTTP request, and Content-Length is not set,
1499 // and method is not (PUT or POST) then reset body length to zero.
1500 is_response = mg_ncasecmp(hm->method.ptr, "HTTP/", 5) == 0;
1501 if (hm->body.len == (size_t) ~0 && !is_response &&
1502 mg_vcasecmp(&hm->method, "PUT") != 0 &&
1503 mg_vcasecmp(&hm->method, "POST") != 0) {
1505 hm->message.len = (size_t) req_len;
1508 // The 204 (No content) responses also have 0 body length
1509 if (hm->body.len == (size_t) ~0 && is_response &&
1510 mg_vcasecmp(&hm->uri, "204") == 0) {
1512 hm->message.len = (size_t) req_len;
1518 static void mg_http_vprintf_chunk(struct mg_connection *c, const char *fmt,
1520 size_t len = c->send.len;
1521 mg_send(c, " \r\n", 10);
1522 mg_vxprintf(mg_pfn_iobuf, &c->send, fmt, ap);
1523 if (c->send.len >= len + 10) {
1524 mg_snprintf((char *) c->send.buf + len, 9, "%08lx", c->send.len - len - 10);
1525 c->send.buf[len + 8] = '\r';
1526 if (c->send.len == len + 10) c->is_resp = 0; // Last chunk, reset marker
1528 mg_send(c, "\r\n", 2);
1531 void mg_http_printf_chunk(struct mg_connection *c, const char *fmt, ...) {
1534 mg_http_vprintf_chunk(c, fmt, &ap);
1538 void mg_http_write_chunk(struct mg_connection *c, const char *buf, size_t len) {
1539 mg_printf(c, "%lx\r\n", (unsigned long) len);
1540 mg_send(c, buf, len);
1541 mg_send(c, "\r\n", 2);
1542 if (len == 0) c->is_resp = 0;
1546 static const char *mg_http_status_code_str(int status_code) {
1547 switch (status_code) {
1548 case 100: return "Continue";
1549 case 201: return "Created";
1550 case 202: return "Accepted";
1551 case 204: return "No Content";
1552 case 206: return "Partial Content";
1553 case 301: return "Moved Permanently";
1554 case 302: return "Found";
1555 case 304: return "Not Modified";
1556 case 400: return "Bad Request";
1557 case 401: return "Unauthorized";
1558 case 403: return "Forbidden";
1559 case 404: return "Not Found";
1560 case 418: return "I'm a teapot";
1561 case 500: return "Internal Server Error";
1562 case 501: return "Not Implemented";
1563 default: return "OK";
1568 void mg_http_reply(struct mg_connection *c, int code, const char *headers,
1569 const char *fmt, ...) {
1572 mg_printf(c, "HTTP/1.1 %d %s\r\n%sContent-Length: \r\n\r\n", code,
1573 mg_http_status_code_str(code), headers == NULL ? "" : headers);
1576 mg_vxprintf(mg_pfn_iobuf, &c->send, fmt, &ap);
1578 if (c->send.len > 16) {
1579 size_t n = mg_snprintf((char *) &c->send.buf[len - 15], 11, "%-10lu",
1580 (unsigned long) (c->send.len - len));
1581 c->send.buf[len - 15 + n] = ' '; // Change ending 0 to space
1586 static void http_cb(struct mg_connection *, int, void *, void *);
1587 static void restore_http_cb(struct mg_connection *c) {
1588 mg_fs_close((struct mg_fd *) c->pfn_data);
1594 char *mg_http_etag(char *buf, size_t len, size_t size, time_t mtime);
1595 char *mg_http_etag(char *buf, size_t len, size_t size, time_t mtime) {
1596 mg_snprintf(buf, len, "\"%lld.%lld\"", (int64_t) mtime, (int64_t) size);
1600 static void static_cb(struct mg_connection *c, int ev, void *ev_data,
1602 if (ev == MG_EV_WRITE || ev == MG_EV_POLL) {
1603 struct mg_fd *fd = (struct mg_fd *) fn_data;
1604 // Read to send IO buffer directly, avoid extra on-stack buffer
1605 size_t n, max = MG_IO_SIZE, space;
1606 size_t *cl = (size_t *) &c->data[(sizeof(c->data) - sizeof(size_t)) /
1607 sizeof(size_t) * sizeof(size_t)];
1608 if (c->send.size < max) mg_iobuf_resize(&c->send, max);
1609 if (c->send.len >= c->send.size) return; // Rate limit
1610 if ((space = c->send.size - c->send.len) > *cl) space = *cl;
1611 n = fd->fs->rd(fd->fd, c->send.buf + c->send.len, space);
1614 if (n == 0) restore_http_cb(c);
1615 } else if (ev == MG_EV_CLOSE) {
1621 // Known mime types. Keep it outside guess_content_type() function, since
1622 // some environments don't like it defined there.
1624 static struct mg_str s_known_types[] = {
1625 MG_C_STR("html"), MG_C_STR("text/html; charset=utf-8"),
1626 MG_C_STR("htm"), MG_C_STR("text/html; charset=utf-8"),
1627 MG_C_STR("css"), MG_C_STR("text/css; charset=utf-8"),
1628 MG_C_STR("js"), MG_C_STR("text/javascript; charset=utf-8"),
1629 MG_C_STR("gif"), MG_C_STR("image/gif"),
1630 MG_C_STR("png"), MG_C_STR("image/png"),
1631 MG_C_STR("jpg"), MG_C_STR("image/jpeg"),
1632 MG_C_STR("jpeg"), MG_C_STR("image/jpeg"),
1633 MG_C_STR("woff"), MG_C_STR("font/woff"),
1634 MG_C_STR("ttf"), MG_C_STR("font/ttf"),
1635 MG_C_STR("svg"), MG_C_STR("image/svg+xml"),
1636 MG_C_STR("txt"), MG_C_STR("text/plain; charset=utf-8"),
1637 MG_C_STR("avi"), MG_C_STR("video/x-msvideo"),
1638 MG_C_STR("csv"), MG_C_STR("text/csv"),
1639 MG_C_STR("doc"), MG_C_STR("application/msword"),
1640 MG_C_STR("exe"), MG_C_STR("application/octet-stream"),
1641 MG_C_STR("gz"), MG_C_STR("application/gzip"),
1642 MG_C_STR("ico"), MG_C_STR("image/x-icon"),
1643 MG_C_STR("json"), MG_C_STR("application/json"),
1644 MG_C_STR("mov"), MG_C_STR("video/quicktime"),
1645 MG_C_STR("mp3"), MG_C_STR("audio/mpeg"),
1646 MG_C_STR("mp4"), MG_C_STR("video/mp4"),
1647 MG_C_STR("mpeg"), MG_C_STR("video/mpeg"),
1648 MG_C_STR("pdf"), MG_C_STR("application/pdf"),
1649 MG_C_STR("shtml"), MG_C_STR("text/html; charset=utf-8"),
1650 MG_C_STR("tgz"), MG_C_STR("application/tar-gz"),
1651 MG_C_STR("wav"), MG_C_STR("audio/wav"),
1652 MG_C_STR("webp"), MG_C_STR("image/webp"),
1653 MG_C_STR("zip"), MG_C_STR("application/zip"),
1654 MG_C_STR("3gp"), MG_C_STR("video/3gpp"),
1659 static struct mg_str guess_content_type(struct mg_str path, const char *extra) {
1660 struct mg_str k, v, s = mg_str(extra);
1663 // Shrink path to its extension only
1664 while (i < path.len && path.ptr[path.len - i - 1] != '.') i++;
1665 path.ptr += path.len - i;
1668 // Process user-provided mime type overrides, if any
1669 while (mg_commalist(&s, &k, &v)) {
1670 if (mg_strcmp(path, k) == 0) return v;
1673 // Process built-in mime types
1674 for (i = 0; s_known_types[i].ptr != NULL; i += 2) {
1675 if (mg_strcmp(path, s_known_types[i]) == 0) return s_known_types[i + 1];
1678 return mg_str("text/plain; charset=utf-8");
1681 static int getrange(struct mg_str *s, size_t *a, size_t *b) {
1682 size_t i, numparsed = 0;
1683 // MG_INFO(("%.*s", (int) s->len, s->ptr));
1684 for (i = 0; i + 6 < s->len; i++) {
1685 if (memcmp(&s->ptr[i], "bytes=", 6) == 0) {
1686 struct mg_str p = mg_str_n(s->ptr + i + 6, s->len - i - 6);
1687 if (p.len > 0 && p.ptr[0] >= '0' && p.ptr[0] <= '9') numparsed++;
1688 if (!mg_to_size_t(p, a)) return 0;
1689 // MG_INFO(("PPP [%.*s] %d", (int) p.len, p.ptr, numparsed));
1690 while (p.len && p.ptr[0] >= '0' && p.ptr[0] <= '9') p.ptr++, p.len--;
1691 if (p.len && p.ptr[0] == '-') p.ptr++, p.len--;
1692 if (!mg_to_size_t(p, b)) return 0;
1693 if (p.len > 0 && p.ptr[0] >= '0' && p.ptr[0] <= '9') numparsed++;
1694 // MG_INFO(("PPP [%.*s] %d", (int) p.len, p.ptr, numparsed));
1698 return (int) numparsed;
1701 void mg_http_serve_file(struct mg_connection *c, struct mg_http_message *hm,
1703 const struct mg_http_serve_opts *opts) {
1704 char etag[64], tmp[MG_PATH_MAX];
1705 struct mg_fs *fs = opts->fs == NULL ? &mg_fs_posix : opts->fs;
1706 struct mg_fd *fd = NULL;
1709 struct mg_str *inm = NULL;
1710 struct mg_str mime = guess_content_type(mg_str(path), opts->mime_types);
1714 // If a browser sends us "Accept-Encoding: gzip", try to open .gz first
1715 struct mg_str *ae = mg_http_get_header(hm, "Accept-Encoding");
1716 if (ae != NULL && mg_strstr(*ae, mg_str("gzip")) != NULL) {
1717 mg_snprintf(tmp, sizeof(tmp), "%s.gz", path);
1718 fd = mg_fs_open(fs, tmp, MG_FS_READ);
1719 if (fd != NULL) gzip = true, path = tmp;
1721 // No luck opening .gz? Open what we've told to open
1722 if (fd == NULL) fd = mg_fs_open(fs, path, MG_FS_READ);
1725 // Failed to open, and page404 is configured? Open it, then
1726 if (fd == NULL && opts->page404 != NULL) {
1727 fd = mg_fs_open(fs, opts->page404, MG_FS_READ);
1728 mime = guess_content_type(mg_str(path), opts->mime_types);
1729 path = opts->page404;
1732 if (fd == NULL || fs->st(path, &size, &mtime) == 0) {
1733 mg_http_reply(c, 404, opts->extra_headers, "Not found\n");
1735 // NOTE: mg_http_etag() call should go first!
1736 } else if (mg_http_etag(etag, sizeof(etag), size, mtime) != NULL &&
1737 (inm = mg_http_get_header(hm, "If-None-Match")) != NULL &&
1738 mg_vcasecmp(inm, etag) == 0) {
1740 mg_http_reply(c, 304, opts->extra_headers, "");
1742 int n, status = 200;
1744 size_t r1 = 0, r2 = 0, cl = size;
1746 // Handle Range header
1747 struct mg_str *rh = mg_http_get_header(hm, "Range");
1749 if (rh != NULL && (n = getrange(rh, &r1, &r2)) > 0) {
1750 // If range is specified like "400-", set second limit to content len
1751 if (n == 1) r2 = cl - 1;
1752 if (r1 > r2 || r2 >= cl) {
1755 mg_snprintf(range, sizeof(range), "Content-Range: bytes */%lld\r\n",
1760 mg_snprintf(range, sizeof(range),
1761 "Content-Range: bytes %llu-%llu/%llu\r\n", (uint64_t) r1,
1762 (uint64_t) (r1 + cl - 1), (uint64_t) size);
1767 "HTTP/1.1 %d %s\r\n"
1768 "Content-Type: %.*s\r\n"
1770 "Content-Length: %llu\r\n"
1772 status, mg_http_status_code_str(status), (int) mime.len, mime.ptr,
1773 etag, (uint64_t) cl, gzip ? "Content-Encoding: gzip\r\n" : "",
1774 range, opts->extra_headers ? opts->extra_headers : "");
1775 if (mg_vcasecmp(&hm->method, "HEAD") == 0) {
1780 // Track to-be-sent content length at the end of c->data, aligned
1781 size_t *clp = (size_t *) &c->data[(sizeof(c->data) - sizeof(size_t)) /
1782 sizeof(size_t) * sizeof(size_t)];
1790 struct printdirentrydata {
1791 struct mg_connection *c;
1792 struct mg_http_message *hm;
1793 const struct mg_http_serve_opts *opts;
1797 static void printdirentry(const char *name, void *userdata) {
1798 struct printdirentrydata *d = (struct printdirentrydata *) userdata;
1799 struct mg_fs *fs = d->opts->fs == NULL ? &mg_fs_posix : d->opts->fs;
1802 char path[MG_PATH_MAX], sz[40], mod[40];
1805 // MG_DEBUG(("[%s] [%s]", d->dir, name));
1806 if (mg_snprintf(path, sizeof(path), "%s%c%s", d->dir, '/', name) >
1808 MG_ERROR(("%s truncated", name));
1809 } else if ((flags = fs->st(path, &size, &t)) == 0) {
1810 MG_ERROR(("%lu stat(%s): %d", d->c->id, path, errno));
1812 const char *slash = flags & MG_FS_DIR ? "/" : "";
1813 if (flags & MG_FS_DIR) {
1814 mg_snprintf(sz, sizeof(sz), "%s", "[DIR]");
1816 mg_snprintf(sz, sizeof(sz), "%lld", (uint64_t) size);
1818 #if defined(MG_HTTP_DIRLIST_TIME_FMT)
1821 struct tm *time_info = localtime(&t);
1822 strftime(time_str, sizeof time_str, "%Y/%m/%d %H:%M:%S", time_info);
1823 mg_snprintf(mod, sizeof(mod), "%s", time_str);
1826 mg_snprintf(mod, sizeof(mod), "%lu", (unsigned long) t);
1828 n = (int) mg_url_encode(name, strlen(name), path, sizeof(path));
1830 " <tr><td><a href=\"%.*s%s\">%s%s</a></td>"
1831 "<td name=%lu>%s</td><td name=%lld>%s</td></tr>\n",
1832 n, path, slash, name, slash, (unsigned long) t, mod,
1833 flags & MG_FS_DIR ? (int64_t) -1 : (int64_t) size, sz);
1837 static void listdir(struct mg_connection *c, struct mg_http_message *hm,
1838 const struct mg_http_serve_opts *opts, char *dir) {
1839 const char *sort_js_code =
1840 "<script>function srt(tb, sc, so, d) {"
1841 "var tr = Array.prototype.slice.call(tb.rows, 0),"
1842 "tr = tr.sort(function (a, b) { var c1 = a.cells[sc], c2 = b.cells[sc],"
1843 "n1 = c1.getAttribute('name'), n2 = c2.getAttribute('name'), "
1844 "t1 = a.cells[2].getAttribute('name'), "
1845 "t2 = b.cells[2].getAttribute('name'); "
1846 "return so * (t1 < 0 && t2 >= 0 ? -1 : t2 < 0 && t1 >= 0 ? 1 : "
1847 "n1 ? parseInt(n2) - parseInt(n1) : "
1848 "c1.textContent.trim().localeCompare(c2.textContent.trim())); });";
1849 const char *sort_js_code2 =
1850 "for (var i = 0; i < tr.length; i++) tb.appendChild(tr[i]); "
1851 "if (!d) window.location.hash = ('sc=' + sc + '&so=' + so); "
1853 "window.onload = function() {"
1854 "var tb = document.getElementById('tb');"
1855 "var m = /sc=([012]).so=(1|-1)/.exec(window.location.hash) || [0, 2, 1];"
1856 "var sc = m[1], so = m[2]; document.onclick = function(ev) { "
1857 "var c = ev.target.rel; if (c) {if (c == sc) so *= -1; srt(tb, c, so); "
1858 "sc = c; ev.preventDefault();}};"
1859 "srt(tb, sc, so, true);"
1862 struct mg_fs *fs = opts->fs == NULL ? &mg_fs_posix : opts->fs;
1863 struct printdirentrydata d = {c, hm, opts, dir};
1864 char tmp[10], buf[MG_PATH_MAX];
1866 int len = mg_url_decode(hm->uri.ptr, hm->uri.len, buf, sizeof(buf), 0);
1867 struct mg_str uri = len > 0 ? mg_str_n(buf, (size_t) len) : hm->uri;
1870 "HTTP/1.1 200 OK\r\n"
1871 "Content-Type: text/html; charset=utf-8\r\n"
1873 "Content-Length: \r\n\r\n",
1874 opts->extra_headers == NULL ? "" : opts->extra_headers);
1875 off = c->send.len; // Start of body
1877 "<!DOCTYPE html><html><head><title>Index of %.*s</title>%s%s"
1878 "<style>th,td {text-align: left; padding-right: 1em; "
1879 "font-family: monospace; }</style></head>"
1880 "<body><h1>Index of %.*s</h1><table cellpadding=\"0\"><thead>"
1881 "<tr><th><a href=\"#\" rel=\"0\">Name</a></th><th>"
1882 "<a href=\"#\" rel=\"1\">Modified</a></th>"
1883 "<th><a href=\"#\" rel=\"2\">Size</a></th></tr>"
1884 "<tr><td colspan=\"3\"><hr></td></tr>"
1886 "<tbody id=\"tb\">\n",
1887 (int) uri.len, uri.ptr, sort_js_code, sort_js_code2, (int) uri.len,
1890 " <tr><td><a href=\"..\">..</a></td>"
1891 "<td name=-1></td><td name=-1>[DIR]</td></tr>\n");
1893 fs->ls(dir, printdirentry, &d);
1895 "</tbody><tfoot><tr><td colspan=\"3\"><hr></td></tr></tfoot>"
1896 "</table><address>Mongoose v.%s</address></body></html>\n",
1898 n = mg_snprintf(tmp, sizeof(tmp), "%lu", (unsigned long) (c->send.len - off));
1899 if (n > sizeof(tmp)) n = 0;
1900 memcpy(c->send.buf + off - 12, tmp, n); // Set content length
1901 c->is_resp = 0; // Mark response end
1904 // Resolve requested file into `path` and return its fs->st() result
1905 static int uri_to_path2(struct mg_connection *c, struct mg_http_message *hm,
1906 struct mg_fs *fs, struct mg_str url, struct mg_str dir,
1907 char *path, size_t path_size) {
1909 // Append URI to the root_dir, and sanitize it
1910 size_t n = mg_snprintf(path, path_size, "%.*s", (int) dir.len, dir.ptr);
1911 if (n > path_size) n = path_size;
1912 path[path_size - 1] = '\0';
1913 if (n + 2 < path_size) path[n++] = '/', path[n] = '\0';
1914 mg_url_decode(hm->uri.ptr + url.len, hm->uri.len - url.len, path + n,
1916 path[path_size - 1] = '\0'; // Double-check
1917 mg_remove_double_dots(path);
1919 while (n > 1 && path[n - 1] == '/') path[--n] = 0; // Trim trailing slashes
1920 flags = mg_vcmp(&hm->uri, "/") == 0 ? MG_FS_DIR : fs->st(path, NULL, NULL);
1921 MG_VERBOSE(("%lu %.*s -> %s %d", c->id, (int) hm->uri.len, hm->uri.ptr, path,
1924 // Do nothing - let's caller decide
1925 } else if ((flags & MG_FS_DIR) && hm->uri.len > 0 &&
1926 hm->uri.ptr[hm->uri.len - 1] != '/') {
1928 "HTTP/1.1 301 Moved\r\n"
1929 "Location: %.*s/\r\n"
1930 "Content-Length: 0\r\n"
1932 (int) hm->uri.len, hm->uri.ptr);
1935 } else if (flags & MG_FS_DIR) {
1936 if (((mg_snprintf(path + n, path_size - n, "/" MG_HTTP_INDEX) > 0 &&
1937 (tmp = fs->st(path, NULL, NULL)) != 0) ||
1938 (mg_snprintf(path + n, path_size - n, "/index.shtml") > 0 &&
1939 (tmp = fs->st(path, NULL, NULL)) != 0))) {
1941 } else if ((mg_snprintf(path + n, path_size - n, "/" MG_HTTP_INDEX ".gz") >
1943 (tmp = fs->st(path, NULL, NULL)) !=
1944 0)) { // check for gzipped index
1946 path[n + 1 + strlen(MG_HTTP_INDEX)] =
1947 '\0'; // Remove appended .gz in index file name
1949 path[n] = '\0'; // Remove appended index file name
1955 static int uri_to_path(struct mg_connection *c, struct mg_http_message *hm,
1956 const struct mg_http_serve_opts *opts, char *path,
1958 struct mg_fs *fs = opts->fs == NULL ? &mg_fs_posix : opts->fs;
1959 struct mg_str k, v, s = mg_str(opts->root_dir), u = {0, 0}, p = {0, 0};
1960 while (mg_commalist(&s, &k, &v)) {
1961 if (v.len == 0) v = k, k = mg_str("/");
1962 if (hm->uri.len < k.len) continue;
1963 if (mg_strcmp(k, mg_str_n(hm->uri.ptr, k.len)) != 0) continue;
1966 return uri_to_path2(c, hm, fs, u, p, path, path_size);
1969 void mg_http_serve_dir(struct mg_connection *c, struct mg_http_message *hm,
1970 const struct mg_http_serve_opts *opts) {
1971 char path[MG_PATH_MAX];
1972 const char *sp = opts->ssi_pattern;
1973 int flags = uri_to_path(c, hm, opts, path, sizeof(path));
1975 // Do nothing: the response has already been sent by uri_to_path()
1976 } else if (flags & MG_FS_DIR) {
1977 listdir(c, hm, opts, path);
1978 } else if (flags && sp != NULL &&
1979 mg_globmatch(sp, strlen(sp), path, strlen(path))) {
1980 mg_http_serve_ssi(c, opts->root_dir, path);
1982 mg_http_serve_file(c, hm, path, opts);
1986 static bool mg_is_url_safe(int c) {
1987 return (c >= '0' && c <= '9') || (c >= 'a' && c <= 'z') ||
1988 (c >= 'A' && c <= 'Z') || c == '.' || c == '_' || c == '-' || c == '~';
1991 size_t mg_url_encode(const char *s, size_t sl, char *buf, size_t len) {
1993 for (i = 0; i < sl; i++) {
1994 int c = *(unsigned char *) &s[i];
1995 if (n + 4 >= len) return 0;
1996 if (mg_is_url_safe(c)) {
2000 mg_hex(&s[i], 1, &buf[n]);
2004 if (len > 0 && n < len - 1) buf[n] = '\0'; // Null-terminate the destination
2005 if (len > 0) buf[len - 1] = '\0'; // Always.
2009 void mg_http_creds(struct mg_http_message *hm, char *user, size_t userlen,
2010 char *pass, size_t passlen) {
2011 struct mg_str *v = mg_http_get_header(hm, "Authorization");
2012 user[0] = pass[0] = '\0';
2013 if (v != NULL && v->len > 6 && memcmp(v->ptr, "Basic ", 6) == 0) {
2015 int n = mg_base64_decode(v->ptr + 6, (int) v->len - 6, buf);
2016 const char *p = (const char *) memchr(buf, ':', n > 0 ? (size_t) n : 0);
2018 mg_snprintf(user, userlen, "%.*s", (int) (p - buf), buf);
2019 mg_snprintf(pass, passlen, "%.*s", n - (int) (p - buf) - 1, p + 1);
2021 } else if (v != NULL && v->len > 7 && memcmp(v->ptr, "Bearer ", 7) == 0) {
2022 mg_snprintf(pass, passlen, "%.*s", (int) v->len - 7, v->ptr + 7);
2023 } else if ((v = mg_http_get_header(hm, "Cookie")) != NULL) {
2024 struct mg_str t = mg_http_get_header_var(*v, mg_str_n("access_token", 12));
2025 if (t.len > 0) mg_snprintf(pass, passlen, "%.*s", (int) t.len, t.ptr);
2027 mg_http_get_var(&hm->query, "access_token", pass, passlen);
2031 static struct mg_str stripquotes(struct mg_str s) {
2032 return s.len > 1 && s.ptr[0] == '"' && s.ptr[s.len - 1] == '"'
2033 ? mg_str_n(s.ptr + 1, s.len - 2)
2037 struct mg_str mg_http_get_header_var(struct mg_str s, struct mg_str v) {
2039 for (i = 0; v.len > 0 && i + v.len + 2 < s.len; i++) {
2040 if (s.ptr[i + v.len] == '=' && memcmp(&s.ptr[i], v.ptr, v.len) == 0) {
2041 const char *p = &s.ptr[i + v.len + 1], *b = p, *x = &s.ptr[s.len];
2042 int q = p < x && *p == '"' ? 1 : 0;
2044 (q ? p == b || *p != '"' : *p != ';' && *p != ' ' && *p != ','))
2046 // MG_INFO(("[%.*s] [%.*s] [%.*s]", (int) s.len, s.ptr, (int) v.len,
2047 // v.ptr, (int) (p - b), b));
2048 return stripquotes(mg_str_n(b, (size_t) (p - b + q)));
2051 return mg_str_n(NULL, 0);
2054 bool mg_http_match_uri(const struct mg_http_message *hm, const char *glob) {
2055 return mg_match(hm->uri, mg_str(glob), NULL);
2058 long mg_http_upload(struct mg_connection *c, struct mg_http_message *hm,
2059 struct mg_fs *fs, const char *path, size_t max_size) {
2061 long res = 0, offset;
2062 mg_http_get_var(&hm->query, "offset", buf, sizeof(buf));
2063 offset = strtol(buf, NULL, 0);
2064 if (hm->body.len == 0) {
2065 mg_http_reply(c, 200, "", "%ld", res); // Nothing to write
2068 size_t current_size = 0;
2069 MG_DEBUG(("%s -> %d bytes @ %ld", path, (int) hm->body.len, offset));
2070 if (offset == 0) fs->rm(path); // If offset if 0, truncate file
2071 fs->st(path, ¤t_size, NULL);
2073 mg_http_reply(c, 400, "", "offset required");
2075 } else if (offset > 0 && current_size != (size_t) offset) {
2076 mg_http_reply(c, 400, "", "%s: offset mismatch", path);
2078 } else if ((size_t) offset + hm->body.len > max_size) {
2079 mg_http_reply(c, 400, "", "%s: over max size of %lu", path,
2080 (unsigned long) max_size);
2082 } else if ((fd = mg_fs_open(fs, path, MG_FS_WRITE)) == NULL) {
2083 mg_http_reply(c, 400, "", "open(%s): %d", path, errno);
2086 res = offset + (long) fs->wr(fd->fd, hm->body.ptr, hm->body.len);
2088 mg_http_reply(c, 200, "", "%ld", res);
2094 int mg_http_status(const struct mg_http_message *hm) {
2095 return atoi(hm->uri.ptr);
2098 // If a server sends data to the client using chunked encoding, Mongoose strips
2099 // off the chunking prefix (hex length and \r\n) and suffix (\r\n), appends the
2100 // stripped data to the body, and fires the MG_EV_HTTP_CHUNK event. When zero
2101 // chunk is received, we fire MG_EV_HTTP_MSG, and the body already has all
2102 // chunking prefixes/suffixes stripped.
2104 // If a server sends data without chunked encoding, we also fire a series of
2105 // MG_EV_HTTP_CHUNK events for every received piece of data, and then we fire
2106 // MG_EV_HTTP_MSG event in the end.
2108 // We track total processed length in the c->pfn_data, which is a void *
2109 // pointer: we store a size_t value there.
2110 static bool getchunk(struct mg_str s, size_t *prefixlen, size_t *datalen) {
2112 while (i < s.len && s.ptr[i] != '\r' && s.ptr[i] != '\n') i++;
2113 n = mg_unhexn(s.ptr, i);
2114 // MG_INFO(("%d %d", (int) (i + n + 4), (int) s.len));
2115 if (s.len < i + n + 4) return false; // Chunk not yet fully buffered
2116 if (s.ptr[i] != '\r' || s.ptr[i + 1] != '\n') return false;
2117 if (s.ptr[i + n + 2] != '\r' || s.ptr[i + n + 3] != '\n') return false;
2123 static bool mg_is_chunked(struct mg_http_message *hm) {
2124 const char *needle = "chunked";
2125 struct mg_str *te = mg_http_get_header(hm, "Transfer-Encoding");
2126 return te != NULL && mg_vcasecmp(te, needle) == 0;
2129 void mg_http_delete_chunk(struct mg_connection *c, struct mg_http_message *hm) {
2130 size_t ofs = (size_t) (hm->chunk.ptr - (char *) c->recv.buf);
2131 mg_iobuf_del(&c->recv, ofs, hm->chunk.len);
2132 c->pfn_data = (void *) ((size_t) c->pfn_data | MG_DMARK);
2135 static void deliver_chunked_chunks(struct mg_connection *c, size_t hlen,
2136 struct mg_http_message *hm, bool *next) {
2137 // | ... headers ... | HEXNUM\r\n ..data.. \r\n | ......
2138 // +------------------+--------------------------+----
2139 // | hlen | chunk1 | ......
2140 char *buf = (char *) &c->recv.buf[hlen], *p = buf;
2141 size_t len = c->recv.len - hlen;
2142 size_t processed = ((size_t) c->pfn_data) & ~MG_DMARK;
2143 size_t mark, pl, dl, del = 0, ofs = 0;
2145 if (processed <= len) len -= processed, buf += processed;
2146 while (!last && getchunk(mg_str_n(buf + ofs, len - ofs), &pl, &dl)) {
2147 size_t saved = c->recv.len;
2148 memmove(p + processed, buf + ofs + pl, dl);
2149 // MG_INFO(("P2 [%.*s]", (int) (processed + dl), p));
2150 hm->chunk = mg_str_n(p + processed, dl);
2151 mg_call(c, MG_EV_HTTP_CHUNK, hm);
2152 ofs += pl + dl + 2, del += pl + 2; // 2 is for \r\n suffix
2154 if (c->recv.len != saved) processed -= dl, buf -= dl;
2155 // mg_hexdump(c->recv.buf, hlen + processed);
2158 mg_iobuf_del(&c->recv, hlen + processed, del);
2159 mark = ((size_t) c->pfn_data) & MG_DMARK;
2160 c->pfn_data = (void *) (processed | mark);
2162 hm->body.len = processed;
2163 hm->message.len = hlen + processed;
2165 if (mark) mg_iobuf_del(&c->recv, 0, hlen), *next = true;
2166 // MG_INFO(("LAST, mark: %lx", mark));
2167 // mg_hexdump(c->recv.buf, c->recv.len);
2171 static void deliver_normal_chunks(struct mg_connection *c, size_t hlen,
2172 struct mg_http_message *hm, bool *next) {
2173 size_t left, processed = ((size_t) c->pfn_data) & ~MG_DMARK;
2174 size_t deleted = ((size_t) c->pfn_data) & MG_DMARK;
2175 hm->chunk = mg_str_n((char *) &c->recv.buf[hlen], c->recv.len - hlen);
2176 if (processed <= hm->chunk.len && !deleted) {
2177 hm->chunk.len -= processed;
2178 hm->chunk.ptr += processed;
2180 left = hm->body.len < processed ? 0 : hm->body.len - processed;
2181 if (hm->chunk.len > left) hm->chunk.len = left;
2182 if (hm->chunk.len > 0) mg_call(c, MG_EV_HTTP_CHUNK, hm);
2183 processed += hm->chunk.len;
2184 deleted = ((size_t) c->pfn_data) & MG_DMARK; // Re-evaluate after user call
2185 if (processed >= hm->body.len) { // Last, 0-len chunk
2186 hm->chunk.len = 0; // Reset length
2187 mg_call(c, MG_EV_HTTP_CHUNK, hm); // Call user handler
2188 c->pfn_data = NULL; // Reset processed counter
2189 if (processed && deleted) mg_iobuf_del(&c->recv, 0, hlen), *next = true;
2191 c->pfn_data = (void *) (processed | deleted); // if it is set
2195 static void http_cb(struct mg_connection *c, int ev, void *evd, void *fnd) {
2196 if (ev == MG_EV_READ || ev == MG_EV_CLOSE) {
2197 struct mg_http_message hm;
2198 // mg_hexdump(c->recv.buf, c->recv.len);
2199 while (c->recv.buf != NULL && c->recv.len > 0) {
2201 int hlen = mg_http_parse((char *) c->recv.buf, c->recv.len, &hm);
2203 mg_error(c, "HTTP parse:\n%.*s", (int) c->recv.len, c->recv.buf);
2206 if (c->is_resp) break; // Response is still generated
2207 if (hlen == 0) break; // Request is not buffered yet
2208 if (ev == MG_EV_CLOSE) { // If client did not set Content-Length
2209 hm.message.len = c->recv.len; // and closes now, deliver a MSG
2210 hm.body.len = hm.message.len - (size_t) (hm.body.ptr - hm.message.ptr);
2212 if (mg_is_chunked(&hm)) {
2213 deliver_chunked_chunks(c, (size_t) hlen, &hm, &next);
2215 deliver_normal_chunks(c, (size_t) hlen, &hm, &next);
2217 if (next) continue; // Chunks & request were deleted
2218 // Chunk events are delivered. If we have full body, deliver MSG
2219 if (c->recv.len < hm.message.len) break;
2220 if (c->is_accepted) c->is_resp = 1; // Start generating response
2221 mg_call(c, MG_EV_HTTP_MSG, &hm); // User handler can clear is_resp
2222 mg_iobuf_del(&c->recv, 0, hm.message.len);
2225 (void) evd, (void) fnd;
2228 static void mg_hfn(struct mg_connection *c, int ev, void *ev_data, void *fnd) {
2229 if (ev == MG_EV_HTTP_MSG) {
2230 struct mg_http_message *hm = (struct mg_http_message *) ev_data;
2231 if (mg_http_match_uri(hm, "/quit")) {
2232 mg_http_reply(c, 200, "", "ok\n");
2235 } else if (mg_http_match_uri(hm, "/debug")) {
2236 int level = (int) mg_json_get_long(hm->body, "$.level", MG_LL_DEBUG);
2238 mg_http_reply(c, 200, "", "Debug level set to %d\n", level);
2240 mg_http_reply(c, 200, "", "hi\n");
2242 } else if (ev == MG_EV_CLOSE) {
2243 if (c->data[0] == 'X') *(bool *) fnd = true;
2247 void mg_hello(const char *url) {
2251 if (mg_http_listen(&mgr, url, mg_hfn, &done) == NULL) done = true;
2252 while (done == false) mg_mgr_poll(&mgr, 100);
2256 struct mg_connection *mg_http_connect(struct mg_mgr *mgr, const char *url,
2257 mg_event_handler_t fn, void *fn_data) {
2258 struct mg_connection *c = mg_connect(mgr, url, fn, fn_data);
2259 if (c != NULL) c->pfn = http_cb;
2263 struct mg_connection *mg_http_listen(struct mg_mgr *mgr, const char *url,
2264 mg_event_handler_t fn, void *fn_data) {
2265 struct mg_connection *c = mg_listen(mgr, url, fn, fn_data);
2266 if (c != NULL) c->pfn = http_cb;
2270 #ifdef MG_ENABLE_LINES
2271 #line 1 "src/iobuf.c"
2277 // Not using memset for zeroing memory, cause it can be dropped by compiler
2278 // See https://github.com/cesanta/mongoose/pull/1265
2279 static void zeromem(volatile unsigned char *buf, size_t len) {
2281 while (len--) *buf++ = 0;
2285 static size_t roundup(size_t size, size_t align) {
2286 return align == 0 ? size : (size + align - 1) / align * align;
2289 int mg_iobuf_resize(struct mg_iobuf *io, size_t new_size) {
2291 new_size = roundup(new_size, io->align);
2292 if (new_size == 0) {
2293 zeromem(io->buf, io->size);
2296 io->len = io->size = 0;
2297 } else if (new_size != io->size) {
2298 // NOTE(lsm): do not use realloc here. Use calloc/free only, to ease the
2299 // porting to some obscure platforms like FreeRTOS
2300 void *p = calloc(1, new_size);
2302 size_t len = new_size < io->len ? new_size : io->len;
2303 if (len > 0 && io->buf != NULL) memmove(p, io->buf, len);
2304 zeromem(io->buf, io->size);
2306 io->buf = (unsigned char *) p;
2307 io->size = new_size;
2310 MG_ERROR(("%lld->%lld", (uint64_t) io->size, (uint64_t) new_size));
2316 int mg_iobuf_init(struct mg_iobuf *io, size_t size, size_t align) {
2319 io->size = io->len = 0;
2320 return mg_iobuf_resize(io, size);
2323 size_t mg_iobuf_add(struct mg_iobuf *io, size_t ofs, const void *buf,
2325 size_t new_size = roundup(io->len + len, io->align);
2326 mg_iobuf_resize(io, new_size); // Attempt to resize
2327 if (new_size != io->size) len = 0; // Resize failure, append nothing
2328 if (ofs < io->len) memmove(io->buf + ofs + len, io->buf + ofs, io->len - ofs);
2329 if (buf != NULL) memmove(io->buf + ofs, buf, len);
2330 if (ofs > io->len) io->len += ofs - io->len;
2335 size_t mg_iobuf_del(struct mg_iobuf *io, size_t ofs, size_t len) {
2336 if (ofs > io->len) ofs = io->len;
2337 if (ofs + len > io->len) len = io->len - ofs;
2338 if (io->buf) memmove(io->buf + ofs, io->buf + ofs + len, io->len - ofs - len);
2339 if (io->buf) zeromem(io->buf + io->len - len, len);
2344 void mg_iobuf_free(struct mg_iobuf *io) {
2345 mg_iobuf_resize(io, 0);
2348 #ifdef MG_ENABLE_LINES
2349 #line 1 "src/json.c"
2355 static const char *escapeseq(int esc) {
2356 return esc ? "\b\f\n\r\t\\\"" : "bfnrt\\\"";
2359 static char json_esc(int c, int esc) {
2360 const char *p, *esc1 = escapeseq(esc), *esc2 = escapeseq(!esc);
2361 for (p = esc1; *p != '\0'; p++) {
2362 if (*p == c) return esc2[p - esc1];
2367 static int mg_pass_string(const char *s, int len) {
2369 for (i = 0; i < len; i++) {
2370 if (s[i] == '\\' && i + 1 < len && json_esc(s[i + 1], 1)) {
2372 } else if (s[i] == '\0') {
2373 return MG_JSON_INVALID;
2374 } else if (s[i] == '"') {
2378 return MG_JSON_INVALID;
2381 static double mg_atod(const char *p, int len, int *numlen) {
2383 int i = 0, sign = 1;
2386 if (i < len && *p == '-') {
2388 } else if (i < len && *p == '+') {
2393 for (; i < len && p[i] >= '0' && p[i] <= '9'; i++) {
2400 if (i < len && p[i] == '.') {
2401 double frac = 0.0, base = 0.1;
2403 for (; i < len && p[i] >= '0' && p[i] <= '9'; i++) {
2404 frac += base * (p[i] - '0');
2411 if (i < len && (p[i] == 'e' || p[i] == 'E')) {
2412 int j, exp = 0, minus = 0;
2414 if (i < len && p[i] == '-') minus = 1, i++;
2415 if (i < len && p[i] == '+') i++;
2416 while (i < len && p[i] >= '0' && p[i] <= '9' && exp < 308)
2417 exp = exp * 10 + (p[i++] - '0');
2418 if (minus) exp = -exp;
2419 for (j = 0; j < exp; j++) d *= 10.0;
2420 for (j = 0; j < -exp; j++) d /= 10.0;
2423 if (numlen != NULL) *numlen = i;
2427 int mg_json_get(struct mg_str json, const char *path, int *toklen) {
2428 const char *s = json.ptr;
2429 int len = (int) json.len;
2430 enum { S_VALUE, S_KEY, S_COLON, S_COMMA_OR_EOO } expecting = S_VALUE;
2431 unsigned char nesting[MG_JSON_MAX_DEPTH];
2432 int i = 0; // Current offset in `s`
2433 int j = 0; // Offset in `s` we're looking for (return value)
2434 int depth = 0; // Current depth (nesting level)
2435 int ed = 0; // Expected depth
2436 int pos = 1; // Current position in `path`
2437 int ci = -1, ei = -1; // Current and expected index in array
2439 if (toklen) *toklen = 0;
2440 if (path[0] != '$') return MG_JSON_INVALID;
2442 #define MG_CHECKRET(x) \
2444 if (depth == ed && path[pos] == '\0' && ci == ei) { \
2445 if (toklen) *toklen = i - j + 1; \
2450 // In the ascii table, the distance between `[` and `]` is 2.
2451 // Ditto for `{` and `}`. Hence +2 in the code below.
2454 if (depth == ed && ci != ei) return MG_JSON_NOT_FOUND; \
2455 if (c != nesting[depth - 1] + 2) return MG_JSON_INVALID; \
2460 for (i = 0; i < len; i++) {
2461 unsigned char c = ((unsigned char *) s)[i];
2462 if (c == ' ' || c == '\t' || c == '\n' || c == '\r') continue;
2463 switch (expecting) {
2465 // p("V %s [%.*s] %d %d %d %d\n", path, pos, path, depth, ed, ci, ei);
2466 if (depth == ed) j = i;
2468 if (depth >= (int) sizeof(nesting)) return MG_JSON_TOO_DEEP;
2469 if (depth == ed && path[pos] == '.' && ci == ei) {
2470 // If we start the object, reset array indices
2471 ed++, pos++, ci = ei = -1;
2473 nesting[depth++] = c;
2476 } else if (c == '[') {
2477 if (depth >= (int) sizeof(nesting)) return MG_JSON_TOO_DEEP;
2478 if (depth == ed && path[pos] == '[' && ei == ci) {
2479 ed++, pos++, ci = 0;
2480 for (ei = 0; path[pos] != ']' && path[pos] != '\0'; pos++) {
2482 ei += path[pos] - '0';
2484 if (path[pos] != 0) pos++;
2486 nesting[depth++] = c;
2488 } else if (c == ']' && depth > 0) { // Empty array
2490 } else if (c == 't' && i + 3 < len && memcmp(&s[i], "true", 4) == 0) {
2492 } else if (c == 'n' && i + 3 < len && memcmp(&s[i], "null", 4) == 0) {
2494 } else if (c == 'f' && i + 4 < len && memcmp(&s[i], "false", 5) == 0) {
2496 } else if (c == '-' || ((c >= '0' && c <= '9'))) {
2498 mg_atod(&s[i], len - i, &numlen);
2500 } else if (c == '"') {
2501 int n = mg_pass_string(&s[i + 1], len - i - 1);
2502 if (n < 0) return n;
2505 return MG_JSON_INVALID;
2508 if (depth == ed && ei >= 0) ci++;
2509 expecting = S_COMMA_OR_EOO;
2514 int n = mg_pass_string(&s[i + 1], len - i - 1);
2515 if (n < 0) return n;
2516 if (i + 1 + n >= len) return MG_JSON_NOT_FOUND;
2517 if (depth < ed) return MG_JSON_NOT_FOUND;
2518 if (depth == ed && path[pos - 1] != '.') return MG_JSON_NOT_FOUND;
2519 // printf("K %s [%.*s] [%.*s] %d %d %d\n", path, pos, path, n,
2520 // &s[i + 1], n, depth, ed);
2521 // NOTE(cpq): in the check sequence below is important.
2522 // strncmp() must go first: it fails fast if the remaining length of
2523 // the path is smaller than `n`.
2524 if (depth == ed && path[pos - 1] == '.' &&
2525 strncmp(&s[i + 1], &path[pos], (size_t) n) == 0 &&
2526 (path[pos + n] == '\0' || path[pos + n] == '.' ||
2527 path[pos + n] == '[')) {
2531 expecting = S_COLON;
2532 } else if (c == '}') { // Empty object
2534 expecting = S_COMMA_OR_EOO;
2536 return MG_JSON_INVALID;
2542 expecting = S_VALUE;
2544 return MG_JSON_INVALID;
2548 case S_COMMA_OR_EOO:
2550 return MG_JSON_INVALID;
2551 } else if (c == ',') {
2552 expecting = (nesting[depth - 1] == '{') ? S_KEY : S_VALUE;
2553 } else if (c == ']' || c == '}') {
2555 if (depth == ed && ei >= 0) ci++;
2557 return MG_JSON_INVALID;
2562 return MG_JSON_NOT_FOUND;
2565 bool mg_json_get_num(struct mg_str json, const char *path, double *v) {
2566 int n, toklen, found = 0;
2567 if ((n = mg_json_get(json, path, &toklen)) >= 0 &&
2568 (json.ptr[n] == '-' || (json.ptr[n] >= '0' && json.ptr[n] <= '9'))) {
2569 if (v != NULL) *v = mg_atod(json.ptr + n, toklen, NULL);
2575 bool mg_json_get_bool(struct mg_str json, const char *path, bool *v) {
2576 int found = 0, off = mg_json_get(json, path, NULL);
2577 if (off >= 0 && (json.ptr[off] == 't' || json.ptr[off] == 'f')) {
2578 if (v != NULL) *v = json.ptr[off] == 't';
2584 static bool json_unescape(const char *s, size_t len, char *to, size_t n) {
2586 for (i = 0, j = 0; i < len && j < n; i++, j++) {
2587 if (s[i] == '\\' && i + 5 < len && s[i + 1] == 'u') {
2588 // \uXXXX escape. We could process a simple one-byte chars
2589 // \u00xx from the ASCII range. More complex chars would require
2590 // dragging in a UTF8 library, which is too much for us
2591 if (s[i + 2] != '0' || s[i + 3] != '0') return false; // Give up
2592 ((unsigned char *) to)[j] = (unsigned char) mg_unhexn(s + i + 4, 2);
2595 } else if (s[i] == '\\' && i + 1 < len) {
2596 char c = json_esc(s[i + 1], 0);
2597 if (c == 0) return false;
2604 if (j >= n) return false;
2605 if (n > 0) to[j] = '\0';
2609 char *mg_json_get_str(struct mg_str json, const char *path) {
2610 char *result = NULL;
2611 int len = 0, off = mg_json_get(json, path, &len);
2612 if (off >= 0 && len > 1 && json.ptr[off] == '"') {
2613 if ((result = (char *) calloc(1, (size_t) len)) != NULL &&
2614 !json_unescape(json.ptr + off + 1, (size_t) (len - 2), result,
2623 char *mg_json_get_b64(struct mg_str json, const char *path, int *slen) {
2624 char *result = NULL;
2625 int len = 0, off = mg_json_get(json, path, &len);
2626 if (off >= 0 && json.ptr[off] == '"' && len > 1 &&
2627 (result = (char *) calloc(1, (size_t) len)) != NULL) {
2628 int k = mg_base64_decode(json.ptr + off + 1, len - 2, result);
2629 if (slen != NULL) *slen = k;
2634 char *mg_json_get_hex(struct mg_str json, const char *path, int *slen) {
2635 char *result = NULL;
2636 int len = 0, off = mg_json_get(json, path, &len);
2637 if (off >= 0 && json.ptr[off] == '"' && len > 1 &&
2638 (result = (char *) calloc(1, (size_t) len / 2)) != NULL) {
2639 mg_unhex(json.ptr + off + 1, (size_t) (len - 2), (uint8_t *) result);
2640 result[len / 2 - 1] = '\0';
2641 if (slen != NULL) *slen = len / 2 - 1;
2646 long mg_json_get_long(struct mg_str json, const char *path, long dflt) {
2649 if (mg_json_get_num(json, path, &dv)) result = (long) dv;
2653 #ifdef MG_ENABLE_LINES
2661 static int s_level = MG_LL_INFO;
2662 static mg_pfn_t s_log_func = mg_pfn_stdout;
2663 static void *s_log_func_param = NULL;
2665 void mg_log_set_fn(mg_pfn_t fn, void *param) {
2667 s_log_func_param = param;
2670 static void logc(unsigned char c) {
2671 s_log_func((char) c, s_log_func_param);
2674 static void logs(const char *buf, size_t len) {
2676 for (i = 0; i < len; i++) logc(((unsigned char *) buf)[i]);
2679 void mg_log_set(int log_level) {
2680 MG_DEBUG(("Setting log level to %d", log_level));
2681 s_level = log_level;
2684 bool mg_log_prefix(int level, const char *file, int line, const char *fname) {
2685 if (level <= s_level) {
2686 const char *p = strrchr(file, '/');
2689 if (p == NULL) p = strrchr(file, '\\');
2690 n = mg_snprintf(buf, sizeof(buf), "%-6llx %d %s:%d:%s", mg_millis(), level,
2691 p == NULL ? file : p + 1, line, fname);
2692 if (n > sizeof(buf) - 2) n = sizeof(buf) - 2;
2693 while (n < sizeof(buf)) buf[n++] = ' ';
2701 void mg_log(const char *fmt, ...) {
2704 mg_vxprintf(s_log_func, s_log_func_param, fmt, &ap);
2706 logc((unsigned char) '\n');
2709 static unsigned char nibble(unsigned c) {
2710 return (unsigned char) (c < 10 ? c + '0' : c + 'W');
2713 #define ISPRINT(x) ((x) >= ' ' && (x) <= '~')
2714 void mg_hexdump(const void *buf, size_t len) {
2715 const unsigned char *p = (const unsigned char *) buf;
2716 unsigned char ascii[16], alen = 0;
2718 for (i = 0; i < len; i++) {
2719 if ((i % 16) == 0) {
2720 // Print buffered ascii chars
2721 if (i > 0) logs(" ", 2), logs((char *) ascii, 16), logc('\n'), alen = 0;
2722 // Print hex address, then \t
2723 logc(nibble((i >> 12) & 15)), logc(nibble((i >> 8) & 15)),
2724 logc(nibble((i >> 4) & 15)), logc('0'), logs(" ", 3);
2726 logc(nibble(p[i] >> 4)), logc(nibble(p[i] & 15)); // Two nibbles, e.g. c5
2727 logc(' '); // Space after hex number
2728 ascii[alen++] = ISPRINT(p[i]) ? p[i] : '.'; // Add to the ascii buf
2730 while (alen < 16) logs(" ", 3), ascii[alen++] = ' ';
2731 logs(" ", 2), logs((char *) ascii, 16), logc('\n');
2734 #ifdef MG_ENABLE_LINES
2740 #if defined(MG_ENABLE_MD5) && MG_ENABLE_MD5
2742 static void mg_byte_reverse(unsigned char *buf, unsigned longs) {
2743 if (MG_BIG_ENDIAN) {
2745 uint32_t t = (uint32_t) ((unsigned) buf[3] << 8 | buf[2]) << 16 |
2746 ((unsigned) buf[1] << 8 | buf[0]);
2747 *(uint32_t *) buf = t;
2751 (void) buf, (void) longs; // Little endian. Do nothing
2755 #define F1(x, y, z) (z ^ (x & (y ^ z)))
2756 #define F2(x, y, z) F1(z, x, y)
2757 #define F3(x, y, z) (x ^ y ^ z)
2758 #define F4(x, y, z) (y ^ (x | ~z))
2760 #define MD5STEP(f, w, x, y, z, data, s) \
2761 (w += f(x, y, z) + data, w = w << s | w >> (32 - s), w += x)
2764 * Start MD5 accumulation. Set bit count to 0 and buffer to mysterious
2765 * initialization constants.
2767 void mg_md5_init(mg_md5_ctx *ctx) {
2768 ctx->buf[0] = 0x67452301;
2769 ctx->buf[1] = 0xefcdab89;
2770 ctx->buf[2] = 0x98badcfe;
2771 ctx->buf[3] = 0x10325476;
2777 static void mg_md5_transform(uint32_t buf[4], uint32_t const in[16]) {
2778 uint32_t a, b, c, d;
2785 MD5STEP(F1, a, b, c, d, in[0] + 0xd76aa478, 7);
2786 MD5STEP(F1, d, a, b, c, in[1] + 0xe8c7b756, 12);
2787 MD5STEP(F1, c, d, a, b, in[2] + 0x242070db, 17);
2788 MD5STEP(F1, b, c, d, a, in[3] + 0xc1bdceee, 22);
2789 MD5STEP(F1, a, b, c, d, in[4] + 0xf57c0faf, 7);
2790 MD5STEP(F1, d, a, b, c, in[5] + 0x4787c62a, 12);
2791 MD5STEP(F1, c, d, a, b, in[6] + 0xa8304613, 17);
2792 MD5STEP(F1, b, c, d, a, in[7] + 0xfd469501, 22);
2793 MD5STEP(F1, a, b, c, d, in[8] + 0x698098d8, 7);
2794 MD5STEP(F1, d, a, b, c, in[9] + 0x8b44f7af, 12);
2795 MD5STEP(F1, c, d, a, b, in[10] + 0xffff5bb1, 17);
2796 MD5STEP(F1, b, c, d, a, in[11] + 0x895cd7be, 22);
2797 MD5STEP(F1, a, b, c, d, in[12] + 0x6b901122, 7);
2798 MD5STEP(F1, d, a, b, c, in[13] + 0xfd987193, 12);
2799 MD5STEP(F1, c, d, a, b, in[14] + 0xa679438e, 17);
2800 MD5STEP(F1, b, c, d, a, in[15] + 0x49b40821, 22);
2802 MD5STEP(F2, a, b, c, d, in[1] + 0xf61e2562, 5);
2803 MD5STEP(F2, d, a, b, c, in[6] + 0xc040b340, 9);
2804 MD5STEP(F2, c, d, a, b, in[11] + 0x265e5a51, 14);
2805 MD5STEP(F2, b, c, d, a, in[0] + 0xe9b6c7aa, 20);
2806 MD5STEP(F2, a, b, c, d, in[5] + 0xd62f105d, 5);
2807 MD5STEP(F2, d, a, b, c, in[10] + 0x02441453, 9);
2808 MD5STEP(F2, c, d, a, b, in[15] + 0xd8a1e681, 14);
2809 MD5STEP(F2, b, c, d, a, in[4] + 0xe7d3fbc8, 20);
2810 MD5STEP(F2, a, b, c, d, in[9] + 0x21e1cde6, 5);
2811 MD5STEP(F2, d, a, b, c, in[14] + 0xc33707d6, 9);
2812 MD5STEP(F2, c, d, a, b, in[3] + 0xf4d50d87, 14);
2813 MD5STEP(F2, b, c, d, a, in[8] + 0x455a14ed, 20);
2814 MD5STEP(F2, a, b, c, d, in[13] + 0xa9e3e905, 5);
2815 MD5STEP(F2, d, a, b, c, in[2] + 0xfcefa3f8, 9);
2816 MD5STEP(F2, c, d, a, b, in[7] + 0x676f02d9, 14);
2817 MD5STEP(F2, b, c, d, a, in[12] + 0x8d2a4c8a, 20);
2819 MD5STEP(F3, a, b, c, d, in[5] + 0xfffa3942, 4);
2820 MD5STEP(F3, d, a, b, c, in[8] + 0x8771f681, 11);
2821 MD5STEP(F3, c, d, a, b, in[11] + 0x6d9d6122, 16);
2822 MD5STEP(F3, b, c, d, a, in[14] + 0xfde5380c, 23);
2823 MD5STEP(F3, a, b, c, d, in[1] + 0xa4beea44, 4);
2824 MD5STEP(F3, d, a, b, c, in[4] + 0x4bdecfa9, 11);
2825 MD5STEP(F3, c, d, a, b, in[7] + 0xf6bb4b60, 16);
2826 MD5STEP(F3, b, c, d, a, in[10] + 0xbebfbc70, 23);
2827 MD5STEP(F3, a, b, c, d, in[13] + 0x289b7ec6, 4);
2828 MD5STEP(F3, d, a, b, c, in[0] + 0xeaa127fa, 11);
2829 MD5STEP(F3, c, d, a, b, in[3] + 0xd4ef3085, 16);
2830 MD5STEP(F3, b, c, d, a, in[6] + 0x04881d05, 23);
2831 MD5STEP(F3, a, b, c, d, in[9] + 0xd9d4d039, 4);
2832 MD5STEP(F3, d, a, b, c, in[12] + 0xe6db99e5, 11);
2833 MD5STEP(F3, c, d, a, b, in[15] + 0x1fa27cf8, 16);
2834 MD5STEP(F3, b, c, d, a, in[2] + 0xc4ac5665, 23);
2836 MD5STEP(F4, a, b, c, d, in[0] + 0xf4292244, 6);
2837 MD5STEP(F4, d, a, b, c, in[7] + 0x432aff97, 10);
2838 MD5STEP(F4, c, d, a, b, in[14] + 0xab9423a7, 15);
2839 MD5STEP(F4, b, c, d, a, in[5] + 0xfc93a039, 21);
2840 MD5STEP(F4, a, b, c, d, in[12] + 0x655b59c3, 6);
2841 MD5STEP(F4, d, a, b, c, in[3] + 0x8f0ccc92, 10);
2842 MD5STEP(F4, c, d, a, b, in[10] + 0xffeff47d, 15);
2843 MD5STEP(F4, b, c, d, a, in[1] + 0x85845dd1, 21);
2844 MD5STEP(F4, a, b, c, d, in[8] + 0x6fa87e4f, 6);
2845 MD5STEP(F4, d, a, b, c, in[15] + 0xfe2ce6e0, 10);
2846 MD5STEP(F4, c, d, a, b, in[6] + 0xa3014314, 15);
2847 MD5STEP(F4, b, c, d, a, in[13] + 0x4e0811a1, 21);
2848 MD5STEP(F4, a, b, c, d, in[4] + 0xf7537e82, 6);
2849 MD5STEP(F4, d, a, b, c, in[11] + 0xbd3af235, 10);
2850 MD5STEP(F4, c, d, a, b, in[2] + 0x2ad7d2bb, 15);
2851 MD5STEP(F4, b, c, d, a, in[9] + 0xeb86d391, 21);
2859 void mg_md5_update(mg_md5_ctx *ctx, const unsigned char *buf, size_t len) {
2863 if ((ctx->bits[0] = t + ((uint32_t) len << 3)) < t) ctx->bits[1]++;
2864 ctx->bits[1] += (uint32_t) len >> 29;
2866 t = (t >> 3) & 0x3f;
2869 unsigned char *p = (unsigned char *) ctx->in + t;
2873 memcpy(p, buf, len);
2877 mg_byte_reverse(ctx->in, 16);
2878 mg_md5_transform(ctx->buf, (uint32_t *) ctx->in);
2884 memcpy(ctx->in, buf, 64);
2885 mg_byte_reverse(ctx->in, 16);
2886 mg_md5_transform(ctx->buf, (uint32_t *) ctx->in);
2891 memcpy(ctx->in, buf, len);
2894 void mg_md5_final(mg_md5_ctx *ctx, unsigned char digest[16]) {
2899 count = (ctx->bits[0] >> 3) & 0x3F;
2901 p = ctx->in + count;
2903 count = 64 - 1 - count;
2905 memset(p, 0, count);
2906 mg_byte_reverse(ctx->in, 16);
2907 mg_md5_transform(ctx->buf, (uint32_t *) ctx->in);
2908 memset(ctx->in, 0, 56);
2910 memset(p, 0, count - 8);
2912 mg_byte_reverse(ctx->in, 14);
2914 a = (uint32_t *) ctx->in;
2915 a[14] = ctx->bits[0];
2916 a[15] = ctx->bits[1];
2918 mg_md5_transform(ctx->buf, (uint32_t *) ctx->in);
2919 mg_byte_reverse((unsigned char *) ctx->buf, 4);
2920 memcpy(digest, ctx->buf, 16);
2921 memset((char *) ctx, 0, sizeof(*ctx));
2925 #ifdef MG_ENABLE_LINES
2926 #line 1 "src/mqtt.c"
2936 #define MQTT_CLEAN_SESSION 0x02
2937 #define MQTT_HAS_WILL 0x04
2938 #define MQTT_WILL_RETAIN 0x20
2939 #define MQTT_HAS_PASSWORD 0x40
2940 #define MQTT_HAS_USER_NAME 0x80
2942 struct mg_mqtt_pmap {
2947 static const struct mg_mqtt_pmap s_prop_map[] = {
2948 {MQTT_PROP_PAYLOAD_FORMAT_INDICATOR, MQTT_PROP_TYPE_BYTE},
2949 {MQTT_PROP_MESSAGE_EXPIRY_INTERVAL, MQTT_PROP_TYPE_INT},
2950 {MQTT_PROP_CONTENT_TYPE, MQTT_PROP_TYPE_STRING},
2951 {MQTT_PROP_RESPONSE_TOPIC, MQTT_PROP_TYPE_STRING},
2952 {MQTT_PROP_CORRELATION_DATA, MQTT_PROP_TYPE_BINARY_DATA},
2953 {MQTT_PROP_SUBSCRIPTION_IDENTIFIER, MQTT_PROP_TYPE_VARIABLE_INT},
2954 {MQTT_PROP_SESSION_EXPIRY_INTERVAL, MQTT_PROP_TYPE_INT},
2955 {MQTT_PROP_ASSIGNED_CLIENT_IDENTIFIER, MQTT_PROP_TYPE_STRING},
2956 {MQTT_PROP_SERVER_KEEP_ALIVE, MQTT_PROP_TYPE_SHORT},
2957 {MQTT_PROP_AUTHENTICATION_METHOD, MQTT_PROP_TYPE_STRING},
2958 {MQTT_PROP_AUTHENTICATION_DATA, MQTT_PROP_TYPE_BINARY_DATA},
2959 {MQTT_PROP_REQUEST_PROBLEM_INFORMATION, MQTT_PROP_TYPE_BYTE},
2960 {MQTT_PROP_WILL_DELAY_INTERVAL, MQTT_PROP_TYPE_INT},
2961 {MQTT_PROP_REQUEST_RESPONSE_INFORMATION, MQTT_PROP_TYPE_BYTE},
2962 {MQTT_PROP_RESPONSE_INFORMATION, MQTT_PROP_TYPE_STRING},
2963 {MQTT_PROP_SERVER_REFERENCE, MQTT_PROP_TYPE_STRING},
2964 {MQTT_PROP_REASON_STRING, MQTT_PROP_TYPE_STRING},
2965 {MQTT_PROP_RECEIVE_MAXIMUM, MQTT_PROP_TYPE_SHORT},
2966 {MQTT_PROP_TOPIC_ALIAS_MAXIMUM, MQTT_PROP_TYPE_SHORT},
2967 {MQTT_PROP_TOPIC_ALIAS, MQTT_PROP_TYPE_SHORT},
2968 {MQTT_PROP_MAXIMUM_QOS, MQTT_PROP_TYPE_BYTE},
2969 {MQTT_PROP_RETAIN_AVAILABLE, MQTT_PROP_TYPE_BYTE},
2970 {MQTT_PROP_USER_PROPERTY, MQTT_PROP_TYPE_STRING_PAIR},
2971 {MQTT_PROP_MAXIMUM_PACKET_SIZE, MQTT_PROP_TYPE_INT},
2972 {MQTT_PROP_WILDCARD_SUBSCRIPTION_AVAILABLE, MQTT_PROP_TYPE_BYTE},
2973 {MQTT_PROP_SUBSCRIPTION_IDENTIFIER_AVAILABLE, MQTT_PROP_TYPE_BYTE},
2974 {MQTT_PROP_SHARED_SUBSCRIPTION_AVAILABLE, MQTT_PROP_TYPE_BYTE}};
2976 void mg_mqtt_send_header(struct mg_connection *c, uint8_t cmd, uint8_t flags,
2978 uint8_t buf[1 + sizeof(len)], *vlen = &buf[1];
2979 buf[0] = (uint8_t) ((cmd << 4) | flags);
2983 if (len > 0) *vlen |= 0x80;
2985 } while (len > 0 && vlen < &buf[sizeof(buf)]);
2986 mg_send(c, buf, (size_t) (vlen - buf));
2989 static void mg_send_u16(struct mg_connection *c, uint16_t value) {
2990 mg_send(c, &value, sizeof(value));
2993 static void mg_send_u32(struct mg_connection *c, uint32_t value) {
2994 mg_send(c, &value, sizeof(value));
2997 static uint8_t compute_variable_length_size(size_t length) {
2998 uint8_t bytes_needed = 0;
3002 } while (length > 0);
3003 return bytes_needed;
3006 static int encode_variable_length(uint8_t *buf, size_t value) {
3010 uint8_t byte = (uint8_t) (value % 128);
3012 if (value > 0) byte |= 0x80;
3014 } while (value > 0);
3019 static uint32_t decode_variable_length(const char *buf,
3020 uint32_t *bytes_consumed) {
3021 uint32_t value = 0, multiplier = 1, offset;
3023 for (offset = 0; offset < 4; offset++) {
3024 uint8_t encoded_byte = ((uint8_t *) buf)[offset];
3025 value += (encoded_byte & 0x7F) * multiplier;
3028 if (!(encoded_byte & 0x80)) break;
3031 if (bytes_consumed != NULL) *bytes_consumed = offset + 1;
3036 static int mqtt_prop_type_by_id(uint8_t prop_id) {
3037 size_t i, num_properties = sizeof(s_prop_map) / sizeof(s_prop_map[0]);
3038 for (i = 0; i < num_properties; ++i) {
3039 if (s_prop_map[i].id == prop_id) return s_prop_map[i].type;
3041 return -1; // Property ID not found
3044 // Returns the size of the properties section, without the
3045 // size of the content's length
3046 static size_t get_properties_length(struct mg_mqtt_prop *props, size_t count) {
3048 for (i = 0; i < count; i++) {
3049 size++; // identifier
3050 switch (mqtt_prop_type_by_id(props[i].id)) {
3051 case MQTT_PROP_TYPE_STRING_PAIR:
3052 size += (uint32_t) (props[i].val.len + props[i].key.len +
3053 2 * sizeof(uint16_t));
3055 case MQTT_PROP_TYPE_STRING:
3056 size += (uint32_t) (props[i].val.len + sizeof(uint16_t));
3058 case MQTT_PROP_TYPE_BINARY_DATA:
3059 size += (uint32_t) (props[i].val.len + sizeof(uint16_t));
3061 case MQTT_PROP_TYPE_VARIABLE_INT:
3062 size += compute_variable_length_size((uint32_t) props[i].iv);
3064 case MQTT_PROP_TYPE_INT: size += (uint32_t) sizeof(uint32_t); break;
3065 case MQTT_PROP_TYPE_SHORT: size += (uint32_t) sizeof(uint16_t); break;
3066 default: return size; // cannot parse further down
3073 // returns the entire size of the properties section, including the
3074 // size of the variable length of the content
3075 static size_t get_props_size(struct mg_mqtt_prop *props, size_t count) {
3076 size_t size = get_properties_length(props, count);
3077 size += compute_variable_length_size(size);
3081 static void mg_send_mqtt_properties(struct mg_connection *c,
3082 struct mg_mqtt_prop *props, size_t nprops) {
3083 size_t total_size = get_properties_length(props, nprops);
3084 uint8_t buf_v[4] = {0, 0, 0, 0};
3085 uint8_t buf[4] = {0, 0, 0, 0};
3086 int i, len = encode_variable_length(buf, total_size);
3088 mg_send(c, buf, (size_t) len);
3089 for (i = 0; i < (int) nprops; i++) {
3090 mg_send(c, &props[i].id, sizeof(props[i].id));
3091 switch (mqtt_prop_type_by_id(props[i].id)) {
3092 case MQTT_PROP_TYPE_STRING_PAIR:
3093 mg_send_u16(c, mg_htons((uint16_t) props[i].key.len));
3094 mg_send(c, props[i].key.ptr, props[i].key.len);
3095 mg_send_u16(c, mg_htons((uint16_t) props[i].val.len));
3096 mg_send(c, props[i].val.ptr, props[i].val.len);
3098 case MQTT_PROP_TYPE_BYTE:
3099 mg_send(c, &props[i].iv, sizeof(uint8_t));
3101 case MQTT_PROP_TYPE_SHORT:
3102 mg_send_u16(c, mg_htons((uint16_t) props[i].iv));
3104 case MQTT_PROP_TYPE_INT:
3105 mg_send_u32(c, mg_htonl((uint32_t) props[i].iv));
3107 case MQTT_PROP_TYPE_STRING:
3108 mg_send_u16(c, mg_htons((uint16_t) props[i].val.len));
3109 mg_send(c, props[i].val.ptr, props[i].val.len);
3111 case MQTT_PROP_TYPE_BINARY_DATA:
3112 mg_send_u16(c, mg_htons((uint16_t) props[i].val.len));
3113 mg_send(c, props[i].val.ptr, props[i].val.len);
3115 case MQTT_PROP_TYPE_VARIABLE_INT:
3116 len = encode_variable_length(buf_v, props[i].iv);
3117 mg_send(c, buf_v, (size_t) len);
3123 size_t mg_mqtt_next_prop(struct mg_mqtt_message *msg, struct mg_mqtt_prop *prop,
3125 uint8_t *i = (uint8_t *) msg->dgram.ptr + msg->props_start + ofs;
3126 size_t new_pos = ofs;
3127 uint32_t bytes_consumed;
3130 if (ofs >= msg->dgram.len || ofs >= msg->props_start + msg->props_size)
3134 switch (mqtt_prop_type_by_id(prop->id)) {
3135 case MQTT_PROP_TYPE_STRING_PAIR:
3136 prop->key.len = (uint16_t) ((((uint16_t) i[0]) << 8) | i[1]);
3137 prop->key.ptr = (char *) i + 2;
3138 i += 2 + prop->key.len;
3139 prop->val.len = (uint16_t) ((((uint16_t) i[0]) << 8) | i[1]);
3140 prop->val.ptr = (char *) i + 2;
3141 new_pos += 2 * sizeof(uint16_t) + prop->val.len + prop->key.len;
3143 case MQTT_PROP_TYPE_BYTE:
3144 prop->iv = (uint8_t) i[0];
3147 case MQTT_PROP_TYPE_SHORT:
3148 prop->iv = (uint16_t) ((((uint16_t) i[0]) << 8) | i[1]);
3149 new_pos += sizeof(uint16_t);
3151 case MQTT_PROP_TYPE_INT:
3152 prop->iv = ((uint32_t) i[0] << 24) | ((uint32_t) i[1] << 16) |
3153 ((uint32_t) i[2] << 8) | i[3];
3154 new_pos += sizeof(uint32_t);
3156 case MQTT_PROP_TYPE_STRING:
3157 prop->val.len = (uint16_t) ((((uint16_t) i[0]) << 8) | i[1]);
3158 prop->val.ptr = (char *) i + 2;
3159 new_pos += 2 + prop->val.len;
3161 case MQTT_PROP_TYPE_BINARY_DATA:
3162 prop->val.len = (uint16_t) ((((uint16_t) i[0]) << 8) | i[1]);
3163 prop->val.ptr = (char *) i + 2;
3164 new_pos += 2 + prop->val.len;
3166 case MQTT_PROP_TYPE_VARIABLE_INT:
3167 prop->iv = decode_variable_length((char *) i, &bytes_consumed);
3168 new_pos += bytes_consumed;
3170 default: new_pos = 0;
3176 void mg_mqtt_login(struct mg_connection *c, const struct mg_mqtt_opts *opts) {
3177 char rnd[10], client_id[21];
3178 struct mg_str cid = opts->client_id;
3179 size_t total_len = 7 + 1 + 2 + 2;
3180 uint8_t hdr[8] = {0, 4, 'M', 'Q', 'T', 'T', opts->version, 0};
3183 mg_random(rnd, sizeof(rnd));
3184 mg_hex(rnd, sizeof(rnd), client_id);
3185 client_id[sizeof(client_id) - 1] = '\0';
3186 cid = mg_str(client_id);
3189 if (hdr[6] == 0) hdr[6] = 4; // If version is not set, use 4 (3.1.1)
3190 c->is_mqtt5 = hdr[6] == 5; // Set version 5 flag
3191 hdr[7] = (uint8_t) ((opts->qos & 3) << 3); // Connection flags
3192 if (opts->user.len > 0) {
3193 total_len += 2 + (uint32_t) opts->user.len;
3194 hdr[7] |= MQTT_HAS_USER_NAME;
3196 if (opts->pass.len > 0) {
3197 total_len += 2 + (uint32_t) opts->pass.len;
3198 hdr[7] |= MQTT_HAS_PASSWORD;
3200 if (opts->topic.len > 0 && opts->message.len > 0) {
3201 total_len += 4 + (uint32_t) opts->topic.len + (uint32_t) opts->message.len;
3202 hdr[7] |= MQTT_HAS_WILL;
3204 if (opts->clean || cid.len == 0) hdr[7] |= MQTT_CLEAN_SESSION;
3205 if (opts->retain) hdr[7] |= MQTT_WILL_RETAIN;
3206 total_len += (uint32_t) cid.len;
3208 total_len += get_props_size(opts->props, opts->num_props);
3209 if (hdr[7] & MQTT_HAS_WILL)
3210 total_len += get_props_size(opts->will_props, opts->num_will_props);
3213 mg_mqtt_send_header(c, MQTT_CMD_CONNECT, 0, (uint32_t) total_len);
3214 mg_send(c, hdr, sizeof(hdr));
3215 // keepalive == 0 means "do not disconnect us!"
3216 mg_send_u16(c, mg_htons((uint16_t) opts->keepalive));
3218 if (c->is_mqtt5) mg_send_mqtt_properties(c, opts->props, opts->num_props);
3220 mg_send_u16(c, mg_htons((uint16_t) cid.len));
3221 mg_send(c, cid.ptr, cid.len);
3223 if (hdr[7] & MQTT_HAS_WILL) {
3225 mg_send_mqtt_properties(c, opts->will_props, opts->num_will_props);
3227 mg_send_u16(c, mg_htons((uint16_t) opts->topic.len));
3228 mg_send(c, opts->topic.ptr, opts->topic.len);
3229 mg_send_u16(c, mg_htons((uint16_t) opts->message.len));
3230 mg_send(c, opts->message.ptr, opts->message.len);
3232 if (opts->user.len > 0) {
3233 mg_send_u16(c, mg_htons((uint16_t) opts->user.len));
3234 mg_send(c, opts->user.ptr, opts->user.len);
3236 if (opts->pass.len > 0) {
3237 mg_send_u16(c, mg_htons((uint16_t) opts->pass.len));
3238 mg_send(c, opts->pass.ptr, opts->pass.len);
3242 void mg_mqtt_pub(struct mg_connection *c, const struct mg_mqtt_opts *opts) {
3243 uint8_t flags = (uint8_t) (((opts->qos & 3) << 1) | (opts->retain ? 1 : 0));
3244 size_t len = 2 + opts->topic.len + opts->message.len;
3245 MG_DEBUG(("%lu [%.*s] -> [%.*s]", c->id, (int) opts->topic.len,
3246 (char *) opts->topic.ptr, (int) opts->message.len,
3247 (char *) opts->message.ptr));
3248 if (opts->qos > 0) len += 2;
3249 if (c->is_mqtt5) len += get_props_size(opts->props, opts->num_props);
3251 mg_mqtt_send_header(c, MQTT_CMD_PUBLISH, flags, (uint32_t) len);
3252 mg_send_u16(c, mg_htons((uint16_t) opts->topic.len));
3253 mg_send(c, opts->topic.ptr, opts->topic.len);
3254 if (opts->qos > 0) {
3255 if (++c->mgr->mqtt_id == 0) ++c->mgr->mqtt_id;
3256 mg_send_u16(c, mg_htons(c->mgr->mqtt_id));
3259 if (c->is_mqtt5) mg_send_mqtt_properties(c, opts->props, opts->num_props);
3261 mg_send(c, opts->message.ptr, opts->message.len);
3264 void mg_mqtt_sub(struct mg_connection *c, const struct mg_mqtt_opts *opts) {
3265 uint8_t qos_ = opts->qos & 3;
3266 size_t plen = c->is_mqtt5 ? get_props_size(opts->props, opts->num_props) : 0;
3267 size_t len = 2 + opts->topic.len + 2 + 1 + plen;
3269 mg_mqtt_send_header(c, MQTT_CMD_SUBSCRIBE, 2, (uint32_t) len);
3270 if (++c->mgr->mqtt_id == 0) ++c->mgr->mqtt_id;
3271 mg_send_u16(c, mg_htons(c->mgr->mqtt_id));
3272 if (c->is_mqtt5) mg_send_mqtt_properties(c, opts->props, opts->num_props);
3274 mg_send_u16(c, mg_htons((uint16_t) opts->topic.len));
3275 mg_send(c, opts->topic.ptr, opts->topic.len);
3276 mg_send(c, &qos_, sizeof(qos_));
3279 int mg_mqtt_parse(const uint8_t *buf, size_t len, uint8_t version,
3280 struct mg_mqtt_message *m) {
3281 uint8_t lc = 0, *p, *end;
3282 uint32_t n = 0, len_len = 0;
3284 memset(m, 0, sizeof(*m));
3285 m->dgram.ptr = (char *) buf;
3286 if (len < 2) return MQTT_INCOMPLETE;
3287 m->cmd = (uint8_t) (buf[0] >> 4);
3288 m->qos = (buf[0] >> 1) & 3;
3291 p = (uint8_t *) buf + 1;
3292 while ((size_t) (p - buf) < len) {
3293 lc = *((uint8_t *) p++);
3294 n += (uint32_t) ((lc & 0x7f) << 7 * len_len);
3296 if (!(lc & 0x80)) break;
3297 if (len_len >= 4) return MQTT_MALFORMED;
3300 if ((lc & 0x80) || (end > buf + len)) return MQTT_INCOMPLETE;
3301 m->dgram.len = (size_t) (end - buf);
3304 case MQTT_CMD_CONNACK:
3305 if (end - p < 2) return MQTT_MALFORMED;
3308 case MQTT_CMD_PUBACK:
3309 case MQTT_CMD_PUBREC:
3310 case MQTT_CMD_PUBREL:
3311 case MQTT_CMD_PUBCOMP:
3312 case MQTT_CMD_SUBSCRIBE:
3313 case MQTT_CMD_SUBACK:
3314 case MQTT_CMD_UNSUBSCRIBE:
3315 case MQTT_CMD_UNSUBACK:
3316 if (p + 2 > end) return MQTT_MALFORMED;
3317 m->id = (uint16_t) ((((uint16_t) p[0]) << 8) | p[1]);
3320 case MQTT_CMD_PUBLISH: {
3321 if (p + 2 > end) return MQTT_MALFORMED;
3322 m->topic.len = (uint16_t) ((((uint16_t) p[0]) << 8) | p[1]);
3323 m->topic.ptr = (char *) p + 2;
3324 p += 2 + m->topic.len;
3325 if (p > end) return MQTT_MALFORMED;
3327 if (p + 2 > end) return MQTT_MALFORMED;
3328 m->id = (uint16_t) ((((uint16_t) p[0]) << 8) | p[1]);
3331 if (p > end) return MQTT_MALFORMED;
3332 if (version == 5 && p + 2 < end) {
3333 m->props_size = decode_variable_length((char *) p, &len_len);
3334 m->props_start = (size_t) (p + len_len - buf);
3335 p += len_len + m->props_size;
3337 if (p > end) return MQTT_MALFORMED;
3338 m->data.ptr = (char *) p;
3339 m->data.len = (size_t) (end - p);
3347 static void mqtt_cb(struct mg_connection *c, int ev, void *ev_data,
3349 if (ev == MG_EV_READ) {
3351 uint8_t version = c->is_mqtt5 ? 5 : 4;
3352 struct mg_mqtt_message mm;
3353 int rc = mg_mqtt_parse(c->recv.buf, c->recv.len, version, &mm);
3354 if (rc == MQTT_MALFORMED) {
3355 MG_ERROR(("%lu MQTT malformed message", c->id));
3358 } else if (rc == MQTT_OK) {
3359 MG_VERBOSE(("%lu MQTT CMD %d len %d [%.*s]", c->id, mm.cmd,
3360 (int) mm.dgram.len, (int) mm.data.len, mm.data.ptr));
3362 case MQTT_CMD_CONNACK:
3363 mg_call(c, MG_EV_MQTT_OPEN, &mm.ack);
3365 MG_DEBUG(("%lu Connected", c->id));
3367 MG_ERROR(("%lu MQTT auth failed, code %d", c->id, mm.ack));
3371 case MQTT_CMD_PUBLISH: {
3372 MG_DEBUG(("%lu [%.*s] -> [%.*s]", c->id, (int) mm.topic.len,
3373 mm.topic.ptr, (int) mm.data.len, mm.data.ptr));
3375 uint16_t id = mg_htons(mm.id);
3376 uint32_t remaining_len = sizeof(id);
3377 if (c->is_mqtt5) remaining_len += 1;
3379 mg_mqtt_send_header(c, MQTT_CMD_PUBACK, 0, remaining_len);
3380 mg_send(c, &id, sizeof(id));
3384 mg_send(c, &zero, sizeof(zero));
3387 mg_call(c, MG_EV_MQTT_MSG, &mm);
3391 mg_call(c, MG_EV_MQTT_CMD, &mm);
3392 mg_iobuf_del(&c->recv, 0, mm.dgram.len);
3402 void mg_mqtt_ping(struct mg_connection *nc) {
3403 mg_mqtt_send_header(nc, MQTT_CMD_PINGREQ, 0, 0);
3406 void mg_mqtt_pong(struct mg_connection *nc) {
3407 mg_mqtt_send_header(nc, MQTT_CMD_PINGRESP, 0, 0);
3410 void mg_mqtt_disconnect(struct mg_connection *c,
3411 const struct mg_mqtt_opts *opts) {
3413 if (c->is_mqtt5) len = 1 + get_props_size(opts->props, opts->num_props);
3414 mg_mqtt_send_header(c, MQTT_CMD_DISCONNECT, 0, (uint32_t) len);
3418 mg_send(c, &zero, sizeof(zero)); // reason code
3419 mg_send_mqtt_properties(c, opts->props, opts->num_props);
3423 struct mg_connection *mg_mqtt_connect(struct mg_mgr *mgr, const char *url,
3424 const struct mg_mqtt_opts *opts,
3425 mg_event_handler_t fn, void *fn_data) {
3426 struct mg_connection *c = mg_connect(mgr, url, fn, fn_data);
3428 struct mg_mqtt_opts empty;
3429 memset(&empty, 0, sizeof(empty));
3430 mg_mqtt_login(c, opts == NULL ? &empty : opts);
3436 struct mg_connection *mg_mqtt_listen(struct mg_mgr *mgr, const char *url,
3437 mg_event_handler_t fn, void *fn_data) {
3438 struct mg_connection *c = mg_listen(mgr, url, fn, fn_data);
3439 if (c != NULL) c->pfn = mqtt_cb, c->pfn_data = mgr;
3443 #ifdef MG_ENABLE_LINES
3454 size_t mg_vprintf(struct mg_connection *c, const char *fmt, va_list *ap) {
3455 size_t old = c->send.len;
3456 mg_vxprintf(mg_pfn_iobuf, &c->send, fmt, ap);
3457 return c->send.len - old;
3460 size_t mg_printf(struct mg_connection *c, const char *fmt, ...) {
3464 len = mg_vprintf(c, fmt, &ap);
3469 static bool mg_atonl(struct mg_str str, struct mg_addr *addr) {
3470 if (mg_vcasecmp(&str, "localhost") != 0) return false;
3471 addr->ip = mg_htonl(0x7f000001);
3472 addr->is_ip6 = false;
3476 static bool mg_atone(struct mg_str str, struct mg_addr *addr) {
3477 if (str.len > 0) return false;
3479 addr->is_ip6 = false;
3483 static bool mg_aton4(struct mg_str str, struct mg_addr *addr) {
3484 uint8_t data[4] = {0, 0, 0, 0};
3485 size_t i, num_dots = 0;
3486 for (i = 0; i < str.len; i++) {
3487 if (str.ptr[i] >= '0' && str.ptr[i] <= '9') {
3488 int octet = data[num_dots] * 10 + (str.ptr[i] - '0');
3489 if (octet > 255) return false;
3490 data[num_dots] = (uint8_t) octet;
3491 } else if (str.ptr[i] == '.') {
3492 if (num_dots >= 3 || i == 0 || str.ptr[i - 1] == '.') return false;
3498 if (num_dots != 3 || str.ptr[i - 1] == '.') return false;
3499 memcpy(&addr->ip, data, sizeof(data));
3500 addr->is_ip6 = false;
3504 static bool mg_v4mapped(struct mg_str str, struct mg_addr *addr) {
3506 if (str.len < 14) return false;
3507 if (str.ptr[0] != ':' || str.ptr[1] != ':' || str.ptr[6] != ':') return false;
3508 for (i = 2; i < 6; i++) {
3509 if (str.ptr[i] != 'f' && str.ptr[i] != 'F') return false;
3511 if (!mg_aton4(mg_str_n(&str.ptr[7], str.len - 7), addr)) return false;
3512 memset(addr->ip6, 0, sizeof(addr->ip6));
3513 addr->ip6[10] = addr->ip6[11] = 255;
3514 memcpy(&addr->ip6[12], &addr->ip, 4);
3515 addr->is_ip6 = true;
3519 static bool mg_aton6(struct mg_str str, struct mg_addr *addr) {
3520 size_t i, j = 0, n = 0, dc = 42;
3521 if (str.len > 2 && str.ptr[0] == '[') str.ptr++, str.len -= 2;
3522 if (mg_v4mapped(str, addr)) return true;
3523 for (i = 0; i < str.len; i++) {
3524 if ((str.ptr[i] >= '0' && str.ptr[i] <= '9') ||
3525 (str.ptr[i] >= 'a' && str.ptr[i] <= 'f') ||
3526 (str.ptr[i] >= 'A' && str.ptr[i] <= 'F')) {
3528 if (i > j + 3) return false;
3529 // MG_DEBUG(("%zu %zu [%.*s]", i, j, (int) (i - j + 1), &str.ptr[j]));
3530 val = mg_unhexn(&str.ptr[j], i - j + 1);
3531 addr->ip6[n] = (uint8_t) ((val >> 8) & 255);
3532 addr->ip6[n + 1] = (uint8_t) (val & 255);
3533 } else if (str.ptr[i] == ':') {
3535 if (i > 0 && str.ptr[i - 1] == ':') {
3536 dc = n; // Double colon
3537 if (i > 1 && str.ptr[i - 2] == ':') return false;
3541 if (n > 14) return false;
3542 addr->ip6[n] = addr->ip6[n + 1] = 0; // For trailing ::
3547 if (n < 14 && dc == 42) return false;
3549 memmove(&addr->ip6[dc + (14 - n)], &addr->ip6[dc], n - dc + 2);
3550 memset(&addr->ip6[dc], 0, 14 - n);
3552 addr->is_ip6 = true;
3556 bool mg_aton(struct mg_str str, struct mg_addr *addr) {
3557 // MG_INFO(("[%.*s]", (int) str.len, str.ptr));
3558 return mg_atone(str, addr) || mg_atonl(str, addr) || mg_aton4(str, addr) ||
3559 mg_aton6(str, addr);
3562 struct mg_connection *mg_alloc_conn(struct mg_mgr *mgr) {
3563 struct mg_connection *c =
3564 (struct mg_connection *) calloc(1, sizeof(*c) + mgr->extraconnsize);
3567 c->send.align = c->recv.align = MG_IO_SIZE;
3568 c->id = ++mgr->nextid;
3573 void mg_close_conn(struct mg_connection *c) {
3574 mg_resolve_cancel(c); // Close any pending DNS query
3575 LIST_DELETE(struct mg_connection, &c->mgr->conns, c);
3576 if (c == c->mgr->dns4.c) c->mgr->dns4.c = NULL;
3577 if (c == c->mgr->dns6.c) c->mgr->dns6.c = NULL;
3578 // Order of operations is important. `MG_EV_CLOSE` event must be fired
3579 // before we deallocate received data, see #1331
3580 mg_call(c, MG_EV_CLOSE, NULL);
3581 MG_DEBUG(("%lu %p closed", c->id, c->fd));
3584 mg_iobuf_free(&c->recv);
3585 mg_iobuf_free(&c->send);
3586 memset(c, 0, sizeof(*c));
3590 struct mg_connection *mg_connect(struct mg_mgr *mgr, const char *url,
3591 mg_event_handler_t fn, void *fn_data) {
3592 struct mg_connection *c = NULL;
3593 if (url == NULL || url[0] == '\0') {
3594 MG_ERROR(("null url"));
3595 } else if ((c = mg_alloc_conn(mgr)) == NULL) {
3598 LIST_ADD_HEAD(struct mg_connection, &mgr->conns, c);
3599 c->is_udp = (strncmp(url, "udp:", 4) == 0);
3600 c->fd = (void *) (size_t) MG_INVALID_SOCKET;
3602 c->is_client = true;
3603 c->fn_data = fn_data;
3604 MG_DEBUG(("%lu %p %s", c->id, c->fd, url));
3605 mg_call(c, MG_EV_OPEN, NULL);
3611 struct mg_connection *mg_listen(struct mg_mgr *mgr, const char *url,
3612 mg_event_handler_t fn, void *fn_data) {
3613 struct mg_connection *c = NULL;
3614 if ((c = mg_alloc_conn(mgr)) == NULL) {
3615 MG_ERROR(("OOM %s", url));
3616 } else if (!mg_open_listener(c, url)) {
3617 MG_ERROR(("Failed: %s, errno %d", url, errno));
3621 c->is_listening = 1;
3622 c->is_udp = strncmp(url, "udp:", 4) == 0;
3623 LIST_ADD_HEAD(struct mg_connection, &mgr->conns, c);
3625 c->fn_data = fn_data;
3626 mg_call(c, MG_EV_OPEN, NULL);
3627 MG_DEBUG(("%lu %p %s", c->id, c->fd, url));
3632 struct mg_connection *mg_wrapfd(struct mg_mgr *mgr, int fd,
3633 mg_event_handler_t fn, void *fn_data) {
3634 struct mg_connection *c = mg_alloc_conn(mgr);
3636 c->fd = (void *) (size_t) fd;
3638 c->fn_data = fn_data;
3640 mg_call(c, MG_EV_OPEN, NULL);
3641 LIST_ADD_HEAD(struct mg_connection, &mgr->conns, c);
3646 struct mg_timer *mg_timer_add(struct mg_mgr *mgr, uint64_t milliseconds,
3647 unsigned flags, void (*fn)(void *), void *arg) {
3648 struct mg_timer *t = (struct mg_timer *) calloc(1, sizeof(*t));
3650 mg_timer_init(&mgr->timers, t, milliseconds, flags, fn, arg);
3651 t->id = mgr->timerid++;
3656 void mg_mgr_free(struct mg_mgr *mgr) {
3657 struct mg_connection *c;
3658 struct mg_timer *tmp, *t = mgr->timers;
3659 while (t != NULL) tmp = t->next, free(t), t = tmp;
3660 mgr->timers = NULL; // Important. Next call to poll won't touch timers
3661 for (c = mgr->conns; c != NULL; c = c->next) c->is_closing = 1;
3662 mg_mgr_poll(mgr, 0);
3663 #if MG_ENABLE_FREERTOS_TCP
3664 FreeRTOS_DeleteSocketSet(mgr->ss);
3666 MG_DEBUG(("All connections closed"));
3668 if (mgr->epoll_fd >= 0) close(mgr->epoll_fd), mgr->epoll_fd = -1;
3672 void mg_mgr_init(struct mg_mgr *mgr) {
3673 memset(mgr, 0, sizeof(*mgr));
3675 if ((mgr->epoll_fd = epoll_create1(0)) < 0) MG_ERROR(("epoll: %d", errno));
3679 #if MG_ARCH == MG_ARCH_WIN32 && MG_ENABLE_WINSOCK
3681 { WSADATA data; WSAStartup(MAKEWORD(2, 2), &data); }
3683 #elif MG_ENABLE_FREERTOS_TCP
3684 mgr->ss = FreeRTOS_CreateSocketSet();
3685 #elif defined(__unix) || defined(__unix__) || defined(__APPLE__)
3686 // Ignore SIGPIPE signal, so if client cancels the request, it
3687 // won't kill the whole process.
3688 signal(SIGPIPE, SIG_IGN);
3690 mgr->dnstimeout = 3000;
3691 mgr->dns4.url = "udp://8.8.8.8:53";
3692 mgr->dns6.url = "udp://[2001:4860:4860::8888]:53";
3695 #ifdef MG_ENABLE_LINES
3696 #line 1 "src/printf.c"
3702 size_t mg_queue_vprintf(struct mg_queue *q, const char *fmt, va_list *ap) {
3703 size_t len = mg_snprintf(NULL, 0, fmt, ap);
3705 if (len == 0 || mg_queue_book(q, &buf, len + 1) < len + 1) {
3706 len = 0; // Nah. Not enough space
3708 len = mg_vsnprintf((char *) buf, len + 1, fmt, ap);
3709 mg_queue_add(q, len);
3714 size_t mg_queue_printf(struct mg_queue *q, const char *fmt, ...) {
3718 len = mg_queue_vprintf(q, fmt, &ap);
3723 static void mg_pfn_iobuf_private(char ch, void *param, bool expand) {
3724 struct mg_iobuf *io = (struct mg_iobuf *) param;
3725 if (expand && io->len + 2 > io->size) mg_iobuf_resize(io, io->len + 2);
3726 if (io->len + 2 <= io->size) {
3727 io->buf[io->len++] = (uint8_t) ch;
3728 io->buf[io->len] = 0;
3729 } else if (io->len < io->size) {
3730 io->buf[io->len++] = 0; // Guarantee to 0-terminate
3734 static void mg_putchar_iobuf_static(char ch, void *param) {
3735 mg_pfn_iobuf_private(ch, param, false);
3738 void mg_pfn_iobuf(char ch, void *param) {
3739 mg_pfn_iobuf_private(ch, param, true);
3742 size_t mg_vsnprintf(char *buf, size_t len, const char *fmt, va_list *ap) {
3743 struct mg_iobuf io = {(uint8_t *) buf, len, 0, 0};
3744 size_t n = mg_vxprintf(mg_putchar_iobuf_static, &io, fmt, ap);
3745 if (n < len) buf[n] = '\0';
3749 size_t mg_snprintf(char *buf, size_t len, const char *fmt, ...) {
3753 n = mg_vsnprintf(buf, len, fmt, &ap);
3758 char *mg_vmprintf(const char *fmt, va_list *ap) {
3759 struct mg_iobuf io = {0, 0, 0, 256};
3760 mg_vxprintf(mg_pfn_iobuf, &io, fmt, ap);
3761 return (char *) io.buf;
3764 char *mg_mprintf(const char *fmt, ...) {
3768 s = mg_vmprintf(fmt, &ap);
3773 void mg_pfn_stdout(char c, void *param) {
3778 static size_t print_ip4(void (*out)(char, void *), void *arg, uint8_t *p) {
3779 return mg_xprintf(out, arg, "%d.%d.%d.%d", p[0], p[1], p[2], p[3]);
3782 static size_t print_ip6(void (*out)(char, void *), void *arg, uint16_t *p) {
3783 return mg_xprintf(out, arg, "[%x:%x:%x:%x:%x:%x:%x:%x]", mg_ntohs(p[0]),
3784 mg_ntohs(p[1]), mg_ntohs(p[2]), mg_ntohs(p[3]),
3785 mg_ntohs(p[4]), mg_ntohs(p[5]), mg_ntohs(p[6]),
3789 size_t mg_print_ip4(void (*out)(char, void *), void *arg, va_list *ap) {
3790 uint8_t *p = va_arg(*ap, uint8_t *);
3791 return print_ip4(out, arg, p);
3794 size_t mg_print_ip6(void (*out)(char, void *), void *arg, va_list *ap) {
3795 uint16_t *p = va_arg(*ap, uint16_t *);
3796 return print_ip6(out, arg, p);
3799 size_t mg_print_ip(void (*out)(char, void *), void *arg, va_list *ap) {
3800 struct mg_addr *addr = va_arg(*ap, struct mg_addr *);
3801 if (addr->is_ip6) return print_ip6(out, arg, (uint16_t *) addr->ip6);
3802 return print_ip4(out, arg, (uint8_t *) &addr->ip);
3805 size_t mg_print_ip_port(void (*out)(char, void *), void *arg, va_list *ap) {
3806 struct mg_addr *a = va_arg(*ap, struct mg_addr *);
3807 return mg_xprintf(out, arg, "%M:%hu", mg_print_ip, a, mg_ntohs(a->port));
3810 size_t mg_print_mac(void (*out)(char, void *), void *arg, va_list *ap) {
3811 uint8_t *p = va_arg(*ap, uint8_t *);
3812 return mg_xprintf(out, arg, "%02x:%02x:%02x:%02x:%02x:%02x", p[0], p[1], p[2],
3816 static char mg_esc(int c, bool esc) {
3817 const char *p, *esc1 = "\b\f\n\r\t\\\"", *esc2 = "bfnrt\\\"";
3818 for (p = esc ? esc1 : esc2; *p != '\0'; p++) {
3819 if (*p == c) return esc ? esc2[p - esc1] : esc1[p - esc2];
3824 static char mg_escape(int c) {
3825 return mg_esc(c, true);
3828 static size_t qcpy(void (*out)(char, void *), void *ptr, char *buf,
3830 size_t i = 0, extra = 0;
3831 for (i = 0; i < len && buf[i] != '\0'; i++) {
3832 char c = mg_escape(buf[i]);
3834 out('\\', ptr), out(c, ptr), extra++;
3842 static size_t bcpy(void (*out)(char, void *), void *arg, uint8_t *buf,
3846 "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
3847 for (i = 0; i < len; i += 3) {
3848 uint8_t c1 = buf[i], c2 = i + 1 < len ? buf[i + 1] : 0,
3849 c3 = i + 2 < len ? buf[i + 2] : 0;
3850 char tmp[4] = {t[c1 >> 2], t[(c1 & 3) << 4 | (c2 >> 4)], '=', '='};
3851 if (i + 1 < len) tmp[2] = t[(c2 & 15) << 2 | (c3 >> 6)];
3852 if (i + 2 < len) tmp[3] = t[c3 & 63];
3853 for (j = 0; j < sizeof(tmp) && tmp[j] != '\0'; j++) out(tmp[j], arg);
3859 size_t mg_print_hex(void (*out)(char, void *), void *arg, va_list *ap) {
3860 size_t bl = (size_t) va_arg(*ap, int);
3861 uint8_t *p = va_arg(*ap, uint8_t *);
3862 const char *hex = "0123456789abcdef";
3864 for (j = 0; j < bl; j++) {
3865 out(hex[(p[j] >> 4) & 0x0F], arg);
3866 out(hex[p[j] & 0x0F], arg);
3870 size_t mg_print_base64(void (*out)(char, void *), void *arg, va_list *ap) {
3871 size_t len = (size_t) va_arg(*ap, int);
3872 uint8_t *buf = va_arg(*ap, uint8_t *);
3873 return bcpy(out, arg, buf, len);
3876 size_t mg_print_esc(void (*out)(char, void *), void *arg, va_list *ap) {
3877 size_t len = (size_t) va_arg(*ap, int);
3878 char *p = va_arg(*ap, char *);
3879 if (len == 0) len = p == NULL ? 0 : strlen(p);
3880 return qcpy(out, arg, p, len);
3883 #ifdef MG_ENABLE_LINES
3884 #line 1 "src/queue.c"
3889 #if defined(__GNUC__) || defined(__clang__)
3890 #define MG_MEMORY_BARRIER() __sync_synchronize()
3891 #elif defined(_MSC_VER) && _MSC_VER >= 1700
3892 #define MG_MEMORY_BARRIER() MemoryBarrier()
3893 #elif !defined(MG_MEMORY_BARRIER)
3894 #define MG_MEMORY_BARRIER()
3897 // Every message in a queue is prepended by a 32-bit message length (ML).
3898 // If ML is 0, then it is the end, and reader must wrap to the beginning.
3900 // Queue when q->tail <= q->head:
3901 // |----- free -----| ML | message1 | ML | message2 | ----- free ------|
3903 // buf tail head len
3905 // Queue when q->tail > q->head:
3906 // | ML | message2 |----- free ------| ML | message1 | 0 |---- free ----|
3908 // buf head tail len
3910 void mg_queue_init(struct mg_queue *q, char *buf, size_t size) {
3913 q->head = q->tail = 0;
3916 static size_t mg_queue_read_len(struct mg_queue *q) {
3918 MG_MEMORY_BARRIER();
3919 memcpy(&n, q->buf + q->tail, sizeof(n));
3920 assert(q->tail + n + sizeof(n) <= q->size);
3924 static void mg_queue_write_len(struct mg_queue *q, size_t len) {
3925 uint32_t n = (uint32_t) len;
3926 memcpy(q->buf + q->head, &n, sizeof(n));
3927 MG_MEMORY_BARRIER();
3930 size_t mg_queue_book(struct mg_queue *q, char **buf, size_t len) {
3931 size_t space = 0, hs = sizeof(uint32_t) * 2; // *2 is for the 0 marker
3932 if (q->head >= q->tail && q->head + len + hs <= q->size) {
3933 space = q->size - q->head - hs; // There is enough space
3934 } else if (q->head >= q->tail && q->tail > hs) {
3935 mg_queue_write_len(q, 0); // Not enough space ahead
3936 q->head = 0; // Wrap head to the beginning
3938 if (q->head + hs + len < q->tail) space = q->tail - q->head - hs;
3939 if (buf != NULL) *buf = q->buf + q->head + sizeof(uint32_t);
3943 size_t mg_queue_next(struct mg_queue *q, char **buf) {
3945 if (q->tail != q->head) {
3946 len = mg_queue_read_len(q);
3947 if (len == 0) { // Zero (head wrapped) ?
3948 q->tail = 0; // Reset tail to the start
3949 if (q->head > q->tail) len = mg_queue_read_len(q); // Read again
3952 if (buf != NULL) *buf = q->buf + q->tail + sizeof(uint32_t);
3953 assert(q->tail + len <= q->size);
3957 void mg_queue_add(struct mg_queue *q, size_t len) {
3959 mg_queue_write_len(q, len);
3960 assert(q->head + sizeof(uint32_t) * 2 + len <= q->size);
3961 q->head += len + sizeof(uint32_t);
3964 void mg_queue_del(struct mg_queue *q, size_t len) {
3965 q->tail += len + sizeof(uint32_t);
3966 assert(q->tail + sizeof(uint32_t) <= q->size);
3969 #ifdef MG_ENABLE_LINES
3975 void mg_rpc_add(struct mg_rpc **head, struct mg_str method,
3976 void (*fn)(struct mg_rpc_req *), void *fn_data) {
3977 struct mg_rpc *rpc = (struct mg_rpc *) calloc(1, sizeof(*rpc));
3979 rpc->method = mg_strdup(method), rpc->fn = fn, rpc->fn_data = fn_data;
3980 rpc->next = *head, *head = rpc;
3984 void mg_rpc_del(struct mg_rpc **head, void (*fn)(struct mg_rpc_req *)) {
3986 while ((r = *head) != NULL) {
3987 if (r->fn == fn || fn == NULL) {
3989 free((void *) r->method.ptr);
3992 head = &(*head)->next;
3997 static void mg_rpc_call(struct mg_rpc_req *r, struct mg_str method) {
3998 struct mg_rpc *h = r->head == NULL ? NULL : *r->head;
3999 while (h != NULL && !mg_match(method, h->method, NULL)) h = h->next;
4004 mg_rpc_err(r, -32601, "\"%.*s not found\"", (int) method.len, method.ptr);
4008 void mg_rpc_process(struct mg_rpc_req *r) {
4009 int len, off = mg_json_get(r->frame, "$.method", &len);
4010 if (off > 0 && r->frame.ptr[off] == '"') {
4011 struct mg_str method = mg_str_n(&r->frame.ptr[off + 1], (size_t) len - 2);
4012 mg_rpc_call(r, method);
4013 } else if ((off = mg_json_get(r->frame, "$.result", &len)) > 0 ||
4014 (off = mg_json_get(r->frame, "$.error", &len)) > 0) {
4015 mg_rpc_call(r, mg_str("")); // JSON response! call "" method handler
4017 mg_rpc_err(r, -32700, "%m", mg_print_esc, (int) r->frame.len,
4018 r->frame.ptr); // Invalid
4022 void mg_rpc_vok(struct mg_rpc_req *r, const char *fmt, va_list *ap) {
4023 int len, off = mg_json_get(r->frame, "$.id", &len);
4025 mg_xprintf(r->pfn, r->pfn_data, "{%m:%.*s,%m:", mg_print_esc, 0, "id", len,
4026 &r->frame.ptr[off], mg_print_esc, 0, "result");
4027 mg_vxprintf(r->pfn, r->pfn_data, fmt == NULL ? "null" : fmt, ap);
4028 mg_xprintf(r->pfn, r->pfn_data, "}");
4032 void mg_rpc_ok(struct mg_rpc_req *r, const char *fmt, ...) {
4035 mg_rpc_vok(r, fmt, &ap);
4039 void mg_rpc_verr(struct mg_rpc_req *r, int code, const char *fmt, va_list *ap) {
4040 int len, off = mg_json_get(r->frame, "$.id", &len);
4041 mg_xprintf(r->pfn, r->pfn_data, "{");
4043 mg_xprintf(r->pfn, r->pfn_data, "%m:%.*s,", mg_print_esc, 0, "id", len,
4044 &r->frame.ptr[off]);
4046 mg_xprintf(r->pfn, r->pfn_data, "%m:{%m:%d,%m:", mg_print_esc, 0, "error",
4047 mg_print_esc, 0, "code", code, mg_print_esc, 0, "message");
4048 mg_vxprintf(r->pfn, r->pfn_data, fmt == NULL ? "null" : fmt, ap);
4049 mg_xprintf(r->pfn, r->pfn_data, "}}");
4052 void mg_rpc_err(struct mg_rpc_req *r, int code, const char *fmt, ...) {
4055 mg_rpc_verr(r, code, fmt, &ap);
4059 static size_t print_methods(mg_pfn_t pfn, void *pfn_data, va_list *ap) {
4060 struct mg_rpc *h, **head = (struct mg_rpc **) va_arg(*ap, void **);
4062 for (h = *head; h != NULL; h = h->next) {
4063 if (h->method.len == 0) continue; // Ignore response handler
4064 len += mg_xprintf(pfn, pfn_data, "%s%m", h == *head ? "" : ",",
4065 mg_print_esc, (int) h->method.len, h->method.ptr);
4070 void mg_rpc_list(struct mg_rpc_req *r) {
4071 mg_rpc_ok(r, "[%M]", print_methods, r->head);
4074 #ifdef MG_ENABLE_LINES
4075 #line 1 "src/sha1.c"
4077 /* Copyright(c) By Steve Reid <steve@edmweb.com> */
4078 /* 100% Public Domain */
4082 union char64long16 {
4083 unsigned char c[64];
4087 #define rol(value, bits) (((value) << (bits)) | ((value) >> (32 - (bits))))
4089 static uint32_t blk0(union char64long16 *block, int i) {
4090 if (MG_BIG_ENDIAN) {
4092 block->l[i] = (rol(block->l[i], 24) & 0xFF00FF00) |
4093 (rol(block->l[i], 8) & 0x00FF00FF);
4098 /* Avoid redefine warning (ARM /usr/include/sys/ucontext.h define R0~R4) */
4107 (block->l[i & 15] = rol(block->l[(i + 13) & 15] ^ block->l[(i + 8) & 15] ^ \
4108 block->l[(i + 2) & 15] ^ block->l[i & 15], \
4110 #define R0(v, w, x, y, z, i) \
4111 z += ((w & (x ^ y)) ^ y) + blk0(block, i) + 0x5A827999 + rol(v, 5); \
4113 #define R1(v, w, x, y, z, i) \
4114 z += ((w & (x ^ y)) ^ y) + blk(i) + 0x5A827999 + rol(v, 5); \
4116 #define R2(v, w, x, y, z, i) \
4117 z += (w ^ x ^ y) + blk(i) + 0x6ED9EBA1 + rol(v, 5); \
4119 #define R3(v, w, x, y, z, i) \
4120 z += (((w | x) & y) | (w & x)) + blk(i) + 0x8F1BBCDC + rol(v, 5); \
4122 #define R4(v, w, x, y, z, i) \
4123 z += (w ^ x ^ y) + blk(i) + 0xCA62C1D6 + rol(v, 5); \
4126 static void mg_sha1_transform(uint32_t state[5],
4127 const unsigned char *buffer) {
4128 uint32_t a, b, c, d, e;
4129 union char64long16 block[1];
4131 memcpy(block, buffer, 64);
4137 R0(a, b, c, d, e, 0);
4138 R0(e, a, b, c, d, 1);
4139 R0(d, e, a, b, c, 2);
4140 R0(c, d, e, a, b, 3);
4141 R0(b, c, d, e, a, 4);
4142 R0(a, b, c, d, e, 5);
4143 R0(e, a, b, c, d, 6);
4144 R0(d, e, a, b, c, 7);
4145 R0(c, d, e, a, b, 8);
4146 R0(b, c, d, e, a, 9);
4147 R0(a, b, c, d, e, 10);
4148 R0(e, a, b, c, d, 11);
4149 R0(d, e, a, b, c, 12);
4150 R0(c, d, e, a, b, 13);
4151 R0(b, c, d, e, a, 14);
4152 R0(a, b, c, d, e, 15);
4153 R1(e, a, b, c, d, 16);
4154 R1(d, e, a, b, c, 17);
4155 R1(c, d, e, a, b, 18);
4156 R1(b, c, d, e, a, 19);
4157 R2(a, b, c, d, e, 20);
4158 R2(e, a, b, c, d, 21);
4159 R2(d, e, a, b, c, 22);
4160 R2(c, d, e, a, b, 23);
4161 R2(b, c, d, e, a, 24);
4162 R2(a, b, c, d, e, 25);
4163 R2(e, a, b, c, d, 26);
4164 R2(d, e, a, b, c, 27);
4165 R2(c, d, e, a, b, 28);
4166 R2(b, c, d, e, a, 29);
4167 R2(a, b, c, d, e, 30);
4168 R2(e, a, b, c, d, 31);
4169 R2(d, e, a, b, c, 32);
4170 R2(c, d, e, a, b, 33);
4171 R2(b, c, d, e, a, 34);
4172 R2(a, b, c, d, e, 35);
4173 R2(e, a, b, c, d, 36);
4174 R2(d, e, a, b, c, 37);
4175 R2(c, d, e, a, b, 38);
4176 R2(b, c, d, e, a, 39);
4177 R3(a, b, c, d, e, 40);
4178 R3(e, a, b, c, d, 41);
4179 R3(d, e, a, b, c, 42);
4180 R3(c, d, e, a, b, 43);
4181 R3(b, c, d, e, a, 44);
4182 R3(a, b, c, d, e, 45);
4183 R3(e, a, b, c, d, 46);
4184 R3(d, e, a, b, c, 47);
4185 R3(c, d, e, a, b, 48);
4186 R3(b, c, d, e, a, 49);
4187 R3(a, b, c, d, e, 50);
4188 R3(e, a, b, c, d, 51);
4189 R3(d, e, a, b, c, 52);
4190 R3(c, d, e, a, b, 53);
4191 R3(b, c, d, e, a, 54);
4192 R3(a, b, c, d, e, 55);
4193 R3(e, a, b, c, d, 56);
4194 R3(d, e, a, b, c, 57);
4195 R3(c, d, e, a, b, 58);
4196 R3(b, c, d, e, a, 59);
4197 R4(a, b, c, d, e, 60);
4198 R4(e, a, b, c, d, 61);
4199 R4(d, e, a, b, c, 62);
4200 R4(c, d, e, a, b, 63);
4201 R4(b, c, d, e, a, 64);
4202 R4(a, b, c, d, e, 65);
4203 R4(e, a, b, c, d, 66);
4204 R4(d, e, a, b, c, 67);
4205 R4(c, d, e, a, b, 68);
4206 R4(b, c, d, e, a, 69);
4207 R4(a, b, c, d, e, 70);
4208 R4(e, a, b, c, d, 71);
4209 R4(d, e, a, b, c, 72);
4210 R4(c, d, e, a, b, 73);
4211 R4(b, c, d, e, a, 74);
4212 R4(a, b, c, d, e, 75);
4213 R4(e, a, b, c, d, 76);
4214 R4(d, e, a, b, c, 77);
4215 R4(c, d, e, a, b, 78);
4216 R4(b, c, d, e, a, 79);
4222 /* Erase working structures. The order of operations is important,
4223 * used to ensure that compiler doesn't optimize those out. */
4224 memset(block, 0, sizeof(block));
4225 a = b = c = d = e = 0;
4233 void mg_sha1_init(mg_sha1_ctx *context) {
4234 context->state[0] = 0x67452301;
4235 context->state[1] = 0xEFCDAB89;
4236 context->state[2] = 0x98BADCFE;
4237 context->state[3] = 0x10325476;
4238 context->state[4] = 0xC3D2E1F0;
4239 context->count[0] = context->count[1] = 0;
4242 void mg_sha1_update(mg_sha1_ctx *context, const unsigned char *data,
4246 j = context->count[0];
4247 if ((context->count[0] += (uint32_t) len << 3) < j) context->count[1]++;
4248 context->count[1] += (uint32_t) (len >> 29);
4250 if ((j + len) > 63) {
4251 memcpy(&context->buffer[j], data, (i = 64 - j));
4252 mg_sha1_transform(context->state, context->buffer);
4253 for (; i + 63 < len; i += 64) {
4254 mg_sha1_transform(context->state, &data[i]);
4259 memcpy(&context->buffer[j], &data[i], len - i);
4262 void mg_sha1_final(unsigned char digest[20], mg_sha1_ctx *context) {
4264 unsigned char finalcount[8], c;
4266 for (i = 0; i < 8; i++) {
4267 finalcount[i] = (unsigned char) ((context->count[(i >= 4 ? 0 : 1)] >>
4268 ((3 - (i & 3)) * 8)) &
4272 mg_sha1_update(context, &c, 1);
4273 while ((context->count[0] & 504) != 448) {
4275 mg_sha1_update(context, &c, 1);
4277 mg_sha1_update(context, finalcount, 8);
4278 for (i = 0; i < 20; i++) {
4280 (unsigned char) ((context->state[i >> 2] >> ((3 - (i & 3)) * 8)) & 255);
4282 memset(context, '\0', sizeof(*context));
4283 memset(&finalcount, '\0', sizeof(finalcount));
4286 #ifdef MG_ENABLE_LINES
4287 #line 1 "src/sntp.c"
4295 #define SNTP_TIME_OFFSET 2208988800U // (1970 - 1900) in seconds
4296 #define SNTP_MAX_FRAC 4294967295.0 // 2 ** 32 - 1
4298 static int64_t gettimestamp(const uint32_t *data) {
4299 uint32_t sec = mg_ntohl(data[0]), frac = mg_ntohl(data[1]);
4300 if (sec) sec -= SNTP_TIME_OFFSET;
4301 return ((int64_t) sec) * 1000 + (int64_t) (frac / SNTP_MAX_FRAC * 1000.0);
4304 int64_t mg_sntp_parse(const unsigned char *buf, size_t len) {
4306 int mode = len > 0 ? buf[0] & 7 : 0;
4307 int version = len > 0 ? (buf[0] >> 3) & 7 : 0;
4309 MG_ERROR(("%s", "corrupt packet"));
4310 } else if (mode != 4 && mode != 5) {
4311 MG_ERROR(("%s", "not a server reply"));
4312 } else if (buf[1] == 0) {
4313 MG_ERROR(("%s", "server sent a kiss of death"));
4314 } else if (version == 4 || version == 3) {
4315 // int64_t ref = gettimestamp((uint32_t *) &buf[16]);
4316 int64_t t0 = gettimestamp((uint32_t *) &buf[24]);
4317 int64_t t1 = gettimestamp((uint32_t *) &buf[32]);
4318 int64_t t2 = gettimestamp((uint32_t *) &buf[40]);
4319 int64_t t3 = (int64_t) mg_millis();
4320 int64_t delta = (t3 - t0) - (t2 - t1);
4321 MG_VERBOSE(("%lld %lld %lld %lld delta:%lld", t0, t1, t2, t3, delta));
4322 res = t2 + delta / 2;
4324 MG_ERROR(("unexpected version: %d", version));
4329 static void sntp_cb(struct mg_connection *c, int ev, void *evd, void *fnd) {
4330 if (ev == MG_EV_READ) {
4331 int64_t milliseconds = mg_sntp_parse(c->recv.buf, c->recv.len);
4332 if (milliseconds > 0) {
4333 MG_INFO(("%lu got time: %lld ms from epoch", c->id, milliseconds));
4334 mg_call(c, MG_EV_SNTP_TIME, (uint64_t *) &milliseconds);
4335 MG_VERBOSE(("%u.%u", (unsigned) (milliseconds / 1000),
4336 (unsigned) (milliseconds % 1000)));
4338 mg_iobuf_del(&c->recv, 0, c->recv.len); // Free receive buffer
4339 } else if (ev == MG_EV_CONNECT) {
4341 } else if (ev == MG_EV_CLOSE) {
4347 void mg_sntp_request(struct mg_connection *c) {
4348 if (c->is_resolving) {
4349 MG_ERROR(("%lu wait until resolved", c->id));
4351 int64_t now = (int64_t) mg_millis(); // Use int64_t, for vc98
4352 uint8_t buf[48] = {0};
4353 uint32_t *t = (uint32_t *) &buf[40];
4354 double frac = ((double) (now % 1000)) / 1000.0 * SNTP_MAX_FRAC;
4355 buf[0] = (0 << 6) | (4 << 3) | 3;
4356 t[0] = mg_htonl((uint32_t) (now / 1000) + SNTP_TIME_OFFSET);
4357 t[1] = mg_htonl((uint32_t) frac);
4358 mg_send(c, buf, sizeof(buf));
4362 struct mg_connection *mg_sntp_connect(struct mg_mgr *mgr, const char *url,
4363 mg_event_handler_t fn, void *fnd) {
4364 struct mg_connection *c = NULL;
4365 if (url == NULL) url = "udp://time.google.com:123";
4366 if ((c = mg_connect(mgr, url, fn, fnd)) != NULL) c->pfn = sntp_cb;
4370 #ifdef MG_ENABLE_LINES
4371 #line 1 "src/sock.c"
4384 #if MG_ENABLE_SOCKET
4387 #define closesocket(x) close(x)
4390 #define FD(c_) ((MG_SOCKET_TYPE) (size_t) (c_)->fd)
4391 #define S2PTR(s_) ((void *) (size_t) (s_))
4393 #ifndef MSG_NONBLOCKING
4394 #define MSG_NONBLOCKING 0
4402 #define MG_SOCK_ERR(errcode) ((errcode) < 0 ? errno : 0)
4405 #ifndef MG_SOCK_INTR
4406 #define MG_SOCK_INTR(fd) (fd == MG_INVALID_SOCKET && MG_SOCK_ERR(-1) == EINTR)
4409 #ifndef MG_SOCK_PENDING
4410 #define MG_SOCK_PENDING(errcode) \
4411 (((errcode) < 0) && (errno == EINPROGRESS || errno == EWOULDBLOCK))
4414 #ifndef MG_SOCK_RESET
4415 #define MG_SOCK_RESET(errcode) \
4416 (((errcode) < 0) && (errno == EPIPE || errno == ECONNRESET))
4421 struct sockaddr_in sin;
4423 struct sockaddr_in6 sin6;
4427 static socklen_t tousa(struct mg_addr *a, union usa *usa) {
4428 socklen_t len = sizeof(usa->sin);
4429 memset(usa, 0, sizeof(*usa));
4430 usa->sin.sin_family = AF_INET;
4431 usa->sin.sin_port = a->port;
4432 *(uint32_t *) &usa->sin.sin_addr = a->ip;
4435 usa->sin.sin_family = AF_INET6;
4436 usa->sin6.sin6_port = a->port;
4437 memcpy(&usa->sin6.sin6_addr, a->ip6, sizeof(a->ip6));
4438 len = sizeof(usa->sin6);
4444 static void tomgaddr(union usa *usa, struct mg_addr *a, bool is_ip6) {
4446 a->port = usa->sin.sin_port;
4447 memcpy(&a->ip, &usa->sin.sin_addr, sizeof(a->ip));
4450 memcpy(a->ip6, &usa->sin6.sin6_addr, sizeof(a->ip6));
4451 a->port = usa->sin6.sin6_port;
4456 static void setlocaddr(MG_SOCKET_TYPE fd, struct mg_addr *addr) {
4458 socklen_t n = sizeof(usa);
4459 if (getsockname(fd, &usa.sa, &n) == 0) {
4460 tomgaddr(&usa, addr, n != sizeof(usa.sin));
4464 static void iolog(struct mg_connection *c, char *buf, long n, bool r) {
4465 if (n == MG_IO_WAIT) {
4467 } else if (n <= 0) {
4468 c->is_closing = 1; // Termination. Don't call mg_error(): #1529
4470 if (c->is_hexdumping) {
4472 socklen_t slen = sizeof(usa.sin);
4473 if (getsockname(FD(c), &usa.sa, &slen) < 0) (void) 0; // Ignore result
4474 MG_INFO(("\n-- %lu %M %s %M %ld", c->id, mg_print_ip_port, &c->loc,
4475 r ? "<-" : "->", mg_print_ip_port, &c->rem, n));
4477 mg_hexdump(buf, (size_t) n);
4480 c->recv.len += (size_t) n;
4481 mg_call(c, MG_EV_READ, &n);
4483 mg_iobuf_del(&c->send, 0, (size_t) n);
4484 // if (c->send.len == 0) mg_iobuf_resize(&c->send, 0);
4485 if (c->send.len == 0) {
4488 mg_call(c, MG_EV_WRITE, &n);
4493 long mg_io_send(struct mg_connection *c, const void *buf, size_t len) {
4497 socklen_t slen = tousa(&c->rem, &usa);
4498 n = sendto(FD(c), (char *) buf, len, 0, &usa.sa, slen);
4499 if (n > 0) setlocaddr(FD(c), &c->loc);
4501 n = send(FD(c), (char *) buf, len, MSG_NONBLOCKING);
4503 if (MG_SOCK_PENDING(n)) return MG_IO_WAIT;
4504 if (MG_SOCK_RESET(n)) return MG_IO_RESET;
4505 if (n <= 0) return MG_IO_ERR;
4509 bool mg_send(struct mg_connection *c, const void *buf, size_t len) {
4511 long n = mg_io_send(c, buf, len);
4512 MG_DEBUG(("%lu %p %d:%d %ld err %d", c->id, c->fd, (int) c->send.len,
4513 (int) c->recv.len, n, MG_SOCK_ERR(n)));
4514 iolog(c, (char *) buf, n, false);
4517 return mg_iobuf_add(&c->send, c->send.len, buf, len);
4521 static void mg_set_non_blocking_mode(MG_SOCKET_TYPE fd) {
4522 #if defined(MG_CUSTOM_NONBLOCK)
4523 MG_CUSTOM_NONBLOCK(fd);
4524 #elif MG_ARCH == MG_ARCH_WIN32 && MG_ENABLE_WINSOCK
4525 unsigned long on = 1;
4526 ioctlsocket(fd, FIONBIO, &on);
4528 unsigned long on = 1;
4529 ioctlsocket(fd, FIONBIO, &on);
4530 #elif MG_ENABLE_FREERTOS_TCP
4531 const BaseType_t off = 0;
4532 if (setsockopt(fd, 0, FREERTOS_SO_RCVTIMEO, &off, sizeof(off)) != 0) (void) 0;
4533 if (setsockopt(fd, 0, FREERTOS_SO_SNDTIMEO, &off, sizeof(off)) != 0) (void) 0;
4534 #elif MG_ENABLE_LWIP
4535 lwip_fcntl(fd, F_SETFL, O_NONBLOCK);
4536 #elif MG_ARCH == MG_ARCH_AZURERTOS
4537 fcntl(fd, F_SETFL, O_NONBLOCK);
4538 #elif MG_ARCH == MG_ARCH_TIRTOS
4540 setsockopt(fd, SOL_SOCKET, SO_BLOCKING, &val, sizeof(val));
4541 // SPRU524J section 3.3.3 page 63, SO_SNDLOWAT
4542 int sz = sizeof(val);
4543 getsockopt(fd, SOL_SOCKET, SO_SNDBUF, &val, &sz);
4544 val /= 2; // set send low-water mark at half send buffer size
4545 setsockopt(fd, SOL_SOCKET, SO_SNDLOWAT, &val, sizeof(val));
4547 fcntl(fd, F_SETFL, fcntl(fd, F_GETFL, 0) | O_NONBLOCK); // Non-blocking mode
4548 fcntl(fd, F_SETFD, FD_CLOEXEC); // Set close-on-exec
4552 bool mg_open_listener(struct mg_connection *c, const char *url) {
4553 MG_SOCKET_TYPE fd = MG_INVALID_SOCKET;
4554 bool success = false;
4555 c->loc.port = mg_htons(mg_url_port(url));
4556 if (!mg_aton(mg_url_host(url), &c->loc)) {
4557 MG_ERROR(("invalid listening URL: %s", url));
4560 socklen_t slen = tousa(&c->loc, &usa);
4561 int rc, on = 1, af = c->loc.is_ip6 ? AF_INET6 : AF_INET;
4562 int type = strncmp(url, "udp:", 4) == 0 ? SOCK_DGRAM : SOCK_STREAM;
4563 int proto = type == SOCK_DGRAM ? IPPROTO_UDP : IPPROTO_TCP;
4566 if ((fd = socket(af, type, proto)) == MG_INVALID_SOCKET) {
4567 MG_ERROR(("socket: %d", MG_SOCK_ERR(-1)));
4568 #if defined(SO_EXCLUSIVEADDRUSE)
4569 } else if ((rc = setsockopt(fd, SOL_SOCKET, SO_EXCLUSIVEADDRUSE,
4570 (char *) &on, sizeof(on))) != 0) {
4571 // "Using SO_REUSEADDR and SO_EXCLUSIVEADDRUSE"
4572 MG_ERROR(("setsockopt(SO_EXCLUSIVEADDRUSE): %d %d", on, MG_SOCK_ERR(rc)));
4573 #elif defined(SO_REUSEADDR) && (!defined(LWIP_SOCKET) || SO_REUSE)
4574 } else if ((rc = setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, (char *) &on,
4575 sizeof(on))) != 0) {
4576 // 1. SO_REUSEADDR semantics on UNIX and Windows is different. On
4577 // Windows, SO_REUSEADDR allows to bind a socket to a port without error
4578 // even if the port is already open by another program. This is not the
4579 // behavior SO_REUSEADDR was designed for, and leads to hard-to-track
4580 // failure scenarios.
4582 // 2. For LWIP, SO_REUSEADDR should be explicitly enabled by defining
4583 // SO_REUSE = 1 in lwipopts.h, otherwise the code below will compile but
4584 // won't work! (setsockopt will return EINVAL)
4585 MG_ERROR(("setsockopt(SO_REUSEADDR): %d", MG_SOCK_ERR(rc)));
4587 #if defined(IPV6_V6ONLY)
4588 } else if (c->loc.is_ip6 &&
4589 (rc = setsockopt(fd, IPPROTO_IPV6, IPV6_V6ONLY, (char *) &on,
4590 sizeof(on))) != 0) {
4591 // See #2089. Allow to bind v4 and v6 sockets on the same port
4592 MG_ERROR(("setsockopt(IPV6_V6ONLY): %d", MG_SOCK_ERR(rc)));
4594 } else if ((rc = bind(fd, &usa.sa, slen)) != 0) {
4595 MG_ERROR(("bind: %d", MG_SOCK_ERR(rc)));
4596 } else if ((type == SOCK_STREAM &&
4597 (rc = listen(fd, MG_SOCK_LISTEN_BACKLOG_SIZE)) != 0)) {
4598 // NOTE(lsm): FreeRTOS uses backlog value as a connection limit
4599 // In case port was set to 0, get the real port number
4600 MG_ERROR(("listen: %d", MG_SOCK_ERR(rc)));
4602 setlocaddr(fd, &c->loc);
4603 mg_set_non_blocking_mode(fd);
4609 if (success == false && fd != MG_INVALID_SOCKET) closesocket(fd);
4613 long mg_io_recv(struct mg_connection *c, void *buf, size_t len) {
4617 socklen_t slen = tousa(&c->rem, &usa);
4618 n = recvfrom(FD(c), (char *) buf, len, 0, &usa.sa, &slen);
4619 if (n > 0) tomgaddr(&usa, &c->rem, slen != sizeof(usa.sin));
4621 n = recv(FD(c), (char *) buf, len, MSG_NONBLOCKING);
4623 if (MG_SOCK_PENDING(n)) return MG_IO_WAIT;
4624 if (MG_SOCK_RESET(n)) return MG_IO_RESET;
4625 if (n <= 0) return MG_IO_ERR;
4629 // NOTE(lsm): do only one iteration of reads, cause some systems
4630 // (e.g. FreeRTOS stack) return 0 instead of -1/EWOULDBLOCK when no data
4631 static void read_conn(struct mg_connection *c) {
4633 if (c->recv.len >= MG_MAX_RECV_SIZE) {
4634 mg_error(c, "max_recv_buf_size reached");
4635 } else if (c->recv.size <= c->recv.len &&
4636 !mg_iobuf_resize(&c->recv, c->recv.size + MG_IO_SIZE)) {
4639 char *buf = (char *) &c->recv.buf[c->recv.len];
4640 size_t len = c->recv.size - c->recv.len;
4641 n = c->is_tls ? mg_tls_recv(c, buf, len) : mg_io_recv(c, buf, len);
4642 MG_DEBUG(("%lu %p snd %ld/%ld rcv %ld/%ld n=%ld err=%d", c->id, c->fd,
4643 (long) c->send.len, (long) c->send.size, (long) c->recv.len,
4644 (long) c->recv.size, n, MG_SOCK_ERR(n)));
4645 iolog(c, buf, n, true);
4649 static void write_conn(struct mg_connection *c) {
4650 char *buf = (char *) c->send.buf;
4651 size_t len = c->send.len;
4652 long n = c->is_tls ? mg_tls_send(c, buf, len) : mg_io_send(c, buf, len);
4653 MG_DEBUG(("%lu %p snd %ld/%ld rcv %ld/%ld n=%ld err=%d", c->id, c->fd,
4654 (long) c->send.len, (long) c->send.size, (long) c->recv.len,
4655 (long) c->recv.size, n, MG_SOCK_ERR(n)));
4656 iolog(c, buf, n, false);
4659 static void close_conn(struct mg_connection *c) {
4660 if (FD(c) != MG_INVALID_SOCKET) {
4662 epoll_ctl(c->mgr->epoll_fd, EPOLL_CTL_DEL, FD(c), NULL);
4665 #if MG_ENABLE_FREERTOS_TCP
4666 FreeRTOS_FD_CLR(c->fd, c->mgr->ss, eSELECT_ALL);
4672 static void connect_conn(struct mg_connection *c) {
4674 socklen_t n = sizeof(usa);
4675 // Use getpeername() to test whether we have connected
4676 if (getpeername(FD(c), &usa.sa, &n) == 0) {
4677 c->is_connecting = 0;
4678 mg_call(c, MG_EV_CONNECT, NULL);
4680 if (c->is_tls_hs) mg_tls_handshake(c);
4682 mg_error(c, "socket error");
4686 static void setsockopts(struct mg_connection *c) {
4687 #if MG_ENABLE_FREERTOS_TCP || MG_ARCH == MG_ARCH_AZURERTOS || \
4688 MG_ARCH == MG_ARCH_TIRTOS
4692 #if !defined(SOL_TCP)
4693 #define SOL_TCP IPPROTO_TCP
4695 if (setsockopt(FD(c), SOL_TCP, TCP_NODELAY, (char *) &on, sizeof(on)) != 0)
4697 if (setsockopt(FD(c), SOL_SOCKET, SO_KEEPALIVE, (char *) &on, sizeof(on)) !=
4703 void mg_connect_resolved(struct mg_connection *c) {
4704 int type = c->is_udp ? SOCK_DGRAM : SOCK_STREAM;
4705 int rc, af = c->rem.is_ip6 ? AF_INET6 : AF_INET; // c->rem has resolved IP
4706 c->fd = S2PTR(socket(af, type, 0)); // Create outbound socket
4707 c->is_resolving = 0; // Clear resolving flag
4708 if (FD(c) == MG_INVALID_SOCKET) {
4709 mg_error(c, "socket(): %d", MG_SOCK_ERR(-1));
4710 } else if (c->is_udp) {
4712 #if MG_ARCH == MG_ARCH_TIRTOS
4713 union usa usa; // TI-RTOS NDK requires binding to receive on UDP sockets
4714 socklen_t slen = tousa(&c->loc, &usa);
4715 if ((rc = bind(c->fd, &usa.sa, slen)) != 0)
4716 MG_ERROR(("bind: %d", MG_SOCK_ERR(rc)));
4718 mg_call(c, MG_EV_RESOLVE, NULL);
4719 mg_call(c, MG_EV_CONNECT, NULL);
4722 socklen_t slen = tousa(&c->rem, &usa);
4723 mg_set_non_blocking_mode(FD(c));
4726 mg_call(c, MG_EV_RESOLVE, NULL);
4727 rc = connect(FD(c), &usa.sa, slen); // Attempt to connect
4728 if (rc == 0) { // Success
4729 mg_call(c, MG_EV_CONNECT, NULL); // Send MG_EV_CONNECT to the user
4730 } else if (MG_SOCK_PENDING(rc)) { // Need to wait for TCP handshake
4731 MG_DEBUG(("%lu %p -> %M pend", c->id, c->fd, mg_print_ip_port, &c->rem));
4732 c->is_connecting = 1;
4734 mg_error(c, "connect: %d", MG_SOCK_ERR(rc));
4739 static MG_SOCKET_TYPE raccept(MG_SOCKET_TYPE sock, union usa *usa,
4741 MG_SOCKET_TYPE fd = MG_INVALID_SOCKET;
4743 memset(usa, 0, sizeof(*usa));
4744 fd = accept(sock, &usa->sa, len);
4745 } while (MG_SOCK_INTR(fd));
4749 static void accept_conn(struct mg_mgr *mgr, struct mg_connection *lsn) {
4750 struct mg_connection *c = NULL;
4752 socklen_t sa_len = sizeof(usa);
4753 MG_SOCKET_TYPE fd = raccept(FD(lsn), &usa, &sa_len);
4754 if (fd == MG_INVALID_SOCKET) {
4755 #if MG_ARCH == MG_ARCH_AZURERTOS
4756 // AzureRTOS, in non-block socket mode can mark listening socket readable
4757 // even it is not. See comment for 'select' func implementation in
4758 // nx_bsd.c That's not an error, just should try later
4759 if (errno != EAGAIN)
4761 MG_ERROR(("%lu accept failed, errno %d", lsn->id, MG_SOCK_ERR(-1)));
4762 #if (MG_ARCH != MG_ARCH_WIN32) && !MG_ENABLE_FREERTOS_TCP && \
4763 (MG_ARCH != MG_ARCH_TIRTOS) && !MG_ENABLE_POLL
4764 } else if ((long) fd >= FD_SETSIZE) {
4765 MG_ERROR(("%ld > %ld", (long) fd, (long) FD_SETSIZE));
4768 } else if ((c = mg_alloc_conn(mgr)) == NULL) {
4769 MG_ERROR(("%lu OOM", lsn->id));
4772 tomgaddr(&usa, &c->rem, sa_len != sizeof(usa.sin));
4773 LIST_ADD_HEAD(struct mg_connection, &mgr->conns, c);
4776 mg_set_non_blocking_mode(FD(c));
4779 c->is_hexdumping = lsn->is_hexdumping;
4782 c->pfn_data = lsn->pfn_data;
4784 c->fn_data = lsn->fn_data;
4785 MG_DEBUG(("%lu %p accepted %M -> %M", c->id, c->fd, mg_print_ip_port,
4786 &c->rem, mg_print_ip_port, &c->loc));
4787 mg_call(c, MG_EV_OPEN, NULL);
4788 mg_call(c, MG_EV_ACCEPT, NULL);
4792 static bool mg_socketpair(MG_SOCKET_TYPE sp[2], union usa usa[2], bool udp) {
4793 MG_SOCKET_TYPE sock;
4794 socklen_t n = sizeof(usa[0].sin);
4795 bool success = false;
4797 sock = sp[0] = sp[1] = MG_INVALID_SOCKET;
4798 (void) memset(&usa[0], 0, sizeof(usa[0]));
4799 usa[0].sin.sin_family = AF_INET;
4800 *(uint32_t *) &usa->sin.sin_addr = mg_htonl(0x7f000001U); // 127.0.0.1
4803 if (udp && (sp[0] = socket(AF_INET, SOCK_DGRAM, 0)) != MG_INVALID_SOCKET &&
4804 (sp[1] = socket(AF_INET, SOCK_DGRAM, 0)) != MG_INVALID_SOCKET &&
4805 bind(sp[0], &usa[0].sa, n) == 0 && bind(sp[1], &usa[1].sa, n) == 0 &&
4806 getsockname(sp[0], &usa[0].sa, &n) == 0 &&
4807 getsockname(sp[1], &usa[1].sa, &n) == 0 &&
4808 connect(sp[0], &usa[1].sa, n) == 0 &&
4809 connect(sp[1], &usa[0].sa, n) == 0) {
4812 (sock = socket(AF_INET, SOCK_STREAM, 0)) != MG_INVALID_SOCKET &&
4813 bind(sock, &usa[0].sa, n) == 0 &&
4814 listen(sock, MG_SOCK_LISTEN_BACKLOG_SIZE) == 0 &&
4815 getsockname(sock, &usa[0].sa, &n) == 0 &&
4816 (sp[0] = socket(AF_INET, SOCK_STREAM, 0)) != MG_INVALID_SOCKET &&
4817 connect(sp[0], &usa[0].sa, n) == 0 &&
4818 (sp[1] = raccept(sock, &usa[1], &n)) != MG_INVALID_SOCKET) {
4822 mg_set_non_blocking_mode(sp[1]);
4824 if (sp[0] != MG_INVALID_SOCKET) closesocket(sp[0]);
4825 if (sp[1] != MG_INVALID_SOCKET) closesocket(sp[1]);
4826 sp[0] = sp[1] = MG_INVALID_SOCKET;
4828 if (sock != MG_INVALID_SOCKET) closesocket(sock);
4832 int mg_mkpipe(struct mg_mgr *mgr, mg_event_handler_t fn, void *fn_data,
4835 MG_SOCKET_TYPE sp[2] = {MG_INVALID_SOCKET, MG_INVALID_SOCKET};
4836 struct mg_connection *c = NULL;
4837 if (!mg_socketpair(sp, usa, udp)) {
4838 MG_ERROR(("Cannot create socket pair"));
4839 } else if ((c = mg_wrapfd(mgr, (int) sp[1], fn, fn_data)) == NULL) {
4842 sp[0] = sp[1] = MG_INVALID_SOCKET;
4844 tomgaddr(&usa[0], &c->rem, false);
4845 MG_DEBUG(("%lu %p pipe %lu", c->id, c->fd, (unsigned long) sp[0]));
4850 static bool can_read(const struct mg_connection *c) {
4851 return c->is_full == false;
4854 static bool can_write(const struct mg_connection *c) {
4855 return c->is_connecting || (c->send.len > 0 && c->is_tls_hs == 0);
4858 static bool skip_iotest(const struct mg_connection *c) {
4859 return (c->is_closing || c->is_resolving || FD(c) == MG_INVALID_SOCKET) ||
4860 (can_read(c) == false && can_write(c) == false);
4863 static void mg_iotest(struct mg_mgr *mgr, int ms) {
4864 #if MG_ENABLE_FREERTOS_TCP
4865 struct mg_connection *c;
4866 for (c = mgr->conns; c != NULL; c = c->next) {
4867 c->is_readable = c->is_writable = 0;
4868 if (skip_iotest(c)) continue;
4870 FreeRTOS_FD_SET(c->fd, mgr->ss, eSELECT_READ | eSELECT_EXCEPT);
4871 if (can_write(c)) FreeRTOS_FD_SET(c->fd, mgr->ss, eSELECT_WRITE);
4873 FreeRTOS_select(mgr->ss, pdMS_TO_TICKS(ms));
4874 for (c = mgr->conns; c != NULL; c = c->next) {
4875 EventBits_t bits = FreeRTOS_FD_ISSET(c->fd, mgr->ss);
4876 c->is_readable = bits & (eSELECT_READ | eSELECT_EXCEPT) ? 1U : 0;
4877 c->is_writable = bits & eSELECT_WRITE ? 1U : 0;
4878 if (c->fd != MG_INVALID_SOCKET)
4879 FreeRTOS_FD_CLR(c->fd, mgr->ss,
4880 eSELECT_READ | eSELECT_EXCEPT | eSELECT_WRITE);
4882 #elif MG_ENABLE_EPOLL
4884 for (struct mg_connection *c = mgr->conns; c != NULL; c = c->next) {
4885 c->is_readable = c->is_writable = 0;
4886 if (mg_tls_pending(c) > 0) ms = 1, c->is_readable = 1;
4887 if (can_write(c)) MG_EPOLL_MOD(c, 1);
4890 struct epoll_event *evs = (struct epoll_event *) alloca(max * sizeof(evs[0]));
4891 int n = epoll_wait(mgr->epoll_fd, evs, (int) max, ms);
4892 for (int i = 0; i < n; i++) {
4893 struct mg_connection *c = (struct mg_connection *) evs[i].data.ptr;
4894 if (evs[i].events & EPOLLERR) {
4895 mg_error(c, "socket error");
4896 } else if (c->is_readable == 0) {
4897 bool rd = evs[i].events & (EPOLLIN | EPOLLHUP);
4898 bool wr = evs[i].events & EPOLLOUT;
4899 c->is_readable = can_read(c) && rd ? 1U : 0;
4900 c->is_writable = can_write(c) && wr ? 1U : 0;
4904 #elif MG_ENABLE_POLL
4906 for (struct mg_connection *c = mgr->conns; c != NULL; c = c->next) n++;
4907 struct pollfd *fds = (struct pollfd *) alloca(n * sizeof(fds[0]));
4908 memset(fds, 0, n * sizeof(fds[0]));
4910 for (struct mg_connection *c = mgr->conns; c != NULL; c = c->next) {
4911 c->is_readable = c->is_writable = 0;
4912 if (skip_iotest(c)) {
4913 // Socket not valid, ignore
4914 } else if (mg_tls_pending(c) > 0) {
4915 ms = 1; // Don't wait if TLS is ready
4918 if (can_read(c)) fds[n].events |= POLLIN;
4919 if (can_write(c)) fds[n].events |= POLLOUT;
4924 // MG_INFO(("poll n=%d ms=%d", (int) n, ms));
4925 if (poll(fds, n, ms) < 0) {
4926 #if MG_ARCH == MG_ARCH_WIN32
4927 if (n == 0) Sleep(ms); // On Windows, poll fails if no sockets
4929 memset(fds, 0, n * sizeof(fds[0]));
4932 for (struct mg_connection *c = mgr->conns; c != NULL; c = c->next) {
4933 if (skip_iotest(c)) {
4934 // Socket not valid, ignore
4935 } else if (mg_tls_pending(c) > 0) {
4938 if (fds[n].revents & POLLERR) {
4939 mg_error(c, "socket error");
4942 (unsigned) (fds[n].revents & (POLLIN | POLLHUP) ? 1 : 0);
4943 c->is_writable = (unsigned) (fds[n].revents & POLLOUT ? 1 : 0);
4949 struct timeval tv = {ms / 1000, (ms % 1000) * 1000}, tv_zero = {0, 0}, *tvp;
4950 struct mg_connection *c;
4951 fd_set rset, wset, eset;
4952 MG_SOCKET_TYPE maxfd = 0;
4958 tvp = ms < 0 ? NULL : &tv;
4959 for (c = mgr->conns; c != NULL; c = c->next) {
4960 c->is_readable = c->is_writable = 0;
4961 if (skip_iotest(c)) continue;
4962 FD_SET(FD(c), &eset);
4963 if (can_read(c)) FD_SET(FD(c), &rset);
4964 if (can_write(c)) FD_SET(FD(c), &wset);
4965 if (mg_tls_pending(c) > 0) tvp = &tv_zero;
4966 if (FD(c) > maxfd) maxfd = FD(c);
4969 if ((rc = select((int) maxfd + 1, &rset, &wset, &eset, tvp)) < 0) {
4970 #if MG_ARCH == MG_ARCH_WIN32
4971 if (maxfd == 0) Sleep(ms); // On Windows, select fails if no sockets
4973 MG_ERROR(("select: %d %d", rc, MG_SOCK_ERR(rc)));
4980 for (c = mgr->conns; c != NULL; c = c->next) {
4981 if (FD(c) != MG_INVALID_SOCKET && FD_ISSET(FD(c), &eset)) {
4982 mg_error(c, "socket error");
4984 c->is_readable = FD(c) != MG_INVALID_SOCKET && FD_ISSET(FD(c), &rset);
4985 c->is_writable = FD(c) != MG_INVALID_SOCKET && FD_ISSET(FD(c), &wset);
4986 if (mg_tls_pending(c) > 0) c->is_readable = 1;
4992 void mg_mgr_poll(struct mg_mgr *mgr, int ms) {
4993 struct mg_connection *c, *tmp;
4998 mg_timer_poll(&mgr->timers, now);
5000 for (c = mgr->conns; c != NULL; c = tmp) {
5001 bool is_resp = c->is_resp;
5003 mg_call(c, MG_EV_POLL, &now);
5004 if (is_resp && !c->is_resp) {
5006 mg_call(c, MG_EV_READ, &n);
5008 MG_VERBOSE(("%lu %c%c %c%c%c%c%c", c->id, c->is_readable ? 'r' : '-',
5009 c->is_writable ? 'w' : '-', c->is_tls ? 'T' : 't',
5010 c->is_connecting ? 'C' : 'c', c->is_tls_hs ? 'H' : 'h',
5011 c->is_resolving ? 'R' : 'r', c->is_closing ? 'C' : 'c'));
5012 if (c->is_resolving || c->is_closing) {
5014 } else if (c->is_listening && c->is_udp == 0) {
5015 if (c->is_readable) accept_conn(mgr, c);
5016 } else if (c->is_connecting) {
5017 if (c->is_readable || c->is_writable) connect_conn(c);
5018 } else if (c->is_tls_hs) {
5019 if ((c->is_readable || c->is_writable)) mg_tls_handshake(c);
5021 if (c->is_readable) read_conn(c);
5022 if (c->is_writable) write_conn(c);
5025 if (c->is_draining && c->send.len == 0) c->is_closing = 1;
5026 if (c->is_closing) close_conn(c);
5031 #ifdef MG_ENABLE_LINES
5038 #ifndef MG_MAX_SSI_DEPTH
5039 #define MG_MAX_SSI_DEPTH 5
5042 #ifndef MG_SSI_BUFSIZ
5043 #define MG_SSI_BUFSIZ 1024
5047 static char *mg_ssi(const char *path, const char *root, int depth) {
5048 struct mg_iobuf b = {NULL, 0, 0, MG_IO_SIZE};
5049 FILE *fp = fopen(path, "rb");
5051 char buf[MG_SSI_BUFSIZ], arg[sizeof(buf)];
5054 buf[0] = arg[0] = '\0';
5055 while ((ch = fgetc(fp)) != EOF) {
5056 if (intag && ch == '>' && buf[len - 1] == '-' && buf[len - 2] == '-') {
5057 buf[len++] = (char) (ch & 0xff);
5059 if (sscanf(buf, "<!--#include file=\"%[^\"]", arg)) {
5060 char tmp[MG_PATH_MAX + MG_SSI_BUFSIZ + 10],
5061 *p = (char *) path + strlen(path), *data;
5062 while (p > path && p[-1] != MG_DIRSEP && p[-1] != '/') p--;
5063 mg_snprintf(tmp, sizeof(tmp), "%.*s%s", (int) (p - path), path, arg);
5064 if (depth < MG_MAX_SSI_DEPTH &&
5065 (data = mg_ssi(tmp, root, depth + 1)) != NULL) {
5066 mg_iobuf_add(&b, b.len, data, strlen(data));
5069 MG_ERROR(("%s: file=%s error or too deep", path, arg));
5071 } else if (sscanf(buf, "<!--#include virtual=\"%[^\"]", arg)) {
5072 char tmp[MG_PATH_MAX + MG_SSI_BUFSIZ + 10], *data;
5073 mg_snprintf(tmp, sizeof(tmp), "%s%s", root, arg);
5074 if (depth < MG_MAX_SSI_DEPTH &&
5075 (data = mg_ssi(tmp, root, depth + 1)) != NULL) {
5076 mg_iobuf_add(&b, b.len, data, strlen(data));
5079 MG_ERROR(("%s: virtual=%s error or too deep", path, arg));
5083 MG_ERROR(("Unknown SSI tag: %.*s", (int) len, buf));
5084 mg_iobuf_add(&b, b.len, buf, len);
5088 } else if (ch == '<') {
5090 if (len > 0) mg_iobuf_add(&b, b.len, buf, len);
5092 buf[len++] = (char) (ch & 0xff);
5094 if (len == 5 && strncmp(buf, "<!--#", 5) != 0) {
5096 } else if (len >= sizeof(buf) - 2) {
5097 MG_ERROR(("%s: SSI tag is too large", path));
5100 buf[len++] = (char) (ch & 0xff);
5102 buf[len++] = (char) (ch & 0xff);
5103 if (len >= sizeof(buf)) {
5104 mg_iobuf_add(&b, b.len, buf, len);
5109 if (len > 0) mg_iobuf_add(&b, b.len, buf, len);
5110 if (b.len > 0) mg_iobuf_add(&b, b.len, "", 1); // nul-terminate
5115 return (char *) b.buf;
5118 void mg_http_serve_ssi(struct mg_connection *c, const char *root,
5119 const char *fullpath) {
5120 const char *headers = "Content-Type: text/html; charset=utf-8\r\n";
5121 char *data = mg_ssi(fullpath, root, 0);
5122 mg_http_reply(c, 200, headers, "%s", data == NULL ? "" : data);
5126 void mg_http_serve_ssi(struct mg_connection *c, const char *root,
5127 const char *fullpath) {
5128 mg_http_reply(c, 501, NULL, "SSI not enabled");
5129 (void) root, (void) fullpath;
5133 #ifdef MG_ENABLE_LINES
5138 struct mg_str mg_str_s(const char *s) {
5139 struct mg_str str = {s, s == NULL ? 0 : strlen(s)};
5143 struct mg_str mg_str_n(const char *s, size_t n) {
5144 struct mg_str str = {s, n};
5148 int mg_lower(const char *s) {
5150 if (c >= 'A' && c <= 'Z') c += 'a' - 'A';
5154 int mg_ncasecmp(const char *s1, const char *s2, size_t len) {
5157 diff = mg_lower(s1++) - mg_lower(s2++);
5158 } while (diff == 0 && s1[-1] != '\0' && --len > 0);
5162 int mg_casecmp(const char *s1, const char *s2) {
5163 return mg_ncasecmp(s1, s2, (size_t) ~0);
5166 int mg_vcmp(const struct mg_str *s1, const char *s2) {
5167 size_t n2 = strlen(s2), n1 = s1->len;
5168 int r = strncmp(s1->ptr, s2, (n1 < n2) ? n1 : n2);
5169 if (r == 0) return (int) (n1 - n2);
5173 int mg_vcasecmp(const struct mg_str *str1, const char *str2) {
5174 size_t n2 = strlen(str2), n1 = str1->len;
5175 int r = mg_ncasecmp(str1->ptr, str2, (n1 < n2) ? n1 : n2);
5176 if (r == 0) return (int) (n1 - n2);
5180 struct mg_str mg_strdup(const struct mg_str s) {
5181 struct mg_str r = {NULL, 0};
5182 if (s.len > 0 && s.ptr != NULL) {
5183 char *sc = (char *) calloc(1, s.len + 1);
5185 memcpy(sc, s.ptr, s.len);
5194 int mg_strcmp(const struct mg_str str1, const struct mg_str str2) {
5196 while (i < str1.len && i < str2.len) {
5197 int c1 = str1.ptr[i];
5198 int c2 = str2.ptr[i];
5199 if (c1 < c2) return -1;
5200 if (c1 > c2) return 1;
5203 if (i < str1.len) return 1;
5204 if (i < str2.len) return -1;
5208 const char *mg_strstr(const struct mg_str haystack,
5209 const struct mg_str needle) {
5211 if (needle.len > haystack.len) return NULL;
5212 if (needle.len == 0) return haystack.ptr;
5213 for (i = 0; i <= haystack.len - needle.len; i++) {
5214 if (memcmp(haystack.ptr + i, needle.ptr, needle.len) == 0) {
5215 return haystack.ptr + i;
5221 static bool is_space(int c) {
5222 return c == ' ' || c == '\r' || c == '\n' || c == '\t';
5225 struct mg_str mg_strstrip(struct mg_str s) {
5226 while (s.len > 0 && is_space((int) *s.ptr)) s.ptr++, s.len--;
5227 while (s.len > 0 && is_space((int) *(s.ptr + s.len - 1))) s.len--;
5231 bool mg_match(struct mg_str s, struct mg_str p, struct mg_str *caps) {
5232 size_t i = 0, j = 0, ni = 0, nj = 0;
5233 if (caps) caps->ptr = NULL, caps->len = 0;
5234 while (i < p.len || j < s.len) {
5235 if (i < p.len && j < s.len && (p.ptr[i] == '?' || s.ptr[j] == p.ptr[i])) {
5237 } else if (p.ptr[i] == '?') {
5238 caps->ptr = &s.ptr[j], caps->len = 1; // Finalize `?` cap
5239 caps++, caps->ptr = NULL, caps->len = 0; // Init next cap
5240 } else if (caps->ptr != NULL && caps->len == 0) {
5241 caps->len = (size_t) (&s.ptr[j] - caps->ptr); // Finalize current cap
5242 caps++, caps->len = 0, caps->ptr = NULL; // Init next cap
5245 } else if (i < p.len && (p.ptr[i] == '*' || p.ptr[i] == '#')) {
5246 if (caps && !caps->ptr) caps->len = 0, caps->ptr = &s.ptr[j]; // Init cap
5247 ni = i++, nj = j + 1;
5248 } else if (nj > 0 && nj <= s.len && (p.ptr[ni] == '#' || s.ptr[j] != '/')) {
5250 if (caps && caps->ptr == NULL && caps->len == 0) {
5251 caps--, caps->len = 0; // Restart previous cap
5257 if (caps && caps->ptr && caps->len == 0) {
5258 caps->len = (size_t) (&s.ptr[j] - caps->ptr);
5263 bool mg_globmatch(const char *s1, size_t n1, const char *s2, size_t n2) {
5264 return mg_match(mg_str_n(s2, n2), mg_str_n(s1, n1), NULL);
5267 static size_t mg_nce(const char *s, size_t n, size_t ofs, size_t *koff,
5268 size_t *klen, size_t *voff, size_t *vlen, char delim) {
5270 for (kvlen = 0; ofs + kvlen < n && s[ofs + kvlen] != delim;) kvlen++;
5271 for (kl = 0; kl < kvlen && s[ofs + kl] != '=';) kl++;
5272 if (koff != NULL) *koff = ofs;
5273 if (klen != NULL) *klen = kl;
5274 if (voff != NULL) *voff = kl < kvlen ? ofs + kl + 1 : 0;
5275 if (vlen != NULL) *vlen = kl < kvlen ? kvlen - kl - 1 : 0;
5277 return ofs > n ? n : ofs;
5280 bool mg_split(struct mg_str *s, struct mg_str *k, struct mg_str *v, char sep) {
5281 size_t koff = 0, klen = 0, voff = 0, vlen = 0, off = 0;
5282 if (s->ptr == NULL || s->len == 0) return 0;
5283 off = mg_nce(s->ptr, s->len, 0, &koff, &klen, &voff, &vlen, sep);
5284 if (k != NULL) *k = mg_str_n(s->ptr + koff, klen);
5285 if (v != NULL) *v = mg_str_n(s->ptr + voff, vlen);
5286 *s = mg_str_n(s->ptr + off, s->len - off);
5290 bool mg_commalist(struct mg_str *s, struct mg_str *k, struct mg_str *v) {
5291 return mg_split(s, k, v, ',');
5294 char *mg_hex(const void *buf, size_t len, char *to) {
5295 const unsigned char *p = (const unsigned char *) buf;
5296 const char *hex = "0123456789abcdef";
5298 for (; len--; p++) {
5299 to[i++] = hex[p[0] >> 4];
5300 to[i++] = hex[p[0] & 0x0f];
5306 static unsigned char mg_unhex_nimble(unsigned char c) {
5307 return (c >= '0' && c <= '9') ? (unsigned char) (c - '0')
5308 : (c >= 'A' && c <= 'F') ? (unsigned char) (c - '7')
5309 : (unsigned char) (c - 'W');
5312 unsigned long mg_unhexn(const char *s, size_t len) {
5313 unsigned long i = 0, v = 0;
5314 for (i = 0; i < len; i++) v <<= 4, v |= mg_unhex_nimble(((uint8_t *) s)[i]);
5318 void mg_unhex(const char *buf, size_t len, unsigned char *to) {
5320 for (i = 0; i < len; i += 2) {
5321 to[i >> 1] = (unsigned char) mg_unhexn(&buf[i], 2);
5325 char *mg_remove_double_dots(char *s) {
5326 char *saved = s, *p = s;
5327 while (*s != '\0') {
5329 if (s[-1] == '/' || s[-1] == '\\') {
5330 while (s[0] != '\0') {
5331 if (s[0] == '/' || s[0] == '\\') {
5333 } else if (s[0] == '.' && s[1] == '.' &&
5334 (s[2] == '/' || s[2] == '\\')) {
5346 #ifdef MG_ENABLE_LINES
5347 #line 1 "src/timer.c"
5352 #define MG_TIMER_CALLED 4
5354 void mg_timer_init(struct mg_timer **head, struct mg_timer *t, uint64_t ms,
5355 unsigned flags, void (*fn)(void *), void *arg) {
5356 t->id = 0, t->period_ms = ms, t->expire = 0;
5357 t->flags = flags, t->fn = fn, t->arg = arg, t->next = *head;
5361 void mg_timer_free(struct mg_timer **head, struct mg_timer *t) {
5362 while (*head && *head != t) head = &(*head)->next;
5363 if (*head) *head = t->next;
5366 // t: expiration time, prd: period, now: current time. Return true if expired
5367 bool mg_timer_expired(uint64_t *t, uint64_t prd, uint64_t now) {
5368 if (now + prd < *t) *t = 0; // Time wrapped? Reset timer
5369 if (*t == 0) *t = now + prd; // Firt poll? Set expiration
5370 if (*t > now) return false; // Not expired yet, return
5371 *t = (now - *t) > prd ? now + prd : *t + prd; // Next expiration time
5372 return true; // Expired, return true
5375 void mg_timer_poll(struct mg_timer **head, uint64_t now_ms) {
5376 struct mg_timer *t, *tmp;
5377 for (t = *head; t != NULL; t = tmp) {
5378 bool once = t->expire == 0 && (t->flags & MG_TIMER_RUN_NOW) &&
5379 !(t->flags & MG_TIMER_CALLED); // Handle MG_TIMER_NOW only once
5380 bool expired = mg_timer_expired(&t->expire, t->period_ms, now_ms);
5382 if (!once && !expired) continue;
5383 if ((t->flags & MG_TIMER_REPEAT) || !(t->flags & MG_TIMER_CALLED)) {
5386 t->flags |= MG_TIMER_CALLED;
5390 #ifdef MG_ENABLE_LINES
5391 #line 1 "src/tls_dummy.c"
5395 #if !MG_ENABLE_MBEDTLS && !MG_ENABLE_OPENSSL && !MG_ENABLE_CUSTOM_TLS
5396 void mg_tls_init(struct mg_connection *c, const struct mg_tls_opts *opts) {
5398 mg_error(c, "TLS is not enabled");
5400 void mg_tls_handshake(struct mg_connection *c) {
5403 void mg_tls_free(struct mg_connection *c) {
5406 long mg_tls_recv(struct mg_connection *c, void *buf, size_t len) {
5407 return c == NULL || buf == NULL || len == 0 ? 0 : -1;
5409 long mg_tls_send(struct mg_connection *c, const void *buf, size_t len) {
5410 return c == NULL || buf == NULL || len == 0 ? 0 : -1;
5412 size_t mg_tls_pending(struct mg_connection *c) {
5418 #ifdef MG_ENABLE_LINES
5419 #line 1 "src/tls_mbed.c"
5425 #if MG_ENABLE_MBEDTLS
5427 #if defined(MBEDTLS_VERSION_NUMBER) && MBEDTLS_VERSION_NUMBER >= 0x03000000
5428 #define MGRNG , rng_get, NULL
5433 void mg_tls_free(struct mg_connection *c) {
5434 struct mg_tls *tls = (struct mg_tls *) c->tls;
5437 mbedtls_ssl_free(&tls->ssl);
5438 mbedtls_pk_free(&tls->pk);
5439 mbedtls_x509_crt_free(&tls->ca);
5440 mbedtls_x509_crt_free(&tls->cert);
5441 mbedtls_ssl_config_free(&tls->conf);
5447 static int mg_net_send(void *ctx, const unsigned char *buf, size_t len) {
5448 long n = mg_io_send((struct mg_connection *) ctx, buf, len);
5449 MG_VERBOSE(("%lu n=%ld e=%d", ((struct mg_connection *) ctx)->id, n, errno));
5450 if (n == MG_IO_WAIT) return MBEDTLS_ERR_SSL_WANT_WRITE;
5451 if (n == MG_IO_RESET) return MBEDTLS_ERR_NET_CONN_RESET;
5452 if (n == MG_IO_ERR) return MBEDTLS_ERR_NET_SEND_FAILED;
5456 static int mg_net_recv(void *ctx, unsigned char *buf, size_t len) {
5457 long n = mg_io_recv((struct mg_connection *) ctx, buf, len);
5458 MG_VERBOSE(("%lu n=%ld", ((struct mg_connection *) ctx)->id, n));
5459 if (n == MG_IO_WAIT) return MBEDTLS_ERR_SSL_WANT_WRITE;
5460 if (n == MG_IO_RESET) return MBEDTLS_ERR_NET_CONN_RESET;
5461 if (n == MG_IO_ERR) return MBEDTLS_ERR_NET_RECV_FAILED;
5465 void mg_tls_handshake(struct mg_connection *c) {
5466 struct mg_tls *tls = (struct mg_tls *) c->tls;
5467 int rc = mbedtls_ssl_handshake(&tls->ssl);
5468 if (rc == 0) { // Success
5469 MG_DEBUG(("%lu success", c->id));
5471 mg_call(c, MG_EV_TLS_HS, NULL);
5472 } else if (rc == MBEDTLS_ERR_SSL_WANT_READ ||
5473 rc == MBEDTLS_ERR_SSL_WANT_WRITE) { // Still pending
5474 MG_VERBOSE(("%lu pending, %d%d %d (-%#x)", c->id, c->is_connecting,
5475 c->is_tls_hs, rc, -rc));
5477 mg_error(c, "TLS handshake: -%#x", -rc); // Error
5481 static int mbed_rng(void *ctx, unsigned char *buf, size_t len) {
5482 mg_random(buf, len);
5487 static void debug_cb(void *c, int lev, const char *s, int n, const char *s2) {
5488 n = (int) strlen(s2) - 1;
5489 MG_INFO(("%lu %d %.*s", ((struct mg_connection *) c)->id, lev, n, s2));
5493 #if defined(MBEDTLS_VERSION_NUMBER) && MBEDTLS_VERSION_NUMBER >= 0x03000000
5494 static int rng_get(void *p_rng, unsigned char *buf, size_t len) {
5496 mg_random(buf, len);
5501 static struct mg_str mg_loadfile(struct mg_fs *fs, const char *path) {
5503 if (path[0] == '-') return mg_str(path);
5504 char *p = mg_file_read(fs, path, &n);
5505 return mg_str_n(p, n);
5508 void mg_tls_init(struct mg_connection *c, const struct mg_tls_opts *opts) {
5509 struct mg_fs *fs = opts->fs == NULL ? &mg_fs_posix : opts->fs;
5510 struct mg_tls *tls = (struct mg_tls *) calloc(1, sizeof(*tls));
5513 if (c->tls == NULL) {
5514 mg_error(c, "TLS OOM");
5517 MG_DEBUG(("%lu Setting TLS", c->id));
5518 mbedtls_ssl_init(&tls->ssl);
5519 mbedtls_ssl_config_init(&tls->conf);
5520 mbedtls_x509_crt_init(&tls->ca);
5521 mbedtls_x509_crt_init(&tls->cert);
5522 mbedtls_pk_init(&tls->pk);
5523 mbedtls_ssl_conf_dbg(&tls->conf, debug_cb, c);
5524 #if defined(MG_MBEDTLS_DEBUG_LEVEL)
5525 mbedtls_debug_set_threshold(MG_MBEDTLS_DEBUG_LEVEL);
5527 if ((rc = mbedtls_ssl_config_defaults(
5529 c->is_client ? MBEDTLS_SSL_IS_CLIENT : MBEDTLS_SSL_IS_SERVER,
5530 MBEDTLS_SSL_TRANSPORT_STREAM, MBEDTLS_SSL_PRESET_DEFAULT)) != 0) {
5531 mg_error(c, "tls defaults %#x", -rc);
5534 mbedtls_ssl_conf_rng(&tls->conf, mbed_rng, c);
5535 if (opts->ca == NULL || strcmp(opts->ca, "*") == 0) {
5536 mbedtls_ssl_conf_authmode(&tls->conf, MBEDTLS_SSL_VERIFY_NONE);
5537 } else if (opts->ca != NULL && opts->ca[0] != '\0') {
5538 #if defined(MBEDTLS_X509_CA_CHAIN_ON_DISK)
5539 tls->cafile = strdup(opts->ca);
5540 rc = mbedtls_ssl_conf_ca_chain_file(&tls->conf, tls->cafile, NULL);
5542 mg_error(c, "parse on-disk chain(%s) err %#x", tls->cafile, -rc);
5546 struct mg_str s = mg_loadfile(fs, opts->ca);
5547 rc = mbedtls_x509_crt_parse(&tls->ca, (uint8_t *) s.ptr, s.len + 1);
5548 if (opts->ca[0] != '-') free((char *) s.ptr);
5550 mg_error(c, "parse(%s) err %#x", opts->ca, -rc);
5553 mbedtls_ssl_conf_ca_chain(&tls->conf, &tls->ca, NULL);
5555 if (opts->srvname.len > 0) {
5556 char *x = mg_mprintf("%.*s", (int) opts->srvname.len, opts->srvname.ptr);
5557 mbedtls_ssl_set_hostname(&tls->ssl, x);
5560 mbedtls_ssl_conf_authmode(&tls->conf, MBEDTLS_SSL_VERIFY_REQUIRED);
5562 if (opts->cert != NULL && opts->cert[0] != '\0') {
5563 struct mg_str s = mg_loadfile(fs, opts->cert);
5564 const char *key = opts->certkey == NULL ? opts->cert : opts->certkey;
5565 rc = mbedtls_x509_crt_parse(&tls->cert, (uint8_t *) s.ptr, s.len + 1);
5566 if (opts->cert[0] != '-') free((char *) s.ptr);
5568 mg_error(c, "parse(%s) err %#x", opts->cert, -rc);
5571 s = mg_loadfile(fs, key);
5572 rc = mbedtls_pk_parse_key(&tls->pk, (uint8_t *) s.ptr, s.len + 1, NULL,
5574 if (key[0] != '-') free((char *) s.ptr);
5576 mg_error(c, "tls key(%s) %#x", key, -rc);
5579 rc = mbedtls_ssl_conf_own_cert(&tls->conf, &tls->cert, &tls->pk);
5581 mg_error(c, "own cert %#x", -rc);
5585 if ((rc = mbedtls_ssl_setup(&tls->ssl, &tls->conf)) != 0) {
5586 mg_error(c, "setup err %#x", -rc);
5592 mbedtls_ssl_set_bio(&tls->ssl, c, mg_net_send, mg_net_recv, 0);
5593 if (c->is_client && c->is_resolving == 0 && c->is_connecting == 0) {
5594 mg_tls_handshake(c);
5601 size_t mg_tls_pending(struct mg_connection *c) {
5602 struct mg_tls *tls = (struct mg_tls *) c->tls;
5603 return tls == NULL ? 0 : mbedtls_ssl_get_bytes_avail(&tls->ssl);
5606 long mg_tls_recv(struct mg_connection *c, void *buf, size_t len) {
5607 struct mg_tls *tls = (struct mg_tls *) c->tls;
5608 long n = mbedtls_ssl_read(&tls->ssl, (unsigned char *) buf, len);
5609 if (n == MBEDTLS_ERR_SSL_WANT_READ || n == MBEDTLS_ERR_SSL_WANT_WRITE)
5611 if (n <= 0) return MG_IO_ERR;
5615 long mg_tls_send(struct mg_connection *c, const void *buf, size_t len) {
5616 struct mg_tls *tls = (struct mg_tls *) c->tls;
5617 long n = mbedtls_ssl_write(&tls->ssl, (unsigned char *) buf, len);
5618 if (n == MBEDTLS_ERR_SSL_WANT_READ || n == MBEDTLS_ERR_SSL_WANT_WRITE)
5620 if (n <= 0) return MG_IO_ERR;
5625 #ifdef MG_ENABLE_LINES
5626 #line 1 "src/tls_openssl.c"
5631 #if MG_ENABLE_OPENSSL
5632 static int mg_tls_err(struct mg_tls *tls, int res) {
5633 int err = SSL_get_error(tls->ssl, res);
5634 // We've just fetched the last error from the queue.
5635 // Now we need to clear the error queue. If we do not, then the following
5636 // can happen (actually reported):
5637 // - A new connection is accept()-ed with cert error (e.g. self-signed cert)
5638 // - Since all accept()-ed connections share listener's context,
5639 // - *ALL* SSL accepted connection report read error on the next poll cycle.
5640 // Thus a single errored connection can close all the rest, unrelated ones.
5641 // Clearing the error keeps the shared SSL_CTX in an OK state.
5643 if (err != 0) ERR_print_errors_fp(stderr);
5645 if (err == SSL_ERROR_WANT_READ) return 0;
5646 if (err == SSL_ERROR_WANT_WRITE) return 0;
5650 void mg_tls_init(struct mg_connection *c, const struct mg_tls_opts *opts) {
5651 struct mg_tls *tls = (struct mg_tls *) calloc(1, sizeof(*tls));
5652 const char *id = "mongoose";
5653 static unsigned char s_initialised = 0;
5657 mg_error(c, "TLS OOM");
5661 if (!s_initialised) {
5665 MG_DEBUG(("%lu Setting TLS, CA: %s, cert: %s, key: %s", c->id,
5666 opts->ca == NULL ? "null" : opts->ca,
5667 opts->cert == NULL ? "null" : opts->cert,
5668 opts->certkey == NULL ? "null" : opts->certkey));
5669 tls->ctx = c->is_client ? SSL_CTX_new(SSLv23_client_method())
5670 : SSL_CTX_new(SSLv23_server_method());
5671 if ((tls->ssl = SSL_new(tls->ctx)) == NULL) {
5672 mg_error(c, "SSL_new");
5675 SSL_set_session_id_context(tls->ssl, (const uint8_t *) id,
5676 (unsigned) strlen(id));
5677 // Disable deprecated protocols
5678 SSL_set_options(tls->ssl, SSL_OP_NO_SSLv2);
5679 SSL_set_options(tls->ssl, SSL_OP_NO_SSLv3);
5680 SSL_set_options(tls->ssl, SSL_OP_NO_TLSv1);
5681 SSL_set_options(tls->ssl, SSL_OP_NO_TLSv1_1);
5682 #ifdef MG_ENABLE_OPENSSL_NO_COMPRESSION
5683 SSL_set_options(tls->ssl, SSL_OP_NO_COMPRESSION);
5685 #ifdef MG_ENABLE_OPENSSL_CIPHER_SERVER_PREFERENCE
5686 SSL_set_options(tls->ssl, SSL_OP_CIPHER_SERVER_PREFERENCE);
5689 if (opts->ca != NULL && opts->ca[0] != '\0') {
5690 SSL_set_verify(tls->ssl, SSL_VERIFY_PEER | SSL_VERIFY_FAIL_IF_NO_PEER_CERT,
5692 if ((rc = SSL_CTX_load_verify_locations(tls->ctx, opts->ca, NULL)) != 1) {
5693 mg_error(c, "load('%s') %d err %d", opts->ca, rc, mg_tls_err(tls, rc));
5697 if (opts->cert != NULL && opts->cert[0] != '\0') {
5698 const char *key = opts->certkey;
5699 if (key == NULL) key = opts->cert;
5700 if ((rc = SSL_use_certificate_file(tls->ssl, opts->cert, 1)) != 1) {
5701 mg_error(c, "Invalid SSL cert, err %d", mg_tls_err(tls, rc));
5703 } else if ((rc = SSL_use_PrivateKey_file(tls->ssl, key, 1)) != 1) {
5704 mg_error(c, "Invalid SSL key, err %d", mg_tls_err(tls, rc));
5706 #if OPENSSL_VERSION_NUMBER > 0x10100000L
5707 } else if ((rc = SSL_use_certificate_chain_file(tls->ssl, opts->cert)) !=
5709 mg_error(c, "Invalid chain, err %d", mg_tls_err(tls, rc));
5713 SSL_set_mode(tls->ssl, SSL_MODE_ACCEPT_MOVING_WRITE_BUFFER);
5714 #if OPENSSL_VERSION_NUMBER > 0x10002000L
5715 SSL_set_ecdh_auto(tls->ssl, 1);
5719 if (opts->ciphers != NULL) SSL_set_cipher_list(tls->ssl, opts->ciphers);
5720 #if OPENSSL_VERSION_NUMBER >= 0x10100000L
5721 if (opts->srvname.len > 0) {
5722 char *s = mg_mprintf("%.*s", (int) opts->srvname.len, opts->srvname.ptr);
5723 SSL_set1_host(tls->ssl, s);
5724 SSL_set_tlsext_host_name(tls->ssl, s);
5731 if (c->is_client && c->is_resolving == 0 && c->is_connecting == 0) {
5732 mg_tls_handshake(c);
5734 MG_DEBUG(("%lu SSL %s OK", c->id, c->is_accepted ? "accept" : "client"));
5741 void mg_tls_handshake(struct mg_connection *c) {
5742 struct mg_tls *tls = (struct mg_tls *) c->tls;
5744 SSL_set_fd(tls->ssl, (int) (size_t) c->fd);
5745 rc = c->is_client ? SSL_connect(tls->ssl) : SSL_accept(tls->ssl);
5747 MG_DEBUG(("%lu success", c->id));
5749 mg_call(c, MG_EV_TLS_HS, NULL);
5751 int code = mg_tls_err(tls, rc);
5752 if (code != 0) mg_error(c, "tls hs: rc %d, err %d", rc, code);
5756 void mg_tls_free(struct mg_connection *c) {
5757 struct mg_tls *tls = (struct mg_tls *) c->tls;
5758 if (tls == NULL) return;
5760 SSL_CTX_free(tls->ctx);
5765 size_t mg_tls_pending(struct mg_connection *c) {
5766 struct mg_tls *tls = (struct mg_tls *) c->tls;
5767 return tls == NULL ? 0 : (size_t) SSL_pending(tls->ssl);
5770 long mg_tls_recv(struct mg_connection *c, void *buf, size_t len) {
5771 struct mg_tls *tls = (struct mg_tls *) c->tls;
5772 int n = SSL_read(tls->ssl, buf, (int) len);
5773 if (n < 0 && mg_tls_err(tls, n) == 0) return MG_IO_WAIT;
5774 if (n <= 0) return MG_IO_ERR;
5778 long mg_tls_send(struct mg_connection *c, const void *buf, size_t len) {
5779 struct mg_tls *tls = (struct mg_tls *) c->tls;
5780 int n = SSL_write(tls->ssl, buf, (int) len);
5781 if (n < 0 && mg_tls_err(tls, n) == 0) return MG_IO_WAIT;
5782 if (n <= 0) return MG_IO_ERR;
5787 #ifdef MG_ENABLE_LINES
5793 size_t key, user, pass, host, port, uri, end;
5796 int mg_url_is_ssl(const char *url) {
5797 return strncmp(url, "wss:", 4) == 0 || strncmp(url, "https:", 6) == 0 ||
5798 strncmp(url, "mqtts:", 6) == 0 || strncmp(url, "ssl:", 4) == 0 ||
5799 strncmp(url, "tls:", 4) == 0;
5802 static struct url urlparse(const char *url) {
5805 memset(&u, 0, sizeof(u));
5806 for (i = 0; url[i] != '\0'; i++) {
5807 if (url[i] == '/' && i > 0 && u.host == 0 && url[i - 1] == '/') {
5810 } else if (url[i] == ']') {
5811 u.port = 0; // IPv6 URLs, like http://[::1]/bar
5812 } else if (url[i] == ':' && u.port == 0 && u.uri == 0) {
5814 } else if (url[i] == '@' && u.user == 0 && u.pass == 0 && u.uri == 0) {
5819 } else if (url[i] == '/' && u.host && u.uri == 0) {
5825 printf("[%s] %d %d %d %d %d\n", url, u.user, u.pass, u.host, u.port, u.uri);
5830 struct mg_str mg_url_host(const char *url) {
5831 struct url u = urlparse(url);
5832 size_t n = u.port ? u.port - u.host - 1
5833 : u.uri ? u.uri - u.host
5835 struct mg_str s = mg_str_n(url + u.host, n);
5839 const char *mg_url_uri(const char *url) {
5840 struct url u = urlparse(url);
5841 return u.uri ? url + u.uri : "/";
5844 unsigned short mg_url_port(const char *url) {
5845 struct url u = urlparse(url);
5846 unsigned short port = 0;
5847 if (strncmp(url, "http:", 5) == 0 || strncmp(url, "ws:", 3) == 0) port = 80;
5848 if (strncmp(url, "wss:", 4) == 0 || strncmp(url, "https:", 6) == 0)
5850 if (strncmp(url, "mqtt:", 5) == 0) port = 1883;
5851 if (strncmp(url, "mqtts:", 6) == 0) port = 8883;
5852 if (u.port) port = (unsigned short) atoi(url + u.port);
5856 struct mg_str mg_url_user(const char *url) {
5857 struct url u = urlparse(url);
5858 struct mg_str s = mg_str("");
5859 if (u.user && (u.pass || u.host)) {
5860 size_t n = u.pass ? u.pass - u.user - 1 : u.host - u.user - 1;
5861 s = mg_str_n(url + u.user, n);
5866 struct mg_str mg_url_pass(const char *url) {
5867 struct url u = urlparse(url);
5868 struct mg_str s = mg_str_n("", 0UL);
5869 if (u.pass && u.host) {
5870 size_t n = u.host - u.pass - 1;
5871 s = mg_str_n(url + u.pass, n);
5876 #ifdef MG_ENABLE_LINES
5877 #line 1 "src/util.c"
5881 #if MG_ENABLE_CUSTOM_RANDOM
5883 void mg_random(void *buf, size_t len) {
5885 unsigned char *p = (unsigned char *) buf;
5886 #if MG_ARCH == MG_ARCH_ESP32
5887 while (len--) *p++ = (unsigned char) (esp_random() & 255);
5889 #elif MG_ARCH == MG_ARCH_WIN32
5890 #elif MG_ARCH == MG_ARCH_UNIX
5891 FILE *fp = fopen("/dev/urandom", "rb");
5893 if (fread(buf, 1, len, fp) == len) done = true;
5897 // If everything above did not work, fallback to a pseudo random generator
5898 while (!done && len--) *p++ = (unsigned char) (rand() & 255);
5902 char *mg_random_str(char *buf, size_t len) {
5904 mg_random(buf, len);
5905 for (i = 0; i < len; i++) {
5906 uint8_t c = ((uint8_t *) buf)[i] % 62U;
5907 buf[i] = i == len - 1 ? (char) '\0' // 0-terminate last byte
5908 : c < 26 ? (char) ('a' + c) // lowercase
5909 : c < 52 ? (char) ('A' + c - 26) // uppercase
5910 : (char) ('0' + c - 52); // numeric
5915 uint32_t mg_ntohl(uint32_t net) {
5916 uint8_t data[4] = {0, 0, 0, 0};
5917 memcpy(&data, &net, sizeof(data));
5918 return (((uint32_t) data[3]) << 0) | (((uint32_t) data[2]) << 8) |
5919 (((uint32_t) data[1]) << 16) | (((uint32_t) data[0]) << 24);
5922 uint16_t mg_ntohs(uint16_t net) {
5923 uint8_t data[2] = {0, 0};
5924 memcpy(&data, &net, sizeof(data));
5925 return (uint16_t) ((uint16_t) data[1] | (((uint16_t) data[0]) << 8));
5928 uint32_t mg_crc32(uint32_t crc, const char *buf, size_t len) {
5929 static const uint32_t crclut[16] = {
5930 // table for polynomial 0xEDB88320 (reflected)
5931 0x00000000, 0x1DB71064, 0x3B6E20C8, 0x26D930AC, 0x76DC4190, 0x6B6B51F4,
5932 0x4DB26158, 0x5005713C, 0xEDB88320, 0xF00F9344, 0xD6D6A3E8, 0xCB61B38C,
5933 0x9B64C2B0, 0x86D3D2D4, 0xA00AE278, 0xBDBDF21C};
5936 uint8_t byte = *(uint8_t *)buf++;
5937 crc = crclut[(crc ^ byte) & 0x0F] ^ (crc >> 4);
5938 crc = crclut[(crc ^ (byte >> 4)) & 0x0F] ^ (crc >> 4);
5943 static int isbyte(int n) {
5944 return n >= 0 && n <= 255;
5947 static int parse_net(const char *spec, uint32_t *net, uint32_t *mask) {
5948 int n, a, b, c, d, slash = 32, len = 0;
5949 if ((sscanf(spec, "%d.%d.%d.%d/%d%n", &a, &b, &c, &d, &slash, &n) == 5 ||
5950 sscanf(spec, "%d.%d.%d.%d%n", &a, &b, &c, &d, &n) == 4) &&
5951 isbyte(a) && isbyte(b) && isbyte(c) && isbyte(d) && slash >= 0 &&
5954 *net = ((uint32_t) a << 24) | ((uint32_t) b << 16) | ((uint32_t) c << 8) |
5956 *mask = slash ? (uint32_t) (0xffffffffU << (32 - slash)) : (uint32_t) 0;
5961 int mg_check_ip_acl(struct mg_str acl, uint32_t remote_ip) {
5963 int allowed = acl.len == 0 ? '+' : '-'; // If any ACL is set, deny by default
5964 while (mg_commalist(&acl, &k, &v)) {
5966 if (k.ptr[0] != '+' && k.ptr[0] != '-') return -1;
5967 if (parse_net(&k.ptr[1], &net, &mask) == 0) return -2;
5968 if ((mg_ntohl(remote_ip) & mask) == net) allowed = k.ptr[0];
5970 return allowed == '+';
5973 #if MG_ENABLE_CUSTOM_MILLIS
5975 uint64_t mg_millis(void) {
5976 #if MG_ARCH == MG_ARCH_WIN32
5977 return GetTickCount();
5978 #elif MG_ARCH == MG_ARCH_RP2040
5979 return time_us_64() / 1000;
5980 #elif MG_ARCH == MG_ARCH_ESP32
5981 return esp_timer_get_time() / 1000;
5982 #elif MG_ARCH == MG_ARCH_ESP8266 || MG_ARCH == MG_ARCH_FREERTOS
5983 return xTaskGetTickCount() * portTICK_PERIOD_MS;
5984 #elif MG_ARCH == MG_ARCH_AZURERTOS
5985 return tx_time_get() * (1000 /* MS per SEC */ / TX_TIMER_TICKS_PER_SECOND);
5986 #elif MG_ARCH == MG_ARCH_TIRTOS
5987 return (uint64_t) Clock_getTicks();
5988 #elif MG_ARCH == MG_ARCH_ZEPHYR
5989 return (uint64_t) k_uptime_get();
5990 #elif MG_ARCH == MG_ARCH_CMSIS_RTOS1
5991 return (uint64_t)rt_time_get();
5992 #elif MG_ARCH == MG_ARCH_CMSIS_RTOS2
5993 return (uint64_t)((osKernelGetTickCount() * 1000) / osKernelGetTickFreq());
5994 #elif MG_ARCH == MG_ARCH_UNIX && defined(__APPLE__)
5995 // Apple CLOCK_MONOTONIC_RAW is equivalent to CLOCK_BOOTTIME on linux
5996 // Apple CLOCK_UPTIME_RAW is equivalent to CLOCK_MONOTONIC_RAW on linux
5997 return clock_gettime_nsec_np(CLOCK_UPTIME_RAW) / 1000000;
5998 #elif MG_ARCH == MG_ARCH_UNIX
5999 struct timespec ts = {0, 0};
6000 // See #1615 - prefer monotonic clock
6001 #if defined(CLOCK_MONOTONIC_RAW)
6002 // Raw hardware-based time that is not subject to NTP adjustment
6003 clock_gettime(CLOCK_MONOTONIC_RAW, &ts);
6004 #elif defined(CLOCK_MONOTONIC)
6005 // Affected by the incremental adjustments performed by adjtime and NTP
6006 clock_gettime(CLOCK_MONOTONIC, &ts);
6008 // Affected by discontinuous jumps in the system time and by the incremental
6009 // adjustments performed by adjtime and NTP
6010 clock_gettime(CLOCK_REALTIME, &ts);
6012 return ((uint64_t) ts.tv_sec * 1000 + (uint64_t) ts.tv_nsec / 1000000);
6013 #elif defined(ARDUINO)
6014 return (uint64_t) millis();
6016 return (uint64_t) (time(NULL) * 1000);
6021 #ifdef MG_ENABLE_LINES
6041 size_t mg_ws_vprintf(struct mg_connection *c, int op, const char *fmt,
6043 size_t len = c->send.len;
6044 size_t n = mg_vxprintf(mg_pfn_iobuf, &c->send, fmt, ap);
6045 mg_ws_wrap(c, c->send.len - len, op);
6049 size_t mg_ws_printf(struct mg_connection *c, int op, const char *fmt, ...) {
6053 len = mg_ws_vprintf(c, op, fmt, &ap);
6058 static void ws_handshake(struct mg_connection *c, const struct mg_str *wskey,
6059 const struct mg_str *wsproto, const char *fmt,
6061 const char *magic = "258EAFA5-E914-47DA-95CA-C5AB0DC85B11";
6062 unsigned char sha[20], b64_sha[30];
6064 mg_sha1_ctx sha_ctx;
6065 mg_sha1_init(&sha_ctx);
6066 mg_sha1_update(&sha_ctx, (unsigned char *) wskey->ptr, wskey->len);
6067 mg_sha1_update(&sha_ctx, (unsigned char *) magic, 36);
6068 mg_sha1_final(sha, &sha_ctx);
6069 mg_base64_encode(sha, sizeof(sha), (char *) b64_sha);
6070 mg_xprintf(mg_pfn_iobuf, &c->send,
6071 "HTTP/1.1 101 Switching Protocols\r\n"
6072 "Upgrade: websocket\r\n"
6073 "Connection: Upgrade\r\n"
6074 "Sec-WebSocket-Accept: %s\r\n",
6076 if (fmt != NULL) mg_vxprintf(mg_pfn_iobuf, &c->send, fmt, ap);
6077 if (wsproto != NULL) {
6078 mg_printf(c, "Sec-WebSocket-Protocol: %.*s\r\n", (int) wsproto->len,
6081 mg_send(c, "\r\n", 2);
6084 static uint32_t be32(const uint8_t *p) {
6085 return (((uint32_t) p[3]) << 0) | (((uint32_t) p[2]) << 8) |
6086 (((uint32_t) p[1]) << 16) | (((uint32_t) p[0]) << 24);
6089 static size_t ws_process(uint8_t *buf, size_t len, struct ws_msg *msg) {
6090 size_t i, n = 0, mask_len = 0;
6091 memset(msg, 0, sizeof(*msg));
6093 n = buf[1] & 0x7f; // Frame length
6094 mask_len = buf[1] & 128 ? 4 : 0; // last bit is a mask bit
6095 msg->flags = buf[0];
6096 if (n < 126 && len >= mask_len) {
6098 msg->header_len = 2 + mask_len;
6099 } else if (n == 126 && len >= 4 + mask_len) {
6100 msg->header_len = 4 + mask_len;
6101 msg->data_len = (((size_t) buf[2]) << 8) | buf[3];
6102 } else if (len >= 10 + mask_len) {
6103 msg->header_len = 10 + mask_len;
6105 (size_t) (((uint64_t) be32(buf + 2) << 32) + be32(buf + 6));
6108 // Sanity check, and integer overflow protection for the boundary check below
6109 // data_len should not be larger than 1 Gb
6110 if (msg->data_len > 1024 * 1024 * 1024) return 0;
6111 if (msg->header_len + msg->data_len > len) return 0;
6113 uint8_t *p = buf + msg->header_len, *m = p - mask_len;
6114 for (i = 0; i < msg->data_len; i++) p[i] ^= m[i & 3];
6116 return msg->header_len + msg->data_len;
6119 static size_t mkhdr(size_t len, int op, bool is_client, uint8_t *buf) {
6121 buf[0] = (uint8_t) (op | 128);
6123 buf[1] = (unsigned char) len;
6125 } else if (len < 65536) {
6126 uint16_t tmp = mg_htons((uint16_t) len);
6128 memcpy(&buf[2], &tmp, sizeof(tmp));
6133 tmp = mg_htonl((uint32_t) (((uint64_t) len) >> 32));
6134 memcpy(&buf[2], &tmp, sizeof(tmp));
6135 tmp = mg_htonl((uint32_t) (len & 0xffffffffU));
6136 memcpy(&buf[6], &tmp, sizeof(tmp));
6140 buf[1] |= 1 << 7; // Set masking flag
6141 mg_random(&buf[n], 4);
6147 static void mg_ws_mask(struct mg_connection *c, size_t len) {
6148 if (c->is_client && c->send.buf != NULL) {
6150 uint8_t *p = c->send.buf + c->send.len - len, *mask = p - 4;
6151 for (i = 0; i < len; i++) p[i] ^= mask[i & 3];
6155 size_t mg_ws_send(struct mg_connection *c, const void *buf, size_t len,
6158 size_t header_len = mkhdr(len, op, c->is_client, header);
6159 mg_send(c, header, header_len);
6160 MG_VERBOSE(("WS out: %d [%.*s]", (int) len, (int) len, buf));
6161 mg_send(c, buf, len);
6163 return header_len + len;
6166 static bool mg_ws_client_handshake(struct mg_connection *c) {
6167 int n = mg_http_get_request_len(c->recv.buf, c->recv.len);
6169 mg_error(c, "not http"); // Some just, not an HTTP request
6171 if (n < 15 || memcmp(c->recv.buf + 9, "101", 3) != 0) {
6172 mg_error(c, "handshake error");
6174 struct mg_http_message hm;
6175 mg_http_parse((char *) c->recv.buf, c->recv.len, &hm);
6176 c->is_websocket = 1;
6177 mg_call(c, MG_EV_WS_OPEN, &hm);
6179 mg_iobuf_del(&c->recv, 0, (size_t) n);
6181 return true; // Request is not yet received, quit event handler
6183 return false; // Continue event handler
6186 static void mg_ws_cb(struct mg_connection *c, int ev, void *ev_data,
6189 size_t ofs = (size_t) c->pfn_data;
6191 // assert(ofs < c->recv.len);
6192 if (ev == MG_EV_READ) {
6193 if (c->is_client && !c->is_websocket && mg_ws_client_handshake(c)) return;
6195 while (ws_process(c->recv.buf + ofs, c->recv.len - ofs, &msg) > 0) {
6196 char *s = (char *) c->recv.buf + ofs + msg.header_len;
6197 struct mg_ws_message m = {{s, msg.data_len}, msg.flags};
6198 size_t len = msg.header_len + msg.data_len;
6199 uint8_t final = msg.flags & 128, op = msg.flags & 15;
6200 // MG_VERBOSE ("fin %d op %d len %d [%.*s]", final, op,
6201 // (int) m.data.len, (int) m.data.len, m.data.ptr));
6203 case WEBSOCKET_OP_CONTINUE:
6204 mg_call(c, MG_EV_WS_CTL, &m);
6206 case WEBSOCKET_OP_PING:
6207 MG_DEBUG(("%s", "WS PONG"));
6208 mg_ws_send(c, s, msg.data_len, WEBSOCKET_OP_PONG);
6209 mg_call(c, MG_EV_WS_CTL, &m);
6211 case WEBSOCKET_OP_PONG:
6212 mg_call(c, MG_EV_WS_CTL, &m);
6214 case WEBSOCKET_OP_TEXT:
6215 case WEBSOCKET_OP_BINARY:
6216 if (final) mg_call(c, MG_EV_WS_MSG, &m);
6218 case WEBSOCKET_OP_CLOSE:
6219 MG_DEBUG(("%lu WS CLOSE", c->id));
6220 mg_call(c, MG_EV_WS_CTL, &m);
6221 // Echo the payload of the received CLOSE message back to the sender
6222 mg_ws_send(c, m.data.ptr, m.data.len, WEBSOCKET_OP_CLOSE);
6226 // Per RFC6455, close conn when an unknown op is recvd
6227 mg_error(c, "unknown WS op %d", op);
6231 // Handle fragmented frames: strip header, keep in c->recv
6232 if (final == 0 || op == 0) {
6233 if (op) ofs++, len--, msg.header_len--; // First frame
6234 mg_iobuf_del(&c->recv, ofs, msg.header_len); // Strip header
6235 len -= msg.header_len;
6237 c->pfn_data = (void *) ofs;
6238 // MG_INFO(("FRAG %d [%.*s]", (int) ofs, (int) ofs, c->recv.buf));
6240 // Remove non-fragmented frame
6241 if (final && op) mg_iobuf_del(&c->recv, ofs, len);
6242 // Last chunk of the fragmented frame
6244 m.flags = c->recv.buf[0];
6245 m.data = mg_str_n((char *) &c->recv.buf[1], (size_t) (ofs - 1));
6246 mg_call(c, MG_EV_WS_MSG, &m);
6247 mg_iobuf_del(&c->recv, 0, ofs);
6257 struct mg_connection *mg_ws_connect(struct mg_mgr *mgr, const char *url,
6258 mg_event_handler_t fn, void *fn_data,
6259 const char *fmt, ...) {
6260 struct mg_connection *c = mg_connect(mgr, url, fn, fn_data);
6262 char nonce[16], key[30];
6263 struct mg_str host = mg_url_host(url);
6264 mg_random(nonce, sizeof(nonce));
6265 mg_base64_encode((unsigned char *) nonce, sizeof(nonce), key);
6266 mg_xprintf(mg_pfn_iobuf, &c->send,
6267 "GET %s HTTP/1.1\r\n"
6268 "Upgrade: websocket\r\n"
6270 "Connection: Upgrade\r\n"
6271 "Sec-WebSocket-Version: 13\r\n"
6272 "Sec-WebSocket-Key: %s\r\n",
6273 mg_url_uri(url), (int) host.len, host.ptr, key);
6277 mg_vxprintf(mg_pfn_iobuf, &c->send, fmt, &ap);
6280 mg_xprintf(mg_pfn_iobuf, &c->send, "\r\n");
6287 void mg_ws_upgrade(struct mg_connection *c, struct mg_http_message *hm,
6288 const char *fmt, ...) {
6289 struct mg_str *wskey = mg_http_get_header(hm, "Sec-WebSocket-Key");
6292 if (wskey == NULL) {
6293 mg_http_reply(c, 426, "", "WS upgrade expected\n");
6296 struct mg_str *wsproto = mg_http_get_header(hm, "Sec-WebSocket-Protocol");
6299 ws_handshake(c, wskey, wsproto, fmt, &ap);
6301 c->is_websocket = 1;
6303 mg_call(c, MG_EV_WS_OPEN, hm);
6307 size_t mg_ws_wrap(struct mg_connection *c, size_t len, int op) {
6308 uint8_t header[14], *p;
6309 size_t header_len = mkhdr(len, op, c->is_client, header);
6311 // NOTE: order of operations is important!
6312 mg_iobuf_add(&c->send, c->send.len, NULL, header_len);
6313 p = &c->send.buf[c->send.len - len]; // p points to data
6314 memmove(p, p - header_len, len); // Shift data
6315 memcpy(p - header_len, header, header_len); // Prepend header
6316 mg_ws_mask(c, len); // Mask data
6321 #ifdef MG_ENABLE_LINES
6322 #line 1 "src/tcpip/driver_nxpimxrt1020.c"
6328 * This driver doesn't support 10M line autoconfiguration yet.
6329 * Packets aren't sent if the link negociated 10M line.
6330 * todo: MAC back auto reconfiguration.
6333 #if MG_ENABLE_TCPIP && defined(MG_ENABLE_DRIVER_IMXRT1020)
6334 struct imx_rt1020_enet {
6335 volatile 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;
6339 #define ENET ((struct imx_rt1020_enet *) (uintptr_t) 0x402D8000u)
6342 #define BIT(x) ((uint32_t) 1 << (x))
6344 #define ENET_RXBUFF_SIZE 1536 // 1522 Buffer must be 64bits aligned
6345 #define ENET_TXBUFF_SIZE 1536 // 1522 hence set to 0x600 (1536)
6346 #define ENET_RXBD_NUM (4)
6347 #define ENET_TXBD_NUM (4)
6349 const uint32_t EIMR_RX_ERR = 0x2400000; // Intr mask RXF+EBERR
6351 void ETH_IRQHandler(void);
6352 static bool mg_tcpip_driver_imxrt1020_init(struct mg_tcpip_if *ifp);
6353 static void wait_phy_complete(void);
6354 static struct mg_tcpip_if *s_ifp; // MIP interface
6356 static size_t mg_tcpip_driver_imxrt1020_tx(const void *, size_t , struct mg_tcpip_if *);
6357 static bool mg_tcpip_driver_imxrt1020_up(struct mg_tcpip_if *ifp);
6359 enum { IMXRT1020_PHY_ADDR = 0x02, IMXRT1020_PHY_BCR = 0, IMXRT1020_PHY_BSR = 1 }; // PHY constants
6361 void delay(uint32_t);
6362 void delay (uint32_t di) {
6363 volatile int dno = 0; // Prevent optimization
6364 for (uint32_t i = 0; i < di; i++)
6365 for (int j=0; j<20; j++) // PLLx20 (500 MHz/24MHz)
6369 static void wait_phy_complete(void) {
6371 const uint32_t delay_max = 0x00100000;
6372 uint32_t delay_cnt = 0;
6373 while (!(ENET->EIR & BIT(23)) && (delay_cnt < delay_max))
6375 ENET->EIR |= BIT(23); // MII interrupt clear
6378 static uint32_t imxrt1020_eth_read_phy(uint8_t addr, uint8_t reg) {
6379 ENET->EIR |= BIT(23); // MII interrupt clear
6380 uint32_t mask_phy_adr_reg = 0x1f; // 0b00011111: Ensure we write 5 bits (Phy address & register)
6381 uint32_t phy_transaction = 0x00;
6382 phy_transaction = (0x1 << 30) \
6384 | ((uint32_t)(addr & mask_phy_adr_reg) << 23) \
6385 | ((uint32_t)(reg & mask_phy_adr_reg) << 18) \
6388 ENET->MMFR = phy_transaction;
6389 wait_phy_complete();
6391 return (ENET->MMFR & 0x0000ffff);
6394 static void imxrt1020_eth_write_phy(uint8_t addr, uint8_t reg, uint32_t val) {
6395 ENET->EIR |= BIT(23); // MII interrupt clear
6396 uint8_t mask_phy_adr_reg = 0x1f; // 0b00011111: Ensure we write 5 bits (Phy address & register)
6397 uint32_t mask_phy_data = 0x0000ffff; // Ensure we write 16 bits (data)
6398 addr &= mask_phy_adr_reg;
6399 reg &= mask_phy_adr_reg;
6400 val &= mask_phy_data;
6401 uint32_t phy_transaction = 0x00;
6402 phy_transaction = (uint32_t)(0x1 << 30) \
6403 | (uint32_t)(0x1 << 28) \
6404 | (uint32_t)(addr << 23) \
6405 | (uint32_t)(reg << 18) \
6406 | (uint32_t)(0x2 << 16) \
6408 ENET->MMFR = phy_transaction;
6409 wait_phy_complete();
6412 // FEC RX/TX descriptors (Enhanced descriptor not enabled)
6413 // Descriptor buffer structure, little endian
6415 typedef struct enet_bd_struct_def
6417 uint16_t length; // Data length
6418 uint16_t control; // Control and status
6419 uint32_t *buffer; // Data ptr
6422 // Descriptor and buffer globals, in non-cached area, 64 bits aligned.
6424 __attribute__((section("NonCacheable,\"aw\",%nobits @"))) enet_bd_struct_t rx_buffer_descriptor[(ENET_RXBD_NUM)] __attribute__((aligned((64U))));
6425 __attribute__((section("NonCacheable,\"aw\",%nobits @"))) enet_bd_struct_t tx_buffer_descriptor[(ENET_TXBD_NUM)] __attribute__((aligned((64U))));
6427 uint8_t rx_data_buffer[(ENET_RXBD_NUM)][((unsigned int)(((ENET_RXBUFF_SIZE)) + (((64U))-1U)) & (unsigned int)(~(unsigned int)(((64U))-1U)))] __attribute__((aligned((64U))));
6428 uint8_t tx_data_buffer[(ENET_TXBD_NUM)][((unsigned int)(((ENET_TXBUFF_SIZE)) + (((64U))-1U)) & (unsigned int)(~(unsigned int)(((64U))-1U)))] __attribute__((aligned((64U))));
6430 // Initialise driver imx_rt1020
6432 // static bool mg_tcpip_driver_imxrt1020_init(uint8_t *mac, void *data) { // VO
6433 static bool mg_tcpip_driver_imxrt1020_init(struct mg_tcpip_if *ifp) {
6435 struct mg_tcpip_driver_imxrt1020_data *d = (struct mg_tcpip_driver_imxrt1020_data *) ifp->driver_data;
6438 // ENET Reset, wait complete
6439 ENET->ECR |= BIT(0);
6440 while((ENET->ECR & BIT(0)) != 0) {}
6442 // Re-latches the pin strapping pin values
6443 ENET->ECR |= BIT(0);
6444 while((ENET->ECR & BIT(0)) != 0) {}
6446 // Setup MII/RMII MDC clock divider (<= 2.5MHz).
6447 ENET->MSCR = 0x130; // HOLDTIME 2 clk, Preamble enable, MDC MII_Speed Div 0x30
6448 imxrt1020_eth_write_phy(IMXRT1020_PHY_ADDR, IMXRT1020_PHY_BCR, 0x8000); // PHY W @0x00 D=0x8000 Soft reset
6449 while (imxrt1020_eth_read_phy(IMXRT1020_PHY_ADDR, IMXRT1020_PHY_BSR) & BIT(15)) {delay(0x5000);} // Wait finished poll 10ms
6453 imxrt1020_eth_write_phy(IMXRT1020_PHY_ADDR, IMXRT1020_PHY_BCR, 0x1200); // PHY W @0x00 D=0x1200 Autonego enable + start
6454 imxrt1020_eth_write_phy(IMXRT1020_PHY_ADDR, 0x1f, 0x8180); // PHY W @0x1f D=0x8180 Ref clock 50 MHz at XI input
6456 uint32_t bcr = imxrt1020_eth_read_phy(IMXRT1020_PHY_ADDR, IMXRT1020_PHY_BCR);
6457 bcr &= ~BIT(10); // Isolation -> Normal
6458 imxrt1020_eth_write_phy(IMXRT1020_PHY_ADDR, IMXRT1020_PHY_BCR, bcr);
6462 ENET->ECR = 0x0; // Disable before configuration
6465 ENET->RCR = 0x05ee0104; // #CRCFWD=0 (CRC kept in frame) + RMII + MII Enable
6467 ENET->TCR = BIT(8) | BIT(2); // Addins (MAC address from PAUR+PALR) + Full duplex enable
6468 //ENET->TFWR = BIT(8); // Store And Forward Enable, 64 bytes (minimize tx latency)
6470 // Configure descriptors and buffers
6472 for (int i = 0; i < ENET_RXBD_NUM; i++) {
6473 // Wrap last descriptor buffer ptr
6474 rx_buffer_descriptor[i].control = (BIT(15) | ((i<(ENET_RXBD_NUM-1))?0:BIT(13))); // E+(W*)
6475 rx_buffer_descriptor[i].buffer = (uint32_t *)rx_data_buffer[i];
6479 for (int i = 0; i < ENET_TXBD_NUM; i++) {
6480 // Wrap last descriptor buffer ptr
6481 tx_buffer_descriptor[i].control = ((i<(ENET_RXBD_NUM-1))?0:BIT(13)) | BIT(10); // (W*)+TC
6482 tx_buffer_descriptor[i].buffer = (uint32_t *)tx_data_buffer[i];
6485 // Continue ENET configuration
6486 ENET->RDSR = (uint32_t)(uintptr_t)rx_buffer_descriptor;
6487 ENET->TDSR = (uint32_t)(uintptr_t)tx_buffer_descriptor;
6488 ENET->MRBR[0] = ENET_RXBUFF_SIZE; // Same size for RX/TX buffers
6490 // MAC address filtering (bytes in reversed order)
6491 ENET->PAUR = ((uint32_t) ifp->mac[4] << 24U) | (uint32_t) ifp->mac[5] << 16U;
6492 ENET->PALR = (uint32_t) (ifp->mac[0] << 24U) | ((uint32_t) ifp->mac[1] << 16U) |
6493 ((uint32_t) ifp->mac[2] << 8U) | ifp->mac[3];
6495 // Init Hash tables (mac filtering)
6496 ENET->IAUR = 0; // Unicast
6498 ENET->GAUR = 0; // Multicast
6502 ENET->ECR |= BIT(8); // ENET Set Little-endian + (FEC buffer desc.)
6503 ENET->ECR |= BIT(1); // Enable
6505 // Set interrupt mask
6506 ENET->EIMR = EIMR_RX_ERR;
6508 // RX Descriptor activation
6509 ENET->RDAR = BIT(24); // Activate Receive Descriptor
6514 static uint32_t s_rt1020_txno;
6516 static size_t mg_tcpip_driver_imxrt1020_tx(const void *buf, size_t len, struct mg_tcpip_if *ifp) {
6518 if (len > sizeof(tx_data_buffer[ENET_TXBD_NUM])) {
6519 // MG_ERROR(("Frame too big, %ld", (long) len));
6520 len = 0; // Frame is too big
6521 } else if ((tx_buffer_descriptor[s_rt1020_txno].control & BIT(15))) {
6522 MG_ERROR(("No free descriptors"));
6523 // printf("D0 %lx SR %lx\n", (long) s_txdesc[0][0], (long) ETH->DMASR);
6524 len = 0; // All descriptors are busy, fail
6526 memcpy(tx_data_buffer[s_rt1020_txno], buf, len); // Copy data
6527 tx_buffer_descriptor[s_rt1020_txno].length = (uint16_t) len; // Set data len
6528 tx_buffer_descriptor[s_rt1020_txno].control |= (uint16_t)(BIT(10)); // TC (transmit CRC)
6529 // tx_buffer_descriptor[s_rt1020_txno].control &= (uint16_t)(BIT(14) | BIT(12)); // Own doesn't affect HW
6530 tx_buffer_descriptor[s_rt1020_txno].control |= (uint16_t)(BIT(15) | BIT(11)); // R+L (ready+last)
6531 ENET->TDAR = BIT(24); // Descriptor updated. Hand over to DMA.
6533 // Relevant Descriptor bits: 15(R) Ready
6534 // 11(L) last in frame
6535 // 10(TC) transmis CRC
6536 // __DSB(); // ARM errata 838869 Cortex-M4, M4F, M7, M7F: "store immediate overlapping
6537 // exception" return might vector to incorrect interrupt.
6538 if (++s_rt1020_txno >= ENET_TXBD_NUM) s_rt1020_txno = 0;
6545 static uint32_t s_rt1020_rxno;
6547 void ENET_IRQHandler(void) {
6548 ENET->EIMR = 0; // Mask interrupts.
6549 uint32_t eir = ENET->EIR; // Read EIR
6550 ENET->EIR = 0xffffffff; // Clear interrupts
6552 if (eir & EIMR_RX_ERR) // Global mask used
6554 if (rx_buffer_descriptor[s_rt1020_rxno].control & BIT(15)) {
6555 ENET->EIMR = EIMR_RX_ERR; // Enable interrupts
6556 return; // Empty? -> exit.
6559 else { // Frame received, loop
6560 for (uint32_t i = 0; i < 10; i++) { // read as they arrive but not forever
6561 if (rx_buffer_descriptor[s_rt1020_rxno].control & BIT(15)) break; // exit when done
6562 // Process if CRC OK and frame not truncated
6563 if (!(rx_buffer_descriptor[s_rt1020_rxno].control & (BIT(2) | BIT(0)))) {
6564 uint32_t len = (rx_buffer_descriptor[s_rt1020_rxno].length);
6565 mg_tcpip_qwrite(rx_buffer_descriptor[s_rt1020_rxno].buffer, len > 4 ? len - 4 : len, s_ifp);
6567 rx_buffer_descriptor[s_rt1020_rxno].control |= BIT(15); // Inform DMA RX is empty
6568 if (++s_rt1020_rxno >= ENET_RXBD_NUM) s_rt1020_rxno = 0;
6572 ENET->EIMR = EIMR_RX_ERR; // Enable interrupts
6576 static bool mg_tcpip_driver_imxrt1020_up(struct mg_tcpip_if *ifp) {
6577 uint32_t bsr = imxrt1020_eth_read_phy(IMXRT1020_PHY_ADDR, IMXRT1020_PHY_BSR);
6579 return bsr & BIT(2) ? 1 : 0;
6583 struct mg_tcpip_driver mg_tcpip_driver_imxrt1020 = {
6584 mg_tcpip_driver_imxrt1020_init, mg_tcpip_driver_imxrt1020_tx, NULL,
6585 mg_tcpip_driver_imxrt1020_up};
6589 #ifdef MG_ENABLE_LINES
6590 #line 1 "src/tcpip/driver_stm32.c"
6594 #if MG_ENABLE_TCPIP && MG_ENABLE_DRIVER_STM32
6596 volatile uint32_t MACCR, MACFFR, MACHTHR, MACHTLR, MACMIIAR, MACMIIDR, MACFCR,
6597 MACVLANTR, RESERVED0[2], MACRWUFFR, MACPMTCSR, RESERVED1, MACDBGR, MACSR,
6598 MACIMR, MACA0HR, MACA0LR, MACA1HR, MACA1LR, MACA2HR, MACA2LR, MACA3HR,
6599 MACA3LR, RESERVED2[40], MMCCR, MMCRIR, MMCTIR, MMCRIMR, MMCTIMR,
6600 RESERVED3[14], MMCTGFSCCR, MMCTGFMSCCR, RESERVED4[5], MMCTGFCR,
6601 RESERVED5[10], MMCRFCECR, MMCRFAECR, RESERVED6[10], MMCRGUFCR,
6602 RESERVED7[334], PTPTSCR, PTPSSIR, PTPTSHR, PTPTSLR, PTPTSHUR, PTPTSLUR,
6603 PTPTSAR, PTPTTHR, PTPTTLR, RESERVED8, PTPTSSR, PTPPPSCR, RESERVED9[564],
6604 DMABMR, DMATPDR, DMARPDR, DMARDLAR, DMATDLAR, DMASR, DMAOMR, DMAIER,
6605 DMAMFBOCR, DMARSWTR, RESERVED10[8], DMACHTDR, DMACHRDR, DMACHTBAR,
6609 #define ETH ((struct stm32_eth *) (uintptr_t) 0x40028000)
6612 #define BIT(x) ((uint32_t) 1 << (x))
6613 #define ETH_PKT_SIZE 1540 // Max frame size
6614 #define ETH_DESC_CNT 4 // Descriptors count
6615 #define ETH_DS 4 // Descriptor size (words)
6617 static uint32_t s_rxdesc[ETH_DESC_CNT][ETH_DS]; // RX descriptors
6618 static uint32_t s_txdesc[ETH_DESC_CNT][ETH_DS]; // TX descriptors
6619 static uint8_t s_rxbuf[ETH_DESC_CNT][ETH_PKT_SIZE]; // RX ethernet buffers
6620 static uint8_t s_txbuf[ETH_DESC_CNT][ETH_PKT_SIZE]; // TX ethernet buffers
6621 static uint8_t s_txno; // Current TX descriptor
6622 static uint8_t s_rxno; // Current RX descriptor
6624 static struct mg_tcpip_if *s_ifp; // MIP interface
6625 enum { PHY_ADDR = 0, PHY_BCR = 0, PHY_BSR = 1, PHY_CSCR = 31 };
6627 static uint32_t eth_read_phy(uint8_t addr, uint8_t reg) {
6628 ETH->MACMIIAR &= (7 << 2);
6629 ETH->MACMIIAR |= ((uint32_t) addr << 11) | ((uint32_t) reg << 6);
6630 ETH->MACMIIAR |= BIT(0);
6631 while (ETH->MACMIIAR & BIT(0)) (void) 0;
6632 return ETH->MACMIIDR;
6635 static void eth_write_phy(uint8_t addr, uint8_t reg, uint32_t val) {
6636 ETH->MACMIIDR = val;
6637 ETH->MACMIIAR &= (7 << 2);
6638 ETH->MACMIIAR |= ((uint32_t) addr << 11) | ((uint32_t) reg << 6) | BIT(1);
6639 ETH->MACMIIAR |= BIT(0);
6640 while (ETH->MACMIIAR & BIT(0)) (void) 0;
6643 static uint32_t get_hclk(void) {
6645 volatile uint32_t CR, PLLCFGR, CFGR;
6646 } *rcc = (struct rcc *) 0x40023800;
6647 uint32_t clk = 0, hsi = 16000000 /* 16 MHz */, hse = 8000000 /* 8MHz */;
6649 if (rcc->CFGR & (1 << 2)) {
6651 } else if (rcc->CFGR & (1 << 3)) {
6652 uint32_t vco, m, n, p;
6653 m = (rcc->PLLCFGR & (0x3f << 0)) >> 0;
6654 n = (rcc->PLLCFGR & (0x1ff << 6)) >> 6;
6655 p = (((rcc->PLLCFGR & (3 << 16)) >> 16) + 1) * 2;
6656 clk = (rcc->PLLCFGR & (1 << 22)) ? hse : hsi;
6657 vco = (uint32_t) ((uint64_t) clk * n / m);
6662 uint32_t hpre = (rcc->CFGR & (15 << 4)) >> 4;
6663 if (hpre < 8) return clk;
6665 uint8_t ahbptab[8] = {1, 2, 3, 4, 6, 7, 8, 9}; // log2(div)
6666 return ((uint32_t) clk) >> ahbptab[hpre - 8];
6669 // Guess CR from HCLK. MDC clock is generated from HCLK (AHB); as per 802.3,
6670 // it must not exceed 2.5MHz As the AHB clock can be (and usually is) derived
6671 // from the HSI (internal RC), and it can go above specs, the datasheets
6672 // specify a range of frequencies and activate one of a series of dividers to
6673 // keep the MDC clock safely below 2.5MHz. We guess a divider setting based on
6674 // HCLK with a +5% drift. If the user uses a different clock from our
6675 // defaults, needs to set the macros on top Valid for STM32F74xxx/75xxx
6676 // (38.8.1) and STM32F42xxx/43xxx (33.8.1) (both 4.5% worst case drift)
6677 static int guess_mdc_cr(void) {
6678 uint8_t crs[] = {2, 3, 0, 1, 4, 5}; // ETH->MACMIIAR::CR values
6679 uint8_t div[] = {16, 26, 42, 62, 102, 124}; // Respective HCLK dividers
6680 uint32_t hclk = get_hclk(); // Guess system HCLK
6681 int result = -1; // Invalid CR value
6682 if (hclk < 25000000) {
6683 MG_ERROR(("HCLK too low"));
6685 for (int i = 0; i < 6; i++) {
6686 if (hclk / div[i] <= 2375000UL /* 2.5MHz - 5% */) {
6691 if (result < 0) MG_ERROR(("HCLK too high"));
6693 MG_DEBUG(("HCLK: %u, CR: %d", hclk, result));
6697 static bool mg_tcpip_driver_stm32_init(struct mg_tcpip_if *ifp) {
6698 struct mg_tcpip_driver_stm32_data *d =
6699 (struct mg_tcpip_driver_stm32_data *) ifp->driver_data;
6702 // Init RX descriptors
6703 for (int i = 0; i < ETH_DESC_CNT; i++) {
6704 s_rxdesc[i][0] = BIT(31); // Own
6705 s_rxdesc[i][1] = sizeof(s_rxbuf[i]) | BIT(14); // 2nd address chained
6706 s_rxdesc[i][2] = (uint32_t) (uintptr_t) s_rxbuf[i]; // Point to data buffer
6708 (uint32_t) (uintptr_t) s_rxdesc[(i + 1) % ETH_DESC_CNT]; // Chain
6711 // Init TX descriptors
6712 for (int i = 0; i < ETH_DESC_CNT; i++) {
6713 s_txdesc[i][2] = (uint32_t) (uintptr_t) s_txbuf[i]; // Buf pointer
6715 (uint32_t) (uintptr_t) s_txdesc[(i + 1) % ETH_DESC_CNT]; // Chain
6718 ETH->DMABMR |= BIT(0); // Software reset
6719 while ((ETH->DMABMR & BIT(0)) != 0) (void) 0; // Wait until done
6721 // Set MDC clock divider. If user told us the value, use it. Otherwise, guess
6722 int cr = (d == NULL || d->mdc_cr < 0) ? guess_mdc_cr() : d->mdc_cr;
6723 ETH->MACMIIAR = ((uint32_t) cr & 7) << 2;
6725 // NOTE(cpq): we do not use extended descriptor bit 7, and do not use
6726 // hardware checksum. Therefore, descriptor size is 4, not 8
6727 // ETH->DMABMR = BIT(13) | BIT(16) | BIT(22) | BIT(23) | BIT(25);
6728 ETH->MACIMR = BIT(3) | BIT(9); // Mask timestamp & PMT IT
6729 ETH->MACFCR = BIT(7); // Disable zero quarta pause
6730 // ETH->MACFFR = BIT(31); // Receive all
6731 eth_write_phy(PHY_ADDR, PHY_BCR, BIT(15)); // Reset PHY
6732 eth_write_phy(PHY_ADDR, PHY_BCR, BIT(12)); // Set autonegotiation
6733 ETH->DMARDLAR = (uint32_t) (uintptr_t) s_rxdesc; // RX descriptors
6734 ETH->DMATDLAR = (uint32_t) (uintptr_t) s_txdesc; // RX descriptors
6735 ETH->DMAIER = BIT(6) | BIT(16); // RIE, NISE
6736 ETH->MACCR = BIT(2) | BIT(3) | BIT(11) | BIT(14); // RE, TE, Duplex, Fast
6737 ETH->DMAOMR = BIT(1) | BIT(13) | BIT(21) | BIT(25); // SR, ST, TSF, RSF
6739 // MAC address filtering
6740 ETH->MACA0HR = ((uint32_t) ifp->mac[5] << 8U) | ifp->mac[4];
6741 ETH->MACA0LR = (uint32_t) (ifp->mac[3] << 24) |
6742 ((uint32_t) ifp->mac[2] << 16) |
6743 ((uint32_t) ifp->mac[1] << 8) | ifp->mac[0];
6747 static size_t mg_tcpip_driver_stm32_tx(const void *buf, size_t len,
6748 struct mg_tcpip_if *ifp) {
6749 if (len > sizeof(s_txbuf[s_txno])) {
6750 MG_ERROR(("Frame too big, %ld", (long) len));
6751 len = 0; // Frame is too big
6752 } else if ((s_txdesc[s_txno][0] & BIT(31))) {
6754 MG_ERROR(("No free descriptors"));
6755 // printf("D0 %lx SR %lx\n", (long) s_txdesc[0][0], (long) ETH->DMASR);
6756 len = 0; // All descriptors are busy, fail
6758 memcpy(s_txbuf[s_txno], buf, len); // Copy data
6759 s_txdesc[s_txno][1] = (uint32_t) len; // Set data len
6760 s_txdesc[s_txno][0] = BIT(20) | BIT(28) | BIT(29) | BIT(30); // Chain,FS,LS
6761 s_txdesc[s_txno][0] |= BIT(31); // Set OWN bit - let DMA take over
6762 if (++s_txno >= ETH_DESC_CNT) s_txno = 0;
6764 ETH->DMASR = BIT(2) | BIT(5); // Clear any prior TBUS/TUS
6765 ETH->DMATPDR = 0; // and resume
6769 static bool mg_tcpip_driver_stm32_up(struct mg_tcpip_if *ifp) {
6770 uint32_t bsr = eth_read_phy(PHY_ADDR, PHY_BSR);
6771 bool up = bsr & BIT(2) ? 1 : 0;
6772 if ((ifp->state == MG_TCPIP_STATE_DOWN) && up) { // link state just went up
6773 uint32_t scsr = eth_read_phy(PHY_ADDR, PHY_CSCR);
6774 uint32_t maccr = ETH->MACCR | BIT(14) | BIT(11); // 100M, Full-duplex
6775 if ((scsr & BIT(3)) == 0) maccr &= ~BIT(14); // 10M
6776 if ((scsr & BIT(4)) == 0) maccr &= ~BIT(11); // Half-duplex
6777 ETH->MACCR = maccr; // IRQ handler does not fiddle with this register
6778 MG_DEBUG(("Link is %uM %s-duplex", maccr & BIT(14) ? 100 : 10,
6779 maccr & BIT(11) ? "full" : "half"));
6784 void ETH_IRQHandler(void);
6785 void ETH_IRQHandler(void) {
6786 if (ETH->DMASR & BIT(6)) { // Frame received, loop
6787 ETH->DMASR = BIT(16) | BIT(6); // Clear flag
6788 for (uint32_t i = 0; i < 10; i++) { // read as they arrive but not forever
6789 if (s_rxdesc[s_rxno][0] & BIT(31)) break; // exit when done
6790 if (((s_rxdesc[s_rxno][0] & (BIT(8) | BIT(9))) == (BIT(8) | BIT(9))) &&
6791 !(s_rxdesc[s_rxno][0] & BIT(15))) { // skip partial/errored frames
6792 uint32_t len = ((s_rxdesc[s_rxno][0] >> 16) & (BIT(14) - 1));
6793 // printf("%lx %lu %lx %.8lx\n", s_rxno, len, s_rxdesc[s_rxno][0],
6795 mg_tcpip_qwrite(s_rxbuf[s_rxno], len > 4 ? len - 4 : len, s_ifp);
6797 s_rxdesc[s_rxno][0] = BIT(31);
6798 if (++s_rxno >= ETH_DESC_CNT) s_rxno = 0;
6801 ETH->DMASR = BIT(7); // Clear possible RBUS while processing
6802 ETH->DMARPDR = 0; // and resume RX
6805 struct mg_tcpip_driver mg_tcpip_driver_stm32 = {mg_tcpip_driver_stm32_init,
6806 mg_tcpip_driver_stm32_tx, NULL,
6807 mg_tcpip_driver_stm32_up};
6810 #ifdef MG_ENABLE_LINES
6811 #line 1 "src/tcpip/driver_stm32h.c"
6815 #if MG_ENABLE_TCPIP && defined(MG_ENABLE_DRIVER_STM32H) && \
6816 MG_ENABLE_DRIVER_STM32H
6818 volatile uint32_t MACCR, MACECR, MACPFR, MACWTR, MACHT0R, MACHT1R,
6819 RESERVED1[14], MACVTR, RESERVED2, MACVHTR, RESERVED3, MACVIR, MACIVIR,
6820 RESERVED4[2], MACTFCR, RESERVED5[7], MACRFCR, RESERVED6[7], MACISR,
6821 MACIER, MACRXTXSR, RESERVED7, MACPCSR, MACRWKPFR, RESERVED8[2], MACLCSR,
6822 MACLTCR, MACLETR, MAC1USTCR, RESERVED9[12], MACVR, MACDR, RESERVED10,
6823 MACHWF0R, MACHWF1R, MACHWF2R, RESERVED11[54], MACMDIOAR, MACMDIODR,
6824 RESERVED12[2], MACARPAR, RESERVED13[59], MACA0HR, MACA0LR, MACA1HR,
6825 MACA1LR, MACA2HR, MACA2LR, MACA3HR, MACA3LR, RESERVED14[248], MMCCR,
6826 MMCRIR, MMCTIR, MMCRIMR, MMCTIMR, RESERVED15[14], MMCTSCGPR, MMCTMCGPR,
6827 RESERVED16[5], MMCTPCGR, RESERVED17[10], MMCRCRCEPR, MMCRAEPR,
6828 RESERVED18[10], MMCRUPGR, RESERVED19[9], MMCTLPIMSTR, MMCTLPITCR,
6829 MMCRLPIMSTR, MMCRLPITCR, RESERVED20[65], MACL3L4C0R, MACL4A0R,
6830 RESERVED21[2], MACL3A0R0R, MACL3A1R0R, MACL3A2R0R, MACL3A3R0R,
6831 RESERVED22[4], MACL3L4C1R, MACL4A1R, RESERVED23[2], MACL3A0R1R,
6832 MACL3A1R1R, MACL3A2R1R, MACL3A3R1R, RESERVED24[108], MACTSCR, MACSSIR,
6833 MACSTSR, MACSTNR, MACSTSUR, MACSTNUR, MACTSAR, RESERVED25, MACTSSR,
6834 RESERVED26[3], MACTTSSNR, MACTTSSSR, RESERVED27[2], MACACR, RESERVED28,
6835 MACATSNR, MACATSSR, MACTSIACR, MACTSEACR, MACTSICNR, MACTSECNR,
6836 RESERVED29[4], MACPPSCR, RESERVED30[3], MACPPSTTSR, MACPPSTTNR, MACPPSIR,
6837 MACPPSWR, RESERVED31[12], MACPOCR, MACSPI0R, MACSPI1R, MACSPI2R, MACLMIR,
6838 RESERVED32[11], MTLOMR, RESERVED33[7], MTLISR, RESERVED34[55], MTLTQOMR,
6839 MTLTQUR, MTLTQDR, RESERVED35[8], MTLQICSR, MTLRQOMR, MTLRQMPOCR, MTLRQDR,
6840 RESERVED36[177], DMAMR, DMASBMR, DMAISR, DMADSR, RESERVED37[60], DMACCR,
6841 DMACTCR, DMACRCR, RESERVED38[2], DMACTDLAR, RESERVED39, DMACRDLAR,
6842 DMACTDTPR, RESERVED40, DMACRDTPR, DMACTDRLR, DMACRDRLR, DMACIER,
6843 DMACRIWTR, DMACSFCSR, RESERVED41, DMACCATDR, RESERVED42, DMACCARDR,
6844 RESERVED43, DMACCATBR, RESERVED44, DMACCARBR, DMACSR, RESERVED45[2],
6849 ((struct stm32h_eth *) (uintptr_t) (0x40000000UL + 0x00020000UL + 0x8000UL))
6852 #define BIT(x) ((uint32_t) 1 << (x))
6853 #define ETH_PKT_SIZE 1540 // Max frame size
6854 #define ETH_DESC_CNT 4 // Descriptors count
6855 #define ETH_DS 4 // Descriptor size (words)
6857 static volatile uint32_t s_rxdesc[ETH_DESC_CNT][ETH_DS]; // RX descriptors
6858 static volatile uint32_t s_txdesc[ETH_DESC_CNT][ETH_DS]; // TX descriptors
6859 static uint8_t s_rxbuf[ETH_DESC_CNT][ETH_PKT_SIZE]; // RX ethernet buffers
6860 static uint8_t s_txbuf[ETH_DESC_CNT][ETH_PKT_SIZE]; // TX ethernet buffers
6861 static struct mg_tcpip_if *s_ifp; // MIP interface
6869 static uint32_t eth_read_phy(uint8_t addr, uint8_t reg) {
6870 ETH->MACMDIOAR &= (0xF << 8);
6871 ETH->MACMDIOAR |= ((uint32_t) addr << 21) | ((uint32_t) reg << 16) | 3 << 2;
6872 ETH->MACMDIOAR |= BIT(0);
6873 while (ETH->MACMDIOAR & BIT(0)) (void) 0;
6874 return ETH->MACMDIODR;
6877 static void eth_write_phy(uint8_t addr, uint8_t reg, uint32_t val) {
6878 ETH->MACMDIODR = val;
6879 ETH->MACMDIOAR &= (0xF << 8);
6880 ETH->MACMDIOAR |= ((uint32_t) addr << 21) | ((uint32_t) reg << 16) | 1 << 2;
6881 ETH->MACMDIOAR |= BIT(0);
6882 while (ETH->MACMDIOAR & BIT(0)) (void) 0;
6885 static uint32_t get_hclk(void) {
6887 volatile uint32_t CR, HSICFGR, CRRCR, CSICFGR, CFGR, RESERVED1, D1CFGR,
6888 D2CFGR, D3CFGR, RESERVED2, PLLCKSELR, PLLCFGR, PLL1DIVR, PLL1FRACR,
6889 PLL2DIVR, PLL2FRACR, PLL3DIVR, PLL3FRACR, RESERVED3, D1CCIPR, D2CCIP1R,
6890 D2CCIP2R, D3CCIPR, RESERVED4, CIER, CIFR, CICR, RESERVED5, BDCR, CSR,
6891 RESERVED6, AHB3RSTR, AHB1RSTR, AHB2RSTR, AHB4RSTR, APB3RSTR, APB1LRSTR,
6892 APB1HRSTR, APB2RSTR, APB4RSTR, GCR, RESERVED8, D3AMR, RESERVED11[9],
6893 RSR, AHB3ENR, AHB1ENR, AHB2ENR, AHB4ENR, APB3ENR, APB1LENR, APB1HENR,
6894 APB2ENR, APB4ENR, RESERVED12, AHB3LPENR, AHB1LPENR, AHB2LPENR,
6895 AHB4LPENR, APB3LPENR, APB1LLPENR, APB1HLPENR, APB2LPENR, APB4LPENR,
6897 } *rcc = ((struct rcc *) (0x40000000 + 0x18020000 + 0x4400));
6898 uint32_t clk = 0, hsi = 64000000 /* 64 MHz */, hse = 8000000 /* 8MHz */,
6899 csi = 4000000 /* 4MHz */;
6900 unsigned int sel = (rcc->CFGR & (7 << 3)) >> 3;
6904 } else if (sel == 2) {
6906 } else if (sel == 3) {
6907 uint32_t vco, m, n, p;
6908 unsigned int src = (rcc->PLLCKSELR & (3 << 0)) >> 0;
6909 m = ((rcc->PLLCKSELR & (0x3F << 4)) >> 4);
6910 n = ((rcc->PLL1DIVR & (0x1FF << 0)) >> 0) + 1 +
6911 ((rcc->PLLCFGR & BIT(0)) ? 1 : 0); // round-up in fractional mode
6912 p = ((rcc->PLL1DIVR & (0x7F << 9)) >> 9) + 1;
6915 } else if (src == 2) {
6919 clk >>= ((rcc->CR & 3) >> 3);
6921 vco = (uint32_t) ((uint64_t) clk * n / m);
6925 clk >>= ((rcc->CR & 3) >> 3);
6927 const uint8_t cptab[12] = {1, 2, 3, 4, 6, 7, 8, 9}; // log2(div)
6928 uint32_t d1cpre = (rcc->D1CFGR & (0x0F << 8)) >> 8;
6929 if (d1cpre >= 8) clk >>= cptab[d1cpre - 8];
6930 MG_DEBUG(("D1 CLK: %u", clk));
6931 uint32_t hpre = (rcc->D1CFGR & (0x0F << 0)) >> 0;
6932 if (hpre < 8) return clk;
6933 return ((uint32_t) clk) >> cptab[hpre - 8];
6936 // Guess CR from AHB1 clock. MDC clock is generated from the ETH peripheral
6937 // clock (AHB1); as per 802.3, it must not exceed 2. As the AHB clock can
6938 // be derived from HSI or CSI (internal RC) clocks, and those can go above
6939 // specs, the datasheets specify a range of frequencies and activate one of a
6940 // series of dividers to keep the MDC clock safely below 2.5MHz. We guess a
6941 // divider setting based on HCLK with some drift. If the user uses a different
6942 // clock from our defaults, needs to set the macros on top. Valid for
6943 // STM32H74xxx/75xxx (58.11.4)(4.5% worst case drift)(CSI clock has a 7.5 %
6944 // worst case drift @ max temp)
6945 static int guess_mdc_cr(void) {
6946 const uint8_t crs[] = {2, 3, 0, 1, 4, 5}; // ETH->MACMDIOAR::CR values
6947 const uint8_t div[] = {16, 26, 42, 62, 102, 124}; // Respective HCLK dividers
6948 uint32_t hclk = get_hclk(); // Guess system HCLK
6949 int result = -1; // Invalid CR value
6950 for (int i = 0; i < 6; i++) {
6951 if (hclk / div[i] <= 2375000UL /* 2.5MHz - 5% */) {
6956 if (result < 0) MG_ERROR(("HCLK too high"));
6957 MG_DEBUG(("HCLK: %u, CR: %d", hclk, result));
6961 static bool mg_tcpip_driver_stm32h_init(struct mg_tcpip_if *ifp) {
6962 struct mg_tcpip_driver_stm32h_data *d =
6963 (struct mg_tcpip_driver_stm32h_data *) ifp->driver_data;
6966 // Init RX descriptors
6967 for (int i = 0; i < ETH_DESC_CNT; i++) {
6968 s_rxdesc[i][0] = (uint32_t) (uintptr_t) s_rxbuf[i]; // Point to data buffer
6969 s_rxdesc[i][3] = BIT(31) | BIT(30) | BIT(24); // OWN, IOC, BUF1V
6972 // Init TX descriptors
6973 for (int i = 0; i < ETH_DESC_CNT; i++) {
6974 s_txdesc[i][0] = (uint32_t) (uintptr_t) s_txbuf[i]; // Buf pointer
6977 ETH->DMAMR |= BIT(0); // Software reset
6978 while ((ETH->DMAMR & BIT(0)) != 0) (void) 0; // Wait until done
6980 // Set MDC clock divider. If user told us the value, use it. Otherwise, guess
6981 int cr = (d == NULL || d->mdc_cr < 0) ? guess_mdc_cr() : d->mdc_cr;
6982 ETH->MACMDIOAR = ((uint32_t) cr & 0xF) << 8;
6984 // NOTE(scaprile): We do not use timing facilities so the DMA engine does not
6985 // re-write buffer address
6986 ETH->DMAMR = 0 << 16; // use interrupt mode 0 (58.8.1) (reset value)
6987 ETH->DMASBMR |= BIT(12); // AAL NOTE(scaprile): is this actually needed
6988 ETH->MACIER = 0; // Do not enable additional irq sources (reset value)
6989 ETH->MACTFCR = BIT(7); // Disable zero-quanta pause
6990 // ETH->MACPFR = BIT(31); // Receive all
6991 eth_write_phy(PHY_ADDR, PHY_BCR, BIT(15)); // Reset PHY
6992 eth_write_phy(PHY_ADDR, PHY_BCR, BIT(12)); // Set autonegotiation
6994 (uint32_t) (uintptr_t) s_rxdesc; // RX descriptors start address
6995 ETH->DMACRDRLR = ETH_DESC_CNT - 1; // ring length
6997 (uint32_t) (uintptr_t) &s_rxdesc[ETH_DESC_CNT -
6998 1]; // last valid descriptor address
7000 (uint32_t) (uintptr_t) s_txdesc; // TX descriptors start address
7001 ETH->DMACTDRLR = ETH_DESC_CNT - 1; // ring length
7003 (uint32_t) (uintptr_t) s_txdesc; // first available descriptor address
7004 ETH->DMACCR = 0; // DSL = 0 (contiguous descriptor table) (reset value)
7005 ETH->DMACIER = BIT(6) | BIT(15); // RIE, NIE
7006 ETH->MACCR = BIT(0) | BIT(1) | BIT(13) | BIT(14) |
7007 BIT(15); // RE, TE, Duplex, Fast, Reserved
7008 ETH->MTLTQOMR |= BIT(1); // TSF
7009 ETH->MTLRQOMR |= BIT(5); // RSF
7010 ETH->DMACTCR |= BIT(0); // ST
7011 ETH->DMACRCR |= BIT(0); // SR
7013 // MAC address filtering
7014 ETH->MACA0HR = ((uint32_t) ifp->mac[5] << 8U) | ifp->mac[4];
7015 ETH->MACA0LR = (uint32_t) (ifp->mac[3] << 24) |
7016 ((uint32_t) ifp->mac[2] << 16) |
7017 ((uint32_t) ifp->mac[1] << 8) | ifp->mac[0];
7021 static uint32_t s_txno;
7022 static size_t mg_tcpip_driver_stm32h_tx(const void *buf, size_t len,
7023 struct mg_tcpip_if *ifp) {
7024 if (len > sizeof(s_txbuf[s_txno])) {
7025 MG_ERROR(("Frame too big, %ld", (long) len));
7026 len = 0; // Frame is too big
7027 } else if ((s_txdesc[s_txno][3] & BIT(31))) {
7028 MG_ERROR(("No free descriptors: %u %08X %08X %08X", s_txno,
7029 s_txdesc[s_txno][3], ETH->DMACSR, ETH->DMACTCR));
7030 for (int i = 0; i < ETH_DESC_CNT; i++) MG_ERROR(("%08X", s_txdesc[i][3]));
7031 len = 0; // All descriptors are busy, fail
7033 memcpy(s_txbuf[s_txno], buf, len); // Copy data
7034 s_txdesc[s_txno][2] = (uint32_t) len; // Set data len
7035 s_txdesc[s_txno][3] = BIT(28) | BIT(29); // FD, LD
7036 s_txdesc[s_txno][3] |= BIT(31); // Set OWN bit - let DMA take over
7037 if (++s_txno >= ETH_DESC_CNT) s_txno = 0;
7039 ETH->DMACSR |= BIT(2) | BIT(1); // Clear any prior TBU, TPS
7040 ETH->DMACTDTPR = (uint32_t) (uintptr_t) &s_txdesc[s_txno]; // and resume
7045 static bool mg_tcpip_driver_stm32h_up(struct mg_tcpip_if *ifp) {
7046 uint32_t bsr = eth_read_phy(PHY_ADDR, PHY_BSR);
7047 bool up = bsr & BIT(2) ? 1 : 0;
7048 if ((ifp->state == MG_TCPIP_STATE_DOWN) && up) { // link state just went up
7049 uint32_t scsr = eth_read_phy(PHY_ADDR, PHY_CSCR);
7050 uint32_t maccr = ETH->MACCR | BIT(14) | BIT(13); // 100M, Full-duplex
7051 if ((scsr & BIT(3)) == 0) maccr &= ~BIT(14); // 10M
7052 if ((scsr & BIT(4)) == 0) maccr &= ~BIT(13); // Half-duplex
7053 ETH->MACCR = maccr; // IRQ handler does not fiddle with this register
7054 MG_DEBUG(("Link is %uM %s-duplex", maccr & BIT(14) ? 100 : 10,
7055 maccr & BIT(13) ? "full" : "half"));
7060 void ETH_IRQHandler(void);
7061 static uint32_t s_rxno;
7062 void ETH_IRQHandler(void) {
7063 if (ETH->DMACSR & BIT(6)) { // Frame received, loop
7064 ETH->DMACSR = BIT(15) | BIT(6); // Clear flag
7065 for (uint32_t i = 0; i < 10; i++) { // read as they arrive but not forever
7066 if (s_rxdesc[s_rxno][3] & BIT(31)) break; // exit when done
7067 if (((s_rxdesc[s_rxno][3] & (BIT(28) | BIT(29))) ==
7068 (BIT(28) | BIT(29))) &&
7069 !(s_rxdesc[s_rxno][3] & BIT(15))) { // skip partial/errored frames
7070 uint32_t len = s_rxdesc[s_rxno][3] & (BIT(15) - 1);
7071 // MG_DEBUG(("%lx %lu %lx %08lx", s_rxno, len, s_rxdesc[s_rxno][3],
7073 mg_tcpip_qwrite(s_rxbuf[s_rxno], len > 4 ? len - 4 : len, s_ifp);
7075 s_rxdesc[s_rxno][3] = BIT(31) | BIT(30) | BIT(24); // OWN, IOC, BUF1V
7076 if (++s_rxno >= ETH_DESC_CNT) s_rxno = 0;
7079 ETH->DMACSR = BIT(7) | BIT(8); // Clear possible RBU RPS while processing
7081 (uint32_t) (uintptr_t) &s_rxdesc[ETH_DESC_CNT - 1]; // and resume RX
7084 struct mg_tcpip_driver mg_tcpip_driver_stm32h = {
7085 mg_tcpip_driver_stm32h_init, mg_tcpip_driver_stm32h_tx, NULL,
7086 mg_tcpip_driver_stm32h_up};
7089 #ifdef MG_ENABLE_LINES
7090 #line 1 "src/tcpip/driver_tm4c.c"
7094 #if MG_ENABLE_TCPIP && defined(MG_ENABLE_DRIVER_TM4C) && MG_ENABLE_DRIVER_TM4C
7096 volatile uint32_t EMACCFG, EMACFRAMEFLTR, EMACHASHTBLH, EMACHASHTBLL,
7097 EMACMIIADDR, EMACMIIDATA, EMACFLOWCTL, EMACVLANTG, RESERVED0, EMACSTATUS,
7098 EMACRWUFF, EMACPMTCTLSTAT, RESERVED1[2], EMACRIS, EMACIM, EMACADDR0H,
7099 EMACADDR0L, EMACADDR1H, EMACADDR1L, EMACADDR2H, EMACADDR2L, EMACADDR3H,
7100 EMACADDR3L, RESERVED2[31], EMACWDOGTO, RESERVED3[8], EMACMMCCTRL,
7101 EMACMMCRXRIS, EMACMMCTXRIS, EMACMMCRXIM, EMACMMCTXIM, RESERVED4,
7102 EMACTXCNTGB, RESERVED5[12], EMACTXCNTSCOL, EMACTXCNTMCOL, RESERVED6[4],
7103 EMACTXOCTCNTG, RESERVED7[6], EMACRXCNTGB, RESERVED8[4], EMACRXCNTCRCERR,
7104 EMACRXCNTALGNERR, RESERVED9[10], EMACRXCNTGUNI, RESERVED10[239],
7105 EMACVLNINCREP, EMACVLANHASH, RESERVED11[93], EMACTIMSTCTRL, EMACSUBSECINC,
7106 EMACTIMSEC, EMACTIMNANO, EMACTIMSECU, EMACTIMNANOU, EMACTIMADD,
7107 EMACTARGSEC, EMACTARGNANO, EMACHWORDSEC, EMACTIMSTAT, EMACPPSCTRL,
7108 RESERVED12[12], EMACPPS0INTVL, EMACPPS0WIDTH, RESERVED13[294],
7109 EMACDMABUSMOD, EMACTXPOLLD, EMACRXPOLLD, EMACRXDLADDR, EMACTXDLADDR,
7110 EMACDMARIS, EMACDMAOPMODE, EMACDMAIM, EMACMFBOC, EMACRXINTWDT,
7111 RESERVED14[8], EMACHOSTXDESC, EMACHOSRXDESC, EMACHOSTXBA, EMACHOSRXBA,
7112 RESERVED15[218], EMACPP, EMACPC, EMACCC, RESERVED16, EMACEPHYRIS,
7113 EMACEPHYIM, EMACEPHYIMSC;
7116 #define EMAC ((struct tm4c_emac *) (uintptr_t) 0x400EC000)
7119 #define BIT(x) ((uint32_t) 1 << (x))
7120 #define ETH_PKT_SIZE 1540 // Max frame size
7121 #define ETH_DESC_CNT 4 // Descriptors count
7122 #define ETH_DS 4 // Descriptor size (words)
7124 static uint32_t s_rxdesc[ETH_DESC_CNT][ETH_DS]; // RX descriptors
7125 static uint32_t s_txdesc[ETH_DESC_CNT][ETH_DS]; // TX descriptors
7126 static uint8_t s_rxbuf[ETH_DESC_CNT][ETH_PKT_SIZE]; // RX ethernet buffers
7127 static uint8_t s_txbuf[ETH_DESC_CNT][ETH_PKT_SIZE]; // TX ethernet buffers
7128 static struct mg_tcpip_if *s_ifp; // MIP interface
7136 static inline void tm4cspin(volatile uint32_t count) {
7137 while (count--) (void) 0;
7140 static uint32_t emac_read_phy(uint8_t addr, uint8_t reg) {
7141 EMAC->EMACMIIADDR &= (0xf << 2);
7142 EMAC->EMACMIIADDR |= ((uint32_t) addr << 11) | ((uint32_t) reg << 6);
7143 EMAC->EMACMIIADDR |= BIT(0);
7144 while (EMAC->EMACMIIADDR & BIT(0)) tm4cspin(1);
7145 return EMAC->EMACMIIDATA;
7148 static void emac_write_phy(uint8_t addr, uint8_t reg, uint32_t val) {
7149 EMAC->EMACMIIDATA = val;
7150 EMAC->EMACMIIADDR &= (0xf << 2);
7151 EMAC->EMACMIIADDR |= ((uint32_t) addr << 11) | ((uint32_t) reg << 6) | BIT(1);
7152 EMAC->EMACMIIADDR |= BIT(0);
7153 while (EMAC->EMACMIIADDR & BIT(0)) tm4cspin(1);
7156 static uint32_t get_sysclk(void) {
7158 volatile uint32_t DONTCARE0[44], RSCLKCFG, DONTCARE1[43], PLLFREQ0,
7160 } *sysctl = (struct sysctl *) 0x400FE000;
7161 uint32_t clk = 0, piosc = 16000000 /* 16 MHz */, mosc = 25000000 /* 25MHz */;
7162 if (sysctl->RSCLKCFG & (1 << 28)) { // USEPLL
7163 uint32_t fin, vco, mdiv, n, q, psysdiv;
7164 uint32_t pllsrc = (sysctl->RSCLKCFG & (0xf << 24)) >> 24;
7167 } else if (pllsrc == 3) {
7170 MG_ERROR(("Unsupported clock source"));
7172 q = (sysctl->PLLFREQ1 & (0x1f << 8)) >> 8;
7173 n = (sysctl->PLLFREQ1 & (0x1f << 0)) >> 0;
7174 fin = clk / ((q + 1) * (n + 1));
7175 mdiv = (sysctl->PLLFREQ0 & (0x3ff << 0)) >>
7176 0; // mint + (mfrac / 1024); MFRAC not supported
7177 psysdiv = (sysctl->RSCLKCFG & (0x3f << 0)) >> 0;
7178 vco = (uint32_t) ((uint64_t) fin * mdiv);
7179 return vco / (psysdiv + 1);
7181 uint32_t oscsrc = (sysctl->RSCLKCFG & (0xf << 20)) >> 20;
7184 } else if (oscsrc == 3) {
7187 MG_ERROR(("Unsupported clock source"));
7189 uint32_t osysdiv = (sysctl->RSCLKCFG & (0xf << 16)) >> 16;
7190 return clk / (osysdiv + 1);
7193 // Guess CR from SYSCLK. MDC clock is generated from SYSCLK (AHB); as per
7194 // 802.3, it must not exceed 2.5MHz (also 20.4.2.6) As the AHB clock can be
7195 // derived from the PIOSC (internal RC), and it can go above specs, the
7196 // datasheets specify a range of frequencies and activate one of a series of
7197 // dividers to keep the MDC clock safely below 2.5MHz. We guess a divider
7198 // setting based on SYSCLK with a +5% drift. If the user uses a different clock
7199 // from our defaults, needs to set the macros on top Valid for TM4C129x (20.7)
7200 // (4.5% worst case drift)
7201 // The PHY receives the main oscillator (MOSC) (20.3.1)
7202 static int guess_mdc_cr(void) {
7203 uint8_t crs[] = {2, 3, 0, 1}; // EMAC->MACMIIAR::CR values
7204 uint8_t div[] = {16, 26, 42, 62}; // Respective HCLK dividers
7205 uint32_t sysclk = get_sysclk(); // Guess system SYSCLK
7206 int result = -1; // Invalid CR value
7207 if (sysclk < 25000000) {
7208 MG_ERROR(("SYSCLK too low"));
7210 for (int i = 0; i < 4; i++) {
7211 if (sysclk / div[i] <= 2375000UL /* 2.5MHz - 5% */) {
7216 if (result < 0) MG_ERROR(("SYSCLK too high"));
7218 MG_DEBUG(("SYSCLK: %u, CR: %d", sysclk, result));
7222 static bool mg_tcpip_driver_tm4c_init(struct mg_tcpip_if *ifp) {
7223 struct mg_tcpip_driver_tm4c_data *d =
7224 (struct mg_tcpip_driver_tm4c_data *) ifp->driver_data;
7227 // Init RX descriptors
7228 for (int i = 0; i < ETH_DESC_CNT; i++) {
7229 s_rxdesc[i][0] = BIT(31); // Own
7230 s_rxdesc[i][1] = sizeof(s_rxbuf[i]) | BIT(14); // 2nd address chained
7231 s_rxdesc[i][2] = (uint32_t) (uintptr_t) s_rxbuf[i]; // Point to data buffer
7233 (uint32_t) (uintptr_t) s_rxdesc[(i + 1) % ETH_DESC_CNT]; // Chain
7234 // MG_DEBUG(("%d %p", i, s_rxdesc[i]));
7237 // Init TX descriptors
7238 for (int i = 0; i < ETH_DESC_CNT; i++) {
7239 s_txdesc[i][2] = (uint32_t) (uintptr_t) s_txbuf[i]; // Buf pointer
7241 (uint32_t) (uintptr_t) s_txdesc[(i + 1) % ETH_DESC_CNT]; // Chain
7244 EMAC->EMACDMABUSMOD |= BIT(0); // Software reset
7245 while ((EMAC->EMACDMABUSMOD & BIT(0)) != 0) tm4cspin(1); // Wait until done
7247 // Set MDC clock divider. If user told us the value, use it. Otherwise, guess
7248 int cr = (d == NULL || d->mdc_cr < 0) ? guess_mdc_cr() : d->mdc_cr;
7249 EMAC->EMACMIIADDR = ((uint32_t) cr & 0xf) << 2;
7251 // NOTE(cpq): we do not use extended descriptor bit 7, and do not use
7252 // hardware checksum. Therefore, descriptor size is 4, not 8
7253 // EMAC->EMACDMABUSMOD = BIT(13) | BIT(16) | BIT(22) | BIT(23) | BIT(25);
7254 EMAC->EMACIM = BIT(3) | BIT(9); // Mask timestamp & PMT IT
7255 EMAC->EMACFLOWCTL = BIT(7); // Disable zero-quanta pause
7256 // EMAC->EMACFRAMEFLTR = BIT(31); // Receive all
7257 // EMAC->EMACPC defaults to internal PHY (EPHY) in MMI mode
7258 emac_write_phy(EPHY_ADDR, EPHYBMCR, BIT(15)); // Reset internal PHY (EPHY)
7259 emac_write_phy(EPHY_ADDR, EPHYBMCR, BIT(12)); // Set autonegotiation
7260 EMAC->EMACRXDLADDR = (uint32_t) (uintptr_t) s_rxdesc; // RX descriptors
7261 EMAC->EMACTXDLADDR = (uint32_t) (uintptr_t) s_txdesc; // TX descriptors
7262 EMAC->EMACDMAIM = BIT(6) | BIT(16); // RIE, NIE
7263 EMAC->EMACCFG = BIT(2) | BIT(3) | BIT(11) | BIT(14); // RE, TE, Duplex, Fast
7264 EMAC->EMACDMAOPMODE =
7265 BIT(1) | BIT(13) | BIT(21) | BIT(25); // SR, ST, TSF, RSF
7266 EMAC->EMACADDR0H = ((uint32_t) ifp->mac[5] << 8U) | ifp->mac[4];
7267 EMAC->EMACADDR0L = (uint32_t) (ifp->mac[3] << 24) |
7268 ((uint32_t) ifp->mac[2] << 16) |
7269 ((uint32_t) ifp->mac[1] << 8) | ifp->mac[0];
7270 // NOTE(scaprile) There are 3 additional slots for filtering, disabled by
7271 // default. This also applies to the STM32 driver (at least for F7)
7275 static uint32_t s_txno;
7276 static size_t mg_tcpip_driver_tm4c_tx(const void *buf, size_t len,
7277 struct mg_tcpip_if *ifp) {
7278 if (len > sizeof(s_txbuf[s_txno])) {
7279 MG_ERROR(("Frame too big, %ld", (long) len));
7281 } else if ((s_txdesc[s_txno][0] & BIT(31))) {
7282 MG_ERROR(("No descriptors available"));
7283 // printf("D0 %lx SR %lx\n", (long) s_txdesc[0][0], (long)
7284 // EMAC->EMACDMARIS);
7287 memcpy(s_txbuf[s_txno], buf, len); // Copy data
7288 s_txdesc[s_txno][1] = (uint32_t) len; // Set data len
7289 s_txdesc[s_txno][0] =
7290 BIT(20) | BIT(28) | BIT(29) | BIT(30); // Chain,FS,LS,IC
7291 s_txdesc[s_txno][0] |= BIT(31); // Set OWN bit - let DMA take over
7292 if (++s_txno >= ETH_DESC_CNT) s_txno = 0;
7294 EMAC->EMACDMARIS = BIT(2) | BIT(5); // Clear any prior TU/UNF
7295 EMAC->EMACTXPOLLD = 0; // and resume
7300 static bool mg_tcpip_driver_tm4c_up(struct mg_tcpip_if *ifp) {
7301 uint32_t bmsr = emac_read_phy(EPHY_ADDR, EPHYBMSR);
7302 bool up = (bmsr & BIT(2)) ? 1 : 0;
7303 if ((ifp->state == MG_TCPIP_STATE_DOWN) && up) { // link state just went up
7304 uint32_t sts = emac_read_phy(EPHY_ADDR, EPHYSTS);
7305 uint32_t emaccfg = EMAC->EMACCFG | BIT(14) | BIT(11); // 100M, Full-duplex
7306 if (sts & BIT(1)) emaccfg &= ~BIT(14); // 10M
7307 if ((sts & BIT(2)) == 0) emaccfg &= ~BIT(11); // Half-duplex
7308 EMAC->EMACCFG = emaccfg; // IRQ handler does not fiddle with this register
7309 MG_DEBUG(("Link is %uM %s-duplex", emaccfg & BIT(14) ? 100 : 10,
7310 emaccfg & BIT(11) ? "full" : "half"));
7315 void EMAC0_IRQHandler(void);
7316 static uint32_t s_rxno;
7317 void EMAC0_IRQHandler(void) {
7318 if (EMAC->EMACDMARIS & BIT(6)) { // Frame received, loop
7319 EMAC->EMACDMARIS = BIT(16) | BIT(6); // Clear flag
7320 for (uint32_t i = 0; i < 10; i++) { // read as they arrive but not forever
7321 if (s_rxdesc[s_rxno][0] & BIT(31)) break; // exit when done
7322 if (((s_rxdesc[s_rxno][0] & (BIT(8) | BIT(9))) == (BIT(8) | BIT(9))) &&
7323 !(s_rxdesc[s_rxno][0] & BIT(15))) { // skip partial/errored frames
7324 uint32_t len = ((s_rxdesc[s_rxno][0] >> 16) & (BIT(14) - 1));
7325 // printf("%lx %lu %lx %.8lx\n", s_rxno, len, s_rxdesc[s_rxno][0],
7326 // EMAC->EMACDMARIS);
7327 mg_tcpip_qwrite(s_rxbuf[s_rxno], len > 4 ? len - 4 : len, s_ifp);
7329 s_rxdesc[s_rxno][0] = BIT(31);
7330 if (++s_rxno >= ETH_DESC_CNT) s_rxno = 0;
7333 EMAC->EMACDMARIS = BIT(7); // Clear possible RU while processing
7334 EMAC->EMACRXPOLLD = 0; // and resume RX
7337 struct mg_tcpip_driver mg_tcpip_driver_tm4c = {mg_tcpip_driver_tm4c_init,
7338 mg_tcpip_driver_tm4c_tx, NULL,
7339 mg_tcpip_driver_tm4c_up};
7342 #ifdef MG_ENABLE_LINES
7343 #line 1 "src/tcpip/driver_w5500.c"
7349 enum { W5500_CR = 0, W5500_S0 = 1, W5500_TX0 = 2, W5500_RX0 = 3 };
7351 static void w5500_txn(struct mg_tcpip_spi *s, uint8_t block, uint16_t addr, bool wr,
7352 void *buf, size_t len) {
7353 uint8_t *p = (uint8_t *) buf;
7354 uint8_t cmd[] = {(uint8_t) (addr >> 8), (uint8_t) (addr & 255),
7355 (uint8_t) ((block << 3) | (wr ? 4 : 0))};
7357 for (size_t i = 0; i < sizeof(cmd); i++) s->txn(s->spi, cmd[i]);
7358 for (size_t i = 0; i < len; i++) {
7359 uint8_t r = s->txn(s->spi, p[i]);
7366 static 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); }
7367 static void w5500_w1(struct mg_tcpip_spi *s, uint8_t block, uint16_t addr, uint8_t val) { w5500_wn(s, block, addr, &val, 1); }
7368 static 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)); }
7369 static 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); }
7370 static 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; }
7371 static 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]); }
7374 static size_t w5500_rx(void *buf, size_t buflen, struct mg_tcpip_if *ifp) {
7375 struct mg_tcpip_spi *s = (struct mg_tcpip_spi *) ifp->driver_data;
7376 uint16_t r = 0, n = 0, len = (uint16_t) buflen, n2; // Read recv len
7377 while ((n2 = w5500_r2(s, W5500_S0, 0x26)) > n) n = n2; // Until it is stable
7378 // printf("RSR: %d\n", (int) n);
7380 uint16_t ptr = w5500_r2(s, W5500_S0, 0x28); // Get read pointer
7381 n = w5500_r2(s, W5500_RX0, ptr); // Read frame length
7382 if (n <= len + 2 && n > 1) {
7383 r = (uint16_t) (n - 2);
7384 w5500_rn(s, W5500_RX0, (uint16_t) (ptr + 2), buf, r);
7386 w5500_w2(s, W5500_S0, 0x28, (uint16_t) (ptr + n)); // Advance read pointer
7387 w5500_w1(s, W5500_S0, 1, 0x40); // Sock0 CR -> RECV
7388 // printf(" RX_RD: tot=%u n=%u r=%u\n", n2, n, r);
7393 static size_t w5500_tx(const void *buf, size_t buflen, struct mg_tcpip_if *ifp) {
7394 struct mg_tcpip_spi *s = (struct mg_tcpip_spi *) ifp->driver_data;
7395 uint16_t n = 0, len = (uint16_t) buflen;
7396 while (n < len) n = w5500_r2(s, W5500_S0, 0x20); // Wait for space
7397 uint16_t ptr = w5500_r2(s, W5500_S0, 0x24); // Get write pointer
7398 w5500_wn(s, W5500_TX0, ptr, (void *) buf, len); // Write data
7399 w5500_w2(s, W5500_S0, 0x24, (uint16_t) (ptr + len)); // Advance write pointer
7400 w5500_w1(s, W5500_S0, 1, 0x20); // Sock0 CR -> SEND
7401 for (int i = 0; i < 40; i++) {
7402 uint8_t ir = w5500_r1(s, W5500_S0, 2); // Read S0 IR
7403 if (ir == 0) continue;
7404 // printf("IR %d, len=%d, free=%d, ptr %d\n", ir, (int) len, (int) n, ptr);
7405 w5500_w1(s, W5500_S0, 2, ir); // Write S0 IR: clear it!
7406 if (ir & 8) len = 0; // Timeout. Report error
7407 if (ir & (16 | 8)) break; // Stop on SEND_OK or timeout
7412 static bool w5500_init(struct mg_tcpip_if *ifp) {
7413 struct mg_tcpip_spi *s = (struct mg_tcpip_spi *) ifp->driver_data;
7415 w5500_w1(s, W5500_CR, 0, 0x80); // Reset chip: CR -> 0x80
7416 w5500_w1(s, W5500_CR, 0x2e, 0); // CR PHYCFGR -> reset
7417 w5500_w1(s, W5500_CR, 0x2e, 0xf8); // CR PHYCFGR -> set
7418 // w5500_wn(s, W5500_CR, 9, s->mac, 6); // Set source MAC
7419 w5500_w1(s, W5500_S0, 0x1e, 16); // Sock0 RX buf size
7420 w5500_w1(s, W5500_S0, 0x1f, 16); // Sock0 TX buf size
7421 w5500_w1(s, W5500_S0, 0, 4); // Sock0 MR -> MACRAW
7422 w5500_w1(s, W5500_S0, 1, 1); // Sock0 CR -> OPEN
7423 return w5500_r1(s, W5500_S0, 3) == 0x42; // Sock0 SR == MACRAW
7426 static bool w5500_up(struct mg_tcpip_if *ifp) {
7427 struct mg_tcpip_spi *spi = (struct mg_tcpip_spi *) ifp->driver_data;
7428 uint8_t phycfgr = w5500_r1(spi, W5500_CR, 0x2e);
7429 return phycfgr & 1; // Bit 0 of PHYCFGR is LNK (0 - down, 1 - up)
7432 struct mg_tcpip_driver mg_tcpip_driver_w5500 = {w5500_init, w5500_tx, w5500_rx, w5500_up};
7435 #ifdef MG_ENABLE_LINES
7436 #line 1 "src/tcpip/tcpip.c"
7442 #define MG_EPHEMERAL_PORT_BASE 32768
7443 #define PDIFF(a, b) ((size_t) (((char *) (b)) - ((char *) (a))))
7445 #ifndef MIP_TCP_KEEPALIVE_MS
7446 #define MIP_TCP_KEEPALIVE_MS 45000 // TCP keep-alive period, ms
7449 #define MIP_TCP_ACK_MS 150 // Timeout for ACKing
7452 uint32_t seq, ack; // TCP seq/ack counters
7453 uint64_t timer; // TCP keep-alive / ACK timer
7454 uint8_t mac[6]; // Peer MAC address
7455 uint8_t ttype; // Timer type. 0: ack, 1: keep-alive
7456 #define MIP_TTYPE_KEEPALIVE 0 // Connection is idle for long, send keepalive
7457 #define MIP_TTYPE_ACK 1 // Peer sent us data, we have to ack it soon
7458 uint8_t tmiss; // Number of keep-alive misses
7459 struct mg_iobuf raw; // For TLS only. Incoming raw data
7462 #pragma pack(push, 1)
7465 uint8_t addr, ctrl, proto[2], code, id, len[2];
7469 uint8_t dst[6]; // Destination MAC address
7470 uint8_t src[6]; // Source MAC address
7471 uint16_t type; // Ethernet type
7475 uint8_t ver; // Version
7476 uint8_t tos; // Unused
7477 uint16_t len; // Length
7478 uint16_t id; // Unused
7479 uint16_t frag; // Fragmentation
7480 uint8_t ttl; // Time to live
7481 uint8_t proto; // Upper level protocol
7482 uint16_t csum; // Checksum
7483 uint32_t src; // Source IP
7484 uint32_t dst; // Destination IP
7488 uint8_t ver; // Version
7489 uint8_t opts[3]; // Options
7490 uint16_t len; // Length
7491 uint8_t proto; // Upper level protocol
7492 uint8_t ttl; // Time to live
7493 uint8_t src[16]; // Source IP
7494 uint8_t dst[16]; // Destination IP
7504 uint16_t fmt; // Format of hardware address
7505 uint16_t pro; // Format of protocol address
7506 uint8_t hlen; // Length of hardware address
7507 uint8_t plen; // Length of protocol address
7508 uint16_t op; // Operation
7509 uint8_t sha[6]; // Sender hardware address
7510 uint32_t spa; // Sender protocol address
7511 uint8_t tha[6]; // Target hardware address
7512 uint32_t tpa; // Target protocol address
7516 uint16_t sport; // Source port
7517 uint16_t dport; // Destination port
7518 uint32_t seq; // Sequence number
7519 uint32_t ack; // Acknowledgement number
7520 uint8_t off; // Data offset
7521 uint8_t flags; // TCP flags
7525 #define TH_PUSH 0x08
7530 uint16_t win; // Window
7531 uint16_t csum; // Checksum
7532 uint16_t urp; // Urgent pointer
7536 uint16_t sport; // Source port
7537 uint16_t dport; // Destination port
7538 uint16_t len; // UDP length
7539 uint16_t csum; // UDP checksum
7543 uint8_t op, htype, hlen, hops;
7545 uint16_t secs, flags;
7546 uint32_t ciaddr, yiaddr, siaddr, giaddr;
7547 uint8_t hwaddr[208];
7549 uint8_t options[32];
7555 struct mg_str raw; // Raw packet data
7556 struct mg_str pay; // Payload data
7568 static void mkpay(struct pkt *pkt, void *p) {
7570 mg_str_n((char *) p, (size_t) (&pkt->raw.ptr[pkt->raw.len] - (char *) p));
7573 static uint32_t csumup(uint32_t sum, const void *buf, size_t len) {
7574 const uint8_t *p = (const uint8_t *) buf;
7575 for (size_t i = 0; i < len; i++) sum += i & 1 ? p[i] : (uint32_t) (p[i] << 8);
7579 static uint16_t csumfin(uint32_t sum) {
7580 while (sum >> 16) sum = (sum & 0xffff) + (sum >> 16);
7581 return mg_htons(~sum & 0xffff);
7584 static uint16_t ipcsum(const void *buf, size_t len) {
7585 uint32_t sum = csumup(0, buf, len);
7586 return csumfin(sum);
7589 static size_t ether_output(struct mg_tcpip_if *ifp, size_t len) {
7590 // size_t min = 64; // Pad short frames to 64 bytes (minimum Ethernet size)
7591 // if (len < min) memset(ifp->tx.ptr + len, 0, min - len), len = min;
7592 // mg_hexdump(ifp->tx.ptr, len);
7593 size_t n = ifp->driver->tx(ifp->tx.ptr, len, ifp);
7594 if (n == len) ifp->nsent++;
7598 static void arp_ask(struct mg_tcpip_if *ifp, uint32_t ip) {
7599 struct eth *eth = (struct eth *) ifp->tx.ptr;
7600 struct arp *arp = (struct arp *) (eth + 1);
7601 memset(eth->dst, 255, sizeof(eth->dst));
7602 memcpy(eth->src, ifp->mac, sizeof(eth->src));
7603 eth->type = mg_htons(0x806);
7604 memset(arp, 0, sizeof(*arp));
7605 arp->fmt = mg_htons(1), arp->pro = mg_htons(0x800), arp->hlen = 6,
7607 arp->op = mg_htons(1), arp->tpa = ip, arp->spa = ifp->ip;
7608 memcpy(arp->sha, ifp->mac, sizeof(arp->sha));
7609 ether_output(ifp, PDIFF(eth, arp + 1));
7612 static void onstatechange(struct mg_tcpip_if *ifp) {
7613 if (ifp->state == MG_TCPIP_STATE_READY) {
7614 MG_INFO(("READY, IP: %M", mg_print_ip4, &ifp->ip));
7615 MG_INFO((" GW: %M", mg_print_ip4, &ifp->gw));
7616 if (ifp->lease_expire > ifp->now) {
7618 (" Lease: %lld sec", (ifp->lease_expire - ifp->now) / 1000));
7620 arp_ask(ifp, ifp->gw);
7621 } else if (ifp->state == MG_TCPIP_STATE_UP) {
7622 MG_ERROR(("Link up"));
7623 srand((unsigned int) mg_millis());
7624 } else if (ifp->state == MG_TCPIP_STATE_DOWN) {
7625 MG_ERROR(("Link down"));
7629 static struct ip *tx_ip(struct mg_tcpip_if *ifp, uint8_t *mac_dst,
7630 uint8_t proto, uint32_t ip_src, uint32_t ip_dst,
7632 struct eth *eth = (struct eth *) ifp->tx.ptr;
7633 struct ip *ip = (struct ip *) (eth + 1);
7634 memcpy(eth->dst, mac_dst, sizeof(eth->dst));
7635 memcpy(eth->src, ifp->mac, sizeof(eth->src)); // Use our MAC
7636 eth->type = mg_htons(0x800);
7637 memset(ip, 0, sizeof(*ip));
7638 ip->ver = 0x45; // Version 4, header length 5 words
7639 ip->frag = 0x40; // Don't fragment
7640 ip->len = mg_htons((uint16_t) (sizeof(*ip) + plen));
7645 ip->csum = ipcsum(ip, sizeof(*ip));
7649 static void tx_udp(struct mg_tcpip_if *ifp, uint8_t *mac_dst, uint32_t ip_src,
7650 uint16_t sport, uint32_t ip_dst, uint16_t dport,
7651 const void *buf, size_t len) {
7653 tx_ip(ifp, mac_dst, 17, ip_src, ip_dst, len + sizeof(struct udp));
7654 struct udp *udp = (struct udp *) (ip + 1);
7655 // MG_DEBUG(("UDP XX LEN %d %d", (int) len, (int) ifp->tx.len));
7658 udp->len = mg_htons((uint16_t) (sizeof(*udp) + len));
7660 uint32_t cs = csumup(0, udp, sizeof(*udp));
7661 cs = csumup(cs, buf, len);
7662 cs = csumup(cs, &ip->src, sizeof(ip->src));
7663 cs = csumup(cs, &ip->dst, sizeof(ip->dst));
7664 cs += (uint32_t) (ip->proto + sizeof(*udp) + len);
7665 udp->csum = csumfin(cs);
7666 memmove(udp + 1, buf, len);
7667 // MG_DEBUG(("UDP LEN %d %d", (int) len, (int) ifp->frame_len));
7668 ether_output(ifp, sizeof(struct eth) + sizeof(*ip) + sizeof(*udp) + len);
7671 static void tx_dhcp(struct mg_tcpip_if *ifp, uint8_t *mac_dst, uint32_t ip_src,
7672 uint32_t ip_dst, uint8_t *opts, size_t optslen) {
7673 struct dhcp dhcp = {1, 1, 6, 0, 0, 0, 0, 0, 0, 0, 0, {0}, 0, {0}};
7674 dhcp.magic = mg_htonl(0x63825363);
7675 memcpy(&dhcp.hwaddr, ifp->mac, sizeof(ifp->mac));
7676 memcpy(&dhcp.xid, ifp->mac + 2, sizeof(dhcp.xid));
7677 memcpy(&dhcp.options, opts, optslen);
7678 tx_udp(ifp, mac_dst, ip_src, mg_htons(68), ip_dst, mg_htons(67), &dhcp,
7682 static void tx_dhcp_request(struct mg_tcpip_if *ifp, uint8_t *mac_dst,
7683 uint32_t ip_src, uint32_t ip_dst) {
7685 53, 1, 3, // Type: DHCP request
7686 55, 2, 1, 3, // GW and mask
7687 12, 3, 'm', 'i', 'p', // Host name: "mip"
7688 54, 4, 0, 0, 0, 0, // DHCP server ID
7689 50, 4, 0, 0, 0, 0, // Requested IP
7690 255 // End of options
7692 memcpy(opts + 14, &ip_dst, sizeof(ip_dst));
7693 memcpy(opts + 20, &ip_src, sizeof(ip_src));
7694 tx_dhcp(ifp, mac_dst, ip_src, ip_dst, opts, sizeof(opts));
7697 static void tx_dhcp_discover(struct mg_tcpip_if *ifp) {
7698 uint8_t mac[6] = {255, 255, 255, 255, 255, 255};
7700 53, 1, 1, // Type: DHCP discover
7701 55, 2, 1, 3, // Parameters: ip, mask
7702 255 // End of options
7704 tx_dhcp(ifp, mac, 0, 0xffffffff, opts, sizeof(opts));
7705 MG_DEBUG(("DHCP discover sent"));
7708 static struct mg_connection *getpeer(struct mg_mgr *mgr, struct pkt *pkt,
7710 struct mg_connection *c = NULL;
7711 for (c = mgr->conns; c != NULL; c = c->next) {
7712 if (c->is_udp && pkt->udp && c->loc.port == pkt->udp->dport) break;
7713 if (!c->is_udp && pkt->tcp && c->loc.port == pkt->tcp->dport &&
7714 lsn == c->is_listening && (lsn || c->rem.port == pkt->tcp->sport))
7720 static void rx_arp(struct mg_tcpip_if *ifp, struct pkt *pkt) {
7721 if (pkt->arp->op == mg_htons(1) && pkt->arp->tpa == ifp->ip) {
7722 // ARP request. Make a response, then send
7723 // MG_DEBUG(("ARP op %d %M: %M", mg_ntohs(pkt->arp->op), mg_print_ip4,
7724 // &pkt->arp->spa, mg_print_ip4, &pkt->arp->tpa));
7725 struct eth *eth = (struct eth *) ifp->tx.ptr;
7726 struct arp *arp = (struct arp *) (eth + 1);
7727 memcpy(eth->dst, pkt->eth->src, sizeof(eth->dst));
7728 memcpy(eth->src, ifp->mac, sizeof(eth->src));
7729 eth->type = mg_htons(0x806);
7731 arp->op = mg_htons(2);
7732 memcpy(arp->tha, pkt->arp->sha, sizeof(pkt->arp->tha));
7733 memcpy(arp->sha, ifp->mac, sizeof(pkt->arp->sha));
7734 arp->tpa = pkt->arp->spa;
7736 MG_DEBUG(("ARP: tell %M we're %M", mg_print_ip4, &arp->tpa, mg_print_ip4,
7738 ether_output(ifp, PDIFF(eth, arp + 1));
7739 } else if (pkt->arp->op == mg_htons(2)) {
7740 if (memcmp(pkt->arp->tha, ifp->mac, sizeof(pkt->arp->tha)) != 0) return;
7741 if (pkt->arp->spa == ifp->gw) {
7742 // Got response for the GW ARP request. Set ifp->gwmac
7743 memcpy(ifp->gwmac, pkt->arp->sha, sizeof(ifp->gwmac));
7745 struct mg_connection *c = getpeer(ifp->mgr, pkt, false);
7746 if (c != NULL && c->is_arplooking) {
7747 struct connstate *s = (struct connstate *) (c + 1);
7748 memcpy(s->mac, pkt->arp->sha, sizeof(s->mac));
7749 MG_DEBUG(("%lu ARP resolved %M -> %M", c->id, mg_print_ip4, &c->rem.ip,
7750 mg_print_mac, s->mac));
7751 c->is_arplooking = 0;
7757 static void rx_icmp(struct mg_tcpip_if *ifp, struct pkt *pkt) {
7758 // MG_DEBUG(("ICMP %d", (int) len));
7759 if (pkt->icmp->type == 8 && pkt->ip != NULL && pkt->ip->dst == ifp->ip) {
7760 size_t hlen = sizeof(struct eth) + sizeof(struct ip) + sizeof(struct icmp);
7761 size_t space = ifp->tx.len - hlen, plen = pkt->pay.len;
7762 if (plen > space) plen = space;
7763 struct ip *ip = tx_ip(ifp, pkt->eth->src, 1, ifp->ip, pkt->ip->src,
7764 sizeof(struct icmp) + plen);
7765 struct icmp *icmp = (struct icmp *) (ip + 1);
7766 memset(icmp, 0, sizeof(*icmp)); // Set csum to 0
7767 memcpy(icmp + 1, pkt->pay.ptr, plen); // Copy RX payload to TX
7768 icmp->csum = ipcsum(icmp, sizeof(*icmp) + plen);
7769 ether_output(ifp, hlen + plen);
7773 static void rx_dhcp_client(struct mg_tcpip_if *ifp, struct pkt *pkt) {
7774 uint32_t ip = 0, gw = 0, mask = 0;
7775 uint8_t *p = pkt->dhcp->options,
7776 *end = (uint8_t *) &pkt->raw.ptr[pkt->raw.len];
7777 if (end < (uint8_t *) (pkt->dhcp + 1)) return;
7778 while (p + 1 < end && p[0] != 255) { // Parse options
7779 if (p[0] == 1 && p[1] == sizeof(ifp->mask) && p + 6 < end) { // Mask
7780 memcpy(&mask, p + 2, sizeof(mask));
7781 } else if (p[0] == 3 && p[1] == sizeof(ifp->gw) && p + 6 < end) { // GW
7782 memcpy(&gw, p + 2, sizeof(gw));
7783 ip = pkt->dhcp->yiaddr;
7784 } else if (p[0] == 51 && p[1] == 4 && p + 6 < end) { // Lease
7786 memcpy(&lease, p + 2, sizeof(lease));
7787 ifp->lease_expire = ifp->now + mg_ntohl(lease) * 1000;
7791 if (ip && mask && gw && ifp->ip == 0) {
7792 memcpy(ifp->gwmac, pkt->eth->src, sizeof(ifp->gwmac));
7793 ifp->ip = ip, ifp->gw = gw, ifp->mask = mask;
7794 ifp->state = MG_TCPIP_STATE_READY;
7796 tx_dhcp_request(ifp, pkt->eth->src, ip, pkt->dhcp->siaddr);
7798 mg_random(&rand, sizeof(rand));
7799 srand((unsigned int) (rand + mg_millis()));
7803 // Simple DHCP server that assigns a next IP address: ifp->ip + 1
7804 static void rx_dhcp_server(struct mg_tcpip_if *ifp, struct pkt *pkt) {
7805 uint8_t op = 0, *p = pkt->dhcp->options,
7806 *end = (uint8_t *) &pkt->raw.ptr[pkt->raw.len];
7807 if (end < (uint8_t *) (pkt->dhcp + 1)) return;
7808 // struct dhcp *req = pkt->dhcp;
7809 struct dhcp res = {2, 1, 6, 0, 0, 0, 0, 0, 0, 0, 0, {0}, 0, {0}};
7810 res.yiaddr = ifp->ip;
7811 ((uint8_t *) (&res.yiaddr))[3]++; // Offer our IP + 1
7812 while (p + 1 < end && p[0] != 255) { // Parse options
7813 if (p[0] == 53 && p[1] == 1 && p + 2 < end) { // Message type
7818 if (op == 1 || op == 3) { // DHCP Discover or DHCP Request
7819 uint8_t msg = op == 1 ? 2 : 5; // Message type: DHCP OFFER or DHCP ACK
7821 53, 1, msg, // Message type
7822 1, 4, 0, 0, 0, 0, // Subnet mask
7823 54, 4, 0, 0, 0, 0, // Server ID
7824 12, 3, 'm', 'i', 'p', // Host name: "mip"
7825 51, 4, 255, 255, 255, 255, // Lease time
7826 255 // End of options
7828 memcpy(&res.hwaddr, pkt->dhcp->hwaddr, 6);
7829 memcpy(opts + 5, &ifp->mask, sizeof(ifp->mask));
7830 memcpy(opts + 11, &ifp->ip, sizeof(ifp->ip));
7831 memcpy(&res.options, opts, sizeof(opts));
7832 res.magic = pkt->dhcp->magic;
7833 res.xid = pkt->dhcp->xid;
7834 // memcpy(ifp->gwmac, pkt->eth->src, sizeof(ifp->gwmac));
7835 tx_udp(ifp, pkt->eth->src, ifp->ip, mg_htons(67),
7836 op == 1 ? ~0U : res.yiaddr, mg_htons(68), &res, sizeof(res));
7840 static void rx_udp(struct mg_tcpip_if *ifp, struct pkt *pkt) {
7841 struct mg_connection *c = getpeer(ifp->mgr, pkt, true);
7843 // No UDP listener on this port. Should send ICMP, but keep silent.
7845 c->rem.port = pkt->udp->sport;
7846 c->rem.ip = pkt->ip->src;
7847 struct connstate *s = (struct connstate *) (c + 1);
7848 memcpy(s->mac, pkt->eth->src, sizeof(s->mac));
7849 if (c->recv.len >= MG_MAX_RECV_SIZE) {
7850 mg_error(c, "max_recv_buf_size reached");
7851 } else if (c->recv.size - c->recv.len < pkt->pay.len &&
7852 !mg_iobuf_resize(&c->recv, c->recv.len + pkt->pay.len)) {
7855 memcpy(&c->recv.buf[c->recv.len], pkt->pay.ptr, pkt->pay.len);
7856 c->recv.len += pkt->pay.len;
7857 mg_call(c, MG_EV_READ, &pkt->pay.len);
7862 static size_t tx_tcp(struct mg_tcpip_if *ifp, uint8_t *dst_mac, uint32_t dst_ip,
7863 uint8_t flags, uint16_t sport, uint16_t dport,
7864 uint32_t seq, uint32_t ack, const void *buf, size_t len) {
7866 tx_ip(ifp, dst_mac, 6, ifp->ip, dst_ip, sizeof(struct tcp) + len);
7867 struct tcp *tcp = (struct tcp *) (ip + 1);
7868 memset(tcp, 0, sizeof(*tcp));
7869 if (buf != NULL && len) memmove(tcp + 1, buf, len);
7875 tcp->win = mg_htons(8192);
7876 tcp->off = (uint8_t) (sizeof(*tcp) / 4 << 4);
7878 uint16_t n = (uint16_t) (sizeof(*tcp) + len);
7879 uint8_t pseudo[] = {0, ip->proto, (uint8_t) (n >> 8), (uint8_t) (n & 255)};
7880 cs = csumup(cs, tcp, n);
7881 cs = csumup(cs, &ip->src, sizeof(ip->src));
7882 cs = csumup(cs, &ip->dst, sizeof(ip->dst));
7883 cs = csumup(cs, pseudo, sizeof(pseudo));
7884 tcp->csum = csumfin(cs);
7885 MG_DEBUG(("TCP %M:%hu -> %M:%hu fl %x len %u", mg_print_ip4, &ip->src,
7886 mg_ntohs(tcp->sport), mg_print_ip4, &ip->dst, mg_ntohs(tcp->dport),
7887 tcp->flags, (int) len));
7888 return ether_output(ifp, PDIFF(ifp->tx.ptr, tcp + 1) + len);
7891 static size_t tx_tcp_pkt(struct mg_tcpip_if *ifp, struct pkt *pkt,
7892 uint8_t flags, uint32_t seq, const void *buf,
7894 uint32_t delta = (pkt->tcp->flags & (TH_SYN | TH_FIN)) ? 1 : 0;
7895 return tx_tcp(ifp, pkt->eth->src, pkt->ip->src, flags, pkt->tcp->dport,
7896 pkt->tcp->sport, seq, mg_htonl(mg_ntohl(pkt->tcp->seq) + delta),
7900 static void settmout(struct mg_connection *c, uint8_t type) {
7901 struct mg_tcpip_if *ifp = (struct mg_tcpip_if *) c->mgr->priv;
7902 struct connstate *s = (struct connstate *) (c + 1);
7903 unsigned n = type == MIP_TTYPE_ACK ? MIP_TCP_ACK_MS : MIP_TCP_KEEPALIVE_MS;
7904 s->timer = ifp->now + n;
7906 MG_VERBOSE(("%lu %d -> %llx", c->id, type, s->timer));
7909 static struct mg_connection *accept_conn(struct mg_connection *lsn,
7911 struct mg_connection *c = mg_alloc_conn(lsn->mgr);
7916 struct connstate *s = (struct connstate *) (c + 1);
7917 s->seq = mg_ntohl(pkt->tcp->ack), s->ack = mg_ntohl(pkt->tcp->seq);
7918 memcpy(s->mac, pkt->eth->src, sizeof(s->mac));
7919 settmout(c, MIP_TTYPE_KEEPALIVE);
7920 c->rem.ip = pkt->ip->src;
7921 c->rem.port = pkt->tcp->sport;
7922 MG_DEBUG(("%lu accepted %M", c->id, mg_print_ip_port, &c->rem));
7923 LIST_ADD_HEAD(struct mg_connection, &lsn->mgr->conns, c);
7925 c->is_hexdumping = lsn->is_hexdumping;
7928 c->pfn_data = lsn->pfn_data;
7930 c->fn_data = lsn->fn_data;
7931 mg_call(c, MG_EV_OPEN, NULL);
7932 mg_call(c, MG_EV_ACCEPT, NULL);
7936 long mg_io_send(struct mg_connection *c, const void *buf, size_t len) {
7937 struct mg_tcpip_if *ifp = (struct mg_tcpip_if *) c->mgr->priv;
7938 struct connstate *s = (struct connstate *) (c + 1);
7940 size_t max_headers_len = 14 + 24 /* max IP */ + 8 /* UDP */;
7941 if (len + max_headers_len > ifp->tx.len) len = ifp->tx.len - max_headers_len;
7942 tx_udp(ifp, s->mac, ifp->ip, c->loc.port, c->rem.ip, c->rem.port, buf, len);
7944 size_t max_headers_len = 14 + 24 /* max IP */ + 60 /* max TCP */;
7945 if (len + max_headers_len > ifp->tx.len) len = ifp->tx.len - max_headers_len;
7946 if (tx_tcp(ifp, s->mac, c->rem.ip, TH_PUSH | TH_ACK, c->loc.port, c->rem.port,
7947 mg_htonl(s->seq), mg_htonl(s->ack), buf, len) > 0) {
7948 s->seq += (uint32_t) len;
7949 if (s->ttype == MIP_TTYPE_ACK) settmout(c, MIP_TTYPE_KEEPALIVE);
7957 long mg_io_recv(struct mg_connection *c, void *buf, size_t len) {
7958 struct connstate *s = (struct connstate *) (c + 1);
7959 if (s->raw.len == 0) return MG_IO_WAIT;
7960 if (len > s->raw.len) len = s->raw.len;
7961 memcpy(buf, s->raw.buf, len);
7962 mg_iobuf_del(&s->raw, 0, len);
7963 MG_DEBUG(("%lu", len));
7967 static void read_conn(struct mg_connection *c, struct pkt *pkt) {
7968 struct connstate *s = (struct connstate *) (c + 1);
7969 struct mg_iobuf *io = c->is_tls ? &s->raw : &c->recv;
7970 uint32_t seq = mg_ntohl(pkt->tcp->seq);
7971 s->raw.align = c->recv.align;
7972 if (pkt->tcp->flags & TH_FIN) {
7973 s->ack = mg_htonl(pkt->tcp->seq) + 1, s->seq = mg_htonl(pkt->tcp->ack);
7975 } else if (pkt->pay.len == 0) {
7976 // TODO(cpq): handle this peer's ACK
7977 } else if (seq != s->ack) {
7978 uint32_t ack = (uint32_t) (mg_htonl(pkt->tcp->seq) + pkt->pay.len);
7979 if (s->ack == ack) {
7980 MG_VERBOSE(("ignoring duplicate pkt"));
7982 // TODO(cpq): peer sent us SEQ which we don't expect. Retransmit rather
7983 // than close this connection
7984 mg_error(c, "SEQ != ACK: %x %x %x", seq, s->ack, ack);
7986 } else if (io->size - io->len < pkt->pay.len &&
7987 !mg_iobuf_resize(io, io->len + pkt->pay.len)) {
7990 // Copy TCP payload into the IO buffer. If the connection is plain text, we
7991 // copy to c->recv. If the connection is TLS, this data is encrypted,
7992 // therefore we copy that encrypted data to the s->raw iobuffer instead,
7993 // and then call mg_tls_recv() to decrypt it. NOTE: mg_tls_recv() will
7994 // call back mg_io_recv() which grabs raw data from s->raw
7995 memcpy(&io->buf[io->len], pkt->pay.ptr, pkt->pay.len);
7996 io->len += pkt->pay.len;
7998 MG_DEBUG(("%lu SEQ %x -> %x", c->id, mg_htonl(pkt->tcp->seq), s->ack));
7999 // Advance ACK counter
8000 s->ack = (uint32_t) (mg_htonl(pkt->tcp->seq) + pkt->pay.len);
8002 // Send ACK immediately
8003 MG_DEBUG((" imm ACK", c->id, mg_htonl(pkt->tcp->seq), s->ack));
8004 tx_tcp((struct mg_tcpip_if *) c->mgr->priv, c->rem.ip, TH_ACK, c->loc.port,
8005 c->rem.port, mg_htonl(s->seq), mg_htonl(s->ack), "", 0);
8007 // if not already running, setup a timer to send an ACK later
8008 if (s->ttype != MIP_TTYPE_ACK) settmout(c, MIP_TTYPE_ACK);
8012 // TLS connection. Make room for decrypted data in c->recv
8014 if (io->size - io->len < pkt->pay.len &&
8015 !mg_iobuf_resize(io, io->len + pkt->pay.len)) {
8018 // Decrypt data directly into c->recv
8019 long n = mg_tls_recv(c, &io->buf[io->len], io->size - io->len);
8020 if (n == MG_IO_ERR) {
8021 mg_error(c, "TLS recv error");
8023 // Decrypted successfully - trigger MG_EV_READ
8024 io->len += (size_t) n;
8025 mg_call(c, MG_EV_READ, &n);
8029 // Plain text connection, data is already in c->recv, trigger MG_EV_READ
8030 mg_call(c, MG_EV_READ, &pkt->pay.len);
8035 static void rx_tcp(struct mg_tcpip_if *ifp, struct pkt *pkt) {
8036 struct mg_connection *c = getpeer(ifp->mgr, pkt, false);
8037 struct connstate *s = c == NULL ? NULL : (struct connstate *) (c + 1);
8039 MG_INFO(("%lu %hhu %d", c ? c->id : 0, pkt->tcp->flags, (int) pkt->pay.len));
8041 if (c != NULL && c->is_connecting && pkt->tcp->flags & (TH_SYN | TH_ACK)) {
8042 s->seq = mg_ntohl(pkt->tcp->ack), s->ack = mg_ntohl(pkt->tcp->seq) + 1;
8043 tx_tcp_pkt(ifp, pkt, TH_ACK, pkt->tcp->ack, NULL, 0);
8044 c->is_connecting = 0; // Client connected
8045 settmout(c, MIP_TTYPE_KEEPALIVE);
8046 mg_call(c, MG_EV_CONNECT, NULL); // Let user know
8047 } else if (c != NULL && c->is_connecting) {
8048 tx_tcp_pkt(ifp, pkt, TH_RST | TH_ACK, pkt->tcp->ack, NULL, 0);
8049 } else if (c != NULL && pkt->tcp->flags & TH_RST) {
8050 mg_error(c, "peer RST"); // RFC-1122 4.2.2.13
8051 } else if (c != NULL) {
8053 MG_DEBUG(("%lu %d %M:%hu -> %M:%hu", c->id, (int) pkt->raw.len,
8054 mg_print_ip4, &pkt->ip->src, mg_ntohs(pkt->tcp->sport),
8055 mg_print_ip4, &pkt->ip->dst, mg_ntohs(pkt->tcp->dport)));
8056 mg_hexdump(pkt->pay.buf, pkt->pay.len);
8058 s->tmiss = 0; // Reset missed keep-alive counter
8059 if (s->ttype == MIP_TTYPE_KEEPALIVE) // Advance keep-alive timer
8061 MIP_TTYPE_KEEPALIVE); // unless a former ACK timeout is pending
8062 read_conn(c, pkt); // Override timer with ACK timeout if needed
8063 } else if ((c = getpeer(ifp->mgr, pkt, true)) == NULL) {
8064 tx_tcp_pkt(ifp, pkt, TH_RST | TH_ACK, pkt->tcp->ack, NULL, 0);
8065 } else if (pkt->tcp->flags & TH_RST) {
8066 if (c->is_accepted) mg_error(c, "peer RST"); // RFC-1122 4.2.2.13
8067 // ignore RST if not connected
8068 } else if (pkt->tcp->flags & TH_SYN) {
8069 // Use peer's source port as ISN, in order to recognise the handshake
8070 uint32_t isn = mg_htonl((uint32_t) mg_ntohs(pkt->tcp->sport));
8071 tx_tcp_pkt(ifp, pkt, TH_SYN | TH_ACK, isn, NULL, 0);
8072 } else if (pkt->tcp->flags & TH_FIN) {
8073 tx_tcp_pkt(ifp, pkt, TH_FIN | TH_ACK, pkt->tcp->ack, NULL, 0);
8074 } else if (mg_htonl(pkt->tcp->ack) == mg_htons(pkt->tcp->sport) + 1U) {
8075 accept_conn(c, pkt);
8076 } else if (!c->is_accepted) { // no peer
8077 tx_tcp_pkt(ifp, pkt, TH_RST | TH_ACK, pkt->tcp->ack, NULL, 0);
8079 // MG_DEBUG(("dropped silently.."));
8083 static void rx_ip(struct mg_tcpip_if *ifp, struct pkt *pkt) {
8084 if (pkt->ip->proto == 1) {
8085 pkt->icmp = (struct icmp *) (pkt->ip + 1);
8086 if (pkt->pay.len < sizeof(*pkt->icmp)) return;
8087 mkpay(pkt, pkt->icmp + 1);
8089 } else if (pkt->ip->proto == 17) {
8090 pkt->udp = (struct udp *) (pkt->ip + 1);
8091 if (pkt->pay.len < sizeof(*pkt->udp)) return;
8092 mkpay(pkt, pkt->udp + 1);
8093 MG_DEBUG(("UDP %M:%hu -> %M:%hu len %u", mg_print_ip4, &pkt->ip->src,
8094 mg_ntohs(pkt->udp->sport), mg_print_ip4, &pkt->ip->dst,
8095 mg_ntohs(pkt->udp->dport), (int) pkt->pay.len));
8096 if (pkt->udp->dport == mg_htons(68)) {
8097 pkt->dhcp = (struct dhcp *) (pkt->udp + 1);
8098 mkpay(pkt, pkt->dhcp + 1);
8099 rx_dhcp_client(ifp, pkt);
8100 } else if (ifp->enable_dhcp_server && pkt->udp->dport == mg_htons(67)) {
8101 pkt->dhcp = (struct dhcp *) (pkt->udp + 1);
8102 mkpay(pkt, pkt->dhcp + 1);
8103 rx_dhcp_server(ifp, pkt);
8107 } else if (pkt->ip->proto == 6) {
8108 pkt->tcp = (struct tcp *) (pkt->ip + 1);
8109 if (pkt->pay.len < sizeof(*pkt->tcp)) return;
8110 mkpay(pkt, pkt->tcp + 1);
8111 uint16_t iplen = mg_ntohs(pkt->ip->len);
8112 uint16_t off = (uint16_t) (sizeof(*pkt->ip) + ((pkt->tcp->off >> 4) * 4U));
8113 if (iplen >= off) pkt->pay.len = (size_t) (iplen - off);
8114 MG_DEBUG(("TCP %M:%hu -> %M:%hu len %u", mg_print_ip4, &pkt->ip->src,
8115 mg_ntohs(pkt->tcp->sport), mg_print_ip4, &pkt->ip->dst,
8116 mg_ntohs(pkt->tcp->dport), (int) pkt->pay.len));
8121 static void rx_ip6(struct mg_tcpip_if *ifp, struct pkt *pkt) {
8122 // MG_DEBUG(("IP %d", (int) len));
8123 if (pkt->ip6->proto == 1 || pkt->ip6->proto == 58) {
8124 pkt->icmp = (struct icmp *) (pkt->ip6 + 1);
8125 if (pkt->pay.len < sizeof(*pkt->icmp)) return;
8126 mkpay(pkt, pkt->icmp + 1);
8128 } else if (pkt->ip6->proto == 17) {
8129 pkt->udp = (struct udp *) (pkt->ip6 + 1);
8130 if (pkt->pay.len < sizeof(*pkt->udp)) return;
8131 // MG_DEBUG((" UDP %u %u -> %u", len, mg_htons(udp->sport),
8132 // mg_htons(udp->dport)));
8133 mkpay(pkt, pkt->udp + 1);
8137 static void mg_tcpip_rx(struct mg_tcpip_if *ifp, void *buf, size_t len) {
8138 const uint8_t broadcast[] = {255, 255, 255, 255, 255, 255};
8140 memset(&pkt, 0, sizeof(pkt));
8141 pkt.raw.ptr = (char *) buf;
8143 pkt.eth = (struct eth *) buf;
8144 if (pkt.raw.len < sizeof(*pkt.eth)) return; // Truncated - runt?
8145 if (ifp->enable_mac_check &&
8146 memcmp(pkt.eth->dst, ifp->mac, sizeof(pkt.eth->dst)) != 0 &&
8147 memcmp(pkt.eth->dst, broadcast, sizeof(pkt.eth->dst)) != 0)
8149 if (ifp->enable_crc32_check && len > 4) {
8150 len -= 4; // TODO(scaprile): check on bigendian
8151 uint32_t crc = mg_crc32(0, (const char *) buf, len);
8152 if (memcmp((void *) ((size_t) buf + len), &crc, sizeof(crc))) return;
8154 if (pkt.eth->type == mg_htons(0x806)) {
8155 pkt.arp = (struct arp *) (pkt.eth + 1);
8156 if (sizeof(*pkt.eth) + sizeof(*pkt.arp) > pkt.raw.len) return; // Truncated
8158 } else if (pkt.eth->type == mg_htons(0x86dd)) {
8159 pkt.ip6 = (struct ip6 *) (pkt.eth + 1);
8160 if (pkt.raw.len < sizeof(*pkt.eth) + sizeof(*pkt.ip6)) return; // Truncated
8161 if ((pkt.ip6->ver >> 4) != 0x6) return; // Not IP
8162 mkpay(&pkt, pkt.ip6 + 1);
8164 } else if (pkt.eth->type == mg_htons(0x800)) {
8165 pkt.ip = (struct ip *) (pkt.eth + 1);
8166 if (pkt.raw.len < sizeof(*pkt.eth) + sizeof(*pkt.ip)) return; // Truncated
8167 // Truncate frame to what IP header tells us
8168 if ((size_t) mg_ntohs(pkt.ip->len) + sizeof(struct eth) < pkt.raw.len) {
8169 pkt.raw.len = (size_t) mg_ntohs(pkt.ip->len) + sizeof(struct eth);
8171 if (pkt.raw.len < sizeof(*pkt.eth) + sizeof(*pkt.ip)) return; // Truncated
8172 if ((pkt.ip->ver >> 4) != 4) return; // Not IP
8173 mkpay(&pkt, pkt.ip + 1);
8176 MG_DEBUG((" Unknown eth type %x", mg_htons(pkt.eth->type)));
8177 mg_hexdump(buf, len >= 16 ? 16 : len);
8181 static void mg_tcpip_poll(struct mg_tcpip_if *ifp, uint64_t uptime_ms) {
8182 if (ifp == NULL || ifp->driver == NULL) return;
8183 bool expired_1000ms = mg_timer_expired(&ifp->timer_1000ms, 1000, uptime_ms);
8184 ifp->now = uptime_ms;
8186 // Handle physical interface up/down status
8187 if (expired_1000ms && ifp->driver->up) {
8188 bool up = ifp->driver->up(ifp);
8189 bool current = ifp->state != MG_TCPIP_STATE_DOWN;
8190 if (up != current) {
8191 ifp->state = up == false ? MG_TCPIP_STATE_DOWN
8192 : ifp->enable_dhcp_client ? MG_TCPIP_STATE_UP
8193 : MG_TCPIP_STATE_READY;
8194 if (!up && ifp->enable_dhcp_client) ifp->ip = 0;
8198 if (ifp->state == MG_TCPIP_STATE_DOWN) return;
8200 // If IP not configured, send DHCP
8201 if (ifp->ip == 0 && expired_1000ms) tx_dhcp_discover(ifp);
8203 // Read data from the network
8204 if (ifp->driver->rx != NULL) { // Polling driver. We must call it
8206 ifp->driver->rx(ifp->recv_queue.buf, ifp->recv_queue.size, ifp);
8207 if (len > 0) mg_tcpip_rx(ifp, ifp->recv_queue.buf, len);
8208 } else { // Interrupt-based driver. Fills recv queue itself
8210 size_t len = mg_queue_next(&ifp->recv_queue, &buf);
8212 mg_tcpip_rx(ifp, buf, len);
8213 mg_queue_del(&ifp->recv_queue, len);
8218 for (struct mg_connection *c = ifp->mgr->conns; c != NULL; c = c->next) {
8219 if (c->is_udp || c->is_listening) continue;
8220 if (c->is_connecting || c->is_resolving) continue;
8221 struct connstate *s = (struct connstate *) (c + 1);
8222 if (uptime_ms > s->timer) {
8223 if (s->ttype == MIP_TTYPE_ACK) {
8224 MG_DEBUG(("%lu ack %x %x", c->id, s->seq, s->ack));
8225 tx_tcp(ifp, s->mac, c->rem.ip, TH_ACK, c->loc.port, c->rem.port,
8226 mg_htonl(s->seq), mg_htonl(s->ack), "", 0);
8228 if (s->tmiss++ > 2) {
8229 mg_error(c, "keepalive");
8231 MG_DEBUG(("%lu keepalive", c->id));
8232 tx_tcp(ifp, s->mac, c->rem.ip, TH_ACK, c->loc.port, c->rem.port,
8233 mg_htonl(s->seq - 1), mg_htonl(s->ack), "", 0);
8236 settmout(c, MIP_TTYPE_KEEPALIVE);
8241 // This function executes in interrupt context, thus it should copy data
8242 // somewhere fast. Note that newlib's malloc is not thread safe, thus use
8243 // our lock-free queue with preallocated buffer to copy data and return asap
8244 void mg_tcpip_qwrite(void *buf, size_t len, struct mg_tcpip_if *ifp) {
8246 if (mg_queue_book(&ifp->recv_queue, &p, len) >= len) {
8247 memcpy(p, buf, len);
8248 mg_queue_add(&ifp->recv_queue, len);
8255 void mg_tcpip_init(struct mg_mgr *mgr, struct mg_tcpip_if *ifp) {
8256 // If MAC address is not set, make a random one
8257 if (ifp->mac[0] == 0 && ifp->mac[1] == 0 && ifp->mac[2] == 0 &&
8258 ifp->mac[3] == 0 && ifp->mac[4] == 0 && ifp->mac[5] == 0) {
8259 ifp->mac[0] = 0x02; // Locally administered, unicast
8260 mg_random(&ifp->mac[1], sizeof(ifp->mac) - 1);
8261 MG_INFO(("MAC not set. Generated random: %M", mg_print_mac, ifp->mac));
8264 if (ifp->driver->init && !ifp->driver->init(ifp)) {
8265 MG_ERROR(("driver init failed"));
8267 size_t framesize = 1540;
8268 ifp->tx.ptr = (char *) calloc(1, framesize), ifp->tx.len = framesize;
8269 if (ifp->recv_queue.size == 0)
8270 ifp->recv_queue.size = ifp->driver->rx ? framesize : 8192;
8271 ifp->recv_queue.buf = (char *) calloc(1, ifp->recv_queue.size);
8272 ifp->timer_1000ms = mg_millis();
8275 mgr->extraconnsize = sizeof(struct connstate);
8276 if (ifp->ip == 0) ifp->enable_dhcp_client = true;
8277 memset(ifp->gwmac, 255, sizeof(ifp->gwmac)); // Set to broadcast
8278 mg_random(&ifp->eport, sizeof(ifp->eport)); // Random from 0 to 65535
8280 MG_EPHEMERAL_PORT_BASE; // Random from MG_EPHEMERAL_PORT_BASE to 65535
8281 if (ifp->tx.ptr == NULL || ifp->recv_queue.buf == NULL) MG_ERROR(("OOM"));
8285 void mg_tcpip_free(struct mg_tcpip_if *ifp) {
8286 free(ifp->recv_queue.buf);
8287 free((char *) ifp->tx.ptr);
8290 int mg_mkpipe(struct mg_mgr *m, mg_event_handler_t fn, void *d, bool udp) {
8291 (void) m, (void) fn, (void) d, (void) udp;
8292 MG_ERROR(("Not implemented"));
8296 static void send_syn(struct mg_connection *c) {
8297 struct connstate *s = (struct connstate *) (c + 1);
8298 uint32_t isn = mg_htonl((uint32_t) mg_ntohs(c->loc.port));
8299 struct mg_tcpip_if *ifp = (struct mg_tcpip_if *) c->mgr->priv;
8300 tx_tcp(ifp, s->mac, c->rem.ip, TH_SYN, c->loc.port, c->rem.port, isn, 0, NULL,
8304 void mg_connect_resolved(struct mg_connection *c) {
8305 struct mg_tcpip_if *ifp = (struct mg_tcpip_if *) c->mgr->priv;
8306 c->is_resolving = 0;
8307 if (ifp->eport < MG_EPHEMERAL_PORT_BASE) ifp->eport = MG_EPHEMERAL_PORT_BASE;
8308 c->loc.ip = ifp->ip;
8309 c->loc.port = mg_htons(ifp->eport++);
8310 MG_DEBUG(("%lu %M -> %M", c->id, mg_print_ip_port, &c->loc, mg_print_ip_port,
8312 mg_call(c, MG_EV_RESOLVE, NULL);
8313 if (((c->rem.ip & ifp->mask) == (ifp->ip & ifp->mask))) {
8314 // If we're in the same LAN, fire an ARP lookup. TODO(cpq): handle this!
8315 MG_DEBUG(("%lu ARP lookup...", c->id));
8316 arp_ask(ifp, c->rem.ip);
8317 c->is_arplooking = 1;
8318 } else if (c->rem.ip == (ifp->ip | ~ifp->mask)) {
8319 struct connstate *s = (struct connstate *) (c + 1);
8320 memset(s->mac, 0xFF, sizeof(s->mac)); // local broadcast
8321 } else if ((*((uint8_t *) &c->rem.ip) & 0xE0) == 0xE0) {
8322 struct connstate *s = (struct connstate *) (c + 1); // 224 to 239, E0 to EF
8323 uint8_t mcastp[3] = {0x01, 0x00, 0x5E}; // multicast group
8324 memcpy(s->mac, mcastp, 3);
8325 memcpy(s->mac + 3, ((uint8_t *) &c->rem.ip) + 1, 3); // 23 LSb
8328 struct connstate *s = (struct connstate *) (c + 1);
8329 memcpy(s->mac, ifp->gwmac, sizeof(ifp->gwmac));
8331 mg_call(c, MG_EV_CONNECT, NULL);
8334 c->is_connecting = 1;
8339 bool mg_open_listener(struct mg_connection *c, const char *url) {
8340 c->loc.port = mg_htons(mg_url_port(url));
8344 static void write_conn(struct mg_connection *c) {
8345 long len = c->is_tls ? mg_tls_send(c, c->send.buf, c->send.len)
8346 : mg_io_send(c, c->send.buf, c->send.len);
8348 mg_iobuf_del(&c->send, 0, (size_t) len);
8349 mg_call(c, MG_EV_WRITE, &len);
8353 static void close_conn(struct mg_connection *c) {
8354 struct connstate *s = (struct connstate *) (c + 1);
8355 mg_iobuf_free(&s->raw); // For TLS connections, release raw data
8356 if (c->is_udp == false && c->is_listening == false) { // For TCP conns,
8357 struct mg_tcpip_if *ifp =
8358 (struct mg_tcpip_if *) c->mgr->priv; // send TCP FIN
8359 tx_tcp(ifp, s->mac, c->rem.ip, TH_FIN | TH_ACK, c->loc.port, c->rem.port,
8360 mg_htonl(s->seq), mg_htonl(s->ack), NULL, 0);
8365 static bool can_write(struct mg_connection *c) {
8366 return c->is_connecting == 0 && c->is_resolving == 0 && c->send.len > 0 &&
8367 c->is_tls_hs == 0 && c->is_arplooking == 0;
8370 void mg_mgr_poll(struct mg_mgr *mgr, int ms) {
8371 struct mg_connection *c, *tmp;
8372 uint64_t now = mg_millis();
8373 mg_tcpip_poll((struct mg_tcpip_if *) mgr->priv, now);
8374 mg_timer_poll(&mgr->timers, now);
8375 for (c = mgr->conns; c != NULL; c = tmp) {
8377 mg_call(c, MG_EV_POLL, &now);
8378 MG_VERBOSE(("%lu .. %c%c%c%c%c", c->id, c->is_tls ? 'T' : 't',
8379 c->is_connecting ? 'C' : 'c', c->is_tls_hs ? 'H' : 'h',
8380 c->is_resolving ? 'R' : 'r', c->is_closing ? 'C' : 'c'));
8381 if (c->is_tls_hs) mg_tls_handshake(c);
8382 if (can_write(c)) write_conn(c);
8383 if (c->is_draining && c->send.len == 0) c->is_closing = 1;
8384 if (c->is_closing) close_conn(c);
8389 bool mg_send(struct mg_connection *c, const void *buf, size_t len) {
8390 struct mg_tcpip_if *ifp = (struct mg_tcpip_if *) c->mgr->priv;
8392 if (ifp->ip == 0 || ifp->state != MG_TCPIP_STATE_READY) {
8393 mg_error(c, "net down");
8394 } else if (c->is_udp) {
8395 struct connstate *s = (struct connstate *) (c + 1);
8396 tx_udp(ifp, s->mac, ifp->ip, c->loc.port, c->rem.ip, c->rem.port, buf, len);
8399 res = mg_iobuf_add(&c->send, c->send.len, buf, len);
8403 #endif // MG_ENABLE_TCPIP