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.ip, &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 size_t i = 0, max = (size_t) -1, max2 = max / 10, result = 0, ndigits = 0;
1249 while (i < str.len && (str.ptr[i] == ' ' || str.ptr[i] == '\t')) i++;
1250 if (i < str.len && str.ptr[i] == '-') return false;
1251 while (i < str.len && str.ptr[i] >= '0' && str.ptr[i] <= '9') {
1252 size_t digit = (size_t) (str.ptr[i] - '0');
1253 if (result > max2) return false; // Overflow
1255 if (result > max - digit) return false; // Overflow
1259 while (i < str.len && (str.ptr[i] == ' ' || str.ptr[i] == '\t')) i++;
1260 if (ndigits == 0) return false; // #2322: Content-Length = 1 * DIGIT
1261 if (i != str.len) return false; // Ditto
1262 *val = (size_t) result;
1266 // Chunk deletion marker is the MSB in the "processed" counter
1267 #define MG_DMARK ((size_t) 1 << (sizeof(size_t) * 8 - 1))
1269 // Multipart POST example:
1271 // Content-Disposition: form-data; name="val"
1275 // Content-Disposition: form-data; name="foo"; filename="a.txt"
1276 // Content-Type: text/plain
1281 size_t mg_http_next_multipart(struct mg_str body, size_t ofs,
1282 struct mg_http_part *part) {
1283 struct mg_str cd = mg_str_n("Content-Disposition", 19);
1284 const char *s = body.ptr;
1285 size_t b = ofs, h1, h2, b1, b2, max = body.len;
1288 if (part != NULL) part->name = part->filename = part->body = mg_str_n(0, 0);
1291 while (b + 2 < max && s[b] != '\r' && s[b + 1] != '\n') b++;
1292 if (b <= ofs || b + 2 >= max) return 0;
1293 // MG_INFO(("B: %zu %zu [%.*s]", ofs, b - ofs, (int) (b - ofs), s));
1298 while (h2 + 2 < max && s[h2] != '\r' && s[h2 + 1] != '\n') h2++;
1299 if (h2 == h1) break;
1300 if (h2 + 2 >= max) return 0;
1301 // MG_INFO(("Header: [%.*s]", (int) (h2 - h1), &s[h1]));
1302 if (part != NULL && h1 + cd.len + 2 < h2 && s[h1 + cd.len] == ':' &&
1303 mg_ncasecmp(&s[h1], cd.ptr, cd.len) == 0) {
1304 struct mg_str v = mg_str_n(&s[h1 + cd.len + 2], h2 - (h1 + cd.len + 2));
1305 part->name = mg_http_get_header_var(v, mg_str_n("name", 4));
1306 part->filename = mg_http_get_header_var(v, mg_str_n("filename", 8));
1311 while (b2 + 2 + (b - ofs) + 2 < max && !(s[b2] == '\r' && s[b2 + 1] == '\n' &&
1312 memcmp(&s[b2 + 2], s, b - ofs) == 0))
1315 if (b2 + 2 >= max) return 0;
1316 if (part != NULL) part->body = mg_str_n(&s[b1], b2 - b1);
1317 // MG_INFO(("Body: [%.*s]", (int) (b2 - b1), &s[b1]));
1321 void mg_http_bauth(struct mg_connection *c, const char *user,
1323 struct mg_str u = mg_str(user), p = mg_str(pass);
1324 size_t need = c->send.len + 36 + (u.len + p.len) * 2;
1325 if (c->send.size < need) mg_iobuf_resize(&c->send, need);
1326 if (c->send.size >= need) {
1328 char *buf = (char *) &c->send.buf[c->send.len];
1329 memcpy(buf, "Authorization: Basic ", 21); // DON'T use mg_send!
1330 for (i = 0; i < (int) u.len; i++) {
1331 n = mg_base64_update(((unsigned char *) u.ptr)[i], buf + 21, n);
1334 n = mg_base64_update(':', buf + 21, n);
1335 for (i = 0; i < (int) p.len; i++) {
1336 n = mg_base64_update(((unsigned char *) p.ptr)[i], buf + 21, n);
1339 n = mg_base64_final(buf + 21, n);
1340 c->send.len += 21 + (size_t) n + 2;
1341 memcpy(&c->send.buf[c->send.len - 2], "\r\n", 2);
1343 MG_ERROR(("%lu oom %d->%d ", c->id, (int) c->send.size, (int) need));
1347 struct mg_str mg_http_var(struct mg_str buf, struct mg_str name) {
1348 struct mg_str k, v, result = mg_str_n(NULL, 0);
1349 while (mg_split(&buf, &k, &v, '&')) {
1350 if (name.len == k.len && mg_ncasecmp(name.ptr, k.ptr, k.len) == 0) {
1358 int mg_http_get_var(const struct mg_str *buf, const char *name, char *dst,
1361 if (dst == NULL || dst_len == 0) {
1362 len = -2; // Bad destination
1363 } else if (buf->ptr == NULL || name == NULL || buf->len == 0) {
1364 len = -1; // Bad source
1367 struct mg_str v = mg_http_var(*buf, mg_str(name));
1368 if (v.ptr == NULL) {
1369 len = -4; // Name does not exist
1371 len = mg_url_decode(v.ptr, v.len, dst, dst_len, 1);
1372 if (len < 0) len = -3; // Failed to decode
1378 static bool isx(int c) {
1379 return (c >= '0' && c <= '9') || (c >= 'a' && c <= 'f') ||
1380 (c >= 'A' && c <= 'F');
1383 int mg_url_decode(const char *src, size_t src_len, char *dst, size_t dst_len,
1384 int is_form_url_encoded) {
1386 for (i = j = 0; i < src_len && j + 1 < dst_len; i++, j++) {
1387 if (src[i] == '%') {
1388 // Use `i + 2 < src_len`, not `i < src_len - 2`, note small src_len
1389 if (i + 2 < src_len && isx(src[i + 1]) && isx(src[i + 2])) {
1390 mg_unhex(src + i + 1, 2, (uint8_t *) &dst[j]);
1395 } else if (is_form_url_encoded && src[i] == '+') {
1401 if (j < dst_len) dst[j] = '\0'; // Null-terminate the destination
1402 return i >= src_len && j < dst_len ? (int) j : -1;
1405 static bool isok(uint8_t c) {
1406 return c == '\n' || c == '\r' || c >= ' ';
1409 int mg_http_get_request_len(const unsigned char *buf, size_t buf_len) {
1411 for (i = 0; i < buf_len; i++) {
1412 if (!isok(buf[i])) return -1;
1413 if ((i > 0 && buf[i] == '\n' && buf[i - 1] == '\n') ||
1414 (i > 3 && buf[i] == '\n' && buf[i - 1] == '\r' && buf[i - 2] == '\n'))
1419 struct mg_str *mg_http_get_header(struct mg_http_message *h, const char *name) {
1420 size_t i, n = strlen(name), max = sizeof(h->headers) / sizeof(h->headers[0]);
1421 for (i = 0; i < max && h->headers[i].name.len > 0; i++) {
1422 struct mg_str *k = &h->headers[i].name, *v = &h->headers[i].value;
1423 if (n == k->len && mg_ncasecmp(k->ptr, name, n) == 0) return v;
1428 // Get character length. Used to parse method, URI, headers
1429 static size_t clen(const char *s) {
1430 uint8_t c = *(uint8_t *) s;
1431 if (c > ' ' && c < '~') return 1; // Usual ascii printed char
1432 if ((c & 0xe0) == 0xc0) return 2; // 2-byte UTF8
1433 if ((c & 0xf0) == 0xe0) return 3; // 3-byte UTF8
1434 if ((c & 0xf8) == 0xf0) return 4; // 4-byte UTF8
1438 // Skip until the newline. Return advanced `s`, or NULL on error
1439 static const char *skiptorn(const char *s, const char *end, struct mg_str *v) {
1441 while (s < end && s[0] != '\n' && s[0] != '\r') s++, v->len++; // To newline
1442 if (s >= end || (s[0] == '\r' && s[1] != '\n')) return NULL; // Stray \r
1443 if (s < end && s[0] == '\r') s++; // Skip \r
1444 if (s >= end || *s++ != '\n') return NULL; // Skip \n
1448 static bool mg_http_parse_headers(const char *s, const char *end,
1449 struct mg_http_header *h, size_t max_hdrs) {
1451 for (i = 0; i < max_hdrs; i++) {
1452 struct mg_str k = {NULL, 0}, v = {NULL, 0};
1453 if (s >= end) return false;
1454 if (s[0] == '\n' || (s[0] == '\r' && s[1] == '\n')) break;
1456 while (s < end && s[0] != ':' && (n = clen(s)) > 0) s += n, k.len += n;
1457 if (k.len == 0) return false; // Empty name
1458 if (s >= end || *s++ != ':') return false; // Invalid, not followed by :
1459 while (s < end && s[0] == ' ') s++; // Skip spaces
1460 if ((s = skiptorn(s, end, &v)) == NULL) return false;
1461 while (v.len > 0 && v.ptr[v.len - 1] == ' ') v.len--; // Trim spaces
1462 // MG_INFO(("--HH [%.*s] [%.*s]", (int) k.len, k.ptr, (int) v.len, v.ptr));
1463 h[i].name = k, h[i].value = v; // Success. Assign values
1468 int mg_http_parse(const char *s, size_t len, struct mg_http_message *hm) {
1469 int is_response, req_len = mg_http_get_request_len((unsigned char *) s, len);
1470 const char *end = s == NULL ? NULL : s + req_len, *qs; // Cannot add to NULL
1474 memset(hm, 0, sizeof(*hm));
1475 if (req_len <= 0) return req_len;
1477 hm->message.ptr = hm->head.ptr = s;
1479 hm->head.len = (size_t) req_len;
1480 hm->chunk.ptr = end;
1481 hm->message.len = hm->body.len = (size_t) ~0; // Set body length to infinite
1483 // Parse request line
1485 while (s < end && (n = clen(s)) > 0) s += n, hm->method.len += n;
1486 while (s < end && s[0] == ' ') s++; // Skip spaces
1488 while (s < end && (n = clen(s)) > 0) s += n, hm->uri.len += n;
1489 while (s < end && s[0] == ' ') s++; // Skip spaces
1490 if ((s = skiptorn(s, end, &hm->proto)) == NULL) return false;
1492 // Sanity check. Allow protocol/reason to be empty
1493 if (hm->method.len == 0 || hm->uri.len == 0) return -1;
1495 // If URI contains '?' character, setup query string
1496 if ((qs = (const char *) memchr(hm->uri.ptr, '?', hm->uri.len)) != NULL) {
1497 hm->query.ptr = qs + 1;
1498 hm->query.len = (size_t) (&hm->uri.ptr[hm->uri.len] - (qs + 1));
1499 hm->uri.len = (size_t) (qs - hm->uri.ptr);
1502 if (!mg_http_parse_headers(s, end, hm->headers,
1503 sizeof(hm->headers) / sizeof(hm->headers[0])))
1504 return -1; // error when parsing
1505 if ((cl = mg_http_get_header(hm, "Content-Length")) != NULL) {
1506 if (mg_to_size_t(*cl, &hm->body.len) == false) return -1;
1507 hm->message.len = (size_t) req_len + hm->body.len;
1510 // mg_http_parse() is used to parse both HTTP requests and HTTP
1511 // responses. If HTTP response does not have Content-Length set, then
1512 // body is read until socket is closed, i.e. body.len is infinite (~0).
1514 // For HTTP requests though, according to
1515 // http://tools.ietf.org/html/rfc7231#section-8.1.3,
1516 // only POST and PUT methods have defined body semantics.
1517 // Therefore, if Content-Length is not specified and methods are
1518 // not one of PUT or POST, set body length to 0.
1520 // So, if it is HTTP request, and Content-Length is not set,
1521 // and method is not (PUT or POST) then reset body length to zero.
1522 is_response = mg_ncasecmp(hm->method.ptr, "HTTP/", 5) == 0;
1523 if (hm->body.len == (size_t) ~0 && !is_response &&
1524 mg_vcasecmp(&hm->method, "PUT") != 0 &&
1525 mg_vcasecmp(&hm->method, "POST") != 0) {
1527 hm->message.len = (size_t) req_len;
1530 // The 204 (No content) responses also have 0 body length
1531 if (hm->body.len == (size_t) ~0 && is_response &&
1532 mg_vcasecmp(&hm->uri, "204") == 0) {
1534 hm->message.len = (size_t) req_len;
1536 if (hm->message.len < (size_t) req_len) return -1; // Overflow protection
1541 static void mg_http_vprintf_chunk(struct mg_connection *c, const char *fmt,
1543 size_t len = c->send.len;
1544 mg_send(c, " \r\n", 10);
1545 mg_vxprintf(mg_pfn_iobuf, &c->send, fmt, ap);
1546 if (c->send.len >= len + 10) {
1547 mg_snprintf((char *) c->send.buf + len, 9, "%08lx", c->send.len - len - 10);
1548 c->send.buf[len + 8] = '\r';
1549 if (c->send.len == len + 10) c->is_resp = 0; // Last chunk, reset marker
1551 mg_send(c, "\r\n", 2);
1554 void mg_http_printf_chunk(struct mg_connection *c, const char *fmt, ...) {
1557 mg_http_vprintf_chunk(c, fmt, &ap);
1561 void mg_http_write_chunk(struct mg_connection *c, const char *buf, size_t len) {
1562 mg_printf(c, "%lx\r\n", (unsigned long) len);
1563 mg_send(c, buf, len);
1564 mg_send(c, "\r\n", 2);
1565 if (len == 0) c->is_resp = 0;
1569 static const char *mg_http_status_code_str(int status_code) {
1570 switch (status_code) {
1571 case 100: return "Continue";
1572 case 101: return "Switching Protocols";
1573 case 102: return "Processing";
1574 case 200: return "OK";
1575 case 201: return "Created";
1576 case 202: return "Accepted";
1577 case 203: return "Non-authoritative Information";
1578 case 204: return "No Content";
1579 case 205: return "Reset Content";
1580 case 206: return "Partial Content";
1581 case 207: return "Multi-Status";
1582 case 208: return "Already Reported";
1583 case 226: return "IM Used";
1584 case 300: return "Multiple Choices";
1585 case 301: return "Moved Permanently";
1586 case 302: return "Found";
1587 case 303: return "See Other";
1588 case 304: return "Not Modified";
1589 case 305: return "Use Proxy";
1590 case 307: return "Temporary Redirect";
1591 case 308: return "Permanent Redirect";
1592 case 400: return "Bad Request";
1593 case 401: return "Unauthorized";
1594 case 402: return "Payment Required";
1595 case 403: return "Forbidden";
1596 case 404: return "Not Found";
1597 case 405: return "Method Not Allowed";
1598 case 406: return "Not Acceptable";
1599 case 407: return "Proxy Authentication Required";
1600 case 408: return "Request Timeout";
1601 case 409: return "Conflict";
1602 case 410: return "Gone";
1603 case 411: return "Length Required";
1604 case 412: return "Precondition Failed";
1605 case 413: return "Payload Too Large";
1606 case 414: return "Request-URI Too Long";
1607 case 415: return "Unsupported Media Type";
1608 case 416: return "Requested Range Not Satisfiable";
1609 case 417: return "Expectation Failed";
1610 case 418: return "I'm a teapot";
1611 case 421: return "Misdirected Request";
1612 case 422: return "Unprocessable Entity";
1613 case 423: return "Locked";
1614 case 424: return "Failed Dependency";
1615 case 426: return "Upgrade Required";
1616 case 428: return "Precondition Required";
1617 case 429: return "Too Many Requests";
1618 case 431: return "Request Header Fields Too Large";
1619 case 444: return "Connection Closed Without Response";
1620 case 451: return "Unavailable For Legal Reasons";
1621 case 499: return "Client Closed Request";
1622 case 500: return "Internal Server Error";
1623 case 501: return "Not Implemented";
1624 case 502: return "Bad Gateway";
1625 case 503: return "Service Unavailable";
1626 case 504: return "Gateway Timeout";
1627 case 505: return "HTTP Version Not Supported";
1628 case 506: return "Variant Also Negotiates";
1629 case 507: return "Insufficient Storage";
1630 case 508: return "Loop Detected";
1631 case 510: return "Not Extended";
1632 case 511: return "Network Authentication Required";
1633 case 599: return "Network Connect Timeout Error";
1639 void mg_http_reply(struct mg_connection *c, int code, const char *headers,
1640 const char *fmt, ...) {
1643 mg_printf(c, "HTTP/1.1 %d %s\r\n%sContent-Length: \r\n\r\n", code,
1644 mg_http_status_code_str(code), headers == NULL ? "" : headers);
1647 mg_vxprintf(mg_pfn_iobuf, &c->send, fmt, &ap);
1649 if (c->send.len > 16) {
1650 size_t n = mg_snprintf((char *) &c->send.buf[len - 15], 11, "%-10lu",
1651 (unsigned long) (c->send.len - len));
1652 c->send.buf[len - 15 + n] = ' '; // Change ending 0 to space
1657 static void http_cb(struct mg_connection *, int, void *, void *);
1658 static void restore_http_cb(struct mg_connection *c) {
1659 mg_fs_close((struct mg_fd *) c->pfn_data);
1665 char *mg_http_etag(char *buf, size_t len, size_t size, time_t mtime);
1666 char *mg_http_etag(char *buf, size_t len, size_t size, time_t mtime) {
1667 mg_snprintf(buf, len, "\"%lld.%lld\"", (int64_t) mtime, (int64_t) size);
1671 static void static_cb(struct mg_connection *c, int ev, void *ev_data,
1673 if (ev == MG_EV_WRITE || ev == MG_EV_POLL) {
1674 struct mg_fd *fd = (struct mg_fd *) fn_data;
1675 // Read to send IO buffer directly, avoid extra on-stack buffer
1676 size_t n, max = MG_IO_SIZE, space;
1677 size_t *cl = (size_t *) &c->data[(sizeof(c->data) - sizeof(size_t)) /
1678 sizeof(size_t) * sizeof(size_t)];
1679 if (c->send.size < max) mg_iobuf_resize(&c->send, max);
1680 if (c->send.len >= c->send.size) return; // Rate limit
1681 if ((space = c->send.size - c->send.len) > *cl) space = *cl;
1682 n = fd->fs->rd(fd->fd, c->send.buf + c->send.len, space);
1685 if (n == 0) restore_http_cb(c);
1686 } else if (ev == MG_EV_CLOSE) {
1692 // Known mime types. Keep it outside guess_content_type() function, since
1693 // some environments don't like it defined there.
1695 static struct mg_str s_known_types[] = {
1696 MG_C_STR("html"), MG_C_STR("text/html; charset=utf-8"),
1697 MG_C_STR("htm"), MG_C_STR("text/html; charset=utf-8"),
1698 MG_C_STR("css"), MG_C_STR("text/css; charset=utf-8"),
1699 MG_C_STR("js"), MG_C_STR("text/javascript; charset=utf-8"),
1700 MG_C_STR("gif"), MG_C_STR("image/gif"),
1701 MG_C_STR("png"), MG_C_STR("image/png"),
1702 MG_C_STR("jpg"), MG_C_STR("image/jpeg"),
1703 MG_C_STR("jpeg"), MG_C_STR("image/jpeg"),
1704 MG_C_STR("woff"), MG_C_STR("font/woff"),
1705 MG_C_STR("ttf"), MG_C_STR("font/ttf"),
1706 MG_C_STR("svg"), MG_C_STR("image/svg+xml"),
1707 MG_C_STR("txt"), MG_C_STR("text/plain; charset=utf-8"),
1708 MG_C_STR("avi"), MG_C_STR("video/x-msvideo"),
1709 MG_C_STR("csv"), MG_C_STR("text/csv"),
1710 MG_C_STR("doc"), MG_C_STR("application/msword"),
1711 MG_C_STR("exe"), MG_C_STR("application/octet-stream"),
1712 MG_C_STR("gz"), MG_C_STR("application/gzip"),
1713 MG_C_STR("ico"), MG_C_STR("image/x-icon"),
1714 MG_C_STR("json"), MG_C_STR("application/json"),
1715 MG_C_STR("mov"), MG_C_STR("video/quicktime"),
1716 MG_C_STR("mp3"), MG_C_STR("audio/mpeg"),
1717 MG_C_STR("mp4"), MG_C_STR("video/mp4"),
1718 MG_C_STR("mpeg"), MG_C_STR("video/mpeg"),
1719 MG_C_STR("pdf"), MG_C_STR("application/pdf"),
1720 MG_C_STR("shtml"), MG_C_STR("text/html; charset=utf-8"),
1721 MG_C_STR("tgz"), MG_C_STR("application/tar-gz"),
1722 MG_C_STR("wav"), MG_C_STR("audio/wav"),
1723 MG_C_STR("webp"), MG_C_STR("image/webp"),
1724 MG_C_STR("zip"), MG_C_STR("application/zip"),
1725 MG_C_STR("3gp"), MG_C_STR("video/3gpp"),
1730 static struct mg_str guess_content_type(struct mg_str path, const char *extra) {
1731 struct mg_str k, v, s = mg_str(extra);
1734 // Shrink path to its extension only
1735 while (i < path.len && path.ptr[path.len - i - 1] != '.') i++;
1736 path.ptr += path.len - i;
1739 // Process user-provided mime type overrides, if any
1740 while (mg_commalist(&s, &k, &v)) {
1741 if (mg_strcmp(path, k) == 0) return v;
1744 // Process built-in mime types
1745 for (i = 0; s_known_types[i].ptr != NULL; i += 2) {
1746 if (mg_strcmp(path, s_known_types[i]) == 0) return s_known_types[i + 1];
1749 return mg_str("text/plain; charset=utf-8");
1752 static int getrange(struct mg_str *s, size_t *a, size_t *b) {
1753 size_t i, numparsed = 0;
1754 for (i = 0; i + 6 < s->len; i++) {
1755 struct mg_str k, v = mg_str_n(s->ptr + i + 6, s->len - i - 6);
1756 if (memcmp(&s->ptr[i], "bytes=", 6) != 0) continue;
1757 if (mg_split(&v, &k, NULL, '-')) {
1758 if (mg_to_size_t(k, a)) numparsed++;
1759 if (v.len > 0 && mg_to_size_t(v, b)) numparsed++;
1761 if (mg_to_size_t(v, a)) numparsed++;
1765 return (int) numparsed;
1768 void mg_http_serve_file(struct mg_connection *c, struct mg_http_message *hm,
1770 const struct mg_http_serve_opts *opts) {
1771 char etag[64], tmp[MG_PATH_MAX];
1772 struct mg_fs *fs = opts->fs == NULL ? &mg_fs_posix : opts->fs;
1773 struct mg_fd *fd = NULL;
1776 struct mg_str *inm = NULL;
1777 struct mg_str mime = guess_content_type(mg_str(path), opts->mime_types);
1781 // If a browser sends us "Accept-Encoding: gzip", try to open .gz first
1782 struct mg_str *ae = mg_http_get_header(hm, "Accept-Encoding");
1783 if (ae != NULL && mg_strstr(*ae, mg_str("gzip")) != NULL) {
1784 mg_snprintf(tmp, sizeof(tmp), "%s.gz", path);
1785 fd = mg_fs_open(fs, tmp, MG_FS_READ);
1786 if (fd != NULL) gzip = true, path = tmp;
1788 // No luck opening .gz? Open what we've told to open
1789 if (fd == NULL) fd = mg_fs_open(fs, path, MG_FS_READ);
1792 // Failed to open, and page404 is configured? Open it, then
1793 if (fd == NULL && opts->page404 != NULL) {
1794 fd = mg_fs_open(fs, opts->page404, MG_FS_READ);
1795 mime = guess_content_type(mg_str(path), opts->mime_types);
1796 path = opts->page404;
1799 if (fd == NULL || fs->st(path, &size, &mtime) == 0) {
1800 mg_http_reply(c, 404, opts->extra_headers, "Not found\n");
1802 // NOTE: mg_http_etag() call should go first!
1803 } else if (mg_http_etag(etag, sizeof(etag), size, mtime) != NULL &&
1804 (inm = mg_http_get_header(hm, "If-None-Match")) != NULL &&
1805 mg_vcasecmp(inm, etag) == 0) {
1807 mg_http_reply(c, 304, opts->extra_headers, "");
1809 int n, status = 200;
1811 size_t r1 = 0, r2 = 0, cl = size;
1813 // Handle Range header
1814 struct mg_str *rh = mg_http_get_header(hm, "Range");
1816 if (rh != NULL && (n = getrange(rh, &r1, &r2)) > 0) {
1817 // If range is specified like "400-", set second limit to content len
1818 if (n == 1) r2 = cl - 1;
1819 if (r1 > r2 || r2 >= cl) {
1822 mg_snprintf(range, sizeof(range), "Content-Range: bytes */%lld\r\n",
1827 mg_snprintf(range, sizeof(range),
1828 "Content-Range: bytes %llu-%llu/%llu\r\n", (uint64_t) r1,
1829 (uint64_t) (r1 + cl - 1), (uint64_t) size);
1834 "HTTP/1.1 %d %s\r\n"
1835 "Content-Type: %.*s\r\n"
1837 "Content-Length: %llu\r\n"
1839 status, mg_http_status_code_str(status), (int) mime.len, mime.ptr,
1840 etag, (uint64_t) cl, gzip ? "Content-Encoding: gzip\r\n" : "",
1841 range, opts->extra_headers ? opts->extra_headers : "");
1842 if (mg_vcasecmp(&hm->method, "HEAD") == 0) {
1847 // Track to-be-sent content length at the end of c->data, aligned
1848 size_t *clp = (size_t *) &c->data[(sizeof(c->data) - sizeof(size_t)) /
1849 sizeof(size_t) * sizeof(size_t)];
1857 struct printdirentrydata {
1858 struct mg_connection *c;
1859 struct mg_http_message *hm;
1860 const struct mg_http_serve_opts *opts;
1864 #if MG_ENABLE_DIRLIST
1865 static void printdirentry(const char *name, void *userdata) {
1866 struct printdirentrydata *d = (struct printdirentrydata *) userdata;
1867 struct mg_fs *fs = d->opts->fs == NULL ? &mg_fs_posix : d->opts->fs;
1870 char path[MG_PATH_MAX], sz[40], mod[40];
1873 // MG_DEBUG(("[%s] [%s]", d->dir, name));
1874 if (mg_snprintf(path, sizeof(path), "%s%c%s", d->dir, '/', name) >
1876 MG_ERROR(("%s truncated", name));
1877 } else if ((flags = fs->st(path, &size, &t)) == 0) {
1878 MG_ERROR(("%lu stat(%s): %d", d->c->id, path, errno));
1880 const char *slash = flags & MG_FS_DIR ? "/" : "";
1881 if (flags & MG_FS_DIR) {
1882 mg_snprintf(sz, sizeof(sz), "%s", "[DIR]");
1884 mg_snprintf(sz, sizeof(sz), "%lld", (uint64_t) size);
1886 #if defined(MG_HTTP_DIRLIST_TIME_FMT)
1889 struct tm *time_info = localtime(&t);
1890 strftime(time_str, sizeof time_str, "%Y/%m/%d %H:%M:%S", time_info);
1891 mg_snprintf(mod, sizeof(mod), "%s", time_str);
1894 mg_snprintf(mod, sizeof(mod), "%lu", (unsigned long) t);
1896 n = (int) mg_url_encode(name, strlen(name), path, sizeof(path));
1898 " <tr><td><a href=\"%.*s%s\">%s%s</a></td>"
1899 "<td name=%lu>%s</td><td name=%lld>%s</td></tr>\n",
1900 n, path, slash, name, slash, (unsigned long) t, mod,
1901 flags & MG_FS_DIR ? (int64_t) -1 : (int64_t) size, sz);
1905 static void listdir(struct mg_connection *c, struct mg_http_message *hm,
1906 const struct mg_http_serve_opts *opts, char *dir) {
1907 const char *sort_js_code =
1908 "<script>function srt(tb, sc, so, d) {"
1909 "var tr = Array.prototype.slice.call(tb.rows, 0),"
1910 "tr = tr.sort(function (a, b) { var c1 = a.cells[sc], c2 = b.cells[sc],"
1911 "n1 = c1.getAttribute('name'), n2 = c2.getAttribute('name'), "
1912 "t1 = a.cells[2].getAttribute('name'), "
1913 "t2 = b.cells[2].getAttribute('name'); "
1914 "return so * (t1 < 0 && t2 >= 0 ? -1 : t2 < 0 && t1 >= 0 ? 1 : "
1915 "n1 ? parseInt(n2) - parseInt(n1) : "
1916 "c1.textContent.trim().localeCompare(c2.textContent.trim())); });";
1917 const char *sort_js_code2 =
1918 "for (var i = 0; i < tr.length; i++) tb.appendChild(tr[i]); "
1919 "if (!d) window.location.hash = ('sc=' + sc + '&so=' + so); "
1921 "window.onload = function() {"
1922 "var tb = document.getElementById('tb');"
1923 "var m = /sc=([012]).so=(1|-1)/.exec(window.location.hash) || [0, 2, 1];"
1924 "var sc = m[1], so = m[2]; document.onclick = function(ev) { "
1925 "var c = ev.target.rel; if (c) {if (c == sc) so *= -1; srt(tb, c, so); "
1926 "sc = c; ev.preventDefault();}};"
1927 "srt(tb, sc, so, true);"
1930 struct mg_fs *fs = opts->fs == NULL ? &mg_fs_posix : opts->fs;
1931 struct printdirentrydata d = {c, hm, opts, dir};
1932 char tmp[10], buf[MG_PATH_MAX];
1934 int len = mg_url_decode(hm->uri.ptr, hm->uri.len, buf, sizeof(buf), 0);
1935 struct mg_str uri = len > 0 ? mg_str_n(buf, (size_t) len) : hm->uri;
1938 "HTTP/1.1 200 OK\r\n"
1939 "Content-Type: text/html; charset=utf-8\r\n"
1941 "Content-Length: \r\n\r\n",
1942 opts->extra_headers == NULL ? "" : opts->extra_headers);
1943 off = c->send.len; // Start of body
1945 "<!DOCTYPE html><html><head><title>Index of %.*s</title>%s%s"
1946 "<style>th,td {text-align: left; padding-right: 1em; "
1947 "font-family: monospace; }</style></head>"
1948 "<body><h1>Index of %.*s</h1><table cellpadding=\"0\"><thead>"
1949 "<tr><th><a href=\"#\" rel=\"0\">Name</a></th><th>"
1950 "<a href=\"#\" rel=\"1\">Modified</a></th>"
1951 "<th><a href=\"#\" rel=\"2\">Size</a></th></tr>"
1952 "<tr><td colspan=\"3\"><hr></td></tr>"
1954 "<tbody id=\"tb\">\n",
1955 (int) uri.len, uri.ptr, sort_js_code, sort_js_code2, (int) uri.len,
1958 " <tr><td><a href=\"..\">..</a></td>"
1959 "<td name=-1></td><td name=-1>[DIR]</td></tr>\n");
1961 fs->ls(dir, printdirentry, &d);
1963 "</tbody><tfoot><tr><td colspan=\"3\"><hr></td></tr></tfoot>"
1964 "</table><address>Mongoose v.%s</address></body></html>\n",
1966 n = mg_snprintf(tmp, sizeof(tmp), "%lu", (unsigned long) (c->send.len - off));
1967 if (n > sizeof(tmp)) n = 0;
1968 memcpy(c->send.buf + off - 12, tmp, n); // Set content length
1969 c->is_resp = 0; // Mark response end
1973 // Resolve requested file into `path` and return its fs->st() result
1974 static int uri_to_path2(struct mg_connection *c, struct mg_http_message *hm,
1975 struct mg_fs *fs, struct mg_str url, struct mg_str dir,
1976 char *path, size_t path_size) {
1978 // Append URI to the root_dir, and sanitize it
1979 size_t n = mg_snprintf(path, path_size, "%.*s", (int) dir.len, dir.ptr);
1980 if (n + 2 >= path_size) {
1981 mg_http_reply(c, 400, "", "Exceeded path size");
1984 path[path_size - 1] = '\0';
1985 // Terminate root dir with slash
1986 if (n > 0 && path[n - 1] != '/') path[n++] = '/', path[n] = '\0';
1987 if (url.len < hm->uri.len) {
1988 mg_url_decode(hm->uri.ptr + url.len, hm->uri.len - url.len, path + n,
1991 path[path_size - 1] = '\0'; // Double-check
1992 if (!mg_path_is_sane(path)) {
1993 mg_http_reply(c, 400, "", "Invalid path");
1997 while (n > 1 && path[n - 1] == '/') path[--n] = 0; // Trim trailing slashes
1998 flags = mg_vcmp(&hm->uri, "/") == 0 ? MG_FS_DIR : fs->st(path, NULL, NULL);
1999 MG_VERBOSE(("%lu %.*s -> %s %d", c->id, (int) hm->uri.len, hm->uri.ptr, path,
2002 // Do nothing - let's caller decide
2003 } else if ((flags & MG_FS_DIR) && hm->uri.len > 0 &&
2004 hm->uri.ptr[hm->uri.len - 1] != '/') {
2006 "HTTP/1.1 301 Moved\r\n"
2007 "Location: %.*s/\r\n"
2008 "Content-Length: 0\r\n"
2010 (int) hm->uri.len, hm->uri.ptr);
2013 } else if (flags & MG_FS_DIR) {
2014 if (((mg_snprintf(path + n, path_size - n, "/" MG_HTTP_INDEX) > 0 &&
2015 (tmp = fs->st(path, NULL, NULL)) != 0) ||
2016 (mg_snprintf(path + n, path_size - n, "/index.shtml") > 0 &&
2017 (tmp = fs->st(path, NULL, NULL)) != 0))) {
2019 } else if ((mg_snprintf(path + n, path_size - n, "/" MG_HTTP_INDEX ".gz") >
2021 (tmp = fs->st(path, NULL, NULL)) !=
2022 0)) { // check for gzipped index
2024 path[n + 1 + strlen(MG_HTTP_INDEX)] =
2025 '\0'; // Remove appended .gz in index file name
2027 path[n] = '\0'; // Remove appended index file name
2033 static int uri_to_path(struct mg_connection *c, struct mg_http_message *hm,
2034 const struct mg_http_serve_opts *opts, char *path,
2036 struct mg_fs *fs = opts->fs == NULL ? &mg_fs_posix : opts->fs;
2037 struct mg_str k, v, s = mg_str(opts->root_dir), u = {0, 0}, p = {0, 0};
2038 while (mg_commalist(&s, &k, &v)) {
2039 if (v.len == 0) v = k, k = mg_str("/"), u = k, p = v;
2040 if (hm->uri.len < k.len) continue;
2041 if (mg_strcmp(k, mg_str_n(hm->uri.ptr, k.len)) != 0) continue;
2044 return uri_to_path2(c, hm, fs, u, p, path, path_size);
2047 void mg_http_serve_dir(struct mg_connection *c, struct mg_http_message *hm,
2048 const struct mg_http_serve_opts *opts) {
2049 char path[MG_PATH_MAX];
2050 const char *sp = opts->ssi_pattern;
2051 int flags = uri_to_path(c, hm, opts, path, sizeof(path));
2053 // Do nothing: the response has already been sent by uri_to_path()
2054 } else if (flags & MG_FS_DIR) {
2055 #if MG_ENABLE_DIRLIST
2056 listdir(c, hm, opts, path);
2058 mg_http_reply(c, 403, "", "Forbidden\n");
2060 } else if (flags && sp != NULL &&
2061 mg_globmatch(sp, strlen(sp), path, strlen(path))) {
2062 mg_http_serve_ssi(c, opts->root_dir, path);
2064 mg_http_serve_file(c, hm, path, opts);
2068 static bool mg_is_url_safe(int c) {
2069 return (c >= '0' && c <= '9') || (c >= 'a' && c <= 'z') ||
2070 (c >= 'A' && c <= 'Z') || c == '.' || c == '_' || c == '-' || c == '~';
2073 size_t mg_url_encode(const char *s, size_t sl, char *buf, size_t len) {
2075 for (i = 0; i < sl; i++) {
2076 int c = *(unsigned char *) &s[i];
2077 if (n + 4 >= len) return 0;
2078 if (mg_is_url_safe(c)) {
2082 mg_hex(&s[i], 1, &buf[n]);
2086 if (len > 0 && n < len - 1) buf[n] = '\0'; // Null-terminate the destination
2087 if (len > 0) buf[len - 1] = '\0'; // Always.
2091 void mg_http_creds(struct mg_http_message *hm, char *user, size_t userlen,
2092 char *pass, size_t passlen) {
2093 struct mg_str *v = mg_http_get_header(hm, "Authorization");
2094 user[0] = pass[0] = '\0';
2095 if (v != NULL && v->len > 6 && memcmp(v->ptr, "Basic ", 6) == 0) {
2097 int n = mg_base64_decode(v->ptr + 6, (int) v->len - 6, buf);
2098 const char *p = (const char *) memchr(buf, ':', n > 0 ? (size_t) n : 0);
2100 mg_snprintf(user, userlen, "%.*s", (int) (p - buf), buf);
2101 mg_snprintf(pass, passlen, "%.*s", n - (int) (p - buf) - 1, p + 1);
2103 } else if (v != NULL && v->len > 7 && memcmp(v->ptr, "Bearer ", 7) == 0) {
2104 mg_snprintf(pass, passlen, "%.*s", (int) v->len - 7, v->ptr + 7);
2105 } else if ((v = mg_http_get_header(hm, "Cookie")) != NULL) {
2106 struct mg_str t = mg_http_get_header_var(*v, mg_str_n("access_token", 12));
2107 if (t.len > 0) mg_snprintf(pass, passlen, "%.*s", (int) t.len, t.ptr);
2109 mg_http_get_var(&hm->query, "access_token", pass, passlen);
2113 static struct mg_str stripquotes(struct mg_str s) {
2114 return s.len > 1 && s.ptr[0] == '"' && s.ptr[s.len - 1] == '"'
2115 ? mg_str_n(s.ptr + 1, s.len - 2)
2119 struct mg_str mg_http_get_header_var(struct mg_str s, struct mg_str v) {
2121 for (i = 0; v.len > 0 && i + v.len + 2 < s.len; i++) {
2122 if (s.ptr[i + v.len] == '=' && memcmp(&s.ptr[i], v.ptr, v.len) == 0) {
2123 const char *p = &s.ptr[i + v.len + 1], *b = p, *x = &s.ptr[s.len];
2124 int q = p < x && *p == '"' ? 1 : 0;
2126 (q ? p == b || *p != '"' : *p != ';' && *p != ' ' && *p != ','))
2128 // MG_INFO(("[%.*s] [%.*s] [%.*s]", (int) s.len, s.ptr, (int) v.len,
2129 // v.ptr, (int) (p - b), b));
2130 return stripquotes(mg_str_n(b, (size_t) (p - b + q)));
2133 return mg_str_n(NULL, 0);
2136 bool mg_http_match_uri(const struct mg_http_message *hm, const char *glob) {
2137 return mg_match(hm->uri, mg_str(glob), NULL);
2140 long mg_http_upload(struct mg_connection *c, struct mg_http_message *hm,
2141 struct mg_fs *fs, const char *path, size_t max_size) {
2143 long res = 0, offset;
2144 mg_http_get_var(&hm->query, "offset", buf, sizeof(buf));
2145 offset = strtol(buf, NULL, 0);
2146 if (hm->body.len == 0) {
2147 mg_http_reply(c, 200, "", "%ld", res); // Nothing to write
2150 size_t current_size = 0;
2151 MG_DEBUG(("%s -> %d bytes @ %ld", path, (int) hm->body.len, offset));
2152 if (offset == 0) fs->rm(path); // If offset if 0, truncate file
2153 fs->st(path, ¤t_size, NULL);
2155 mg_http_reply(c, 400, "", "offset required");
2157 } else if (offset > 0 && current_size != (size_t) offset) {
2158 mg_http_reply(c, 400, "", "%s: offset mismatch", path);
2160 } else if ((size_t) offset + hm->body.len > max_size) {
2161 mg_http_reply(c, 400, "", "%s: over max size of %lu", path,
2162 (unsigned long) max_size);
2164 } else if ((fd = mg_fs_open(fs, path, MG_FS_WRITE)) == NULL) {
2165 mg_http_reply(c, 400, "", "open(%s): %d", path, errno);
2168 res = offset + (long) fs->wr(fd->fd, hm->body.ptr, hm->body.len);
2170 mg_http_reply(c, 200, "", "%ld", res);
2176 int mg_http_status(const struct mg_http_message *hm) {
2177 return atoi(hm->uri.ptr);
2180 // If a server sends data to the client using chunked encoding, Mongoose strips
2181 // off the chunking prefix (hex length and \r\n) and suffix (\r\n), appends the
2182 // stripped data to the body, and fires the MG_EV_HTTP_CHUNK event. When zero
2183 // chunk is received, we fire MG_EV_HTTP_MSG, and the body already has all
2184 // chunking prefixes/suffixes stripped.
2186 // If a server sends data without chunked encoding, we also fire a series of
2187 // MG_EV_HTTP_CHUNK events for every received piece of data, and then we fire
2188 // MG_EV_HTTP_MSG event in the end.
2190 // We track total processed length in the c->pfn_data, which is a void *
2191 // pointer: we store a size_t value there.
2192 static bool getchunk(struct mg_str s, size_t *prefixlen, size_t *datalen) {
2194 while (i < s.len && s.ptr[i] != '\r' && s.ptr[i] != '\n') i++;
2195 n = mg_unhexn(s.ptr, i);
2196 // MG_INFO(("%d %d", (int) (i + n + 4), (int) s.len));
2197 if (s.len < i + n + 4) return false; // Chunk not yet fully buffered
2198 if (s.ptr[i] != '\r' || s.ptr[i + 1] != '\n') return false;
2199 if (s.ptr[i + n + 2] != '\r' || s.ptr[i + n + 3] != '\n') return false;
2205 static bool mg_is_chunked(struct mg_http_message *hm) {
2206 const char *needle = "chunked";
2207 struct mg_str *te = mg_http_get_header(hm, "Transfer-Encoding");
2208 return te != NULL && mg_vcasecmp(te, needle) == 0;
2211 void mg_http_delete_chunk(struct mg_connection *c, struct mg_http_message *hm) {
2212 size_t ofs = (size_t) (hm->chunk.ptr - (char *) c->recv.buf);
2213 mg_iobuf_del(&c->recv, ofs, hm->chunk.len);
2214 c->pfn_data = (void *) ((size_t) c->pfn_data | MG_DMARK);
2217 static void deliver_chunked_chunks(struct mg_connection *c, size_t hlen,
2218 struct mg_http_message *hm, bool *next) {
2219 // | ... headers ... | HEXNUM\r\n ..data.. \r\n | ......
2220 // +------------------+--------------------------+----
2221 // | hlen | chunk1 | ......
2222 char *buf = (char *) &c->recv.buf[hlen], *p = buf;
2223 size_t len = c->recv.len - hlen;
2224 size_t processed = ((size_t) c->pfn_data) & ~MG_DMARK;
2225 size_t mark, pl, dl, del = 0, ofs = 0;
2227 if (processed <= len) len -= processed, buf += processed;
2228 while (!last && getchunk(mg_str_n(buf + ofs, len - ofs), &pl, &dl)) {
2229 size_t saved = c->recv.len;
2230 memmove(p + processed, buf + ofs + pl, dl);
2231 // MG_INFO(("P2 [%.*s]", (int) (processed + dl), p));
2232 hm->chunk = mg_str_n(p + processed, dl);
2233 mg_call(c, MG_EV_HTTP_CHUNK, hm);
2234 ofs += pl + dl + 2, del += pl + 2; // 2 is for \r\n suffix
2236 if (c->recv.len != saved) processed -= dl, buf -= dl;
2237 // mg_hexdump(c->recv.buf, hlen + processed);
2240 mg_iobuf_del(&c->recv, hlen + processed, del);
2241 mark = ((size_t) c->pfn_data) & MG_DMARK;
2242 c->pfn_data = (void *) (processed | mark);
2244 hm->body.len = processed;
2245 hm->message.len = hlen + processed;
2247 if (mark) mg_iobuf_del(&c->recv, 0, hlen), *next = true;
2248 // MG_INFO(("LAST, mark: %lx", mark));
2249 // mg_hexdump(c->recv.buf, c->recv.len);
2253 static void deliver_normal_chunks(struct mg_connection *c, size_t hlen,
2254 struct mg_http_message *hm, bool *next) {
2255 size_t left, processed = ((size_t) c->pfn_data) & ~MG_DMARK;
2256 size_t deleted = ((size_t) c->pfn_data) & MG_DMARK;
2257 hm->chunk = mg_str_n((char *) &c->recv.buf[hlen], c->recv.len - hlen);
2258 if (processed <= hm->chunk.len && !deleted) {
2259 hm->chunk.len -= processed;
2260 hm->chunk.ptr += processed;
2262 left = hm->body.len < processed ? 0 : hm->body.len - processed;
2263 if (hm->chunk.len > left) hm->chunk.len = left;
2264 if (hm->chunk.len > 0) mg_call(c, MG_EV_HTTP_CHUNK, hm);
2265 processed += hm->chunk.len;
2266 deleted = ((size_t) c->pfn_data) & MG_DMARK; // Re-evaluate after user call
2267 if (processed >= hm->body.len) { // Last, 0-len chunk
2268 hm->chunk.len = 0; // Reset length
2269 mg_call(c, MG_EV_HTTP_CHUNK, hm); // Call user handler
2270 c->pfn_data = NULL; // Reset processed counter
2271 if (processed && deleted) mg_iobuf_del(&c->recv, 0, hlen), *next = true;
2273 c->pfn_data = (void *) (processed | deleted); // if it is set
2277 static void http_cb(struct mg_connection *c, int ev, void *evd, void *fnd) {
2278 if (ev == MG_EV_READ || ev == MG_EV_CLOSE) {
2279 struct mg_http_message hm;
2280 while (c->recv.buf != NULL && c->recv.len > 0) {
2282 int hlen = mg_http_parse((char *) c->recv.buf, c->recv.len, &hm);
2284 mg_error(c, "HTTP parse:\n%.*s", (int) c->recv.len, c->recv.buf);
2287 if (c->is_resp) break; // Response is still generated
2288 if (hlen == 0) break; // Request is not buffered yet
2289 if (ev == MG_EV_CLOSE) { // If client did not set Content-Length
2290 hm.message.len = c->recv.len; // and closes now, deliver a MSG
2291 hm.body.len = hm.message.len - (size_t) (hm.body.ptr - hm.message.ptr);
2293 if (mg_is_chunked(&hm)) {
2294 deliver_chunked_chunks(c, (size_t) hlen, &hm, &next);
2296 deliver_normal_chunks(c, (size_t) hlen, &hm, &next);
2298 if (next) continue; // Chunks & request were deleted
2299 // Chunk events are delivered. If we have full body, deliver MSG
2300 if (c->recv.len < hm.message.len) break;
2301 if (c->is_accepted) c->is_resp = 1; // Start generating response
2302 mg_call(c, MG_EV_HTTP_MSG, &hm); // User handler can clear is_resp
2303 mg_iobuf_del(&c->recv, 0, hm.message.len);
2306 (void) evd, (void) fnd;
2309 static void mg_hfn(struct mg_connection *c, int ev, void *ev_data, void *fnd) {
2310 if (ev == MG_EV_HTTP_MSG) {
2311 struct mg_http_message *hm = (struct mg_http_message *) ev_data;
2312 if (mg_http_match_uri(hm, "/quit")) {
2313 mg_http_reply(c, 200, "", "ok\n");
2316 } else if (mg_http_match_uri(hm, "/debug")) {
2317 int level = (int) mg_json_get_long(hm->body, "$.level", MG_LL_DEBUG);
2319 mg_http_reply(c, 200, "", "Debug level set to %d\n", level);
2321 mg_http_reply(c, 200, "", "hi\n");
2323 } else if (ev == MG_EV_CLOSE) {
2324 if (c->data[0] == 'X') *(bool *) fnd = true;
2328 void mg_hello(const char *url) {
2332 if (mg_http_listen(&mgr, url, mg_hfn, &done) == NULL) done = true;
2333 while (done == false) mg_mgr_poll(&mgr, 100);
2337 struct mg_connection *mg_http_connect(struct mg_mgr *mgr, const char *url,
2338 mg_event_handler_t fn, void *fn_data) {
2339 struct mg_connection *c = mg_connect(mgr, url, fn, fn_data);
2340 if (c != NULL) c->pfn = http_cb;
2344 struct mg_connection *mg_http_listen(struct mg_mgr *mgr, const char *url,
2345 mg_event_handler_t fn, void *fn_data) {
2346 struct mg_connection *c = mg_listen(mgr, url, fn, fn_data);
2347 if (c != NULL) c->pfn = http_cb;
2351 #ifdef MG_ENABLE_LINES
2352 #line 1 "src/iobuf.c"
2358 // Not using memset for zeroing memory, cause it can be dropped by compiler
2359 // See https://github.com/cesanta/mongoose/pull/1265
2360 static void zeromem(volatile unsigned char *buf, size_t len) {
2362 while (len--) *buf++ = 0;
2366 static size_t roundup(size_t size, size_t align) {
2367 return align == 0 ? size : (size + align - 1) / align * align;
2370 int mg_iobuf_resize(struct mg_iobuf *io, size_t new_size) {
2372 new_size = roundup(new_size, io->align);
2373 if (new_size == 0) {
2374 zeromem(io->buf, io->size);
2377 io->len = io->size = 0;
2378 } else if (new_size != io->size) {
2379 // NOTE(lsm): do not use realloc here. Use calloc/free only, to ease the
2380 // porting to some obscure platforms like FreeRTOS
2381 void *p = calloc(1, new_size);
2383 size_t len = new_size < io->len ? new_size : io->len;
2384 if (len > 0 && io->buf != NULL) memmove(p, io->buf, len);
2385 zeromem(io->buf, io->size);
2387 io->buf = (unsigned char *) p;
2388 io->size = new_size;
2391 MG_ERROR(("%lld->%lld", (uint64_t) io->size, (uint64_t) new_size));
2397 int mg_iobuf_init(struct mg_iobuf *io, size_t size, size_t align) {
2400 io->size = io->len = 0;
2401 return mg_iobuf_resize(io, size);
2404 size_t mg_iobuf_add(struct mg_iobuf *io, size_t ofs, const void *buf,
2406 size_t new_size = roundup(io->len + len, io->align);
2407 mg_iobuf_resize(io, new_size); // Attempt to resize
2408 if (new_size != io->size) len = 0; // Resize failure, append nothing
2409 if (ofs < io->len) memmove(io->buf + ofs + len, io->buf + ofs, io->len - ofs);
2410 if (buf != NULL) memmove(io->buf + ofs, buf, len);
2411 if (ofs > io->len) io->len += ofs - io->len;
2416 size_t mg_iobuf_del(struct mg_iobuf *io, size_t ofs, size_t len) {
2417 if (ofs > io->len) ofs = io->len;
2418 if (ofs + len > io->len) len = io->len - ofs;
2419 if (io->buf) memmove(io->buf + ofs, io->buf + ofs + len, io->len - ofs - len);
2420 if (io->buf) zeromem(io->buf + io->len - len, len);
2425 void mg_iobuf_free(struct mg_iobuf *io) {
2426 mg_iobuf_resize(io, 0);
2429 #ifdef MG_ENABLE_LINES
2430 #line 1 "src/json.c"
2436 static const char *escapeseq(int esc) {
2437 return esc ? "\b\f\n\r\t\\\"" : "bfnrt\\\"";
2440 static char json_esc(int c, int esc) {
2441 const char *p, *esc1 = escapeseq(esc), *esc2 = escapeseq(!esc);
2442 for (p = esc1; *p != '\0'; p++) {
2443 if (*p == c) return esc2[p - esc1];
2448 static int mg_pass_string(const char *s, int len) {
2450 for (i = 0; i < len; i++) {
2451 if (s[i] == '\\' && i + 1 < len && json_esc(s[i + 1], 1)) {
2453 } else if (s[i] == '\0') {
2454 return MG_JSON_INVALID;
2455 } else if (s[i] == '"') {
2459 return MG_JSON_INVALID;
2462 static double mg_atod(const char *p, int len, int *numlen) {
2464 int i = 0, sign = 1;
2467 if (i < len && *p == '-') {
2469 } else if (i < len && *p == '+') {
2474 for (; i < len && p[i] >= '0' && p[i] <= '9'; i++) {
2481 if (i < len && p[i] == '.') {
2482 double frac = 0.0, base = 0.1;
2484 for (; i < len && p[i] >= '0' && p[i] <= '9'; i++) {
2485 frac += base * (p[i] - '0');
2492 if (i < len && (p[i] == 'e' || p[i] == 'E')) {
2493 int j, exp = 0, minus = 0;
2495 if (i < len && p[i] == '-') minus = 1, i++;
2496 if (i < len && p[i] == '+') i++;
2497 while (i < len && p[i] >= '0' && p[i] <= '9' && exp < 308)
2498 exp = exp * 10 + (p[i++] - '0');
2499 if (minus) exp = -exp;
2500 for (j = 0; j < exp; j++) d *= 10.0;
2501 for (j = 0; j < -exp; j++) d /= 10.0;
2504 if (numlen != NULL) *numlen = i;
2508 int mg_json_get(struct mg_str json, const char *path, int *toklen) {
2509 const char *s = json.ptr;
2510 int len = (int) json.len;
2511 enum { S_VALUE, S_KEY, S_COLON, S_COMMA_OR_EOO } expecting = S_VALUE;
2512 unsigned char nesting[MG_JSON_MAX_DEPTH];
2513 int i = 0; // Current offset in `s`
2514 int j = 0; // Offset in `s` we're looking for (return value)
2515 int depth = 0; // Current depth (nesting level)
2516 int ed = 0; // Expected depth
2517 int pos = 1; // Current position in `path`
2518 int ci = -1, ei = -1; // Current and expected index in array
2520 if (toklen) *toklen = 0;
2521 if (path[0] != '$') return MG_JSON_INVALID;
2523 #define MG_CHECKRET(x) \
2525 if (depth == ed && path[pos] == '\0' && ci == ei) { \
2526 if (toklen) *toklen = i - j + 1; \
2531 // In the ascii table, the distance between `[` and `]` is 2.
2532 // Ditto for `{` and `}`. Hence +2 in the code below.
2535 if (depth == ed && ci != ei) return MG_JSON_NOT_FOUND; \
2536 if (c != nesting[depth - 1] + 2) return MG_JSON_INVALID; \
2541 for (i = 0; i < len; i++) {
2542 unsigned char c = ((unsigned char *) s)[i];
2543 if (c == ' ' || c == '\t' || c == '\n' || c == '\r') continue;
2544 switch (expecting) {
2546 // p("V %s [%.*s] %d %d %d %d\n", path, pos, path, depth, ed, ci, ei);
2547 if (depth == ed) j = i;
2549 if (depth >= (int) sizeof(nesting)) return MG_JSON_TOO_DEEP;
2550 if (depth == ed && path[pos] == '.' && ci == ei) {
2551 // If we start the object, reset array indices
2552 ed++, pos++, ci = ei = -1;
2554 nesting[depth++] = c;
2557 } else if (c == '[') {
2558 if (depth >= (int) sizeof(nesting)) return MG_JSON_TOO_DEEP;
2559 if (depth == ed && path[pos] == '[' && ei == ci) {
2560 ed++, pos++, ci = 0;
2561 for (ei = 0; path[pos] != ']' && path[pos] != '\0'; pos++) {
2563 ei += path[pos] - '0';
2565 if (path[pos] != 0) pos++;
2567 nesting[depth++] = c;
2569 } else if (c == ']' && depth > 0) { // Empty array
2571 } else if (c == 't' && i + 3 < len && memcmp(&s[i], "true", 4) == 0) {
2573 } else if (c == 'n' && i + 3 < len && memcmp(&s[i], "null", 4) == 0) {
2575 } else if (c == 'f' && i + 4 < len && memcmp(&s[i], "false", 5) == 0) {
2577 } else if (c == '-' || ((c >= '0' && c <= '9'))) {
2579 mg_atod(&s[i], len - i, &numlen);
2581 } else if (c == '"') {
2582 int n = mg_pass_string(&s[i + 1], len - i - 1);
2583 if (n < 0) return n;
2586 return MG_JSON_INVALID;
2589 if (depth == ed && ei >= 0) ci++;
2590 expecting = S_COMMA_OR_EOO;
2595 int n = mg_pass_string(&s[i + 1], len - i - 1);
2596 if (n < 0) return n;
2597 if (i + 1 + n >= len) return MG_JSON_NOT_FOUND;
2598 if (depth < ed) return MG_JSON_NOT_FOUND;
2599 if (depth == ed && path[pos - 1] != '.') return MG_JSON_NOT_FOUND;
2600 // printf("K %s [%.*s] [%.*s] %d %d %d %d %d\n", path, pos, path, n,
2601 // &s[i + 1], n, depth, ed, ci, ei);
2602 // NOTE(cpq): in the check sequence below is important.
2603 // strncmp() must go first: it fails fast if the remaining length of
2604 // the path is smaller than `n`.
2605 if (depth == ed && path[pos - 1] == '.' &&
2606 strncmp(&s[i + 1], &path[pos], (size_t) n) == 0 &&
2607 (path[pos + n] == '\0' || path[pos + n] == '.' ||
2608 path[pos + n] == '[')) {
2612 expecting = S_COLON;
2613 } else if (c == '}') { // Empty object
2615 expecting = S_COMMA_OR_EOO;
2616 if (depth == ed && ei >= 0) ci++;
2618 return MG_JSON_INVALID;
2624 expecting = S_VALUE;
2626 return MG_JSON_INVALID;
2630 case S_COMMA_OR_EOO:
2632 return MG_JSON_INVALID;
2633 } else if (c == ',') {
2634 expecting = (nesting[depth - 1] == '{') ? S_KEY : S_VALUE;
2635 } else if (c == ']' || c == '}') {
2636 if (depth == ed && c == '}' && path[pos - 1] == '.')
2637 return MG_JSON_NOT_FOUND;
2638 if (depth == ed && c == ']' && path[pos - 1] == ',')
2639 return MG_JSON_NOT_FOUND;
2641 if (depth == ed && ei >= 0) ci++;
2643 return MG_JSON_INVALID;
2648 return MG_JSON_NOT_FOUND;
2651 bool mg_json_get_num(struct mg_str json, const char *path, double *v) {
2652 int n, toklen, found = 0;
2653 if ((n = mg_json_get(json, path, &toklen)) >= 0 &&
2654 (json.ptr[n] == '-' || (json.ptr[n] >= '0' && json.ptr[n] <= '9'))) {
2655 if (v != NULL) *v = mg_atod(json.ptr + n, toklen, NULL);
2661 bool mg_json_get_bool(struct mg_str json, const char *path, bool *v) {
2662 int found = 0, off = mg_json_get(json, path, NULL);
2663 if (off >= 0 && (json.ptr[off] == 't' || json.ptr[off] == 'f')) {
2664 if (v != NULL) *v = json.ptr[off] == 't';
2670 bool mg_json_unescape(struct mg_str s, char *to, size_t n) {
2672 for (i = 0, j = 0; i < s.len && j < n; i++, j++) {
2673 if (s.ptr[i] == '\\' && i + 5 < s.len && s.ptr[i + 1] == 'u') {
2674 // \uXXXX escape. We could process a simple one-byte chars
2675 // \u00xx from the ASCII range. More complex chars would require
2676 // dragging in a UTF8 library, which is too much for us
2677 if (s.ptr[i + 2] != '0' || s.ptr[i + 3] != '0') return false; // Give up
2678 ((unsigned char *) to)[j] = (unsigned char) mg_unhexn(s.ptr + i + 4, 2);
2681 } else if (s.ptr[i] == '\\' && i + 1 < s.len) {
2682 char c = json_esc(s.ptr[i + 1], 0);
2683 if (c == 0) return false;
2690 if (j >= n) return false;
2691 if (n > 0) to[j] = '\0';
2695 char *mg_json_get_str(struct mg_str json, const char *path) {
2696 char *result = NULL;
2697 int len = 0, off = mg_json_get(json, path, &len);
2698 if (off >= 0 && len > 1 && json.ptr[off] == '"') {
2699 if ((result = (char *) calloc(1, (size_t) len)) != NULL &&
2700 !mg_json_unescape(mg_str_n(json.ptr + off + 1, (size_t) (len - 2)),
2701 result, (size_t) len)) {
2709 char *mg_json_get_b64(struct mg_str json, const char *path, int *slen) {
2710 char *result = NULL;
2711 int len = 0, off = mg_json_get(json, path, &len);
2712 if (off >= 0 && json.ptr[off] == '"' && len > 1 &&
2713 (result = (char *) calloc(1, (size_t) len)) != NULL) {
2714 int k = mg_base64_decode(json.ptr + off + 1, len - 2, result);
2715 if (slen != NULL) *slen = k;
2720 char *mg_json_get_hex(struct mg_str json, const char *path, int *slen) {
2721 char *result = NULL;
2722 int len = 0, off = mg_json_get(json, path, &len);
2723 if (off >= 0 && json.ptr[off] == '"' && len > 1 &&
2724 (result = (char *) calloc(1, (size_t) len / 2)) != NULL) {
2725 mg_unhex(json.ptr + off + 1, (size_t) (len - 2), (uint8_t *) result);
2726 result[len / 2 - 1] = '\0';
2727 if (slen != NULL) *slen = len / 2 - 1;
2732 long mg_json_get_long(struct mg_str json, const char *path, long dflt) {
2735 if (mg_json_get_num(json, path, &dv)) result = (long) dv;
2739 #ifdef MG_ENABLE_LINES
2747 static int s_level = MG_LL_INFO;
2748 static mg_pfn_t s_log_func = mg_pfn_stdout;
2749 static void *s_log_func_param = NULL;
2751 void mg_log_set_fn(mg_pfn_t fn, void *param) {
2753 s_log_func_param = param;
2756 static void logc(unsigned char c) {
2757 s_log_func((char) c, s_log_func_param);
2760 static void logs(const char *buf, size_t len) {
2762 for (i = 0; i < len; i++) logc(((unsigned char *) buf)[i]);
2765 void mg_log_set(int log_level) {
2766 MG_DEBUG(("Setting log level to %d", log_level));
2767 s_level = log_level;
2770 bool mg_log_prefix(int level, const char *file, int line, const char *fname) {
2771 if (level <= s_level) {
2772 const char *p = strrchr(file, '/');
2775 if (p == NULL) p = strrchr(file, '\\');
2776 n = mg_snprintf(buf, sizeof(buf), "%-6llx %d %s:%d:%s", mg_millis(), level,
2777 p == NULL ? file : p + 1, line, fname);
2778 if (n > sizeof(buf) - 2) n = sizeof(buf) - 2;
2779 while (n < sizeof(buf)) buf[n++] = ' ';
2787 void mg_log(const char *fmt, ...) {
2790 mg_vxprintf(s_log_func, s_log_func_param, fmt, &ap);
2795 static unsigned char nibble(unsigned c) {
2796 return (unsigned char) (c < 10 ? c + '0' : c + 'W');
2799 #define ISPRINT(x) ((x) >= ' ' && (x) <= '~')
2800 void mg_hexdump(const void *buf, size_t len) {
2801 const unsigned char *p = (const unsigned char *) buf;
2802 unsigned char ascii[16], alen = 0;
2804 for (i = 0; i < len; i++) {
2805 if ((i % 16) == 0) {
2806 // Print buffered ascii chars
2807 if (i > 0) logs(" ", 2), logs((char *) ascii, 16), logc('\n'), alen = 0;
2808 // Print hex address, then \t
2809 logc(nibble((i >> 12) & 15)), logc(nibble((i >> 8) & 15)),
2810 logc(nibble((i >> 4) & 15)), logc('0'), logs(" ", 3);
2812 logc(nibble(p[i] >> 4)), logc(nibble(p[i] & 15)); // Two nibbles, e.g. c5
2813 logc(' '); // Space after hex number
2814 ascii[alen++] = ISPRINT(p[i]) ? p[i] : '.'; // Add to the ascii buf
2816 while (alen < 16) logs(" ", 3), ascii[alen++] = ' ';
2817 logs(" ", 2), logs((char *) ascii, 16), logc('\n');
2820 #ifdef MG_ENABLE_LINES
2826 #if defined(MG_ENABLE_MD5) && MG_ENABLE_MD5
2828 static void mg_byte_reverse(unsigned char *buf, unsigned longs) {
2829 if (MG_BIG_ENDIAN) {
2831 uint32_t t = (uint32_t) ((unsigned) buf[3] << 8 | buf[2]) << 16 |
2832 ((unsigned) buf[1] << 8 | buf[0]);
2833 *(uint32_t *) buf = t;
2837 (void) buf, (void) longs; // Little endian. Do nothing
2841 #define F1(x, y, z) (z ^ (x & (y ^ z)))
2842 #define F2(x, y, z) F1(z, x, y)
2843 #define F3(x, y, z) (x ^ y ^ z)
2844 #define F4(x, y, z) (y ^ (x | ~z))
2846 #define MD5STEP(f, w, x, y, z, data, s) \
2847 (w += f(x, y, z) + data, w = w << s | w >> (32 - s), w += x)
2850 * Start MD5 accumulation. Set bit count to 0 and buffer to mysterious
2851 * initialization constants.
2853 void mg_md5_init(mg_md5_ctx *ctx) {
2854 ctx->buf[0] = 0x67452301;
2855 ctx->buf[1] = 0xefcdab89;
2856 ctx->buf[2] = 0x98badcfe;
2857 ctx->buf[3] = 0x10325476;
2863 static void mg_md5_transform(uint32_t buf[4], uint32_t const in[16]) {
2864 uint32_t a, b, c, d;
2871 MD5STEP(F1, a, b, c, d, in[0] + 0xd76aa478, 7);
2872 MD5STEP(F1, d, a, b, c, in[1] + 0xe8c7b756, 12);
2873 MD5STEP(F1, c, d, a, b, in[2] + 0x242070db, 17);
2874 MD5STEP(F1, b, c, d, a, in[3] + 0xc1bdceee, 22);
2875 MD5STEP(F1, a, b, c, d, in[4] + 0xf57c0faf, 7);
2876 MD5STEP(F1, d, a, b, c, in[5] + 0x4787c62a, 12);
2877 MD5STEP(F1, c, d, a, b, in[6] + 0xa8304613, 17);
2878 MD5STEP(F1, b, c, d, a, in[7] + 0xfd469501, 22);
2879 MD5STEP(F1, a, b, c, d, in[8] + 0x698098d8, 7);
2880 MD5STEP(F1, d, a, b, c, in[9] + 0x8b44f7af, 12);
2881 MD5STEP(F1, c, d, a, b, in[10] + 0xffff5bb1, 17);
2882 MD5STEP(F1, b, c, d, a, in[11] + 0x895cd7be, 22);
2883 MD5STEP(F1, a, b, c, d, in[12] + 0x6b901122, 7);
2884 MD5STEP(F1, d, a, b, c, in[13] + 0xfd987193, 12);
2885 MD5STEP(F1, c, d, a, b, in[14] + 0xa679438e, 17);
2886 MD5STEP(F1, b, c, d, a, in[15] + 0x49b40821, 22);
2888 MD5STEP(F2, a, b, c, d, in[1] + 0xf61e2562, 5);
2889 MD5STEP(F2, d, a, b, c, in[6] + 0xc040b340, 9);
2890 MD5STEP(F2, c, d, a, b, in[11] + 0x265e5a51, 14);
2891 MD5STEP(F2, b, c, d, a, in[0] + 0xe9b6c7aa, 20);
2892 MD5STEP(F2, a, b, c, d, in[5] + 0xd62f105d, 5);
2893 MD5STEP(F2, d, a, b, c, in[10] + 0x02441453, 9);
2894 MD5STEP(F2, c, d, a, b, in[15] + 0xd8a1e681, 14);
2895 MD5STEP(F2, b, c, d, a, in[4] + 0xe7d3fbc8, 20);
2896 MD5STEP(F2, a, b, c, d, in[9] + 0x21e1cde6, 5);
2897 MD5STEP(F2, d, a, b, c, in[14] + 0xc33707d6, 9);
2898 MD5STEP(F2, c, d, a, b, in[3] + 0xf4d50d87, 14);
2899 MD5STEP(F2, b, c, d, a, in[8] + 0x455a14ed, 20);
2900 MD5STEP(F2, a, b, c, d, in[13] + 0xa9e3e905, 5);
2901 MD5STEP(F2, d, a, b, c, in[2] + 0xfcefa3f8, 9);
2902 MD5STEP(F2, c, d, a, b, in[7] + 0x676f02d9, 14);
2903 MD5STEP(F2, b, c, d, a, in[12] + 0x8d2a4c8a, 20);
2905 MD5STEP(F3, a, b, c, d, in[5] + 0xfffa3942, 4);
2906 MD5STEP(F3, d, a, b, c, in[8] + 0x8771f681, 11);
2907 MD5STEP(F3, c, d, a, b, in[11] + 0x6d9d6122, 16);
2908 MD5STEP(F3, b, c, d, a, in[14] + 0xfde5380c, 23);
2909 MD5STEP(F3, a, b, c, d, in[1] + 0xa4beea44, 4);
2910 MD5STEP(F3, d, a, b, c, in[4] + 0x4bdecfa9, 11);
2911 MD5STEP(F3, c, d, a, b, in[7] + 0xf6bb4b60, 16);
2912 MD5STEP(F3, b, c, d, a, in[10] + 0xbebfbc70, 23);
2913 MD5STEP(F3, a, b, c, d, in[13] + 0x289b7ec6, 4);
2914 MD5STEP(F3, d, a, b, c, in[0] + 0xeaa127fa, 11);
2915 MD5STEP(F3, c, d, a, b, in[3] + 0xd4ef3085, 16);
2916 MD5STEP(F3, b, c, d, a, in[6] + 0x04881d05, 23);
2917 MD5STEP(F3, a, b, c, d, in[9] + 0xd9d4d039, 4);
2918 MD5STEP(F3, d, a, b, c, in[12] + 0xe6db99e5, 11);
2919 MD5STEP(F3, c, d, a, b, in[15] + 0x1fa27cf8, 16);
2920 MD5STEP(F3, b, c, d, a, in[2] + 0xc4ac5665, 23);
2922 MD5STEP(F4, a, b, c, d, in[0] + 0xf4292244, 6);
2923 MD5STEP(F4, d, a, b, c, in[7] + 0x432aff97, 10);
2924 MD5STEP(F4, c, d, a, b, in[14] + 0xab9423a7, 15);
2925 MD5STEP(F4, b, c, d, a, in[5] + 0xfc93a039, 21);
2926 MD5STEP(F4, a, b, c, d, in[12] + 0x655b59c3, 6);
2927 MD5STEP(F4, d, a, b, c, in[3] + 0x8f0ccc92, 10);
2928 MD5STEP(F4, c, d, a, b, in[10] + 0xffeff47d, 15);
2929 MD5STEP(F4, b, c, d, a, in[1] + 0x85845dd1, 21);
2930 MD5STEP(F4, a, b, c, d, in[8] + 0x6fa87e4f, 6);
2931 MD5STEP(F4, d, a, b, c, in[15] + 0xfe2ce6e0, 10);
2932 MD5STEP(F4, c, d, a, b, in[6] + 0xa3014314, 15);
2933 MD5STEP(F4, b, c, d, a, in[13] + 0x4e0811a1, 21);
2934 MD5STEP(F4, a, b, c, d, in[4] + 0xf7537e82, 6);
2935 MD5STEP(F4, d, a, b, c, in[11] + 0xbd3af235, 10);
2936 MD5STEP(F4, c, d, a, b, in[2] + 0x2ad7d2bb, 15);
2937 MD5STEP(F4, b, c, d, a, in[9] + 0xeb86d391, 21);
2945 void mg_md5_update(mg_md5_ctx *ctx, const unsigned char *buf, size_t len) {
2949 if ((ctx->bits[0] = t + ((uint32_t) len << 3)) < t) ctx->bits[1]++;
2950 ctx->bits[1] += (uint32_t) len >> 29;
2952 t = (t >> 3) & 0x3f;
2955 unsigned char *p = (unsigned char *) ctx->in + t;
2959 memcpy(p, buf, len);
2963 mg_byte_reverse(ctx->in, 16);
2964 mg_md5_transform(ctx->buf, (uint32_t *) ctx->in);
2970 memcpy(ctx->in, buf, 64);
2971 mg_byte_reverse(ctx->in, 16);
2972 mg_md5_transform(ctx->buf, (uint32_t *) ctx->in);
2977 memcpy(ctx->in, buf, len);
2980 void mg_md5_final(mg_md5_ctx *ctx, unsigned char digest[16]) {
2985 count = (ctx->bits[0] >> 3) & 0x3F;
2987 p = ctx->in + count;
2989 count = 64 - 1 - count;
2991 memset(p, 0, count);
2992 mg_byte_reverse(ctx->in, 16);
2993 mg_md5_transform(ctx->buf, (uint32_t *) ctx->in);
2994 memset(ctx->in, 0, 56);
2996 memset(p, 0, count - 8);
2998 mg_byte_reverse(ctx->in, 14);
3000 a = (uint32_t *) ctx->in;
3001 a[14] = ctx->bits[0];
3002 a[15] = ctx->bits[1];
3004 mg_md5_transform(ctx->buf, (uint32_t *) ctx->in);
3005 mg_byte_reverse((unsigned char *) ctx->buf, 4);
3006 memcpy(digest, ctx->buf, 16);
3007 memset((char *) ctx, 0, sizeof(*ctx));
3011 #ifdef MG_ENABLE_LINES
3012 #line 1 "src/mqtt.c"
3022 #define MQTT_CLEAN_SESSION 0x02
3023 #define MQTT_HAS_WILL 0x04
3024 #define MQTT_WILL_RETAIN 0x20
3025 #define MQTT_HAS_PASSWORD 0x40
3026 #define MQTT_HAS_USER_NAME 0x80
3028 struct mg_mqtt_pmap {
3033 static const struct mg_mqtt_pmap s_prop_map[] = {
3034 {MQTT_PROP_PAYLOAD_FORMAT_INDICATOR, MQTT_PROP_TYPE_BYTE},
3035 {MQTT_PROP_MESSAGE_EXPIRY_INTERVAL, MQTT_PROP_TYPE_INT},
3036 {MQTT_PROP_CONTENT_TYPE, MQTT_PROP_TYPE_STRING},
3037 {MQTT_PROP_RESPONSE_TOPIC, MQTT_PROP_TYPE_STRING},
3038 {MQTT_PROP_CORRELATION_DATA, MQTT_PROP_TYPE_BINARY_DATA},
3039 {MQTT_PROP_SUBSCRIPTION_IDENTIFIER, MQTT_PROP_TYPE_VARIABLE_INT},
3040 {MQTT_PROP_SESSION_EXPIRY_INTERVAL, MQTT_PROP_TYPE_INT},
3041 {MQTT_PROP_ASSIGNED_CLIENT_IDENTIFIER, MQTT_PROP_TYPE_STRING},
3042 {MQTT_PROP_SERVER_KEEP_ALIVE, MQTT_PROP_TYPE_SHORT},
3043 {MQTT_PROP_AUTHENTICATION_METHOD, MQTT_PROP_TYPE_STRING},
3044 {MQTT_PROP_AUTHENTICATION_DATA, MQTT_PROP_TYPE_BINARY_DATA},
3045 {MQTT_PROP_REQUEST_PROBLEM_INFORMATION, MQTT_PROP_TYPE_BYTE},
3046 {MQTT_PROP_WILL_DELAY_INTERVAL, MQTT_PROP_TYPE_INT},
3047 {MQTT_PROP_REQUEST_RESPONSE_INFORMATION, MQTT_PROP_TYPE_BYTE},
3048 {MQTT_PROP_RESPONSE_INFORMATION, MQTT_PROP_TYPE_STRING},
3049 {MQTT_PROP_SERVER_REFERENCE, MQTT_PROP_TYPE_STRING},
3050 {MQTT_PROP_REASON_STRING, MQTT_PROP_TYPE_STRING},
3051 {MQTT_PROP_RECEIVE_MAXIMUM, MQTT_PROP_TYPE_SHORT},
3052 {MQTT_PROP_TOPIC_ALIAS_MAXIMUM, MQTT_PROP_TYPE_SHORT},
3053 {MQTT_PROP_TOPIC_ALIAS, MQTT_PROP_TYPE_SHORT},
3054 {MQTT_PROP_MAXIMUM_QOS, MQTT_PROP_TYPE_BYTE},
3055 {MQTT_PROP_RETAIN_AVAILABLE, MQTT_PROP_TYPE_BYTE},
3056 {MQTT_PROP_USER_PROPERTY, MQTT_PROP_TYPE_STRING_PAIR},
3057 {MQTT_PROP_MAXIMUM_PACKET_SIZE, MQTT_PROP_TYPE_INT},
3058 {MQTT_PROP_WILDCARD_SUBSCRIPTION_AVAILABLE, MQTT_PROP_TYPE_BYTE},
3059 {MQTT_PROP_SUBSCRIPTION_IDENTIFIER_AVAILABLE, MQTT_PROP_TYPE_BYTE},
3060 {MQTT_PROP_SHARED_SUBSCRIPTION_AVAILABLE, MQTT_PROP_TYPE_BYTE}};
3062 void mg_mqtt_send_header(struct mg_connection *c, uint8_t cmd, uint8_t flags,
3064 uint8_t buf[1 + sizeof(len)], *vlen = &buf[1];
3065 buf[0] = (uint8_t) ((cmd << 4) | flags);
3069 if (len > 0) *vlen |= 0x80;
3071 } while (len > 0 && vlen < &buf[sizeof(buf)]);
3072 mg_send(c, buf, (size_t) (vlen - buf));
3075 static void mg_send_u16(struct mg_connection *c, uint16_t value) {
3076 mg_send(c, &value, sizeof(value));
3079 static void mg_send_u32(struct mg_connection *c, uint32_t value) {
3080 mg_send(c, &value, sizeof(value));
3083 static uint8_t varint_size(size_t length) {
3084 uint8_t bytes_needed = 0;
3088 } while (length > 0);
3089 return bytes_needed;
3092 static size_t encode_varint(uint8_t *buf, size_t value) {
3096 uint8_t byte = (uint8_t) (value % 128);
3098 if (value > 0) byte |= 0x80;
3100 } while (value > 0);
3105 static size_t decode_varint(const uint8_t *buf, size_t len, size_t *value) {
3106 size_t multiplier = 1, offset;
3109 for (offset = 0; offset < 4 && offset < len; offset++) {
3110 uint8_t encoded_byte = buf[offset];
3111 *value += (encoded_byte & 0x7f) * multiplier;
3114 if ((encoded_byte & 0x80) == 0) return offset + 1;
3120 static int mqtt_prop_type_by_id(uint8_t prop_id) {
3121 size_t i, num_properties = sizeof(s_prop_map) / sizeof(s_prop_map[0]);
3122 for (i = 0; i < num_properties; ++i) {
3123 if (s_prop_map[i].id == prop_id) return s_prop_map[i].type;
3125 return -1; // Property ID not found
3128 // Returns the size of the properties section, without the
3129 // size of the content's length
3130 static size_t get_properties_length(struct mg_mqtt_prop *props, size_t count) {
3132 for (i = 0; i < count; i++) {
3133 size++; // identifier
3134 switch (mqtt_prop_type_by_id(props[i].id)) {
3135 case MQTT_PROP_TYPE_STRING_PAIR:
3136 size += (uint32_t) (props[i].val.len + props[i].key.len +
3137 2 * sizeof(uint16_t));
3139 case MQTT_PROP_TYPE_STRING:
3140 size += (uint32_t) (props[i].val.len + sizeof(uint16_t));
3142 case MQTT_PROP_TYPE_BINARY_DATA:
3143 size += (uint32_t) (props[i].val.len + sizeof(uint16_t));
3145 case MQTT_PROP_TYPE_VARIABLE_INT:
3146 size += varint_size((uint32_t) props[i].iv);
3148 case MQTT_PROP_TYPE_INT:
3149 size += (uint32_t) sizeof(uint32_t);
3151 case MQTT_PROP_TYPE_SHORT:
3152 size += (uint32_t) sizeof(uint16_t);
3154 case MQTT_PROP_TYPE_BYTE:
3155 size += (uint32_t) sizeof(uint8_t);
3158 return size; // cannot parse further down
3165 // returns the entire size of the properties section, including the
3166 // size of the variable length of the content
3167 static size_t get_props_size(struct mg_mqtt_prop *props, size_t count) {
3168 size_t size = get_properties_length(props, count);
3169 size += varint_size(size);
3173 static void mg_send_mqtt_properties(struct mg_connection *c,
3174 struct mg_mqtt_prop *props, size_t nprops) {
3175 size_t total_size = get_properties_length(props, nprops);
3176 uint8_t buf_v[4] = {0, 0, 0, 0};
3177 uint8_t buf[4] = {0, 0, 0, 0};
3178 size_t i, len = encode_varint(buf, total_size);
3180 mg_send(c, buf, (size_t) len);
3181 for (i = 0; i < nprops; i++) {
3182 mg_send(c, &props[i].id, sizeof(props[i].id));
3183 switch (mqtt_prop_type_by_id(props[i].id)) {
3184 case MQTT_PROP_TYPE_STRING_PAIR:
3185 mg_send_u16(c, mg_htons((uint16_t) props[i].key.len));
3186 mg_send(c, props[i].key.ptr, props[i].key.len);
3187 mg_send_u16(c, mg_htons((uint16_t) props[i].val.len));
3188 mg_send(c, props[i].val.ptr, props[i].val.len);
3190 case MQTT_PROP_TYPE_BYTE:
3191 mg_send(c, &props[i].iv, sizeof(uint8_t));
3193 case MQTT_PROP_TYPE_SHORT:
3194 mg_send_u16(c, mg_htons((uint16_t) props[i].iv));
3196 case MQTT_PROP_TYPE_INT:
3197 mg_send_u32(c, mg_htonl((uint32_t) props[i].iv));
3199 case MQTT_PROP_TYPE_STRING:
3200 mg_send_u16(c, mg_htons((uint16_t) props[i].val.len));
3201 mg_send(c, props[i].val.ptr, props[i].val.len);
3203 case MQTT_PROP_TYPE_BINARY_DATA:
3204 mg_send_u16(c, mg_htons((uint16_t) props[i].val.len));
3205 mg_send(c, props[i].val.ptr, props[i].val.len);
3207 case MQTT_PROP_TYPE_VARIABLE_INT:
3208 len = encode_varint(buf_v, props[i].iv);
3209 mg_send(c, buf_v, (size_t) len);
3215 size_t mg_mqtt_next_prop(struct mg_mqtt_message *msg, struct mg_mqtt_prop *prop,
3217 uint8_t *i = (uint8_t *) msg->dgram.ptr + msg->props_start + ofs;
3218 uint8_t *end = (uint8_t *) msg->dgram.ptr + msg->dgram.len;
3219 size_t new_pos = ofs, len;
3222 if (ofs >= msg->dgram.len || ofs >= msg->props_start + msg->props_size)
3226 switch (mqtt_prop_type_by_id(prop->id)) {
3227 case MQTT_PROP_TYPE_STRING_PAIR:
3228 prop->key.len = (uint16_t) ((((uint16_t) i[0]) << 8) | i[1]);
3229 prop->key.ptr = (char *) i + 2;
3230 i += 2 + prop->key.len;
3231 prop->val.len = (uint16_t) ((((uint16_t) i[0]) << 8) | i[1]);
3232 prop->val.ptr = (char *) i + 2;
3233 new_pos += 2 * sizeof(uint16_t) + prop->val.len + prop->key.len;
3235 case MQTT_PROP_TYPE_BYTE:
3236 prop->iv = (uint8_t) i[0];
3239 case MQTT_PROP_TYPE_SHORT:
3240 prop->iv = (uint16_t) ((((uint16_t) i[0]) << 8) | i[1]);
3241 new_pos += sizeof(uint16_t);
3243 case MQTT_PROP_TYPE_INT:
3244 prop->iv = ((uint32_t) i[0] << 24) | ((uint32_t) i[1] << 16) |
3245 ((uint32_t) i[2] << 8) | i[3];
3246 new_pos += sizeof(uint32_t);
3248 case MQTT_PROP_TYPE_STRING:
3249 prop->val.len = (uint16_t) ((((uint16_t) i[0]) << 8) | i[1]);
3250 prop->val.ptr = (char *) i + 2;
3251 new_pos += 2 + prop->val.len;
3253 case MQTT_PROP_TYPE_BINARY_DATA:
3254 prop->val.len = (uint16_t) ((((uint16_t) i[0]) << 8) | i[1]);
3255 prop->val.ptr = (char *) i + 2;
3256 new_pos += 2 + prop->val.len;
3258 case MQTT_PROP_TYPE_VARIABLE_INT:
3259 len = decode_varint(i, (size_t) (end - i), (size_t *) &prop->iv);
3260 new_pos = (!len) ? 0 : new_pos + len;
3269 void mg_mqtt_login(struct mg_connection *c, const struct mg_mqtt_opts *opts) {
3270 char rnd[10], client_id[21];
3271 struct mg_str cid = opts->client_id;
3272 size_t total_len = 7 + 1 + 2 + 2;
3273 uint8_t hdr[8] = {0, 4, 'M', 'Q', 'T', 'T', opts->version, 0};
3276 mg_random(rnd, sizeof(rnd));
3277 mg_hex(rnd, sizeof(rnd), client_id);
3278 client_id[sizeof(client_id) - 1] = '\0';
3279 cid = mg_str(client_id);
3282 if (hdr[6] == 0) hdr[6] = 4; // If version is not set, use 4 (3.1.1)
3283 c->is_mqtt5 = hdr[6] == 5; // Set version 5 flag
3284 hdr[7] = (uint8_t) ((opts->qos & 3) << 3); // Connection flags
3285 if (opts->user.len > 0) {
3286 total_len += 2 + (uint32_t) opts->user.len;
3287 hdr[7] |= MQTT_HAS_USER_NAME;
3289 if (opts->pass.len > 0) {
3290 total_len += 2 + (uint32_t) opts->pass.len;
3291 hdr[7] |= MQTT_HAS_PASSWORD;
3293 if (opts->topic.len > 0 && opts->message.len > 0) {
3294 total_len += 4 + (uint32_t) opts->topic.len + (uint32_t) opts->message.len;
3295 hdr[7] |= MQTT_HAS_WILL;
3297 if (opts->clean || cid.len == 0) hdr[7] |= MQTT_CLEAN_SESSION;
3298 if (opts->retain) hdr[7] |= MQTT_WILL_RETAIN;
3299 total_len += (uint32_t) cid.len;
3301 total_len += get_props_size(opts->props, opts->num_props);
3302 if (hdr[7] & MQTT_HAS_WILL)
3303 total_len += get_props_size(opts->will_props, opts->num_will_props);
3306 mg_mqtt_send_header(c, MQTT_CMD_CONNECT, 0, (uint32_t) total_len);
3307 mg_send(c, hdr, sizeof(hdr));
3308 // keepalive == 0 means "do not disconnect us!"
3309 mg_send_u16(c, mg_htons((uint16_t) opts->keepalive));
3311 if (c->is_mqtt5) mg_send_mqtt_properties(c, opts->props, opts->num_props);
3313 mg_send_u16(c, mg_htons((uint16_t) cid.len));
3314 mg_send(c, cid.ptr, cid.len);
3316 if (hdr[7] & MQTT_HAS_WILL) {
3318 mg_send_mqtt_properties(c, opts->will_props, opts->num_will_props);
3320 mg_send_u16(c, mg_htons((uint16_t) opts->topic.len));
3321 mg_send(c, opts->topic.ptr, opts->topic.len);
3322 mg_send_u16(c, mg_htons((uint16_t) opts->message.len));
3323 mg_send(c, opts->message.ptr, opts->message.len);
3325 if (opts->user.len > 0) {
3326 mg_send_u16(c, mg_htons((uint16_t) opts->user.len));
3327 mg_send(c, opts->user.ptr, opts->user.len);
3329 if (opts->pass.len > 0) {
3330 mg_send_u16(c, mg_htons((uint16_t) opts->pass.len));
3331 mg_send(c, opts->pass.ptr, opts->pass.len);
3335 void mg_mqtt_pub(struct mg_connection *c, const struct mg_mqtt_opts *opts) {
3336 uint8_t flags = (uint8_t) (((opts->qos & 3) << 1) | (opts->retain ? 1 : 0));
3337 size_t len = 2 + opts->topic.len + opts->message.len;
3338 MG_DEBUG(("%lu [%.*s] -> [%.*s]", c->id, (int) opts->topic.len,
3339 (char *) opts->topic.ptr, (int) opts->message.len,
3340 (char *) opts->message.ptr));
3341 if (opts->qos > 0) len += 2;
3342 if (c->is_mqtt5) len += get_props_size(opts->props, opts->num_props);
3344 mg_mqtt_send_header(c, MQTT_CMD_PUBLISH, flags, (uint32_t) len);
3345 mg_send_u16(c, mg_htons((uint16_t) opts->topic.len));
3346 mg_send(c, opts->topic.ptr, opts->topic.len);
3347 if (opts->qos > 0) {
3348 if (++c->mgr->mqtt_id == 0) ++c->mgr->mqtt_id;
3349 mg_send_u16(c, mg_htons(c->mgr->mqtt_id));
3352 if (c->is_mqtt5) mg_send_mqtt_properties(c, opts->props, opts->num_props);
3354 mg_send(c, opts->message.ptr, opts->message.len);
3357 void mg_mqtt_sub(struct mg_connection *c, const struct mg_mqtt_opts *opts) {
3358 uint8_t qos_ = opts->qos & 3;
3359 size_t plen = c->is_mqtt5 ? get_props_size(opts->props, opts->num_props) : 0;
3360 size_t len = 2 + opts->topic.len + 2 + 1 + plen;
3362 mg_mqtt_send_header(c, MQTT_CMD_SUBSCRIBE, 2, (uint32_t) len);
3363 if (++c->mgr->mqtt_id == 0) ++c->mgr->mqtt_id;
3364 mg_send_u16(c, mg_htons(c->mgr->mqtt_id));
3365 if (c->is_mqtt5) mg_send_mqtt_properties(c, opts->props, opts->num_props);
3367 mg_send_u16(c, mg_htons((uint16_t) opts->topic.len));
3368 mg_send(c, opts->topic.ptr, opts->topic.len);
3369 mg_send(c, &qos_, sizeof(qos_));
3372 int mg_mqtt_parse(const uint8_t *buf, size_t len, uint8_t version,
3373 struct mg_mqtt_message *m) {
3374 uint8_t lc = 0, *p, *end;
3375 uint32_t n = 0, len_len = 0;
3377 memset(m, 0, sizeof(*m));
3378 m->dgram.ptr = (char *) buf;
3379 if (len < 2) return MQTT_INCOMPLETE;
3380 m->cmd = (uint8_t) (buf[0] >> 4);
3381 m->qos = (buf[0] >> 1) & 3;
3384 p = (uint8_t *) buf + 1;
3385 while ((size_t) (p - buf) < len) {
3386 lc = *((uint8_t *) p++);
3387 n += (uint32_t) ((lc & 0x7f) << 7 * len_len);
3389 if (!(lc & 0x80)) break;
3390 if (len_len >= 4) return MQTT_MALFORMED;
3393 if ((lc & 0x80) || (end > buf + len)) return MQTT_INCOMPLETE;
3394 m->dgram.len = (size_t) (end - buf);
3397 case MQTT_CMD_CONNACK:
3398 if (end - p < 2) return MQTT_MALFORMED;
3401 case MQTT_CMD_PUBACK:
3402 case MQTT_CMD_PUBREC:
3403 case MQTT_CMD_PUBREL:
3404 case MQTT_CMD_PUBCOMP:
3405 case MQTT_CMD_SUBSCRIBE:
3406 case MQTT_CMD_SUBACK:
3407 case MQTT_CMD_UNSUBSCRIBE:
3408 case MQTT_CMD_UNSUBACK:
3409 if (p + 2 > end) return MQTT_MALFORMED;
3410 m->id = (uint16_t) ((((uint16_t) p[0]) << 8) | p[1]);
3413 case MQTT_CMD_PUBLISH: {
3414 if (p + 2 > end) return MQTT_MALFORMED;
3415 m->topic.len = (uint16_t) ((((uint16_t) p[0]) << 8) | p[1]);
3416 m->topic.ptr = (char *) p + 2;
3417 p += 2 + m->topic.len;
3418 if (p > end) return MQTT_MALFORMED;
3420 if (p + 2 > end) return MQTT_MALFORMED;
3421 m->id = (uint16_t) ((((uint16_t) p[0]) << 8) | p[1]);
3424 if (p > end) return MQTT_MALFORMED;
3425 if (version == 5 && p + 2 < end) {
3426 len_len = (uint32_t) decode_varint(p, (size_t) (end - p), &m->props_size);
3427 if (!len_len) return MQTT_MALFORMED;
3428 m->props_start = (size_t) (p + len_len - buf);
3429 p += len_len + m->props_size;
3431 if (p > end) return MQTT_MALFORMED;
3432 m->data.ptr = (char *) p;
3433 m->data.len = (size_t) (end - p);
3442 static void mqtt_cb(struct mg_connection *c, int ev, void *ev_data,
3444 if (ev == MG_EV_READ) {
3446 uint8_t version = c->is_mqtt5 ? 5 : 4;
3447 struct mg_mqtt_message mm;
3448 int rc = mg_mqtt_parse(c->recv.buf, c->recv.len, version, &mm);
3449 if (rc == MQTT_MALFORMED) {
3450 MG_ERROR(("%lu MQTT malformed message", c->id));
3453 } else if (rc == MQTT_OK) {
3454 MG_VERBOSE(("%lu MQTT CMD %d len %d [%.*s]", c->id, mm.cmd,
3455 (int) mm.dgram.len, (int) mm.data.len, mm.data.ptr));
3457 case MQTT_CMD_CONNACK:
3458 mg_call(c, MG_EV_MQTT_OPEN, &mm.ack);
3460 MG_DEBUG(("%lu Connected", c->id));
3462 MG_ERROR(("%lu MQTT auth failed, code %d", c->id, mm.ack));
3466 case MQTT_CMD_PUBLISH: {
3467 MG_DEBUG(("%lu [%.*s] -> [%.*s]", c->id, (int) mm.topic.len,
3468 mm.topic.ptr, (int) mm.data.len, mm.data.ptr));
3470 uint16_t id = mg_ntohs(mm.id);
3471 uint32_t remaining_len = sizeof(id);
3472 if (c->is_mqtt5) remaining_len += 2; // 3.4.2
3474 mg_mqtt_send_header(
3476 (uint8_t) (mm.qos == 2 ? MQTT_CMD_PUBREC : MQTT_CMD_PUBACK),
3478 mg_send(c, &id, sizeof(id));
3482 mg_send(c, &zero, sizeof(zero));
3485 mg_call(c, MG_EV_MQTT_MSG, &mm); // let the app handle qos stuff
3488 case MQTT_CMD_PUBREC: { // MQTT5: 3.5.2-1 TODO(): variable header rc
3489 uint16_t id = mg_ntohs(mm.id);
3490 uint32_t remaining_len = sizeof(id); // MQTT5 3.6.2-1
3491 mg_mqtt_send_header(c, MQTT_CMD_PUBREL, 2, remaining_len);
3492 mg_send(c, &id, sizeof(id)); // MQTT5 3.6.1-1, flags = 2
3495 case MQTT_CMD_PUBREL: { // MQTT5: 3.6.2-1 TODO(): variable header rc
3496 uint16_t id = mg_ntohs(mm.id);
3497 uint32_t remaining_len = sizeof(id); // MQTT5 3.7.2-1
3498 mg_mqtt_send_header(c, MQTT_CMD_PUBCOMP, 0, remaining_len);
3499 mg_send(c, &id, sizeof(id));
3503 mg_call(c, MG_EV_MQTT_CMD, &mm);
3504 mg_iobuf_del(&c->recv, 0, mm.dgram.len);
3514 void mg_mqtt_ping(struct mg_connection *nc) {
3515 mg_mqtt_send_header(nc, MQTT_CMD_PINGREQ, 0, 0);
3518 void mg_mqtt_pong(struct mg_connection *nc) {
3519 mg_mqtt_send_header(nc, MQTT_CMD_PINGRESP, 0, 0);
3522 void mg_mqtt_disconnect(struct mg_connection *c,
3523 const struct mg_mqtt_opts *opts) {
3525 if (c->is_mqtt5) len = 1 + get_props_size(opts->props, opts->num_props);
3526 mg_mqtt_send_header(c, MQTT_CMD_DISCONNECT, 0, (uint32_t) len);
3530 mg_send(c, &zero, sizeof(zero)); // reason code
3531 mg_send_mqtt_properties(c, opts->props, opts->num_props);
3535 struct mg_connection *mg_mqtt_connect(struct mg_mgr *mgr, const char *url,
3536 const struct mg_mqtt_opts *opts,
3537 mg_event_handler_t fn, void *fn_data) {
3538 struct mg_connection *c = mg_connect(mgr, url, fn, fn_data);
3540 struct mg_mqtt_opts empty;
3541 memset(&empty, 0, sizeof(empty));
3542 mg_mqtt_login(c, opts == NULL ? &empty : opts);
3548 struct mg_connection *mg_mqtt_listen(struct mg_mgr *mgr, const char *url,
3549 mg_event_handler_t fn, void *fn_data) {
3550 struct mg_connection *c = mg_listen(mgr, url, fn, fn_data);
3551 if (c != NULL) c->pfn = mqtt_cb, c->pfn_data = mgr;
3555 #ifdef MG_ENABLE_LINES
3566 size_t mg_vprintf(struct mg_connection *c, const char *fmt, va_list *ap) {
3567 size_t old = c->send.len;
3568 mg_vxprintf(mg_pfn_iobuf, &c->send, fmt, ap);
3569 return c->send.len - old;
3572 size_t mg_printf(struct mg_connection *c, const char *fmt, ...) {
3576 len = mg_vprintf(c, fmt, &ap);
3581 static bool mg_atonl(struct mg_str str, struct mg_addr *addr) {
3582 uint32_t localhost = mg_htonl(0x7f000001);
3583 if (mg_vcasecmp(&str, "localhost") != 0) return false;
3584 memcpy(addr->ip, &localhost, sizeof(uint32_t));
3585 addr->is_ip6 = false;
3589 static bool mg_atone(struct mg_str str, struct mg_addr *addr) {
3590 if (str.len > 0) return false;
3591 memset(addr->ip, 0, sizeof(addr->ip));
3592 addr->is_ip6 = false;
3596 static bool mg_aton4(struct mg_str str, struct mg_addr *addr) {
3597 uint8_t data[4] = {0, 0, 0, 0};
3598 size_t i, num_dots = 0;
3599 for (i = 0; i < str.len; i++) {
3600 if (str.ptr[i] >= '0' && str.ptr[i] <= '9') {
3601 int octet = data[num_dots] * 10 + (str.ptr[i] - '0');
3602 if (octet > 255) return false;
3603 data[num_dots] = (uint8_t) octet;
3604 } else if (str.ptr[i] == '.') {
3605 if (num_dots >= 3 || i == 0 || str.ptr[i - 1] == '.') return false;
3611 if (num_dots != 3 || str.ptr[i - 1] == '.') return false;
3612 memcpy(&addr->ip, data, sizeof(data));
3613 addr->is_ip6 = false;
3617 static bool mg_v4mapped(struct mg_str str, struct mg_addr *addr) {
3620 if (str.len < 14) return false;
3621 if (str.ptr[0] != ':' || str.ptr[1] != ':' || str.ptr[6] != ':') return false;
3622 for (i = 2; i < 6; i++) {
3623 if (str.ptr[i] != 'f' && str.ptr[i] != 'F') return false;
3625 // struct mg_str s = mg_str_n(&str.ptr[7], str.len - 7);
3626 if (!mg_aton4(mg_str_n(&str.ptr[7], str.len - 7), addr)) return false;
3627 memcpy(&ipv4, addr->ip, sizeof(ipv4));
3628 memset(addr->ip, 0, sizeof(addr->ip));
3629 addr->ip[10] = addr->ip[11] = 255;
3630 memcpy(&addr->ip[12], &ipv4, 4);
3631 addr->is_ip6 = true;
3635 static bool mg_aton6(struct mg_str str, struct mg_addr *addr) {
3636 size_t i, j = 0, n = 0, dc = 42;
3637 if (str.len > 2 && str.ptr[0] == '[') str.ptr++, str.len -= 2;
3638 if (mg_v4mapped(str, addr)) return true;
3639 for (i = 0; i < str.len; i++) {
3640 if ((str.ptr[i] >= '0' && str.ptr[i] <= '9') ||
3641 (str.ptr[i] >= 'a' && str.ptr[i] <= 'f') ||
3642 (str.ptr[i] >= 'A' && str.ptr[i] <= 'F')) {
3644 if (i > j + 3) return false;
3645 // MG_DEBUG(("%zu %zu [%.*s]", i, j, (int) (i - j + 1), &str.ptr[j]));
3646 val = mg_unhexn(&str.ptr[j], i - j + 1);
3647 addr->ip[n] = (uint8_t) ((val >> 8) & 255);
3648 addr->ip[n + 1] = (uint8_t) (val & 255);
3649 } else if (str.ptr[i] == ':') {
3651 if (i > 0 && str.ptr[i - 1] == ':') {
3652 dc = n; // Double colon
3653 if (i > 1 && str.ptr[i - 2] == ':') return false;
3657 if (n > 14) return false;
3658 addr->ip[n] = addr->ip[n + 1] = 0; // For trailing ::
3663 if (n < 14 && dc == 42) return false;
3665 memmove(&addr->ip[dc + (14 - n)], &addr->ip[dc], n - dc + 2);
3666 memset(&addr->ip[dc], 0, 14 - n);
3669 addr->is_ip6 = true;
3673 bool mg_aton(struct mg_str str, struct mg_addr *addr) {
3674 // MG_INFO(("[%.*s]", (int) str.len, str.ptr));
3675 return mg_atone(str, addr) || mg_atonl(str, addr) || mg_aton4(str, addr) ||
3676 mg_aton6(str, addr);
3679 struct mg_connection *mg_alloc_conn(struct mg_mgr *mgr) {
3680 struct mg_connection *c =
3681 (struct mg_connection *) calloc(1, sizeof(*c) + mgr->extraconnsize);
3684 c->send.align = c->recv.align = MG_IO_SIZE;
3685 c->id = ++mgr->nextid;
3690 void mg_close_conn(struct mg_connection *c) {
3691 mg_resolve_cancel(c); // Close any pending DNS query
3692 LIST_DELETE(struct mg_connection, &c->mgr->conns, c);
3693 if (c == c->mgr->dns4.c) c->mgr->dns4.c = NULL;
3694 if (c == c->mgr->dns6.c) c->mgr->dns6.c = NULL;
3695 // Order of operations is important. `MG_EV_CLOSE` event must be fired
3696 // before we deallocate received data, see #1331
3697 mg_call(c, MG_EV_CLOSE, NULL);
3698 MG_DEBUG(("%lu %p closed", c->id, c->fd));
3701 mg_iobuf_free(&c->recv);
3702 mg_iobuf_free(&c->send);
3703 memset(c, 0, sizeof(*c));
3707 struct mg_connection *mg_connect(struct mg_mgr *mgr, const char *url,
3708 mg_event_handler_t fn, void *fn_data) {
3709 struct mg_connection *c = NULL;
3710 if (url == NULL || url[0] == '\0') {
3711 MG_ERROR(("null url"));
3712 } else if ((c = mg_alloc_conn(mgr)) == NULL) {
3715 LIST_ADD_HEAD(struct mg_connection, &mgr->conns, c);
3716 c->is_udp = (strncmp(url, "udp:", 4) == 0);
3717 c->fd = (void *) (size_t) MG_INVALID_SOCKET;
3719 c->is_client = true;
3720 c->fn_data = fn_data;
3721 MG_DEBUG(("%lu %p %s", c->id, c->fd, url));
3722 mg_call(c, MG_EV_OPEN, (void *) url);
3724 if (mg_url_is_ssl(url)) {
3725 struct mg_str host = mg_url_host(url);
3726 mg_tls_init(c, host);
3732 struct mg_connection *mg_listen(struct mg_mgr *mgr, const char *url,
3733 mg_event_handler_t fn, void *fn_data) {
3734 struct mg_connection *c = NULL;
3735 if ((c = mg_alloc_conn(mgr)) == NULL) {
3736 MG_ERROR(("OOM %s", url));
3737 } else if (!mg_open_listener(c, url)) {
3738 MG_ERROR(("Failed: %s, errno %d", url, errno));
3742 c->is_listening = 1;
3743 c->is_udp = strncmp(url, "udp:", 4) == 0;
3744 LIST_ADD_HEAD(struct mg_connection, &mgr->conns, c);
3746 c->fn_data = fn_data;
3747 mg_call(c, MG_EV_OPEN, NULL);
3748 if (mg_url_is_ssl(url)) c->is_tls = 1; // Accepted connection must
3749 MG_DEBUG(("%lu %p %s", c->id, c->fd, url));
3754 struct mg_connection *mg_wrapfd(struct mg_mgr *mgr, int fd,
3755 mg_event_handler_t fn, void *fn_data) {
3756 struct mg_connection *c = mg_alloc_conn(mgr);
3758 c->fd = (void *) (size_t) fd;
3760 c->fn_data = fn_data;
3762 mg_call(c, MG_EV_OPEN, NULL);
3763 LIST_ADD_HEAD(struct mg_connection, &mgr->conns, c);
3768 struct mg_timer *mg_timer_add(struct mg_mgr *mgr, uint64_t milliseconds,
3769 unsigned flags, void (*fn)(void *), void *arg) {
3770 struct mg_timer *t = (struct mg_timer *) calloc(1, sizeof(*t));
3772 mg_timer_init(&mgr->timers, t, milliseconds, flags, fn, arg);
3773 t->id = mgr->timerid++;
3778 void mg_mgr_free(struct mg_mgr *mgr) {
3779 struct mg_connection *c;
3780 struct mg_timer *tmp, *t = mgr->timers;
3781 while (t != NULL) tmp = t->next, free(t), t = tmp;
3782 mgr->timers = NULL; // Important. Next call to poll won't touch timers
3783 for (c = mgr->conns; c != NULL; c = c->next) c->is_closing = 1;
3784 mg_mgr_poll(mgr, 0);
3785 #if MG_ENABLE_FREERTOS_TCP
3786 FreeRTOS_DeleteSocketSet(mgr->ss);
3788 MG_DEBUG(("All connections closed"));
3790 if (mgr->epoll_fd >= 0) close(mgr->epoll_fd), mgr->epoll_fd = -1;
3792 mg_tls_ctx_free(mgr);
3795 void mg_mgr_init(struct mg_mgr *mgr) {
3796 memset(mgr, 0, sizeof(*mgr));
3798 if ((mgr->epoll_fd = epoll_create1(0)) < 0) MG_ERROR(("epoll: %d", errno));
3802 #if MG_ARCH == MG_ARCH_WIN32 && MG_ENABLE_WINSOCK
3804 { WSADATA data; WSAStartup(MAKEWORD(2, 2), &data); }
3806 #elif MG_ENABLE_FREERTOS_TCP
3807 mgr->ss = FreeRTOS_CreateSocketSet();
3808 #elif defined(__unix) || defined(__unix__) || defined(__APPLE__)
3809 // Ignore SIGPIPE signal, so if client cancels the request, it
3810 // won't kill the whole process.
3811 signal(SIGPIPE, SIG_IGN);
3813 mgr->dnstimeout = 3000;
3814 mgr->dns4.url = "udp://8.8.8.8:53";
3815 mgr->dns6.url = "udp://[2001:4860:4860::8888]:53";
3818 #ifdef MG_ENABLE_LINES
3819 #line 1 "src/net_builtin.c"
3823 #if defined(MG_ENABLE_TCPIP) && MG_ENABLE_TCPIP
3824 #define MG_EPHEMERAL_PORT_BASE 32768
3825 #define PDIFF(a, b) ((size_t) (((char *) (b)) - ((char *) (a))))
3827 #ifndef MIP_TCP_KEEPALIVE_MS
3828 #define MIP_TCP_KEEPALIVE_MS 45000 // TCP keep-alive period, ms
3831 #define MIP_TCP_ACK_MS 150 // Timeout for ACKing
3832 #define MIP_TCP_ARP_MS 100 // Timeout for ARP response
3833 #define MIP_TCP_SYN_MS 15000 // Timeout for connection establishment
3834 #define MIP_TCP_FIN_MS 1000 // Timeout for closing connection
3837 uint32_t seq, ack; // TCP seq/ack counters
3838 uint64_t timer; // TCP keep-alive / ACK timer
3839 uint8_t mac[6]; // Peer MAC address
3840 uint8_t ttype; // Timer type. 0: ack, 1: keep-alive
3841 #define MIP_TTYPE_KEEPALIVE 0 // Connection is idle for long, send keepalive
3842 #define MIP_TTYPE_ACK 1 // Peer sent us data, we have to ack it soon
3843 #define MIP_TTYPE_ARP 2 // ARP resolve sent, waiting for response
3844 #define MIP_TTYPE_SYN 3 // SYN sent, waiting for response
3845 #define MIP_TTYPE_FIN 4 // FIN sent, waiting until terminating the connection
3846 uint8_t tmiss; // Number of keep-alive misses
3847 struct mg_iobuf raw; // For TLS only. Incoming raw data
3850 #pragma pack(push, 1)
3853 uint8_t addr, ctrl, proto[2], code, id, len[2];
3857 uint8_t dst[6]; // Destination MAC address
3858 uint8_t src[6]; // Source MAC address
3859 uint16_t type; // Ethernet type
3863 uint8_t ver; // Version
3864 uint8_t tos; // Unused
3865 uint16_t len; // Length
3866 uint16_t id; // Unused
3867 uint16_t frag; // Fragmentation
3868 uint8_t ttl; // Time to live
3869 uint8_t proto; // Upper level protocol
3870 uint16_t csum; // Checksum
3871 uint32_t src; // Source IP
3872 uint32_t dst; // Destination IP
3876 uint8_t ver; // Version
3877 uint8_t opts[3]; // Options
3878 uint16_t len; // Length
3879 uint8_t proto; // Upper level protocol
3880 uint8_t ttl; // Time to live
3881 uint8_t src[16]; // Source IP
3882 uint8_t dst[16]; // Destination IP
3892 uint16_t fmt; // Format of hardware address
3893 uint16_t pro; // Format of protocol address
3894 uint8_t hlen; // Length of hardware address
3895 uint8_t plen; // Length of protocol address
3896 uint16_t op; // Operation
3897 uint8_t sha[6]; // Sender hardware address
3898 uint32_t spa; // Sender protocol address
3899 uint8_t tha[6]; // Target hardware address
3900 uint32_t tpa; // Target protocol address
3904 uint16_t sport; // Source port
3905 uint16_t dport; // Destination port
3906 uint32_t seq; // Sequence number
3907 uint32_t ack; // Acknowledgement number
3908 uint8_t off; // Data offset
3909 uint8_t flags; // TCP flags
3913 #define TH_PUSH 0x08
3918 uint16_t win; // Window
3919 uint16_t csum; // Checksum
3920 uint16_t urp; // Urgent pointer
3924 uint16_t sport; // Source port
3925 uint16_t dport; // Destination port
3926 uint16_t len; // UDP length
3927 uint16_t csum; // UDP checksum
3931 uint8_t op, htype, hlen, hops;
3933 uint16_t secs, flags;
3934 uint32_t ciaddr, yiaddr, siaddr, giaddr;
3935 uint8_t hwaddr[208];
3937 uint8_t options[32];
3943 struct mg_str raw; // Raw packet data
3944 struct mg_str pay; // Payload data
3956 static void send_syn(struct mg_connection *c);
3958 static void mkpay(struct pkt *pkt, void *p) {
3960 mg_str_n((char *) p, (size_t) (&pkt->raw.ptr[pkt->raw.len] - (char *) p));
3963 static uint32_t csumup(uint32_t sum, const void *buf, size_t len) {
3964 const uint8_t *p = (const uint8_t *) buf;
3965 for (size_t i = 0; i < len; i++) sum += i & 1 ? p[i] : (uint32_t) (p[i] << 8);
3969 static uint16_t csumfin(uint32_t sum) {
3970 while (sum >> 16) sum = (sum & 0xffff) + (sum >> 16);
3971 return mg_htons(~sum & 0xffff);
3974 static uint16_t ipcsum(const void *buf, size_t len) {
3975 uint32_t sum = csumup(0, buf, len);
3976 return csumfin(sum);
3979 static void settmout(struct mg_connection *c, uint8_t type) {
3980 struct mg_tcpip_if *ifp = (struct mg_tcpip_if *) c->mgr->priv;
3981 struct connstate *s = (struct connstate *) (c + 1);
3982 unsigned n = type == MIP_TTYPE_ACK ? MIP_TCP_ACK_MS
3983 : type == MIP_TTYPE_ARP ? MIP_TCP_ARP_MS
3984 : type == MIP_TTYPE_SYN ? MIP_TCP_SYN_MS
3985 : type == MIP_TTYPE_FIN ? MIP_TCP_FIN_MS
3986 : MIP_TCP_KEEPALIVE_MS;
3987 s->timer = ifp->now + n;
3989 MG_VERBOSE(("%lu %d -> %llx", c->id, type, s->timer));
3992 static size_t ether_output(struct mg_tcpip_if *ifp, size_t len) {
3993 // size_t min = 64; // Pad short frames to 64 bytes (minimum Ethernet size)
3994 // if (len < min) memset(ifp->tx.ptr + len, 0, min - len), len = min;
3995 // mg_hexdump(ifp->tx.ptr, len);
3996 size_t n = ifp->driver->tx(ifp->tx.ptr, len, ifp);
3997 if (n == len) ifp->nsent++;
4001 static void arp_ask(struct mg_tcpip_if *ifp, uint32_t ip) {
4002 struct eth *eth = (struct eth *) ifp->tx.ptr;
4003 struct arp *arp = (struct arp *) (eth + 1);
4004 memset(eth->dst, 255, sizeof(eth->dst));
4005 memcpy(eth->src, ifp->mac, sizeof(eth->src));
4006 eth->type = mg_htons(0x806);
4007 memset(arp, 0, sizeof(*arp));
4008 arp->fmt = mg_htons(1), arp->pro = mg_htons(0x800), arp->hlen = 6,
4010 arp->op = mg_htons(1), arp->tpa = ip, arp->spa = ifp->ip;
4011 memcpy(arp->sha, ifp->mac, sizeof(arp->sha));
4012 ether_output(ifp, PDIFF(eth, arp + 1));
4015 static void onstatechange(struct mg_tcpip_if *ifp) {
4016 if (ifp->state == MG_TCPIP_STATE_READY) {
4017 MG_INFO(("READY, IP: %M", mg_print_ip4, &ifp->ip));
4018 MG_INFO((" GW: %M", mg_print_ip4, &ifp->gw));
4019 MG_INFO((" MAC: %M", mg_print_mac, &ifp->mac));
4020 arp_ask(ifp, ifp->gw);
4021 } else if (ifp->state == MG_TCPIP_STATE_UP) {
4022 MG_ERROR(("Link up"));
4023 srand((unsigned int) mg_millis());
4024 } else if (ifp->state == MG_TCPIP_STATE_DOWN) {
4025 MG_ERROR(("Link down"));
4029 static struct ip *tx_ip(struct mg_tcpip_if *ifp, uint8_t *mac_dst,
4030 uint8_t proto, uint32_t ip_src, uint32_t ip_dst,
4032 struct eth *eth = (struct eth *) ifp->tx.ptr;
4033 struct ip *ip = (struct ip *) (eth + 1);
4034 memcpy(eth->dst, mac_dst, sizeof(eth->dst));
4035 memcpy(eth->src, ifp->mac, sizeof(eth->src)); // Use our MAC
4036 eth->type = mg_htons(0x800);
4037 memset(ip, 0, sizeof(*ip));
4038 ip->ver = 0x45; // Version 4, header length 5 words
4039 ip->frag = 0x40; // Don't fragment
4040 ip->len = mg_htons((uint16_t) (sizeof(*ip) + plen));
4045 ip->csum = ipcsum(ip, sizeof(*ip));
4049 static void tx_udp(struct mg_tcpip_if *ifp, uint8_t *mac_dst, uint32_t ip_src,
4050 uint16_t sport, uint32_t ip_dst, uint16_t dport,
4051 const void *buf, size_t len) {
4053 tx_ip(ifp, mac_dst, 17, ip_src, ip_dst, len + sizeof(struct udp));
4054 struct udp *udp = (struct udp *) (ip + 1);
4055 // MG_DEBUG(("UDP XX LEN %d %d", (int) len, (int) ifp->tx.len));
4058 udp->len = mg_htons((uint16_t) (sizeof(*udp) + len));
4060 uint32_t cs = csumup(0, udp, sizeof(*udp));
4061 cs = csumup(cs, buf, len);
4062 cs = csumup(cs, &ip->src, sizeof(ip->src));
4063 cs = csumup(cs, &ip->dst, sizeof(ip->dst));
4064 cs += (uint32_t) (ip->proto + sizeof(*udp) + len);
4065 udp->csum = csumfin(cs);
4066 memmove(udp + 1, buf, len);
4067 // MG_DEBUG(("UDP LEN %d %d", (int) len, (int) ifp->frame_len));
4068 ether_output(ifp, sizeof(struct eth) + sizeof(*ip) + sizeof(*udp) + len);
4071 static void tx_dhcp(struct mg_tcpip_if *ifp, uint8_t *mac_dst, uint32_t ip_src,
4072 uint32_t ip_dst, uint8_t *opts, size_t optslen,
4074 // https://datatracker.ietf.org/doc/html/rfc2132#section-9.6
4075 struct dhcp dhcp = {1, 1, 6, 0, 0, 0, 0, 0, 0, 0, 0, {0}, 0, {0}};
4076 dhcp.magic = mg_htonl(0x63825363);
4077 memcpy(&dhcp.hwaddr, ifp->mac, sizeof(ifp->mac));
4078 memcpy(&dhcp.xid, ifp->mac + 2, sizeof(dhcp.xid));
4079 memcpy(&dhcp.options, opts, optslen);
4080 if (ciaddr) dhcp.ciaddr = ip_src;
4081 tx_udp(ifp, mac_dst, ip_src, mg_htons(68), ip_dst, mg_htons(67), &dhcp,
4085 static const uint8_t broadcast[] = {255, 255, 255, 255, 255, 255};
4087 // RFC-2131 #4.3.6, #4.4.1
4088 static void tx_dhcp_request_sel(struct mg_tcpip_if *ifp, uint32_t ip_req,
4091 53, 1, 3, // Type: DHCP request
4092 55, 2, 1, 3, // GW and mask
4093 12, 3, 'm', 'i', 'p', // Host name: "mip"
4094 54, 4, 0, 0, 0, 0, // DHCP server ID
4095 50, 4, 0, 0, 0, 0, // Requested IP
4096 255 // End of options
4098 memcpy(opts + 14, &ip_srv, sizeof(ip_srv));
4099 memcpy(opts + 20, &ip_req, sizeof(ip_req));
4100 tx_dhcp(ifp, (uint8_t *) broadcast, 0, 0xffffffff, opts, sizeof(opts), false);
4101 MG_DEBUG(("DHCP req sent"));
4104 // RFC-2131 #4.3.6, #4.4.5 (renewing: unicast, rebinding: bcast)
4105 static void tx_dhcp_request_re(struct mg_tcpip_if *ifp, uint8_t *mac_dst,
4106 uint32_t ip_src, uint32_t ip_dst) {
4108 53, 1, 3, // Type: DHCP request
4109 255 // End of options
4111 tx_dhcp(ifp, mac_dst, ip_src, ip_dst, opts, sizeof(opts), true);
4112 MG_DEBUG(("DHCP req sent"));
4115 static void tx_dhcp_discover(struct mg_tcpip_if *ifp) {
4117 53, 1, 1, // Type: DHCP discover
4118 55, 2, 1, 3, // Parameters: ip, mask
4119 255 // End of options
4121 tx_dhcp(ifp, (uint8_t *) broadcast, 0, 0xffffffff, opts, sizeof(opts), false);
4122 MG_DEBUG(("DHCP discover sent. Our MAC: %M", mg_print_mac, ifp->mac));
4125 static struct mg_connection *getpeer(struct mg_mgr *mgr, struct pkt *pkt,
4127 struct mg_connection *c = NULL;
4128 for (c = mgr->conns; c != NULL; c = c->next) {
4129 if (c->is_arplooking && pkt->arp &&
4130 memcmp(&pkt->arp->spa, c->rem.ip, sizeof(pkt->arp->spa)) == 0)
4132 if (c->is_udp && pkt->udp && c->loc.port == pkt->udp->dport) break;
4133 if (!c->is_udp && pkt->tcp && c->loc.port == pkt->tcp->dport &&
4134 lsn == c->is_listening && (lsn || c->rem.port == pkt->tcp->sport))
4140 static void rx_arp(struct mg_tcpip_if *ifp, struct pkt *pkt) {
4141 if (pkt->arp->op == mg_htons(1) && pkt->arp->tpa == ifp->ip) {
4142 // ARP request. Make a response, then send
4143 // MG_DEBUG(("ARP op %d %M: %M", mg_ntohs(pkt->arp->op), mg_print_ip4,
4144 // &pkt->arp->spa, mg_print_ip4, &pkt->arp->tpa));
4145 struct eth *eth = (struct eth *) ifp->tx.ptr;
4146 struct arp *arp = (struct arp *) (eth + 1);
4147 memcpy(eth->dst, pkt->eth->src, sizeof(eth->dst));
4148 memcpy(eth->src, ifp->mac, sizeof(eth->src));
4149 eth->type = mg_htons(0x806);
4151 arp->op = mg_htons(2);
4152 memcpy(arp->tha, pkt->arp->sha, sizeof(pkt->arp->tha));
4153 memcpy(arp->sha, ifp->mac, sizeof(pkt->arp->sha));
4154 arp->tpa = pkt->arp->spa;
4156 MG_DEBUG(("ARP: tell %M we're %M", mg_print_ip4, &arp->tpa, mg_print_mac,
4158 ether_output(ifp, PDIFF(eth, arp + 1));
4159 } else if (pkt->arp->op == mg_htons(2)) {
4160 if (memcmp(pkt->arp->tha, ifp->mac, sizeof(pkt->arp->tha)) != 0) return;
4161 if (pkt->arp->spa == ifp->gw) {
4162 // Got response for the GW ARP request. Set ifp->gwmac
4163 memcpy(ifp->gwmac, pkt->arp->sha, sizeof(ifp->gwmac));
4165 struct mg_connection *c = getpeer(ifp->mgr, pkt, false);
4166 if (c != NULL && c->is_arplooking) {
4167 struct connstate *s = (struct connstate *) (c + 1);
4168 memcpy(s->mac, pkt->arp->sha, sizeof(s->mac));
4169 MG_DEBUG(("%lu ARP resolved %M -> %M", c->id, mg_print_ip4, c->rem.ip,
4170 mg_print_mac, s->mac));
4171 c->is_arplooking = 0;
4173 settmout(c, MIP_TTYPE_SYN);
4179 static void rx_icmp(struct mg_tcpip_if *ifp, struct pkt *pkt) {
4180 // MG_DEBUG(("ICMP %d", (int) len));
4181 if (pkt->icmp->type == 8 && pkt->ip != NULL && pkt->ip->dst == ifp->ip) {
4182 size_t hlen = sizeof(struct eth) + sizeof(struct ip) + sizeof(struct icmp);
4183 size_t space = ifp->tx.len - hlen, plen = pkt->pay.len;
4184 if (plen > space) plen = space;
4185 struct ip *ip = tx_ip(ifp, pkt->eth->src, 1, ifp->ip, pkt->ip->src,
4186 sizeof(struct icmp) + plen);
4187 struct icmp *icmp = (struct icmp *) (ip + 1);
4188 memset(icmp, 0, sizeof(*icmp)); // Set csum to 0
4189 memcpy(icmp + 1, pkt->pay.ptr, plen); // Copy RX payload to TX
4190 icmp->csum = ipcsum(icmp, sizeof(*icmp) + plen);
4191 ether_output(ifp, hlen + plen);
4195 static void rx_dhcp_client(struct mg_tcpip_if *ifp, struct pkt *pkt) {
4196 uint32_t ip = 0, gw = 0, mask = 0, lease = 0;
4197 uint8_t msgtype = 0, state = ifp->state;
4198 // perform size check first, then access fields
4199 uint8_t *p = pkt->dhcp->options,
4200 *end = (uint8_t *) &pkt->raw.ptr[pkt->raw.len];
4201 if (end < (uint8_t *) (pkt->dhcp + 1)) return;
4202 if (memcmp(&pkt->dhcp->xid, ifp->mac + 2, sizeof(pkt->dhcp->xid))) return;
4203 while (p + 1 < end && p[0] != 255) { // Parse options RFC-1533 #9
4204 if (p[0] == 1 && p[1] == sizeof(ifp->mask) && p + 6 < end) { // Mask
4205 memcpy(&mask, p + 2, sizeof(mask));
4206 } else if (p[0] == 3 && p[1] == sizeof(ifp->gw) && p + 6 < end) { // GW
4207 memcpy(&gw, p + 2, sizeof(gw));
4208 ip = pkt->dhcp->yiaddr;
4209 } else if (p[0] == 51 && p[1] == 4 && p + 6 < end) { // Lease
4210 memcpy(&lease, p + 2, sizeof(lease));
4211 lease = mg_ntohl(lease);
4212 } else if (p[0] == 53 && p[1] == 1 && p + 6 < end) { // Msg Type
4217 // Process message type, RFC-1533 (9.4); RFC-2131 (3.1, 4)
4218 if (msgtype == 6 && ifp->ip == ip) { // DHCPNACK, release IP
4219 ifp->state = MG_TCPIP_STATE_UP, ifp->ip = 0;
4220 } else if (msgtype == 2 && ifp->state == MG_TCPIP_STATE_UP && ip && gw &&
4221 lease) { // DHCPOFFER
4222 tx_dhcp_request_sel(ifp, ip, pkt->dhcp->siaddr); // select IP, (4.4.1)
4223 ifp->state = MG_TCPIP_STATE_REQ; // REQUESTING state
4224 } else if (msgtype == 5) { // DHCPACK
4225 if (ifp->state == MG_TCPIP_STATE_REQ && ip && gw && lease) { // got an IP
4226 ifp->lease_expire = ifp->now + lease * 1000;
4227 MG_INFO(("Lease: %u sec (%lld)", lease, ifp->lease_expire / 1000));
4228 // assume DHCP server = router until ARP resolves
4229 memcpy(ifp->gwmac, pkt->eth->src, sizeof(ifp->gwmac));
4230 ifp->ip = ip, ifp->gw = gw, ifp->mask = mask;
4231 ifp->state = MG_TCPIP_STATE_READY; // BOUND state
4233 mg_random(&rand, sizeof(rand));
4234 srand((unsigned int) (rand + mg_millis()));
4235 } else if (ifp->state == MG_TCPIP_STATE_READY && ifp->ip == ip) { // renew
4236 ifp->lease_expire = ifp->now + lease * 1000;
4237 MG_INFO(("Lease: %u sec (%lld)", lease, ifp->lease_expire / 1000));
4238 } // TODO(): accept provided T1/T2 and store server IP for renewal (4.4)
4240 if (ifp->state != state) onstatechange(ifp);
4243 // Simple DHCP server that assigns a next IP address: ifp->ip + 1
4244 static void rx_dhcp_server(struct mg_tcpip_if *ifp, struct pkt *pkt) {
4245 uint8_t op = 0, *p = pkt->dhcp->options,
4246 *end = (uint8_t *) &pkt->raw.ptr[pkt->raw.len];
4247 if (end < (uint8_t *) (pkt->dhcp + 1)) return;
4248 // struct dhcp *req = pkt->dhcp;
4249 struct dhcp res = {2, 1, 6, 0, 0, 0, 0, 0, 0, 0, 0, {0}, 0, {0}};
4250 res.yiaddr = ifp->ip;
4251 ((uint8_t *) (&res.yiaddr))[3]++; // Offer our IP + 1
4252 while (p + 1 < end && p[0] != 255) { // Parse options
4253 if (p[0] == 53 && p[1] == 1 && p + 2 < end) { // Message type
4258 if (op == 1 || op == 3) { // DHCP Discover or DHCP Request
4259 uint8_t msg = op == 1 ? 2 : 5; // Message type: DHCP OFFER or DHCP ACK
4261 53, 1, msg, // Message type
4262 1, 4, 0, 0, 0, 0, // Subnet mask
4263 54, 4, 0, 0, 0, 0, // Server ID
4264 12, 3, 'm', 'i', 'p', // Host name: "mip"
4265 51, 4, 255, 255, 255, 255, // Lease time
4266 255 // End of options
4268 memcpy(&res.hwaddr, pkt->dhcp->hwaddr, 6);
4269 memcpy(opts + 5, &ifp->mask, sizeof(ifp->mask));
4270 memcpy(opts + 11, &ifp->ip, sizeof(ifp->ip));
4271 memcpy(&res.options, opts, sizeof(opts));
4272 res.magic = pkt->dhcp->magic;
4273 res.xid = pkt->dhcp->xid;
4274 // memcpy(ifp->gwmac, pkt->eth->src, sizeof(ifp->gwmac));
4275 tx_udp(ifp, pkt->eth->src, ifp->ip, mg_htons(67),
4276 op == 1 ? ~0U : res.yiaddr, mg_htons(68), &res, sizeof(res));
4280 static void rx_udp(struct mg_tcpip_if *ifp, struct pkt *pkt) {
4281 struct mg_connection *c = getpeer(ifp->mgr, pkt, true);
4283 // No UDP listener on this port. Should send ICMP, but keep silent.
4285 c->rem.port = pkt->udp->sport;
4286 memcpy(c->rem.ip, &pkt->ip->src, sizeof(uint32_t));
4287 struct connstate *s = (struct connstate *) (c + 1);
4288 memcpy(s->mac, pkt->eth->src, sizeof(s->mac));
4289 if (c->recv.len >= MG_MAX_RECV_SIZE) {
4290 mg_error(c, "max_recv_buf_size reached");
4291 } else if (c->recv.size - c->recv.len < pkt->pay.len &&
4292 !mg_iobuf_resize(&c->recv, c->recv.len + pkt->pay.len)) {
4295 memcpy(&c->recv.buf[c->recv.len], pkt->pay.ptr, pkt->pay.len);
4296 c->recv.len += pkt->pay.len;
4297 mg_call(c, MG_EV_READ, &pkt->pay.len);
4302 static size_t tx_tcp(struct mg_tcpip_if *ifp, uint8_t *dst_mac, uint32_t dst_ip,
4303 uint8_t flags, uint16_t sport, uint16_t dport,
4304 uint32_t seq, uint32_t ack, const void *buf, size_t len) {
4306 tx_ip(ifp, dst_mac, 6, ifp->ip, dst_ip, sizeof(struct tcp) + len);
4307 struct tcp *tcp = (struct tcp *) (ip + 1);
4308 memset(tcp, 0, sizeof(*tcp));
4309 if (buf != NULL && len) memmove(tcp + 1, buf, len);
4315 tcp->win = mg_htons(8192);
4316 tcp->off = (uint8_t) (sizeof(*tcp) / 4 << 4);
4318 uint16_t n = (uint16_t) (sizeof(*tcp) + len);
4319 uint8_t pseudo[] = {0, ip->proto, (uint8_t) (n >> 8), (uint8_t) (n & 255)};
4320 cs = csumup(cs, tcp, n);
4321 cs = csumup(cs, &ip->src, sizeof(ip->src));
4322 cs = csumup(cs, &ip->dst, sizeof(ip->dst));
4323 cs = csumup(cs, pseudo, sizeof(pseudo));
4324 tcp->csum = csumfin(cs);
4325 MG_VERBOSE(("TCP %M:%hu -> %M:%hu fl %x len %u", mg_print_ip4, &ip->src,
4326 mg_ntohs(tcp->sport), mg_print_ip4, &ip->dst,
4327 mg_ntohs(tcp->dport), tcp->flags, (int) len));
4328 // mg_hexdump(ifp->tx.ptr, PDIFF(ifp->tx.ptr, tcp + 1) + len);
4329 return ether_output(ifp, PDIFF(ifp->tx.ptr, tcp + 1) + len);
4332 static size_t tx_tcp_pkt(struct mg_tcpip_if *ifp, struct pkt *pkt,
4333 uint8_t flags, uint32_t seq, const void *buf,
4335 uint32_t delta = (pkt->tcp->flags & (TH_SYN | TH_FIN)) ? 1 : 0;
4336 return tx_tcp(ifp, pkt->eth->src, pkt->ip->src, flags, pkt->tcp->dport,
4337 pkt->tcp->sport, seq, mg_htonl(mg_ntohl(pkt->tcp->seq) + delta),
4341 static struct mg_connection *accept_conn(struct mg_connection *lsn,
4343 struct mg_connection *c = mg_alloc_conn(lsn->mgr);
4348 struct connstate *s = (struct connstate *) (c + 1);
4349 s->seq = mg_ntohl(pkt->tcp->ack), s->ack = mg_ntohl(pkt->tcp->seq);
4350 memcpy(s->mac, pkt->eth->src, sizeof(s->mac));
4351 settmout(c, MIP_TTYPE_KEEPALIVE);
4352 memcpy(c->rem.ip, &pkt->ip->src, sizeof(uint32_t));
4353 c->rem.port = pkt->tcp->sport;
4354 MG_DEBUG(("%lu accepted %M", c->id, mg_print_ip_port, &c->rem));
4355 LIST_ADD_HEAD(struct mg_connection, &lsn->mgr->conns, c);
4357 c->is_hexdumping = lsn->is_hexdumping;
4360 c->pfn_data = lsn->pfn_data;
4362 c->fn_data = lsn->fn_data;
4363 mg_call(c, MG_EV_OPEN, NULL);
4364 mg_call(c, MG_EV_ACCEPT, NULL);
4365 if (lsn->is_tls) mg_tls_init(c, mg_str(""));
4369 long mg_io_send(struct mg_connection *c, const void *buf, size_t len) {
4370 struct mg_tcpip_if *ifp = (struct mg_tcpip_if *) c->mgr->priv;
4371 struct connstate *s = (struct connstate *) (c + 1);
4373 memcpy(&rem_ip, c->rem.ip, sizeof(uint32_t));
4375 size_t max_headers_len = 14 + 24 /* max IP */ + 8 /* UDP */;
4376 if (len + max_headers_len > ifp->tx.len) {
4377 len = ifp->tx.len - max_headers_len;
4379 tx_udp(ifp, s->mac, ifp->ip, c->loc.port, rem_ip, c->rem.port, buf, len);
4381 size_t max_headers_len = 14 + 24 /* max IP */ + 60 /* max TCP */;
4382 if (len + max_headers_len > ifp->tx.len)
4383 len = ifp->tx.len - max_headers_len;
4384 if (tx_tcp(ifp, s->mac, rem_ip, TH_PUSH | TH_ACK, c->loc.port, c->rem.port,
4385 mg_htonl(s->seq), mg_htonl(s->ack), buf, len) > 0) {
4386 s->seq += (uint32_t) len;
4387 if (s->ttype == MIP_TTYPE_ACK) settmout(c, MIP_TTYPE_KEEPALIVE);
4395 long mg_io_recv(struct mg_connection *c, void *buf, size_t len) {
4396 struct connstate *s = (struct connstate *) (c + 1);
4397 if (s->raw.len == 0) return MG_IO_WAIT;
4398 if (len > s->raw.len) len = s->raw.len;
4399 memcpy(buf, s->raw.buf, len);
4400 mg_iobuf_del(&s->raw, 0, len);
4404 static void read_conn(struct mg_connection *c, struct pkt *pkt) {
4405 struct connstate *s = (struct connstate *) (c + 1);
4406 struct mg_iobuf *io = c->is_tls ? &s->raw : &c->recv;
4407 uint32_t seq = mg_ntohl(pkt->tcp->seq);
4408 s->raw.align = c->recv.align;
4410 memcpy(&rem_ip, c->rem.ip, sizeof(uint32_t));
4411 if (pkt->tcp->flags & TH_FIN) {
4412 // If we initiated the closure, we reply with ACK upon receiving FIN
4413 // If we didn't initiate it, we reply with FIN as part of the normal TCP
4415 uint8_t flags = TH_ACK;
4416 s->ack = (uint32_t) (mg_htonl(pkt->tcp->seq) + pkt->pay.len + 1);
4417 if (c->is_draining && s->ttype == MIP_TTYPE_FIN) {
4418 if (s->seq == mg_htonl(pkt->tcp->ack))
4419 // Checking for simultaneous closure
4422 s->seq = mg_htonl(pkt->tcp->ack);
4426 settmout(c, MIP_TTYPE_FIN);
4428 tx_tcp((struct mg_tcpip_if *) c->mgr->priv, s->mac, rem_ip, flags,
4429 c->loc.port, c->rem.port, mg_htonl(s->seq), mg_htonl(s->ack), "", 0);
4430 } else if (pkt->pay.len == 0) {
4431 // TODO(cpq): handle this peer's ACK
4432 } else if (seq != s->ack) {
4433 uint32_t ack = (uint32_t) (mg_htonl(pkt->tcp->seq) + pkt->pay.len);
4434 if (s->ack == ack) {
4435 MG_VERBOSE(("ignoring duplicate pkt"));
4437 MG_VERBOSE(("SEQ != ACK: %x %x %x", seq, s->ack, ack));
4438 tx_tcp((struct mg_tcpip_if *) c->mgr->priv, s->mac, rem_ip, TH_ACK,
4439 c->loc.port, c->rem.port, mg_htonl(s->seq), mg_htonl(s->ack), "",
4442 } else if (io->size - io->len < pkt->pay.len &&
4443 !mg_iobuf_resize(io, io->len + pkt->pay.len)) {
4446 // Copy TCP payload into the IO buffer. If the connection is plain text,
4447 // we copy to c->recv. If the connection is TLS, this data is encrypted,
4448 // therefore we copy that encrypted data to the s->raw iobuffer instead,
4449 // and then call mg_tls_recv() to decrypt it. NOTE: mg_tls_recv() will
4450 // call back mg_io_recv() which grabs raw data from s->raw
4451 memcpy(&io->buf[io->len], pkt->pay.ptr, pkt->pay.len);
4452 io->len += pkt->pay.len;
4454 MG_VERBOSE(("%lu SEQ %x -> %x", c->id, mg_htonl(pkt->tcp->seq), s->ack));
4455 // Advance ACK counter
4456 s->ack = (uint32_t) (mg_htonl(pkt->tcp->seq) + pkt->pay.len);
4458 // Send ACK immediately
4460 memcpy(&rem_ip, c->rem.ip, sizeof(uint32_t));
4461 MG_DEBUG((" imm ACK", c->id, mg_htonl(pkt->tcp->seq), s->ack));
4462 tx_tcp((struct mg_tcpip_if *) c->mgr->priv, s->mac, rem_ip, TH_ACK, c->loc.port,
4463 c->rem.port, mg_htonl(s->seq), mg_htonl(s->ack), "", 0);
4465 // if not already running, setup a timer to send an ACK later
4466 if (s->ttype != MIP_TTYPE_ACK) settmout(c, MIP_TTYPE_ACK);
4470 // TLS connection. Make room for decrypted data in c->recv
4472 if (io->size - io->len < pkt->pay.len &&
4473 !mg_iobuf_resize(io, io->len + pkt->pay.len)) {
4476 // Decrypt data directly into c->recv
4477 long n = mg_tls_recv(c, &io->buf[io->len], io->size - io->len);
4478 if (n == MG_IO_ERR) {
4479 mg_error(c, "TLS recv error");
4481 // Decrypted successfully - trigger MG_EV_READ
4482 io->len += (size_t) n;
4483 mg_call(c, MG_EV_READ, &n);
4487 // Plain text connection, data is already in c->recv, trigger
4489 mg_call(c, MG_EV_READ, &pkt->pay.len);
4494 static void rx_tcp(struct mg_tcpip_if *ifp, struct pkt *pkt) {
4495 struct mg_connection *c = getpeer(ifp->mgr, pkt, false);
4496 struct connstate *s = c == NULL ? NULL : (struct connstate *) (c + 1);
4498 MG_INFO(("%lu %hhu %d", c ? c->id : 0, pkt->tcp->flags, (int) pkt->pay.len));
4500 if (c != NULL && c->is_connecting && pkt->tcp->flags & (TH_SYN | TH_ACK)) {
4501 s->seq = mg_ntohl(pkt->tcp->ack), s->ack = mg_ntohl(pkt->tcp->seq) + 1;
4502 tx_tcp_pkt(ifp, pkt, TH_ACK, pkt->tcp->ack, NULL, 0);
4503 c->is_connecting = 0; // Client connected
4504 settmout(c, MIP_TTYPE_KEEPALIVE);
4505 mg_call(c, MG_EV_CONNECT, NULL); // Let user know
4506 } else if (c != NULL && c->is_connecting) {
4507 // mg_hexdump(pkt->raw.ptr, pkt->raw.len);
4508 tx_tcp_pkt(ifp, pkt, TH_RST | TH_ACK, pkt->tcp->ack, NULL, 0);
4509 } else if (c != NULL && pkt->tcp->flags & TH_RST) {
4510 mg_error(c, "peer RST"); // RFC-1122 4.2.2.13
4511 } else if (c != NULL) {
4513 MG_DEBUG(("%lu %d %M:%hu -> %M:%hu", c->id, (int) pkt->raw.len,
4514 mg_print_ip4, &pkt->ip->src, mg_ntohs(pkt->tcp->sport),
4515 mg_print_ip4, &pkt->ip->dst, mg_ntohs(pkt->tcp->dport)));
4516 mg_hexdump(pkt->pay.ptr, pkt->pay.len);
4518 s->tmiss = 0; // Reset missed keep-alive counter
4519 if (s->ttype == MIP_TTYPE_KEEPALIVE) // Advance keep-alive timer
4521 MIP_TTYPE_KEEPALIVE); // unless a former ACK timeout is pending
4522 read_conn(c, pkt); // Override timer with ACK timeout if needed
4523 } else if ((c = getpeer(ifp->mgr, pkt, true)) == NULL) {
4524 tx_tcp_pkt(ifp, pkt, TH_RST | TH_ACK, pkt->tcp->ack, NULL, 0);
4525 } else if (pkt->tcp->flags & TH_RST) {
4526 if (c->is_accepted) mg_error(c, "peer RST"); // RFC-1122 4.2.2.13
4527 // ignore RST if not connected
4528 } else if (pkt->tcp->flags & TH_SYN) {
4529 // Use peer's source port as ISN, in order to recognise the handshake
4530 uint32_t isn = mg_htonl((uint32_t) mg_ntohs(pkt->tcp->sport));
4531 tx_tcp_pkt(ifp, pkt, TH_SYN | TH_ACK, isn, NULL, 0);
4532 } else if (pkt->tcp->flags & TH_FIN) {
4533 tx_tcp_pkt(ifp, pkt, TH_FIN | TH_ACK, pkt->tcp->ack, NULL, 0);
4534 } else if (mg_htonl(pkt->tcp->ack) == mg_htons(pkt->tcp->sport) + 1U) {
4535 accept_conn(c, pkt);
4536 } else if (!c->is_accepted) { // no peer
4537 tx_tcp_pkt(ifp, pkt, TH_RST | TH_ACK, pkt->tcp->ack, NULL, 0);
4539 // MG_VERBOSE(("dropped silently.."));
4543 static void rx_ip(struct mg_tcpip_if *ifp, struct pkt *pkt) {
4544 if (pkt->ip->proto == 1) {
4545 pkt->icmp = (struct icmp *) (pkt->ip + 1);
4546 if (pkt->pay.len < sizeof(*pkt->icmp)) return;
4547 mkpay(pkt, pkt->icmp + 1);
4549 } else if (pkt->ip->proto == 17) {
4550 pkt->udp = (struct udp *) (pkt->ip + 1);
4551 if (pkt->pay.len < sizeof(*pkt->udp)) return;
4552 mkpay(pkt, pkt->udp + 1);
4553 MG_VERBOSE(("UDP %M:%hu -> %M:%hu len %u", mg_print_ip4, &pkt->ip->src,
4554 mg_ntohs(pkt->udp->sport), mg_print_ip4, &pkt->ip->dst,
4555 mg_ntohs(pkt->udp->dport), (int) pkt->pay.len));
4556 if (ifp->enable_dhcp_client && pkt->udp->dport == mg_htons(68)) {
4557 pkt->dhcp = (struct dhcp *) (pkt->udp + 1);
4558 mkpay(pkt, pkt->dhcp + 1);
4559 rx_dhcp_client(ifp, pkt);
4560 } else if (ifp->enable_dhcp_server && pkt->udp->dport == mg_htons(67)) {
4561 pkt->dhcp = (struct dhcp *) (pkt->udp + 1);
4562 mkpay(pkt, pkt->dhcp + 1);
4563 rx_dhcp_server(ifp, pkt);
4567 } else if (pkt->ip->proto == 6) {
4568 pkt->tcp = (struct tcp *) (pkt->ip + 1);
4569 if (pkt->pay.len < sizeof(*pkt->tcp)) return;
4570 mkpay(pkt, pkt->tcp + 1);
4571 uint16_t iplen = mg_ntohs(pkt->ip->len);
4572 uint16_t off = (uint16_t) (sizeof(*pkt->ip) + ((pkt->tcp->off >> 4) * 4U));
4573 if (iplen >= off) pkt->pay.len = (size_t) (iplen - off);
4574 MG_VERBOSE(("TCP %M:%hu -> %M:%hu len %u", mg_print_ip4, &pkt->ip->src,
4575 mg_ntohs(pkt->tcp->sport), mg_print_ip4, &pkt->ip->dst,
4576 mg_ntohs(pkt->tcp->dport), (int) pkt->pay.len));
4581 static void rx_ip6(struct mg_tcpip_if *ifp, struct pkt *pkt) {
4582 // MG_DEBUG(("IP %d", (int) len));
4583 if (pkt->ip6->proto == 1 || pkt->ip6->proto == 58) {
4584 pkt->icmp = (struct icmp *) (pkt->ip6 + 1);
4585 if (pkt->pay.len < sizeof(*pkt->icmp)) return;
4586 mkpay(pkt, pkt->icmp + 1);
4588 } else if (pkt->ip6->proto == 17) {
4589 pkt->udp = (struct udp *) (pkt->ip6 + 1);
4590 if (pkt->pay.len < sizeof(*pkt->udp)) return;
4591 // MG_DEBUG((" UDP %u %u -> %u", len, mg_htons(udp->sport),
4592 // mg_htons(udp->dport)));
4593 mkpay(pkt, pkt->udp + 1);
4597 static void mg_tcpip_rx(struct mg_tcpip_if *ifp, void *buf, size_t len) {
4599 memset(&pkt, 0, sizeof(pkt));
4600 pkt.raw.ptr = (char *) buf;
4602 pkt.eth = (struct eth *) buf;
4603 // mg_hexdump(buf, len > 16 ? 16: len);
4604 if (pkt.raw.len < sizeof(*pkt.eth)) return; // Truncated - runt?
4605 if (ifp->enable_mac_check &&
4606 memcmp(pkt.eth->dst, ifp->mac, sizeof(pkt.eth->dst)) != 0 &&
4607 memcmp(pkt.eth->dst, broadcast, sizeof(pkt.eth->dst)) != 0)
4609 if (ifp->enable_crc32_check && len > 4) {
4610 len -= 4; // TODO(scaprile): check on bigendian
4611 uint32_t crc = mg_crc32(0, (const char *) buf, len);
4612 if (memcmp((void *) ((size_t) buf + len), &crc, sizeof(crc))) return;
4614 if (pkt.eth->type == mg_htons(0x806)) {
4615 pkt.arp = (struct arp *) (pkt.eth + 1);
4616 if (sizeof(*pkt.eth) + sizeof(*pkt.arp) > pkt.raw.len) return; // Truncated
4618 } else if (pkt.eth->type == mg_htons(0x86dd)) {
4619 pkt.ip6 = (struct ip6 *) (pkt.eth + 1);
4620 if (pkt.raw.len < sizeof(*pkt.eth) + sizeof(*pkt.ip6)) return; // Truncated
4621 if ((pkt.ip6->ver >> 4) != 0x6) return; // Not IP
4622 mkpay(&pkt, pkt.ip6 + 1);
4624 } else if (pkt.eth->type == mg_htons(0x800)) {
4625 pkt.ip = (struct ip *) (pkt.eth + 1);
4626 if (pkt.raw.len < sizeof(*pkt.eth) + sizeof(*pkt.ip)) return; // Truncated
4627 // Truncate frame to what IP header tells us
4628 if ((size_t) mg_ntohs(pkt.ip->len) + sizeof(struct eth) < pkt.raw.len) {
4629 pkt.raw.len = (size_t) mg_ntohs(pkt.ip->len) + sizeof(struct eth);
4631 if (pkt.raw.len < sizeof(*pkt.eth) + sizeof(*pkt.ip)) return; // Truncated
4632 if ((pkt.ip->ver >> 4) != 4) return; // Not IP
4633 mkpay(&pkt, pkt.ip + 1);
4636 MG_DEBUG(("Unknown eth type %x", mg_htons(pkt.eth->type)));
4637 //mg_hexdump(buf, len >= 32 ? 32 : len);
4641 static void mg_tcpip_poll(struct mg_tcpip_if *ifp, uint64_t uptime_ms) {
4642 if (ifp == NULL || ifp->driver == NULL) return;
4643 bool expired_1000ms = mg_timer_expired(&ifp->timer_1000ms, 1000, uptime_ms);
4644 ifp->now = uptime_ms;
4646 // Handle physical interface up/down status
4647 if (expired_1000ms && ifp->driver->up) {
4648 bool up = ifp->driver->up(ifp);
4649 bool current = ifp->state != MG_TCPIP_STATE_DOWN;
4650 if (up != current) {
4651 ifp->state = up == false ? MG_TCPIP_STATE_DOWN
4652 : ifp->enable_dhcp_client ? MG_TCPIP_STATE_UP
4653 : MG_TCPIP_STATE_READY;
4654 if (!up && ifp->enable_dhcp_client) ifp->ip = 0;
4658 if (ifp->state == MG_TCPIP_STATE_DOWN) return;
4660 // DHCP RFC-2131 (4.4)
4661 if (ifp->state == MG_TCPIP_STATE_UP && expired_1000ms) {
4662 tx_dhcp_discover(ifp); // INIT (4.4.1)
4663 } else if (expired_1000ms && ifp->state == MG_TCPIP_STATE_READY &&
4664 ifp->lease_expire > 0) { // BOUND / RENEWING / REBINDING
4665 if (ifp->now >= ifp->lease_expire) {
4666 ifp->state = MG_TCPIP_STATE_UP, ifp->ip = 0; // expired, release IP
4668 } else if (ifp->now + 30UL * 60UL * 1000UL > ifp->lease_expire &&
4669 ((ifp->now / 1000) % 60) == 0) {
4670 // hack: 30 min before deadline, try to rebind (4.3.6) every min
4671 tx_dhcp_request_re(ifp, (uint8_t *) broadcast, ifp->ip, 0xffffffff);
4672 } // TODO(): Handle T1 (RENEWING) and T2 (REBINDING) (4.4.5)
4675 // Read data from the network
4676 if (ifp->driver->rx != NULL) { // Polling driver. We must call it
4678 ifp->driver->rx(ifp->recv_queue.buf, ifp->recv_queue.size, ifp);
4679 if (len > 0) mg_tcpip_rx(ifp, ifp->recv_queue.buf, len);
4680 } else { // Interrupt-based driver. Fills recv queue itself
4682 size_t len = mg_queue_next(&ifp->recv_queue, &buf);
4684 mg_tcpip_rx(ifp, buf, len);
4685 mg_queue_del(&ifp->recv_queue, len);
4690 for (struct mg_connection *c = ifp->mgr->conns; c != NULL; c = c->next) {
4691 if (c->is_udp || c->is_listening || c->is_resolving) continue;
4692 struct connstate *s = (struct connstate *) (c + 1);
4694 memcpy(&rem_ip, c->rem.ip, sizeof(uint32_t));
4695 if (uptime_ms > s->timer) {
4696 if (s->ttype == MIP_TTYPE_ACK) {
4697 MG_VERBOSE(("%lu ack %x %x", c->id, s->seq, s->ack));
4698 tx_tcp(ifp, s->mac, rem_ip, TH_ACK, c->loc.port, c->rem.port,
4699 mg_htonl(s->seq), mg_htonl(s->ack), "", 0);
4700 } else if (s->ttype == MIP_TTYPE_ARP) {
4701 mg_error(c, "ARP timeout");
4702 } else if (s->ttype == MIP_TTYPE_SYN) {
4703 mg_error(c, "Connection timeout");
4704 } else if (s->ttype == MIP_TTYPE_FIN) {
4708 if (s->tmiss++ > 2) {
4709 mg_error(c, "keepalive");
4711 MG_VERBOSE(("%lu keepalive", c->id));
4712 tx_tcp(ifp, s->mac, rem_ip, TH_ACK, c->loc.port, c->rem.port,
4713 mg_htonl(s->seq - 1), mg_htonl(s->ack), "", 0);
4717 settmout(c, MIP_TTYPE_KEEPALIVE);
4722 // This function executes in interrupt context, thus it should copy data
4723 // somewhere fast. Note that newlib's malloc is not thread safe, thus use
4724 // our lock-free queue with preallocated buffer to copy data and return asap
4725 void mg_tcpip_qwrite(void *buf, size_t len, struct mg_tcpip_if *ifp) {
4727 if (mg_queue_book(&ifp->recv_queue, &p, len) >= len) {
4728 memcpy(p, buf, len);
4729 mg_queue_add(&ifp->recv_queue, len);
4736 void mg_tcpip_init(struct mg_mgr *mgr, struct mg_tcpip_if *ifp) {
4737 // If MAC address is not set, make a random one
4738 if (ifp->mac[0] == 0 && ifp->mac[1] == 0 && ifp->mac[2] == 0 &&
4739 ifp->mac[3] == 0 && ifp->mac[4] == 0 && ifp->mac[5] == 0) {
4740 ifp->mac[0] = 0x02; // Locally administered, unicast
4741 mg_random(&ifp->mac[1], sizeof(ifp->mac) - 1);
4742 MG_INFO(("MAC not set. Generated random: %M", mg_print_mac, ifp->mac));
4745 if (ifp->driver->init && !ifp->driver->init(ifp)) {
4746 MG_ERROR(("driver init failed"));
4748 size_t framesize = 1540;
4749 ifp->tx.ptr = (char *) calloc(1, framesize), ifp->tx.len = framesize;
4750 if (ifp->recv_queue.size == 0)
4751 ifp->recv_queue.size = ifp->driver->rx ? framesize : 8192;
4752 ifp->recv_queue.buf = (char *) calloc(1, ifp->recv_queue.size);
4753 ifp->timer_1000ms = mg_millis();
4756 mgr->extraconnsize = sizeof(struct connstate);
4757 if (ifp->ip == 0) ifp->enable_dhcp_client = true;
4758 memset(ifp->gwmac, 255, sizeof(ifp->gwmac)); // Set to broadcast
4759 mg_random(&ifp->eport, sizeof(ifp->eport)); // Random from 0 to 65535
4760 ifp->eport |= MG_EPHEMERAL_PORT_BASE; // Random from
4761 // MG_EPHEMERAL_PORT_BASE to 65535
4762 if (ifp->tx.ptr == NULL || ifp->recv_queue.buf == NULL) MG_ERROR(("OOM"));
4766 void mg_tcpip_free(struct mg_tcpip_if *ifp) {
4767 free(ifp->recv_queue.buf);
4768 free((char *) ifp->tx.ptr);
4771 int mg_mkpipe(struct mg_mgr *m, mg_event_handler_t fn, void *d, bool udp) {
4772 (void) m, (void) fn, (void) d, (void) udp;
4773 MG_ERROR(("Not implemented"));
4777 static void send_syn(struct mg_connection *c) {
4778 struct connstate *s = (struct connstate *) (c + 1);
4779 uint32_t isn = mg_htonl((uint32_t) mg_ntohs(c->loc.port));
4780 struct mg_tcpip_if *ifp = (struct mg_tcpip_if *) c->mgr->priv;
4782 memcpy(&rem_ip, c->rem.ip, sizeof(uint32_t));
4783 tx_tcp(ifp, s->mac, rem_ip, TH_SYN, c->loc.port, c->rem.port, isn, 0, NULL,
4787 void mg_connect_resolved(struct mg_connection *c) {
4788 struct mg_tcpip_if *ifp = (struct mg_tcpip_if *) c->mgr->priv;
4790 memcpy(&rem_ip, c->rem.ip, sizeof(uint32_t));
4791 c->is_resolving = 0;
4792 if (ifp->eport < MG_EPHEMERAL_PORT_BASE) ifp->eport = MG_EPHEMERAL_PORT_BASE;
4793 memcpy(c->loc.ip, &ifp->ip, sizeof(uint32_t));
4794 c->loc.port = mg_htons(ifp->eport++);
4795 MG_DEBUG(("%lu %M -> %M", c->id, mg_print_ip_port, &c->loc, mg_print_ip_port,
4797 mg_call(c, MG_EV_RESOLVE, NULL);
4798 if (((rem_ip & ifp->mask) == (ifp->ip & ifp->mask))) {
4799 // If we're in the same LAN, fire an ARP lookup.
4800 MG_DEBUG(("%lu ARP lookup...", c->id));
4801 arp_ask(ifp, rem_ip);
4802 settmout(c, MIP_TTYPE_ARP);
4803 c->is_arplooking = 1;
4804 c->is_connecting = 1;
4805 } else if (rem_ip == (ifp->ip | ~ifp->mask)) {
4806 struct connstate *s = (struct connstate *) (c + 1);
4807 memset(s->mac, 0xFF, sizeof(s->mac)); // local broadcast
4808 } else if ((*((uint8_t *) &rem_ip) & 0xE0) == 0xE0) {
4809 struct connstate *s = (struct connstate *) (c + 1); // 224 to 239, E0 to EF
4810 uint8_t mcastp[3] = {0x01, 0x00, 0x5E}; // multicast group
4811 memcpy(s->mac, mcastp, 3);
4812 memcpy(s->mac + 3, ((uint8_t *) &rem_ip) + 1, 3); // 23 LSb
4815 struct connstate *s = (struct connstate *) (c + 1);
4816 memcpy(s->mac, ifp->gwmac, sizeof(ifp->gwmac));
4818 mg_call(c, MG_EV_CONNECT, NULL);
4821 settmout(c, MIP_TTYPE_SYN);
4822 c->is_connecting = 1;
4827 bool mg_open_listener(struct mg_connection *c, const char *url) {
4828 c->loc.port = mg_htons(mg_url_port(url));
4832 static void write_conn(struct mg_connection *c) {
4833 long len = c->is_tls ? mg_tls_send(c, c->send.buf, c->send.len)
4834 : mg_io_send(c, c->send.buf, c->send.len);
4836 mg_iobuf_del(&c->send, 0, (size_t) len);
4837 mg_call(c, MG_EV_WRITE, &len);
4841 static void init_closure(struct mg_connection *c) {
4842 struct connstate *s = (struct connstate *) (c + 1);
4843 if (c->is_udp == false && c->is_listening == false &&
4844 c->is_connecting == false) { // For TCP conns,
4845 struct mg_tcpip_if *ifp =
4846 (struct mg_tcpip_if *) c->mgr->priv; // send TCP FIN
4848 memcpy(&rem_ip, c->rem.ip, sizeof(uint32_t));
4849 tx_tcp(ifp, s->mac, rem_ip, TH_FIN | TH_ACK, c->loc.port, c->rem.port,
4850 mg_htonl(s->seq), mg_htonl(s->ack), NULL, 0);
4851 settmout(c, MIP_TTYPE_FIN);
4855 static void close_conn(struct mg_connection *c) {
4856 struct connstate *s = (struct connstate *) (c + 1);
4857 mg_iobuf_free(&s->raw); // For TLS connections, release raw data
4861 static bool can_write(struct mg_connection *c) {
4862 return c->is_connecting == 0 && c->is_resolving == 0 && c->send.len > 0 &&
4863 c->is_tls_hs == 0 && c->is_arplooking == 0;
4866 void mg_mgr_poll(struct mg_mgr *mgr, int ms) {
4867 struct mg_connection *c, *tmp;
4868 uint64_t now = mg_millis();
4869 mg_tcpip_poll((struct mg_tcpip_if *) mgr->priv, now);
4870 mg_timer_poll(&mgr->timers, now);
4871 for (c = mgr->conns; c != NULL; c = tmp) {
4873 struct connstate *s = (struct connstate *) (c + 1);
4874 mg_call(c, MG_EV_POLL, &now);
4875 MG_VERBOSE(("%lu .. %c%c%c%c%c", c->id, c->is_tls ? 'T' : 't',
4876 c->is_connecting ? 'C' : 'c', c->is_tls_hs ? 'H' : 'h',
4877 c->is_resolving ? 'R' : 'r', c->is_closing ? 'C' : 'c'));
4878 if (c->is_tls_hs) mg_tls_handshake(c);
4879 if (can_write(c)) write_conn(c);
4880 if (c->is_draining && c->send.len == 0 && s->ttype != MIP_TTYPE_FIN)
4882 if (c->is_closing) close_conn(c);
4887 bool mg_send(struct mg_connection *c, const void *buf, size_t len) {
4888 struct mg_tcpip_if *ifp = (struct mg_tcpip_if *) c->mgr->priv;
4891 memcpy(&rem_ip, c->rem.ip, sizeof(uint32_t));
4892 if (ifp->ip == 0 || ifp->state != MG_TCPIP_STATE_READY) {
4893 mg_error(c, "net down");
4894 } else if (c->is_udp) {
4895 struct connstate *s = (struct connstate *) (c + 1);
4896 tx_udp(ifp, s->mac, ifp->ip, c->loc.port, rem_ip, c->rem.port, buf, len);
4899 res = mg_iobuf_add(&c->send, c->send.len, buf, len);
4903 #endif // MG_ENABLE_TCPIP
4905 #ifdef MG_ENABLE_LINES
4906 #line 1 "src/printf.c"
4912 size_t mg_queue_vprintf(struct mg_queue *q, const char *fmt, va_list *ap) {
4913 size_t len = mg_snprintf(NULL, 0, fmt, ap);
4915 if (len == 0 || mg_queue_book(q, &buf, len + 1) < len + 1) {
4916 len = 0; // Nah. Not enough space
4918 len = mg_vsnprintf((char *) buf, len + 1, fmt, ap);
4919 mg_queue_add(q, len);
4924 size_t mg_queue_printf(struct mg_queue *q, const char *fmt, ...) {
4928 len = mg_queue_vprintf(q, fmt, &ap);
4933 static void mg_pfn_iobuf_private(char ch, void *param, bool expand) {
4934 struct mg_iobuf *io = (struct mg_iobuf *) param;
4935 if (expand && io->len + 2 > io->size) mg_iobuf_resize(io, io->len + 2);
4936 if (io->len + 2 <= io->size) {
4937 io->buf[io->len++] = (uint8_t) ch;
4938 io->buf[io->len] = 0;
4939 } else if (io->len < io->size) {
4940 io->buf[io->len++] = 0; // Guarantee to 0-terminate
4944 static void mg_putchar_iobuf_static(char ch, void *param) {
4945 mg_pfn_iobuf_private(ch, param, false);
4948 void mg_pfn_iobuf(char ch, void *param) {
4949 mg_pfn_iobuf_private(ch, param, true);
4952 size_t mg_vsnprintf(char *buf, size_t len, const char *fmt, va_list *ap) {
4953 struct mg_iobuf io = {(uint8_t *) buf, len, 0, 0};
4954 size_t n = mg_vxprintf(mg_putchar_iobuf_static, &io, fmt, ap);
4955 if (n < len) buf[n] = '\0';
4959 size_t mg_snprintf(char *buf, size_t len, const char *fmt, ...) {
4963 n = mg_vsnprintf(buf, len, fmt, &ap);
4968 char *mg_vmprintf(const char *fmt, va_list *ap) {
4969 struct mg_iobuf io = {0, 0, 0, 256};
4970 mg_vxprintf(mg_pfn_iobuf, &io, fmt, ap);
4971 return (char *) io.buf;
4974 char *mg_mprintf(const char *fmt, ...) {
4978 s = mg_vmprintf(fmt, &ap);
4983 void mg_pfn_stdout(char c, void *param) {
4988 static size_t print_ip4(void (*out)(char, void *), void *arg, uint8_t *p) {
4989 return mg_xprintf(out, arg, "%d.%d.%d.%d", p[0], p[1], p[2], p[3]);
4992 static size_t print_ip6(void (*out)(char, void *), void *arg, uint16_t *p) {
4993 return mg_xprintf(out, arg, "[%x:%x:%x:%x:%x:%x:%x:%x]", mg_ntohs(p[0]),
4994 mg_ntohs(p[1]), mg_ntohs(p[2]), mg_ntohs(p[3]),
4995 mg_ntohs(p[4]), mg_ntohs(p[5]), mg_ntohs(p[6]),
4999 size_t mg_print_ip4(void (*out)(char, void *), void *arg, va_list *ap) {
5000 uint8_t *p = va_arg(*ap, uint8_t *);
5001 return print_ip4(out, arg, p);
5004 size_t mg_print_ip6(void (*out)(char, void *), void *arg, va_list *ap) {
5005 uint16_t *p = va_arg(*ap, uint16_t *);
5006 return print_ip6(out, arg, p);
5009 size_t mg_print_ip(void (*out)(char, void *), void *arg, va_list *ap) {
5010 struct mg_addr *addr = va_arg(*ap, struct mg_addr *);
5011 if (addr->is_ip6) return print_ip6(out, arg, (uint16_t *) addr->ip);
5012 return print_ip4(out, arg, (uint8_t *) &addr->ip);
5015 size_t mg_print_ip_port(void (*out)(char, void *), void *arg, va_list *ap) {
5016 struct mg_addr *a = va_arg(*ap, struct mg_addr *);
5017 return mg_xprintf(out, arg, "%M:%hu", mg_print_ip, a, mg_ntohs(a->port));
5020 size_t mg_print_mac(void (*out)(char, void *), void *arg, va_list *ap) {
5021 uint8_t *p = va_arg(*ap, uint8_t *);
5022 return mg_xprintf(out, arg, "%02x:%02x:%02x:%02x:%02x:%02x", p[0], p[1], p[2],
5026 static char mg_esc(int c, bool esc) {
5027 const char *p, *esc1 = "\b\f\n\r\t\\\"", *esc2 = "bfnrt\\\"";
5028 for (p = esc ? esc1 : esc2; *p != '\0'; p++) {
5029 if (*p == c) return esc ? esc2[p - esc1] : esc1[p - esc2];
5034 static char mg_escape(int c) {
5035 return mg_esc(c, true);
5038 static size_t qcpy(void (*out)(char, void *), void *ptr, char *buf,
5040 size_t i = 0, extra = 0;
5041 for (i = 0; i < len && buf[i] != '\0'; i++) {
5042 char c = mg_escape(buf[i]);
5044 out('\\', ptr), out(c, ptr), extra++;
5052 static size_t bcpy(void (*out)(char, void *), void *arg, uint8_t *buf,
5056 "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
5057 for (i = 0; i < len; i += 3) {
5058 uint8_t c1 = buf[i], c2 = i + 1 < len ? buf[i + 1] : 0,
5059 c3 = i + 2 < len ? buf[i + 2] : 0;
5060 char tmp[4] = {t[c1 >> 2], t[(c1 & 3) << 4 | (c2 >> 4)], '=', '='};
5061 if (i + 1 < len) tmp[2] = t[(c2 & 15) << 2 | (c3 >> 6)];
5062 if (i + 2 < len) tmp[3] = t[c3 & 63];
5063 for (j = 0; j < sizeof(tmp) && tmp[j] != '\0'; j++) out(tmp[j], arg);
5069 size_t mg_print_hex(void (*out)(char, void *), void *arg, va_list *ap) {
5070 size_t bl = (size_t) va_arg(*ap, int);
5071 uint8_t *p = va_arg(*ap, uint8_t *);
5072 const char *hex = "0123456789abcdef";
5074 for (j = 0; j < bl; j++) {
5075 out(hex[(p[j] >> 4) & 0x0F], arg);
5076 out(hex[p[j] & 0x0F], arg);
5080 size_t mg_print_base64(void (*out)(char, void *), void *arg, va_list *ap) {
5081 size_t len = (size_t) va_arg(*ap, int);
5082 uint8_t *buf = va_arg(*ap, uint8_t *);
5083 return bcpy(out, arg, buf, len);
5086 size_t mg_print_esc(void (*out)(char, void *), void *arg, va_list *ap) {
5087 size_t len = (size_t) va_arg(*ap, int);
5088 char *p = va_arg(*ap, char *);
5089 if (len == 0) len = p == NULL ? 0 : strlen(p);
5090 return qcpy(out, arg, p, len);
5093 #ifdef MG_ENABLE_LINES
5094 #line 1 "src/queue.c"
5099 #if defined(__GNUC__) || defined(__clang__)
5100 #define MG_MEMORY_BARRIER() __sync_synchronize()
5101 #elif defined(_MSC_VER) && _MSC_VER >= 1700
5102 #define MG_MEMORY_BARRIER() MemoryBarrier()
5103 #elif !defined(MG_MEMORY_BARRIER)
5104 #define MG_MEMORY_BARRIER()
5107 // Every message in a queue is prepended by a 32-bit message length (ML).
5108 // If ML is 0, then it is the end, and reader must wrap to the beginning.
5110 // Queue when q->tail <= q->head:
5111 // |----- free -----| ML | message1 | ML | message2 | ----- free ------|
5113 // buf tail head len
5115 // Queue when q->tail > q->head:
5116 // | ML | message2 |----- free ------| ML | message1 | 0 |---- free ----|
5118 // buf head tail len
5120 void mg_queue_init(struct mg_queue *q, char *buf, size_t size) {
5123 q->head = q->tail = 0;
5126 static size_t mg_queue_read_len(struct mg_queue *q) {
5128 MG_MEMORY_BARRIER();
5129 memcpy(&n, q->buf + q->tail, sizeof(n));
5130 assert(q->tail + n + sizeof(n) <= q->size);
5134 static void mg_queue_write_len(struct mg_queue *q, size_t len) {
5135 uint32_t n = (uint32_t) len;
5136 memcpy(q->buf + q->head, &n, sizeof(n));
5137 MG_MEMORY_BARRIER();
5140 size_t mg_queue_book(struct mg_queue *q, char **buf, size_t len) {
5141 size_t space = 0, hs = sizeof(uint32_t) * 2; // *2 is for the 0 marker
5142 if (q->head >= q->tail && q->head + len + hs <= q->size) {
5143 space = q->size - q->head - hs; // There is enough space
5144 } else if (q->head >= q->tail && q->tail > hs) {
5145 mg_queue_write_len(q, 0); // Not enough space ahead
5146 q->head = 0; // Wrap head to the beginning
5148 if (q->head + hs + len < q->tail) space = q->tail - q->head - hs;
5149 if (buf != NULL) *buf = q->buf + q->head + sizeof(uint32_t);
5153 size_t mg_queue_next(struct mg_queue *q, char **buf) {
5155 if (q->tail != q->head) {
5156 len = mg_queue_read_len(q);
5157 if (len == 0) { // Zero (head wrapped) ?
5158 q->tail = 0; // Reset tail to the start
5159 if (q->head > q->tail) len = mg_queue_read_len(q); // Read again
5162 if (buf != NULL) *buf = q->buf + q->tail + sizeof(uint32_t);
5163 assert(q->tail + len <= q->size);
5167 void mg_queue_add(struct mg_queue *q, size_t len) {
5169 mg_queue_write_len(q, len);
5170 assert(q->head + sizeof(uint32_t) * 2 + len <= q->size);
5171 q->head += len + sizeof(uint32_t);
5174 void mg_queue_del(struct mg_queue *q, size_t len) {
5175 q->tail += len + sizeof(uint32_t);
5176 assert(q->tail + sizeof(uint32_t) <= q->size);
5179 #ifdef MG_ENABLE_LINES
5185 void mg_rpc_add(struct mg_rpc **head, struct mg_str method,
5186 void (*fn)(struct mg_rpc_req *), void *fn_data) {
5187 struct mg_rpc *rpc = (struct mg_rpc *) calloc(1, sizeof(*rpc));
5189 rpc->method = mg_strdup(method), rpc->fn = fn, rpc->fn_data = fn_data;
5190 rpc->next = *head, *head = rpc;
5194 void mg_rpc_del(struct mg_rpc **head, void (*fn)(struct mg_rpc_req *)) {
5196 while ((r = *head) != NULL) {
5197 if (r->fn == fn || fn == NULL) {
5199 free((void *) r->method.ptr);
5202 head = &(*head)->next;
5207 static void mg_rpc_call(struct mg_rpc_req *r, struct mg_str method) {
5208 struct mg_rpc *h = r->head == NULL ? NULL : *r->head;
5209 while (h != NULL && !mg_match(method, h->method, NULL)) h = h->next;
5214 mg_rpc_err(r, -32601, "\"%.*s not found\"", (int) method.len, method.ptr);
5218 void mg_rpc_process(struct mg_rpc_req *r) {
5219 int len, off = mg_json_get(r->frame, "$.method", &len);
5220 if (off > 0 && r->frame.ptr[off] == '"') {
5221 struct mg_str method = mg_str_n(&r->frame.ptr[off + 1], (size_t) len - 2);
5222 mg_rpc_call(r, method);
5223 } else if ((off = mg_json_get(r->frame, "$.result", &len)) > 0 ||
5224 (off = mg_json_get(r->frame, "$.error", &len)) > 0) {
5225 mg_rpc_call(r, mg_str("")); // JSON response! call "" method handler
5227 mg_rpc_err(r, -32700, "%m", mg_print_esc, (int) r->frame.len,
5228 r->frame.ptr); // Invalid
5232 void mg_rpc_vok(struct mg_rpc_req *r, const char *fmt, va_list *ap) {
5233 int len, off = mg_json_get(r->frame, "$.id", &len);
5235 mg_xprintf(r->pfn, r->pfn_data, "{%m:%.*s,%m:", mg_print_esc, 0, "id", len,
5236 &r->frame.ptr[off], mg_print_esc, 0, "result");
5237 mg_vxprintf(r->pfn, r->pfn_data, fmt == NULL ? "null" : fmt, ap);
5238 mg_xprintf(r->pfn, r->pfn_data, "}");
5242 void mg_rpc_ok(struct mg_rpc_req *r, const char *fmt, ...) {
5245 mg_rpc_vok(r, fmt, &ap);
5249 void mg_rpc_verr(struct mg_rpc_req *r, int code, const char *fmt, va_list *ap) {
5250 int len, off = mg_json_get(r->frame, "$.id", &len);
5251 mg_xprintf(r->pfn, r->pfn_data, "{");
5253 mg_xprintf(r->pfn, r->pfn_data, "%m:%.*s,", mg_print_esc, 0, "id", len,
5254 &r->frame.ptr[off]);
5256 mg_xprintf(r->pfn, r->pfn_data, "%m:{%m:%d,%m:", mg_print_esc, 0, "error",
5257 mg_print_esc, 0, "code", code, mg_print_esc, 0, "message");
5258 mg_vxprintf(r->pfn, r->pfn_data, fmt == NULL ? "null" : fmt, ap);
5259 mg_xprintf(r->pfn, r->pfn_data, "}}");
5262 void mg_rpc_err(struct mg_rpc_req *r, int code, const char *fmt, ...) {
5265 mg_rpc_verr(r, code, fmt, &ap);
5269 static size_t print_methods(mg_pfn_t pfn, void *pfn_data, va_list *ap) {
5270 struct mg_rpc *h, **head = (struct mg_rpc **) va_arg(*ap, void **);
5272 for (h = *head; h != NULL; h = h->next) {
5273 if (h->method.len == 0) continue; // Ignore response handler
5274 len += mg_xprintf(pfn, pfn_data, "%s%m", h == *head ? "" : ",",
5275 mg_print_esc, (int) h->method.len, h->method.ptr);
5280 void mg_rpc_list(struct mg_rpc_req *r) {
5281 mg_rpc_ok(r, "[%M]", print_methods, r->head);
5284 #ifdef MG_ENABLE_LINES
5285 #line 1 "src/sha1.c"
5287 /* Copyright(c) By Steve Reid <steve@edmweb.com> */
5288 /* 100% Public Domain */
5292 union char64long16 {
5293 unsigned char c[64];
5297 #define rol(value, bits) (((value) << (bits)) | ((value) >> (32 - (bits))))
5299 static uint32_t blk0(union char64long16 *block, int i) {
5300 if (MG_BIG_ENDIAN) {
5302 block->l[i] = (rol(block->l[i], 24) & 0xFF00FF00) |
5303 (rol(block->l[i], 8) & 0x00FF00FF);
5308 /* Avoid redefine warning (ARM /usr/include/sys/ucontext.h define R0~R4) */
5317 (block->l[i & 15] = rol(block->l[(i + 13) & 15] ^ block->l[(i + 8) & 15] ^ \
5318 block->l[(i + 2) & 15] ^ block->l[i & 15], \
5320 #define R0(v, w, x, y, z, i) \
5321 z += ((w & (x ^ y)) ^ y) + blk0(block, i) + 0x5A827999 + rol(v, 5); \
5323 #define R1(v, w, x, y, z, i) \
5324 z += ((w & (x ^ y)) ^ y) + blk(i) + 0x5A827999 + rol(v, 5); \
5326 #define R2(v, w, x, y, z, i) \
5327 z += (w ^ x ^ y) + blk(i) + 0x6ED9EBA1 + rol(v, 5); \
5329 #define R3(v, w, x, y, z, i) \
5330 z += (((w | x) & y) | (w & x)) + blk(i) + 0x8F1BBCDC + rol(v, 5); \
5332 #define R4(v, w, x, y, z, i) \
5333 z += (w ^ x ^ y) + blk(i) + 0xCA62C1D6 + rol(v, 5); \
5336 static void mg_sha1_transform(uint32_t state[5],
5337 const unsigned char *buffer) {
5338 uint32_t a, b, c, d, e;
5339 union char64long16 block[1];
5341 memcpy(block, buffer, 64);
5347 R0(a, b, c, d, e, 0);
5348 R0(e, a, b, c, d, 1);
5349 R0(d, e, a, b, c, 2);
5350 R0(c, d, e, a, b, 3);
5351 R0(b, c, d, e, a, 4);
5352 R0(a, b, c, d, e, 5);
5353 R0(e, a, b, c, d, 6);
5354 R0(d, e, a, b, c, 7);
5355 R0(c, d, e, a, b, 8);
5356 R0(b, c, d, e, a, 9);
5357 R0(a, b, c, d, e, 10);
5358 R0(e, a, b, c, d, 11);
5359 R0(d, e, a, b, c, 12);
5360 R0(c, d, e, a, b, 13);
5361 R0(b, c, d, e, a, 14);
5362 R0(a, b, c, d, e, 15);
5363 R1(e, a, b, c, d, 16);
5364 R1(d, e, a, b, c, 17);
5365 R1(c, d, e, a, b, 18);
5366 R1(b, c, d, e, a, 19);
5367 R2(a, b, c, d, e, 20);
5368 R2(e, a, b, c, d, 21);
5369 R2(d, e, a, b, c, 22);
5370 R2(c, d, e, a, b, 23);
5371 R2(b, c, d, e, a, 24);
5372 R2(a, b, c, d, e, 25);
5373 R2(e, a, b, c, d, 26);
5374 R2(d, e, a, b, c, 27);
5375 R2(c, d, e, a, b, 28);
5376 R2(b, c, d, e, a, 29);
5377 R2(a, b, c, d, e, 30);
5378 R2(e, a, b, c, d, 31);
5379 R2(d, e, a, b, c, 32);
5380 R2(c, d, e, a, b, 33);
5381 R2(b, c, d, e, a, 34);
5382 R2(a, b, c, d, e, 35);
5383 R2(e, a, b, c, d, 36);
5384 R2(d, e, a, b, c, 37);
5385 R2(c, d, e, a, b, 38);
5386 R2(b, c, d, e, a, 39);
5387 R3(a, b, c, d, e, 40);
5388 R3(e, a, b, c, d, 41);
5389 R3(d, e, a, b, c, 42);
5390 R3(c, d, e, a, b, 43);
5391 R3(b, c, d, e, a, 44);
5392 R3(a, b, c, d, e, 45);
5393 R3(e, a, b, c, d, 46);
5394 R3(d, e, a, b, c, 47);
5395 R3(c, d, e, a, b, 48);
5396 R3(b, c, d, e, a, 49);
5397 R3(a, b, c, d, e, 50);
5398 R3(e, a, b, c, d, 51);
5399 R3(d, e, a, b, c, 52);
5400 R3(c, d, e, a, b, 53);
5401 R3(b, c, d, e, a, 54);
5402 R3(a, b, c, d, e, 55);
5403 R3(e, a, b, c, d, 56);
5404 R3(d, e, a, b, c, 57);
5405 R3(c, d, e, a, b, 58);
5406 R3(b, c, d, e, a, 59);
5407 R4(a, b, c, d, e, 60);
5408 R4(e, a, b, c, d, 61);
5409 R4(d, e, a, b, c, 62);
5410 R4(c, d, e, a, b, 63);
5411 R4(b, c, d, e, a, 64);
5412 R4(a, b, c, d, e, 65);
5413 R4(e, a, b, c, d, 66);
5414 R4(d, e, a, b, c, 67);
5415 R4(c, d, e, a, b, 68);
5416 R4(b, c, d, e, a, 69);
5417 R4(a, b, c, d, e, 70);
5418 R4(e, a, b, c, d, 71);
5419 R4(d, e, a, b, c, 72);
5420 R4(c, d, e, a, b, 73);
5421 R4(b, c, d, e, a, 74);
5422 R4(a, b, c, d, e, 75);
5423 R4(e, a, b, c, d, 76);
5424 R4(d, e, a, b, c, 77);
5425 R4(c, d, e, a, b, 78);
5426 R4(b, c, d, e, a, 79);
5432 /* Erase working structures. The order of operations is important,
5433 * used to ensure that compiler doesn't optimize those out. */
5434 memset(block, 0, sizeof(block));
5435 a = b = c = d = e = 0;
5443 void mg_sha1_init(mg_sha1_ctx *context) {
5444 context->state[0] = 0x67452301;
5445 context->state[1] = 0xEFCDAB89;
5446 context->state[2] = 0x98BADCFE;
5447 context->state[3] = 0x10325476;
5448 context->state[4] = 0xC3D2E1F0;
5449 context->count[0] = context->count[1] = 0;
5452 void mg_sha1_update(mg_sha1_ctx *context, const unsigned char *data,
5456 j = context->count[0];
5457 if ((context->count[0] += (uint32_t) len << 3) < j) context->count[1]++;
5458 context->count[1] += (uint32_t) (len >> 29);
5460 if ((j + len) > 63) {
5461 memcpy(&context->buffer[j], data, (i = 64 - j));
5462 mg_sha1_transform(context->state, context->buffer);
5463 for (; i + 63 < len; i += 64) {
5464 mg_sha1_transform(context->state, &data[i]);
5469 memcpy(&context->buffer[j], &data[i], len - i);
5472 void mg_sha1_final(unsigned char digest[20], mg_sha1_ctx *context) {
5474 unsigned char finalcount[8], c;
5476 for (i = 0; i < 8; i++) {
5477 finalcount[i] = (unsigned char) ((context->count[(i >= 4 ? 0 : 1)] >>
5478 ((3 - (i & 3)) * 8)) &
5482 mg_sha1_update(context, &c, 1);
5483 while ((context->count[0] & 504) != 448) {
5485 mg_sha1_update(context, &c, 1);
5487 mg_sha1_update(context, finalcount, 8);
5488 for (i = 0; i < 20; i++) {
5490 (unsigned char) ((context->state[i >> 2] >> ((3 - (i & 3)) * 8)) & 255);
5492 memset(context, '\0', sizeof(*context));
5493 memset(&finalcount, '\0', sizeof(finalcount));
5496 #ifdef MG_ENABLE_LINES
5497 #line 1 "src/sntp.c"
5505 #define SNTP_TIME_OFFSET 2208988800U // (1970 - 1900) in seconds
5506 #define SNTP_MAX_FRAC 4294967295.0 // 2 ** 32 - 1
5508 static int64_t gettimestamp(const uint32_t *data) {
5509 uint32_t sec = mg_ntohl(data[0]), frac = mg_ntohl(data[1]);
5510 if (sec) sec -= SNTP_TIME_OFFSET;
5511 return ((int64_t) sec) * 1000 + (int64_t) (frac / SNTP_MAX_FRAC * 1000.0);
5514 int64_t mg_sntp_parse(const unsigned char *buf, size_t len) {
5516 int mode = len > 0 ? buf[0] & 7 : 0;
5517 int version = len > 0 ? (buf[0] >> 3) & 7 : 0;
5519 MG_ERROR(("%s", "corrupt packet"));
5520 } else if (mode != 4 && mode != 5) {
5521 MG_ERROR(("%s", "not a server reply"));
5522 } else if (buf[1] == 0) {
5523 MG_ERROR(("%s", "server sent a kiss of death"));
5524 } else if (version == 4 || version == 3) {
5525 // int64_t ref = gettimestamp((uint32_t *) &buf[16]);
5526 int64_t t0 = gettimestamp((uint32_t *) &buf[24]);
5527 int64_t t1 = gettimestamp((uint32_t *) &buf[32]);
5528 int64_t t2 = gettimestamp((uint32_t *) &buf[40]);
5529 int64_t t3 = (int64_t) mg_millis();
5530 int64_t delta = (t3 - t0) - (t2 - t1);
5531 MG_VERBOSE(("%lld %lld %lld %lld delta:%lld", t0, t1, t2, t3, delta));
5532 res = t2 + delta / 2;
5534 MG_ERROR(("unexpected version: %d", version));
5539 static void sntp_cb(struct mg_connection *c, int ev, void *evd, void *fnd) {
5540 if (ev == MG_EV_READ) {
5541 int64_t milliseconds = mg_sntp_parse(c->recv.buf, c->recv.len);
5542 if (milliseconds > 0) {
5543 MG_INFO(("%lu got time: %lld ms from epoch", c->id, milliseconds));
5544 mg_call(c, MG_EV_SNTP_TIME, (uint64_t *) &milliseconds);
5545 MG_VERBOSE(("%u.%u", (unsigned) (milliseconds / 1000),
5546 (unsigned) (milliseconds % 1000)));
5548 mg_iobuf_del(&c->recv, 0, c->recv.len); // Free receive buffer
5549 } else if (ev == MG_EV_CONNECT) {
5551 } else if (ev == MG_EV_CLOSE) {
5557 void mg_sntp_request(struct mg_connection *c) {
5558 if (c->is_resolving) {
5559 MG_ERROR(("%lu wait until resolved", c->id));
5561 int64_t now = (int64_t) mg_millis(); // Use int64_t, for vc98
5562 uint8_t buf[48] = {0};
5563 uint32_t *t = (uint32_t *) &buf[40];
5564 double frac = ((double) (now % 1000)) / 1000.0 * SNTP_MAX_FRAC;
5565 buf[0] = (0 << 6) | (4 << 3) | 3;
5566 t[0] = mg_htonl((uint32_t) (now / 1000) + SNTP_TIME_OFFSET);
5567 t[1] = mg_htonl((uint32_t) frac);
5568 mg_send(c, buf, sizeof(buf));
5572 struct mg_connection *mg_sntp_connect(struct mg_mgr *mgr, const char *url,
5573 mg_event_handler_t fn, void *fnd) {
5574 struct mg_connection *c = NULL;
5575 if (url == NULL) url = "udp://time.google.com:123";
5576 if ((c = mg_connect(mgr, url, fn, fnd)) != NULL) c->pfn = sntp_cb;
5580 #ifdef MG_ENABLE_LINES
5581 #line 1 "src/sock.c"
5594 #if MG_ENABLE_SOCKET
5597 #define closesocket(x) close(x)
5600 #define FD(c_) ((MG_SOCKET_TYPE) (size_t) (c_)->fd)
5601 #define S2PTR(s_) ((void *) (size_t) (s_))
5603 #ifndef MSG_NONBLOCKING
5604 #define MSG_NONBLOCKING 0
5612 #define MG_SOCK_ERR(errcode) ((errcode) < 0 ? errno : 0)
5615 #ifndef MG_SOCK_INTR
5616 #define MG_SOCK_INTR(fd) (fd == MG_INVALID_SOCKET && MG_SOCK_ERR(-1) == EINTR)
5619 #ifndef MG_SOCK_PENDING
5620 #define MG_SOCK_PENDING(errcode) \
5621 (((errcode) < 0) && (errno == EINPROGRESS || errno == EWOULDBLOCK))
5624 #ifndef MG_SOCK_RESET
5625 #define MG_SOCK_RESET(errcode) \
5626 (((errcode) < 0) && (errno == EPIPE || errno == ECONNRESET))
5631 struct sockaddr_in sin;
5633 struct sockaddr_in6 sin6;
5637 static socklen_t tousa(struct mg_addr *a, union usa *usa) {
5638 socklen_t len = sizeof(usa->sin);
5639 memset(usa, 0, sizeof(*usa));
5640 usa->sin.sin_family = AF_INET;
5641 usa->sin.sin_port = a->port;
5642 memcpy(&usa->sin.sin_addr, a->ip, sizeof(uint32_t));
5645 usa->sin.sin_family = AF_INET6;
5646 usa->sin6.sin6_port = a->port;
5647 memcpy(&usa->sin6.sin6_addr, a->ip, sizeof(a->ip));
5648 len = sizeof(usa->sin6);
5654 static void tomgaddr(union usa *usa, struct mg_addr *a, bool is_ip6) {
5656 a->port = usa->sin.sin_port;
5657 memcpy(&a->ip, &usa->sin.sin_addr, sizeof(uint32_t));
5660 memcpy(a->ip, &usa->sin6.sin6_addr, sizeof(a->ip));
5661 a->port = usa->sin6.sin6_port;
5666 static void setlocaddr(MG_SOCKET_TYPE fd, struct mg_addr *addr) {
5668 socklen_t n = sizeof(usa);
5669 if (getsockname(fd, &usa.sa, &n) == 0) {
5670 tomgaddr(&usa, addr, n != sizeof(usa.sin));
5674 static void iolog(struct mg_connection *c, char *buf, long n, bool r) {
5675 if (n == MG_IO_WAIT) {
5677 } else if (n <= 0) {
5678 c->is_closing = 1; // Termination. Don't call mg_error(): #1529
5680 if (c->is_hexdumping) {
5682 socklen_t slen = sizeof(usa.sin);
5683 if (getsockname(FD(c), &usa.sa, &slen) < 0) (void) 0; // Ignore result
5684 MG_INFO(("\n-- %lu %M %s %M %ld", c->id, mg_print_ip_port, &c->loc,
5685 r ? "<-" : "->", mg_print_ip_port, &c->rem, n));
5687 mg_hexdump(buf, (size_t) n);
5690 c->recv.len += (size_t) n;
5691 mg_call(c, MG_EV_READ, &n);
5693 mg_iobuf_del(&c->send, 0, (size_t) n);
5694 // if (c->send.len == 0) mg_iobuf_resize(&c->send, 0);
5695 if (c->send.len == 0) {
5698 mg_call(c, MG_EV_WRITE, &n);
5703 long mg_io_send(struct mg_connection *c, const void *buf, size_t len) {
5707 socklen_t slen = tousa(&c->rem, &usa);
5708 n = sendto(FD(c), (char *) buf, len, 0, &usa.sa, slen);
5709 if (n > 0) setlocaddr(FD(c), &c->loc);
5711 n = send(FD(c), (char *) buf, len, MSG_NONBLOCKING);
5713 if (MG_SOCK_PENDING(n)) return MG_IO_WAIT;
5714 if (MG_SOCK_RESET(n)) return MG_IO_RESET;
5715 if (n <= 0) return MG_IO_ERR;
5719 bool mg_send(struct mg_connection *c, const void *buf, size_t len) {
5721 long n = mg_io_send(c, buf, len);
5722 MG_DEBUG(("%lu %p %d:%d %ld err %d", c->id, c->fd, (int) c->send.len,
5723 (int) c->recv.len, n, MG_SOCK_ERR(n)));
5724 iolog(c, (char *) buf, n, false);
5727 return mg_iobuf_add(&c->send, c->send.len, buf, len);
5731 static void mg_set_non_blocking_mode(MG_SOCKET_TYPE fd) {
5732 #if defined(MG_CUSTOM_NONBLOCK)
5733 MG_CUSTOM_NONBLOCK(fd);
5734 #elif MG_ARCH == MG_ARCH_WIN32 && MG_ENABLE_WINSOCK
5735 unsigned long on = 1;
5736 ioctlsocket(fd, FIONBIO, &on);
5738 unsigned long on = 1;
5739 ioctlsocket(fd, FIONBIO, &on);
5740 #elif MG_ENABLE_FREERTOS_TCP
5741 const BaseType_t off = 0;
5742 if (setsockopt(fd, 0, FREERTOS_SO_RCVTIMEO, &off, sizeof(off)) != 0) (void) 0;
5743 if (setsockopt(fd, 0, FREERTOS_SO_SNDTIMEO, &off, sizeof(off)) != 0) (void) 0;
5744 #elif MG_ENABLE_LWIP
5745 lwip_fcntl(fd, F_SETFL, O_NONBLOCK);
5746 #elif MG_ARCH == MG_ARCH_AZURERTOS
5747 fcntl(fd, F_SETFL, O_NONBLOCK);
5748 #elif MG_ARCH == MG_ARCH_TIRTOS
5750 setsockopt(fd, SOL_SOCKET, SO_BLOCKING, &val, sizeof(val));
5751 // SPRU524J section 3.3.3 page 63, SO_SNDLOWAT
5752 int sz = sizeof(val);
5753 getsockopt(fd, SOL_SOCKET, SO_SNDBUF, &val, &sz);
5754 val /= 2; // set send low-water mark at half send buffer size
5755 setsockopt(fd, SOL_SOCKET, SO_SNDLOWAT, &val, sizeof(val));
5757 fcntl(fd, F_SETFL, fcntl(fd, F_GETFL, 0) | O_NONBLOCK); // Non-blocking mode
5758 fcntl(fd, F_SETFD, FD_CLOEXEC); // Set close-on-exec
5762 bool mg_open_listener(struct mg_connection *c, const char *url) {
5763 MG_SOCKET_TYPE fd = MG_INVALID_SOCKET;
5764 bool success = false;
5765 c->loc.port = mg_htons(mg_url_port(url));
5766 if (!mg_aton(mg_url_host(url), &c->loc)) {
5767 MG_ERROR(("invalid listening URL: %s", url));
5770 socklen_t slen = tousa(&c->loc, &usa);
5771 int rc, on = 1, af = c->loc.is_ip6 ? AF_INET6 : AF_INET;
5772 int type = strncmp(url, "udp:", 4) == 0 ? SOCK_DGRAM : SOCK_STREAM;
5773 int proto = type == SOCK_DGRAM ? IPPROTO_UDP : IPPROTO_TCP;
5776 if ((fd = socket(af, type, proto)) == MG_INVALID_SOCKET) {
5777 MG_ERROR(("socket: %d", MG_SOCK_ERR(-1)));
5778 #if defined(SO_EXCLUSIVEADDRUSE)
5779 } else if ((rc = setsockopt(fd, SOL_SOCKET, SO_EXCLUSIVEADDRUSE,
5780 (char *) &on, sizeof(on))) != 0) {
5781 // "Using SO_REUSEADDR and SO_EXCLUSIVEADDRUSE"
5782 MG_ERROR(("setsockopt(SO_EXCLUSIVEADDRUSE): %d %d", on, MG_SOCK_ERR(rc)));
5783 #elif defined(SO_REUSEADDR) && (!defined(LWIP_SOCKET) || SO_REUSE)
5784 } else if ((rc = setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, (char *) &on,
5785 sizeof(on))) != 0) {
5786 // 1. SO_REUSEADDR semantics on UNIX and Windows is different. On
5787 // Windows, SO_REUSEADDR allows to bind a socket to a port without error
5788 // even if the port is already open by another program. This is not the
5789 // behavior SO_REUSEADDR was designed for, and leads to hard-to-track
5790 // failure scenarios.
5792 // 2. For LWIP, SO_REUSEADDR should be explicitly enabled by defining
5793 // SO_REUSE = 1 in lwipopts.h, otherwise the code below will compile but
5794 // won't work! (setsockopt will return EINVAL)
5795 MG_ERROR(("setsockopt(SO_REUSEADDR): %d", MG_SOCK_ERR(rc)));
5797 #if defined(IPV6_V6ONLY)
5798 } else if (c->loc.is_ip6 &&
5799 (rc = setsockopt(fd, IPPROTO_IPV6, IPV6_V6ONLY, (char *) &on,
5800 sizeof(on))) != 0) {
5801 // See #2089. Allow to bind v4 and v6 sockets on the same port
5802 MG_ERROR(("setsockopt(IPV6_V6ONLY): %d", MG_SOCK_ERR(rc)));
5804 } else if ((rc = bind(fd, &usa.sa, slen)) != 0) {
5805 MG_ERROR(("bind: %d", MG_SOCK_ERR(rc)));
5806 } else if ((type == SOCK_STREAM &&
5807 (rc = listen(fd, MG_SOCK_LISTEN_BACKLOG_SIZE)) != 0)) {
5808 // NOTE(lsm): FreeRTOS uses backlog value as a connection limit
5809 // In case port was set to 0, get the real port number
5810 MG_ERROR(("listen: %d", MG_SOCK_ERR(rc)));
5812 setlocaddr(fd, &c->loc);
5813 mg_set_non_blocking_mode(fd);
5819 if (success == false && fd != MG_INVALID_SOCKET) closesocket(fd);
5823 long mg_io_recv(struct mg_connection *c, void *buf, size_t len) {
5827 socklen_t slen = tousa(&c->rem, &usa);
5828 n = recvfrom(FD(c), (char *) buf, len, 0, &usa.sa, &slen);
5829 if (n > 0) tomgaddr(&usa, &c->rem, slen != sizeof(usa.sin));
5831 n = recv(FD(c), (char *) buf, len, MSG_NONBLOCKING);
5833 if (MG_SOCK_PENDING(n)) return MG_IO_WAIT;
5834 if (MG_SOCK_RESET(n)) return MG_IO_RESET;
5835 if (n <= 0) return MG_IO_ERR;
5839 // NOTE(lsm): do only one iteration of reads, cause some systems
5840 // (e.g. FreeRTOS stack) return 0 instead of -1/EWOULDBLOCK when no data
5841 static void read_conn(struct mg_connection *c) {
5843 if (c->recv.len >= MG_MAX_RECV_SIZE) {
5844 mg_error(c, "max_recv_buf_size reached");
5845 } else if (c->recv.size <= c->recv.len &&
5846 !mg_iobuf_resize(&c->recv, c->recv.size + MG_IO_SIZE)) {
5849 char *buf = (char *) &c->recv.buf[c->recv.len];
5850 size_t len = c->recv.size - c->recv.len;
5851 n = c->is_tls ? mg_tls_recv(c, buf, len) : mg_io_recv(c, buf, len);
5852 MG_DEBUG(("%lu %p snd %ld/%ld rcv %ld/%ld n=%ld err=%d", c->id, c->fd,
5853 (long) c->send.len, (long) c->send.size, (long) c->recv.len,
5854 (long) c->recv.size, n, MG_SOCK_ERR(n)));
5855 iolog(c, buf, n, true);
5859 static void write_conn(struct mg_connection *c) {
5860 char *buf = (char *) c->send.buf;
5861 size_t len = c->send.len;
5862 long n = c->is_tls ? mg_tls_send(c, buf, len) : mg_io_send(c, buf, len);
5863 MG_DEBUG(("%lu %p snd %ld/%ld rcv %ld/%ld n=%ld err=%d", c->id, c->fd,
5864 (long) c->send.len, (long) c->send.size, (long) c->recv.len,
5865 (long) c->recv.size, n, MG_SOCK_ERR(n)));
5866 iolog(c, buf, n, false);
5869 static void close_conn(struct mg_connection *c) {
5870 if (FD(c) != MG_INVALID_SOCKET) {
5872 epoll_ctl(c->mgr->epoll_fd, EPOLL_CTL_DEL, FD(c), NULL);
5875 #if MG_ENABLE_FREERTOS_TCP
5876 FreeRTOS_FD_CLR(c->fd, c->mgr->ss, eSELECT_ALL);
5882 static void connect_conn(struct mg_connection *c) {
5884 socklen_t n = sizeof(usa);
5885 // Use getpeername() to test whether we have connected
5886 if (getpeername(FD(c), &usa.sa, &n) == 0) {
5887 c->is_connecting = 0;
5888 mg_call(c, MG_EV_CONNECT, NULL);
5890 if (c->is_tls_hs) mg_tls_handshake(c);
5892 mg_error(c, "socket error");
5896 static void setsockopts(struct mg_connection *c) {
5897 #if MG_ENABLE_FREERTOS_TCP || MG_ARCH == MG_ARCH_AZURERTOS || \
5898 MG_ARCH == MG_ARCH_TIRTOS
5902 #if !defined(SOL_TCP)
5903 #define SOL_TCP IPPROTO_TCP
5905 if (setsockopt(FD(c), SOL_TCP, TCP_NODELAY, (char *) &on, sizeof(on)) != 0)
5907 if (setsockopt(FD(c), SOL_SOCKET, SO_KEEPALIVE, (char *) &on, sizeof(on)) !=
5913 void mg_connect_resolved(struct mg_connection *c) {
5914 int type = c->is_udp ? SOCK_DGRAM : SOCK_STREAM;
5915 int rc, af = c->rem.is_ip6 ? AF_INET6 : AF_INET; // c->rem has resolved IP
5916 c->fd = S2PTR(socket(af, type, 0)); // Create outbound socket
5917 c->is_resolving = 0; // Clear resolving flag
5918 if (FD(c) == MG_INVALID_SOCKET) {
5919 mg_error(c, "socket(): %d", MG_SOCK_ERR(-1));
5920 } else if (c->is_udp) {
5922 #if MG_ARCH == MG_ARCH_TIRTOS
5923 union usa usa; // TI-RTOS NDK requires binding to receive on UDP sockets
5924 socklen_t slen = tousa(&c->loc, &usa);
5925 if ((rc = bind(c->fd, &usa.sa, slen)) != 0)
5926 MG_ERROR(("bind: %d", MG_SOCK_ERR(rc)));
5928 mg_call(c, MG_EV_RESOLVE, NULL);
5929 mg_call(c, MG_EV_CONNECT, NULL);
5932 socklen_t slen = tousa(&c->rem, &usa);
5933 mg_set_non_blocking_mode(FD(c));
5936 mg_call(c, MG_EV_RESOLVE, NULL);
5937 rc = connect(FD(c), &usa.sa, slen); // Attempt to connect
5938 if (rc == 0) { // Success
5939 mg_call(c, MG_EV_CONNECT, NULL); // Send MG_EV_CONNECT to the user
5940 } else if (MG_SOCK_PENDING(rc)) { // Need to wait for TCP handshake
5941 MG_DEBUG(("%lu %p -> %M pend", c->id, c->fd, mg_print_ip_port, &c->rem));
5942 c->is_connecting = 1;
5944 mg_error(c, "connect: %d", MG_SOCK_ERR(rc));
5949 static MG_SOCKET_TYPE raccept(MG_SOCKET_TYPE sock, union usa *usa,
5951 MG_SOCKET_TYPE fd = MG_INVALID_SOCKET;
5953 memset(usa, 0, sizeof(*usa));
5954 fd = accept(sock, &usa->sa, len);
5955 } while (MG_SOCK_INTR(fd));
5959 static void accept_conn(struct mg_mgr *mgr, struct mg_connection *lsn) {
5960 struct mg_connection *c = NULL;
5962 socklen_t sa_len = sizeof(usa);
5963 MG_SOCKET_TYPE fd = raccept(FD(lsn), &usa, &sa_len);
5964 if (fd == MG_INVALID_SOCKET) {
5965 #if MG_ARCH == MG_ARCH_AZURERTOS
5966 // AzureRTOS, in non-block socket mode can mark listening socket readable
5967 // even it is not. See comment for 'select' func implementation in
5968 // nx_bsd.c That's not an error, just should try later
5969 if (errno != EAGAIN)
5971 MG_ERROR(("%lu accept failed, errno %d", lsn->id, MG_SOCK_ERR(-1)));
5972 #if (MG_ARCH != MG_ARCH_WIN32) && !MG_ENABLE_FREERTOS_TCP && \
5973 (MG_ARCH != MG_ARCH_TIRTOS) && !MG_ENABLE_POLL && !MG_ENABLE_EPOLL
5974 } else if ((long) fd >= FD_SETSIZE) {
5975 MG_ERROR(("%ld > %ld", (long) fd, (long) FD_SETSIZE));
5978 } else if ((c = mg_alloc_conn(mgr)) == NULL) {
5979 MG_ERROR(("%lu OOM", lsn->id));
5982 tomgaddr(&usa, &c->rem, sa_len != sizeof(usa.sin));
5983 LIST_ADD_HEAD(struct mg_connection, &mgr->conns, c);
5986 mg_set_non_blocking_mode(FD(c));
5989 c->is_hexdumping = lsn->is_hexdumping;
5992 c->pfn_data = lsn->pfn_data;
5994 c->fn_data = lsn->fn_data;
5995 MG_DEBUG(("%lu %p accepted %M -> %M", c->id, c->fd, mg_print_ip_port,
5996 &c->rem, mg_print_ip_port, &c->loc));
5997 mg_call(c, MG_EV_OPEN, NULL);
5998 mg_call(c, MG_EV_ACCEPT, NULL);
5999 if (lsn->is_tls) mg_tls_init(c, mg_str(""));
6003 static bool can_read(const struct mg_connection *c) {
6004 return c->is_full == false;
6007 static bool can_write(const struct mg_connection *c) {
6008 return c->is_connecting || (c->send.len > 0 && c->is_tls_hs == 0);
6011 static bool skip_iotest(const struct mg_connection *c) {
6012 return (c->is_closing || c->is_resolving || FD(c) == MG_INVALID_SOCKET) ||
6013 (can_read(c) == false && can_write(c) == false);
6016 static void mg_iotest(struct mg_mgr *mgr, int ms) {
6017 #if MG_ENABLE_FREERTOS_TCP
6018 struct mg_connection *c;
6019 for (c = mgr->conns; c != NULL; c = c->next) {
6020 c->is_readable = c->is_writable = 0;
6021 if (skip_iotest(c)) continue;
6023 FreeRTOS_FD_SET(c->fd, mgr->ss, eSELECT_READ | eSELECT_EXCEPT);
6024 if (can_write(c)) FreeRTOS_FD_SET(c->fd, mgr->ss, eSELECT_WRITE);
6026 FreeRTOS_select(mgr->ss, pdMS_TO_TICKS(ms));
6027 for (c = mgr->conns; c != NULL; c = c->next) {
6028 EventBits_t bits = FreeRTOS_FD_ISSET(c->fd, mgr->ss);
6029 c->is_readable = bits & (eSELECT_READ | eSELECT_EXCEPT) ? 1U : 0;
6030 c->is_writable = bits & eSELECT_WRITE ? 1U : 0;
6031 if (c->fd != MG_INVALID_SOCKET)
6032 FreeRTOS_FD_CLR(c->fd, mgr->ss,
6033 eSELECT_READ | eSELECT_EXCEPT | eSELECT_WRITE);
6035 #elif MG_ENABLE_EPOLL
6037 for (struct mg_connection *c = mgr->conns; c != NULL; c = c->next) {
6038 c->is_readable = c->is_writable = 0;
6039 if (mg_tls_pending(c) > 0) ms = 1, c->is_readable = 1;
6040 if (can_write(c)) MG_EPOLL_MOD(c, 1);
6043 struct epoll_event *evs = (struct epoll_event *) alloca(max * sizeof(evs[0]));
6044 int n = epoll_wait(mgr->epoll_fd, evs, (int) max, ms);
6045 for (int i = 0; i < n; i++) {
6046 struct mg_connection *c = (struct mg_connection *) evs[i].data.ptr;
6047 if (evs[i].events & EPOLLERR) {
6048 mg_error(c, "socket error");
6049 } else if (c->is_readable == 0) {
6050 bool rd = evs[i].events & (EPOLLIN | EPOLLHUP);
6051 bool wr = evs[i].events & EPOLLOUT;
6052 c->is_readable = can_read(c) && rd ? 1U : 0;
6053 c->is_writable = can_write(c) && wr ? 1U : 0;
6057 #elif MG_ENABLE_POLL
6059 for (struct mg_connection *c = mgr->conns; c != NULL; c = c->next) n++;
6060 struct pollfd *fds = (struct pollfd *) alloca(n * sizeof(fds[0]));
6061 memset(fds, 0, n * sizeof(fds[0]));
6063 for (struct mg_connection *c = mgr->conns; c != NULL; c = c->next) {
6064 c->is_readable = c->is_writable = 0;
6065 if (skip_iotest(c)) {
6066 // Socket not valid, ignore
6067 } else if (mg_tls_pending(c) > 0) {
6068 ms = 1; // Don't wait if TLS is ready
6071 if (can_read(c)) fds[n].events |= POLLIN;
6072 if (can_write(c)) fds[n].events |= POLLOUT;
6077 // MG_INFO(("poll n=%d ms=%d", (int) n, ms));
6078 if (poll(fds, n, ms) < 0) {
6079 #if MG_ARCH == MG_ARCH_WIN32
6080 if (n == 0) Sleep(ms); // On Windows, poll fails if no sockets
6082 memset(fds, 0, n * sizeof(fds[0]));
6085 for (struct mg_connection *c = mgr->conns; c != NULL; c = c->next) {
6086 if (skip_iotest(c)) {
6087 // Socket not valid, ignore
6088 } else if (mg_tls_pending(c) > 0) {
6091 if (fds[n].revents & POLLERR) {
6092 mg_error(c, "socket error");
6095 (unsigned) (fds[n].revents & (POLLIN | POLLHUP) ? 1 : 0);
6096 c->is_writable = (unsigned) (fds[n].revents & POLLOUT ? 1 : 0);
6102 struct timeval tv = {ms / 1000, (ms % 1000) * 1000}, tv_zero = {0, 0}, *tvp;
6103 struct mg_connection *c;
6104 fd_set rset, wset, eset;
6105 MG_SOCKET_TYPE maxfd = 0;
6111 tvp = ms < 0 ? NULL : &tv;
6112 for (c = mgr->conns; c != NULL; c = c->next) {
6113 c->is_readable = c->is_writable = 0;
6114 if (skip_iotest(c)) continue;
6115 FD_SET(FD(c), &eset);
6116 if (can_read(c)) FD_SET(FD(c), &rset);
6117 if (can_write(c)) FD_SET(FD(c), &wset);
6118 if (mg_tls_pending(c) > 0) tvp = &tv_zero;
6119 if (FD(c) > maxfd) maxfd = FD(c);
6122 if ((rc = select((int) maxfd + 1, &rset, &wset, &eset, tvp)) < 0) {
6123 #if MG_ARCH == MG_ARCH_WIN32
6124 if (maxfd == 0) Sleep(ms); // On Windows, select fails if no sockets
6126 MG_ERROR(("select: %d %d", rc, MG_SOCK_ERR(rc)));
6133 for (c = mgr->conns; c != NULL; c = c->next) {
6134 if (FD(c) != MG_INVALID_SOCKET && FD_ISSET(FD(c), &eset)) {
6135 mg_error(c, "socket error");
6137 c->is_readable = FD(c) != MG_INVALID_SOCKET && FD_ISSET(FD(c), &rset);
6138 c->is_writable = FD(c) != MG_INVALID_SOCKET && FD_ISSET(FD(c), &wset);
6139 if (mg_tls_pending(c) > 0) c->is_readable = 1;
6145 void mg_mgr_poll(struct mg_mgr *mgr, int ms) {
6146 struct mg_connection *c, *tmp;
6151 mg_timer_poll(&mgr->timers, now);
6153 for (c = mgr->conns; c != NULL; c = tmp) {
6154 bool is_resp = c->is_resp;
6156 mg_call(c, MG_EV_POLL, &now);
6157 if (is_resp && !c->is_resp) {
6159 mg_call(c, MG_EV_READ, &n);
6161 MG_VERBOSE(("%lu %c%c %c%c%c%c%c", c->id, c->is_readable ? 'r' : '-',
6162 c->is_writable ? 'w' : '-', c->is_tls ? 'T' : 't',
6163 c->is_connecting ? 'C' : 'c', c->is_tls_hs ? 'H' : 'h',
6164 c->is_resolving ? 'R' : 'r', c->is_closing ? 'C' : 'c'));
6165 if (c->is_resolving || c->is_closing) {
6167 } else if (c->is_listening && c->is_udp == 0) {
6168 if (c->is_readable) accept_conn(mgr, c);
6169 } else if (c->is_connecting) {
6170 if (c->is_readable || c->is_writable) connect_conn(c);
6171 } else if (c->is_tls_hs) {
6172 if ((c->is_readable || c->is_writable)) mg_tls_handshake(c);
6174 if (c->is_readable) read_conn(c);
6175 if (c->is_writable) write_conn(c);
6178 if (c->is_draining && c->send.len == 0) c->is_closing = 1;
6179 if (c->is_closing) close_conn(c);
6184 #ifdef MG_ENABLE_LINES
6191 #ifndef MG_MAX_SSI_DEPTH
6192 #define MG_MAX_SSI_DEPTH 5
6195 #ifndef MG_SSI_BUFSIZ
6196 #define MG_SSI_BUFSIZ 1024
6200 static char *mg_ssi(const char *path, const char *root, int depth) {
6201 struct mg_iobuf b = {NULL, 0, 0, MG_IO_SIZE};
6202 FILE *fp = fopen(path, "rb");
6204 char buf[MG_SSI_BUFSIZ], arg[sizeof(buf)];
6207 buf[0] = arg[0] = '\0';
6208 while ((ch = fgetc(fp)) != EOF) {
6209 if (intag && ch == '>' && buf[len - 1] == '-' && buf[len - 2] == '-') {
6210 buf[len++] = (char) (ch & 0xff);
6212 if (sscanf(buf, "<!--#include file=\"%[^\"]", arg)) {
6213 char tmp[MG_PATH_MAX + MG_SSI_BUFSIZ + 10],
6214 *p = (char *) path + strlen(path), *data;
6215 while (p > path && p[-1] != MG_DIRSEP && p[-1] != '/') p--;
6216 mg_snprintf(tmp, sizeof(tmp), "%.*s%s", (int) (p - path), path, arg);
6217 if (depth < MG_MAX_SSI_DEPTH &&
6218 (data = mg_ssi(tmp, root, depth + 1)) != NULL) {
6219 mg_iobuf_add(&b, b.len, data, strlen(data));
6222 MG_ERROR(("%s: file=%s error or too deep", path, arg));
6224 } else if (sscanf(buf, "<!--#include virtual=\"%[^\"]", arg)) {
6225 char tmp[MG_PATH_MAX + MG_SSI_BUFSIZ + 10], *data;
6226 mg_snprintf(tmp, sizeof(tmp), "%s%s", root, arg);
6227 if (depth < MG_MAX_SSI_DEPTH &&
6228 (data = mg_ssi(tmp, root, depth + 1)) != NULL) {
6229 mg_iobuf_add(&b, b.len, data, strlen(data));
6232 MG_ERROR(("%s: virtual=%s error or too deep", path, arg));
6236 MG_ERROR(("Unknown SSI tag: %.*s", (int) len, buf));
6237 mg_iobuf_add(&b, b.len, buf, len);
6241 } else if (ch == '<') {
6243 if (len > 0) mg_iobuf_add(&b, b.len, buf, len);
6245 buf[len++] = (char) (ch & 0xff);
6247 if (len == 5 && strncmp(buf, "<!--#", 5) != 0) {
6249 } else if (len >= sizeof(buf) - 2) {
6250 MG_ERROR(("%s: SSI tag is too large", path));
6253 buf[len++] = (char) (ch & 0xff);
6255 buf[len++] = (char) (ch & 0xff);
6256 if (len >= sizeof(buf)) {
6257 mg_iobuf_add(&b, b.len, buf, len);
6262 if (len > 0) mg_iobuf_add(&b, b.len, buf, len);
6263 if (b.len > 0) mg_iobuf_add(&b, b.len, "", 1); // nul-terminate
6268 return (char *) b.buf;
6271 void mg_http_serve_ssi(struct mg_connection *c, const char *root,
6272 const char *fullpath) {
6273 const char *headers = "Content-Type: text/html; charset=utf-8\r\n";
6274 char *data = mg_ssi(fullpath, root, 0);
6275 mg_http_reply(c, 200, headers, "%s", data == NULL ? "" : data);
6279 void mg_http_serve_ssi(struct mg_connection *c, const char *root,
6280 const char *fullpath) {
6281 mg_http_reply(c, 501, NULL, "SSI not enabled");
6282 (void) root, (void) fullpath;
6286 #ifdef MG_ENABLE_LINES
6291 struct mg_str mg_str_s(const char *s) {
6292 struct mg_str str = {s, s == NULL ? 0 : strlen(s)};
6296 struct mg_str mg_str_n(const char *s, size_t n) {
6297 struct mg_str str = {s, n};
6301 int mg_lower(const char *s) {
6303 if (c >= 'A' && c <= 'Z') c += 'a' - 'A';
6307 int mg_ncasecmp(const char *s1, const char *s2, size_t len) {
6310 diff = mg_lower(s1++) - mg_lower(s2++);
6311 } while (diff == 0 && s1[-1] != '\0' && --len > 0);
6315 int mg_casecmp(const char *s1, const char *s2) {
6316 return mg_ncasecmp(s1, s2, (size_t) ~0);
6319 int mg_vcmp(const struct mg_str *s1, const char *s2) {
6320 size_t n2 = strlen(s2), n1 = s1->len;
6321 int r = strncmp(s1->ptr, s2, (n1 < n2) ? n1 : n2);
6322 if (r == 0) return (int) (n1 - n2);
6326 int mg_vcasecmp(const struct mg_str *str1, const char *str2) {
6327 size_t n2 = strlen(str2), n1 = str1->len;
6328 int r = mg_ncasecmp(str1->ptr, str2, (n1 < n2) ? n1 : n2);
6329 if (r == 0) return (int) (n1 - n2);
6333 struct mg_str mg_strdup(const struct mg_str s) {
6334 struct mg_str r = {NULL, 0};
6335 if (s.len > 0 && s.ptr != NULL) {
6336 char *sc = (char *) calloc(1, s.len + 1);
6338 memcpy(sc, s.ptr, s.len);
6347 int mg_strcmp(const struct mg_str str1, const struct mg_str str2) {
6349 while (i < str1.len && i < str2.len) {
6350 int c1 = str1.ptr[i];
6351 int c2 = str2.ptr[i];
6352 if (c1 < c2) return -1;
6353 if (c1 > c2) return 1;
6356 if (i < str1.len) return 1;
6357 if (i < str2.len) return -1;
6361 const char *mg_strstr(const struct mg_str haystack,
6362 const struct mg_str needle) {
6364 if (needle.len > haystack.len) return NULL;
6365 if (needle.len == 0) return haystack.ptr;
6366 for (i = 0; i <= haystack.len - needle.len; i++) {
6367 if (memcmp(haystack.ptr + i, needle.ptr, needle.len) == 0) {
6368 return haystack.ptr + i;
6374 static bool is_space(int c) {
6375 return c == ' ' || c == '\r' || c == '\n' || c == '\t';
6378 struct mg_str mg_strstrip(struct mg_str s) {
6379 while (s.len > 0 && is_space((int) *s.ptr)) s.ptr++, s.len--;
6380 while (s.len > 0 && is_space((int) *(s.ptr + s.len - 1))) s.len--;
6384 bool mg_match(struct mg_str s, struct mg_str p, struct mg_str *caps) {
6385 size_t i = 0, j = 0, ni = 0, nj = 0;
6386 if (caps) caps->ptr = NULL, caps->len = 0;
6387 while (i < p.len || j < s.len) {
6388 if (i < p.len && j < s.len && (p.ptr[i] == '?' || s.ptr[j] == p.ptr[i])) {
6390 } else if (p.ptr[i] == '?') {
6391 caps->ptr = &s.ptr[j], caps->len = 1; // Finalize `?` cap
6392 caps++, caps->ptr = NULL, caps->len = 0; // Init next cap
6393 } else if (caps->ptr != NULL && caps->len == 0) {
6394 caps->len = (size_t) (&s.ptr[j] - caps->ptr); // Finalize current cap
6395 caps++, caps->len = 0, caps->ptr = NULL; // Init next cap
6398 } else if (i < p.len && (p.ptr[i] == '*' || p.ptr[i] == '#')) {
6399 if (caps && !caps->ptr) caps->len = 0, caps->ptr = &s.ptr[j]; // Init cap
6400 ni = i++, nj = j + 1;
6401 } else if (nj > 0 && nj <= s.len && (p.ptr[ni] == '#' || s.ptr[j] != '/')) {
6403 if (caps && caps->ptr == NULL && caps->len == 0) {
6404 caps--, caps->len = 0; // Restart previous cap
6410 if (caps && caps->ptr && caps->len == 0) {
6411 caps->len = (size_t) (&s.ptr[j] - caps->ptr);
6416 bool mg_globmatch(const char *s1, size_t n1, const char *s2, size_t n2) {
6417 return mg_match(mg_str_n(s2, n2), mg_str_n(s1, n1), NULL);
6420 static size_t mg_nce(const char *s, size_t n, size_t ofs, size_t *koff,
6421 size_t *klen, size_t *voff, size_t *vlen, char delim) {
6423 for (kvlen = 0; ofs + kvlen < n && s[ofs + kvlen] != delim;) kvlen++;
6424 for (kl = 0; kl < kvlen && s[ofs + kl] != '=';) kl++;
6425 if (koff != NULL) *koff = ofs;
6426 if (klen != NULL) *klen = kl;
6427 if (voff != NULL) *voff = kl < kvlen ? ofs + kl + 1 : 0;
6428 if (vlen != NULL) *vlen = kl < kvlen ? kvlen - kl - 1 : 0;
6430 return ofs > n ? n : ofs;
6433 bool mg_split(struct mg_str *s, struct mg_str *k, struct mg_str *v, char sep) {
6434 size_t koff = 0, klen = 0, voff = 0, vlen = 0, off = 0;
6435 if (s->ptr == NULL || s->len == 0) return 0;
6436 off = mg_nce(s->ptr, s->len, 0, &koff, &klen, &voff, &vlen, sep);
6437 if (k != NULL) *k = mg_str_n(s->ptr + koff, klen);
6438 if (v != NULL) *v = mg_str_n(s->ptr + voff, vlen);
6439 *s = mg_str_n(s->ptr + off, s->len - off);
6443 bool mg_commalist(struct mg_str *s, struct mg_str *k, struct mg_str *v) {
6444 return mg_split(s, k, v, ',');
6447 char *mg_hex(const void *buf, size_t len, char *to) {
6448 const unsigned char *p = (const unsigned char *) buf;
6449 const char *hex = "0123456789abcdef";
6451 for (; len--; p++) {
6452 to[i++] = hex[p[0] >> 4];
6453 to[i++] = hex[p[0] & 0x0f];
6459 static unsigned char mg_unhex_nimble(unsigned char c) {
6460 return (c >= '0' && c <= '9') ? (unsigned char) (c - '0')
6461 : (c >= 'A' && c <= 'F') ? (unsigned char) (c - '7')
6462 : (unsigned char) (c - 'W');
6465 unsigned long mg_unhexn(const char *s, size_t len) {
6466 unsigned long i = 0, v = 0;
6467 for (i = 0; i < len; i++) v <<= 4, v |= mg_unhex_nimble(((uint8_t *) s)[i]);
6471 void mg_unhex(const char *buf, size_t len, unsigned char *to) {
6473 for (i = 0; i < len; i += 2) {
6474 to[i >> 1] = (unsigned char) mg_unhexn(&buf[i], 2);
6478 bool mg_path_is_sane(const char *path) {
6479 const char *s = path;
6480 for (; s[0] != '\0'; s++) {
6481 if (s == path || s[0] == '/' || s[0] == '\\') { // Subdir?
6482 if (s[1] == '.' && s[2] == '.') return false; // Starts with ..
6488 #ifdef MG_ENABLE_LINES
6489 #line 1 "src/timer.c"
6494 #define MG_TIMER_CALLED 4
6496 void mg_timer_init(struct mg_timer **head, struct mg_timer *t, uint64_t ms,
6497 unsigned flags, void (*fn)(void *), void *arg) {
6498 t->id = 0, t->period_ms = ms, t->expire = 0;
6499 t->flags = flags, t->fn = fn, t->arg = arg, t->next = *head;
6503 void mg_timer_free(struct mg_timer **head, struct mg_timer *t) {
6504 while (*head && *head != t) head = &(*head)->next;
6505 if (*head) *head = t->next;
6508 // t: expiration time, prd: period, now: current time. Return true if expired
6509 bool mg_timer_expired(uint64_t *t, uint64_t prd, uint64_t now) {
6510 if (now + prd < *t) *t = 0; // Time wrapped? Reset timer
6511 if (*t == 0) *t = now + prd; // Firt poll? Set expiration
6512 if (*t > now) return false; // Not expired yet, return
6513 *t = (now - *t) > prd ? now + prd : *t + prd; // Next expiration time
6514 return true; // Expired, return true
6517 void mg_timer_poll(struct mg_timer **head, uint64_t now_ms) {
6518 struct mg_timer *t, *tmp;
6519 for (t = *head; t != NULL; t = tmp) {
6520 bool once = t->expire == 0 && (t->flags & MG_TIMER_RUN_NOW) &&
6521 !(t->flags & MG_TIMER_CALLED); // Handle MG_TIMER_NOW only once
6522 bool expired = mg_timer_expired(&t->expire, t->period_ms, now_ms);
6524 if (!once && !expired) continue;
6525 if ((t->flags & MG_TIMER_REPEAT) || !(t->flags & MG_TIMER_CALLED)) {
6528 t->flags |= MG_TIMER_CALLED;
6532 #ifdef MG_ENABLE_LINES
6533 #line 1 "src/tls_builtin.c"
6537 #if MG_TLS == MG_TLS_BUILTIN
6539 struct mg_iobuf send;
6540 struct mg_iobuf recv;
6543 #define MG_LOAD_BE16(p) ((uint16_t) ((MG_U8P(p)[0] << 8U) | MG_U8P(p)[1]))
6544 #define TLS_HDR_SIZE 5 // 1 byte type, 2 bytes version, 2 bytes len
6546 static inline bool mg_is_big_endian(void) {
6548 return *(unsigned char *) &v == 1;
6550 static inline uint16_t mg_swap16(uint16_t v) {
6551 return (uint16_t) ((v << 8U) | (v >> 8U));
6553 static inline uint32_t mg_swap32(uint32_t v) {
6554 return (v >> 24) | (v >> 8 & 0xff00) | (v << 8 & 0xff0000) | (v << 24);
6556 static inline uint64_t mg_swap64(uint64_t v) {
6557 return (((uint64_t) mg_swap32((uint32_t) v)) << 32) |
6558 mg_swap32((uint32_t) (v >> 32));
6560 static inline uint16_t mg_be16(uint16_t v) {
6561 return mg_is_big_endian() ? mg_swap16(v) : v;
6563 static inline uint32_t mg_be32(uint32_t v) {
6564 return mg_is_big_endian() ? mg_swap32(v) : v;
6567 static inline void add8(struct mg_iobuf *io, uint8_t data) {
6568 mg_iobuf_add(io, io->len, &data, sizeof(data));
6570 static inline void add16(struct mg_iobuf *io, uint16_t data) {
6571 data = mg_htons(data);
6572 mg_iobuf_add(io, io->len, &data, sizeof(data));
6574 static inline void add32(struct mg_iobuf *io, uint32_t data) {
6575 data = mg_htonl(data);
6576 mg_iobuf_add(io, io->len, &data, sizeof(data));
6579 void mg_tls_init(struct mg_connection *c, struct mg_str hostname) {
6580 struct tls_data *tls = (struct tls_data *) calloc(1, sizeof(struct tls_data));
6582 tls->send.align = tls->recv.align = MG_IO_SIZE;
6584 c->is_tls = c->is_tls_hs = 1;
6586 mg_error(c, "tls oom");
6590 void mg_tls_free(struct mg_connection *c) {
6591 struct tls_data *tls = c->tls;
6593 mg_iobuf_free(&tls->send);
6594 mg_iobuf_free(&tls->recv);
6599 long mg_tls_send(struct mg_connection *c, const void *buf, size_t len) {
6600 (void) c, (void) buf, (void) len;
6601 // MG_INFO(("BBBBBBBB"));
6604 long mg_tls_recv(struct mg_connection *c, void *buf, size_t len) {
6605 (void) c, (void) buf, (void) len;
6607 long n = mg_io_recv(c, tmp, sizeof(tmp));
6608 if (n > 0) mg_hexdump(tmp, (size_t) n);
6609 MG_INFO(("AAAAAAAA"));
6611 // struct mg_tls *tls = (struct mg_tls *) c->tls;
6612 // long n = mbedtls_ssl_read(&tls->ssl, (unsigned char *) buf, len);
6613 // if (n == MBEDTLS_ERR_SSL_WANT_READ || n == MBEDTLS_ERR_SSL_WANT_WRITE)
6614 // return MG_IO_WAIT;
6615 // if (n <= 0) return MG_IO_ERR;
6618 size_t mg_tls_pending(struct mg_connection *c) {
6622 void mg_tls_handshake(struct mg_connection *c) {
6623 struct tls_data *tls = c->tls;
6624 struct mg_iobuf *rio = &tls->recv;
6625 struct mg_iobuf *wio = &tls->send;
6626 // Pull data from TCP
6628 mg_iobuf_resize(rio, rio->len + 1);
6629 long n = mg_io_recv(c, &rio->buf[rio->len], rio->size - rio->len);
6631 rio->len += (size_t) n;
6632 } else if (n == MG_IO_WAIT) {
6635 mg_error(c, "IO err");
6639 // Look if we've pulled everything
6640 if (rio->len < TLS_HDR_SIZE) return;
6641 uint8_t record_type = rio->buf[0];
6642 uint16_t record_len = MG_LOAD_BE16(rio->buf + 3);
6643 uint16_t record_version = MG_LOAD_BE16(rio->buf + 1);
6644 if (record_type != 22) {
6645 mg_error(c, "no 22");
6648 if (rio->len < (size_t) TLS_HDR_SIZE + record_len) return;
6650 // struct tls_hello *hello = (struct tls_hello *) (hdr + 1);
6651 MG_INFO(("CT=%d V=%hx L=%hu", record_type, record_version, record_len));
6652 mg_hexdump(rio->buf, rio->len);
6654 // Send response. Server Hello
6655 size_t ofs = wio->len;
6656 add8(wio, 22), add16(wio, 0x303), add16(wio, 0); // Layer: type, ver, len
6657 add8(wio, 2), add8(wio, 0), add16(wio, 0), add16(wio, 0x304); // Hello
6658 mg_iobuf_add(wio, wio->len, NULL, 32); // 32 random
6659 mg_random(wio->buf + wio->len - 32, 32); // bytes
6660 add8(wio, 0); // Session ID
6661 add16(wio, 0x1301); // Cipher: TLS_AES_128_GCM_SHA256
6662 add8(wio, 0); // Compression method: 0
6663 add16(wio, 46); // Extensions length
6664 add16(wio, 43), add16(wio, 2), add16(wio, 0x304); // extension: TLS 1.3
6665 add16(wio, 51), add16(wio, 36), add16(wio, 29), add16(wio, 32); // keyshare
6666 mg_iobuf_add(wio, wio->len, NULL, 32); // 32 random
6667 mg_random(wio->buf + wio->len - 32, 32); // bytes
6668 *(uint16_t *) &wio->buf[ofs + 3] = mg_be16((uint16_t) (wio->len - ofs - 5));
6669 *(uint16_t *) &wio->buf[ofs + 7] = mg_be16((uint16_t) (wio->len - ofs - 9));
6671 // Change cipher. Cipher's payload is an encypted app data
6673 add8(wio, 20), add16(wio, 0x303); // Layer: type, version
6674 add16(wio, 1), add8(wio, 1);
6676 ofs = wio->len; // Application data
6677 add8(wio, 23), add16(wio, 0x303), add16(wio, 5); // Layer: type, version
6678 // mg_iobuf_add(wio, wio->len, "\x01\x02\x03\x04\x05", 5);
6679 add8(wio, 22); // handshake message
6680 add8(wio, 8); // encrypted extensions
6681 add8(wio, 0), add16(wio, 2), add16(wio, 0); // empty 2 bytes
6682 add8(wio, 11); // certificate message
6683 add8(wio, 0), add16(wio, 4), add32(wio, 0x1020304); // len
6684 *(uint16_t *) &wio->buf[ofs + 3] = mg_be16((uint16_t)(wio->len - ofs - 5));
6686 mg_io_send(c, wio->buf, wio->len);
6693 void mg_tls_ctx_free(struct mg_mgr *mgr) {
6694 mgr->tls_ctx = NULL;
6696 void mg_tls_ctx_init(struct mg_mgr *mgr, const struct mg_tls_opts *opts) {
6697 (void) opts, (void) mgr;
6701 #ifdef MG_ENABLE_LINES
6702 #line 1 "src/tls_dummy.c"
6706 #if MG_TLS == MG_TLS_NONE
6707 void mg_tls_init(struct mg_connection *c, struct mg_str hostname) {
6709 mg_error(c, "TLS is not enabled");
6711 void mg_tls_handshake(struct mg_connection *c) {
6714 void mg_tls_free(struct mg_connection *c) {
6717 long mg_tls_recv(struct mg_connection *c, void *buf, size_t len) {
6718 return c == NULL || buf == NULL || len == 0 ? 0 : -1;
6720 long mg_tls_send(struct mg_connection *c, const void *buf, size_t len) {
6721 return c == NULL || buf == NULL || len == 0 ? 0 : -1;
6723 size_t mg_tls_pending(struct mg_connection *c) {
6727 void mg_tls_ctx_free(struct mg_mgr *mgr) {
6728 mgr->tls_ctx = NULL;
6730 void mg_tls_ctx_init(struct mg_mgr *mgr, const struct mg_tls_opts *opts) {
6731 (void) opts, (void) mgr;
6735 #ifdef MG_ENABLE_LINES
6736 #line 1 "src/tls_mbed.c"
6742 #if MG_TLS == MG_TLS_MBED
6744 #if defined(MBEDTLS_VERSION_NUMBER) && MBEDTLS_VERSION_NUMBER >= 0x03000000
6745 #define MGRNG , rng_get, NULL
6750 void mg_tls_free(struct mg_connection *c) {
6751 struct mg_tls *tls = (struct mg_tls *) c->tls;
6753 mbedtls_ssl_free(&tls->ssl);
6754 mbedtls_ssl_config_free(&tls->conf);
6760 static int mg_net_send(void *ctx, const unsigned char *buf, size_t len) {
6761 long n = mg_io_send((struct mg_connection *) ctx, buf, len);
6762 MG_VERBOSE(("%lu n=%ld e=%d", ((struct mg_connection *) ctx)->id, n, errno));
6763 if (n == MG_IO_WAIT) return MBEDTLS_ERR_SSL_WANT_WRITE;
6764 if (n == MG_IO_RESET) return MBEDTLS_ERR_NET_CONN_RESET;
6765 if (n == MG_IO_ERR) return MBEDTLS_ERR_NET_SEND_FAILED;
6769 static int mg_net_recv(void *ctx, unsigned char *buf, size_t len) {
6770 long n = mg_io_recv((struct mg_connection *) ctx, buf, len);
6771 MG_VERBOSE(("%lu n=%ld", ((struct mg_connection *) ctx)->id, n));
6772 if (n == MG_IO_WAIT) return MBEDTLS_ERR_SSL_WANT_WRITE;
6773 if (n == MG_IO_RESET) return MBEDTLS_ERR_NET_CONN_RESET;
6774 if (n == MG_IO_ERR) return MBEDTLS_ERR_NET_RECV_FAILED;
6778 void mg_tls_handshake(struct mg_connection *c) {
6779 struct mg_tls *tls = (struct mg_tls *) c->tls;
6780 int rc = mbedtls_ssl_handshake(&tls->ssl);
6781 if (rc == 0) { // Success
6782 MG_DEBUG(("%lu success", c->id));
6784 mg_call(c, MG_EV_TLS_HS, NULL);
6785 } else if (rc == MBEDTLS_ERR_SSL_WANT_READ ||
6786 rc == MBEDTLS_ERR_SSL_WANT_WRITE) { // Still pending
6787 MG_VERBOSE(("%lu pending, %d%d %d (-%#x)", c->id, c->is_connecting,
6788 c->is_tls_hs, rc, -rc));
6790 mg_error(c, "TLS handshake: -%#x", -rc); // Error
6794 static int mbed_rng(void *ctx, unsigned char *buf, size_t len) {
6795 mg_random(buf, len);
6800 static void debug_cb(void *c, int lev, const char *s, int n, const char *s2) {
6801 n = (int) strlen(s2) - 1;
6802 MG_INFO(("%lu %d %.*s", ((struct mg_connection *) c)->id, lev, n, s2));
6806 #ifdef MBEDTLS_SSL_SESSION_TICKETS
6807 static int rng_get(void *p_rng, unsigned char *buf, size_t len) {
6809 mg_random(buf, len);
6814 void mg_tls_init(struct mg_connection *c, struct mg_str hostname) {
6815 struct mg_tls_ctx *ctx = (struct mg_tls_ctx *) c->mgr->tls_ctx;
6816 struct mg_tls *tls = (struct mg_tls *) calloc(1, sizeof(*tls));
6820 if (c->tls == NULL) {
6821 mg_error(c, "TLS OOM");
6825 MG_DEBUG(("%lu Setting TLS", c->id));
6826 mbedtls_ssl_init(&tls->ssl);
6827 mbedtls_ssl_config_init(&tls->conf);
6828 mbedtls_ssl_conf_dbg(&tls->conf, debug_cb, c);
6829 #if defined(MG_MBEDTLS_DEBUG_LEVEL)
6830 mbedtls_debug_set_threshold(MG_MBEDTLS_DEBUG_LEVEL);
6832 if ((rc = mbedtls_ssl_config_defaults(
6834 c->is_client ? MBEDTLS_SSL_IS_CLIENT : MBEDTLS_SSL_IS_SERVER,
6835 MBEDTLS_SSL_TRANSPORT_STREAM, MBEDTLS_SSL_PRESET_DEFAULT)) != 0) {
6836 mg_error(c, "tls defaults %#x", -rc);
6839 mbedtls_ssl_conf_rng(&tls->conf, mbed_rng, c);
6841 if (c->is_client && ctx->client_ca.version) {
6842 mbedtls_ssl_conf_ca_chain(&tls->conf, &ctx->client_ca, NULL);
6843 mbedtls_ssl_conf_authmode(&tls->conf, MBEDTLS_SSL_VERIFY_REQUIRED);
6844 if (hostname.ptr != NULL && hostname.ptr[0] != '\0') {
6845 struct mg_addr addr;
6846 if (!mg_aton(hostname, &addr)) { // if srvname is not an IP address
6847 char *host = mg_mprintf("%.*s", (int) hostname.len, hostname.ptr);
6848 mbedtls_ssl_set_hostname(&tls->ssl, host);
6852 } else if (!c->is_client && ctx->server_ca.version) {
6853 mbedtls_ssl_conf_ca_chain(&tls->conf, &ctx->server_ca, NULL);
6854 mbedtls_ssl_conf_authmode(&tls->conf, MBEDTLS_SSL_VERIFY_REQUIRED);
6856 mbedtls_ssl_conf_authmode(&tls->conf, MBEDTLS_SSL_VERIFY_NONE);
6858 if (c->is_client && ctx->client_cert.version &&
6859 (rc = mbedtls_ssl_conf_own_cert(&tls->conf, &ctx->client_cert,
6860 &ctx->client_key)) != 0) {
6861 mg_error(c, "own cert %#x", -rc);
6864 if (!c->is_client && ctx->server_cert.version &&
6865 (rc = mbedtls_ssl_conf_own_cert(&tls->conf, &ctx->server_cert,
6866 &ctx->server_key)) != 0) {
6867 mg_error(c, "own cert %#x", -rc);
6870 #ifdef MBEDTLS_SSL_SESSION_TICKETS
6871 mbedtls_ssl_conf_session_tickets_cb(&tls->conf, mbedtls_ssl_ticket_write,
6872 mbedtls_ssl_ticket_parse,
6876 if ((rc = mbedtls_ssl_setup(&tls->ssl, &tls->conf)) != 0) {
6877 mg_error(c, "setup err %#x", -rc);
6884 mbedtls_ssl_set_bio(&tls->ssl, c, mg_net_send, mg_net_recv, 0);
6885 if (c->is_client && c->is_resolving == 0 && c->is_connecting == 0) {
6886 mg_tls_handshake(c);
6893 size_t mg_tls_pending(struct mg_connection *c) {
6894 struct mg_tls *tls = (struct mg_tls *) c->tls;
6895 return tls == NULL ? 0 : mbedtls_ssl_get_bytes_avail(&tls->ssl);
6898 long mg_tls_recv(struct mg_connection *c, void *buf, size_t len) {
6899 struct mg_tls *tls = (struct mg_tls *) c->tls;
6900 long n = mbedtls_ssl_read(&tls->ssl, (unsigned char *) buf, len);
6901 if (n == MBEDTLS_ERR_SSL_WANT_READ || n == MBEDTLS_ERR_SSL_WANT_WRITE)
6903 if (n <= 0) return MG_IO_ERR;
6907 long mg_tls_send(struct mg_connection *c, const void *buf, size_t len) {
6908 struct mg_tls *tls = (struct mg_tls *) c->tls;
6909 long n = mbedtls_ssl_write(&tls->ssl, (unsigned char *) buf, len);
6910 if (n == MBEDTLS_ERR_SSL_WANT_READ || n == MBEDTLS_ERR_SSL_WANT_WRITE)
6912 if (n <= 0) return MG_IO_ERR;
6916 static bool load_cert(struct mg_str str, mbedtls_x509_crt *p) {
6918 if (str.ptr == NULL || str.ptr[0] == '\0' || str.ptr[0] == '*') return true;
6919 if (str.ptr[0] == '-') str.len++; // PEM, include trailing NUL
6920 if ((rc = mbedtls_x509_crt_parse(p, (uint8_t *) str.ptr, str.len)) != 0) {
6921 MG_ERROR(("cert err %#x", -rc));
6927 static bool load_key(struct mg_str str, mbedtls_pk_context *p) {
6929 if (str.ptr == NULL || str.ptr[0] == '\0' || str.ptr[0] == '*') return true;
6930 if (str.ptr[0] == '-') str.len++; // PEM, include trailing NUL
6931 if ((rc = mbedtls_pk_parse_key(p, (uint8_t *) str.ptr, str.len, NULL,
6933 MG_ERROR(("key err %#x", -rc));
6939 void mg_tls_ctx_init(struct mg_mgr *mgr, const struct mg_tls_opts *opts) {
6940 struct mg_tls_ctx *ctx = (struct mg_tls_ctx *) calloc(1, sizeof(*ctx));
6941 if (ctx == NULL) goto fail;
6942 MG_DEBUG(("Setting up TLS context"));
6944 #if defined(MG_MBEDTLS_DEBUG_LEVEL)
6945 mbedtls_debug_set_threshold(MG_MBEDTLS_DEBUG_LEVEL);
6948 if (!load_cert(opts->client_ca, &ctx->client_ca)) goto fail;
6949 if (!load_cert(opts->server_ca, &ctx->server_ca)) goto fail;
6950 if (!load_cert(opts->client_cert, &ctx->client_cert)) goto fail;
6951 if (!load_cert(opts->server_cert, &ctx->server_cert)) goto fail;
6952 if (!load_key(opts->server_key, &ctx->server_key)) goto fail;
6953 if (!load_key(opts->client_key, &ctx->client_key)) goto fail;
6955 #ifdef MBEDTLS_SSL_SESSION_TICKETS
6958 mbedtls_ssl_ticket_init(&ctx->ticket_ctx);
6959 if ((rc = mbedtls_ssl_ticket_setup(&ctx->ticket_ctx, rng_get, NULL,
6960 MBEDTLS_CIPHER_AES_128_GCM, 86400)) !=
6962 MG_ERROR(("setup session tickets err %#x", -rc));
6970 mg_tls_ctx_free(mgr);
6973 void mg_tls_ctx_free(struct mg_mgr *mgr) {
6974 struct mg_tls_ctx *ctx = (struct mg_tls_ctx *) mgr->tls_ctx;
6976 mbedtls_x509_crt_free(&ctx->server_cert);
6977 mbedtls_pk_free(&ctx->server_key);
6978 mbedtls_x509_crt_free(&ctx->client_cert);
6979 mbedtls_pk_free(&ctx->client_key);
6980 mbedtls_x509_crt_free(&ctx->client_ca);
6981 mbedtls_x509_crt_free(&ctx->server_ca);
6982 #ifdef MBEDTLS_SSL_SESSION_TICKETS
6983 mbedtls_ssl_ticket_free(&ctx->ticket_ctx);
6986 mgr->tls_ctx = NULL;
6991 #ifdef MG_ENABLE_LINES
6992 #line 1 "src/tls_openssl.c"
6997 #if MG_TLS == MG_TLS_OPENSSL
6998 static int mg_tls_err(struct mg_tls *tls, int res) {
6999 int err = SSL_get_error(tls->ssl, res);
7000 // We've just fetched the last error from the queue.
7001 // Now we need to clear the error queue. If we do not, then the following
7002 // can happen (actually reported):
7003 // - A new connection is accept()-ed with cert error (e.g. self-signed cert)
7004 // - Since all accept()-ed connections share listener's context,
7005 // - *ALL* SSL accepted connection report read error on the next poll cycle.
7006 // Thus a single errored connection can close all the rest, unrelated ones.
7007 // Clearing the error keeps the shared SSL_CTX in an OK state.
7009 if (err != 0) ERR_print_errors_fp(stderr);
7011 if (err == SSL_ERROR_WANT_READ) return 0;
7012 if (err == SSL_ERROR_WANT_WRITE) return 0;
7016 static STACK_OF(X509_INFO) * load_ca_certs(const char *ca, int ca_len) {
7017 BIO *ca_bio = BIO_new_mem_buf(ca, ca_len);
7018 if (!ca_bio) return NULL;
7019 STACK_OF(X509_INFO) *certs = PEM_X509_INFO_read_bio(ca_bio, NULL, NULL, NULL);
7024 static bool add_ca_certs(SSL_CTX *ctx, STACK_OF(X509_INFO) * certs) {
7025 X509_STORE *cert_store = SSL_CTX_get_cert_store(ctx);
7026 for (int i = 0; i < sk_X509_INFO_num(certs); i++) {
7027 X509_INFO *cert_info = sk_X509_INFO_value(certs, i);
7028 if (cert_info->x509 && !X509_STORE_add_cert(cert_store, cert_info->x509))
7034 static EVP_PKEY *load_key(const char *key, int key_len) {
7035 BIO *key_bio = BIO_new_mem_buf(key, key_len);
7036 if (!key_bio) return NULL;
7037 EVP_PKEY *priv_key = PEM_read_bio_PrivateKey(key_bio, NULL, 0, NULL);
7042 static X509 *load_cert(const char *cert, int cert_len) {
7043 BIO *cert_bio = BIO_new_mem_buf(cert, cert_len);
7044 if (!cert_bio) return NULL;
7045 X509 *x509 = PEM_read_bio_X509(cert_bio, NULL, 0, NULL);
7050 void mg_tls_init(struct mg_connection *c, struct mg_str hostname) {
7051 struct mg_tls_ctx *ctx = (struct mg_tls_ctx *) c->mgr->tls_ctx;
7052 struct mg_tls *tls = (struct mg_tls *) calloc(1, sizeof(*tls));
7055 mg_error(c, "TLS context not initialized");
7060 mg_error(c, "TLS OOM");
7064 tls->ctx = c->is_client ? SSL_CTX_new(TLS_client_method())
7065 : SSL_CTX_new(TLS_server_method());
7066 if ((tls->ssl = SSL_new(tls->ctx)) == NULL) {
7067 mg_error(c, "SSL_new");
7071 SSL_set_min_proto_version(tls->ssl, TLS1_2_VERSION);
7073 #ifdef MG_ENABLE_OPENSSL_NO_COMPRESSION
7074 SSL_set_options(tls->ssl, SSL_OP_NO_COMPRESSION);
7076 #ifdef MG_ENABLE_OPENSSL_CIPHER_SERVER_PREFERENCE
7077 SSL_set_options(tls->ssl, SSL_OP_CIPHER_SERVER_PREFERENCE);
7081 if (ctx->client_ca) {
7082 SSL_set_verify(tls->ssl,
7083 SSL_VERIFY_PEER | SSL_VERIFY_FAIL_IF_NO_PEER_CERT, NULL);
7084 if (!add_ca_certs(tls->ctx, ctx->client_ca)) goto fail;
7086 if (ctx->client_cert && ctx->client_key) {
7087 if (SSL_use_certificate(tls->ssl, ctx->client_cert) != 1) {
7088 mg_error(c, "SSL_CTX_use_certificate");
7091 if (SSL_use_PrivateKey(tls->ssl, ctx->client_key) != 1) {
7092 mg_error(c, "SSL_CTX_use_PrivateKey");
7097 if (ctx->server_ca) {
7098 SSL_set_verify(tls->ssl,
7099 SSL_VERIFY_PEER | SSL_VERIFY_FAIL_IF_NO_PEER_CERT, NULL);
7100 if (!add_ca_certs(tls->ctx, ctx->server_ca)) goto fail;
7102 if (ctx->server_cert && ctx->server_key) {
7103 if (SSL_use_certificate(tls->ssl, ctx->server_cert) != 1) {
7104 mg_error(c, "SSL_CTX_use_certificate");
7107 if (SSL_use_PrivateKey(tls->ssl, ctx->server_key) != 1) {
7108 mg_error(c, "SSL_CTX_use_PrivateKey");
7114 SSL_set_mode(tls->ssl, SSL_MODE_ACCEPT_MOVING_WRITE_BUFFER);
7115 #if OPENSSL_VERSION_NUMBER > 0x10002000L
7116 SSL_set_ecdh_auto(tls->ssl, 1);
7119 #if OPENSSL_VERSION_NUMBER >= 0x10100000L
7120 if (c->is_client && hostname.ptr && hostname.ptr[0] != '\0') {
7121 char *s = mg_mprintf("%.*s", (int) hostname.len, hostname.ptr);
7122 SSL_set1_host(tls->ssl, s);
7123 SSL_set_tlsext_host_name(tls->ssl, s);
7131 if (c->is_client && c->is_resolving == 0 && c->is_connecting == 0) {
7132 mg_tls_handshake(c);
7134 MG_DEBUG(("%lu SSL %s OK", c->id, c->is_accepted ? "accept" : "client"));
7142 void mg_tls_handshake(struct mg_connection *c) {
7143 struct mg_tls *tls = (struct mg_tls *) c->tls;
7145 SSL_set_fd(tls->ssl, (int) (size_t) c->fd);
7146 rc = c->is_client ? SSL_connect(tls->ssl) : SSL_accept(tls->ssl);
7148 MG_DEBUG(("%lu success", c->id));
7150 mg_call(c, MG_EV_TLS_HS, NULL);
7152 int code = mg_tls_err(tls, rc);
7153 if (code != 0) mg_error(c, "tls hs: rc %d, err %d", rc, code);
7157 void mg_tls_free(struct mg_connection *c) {
7158 struct mg_tls *tls = (struct mg_tls *) c->tls;
7159 if (tls == NULL) return;
7161 SSL_CTX_free(tls->ctx);
7166 size_t mg_tls_pending(struct mg_connection *c) {
7167 struct mg_tls *tls = (struct mg_tls *) c->tls;
7168 return tls == NULL ? 0 : (size_t) SSL_pending(tls->ssl);
7171 long mg_tls_recv(struct mg_connection *c, void *buf, size_t len) {
7172 struct mg_tls *tls = (struct mg_tls *) c->tls;
7173 int n = SSL_read(tls->ssl, buf, (int) len);
7174 if (n < 0 && mg_tls_err(tls, n) == 0) return MG_IO_WAIT;
7175 if (n <= 0) return MG_IO_ERR;
7179 long mg_tls_send(struct mg_connection *c, const void *buf, size_t len) {
7180 struct mg_tls *tls = (struct mg_tls *) c->tls;
7181 int n = SSL_write(tls->ssl, buf, (int) len);
7182 if (n < 0 && mg_tls_err(tls, n) == 0) return MG_IO_WAIT;
7183 if (n <= 0) return MG_IO_ERR;
7187 void mg_tls_ctx_free(struct mg_mgr *mgr) {
7188 struct mg_tls_ctx *ctx = (struct mg_tls_ctx *) mgr->tls_ctx;
7190 if (ctx->server_cert) X509_free(ctx->server_cert);
7191 if (ctx->server_key) EVP_PKEY_free(ctx->server_key);
7193 sk_X509_INFO_pop_free(ctx->server_ca, X509_INFO_free);
7194 if (ctx->client_cert) X509_free(ctx->client_cert);
7195 if (ctx->client_key) EVP_PKEY_free(ctx->client_key);
7197 sk_X509_INFO_pop_free(ctx->client_ca, X509_INFO_free);
7199 mgr->tls_ctx = NULL;
7203 void mg_tls_ctx_init(struct mg_mgr *mgr, const struct mg_tls_opts *opts) {
7204 static unsigned char s_initialised = 0;
7205 if (!s_initialised) {
7210 struct mg_tls_ctx *ctx = (struct mg_tls_ctx *) calloc(1, sizeof(*ctx));
7211 if (ctx == NULL) return;
7213 if (opts->server_cert.ptr && opts->server_cert.ptr[0] != '\0') {
7214 struct mg_str key = opts->server_key;
7215 if (!key.ptr) key = opts->server_cert;
7216 if (!(ctx->server_cert =
7217 load_cert(opts->server_cert.ptr, (int) opts->server_cert.len)))
7219 if (!(ctx->server_key = load_key(key.ptr, (int) key.len))) goto fail;
7222 if (opts->server_ca.ptr && opts->server_ca.ptr[0] != '\0') {
7223 if (!(ctx->server_ca =
7224 load_ca_certs(opts->server_ca.ptr, (int) opts->server_ca.len)))
7228 if (opts->client_cert.ptr && opts->client_cert.ptr[0] != '\0') {
7229 struct mg_str key = opts->client_key;
7230 if (!key.ptr) key = opts->client_cert;
7231 if (!(ctx->client_cert =
7232 load_cert(opts->client_cert.ptr, (int) opts->client_cert.len)))
7234 if (!(ctx->client_key = load_key(key.ptr, (int) key.len))) goto fail;
7237 if (opts->client_ca.ptr && opts->client_ca.ptr[0] != '\0') {
7238 if (!(ctx->client_ca =
7239 load_ca_certs(opts->client_ca.ptr, (int) opts->client_ca.len)))
7246 MG_ERROR(("TLS ctx init error"));
7247 mg_tls_ctx_free(mgr);
7252 #ifdef MG_ENABLE_LINES
7258 size_t key, user, pass, host, port, uri, end;
7261 int mg_url_is_ssl(const char *url) {
7262 return strncmp(url, "wss:", 4) == 0 || strncmp(url, "https:", 6) == 0 ||
7263 strncmp(url, "mqtts:", 6) == 0 || strncmp(url, "ssl:", 4) == 0 ||
7264 strncmp(url, "tls:", 4) == 0;
7267 static struct url urlparse(const char *url) {
7270 memset(&u, 0, sizeof(u));
7271 for (i = 0; url[i] != '\0'; i++) {
7272 if (url[i] == '/' && i > 0 && u.host == 0 && url[i - 1] == '/') {
7275 } else if (url[i] == ']') {
7276 u.port = 0; // IPv6 URLs, like http://[::1]/bar
7277 } else if (url[i] == ':' && u.port == 0 && u.uri == 0) {
7279 } else if (url[i] == '@' && u.user == 0 && u.pass == 0 && u.uri == 0) {
7284 } else if (url[i] == '/' && u.host && u.uri == 0) {
7290 printf("[%s] %d %d %d %d %d\n", url, u.user, u.pass, u.host, u.port, u.uri);
7295 struct mg_str mg_url_host(const char *url) {
7296 struct url u = urlparse(url);
7297 size_t n = u.port ? u.port - u.host - 1
7298 : u.uri ? u.uri - u.host
7300 struct mg_str s = mg_str_n(url + u.host, n);
7304 const char *mg_url_uri(const char *url) {
7305 struct url u = urlparse(url);
7306 return u.uri ? url + u.uri : "/";
7309 unsigned short mg_url_port(const char *url) {
7310 struct url u = urlparse(url);
7311 unsigned short port = 0;
7312 if (strncmp(url, "http:", 5) == 0 || strncmp(url, "ws:", 3) == 0) port = 80;
7313 if (strncmp(url, "wss:", 4) == 0 || strncmp(url, "https:", 6) == 0)
7315 if (strncmp(url, "mqtt:", 5) == 0) port = 1883;
7316 if (strncmp(url, "mqtts:", 6) == 0) port = 8883;
7317 if (u.port) port = (unsigned short) atoi(url + u.port);
7321 struct mg_str mg_url_user(const char *url) {
7322 struct url u = urlparse(url);
7323 struct mg_str s = mg_str("");
7324 if (u.user && (u.pass || u.host)) {
7325 size_t n = u.pass ? u.pass - u.user - 1 : u.host - u.user - 1;
7326 s = mg_str_n(url + u.user, n);
7331 struct mg_str mg_url_pass(const char *url) {
7332 struct url u = urlparse(url);
7333 struct mg_str s = mg_str_n("", 0UL);
7334 if (u.pass && u.host) {
7335 size_t n = u.host - u.pass - 1;
7336 s = mg_str_n(url + u.pass, n);
7341 #ifdef MG_ENABLE_LINES
7342 #line 1 "src/util.c"
7346 #if MG_ENABLE_CUSTOM_RANDOM
7348 void mg_random(void *buf, size_t len) {
7350 unsigned char *p = (unsigned char *) buf;
7351 #if MG_ARCH == MG_ARCH_ESP32
7352 while (len--) *p++ = (unsigned char) (esp_random() & 255);
7354 #elif MG_ARCH == MG_ARCH_WIN32
7355 #elif MG_ARCH == MG_ARCH_UNIX
7356 FILE *fp = fopen("/dev/urandom", "rb");
7358 if (fread(buf, 1, len, fp) == len) done = true;
7362 // If everything above did not work, fallback to a pseudo random generator
7363 while (!done && len--) *p++ = (unsigned char) (rand() & 255);
7367 char *mg_random_str(char *buf, size_t len) {
7369 mg_random(buf, len);
7370 for (i = 0; i < len; i++) {
7371 uint8_t c = ((uint8_t *) buf)[i] % 62U;
7372 buf[i] = i == len - 1 ? (char) '\0' // 0-terminate last byte
7373 : c < 26 ? (char) ('a' + c) // lowercase
7374 : c < 52 ? (char) ('A' + c - 26) // uppercase
7375 : (char) ('0' + c - 52); // numeric
7380 uint32_t mg_ntohl(uint32_t net) {
7381 uint8_t data[4] = {0, 0, 0, 0};
7382 memcpy(&data, &net, sizeof(data));
7383 return (((uint32_t) data[3]) << 0) | (((uint32_t) data[2]) << 8) |
7384 (((uint32_t) data[1]) << 16) | (((uint32_t) data[0]) << 24);
7387 uint16_t mg_ntohs(uint16_t net) {
7388 uint8_t data[2] = {0, 0};
7389 memcpy(&data, &net, sizeof(data));
7390 return (uint16_t) ((uint16_t) data[1] | (((uint16_t) data[0]) << 8));
7393 uint32_t mg_crc32(uint32_t crc, const char *buf, size_t len) {
7394 static const uint32_t crclut[16] = {
7395 // table for polynomial 0xEDB88320 (reflected)
7396 0x00000000, 0x1DB71064, 0x3B6E20C8, 0x26D930AC, 0x76DC4190, 0x6B6B51F4,
7397 0x4DB26158, 0x5005713C, 0xEDB88320, 0xF00F9344, 0xD6D6A3E8, 0xCB61B38C,
7398 0x9B64C2B0, 0x86D3D2D4, 0xA00AE278, 0xBDBDF21C};
7401 uint8_t byte = *(uint8_t *) buf++;
7402 crc = crclut[(crc ^ byte) & 0x0F] ^ (crc >> 4);
7403 crc = crclut[(crc ^ (byte >> 4)) & 0x0F] ^ (crc >> 4);
7408 static int isbyte(int n) {
7409 return n >= 0 && n <= 255;
7412 static int parse_net(const char *spec, uint32_t *net, uint32_t *mask) {
7413 int n, a, b, c, d, slash = 32, len = 0;
7414 if ((sscanf(spec, "%d.%d.%d.%d/%d%n", &a, &b, &c, &d, &slash, &n) == 5 ||
7415 sscanf(spec, "%d.%d.%d.%d%n", &a, &b, &c, &d, &n) == 4) &&
7416 isbyte(a) && isbyte(b) && isbyte(c) && isbyte(d) && slash >= 0 &&
7419 *net = ((uint32_t) a << 24) | ((uint32_t) b << 16) | ((uint32_t) c << 8) |
7421 *mask = slash ? (uint32_t) (0xffffffffU << (32 - slash)) : (uint32_t) 0;
7426 int mg_check_ip_acl(struct mg_str acl, struct mg_addr *remote_ip) {
7428 int allowed = acl.len == 0 ? '+' : '-'; // If any ACL is set, deny by default
7429 uint32_t remote_ip4;
7430 if (remote_ip->is_ip6) {
7431 return -1; // TODO(): handle IPv6 ACL and addresses
7433 memcpy((void *) &remote_ip4, remote_ip->ip, sizeof(remote_ip4));
7434 while (mg_commalist(&acl, &k, &v)) {
7436 if (k.ptr[0] != '+' && k.ptr[0] != '-') return -1;
7437 if (parse_net(&k.ptr[1], &net, &mask) == 0) return -2;
7438 if ((mg_ntohl(remote_ip4) & mask) == net) allowed = k.ptr[0];
7441 return allowed == '+';
7444 #if MG_ENABLE_CUSTOM_MILLIS
7446 uint64_t mg_millis(void) {
7447 #if MG_ARCH == MG_ARCH_WIN32
7448 return GetTickCount();
7449 #elif MG_ARCH == MG_ARCH_RP2040
7450 return time_us_64() / 1000;
7451 #elif MG_ARCH == MG_ARCH_ESP32
7452 return esp_timer_get_time() / 1000;
7453 #elif MG_ARCH == MG_ARCH_ESP8266 || MG_ARCH == MG_ARCH_FREERTOS
7454 return xTaskGetTickCount() * portTICK_PERIOD_MS;
7455 #elif MG_ARCH == MG_ARCH_AZURERTOS
7456 return tx_time_get() * (1000 /* MS per SEC */ / TX_TIMER_TICKS_PER_SECOND);
7457 #elif MG_ARCH == MG_ARCH_TIRTOS
7458 return (uint64_t) Clock_getTicks();
7459 #elif MG_ARCH == MG_ARCH_ZEPHYR
7460 return (uint64_t) k_uptime_get();
7461 #elif MG_ARCH == MG_ARCH_CMSIS_RTOS1
7462 return (uint64_t) rt_time_get();
7463 #elif MG_ARCH == MG_ARCH_CMSIS_RTOS2
7464 return (uint64_t) ((osKernelGetTickCount() * 1000) / osKernelGetTickFreq());
7465 #elif MG_ARCH == MG_ARCH_RTTHREAD
7466 return (uint64_t) ((rt_tick_get() * 1000) / RT_TICK_PER_SECOND);
7467 #elif MG_ARCH == MG_ARCH_UNIX && defined(__APPLE__)
7468 // Apple CLOCK_MONOTONIC_RAW is equivalent to CLOCK_BOOTTIME on linux
7469 // Apple CLOCK_UPTIME_RAW is equivalent to CLOCK_MONOTONIC_RAW on linux
7470 return clock_gettime_nsec_np(CLOCK_UPTIME_RAW) / 1000000;
7471 #elif MG_ARCH == MG_ARCH_UNIX
7472 struct timespec ts = {0, 0};
7473 // See #1615 - prefer monotonic clock
7474 #if defined(CLOCK_MONOTONIC_RAW)
7475 // Raw hardware-based time that is not subject to NTP adjustment
7476 clock_gettime(CLOCK_MONOTONIC_RAW, &ts);
7477 #elif defined(CLOCK_MONOTONIC)
7478 // Affected by the incremental adjustments performed by adjtime and NTP
7479 clock_gettime(CLOCK_MONOTONIC, &ts);
7481 // Affected by discontinuous jumps in the system time and by the incremental
7482 // adjustments performed by adjtime and NTP
7483 clock_gettime(CLOCK_REALTIME, &ts);
7485 return ((uint64_t) ts.tv_sec * 1000 + (uint64_t) ts.tv_nsec / 1000000);
7486 #elif defined(ARDUINO)
7487 return (uint64_t) millis();
7489 return (uint64_t) (time(NULL) * 1000);
7494 #ifdef MG_ENABLE_LINES
7514 size_t mg_ws_vprintf(struct mg_connection *c, int op, const char *fmt,
7516 size_t len = c->send.len;
7517 size_t n = mg_vxprintf(mg_pfn_iobuf, &c->send, fmt, ap);
7518 mg_ws_wrap(c, c->send.len - len, op);
7522 size_t mg_ws_printf(struct mg_connection *c, int op, const char *fmt, ...) {
7526 len = mg_ws_vprintf(c, op, fmt, &ap);
7531 static void ws_handshake(struct mg_connection *c, const struct mg_str *wskey,
7532 const struct mg_str *wsproto, const char *fmt,
7534 const char *magic = "258EAFA5-E914-47DA-95CA-C5AB0DC85B11";
7535 unsigned char sha[20], b64_sha[30];
7537 mg_sha1_ctx sha_ctx;
7538 mg_sha1_init(&sha_ctx);
7539 mg_sha1_update(&sha_ctx, (unsigned char *) wskey->ptr, wskey->len);
7540 mg_sha1_update(&sha_ctx, (unsigned char *) magic, 36);
7541 mg_sha1_final(sha, &sha_ctx);
7542 mg_base64_encode(sha, sizeof(sha), (char *) b64_sha);
7543 mg_xprintf(mg_pfn_iobuf, &c->send,
7544 "HTTP/1.1 101 Switching Protocols\r\n"
7545 "Upgrade: websocket\r\n"
7546 "Connection: Upgrade\r\n"
7547 "Sec-WebSocket-Accept: %s\r\n",
7549 if (fmt != NULL) mg_vxprintf(mg_pfn_iobuf, &c->send, fmt, ap);
7550 if (wsproto != NULL) {
7551 mg_printf(c, "Sec-WebSocket-Protocol: %.*s\r\n", (int) wsproto->len,
7554 mg_send(c, "\r\n", 2);
7557 static uint32_t be32(const uint8_t *p) {
7558 return (((uint32_t) p[3]) << 0) | (((uint32_t) p[2]) << 8) |
7559 (((uint32_t) p[1]) << 16) | (((uint32_t) p[0]) << 24);
7562 static size_t ws_process(uint8_t *buf, size_t len, struct ws_msg *msg) {
7563 size_t i, n = 0, mask_len = 0;
7564 memset(msg, 0, sizeof(*msg));
7566 n = buf[1] & 0x7f; // Frame length
7567 mask_len = buf[1] & 128 ? 4 : 0; // last bit is a mask bit
7568 msg->flags = buf[0];
7569 if (n < 126 && len >= mask_len) {
7571 msg->header_len = 2 + mask_len;
7572 } else if (n == 126 && len >= 4 + mask_len) {
7573 msg->header_len = 4 + mask_len;
7574 msg->data_len = (((size_t) buf[2]) << 8) | buf[3];
7575 } else if (len >= 10 + mask_len) {
7576 msg->header_len = 10 + mask_len;
7578 (size_t) (((uint64_t) be32(buf + 2) << 32) + be32(buf + 6));
7581 // Sanity check, and integer overflow protection for the boundary check below
7582 // data_len should not be larger than 1 Gb
7583 if (msg->data_len > 1024 * 1024 * 1024) return 0;
7584 if (msg->header_len + msg->data_len > len) return 0;
7586 uint8_t *p = buf + msg->header_len, *m = p - mask_len;
7587 for (i = 0; i < msg->data_len; i++) p[i] ^= m[i & 3];
7589 return msg->header_len + msg->data_len;
7592 static size_t mkhdr(size_t len, int op, bool is_client, uint8_t *buf) {
7594 buf[0] = (uint8_t) (op | 128);
7596 buf[1] = (unsigned char) len;
7598 } else if (len < 65536) {
7599 uint16_t tmp = mg_htons((uint16_t) len);
7601 memcpy(&buf[2], &tmp, sizeof(tmp));
7606 tmp = mg_htonl((uint32_t) (((uint64_t) len) >> 32));
7607 memcpy(&buf[2], &tmp, sizeof(tmp));
7608 tmp = mg_htonl((uint32_t) (len & 0xffffffffU));
7609 memcpy(&buf[6], &tmp, sizeof(tmp));
7613 buf[1] |= 1 << 7; // Set masking flag
7614 mg_random(&buf[n], 4);
7620 static void mg_ws_mask(struct mg_connection *c, size_t len) {
7621 if (c->is_client && c->send.buf != NULL) {
7623 uint8_t *p = c->send.buf + c->send.len - len, *mask = p - 4;
7624 for (i = 0; i < len; i++) p[i] ^= mask[i & 3];
7628 size_t mg_ws_send(struct mg_connection *c, const void *buf, size_t len,
7631 size_t header_len = mkhdr(len, op, c->is_client, header);
7632 mg_send(c, header, header_len);
7633 MG_VERBOSE(("WS out: %d [%.*s]", (int) len, (int) len, buf));
7634 mg_send(c, buf, len);
7636 return header_len + len;
7639 static bool mg_ws_client_handshake(struct mg_connection *c) {
7640 int n = mg_http_get_request_len(c->recv.buf, c->recv.len);
7642 mg_error(c, "not http"); // Some just, not an HTTP request
7644 if (n < 15 || memcmp(c->recv.buf + 9, "101", 3) != 0) {
7645 mg_error(c, "ws handshake error");
7647 struct mg_http_message hm;
7648 if (mg_http_parse((char *) c->recv.buf, c->recv.len, &hm)) {
7649 c->is_websocket = 1;
7650 mg_call(c, MG_EV_WS_OPEN, &hm);
7652 mg_error(c, "ws handshake error");
7655 mg_iobuf_del(&c->recv, 0, (size_t) n);
7657 return true; // Request is not yet received, quit event handler
7659 return false; // Continue event handler
7662 static void mg_ws_cb(struct mg_connection *c, int ev, void *ev_data,
7665 size_t ofs = (size_t) c->pfn_data;
7667 // assert(ofs < c->recv.len);
7668 if (ev == MG_EV_READ) {
7669 if (c->is_client && !c->is_websocket && mg_ws_client_handshake(c)) return;
7671 while (ws_process(c->recv.buf + ofs, c->recv.len - ofs, &msg) > 0) {
7672 char *s = (char *) c->recv.buf + ofs + msg.header_len;
7673 struct mg_ws_message m = {{s, msg.data_len}, msg.flags};
7674 size_t len = msg.header_len + msg.data_len;
7675 uint8_t final = msg.flags & 128, op = msg.flags & 15;
7676 // MG_VERBOSE ("fin %d op %d len %d [%.*s]", final, op,
7677 // (int) m.data.len, (int) m.data.len, m.data.ptr));
7679 case WEBSOCKET_OP_CONTINUE:
7680 mg_call(c, MG_EV_WS_CTL, &m);
7682 case WEBSOCKET_OP_PING:
7683 MG_DEBUG(("%s", "WS PONG"));
7684 mg_ws_send(c, s, msg.data_len, WEBSOCKET_OP_PONG);
7685 mg_call(c, MG_EV_WS_CTL, &m);
7687 case WEBSOCKET_OP_PONG:
7688 mg_call(c, MG_EV_WS_CTL, &m);
7690 case WEBSOCKET_OP_TEXT:
7691 case WEBSOCKET_OP_BINARY:
7692 if (final) mg_call(c, MG_EV_WS_MSG, &m);
7694 case WEBSOCKET_OP_CLOSE:
7695 MG_DEBUG(("%lu WS CLOSE", c->id));
7696 mg_call(c, MG_EV_WS_CTL, &m);
7697 // Echo the payload of the received CLOSE message back to the sender
7698 mg_ws_send(c, m.data.ptr, m.data.len, WEBSOCKET_OP_CLOSE);
7702 // Per RFC6455, close conn when an unknown op is recvd
7703 mg_error(c, "unknown WS op %d", op);
7707 // Handle fragmented frames: strip header, keep in c->recv
7708 if (final == 0 || op == 0) {
7709 if (op) ofs++, len--, msg.header_len--; // First frame
7710 mg_iobuf_del(&c->recv, ofs, msg.header_len); // Strip header
7711 len -= msg.header_len;
7713 c->pfn_data = (void *) ofs;
7714 // MG_INFO(("FRAG %d [%.*s]", (int) ofs, (int) ofs, c->recv.buf));
7716 // Remove non-fragmented frame
7717 if (final && op) mg_iobuf_del(&c->recv, ofs, len);
7718 // Last chunk of the fragmented frame
7720 m.flags = c->recv.buf[0];
7721 m.data = mg_str_n((char *) &c->recv.buf[1], (size_t) (ofs - 1));
7722 mg_call(c, MG_EV_WS_MSG, &m);
7723 mg_iobuf_del(&c->recv, 0, ofs);
7733 struct mg_connection *mg_ws_connect(struct mg_mgr *mgr, const char *url,
7734 mg_event_handler_t fn, void *fn_data,
7735 const char *fmt, ...) {
7736 struct mg_connection *c = mg_connect(mgr, url, fn, fn_data);
7738 char nonce[16], key[30];
7739 struct mg_str host = mg_url_host(url);
7740 mg_random(nonce, sizeof(nonce));
7741 mg_base64_encode((unsigned char *) nonce, sizeof(nonce), key);
7742 mg_xprintf(mg_pfn_iobuf, &c->send,
7743 "GET %s HTTP/1.1\r\n"
7744 "Upgrade: websocket\r\n"
7746 "Connection: Upgrade\r\n"
7747 "Sec-WebSocket-Version: 13\r\n"
7748 "Sec-WebSocket-Key: %s\r\n",
7749 mg_url_uri(url), (int) host.len, host.ptr, key);
7753 mg_vxprintf(mg_pfn_iobuf, &c->send, fmt, &ap);
7756 mg_xprintf(mg_pfn_iobuf, &c->send, "\r\n");
7763 void mg_ws_upgrade(struct mg_connection *c, struct mg_http_message *hm,
7764 const char *fmt, ...) {
7765 struct mg_str *wskey = mg_http_get_header(hm, "Sec-WebSocket-Key");
7768 if (wskey == NULL) {
7769 mg_http_reply(c, 426, "", "WS upgrade expected\n");
7772 struct mg_str *wsproto = mg_http_get_header(hm, "Sec-WebSocket-Protocol");
7775 ws_handshake(c, wskey, wsproto, fmt, &ap);
7777 c->is_websocket = 1;
7779 mg_call(c, MG_EV_WS_OPEN, hm);
7783 size_t mg_ws_wrap(struct mg_connection *c, size_t len, int op) {
7784 uint8_t header[14], *p;
7785 size_t header_len = mkhdr(len, op, c->is_client, header);
7787 // NOTE: order of operations is important!
7788 mg_iobuf_add(&c->send, c->send.len, NULL, header_len);
7789 p = &c->send.buf[c->send.len - len]; // p points to data
7790 memmove(p, p - header_len, len); // Shift data
7791 memcpy(p - header_len, header, header_len); // Prepend header
7792 mg_ws_mask(c, len); // Mask data
7797 #ifdef MG_ENABLE_LINES
7798 #line 1 "src/drivers/rt1020.c"
7804 * This driver doesn't support 10M line autoconfiguration yet.
7805 * Packets aren't sent if the link negociated 10M line.
7806 * todo: MAC back auto reconfiguration.
7809 #if MG_ENABLE_TCPIP && defined(MG_ENABLE_DRIVER_IMXRT1020)
7810 struct imx_rt1020_enet {
7811 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;
7815 #define ENET ((struct imx_rt1020_enet *) (uintptr_t) 0x402D8000u)
7818 #define BIT(x) ((uint32_t) 1 << (x))
7820 #define ENET_RXBUFF_SIZE 1536 // 1522 Buffer must be 64bits aligned
7821 #define ENET_TXBUFF_SIZE 1536 // 1522 hence set to 0x600 (1536)
7822 #define ENET_RXBD_NUM (4)
7823 #define ENET_TXBD_NUM (4)
7825 const uint32_t EIMR_RX_ERR = 0x2400000; // Intr mask RXF+EBERR
7827 void ETH_IRQHandler(void);
7828 static bool mg_tcpip_driver_imxrt1020_init(struct mg_tcpip_if *ifp);
7829 static void wait_phy_complete(void);
7830 static struct mg_tcpip_if *s_ifp; // MIP interface
7832 static size_t mg_tcpip_driver_imxrt1020_tx(const void *, size_t , struct mg_tcpip_if *);
7833 static bool mg_tcpip_driver_imxrt1020_up(struct mg_tcpip_if *ifp);
7835 enum { IMXRT1020_PHY_ADDR = 0x02, IMXRT1020_PHY_BCR = 0, IMXRT1020_PHY_BSR = 1 }; // PHY constants
7837 void delay(uint32_t);
7838 void delay (uint32_t di) {
7839 volatile int dno = 0; // Prevent optimization
7840 for (uint32_t i = 0; i < di; i++)
7841 for (int j=0; j<20; j++) // PLLx20 (500 MHz/24MHz)
7845 static void wait_phy_complete(void) {
7847 const uint32_t delay_max = 0x00100000;
7848 uint32_t delay_cnt = 0;
7849 while (!(ENET->EIR & BIT(23)) && (delay_cnt < delay_max))
7851 ENET->EIR |= BIT(23); // MII interrupt clear
7854 static uint32_t imxrt1020_eth_read_phy(uint8_t addr, uint8_t reg) {
7855 ENET->EIR |= BIT(23); // MII interrupt clear
7856 uint32_t mask_phy_adr_reg = 0x1f; // 0b00011111: Ensure we write 5 bits (Phy address & register)
7857 uint32_t phy_transaction = 0x00;
7858 phy_transaction = (0x1 << 30) \
7860 | ((uint32_t)(addr & mask_phy_adr_reg) << 23) \
7861 | ((uint32_t)(reg & mask_phy_adr_reg) << 18) \
7864 ENET->MMFR = phy_transaction;
7865 wait_phy_complete();
7867 return (ENET->MMFR & 0x0000ffff);
7870 static void imxrt1020_eth_write_phy(uint8_t addr, uint8_t reg, uint32_t val) {
7871 ENET->EIR |= BIT(23); // MII interrupt clear
7872 uint8_t mask_phy_adr_reg = 0x1f; // 0b00011111: Ensure we write 5 bits (Phy address & register)
7873 uint32_t mask_phy_data = 0x0000ffff; // Ensure we write 16 bits (data)
7874 addr &= mask_phy_adr_reg;
7875 reg &= mask_phy_adr_reg;
7876 val &= mask_phy_data;
7877 uint32_t phy_transaction = 0x00;
7878 phy_transaction = (uint32_t)(0x1 << 30) \
7879 | (uint32_t)(0x1 << 28) \
7880 | (uint32_t)(addr << 23) \
7881 | (uint32_t)(reg << 18) \
7882 | (uint32_t)(0x2 << 16) \
7884 ENET->MMFR = phy_transaction;
7885 wait_phy_complete();
7888 // FEC RX/TX descriptors (Enhanced descriptor not enabled)
7889 // Descriptor buffer structure, little endian
7891 typedef struct enet_bd_struct_def
7893 uint16_t length; // Data length
7894 uint16_t control; // Control and status
7895 uint32_t *buffer; // Data ptr
7898 // Descriptor and buffer globals, in non-cached area, 64 bits aligned.
7900 __attribute__((section("NonCacheable,\"aw\",%nobits @"))) enet_bd_struct_t rx_buffer_descriptor[(ENET_RXBD_NUM)] __attribute__((aligned((64U))));
7901 __attribute__((section("NonCacheable,\"aw\",%nobits @"))) enet_bd_struct_t tx_buffer_descriptor[(ENET_TXBD_NUM)] __attribute__((aligned((64U))));
7903 uint8_t rx_data_buffer[(ENET_RXBD_NUM)][((unsigned int)(((ENET_RXBUFF_SIZE)) + (((64U))-1U)) & (unsigned int)(~(unsigned int)(((64U))-1U)))] __attribute__((aligned((64U))));
7904 uint8_t tx_data_buffer[(ENET_TXBD_NUM)][((unsigned int)(((ENET_TXBUFF_SIZE)) + (((64U))-1U)) & (unsigned int)(~(unsigned int)(((64U))-1U)))] __attribute__((aligned((64U))));
7906 // Initialise driver imx_rt1020
7908 // static bool mg_tcpip_driver_imxrt1020_init(uint8_t *mac, void *data) { // VO
7909 static bool mg_tcpip_driver_imxrt1020_init(struct mg_tcpip_if *ifp) {
7911 struct mg_tcpip_driver_imxrt1020_data *d = (struct mg_tcpip_driver_imxrt1020_data *) ifp->driver_data;
7914 // ENET Reset, wait complete
7915 ENET->ECR |= BIT(0);
7916 while((ENET->ECR & BIT(0)) != 0) {}
7918 // Re-latches the pin strapping pin values
7919 ENET->ECR |= BIT(0);
7920 while((ENET->ECR & BIT(0)) != 0) {}
7922 // Setup MII/RMII MDC clock divider (<= 2.5MHz).
7923 ENET->MSCR = 0x130; // HOLDTIME 2 clk, Preamble enable, MDC MII_Speed Div 0x30
7924 imxrt1020_eth_write_phy(IMXRT1020_PHY_ADDR, IMXRT1020_PHY_BCR, 0x8000); // PHY W @0x00 D=0x8000 Soft reset
7925 while (imxrt1020_eth_read_phy(IMXRT1020_PHY_ADDR, IMXRT1020_PHY_BSR) & BIT(15)) {delay(0x5000);} // Wait finished poll 10ms
7929 imxrt1020_eth_write_phy(IMXRT1020_PHY_ADDR, IMXRT1020_PHY_BCR, 0x1200); // PHY W @0x00 D=0x1200 Autonego enable + start
7930 imxrt1020_eth_write_phy(IMXRT1020_PHY_ADDR, 0x1f, 0x8180); // PHY W @0x1f D=0x8180 Ref clock 50 MHz at XI input
7932 uint32_t bcr = imxrt1020_eth_read_phy(IMXRT1020_PHY_ADDR, IMXRT1020_PHY_BCR);
7933 bcr &= ~BIT(10); // Isolation -> Normal
7934 imxrt1020_eth_write_phy(IMXRT1020_PHY_ADDR, IMXRT1020_PHY_BCR, bcr);
7938 ENET->ECR = 0x0; // Disable before configuration
7941 ENET->RCR = 0x05ee0104; // #CRCFWD=0 (CRC kept in frame) + RMII + MII Enable
7943 ENET->TCR = BIT(8) | BIT(2); // Addins (MAC address from PAUR+PALR) + Full duplex enable
7944 //ENET->TFWR = BIT(8); // Store And Forward Enable, 64 bytes (minimize tx latency)
7946 // Configure descriptors and buffers
7948 for (int i = 0; i < ENET_RXBD_NUM; i++) {
7949 // Wrap last descriptor buffer ptr
7950 rx_buffer_descriptor[i].control = (BIT(15) | ((i<(ENET_RXBD_NUM-1))?0:BIT(13))); // E+(W*)
7951 rx_buffer_descriptor[i].buffer = (uint32_t *)rx_data_buffer[i];
7955 for (int i = 0; i < ENET_TXBD_NUM; i++) {
7956 // Wrap last descriptor buffer ptr
7957 tx_buffer_descriptor[i].control = ((i<(ENET_RXBD_NUM-1))?0:BIT(13)) | BIT(10); // (W*)+TC
7958 tx_buffer_descriptor[i].buffer = (uint32_t *)tx_data_buffer[i];
7961 // Continue ENET configuration
7962 ENET->RDSR = (uint32_t)(uintptr_t)rx_buffer_descriptor;
7963 ENET->TDSR = (uint32_t)(uintptr_t)tx_buffer_descriptor;
7964 ENET->MRBR[0] = ENET_RXBUFF_SIZE; // Same size for RX/TX buffers
7966 // MAC address filtering (bytes in reversed order)
7967 ENET->PAUR = ((uint32_t) ifp->mac[4] << 24U) | (uint32_t) ifp->mac[5] << 16U;
7968 ENET->PALR = (uint32_t) (ifp->mac[0] << 24U) | ((uint32_t) ifp->mac[1] << 16U) |
7969 ((uint32_t) ifp->mac[2] << 8U) | ifp->mac[3];
7971 // Init Hash tables (mac filtering)
7972 ENET->IAUR = 0; // Unicast
7974 ENET->GAUR = 0; // Multicast
7978 ENET->ECR |= BIT(8); // ENET Set Little-endian + (FEC buffer desc.)
7979 ENET->ECR |= BIT(1); // Enable
7981 // Set interrupt mask
7982 ENET->EIMR = EIMR_RX_ERR;
7984 // RX Descriptor activation
7985 ENET->RDAR = BIT(24); // Activate Receive Descriptor
7990 static uint32_t s_rt1020_txno;
7992 static size_t mg_tcpip_driver_imxrt1020_tx(const void *buf, size_t len, struct mg_tcpip_if *ifp) {
7994 if (len > sizeof(tx_data_buffer[ENET_TXBD_NUM])) {
7995 // MG_ERROR(("Frame too big, %ld", (long) len));
7996 len = 0; // Frame is too big
7997 } else if ((tx_buffer_descriptor[s_rt1020_txno].control & BIT(15))) {
7998 MG_ERROR(("No free descriptors"));
7999 // printf("D0 %lx SR %lx\n", (long) s_txdesc[0][0], (long) ETH->DMASR);
8000 len = 0; // All descriptors are busy, fail
8002 memcpy(tx_data_buffer[s_rt1020_txno], buf, len); // Copy data
8003 tx_buffer_descriptor[s_rt1020_txno].length = (uint16_t) len; // Set data len
8004 tx_buffer_descriptor[s_rt1020_txno].control |= (uint16_t)(BIT(10)); // TC (transmit CRC)
8005 // tx_buffer_descriptor[s_rt1020_txno].control &= (uint16_t)(BIT(14) | BIT(12)); // Own doesn't affect HW
8006 tx_buffer_descriptor[s_rt1020_txno].control |= (uint16_t)(BIT(15) | BIT(11)); // R+L (ready+last)
8007 ENET->TDAR = BIT(24); // Descriptor updated. Hand over to DMA.
8009 // Relevant Descriptor bits: 15(R) Ready
8010 // 11(L) last in frame
8011 // 10(TC) transmis CRC
8012 // __DSB(); // ARM errata 838869 Cortex-M4, M4F, M7, M7F: "store immediate overlapping
8013 // exception" return might vector to incorrect interrupt.
8014 if (++s_rt1020_txno >= ENET_TXBD_NUM) s_rt1020_txno = 0;
8021 static uint32_t s_rt1020_rxno;
8023 void ENET_IRQHandler(void) {
8024 ENET->EIMR = 0; // Mask interrupts.
8025 uint32_t eir = ENET->EIR; // Read EIR
8026 ENET->EIR = 0xffffffff; // Clear interrupts
8028 if (eir & EIMR_RX_ERR) // Global mask used
8030 if (rx_buffer_descriptor[s_rt1020_rxno].control & BIT(15)) {
8031 ENET->EIMR = EIMR_RX_ERR; // Enable interrupts
8032 return; // Empty? -> exit.
8035 else { // Frame received, loop
8036 for (uint32_t i = 0; i < 10; i++) { // read as they arrive but not forever
8037 if (rx_buffer_descriptor[s_rt1020_rxno].control & BIT(15)) break; // exit when done
8038 // Process if CRC OK and frame not truncated
8039 if (!(rx_buffer_descriptor[s_rt1020_rxno].control & (BIT(2) | BIT(0)))) {
8040 uint32_t len = (rx_buffer_descriptor[s_rt1020_rxno].length);
8041 mg_tcpip_qwrite(rx_buffer_descriptor[s_rt1020_rxno].buffer, len > 4 ? len - 4 : len, s_ifp);
8043 rx_buffer_descriptor[s_rt1020_rxno].control |= BIT(15); // Inform DMA RX is empty
8044 if (++s_rt1020_rxno >= ENET_RXBD_NUM) s_rt1020_rxno = 0;
8048 ENET->EIMR = EIMR_RX_ERR; // Enable interrupts
8052 static bool mg_tcpip_driver_imxrt1020_up(struct mg_tcpip_if *ifp) {
8053 uint32_t bsr = imxrt1020_eth_read_phy(IMXRT1020_PHY_ADDR, IMXRT1020_PHY_BSR);
8055 return bsr & BIT(2) ? 1 : 0;
8059 struct mg_tcpip_driver mg_tcpip_driver_imxrt1020 = {
8060 mg_tcpip_driver_imxrt1020_init, mg_tcpip_driver_imxrt1020_tx, NULL,
8061 mg_tcpip_driver_imxrt1020_up};
8065 #ifdef MG_ENABLE_LINES
8066 #line 1 "src/drivers/same54.c"
8070 #if MG_ENABLE_TCPIP && defined(MG_ENABLE_DRIVER_SAME54) && \
8071 MG_ENABLE_DRIVER_SAME54
8076 #define BIT(x) ((uint32_t) 1 << (x))
8077 #define ETH_PKT_SIZE 1536 // Max frame size
8078 #define ETH_DESC_CNT 4 // Descriptors count
8079 #define ETH_DS 2 // Descriptor size (words)
8081 static uint8_t s_rxbuf[ETH_DESC_CNT][ETH_PKT_SIZE];
8082 static uint8_t s_txbuf[ETH_DESC_CNT][ETH_PKT_SIZE];
8083 static uint32_t s_rxdesc[ETH_DESC_CNT][ETH_DS]; // RX descriptors
8084 static uint32_t s_txdesc[ETH_DESC_CNT][ETH_DS]; // TX descriptors
8085 static uint8_t s_txno; // Current TX descriptor
8086 static uint8_t s_rxno; // Current RX descriptor
8088 static struct mg_tcpip_if *s_ifp; // MIP interface
8089 enum { PHY_ADDR = 0, PHY_BCR = 0, PHY_BSR = 1 };
8091 #define PHY_BCR_DUPLEX_MODE_Msk BIT(8)
8092 #define PHY_BCR_SPEED_Msk BIT(13)
8093 #define PHY_BSR_LINK_STATUS_Msk BIT(2)
8095 static uint16_t eth_read_phy(uint8_t addr, uint8_t reg) {
8096 GMAC_REGS->GMAC_MAN = GMAC_MAN_CLTTO_Msk |
8097 GMAC_MAN_OP(2) | // Setting the read operation
8098 GMAC_MAN_WTN(2) | GMAC_MAN_PHYA(addr) | // PHY address
8099 GMAC_MAN_REGA(reg); // Setting the register
8100 while (!(GMAC_REGS->GMAC_NSR & GMAC_NSR_IDLE_Msk)) (void) 0;
8101 return GMAC_REGS->GMAC_MAN & GMAC_MAN_DATA_Msk; // Getting the read value
8105 static void eth_write_phy(uint8_t addr, uint8_t reg, uint16_t val) {
8106 GMAC_REGS->GMAC_MAN = GMAC_MAN_CLTTO_Msk | GMAC_MAN_OP(1) | // Setting the write operation
8107 GMAC_MAN_WTN(2) | GMAC_MAN_PHYA(addr) | // PHY address
8108 GMAC_MAN_REGA(reg) | GMAC_MAN_DATA(val); // Setting the register
8109 while (!(GMAC_REGS->GMAC_NSR & GMAC_NSR_IDLE_Msk)); // Waiting until the write op is complete
8113 int get_clock_rate(struct mg_tcpip_driver_same54_data *d) {
8114 if (d && d->mdc_cr >= 0 && d->mdc_cr <= 5) {
8117 // get MCLK from GCLK_GENERATOR 0
8120 if (!(GCLK_REGS->GCLK_GENCTRL[0] & GCLK_GENCTRL_DIVSEL_Msk)) {
8121 div = ((GCLK_REGS->GCLK_GENCTRL[0] & 0x00FF0000) >> 16);
8122 if (div == 0) div = 1;
8124 switch (GCLK_REGS->GCLK_GENCTRL[0] & GCLK_GENCTRL_SRC_Msk) {
8125 case GCLK_GENCTRL_SRC_XOSC0_Val:
8126 mclk = 32000000UL; /* 32MHz */
8128 case GCLK_GENCTRL_SRC_XOSC1_Val:
8129 mclk = 32000000UL; /* 32MHz */
8131 case GCLK_GENCTRL_SRC_OSCULP32K_Val:
8134 case GCLK_GENCTRL_SRC_XOSC32K_Val:
8137 case GCLK_GENCTRL_SRC_DFLL_Val:
8138 mclk = 48000000UL; /* 48MHz */
8140 case GCLK_GENCTRL_SRC_DPLL0_Val:
8141 mclk = 200000000UL; /* 200MHz */
8143 case GCLK_GENCTRL_SRC_DPLL1_Val:
8144 mclk = 200000000UL; /* 200MHz */
8147 mclk = 200000000UL; /* 200MHz */
8151 uint8_t crs[] = {0, 1, 2, 3, 4, 5}; // GMAC->NCFGR::CLK values
8152 uint8_t dividers[] = {8, 16, 32, 48, 64, 128}; // Respective CLK dividers
8153 for (int i = 0; i < 6; i++) {
8154 if (mclk / dividers[i] <= 2375000UL /* 2.5MHz - 5% */) {
8163 static bool mg_tcpip_driver_same54_init(struct mg_tcpip_if *ifp) {
8164 struct mg_tcpip_driver_same54_data *d =
8165 (struct mg_tcpip_driver_same54_data *) ifp->driver_data;
8168 MCLK_REGS->MCLK_APBCMASK |= MCLK_APBCMASK_GMAC_Msk;
8169 MCLK_REGS->MCLK_AHBMASK |= MCLK_AHBMASK_GMAC_Msk;
8170 GMAC_REGS->GMAC_NCFGR = GMAC_NCFGR_CLK(get_clock_rate(d)); // Set MDC divider
8171 GMAC_REGS->GMAC_NCR = 0; // Disable RX & TX
8172 GMAC_REGS->GMAC_NCR |= GMAC_NCR_MPE_Msk; // Enable MDC & MDIO
8174 for (int i = 0; i < ETH_DESC_CNT; i++) { // Init TX descriptors
8175 s_txdesc[i][0] = (uint32_t) s_txbuf[i]; // Point to data buffer
8176 s_txdesc[i][1] = BIT(31); // OWN bit
8178 s_txdesc[ETH_DESC_CNT - 1][1] |= BIT(30); // Last tx descriptor - wrap
8180 GMAC_REGS->GMAC_DCFGR = GMAC_DCFGR_DRBS(0x18); // DMA recv buf 1536
8181 for (int i = 0; i < ETH_DESC_CNT; i++) { // Init RX descriptors
8182 s_rxdesc[i][0] = (uint32_t) s_rxbuf[i]; // Address of the data buffer
8183 s_rxdesc[i][1] = 0; // Clear status
8185 s_rxdesc[ETH_DESC_CNT - 1][0] |= BIT(1); // Last rx descriptor - wrap
8187 GMAC_REGS->GMAC_TBQB = (uint32_t) s_txdesc; // about the descriptor addresses
8188 GMAC_REGS->GMAC_RBQB = (uint32_t) s_rxdesc; // Let the controller know
8190 GMAC_REGS->SA[0].GMAC_SAB =
8191 MG_U32(ifp->mac[3], ifp->mac[2], ifp->mac[1], ifp->mac[0]);
8192 GMAC_REGS->SA[0].GMAC_SAT = MG_U32(0, 0, ifp->mac[5], ifp->mac[4]);
8194 GMAC_REGS->GMAC_UR &= ~GMAC_UR_MII_Msk; // Disable MII, use RMII
8195 GMAC_REGS->GMAC_NCFGR |= GMAC_NCFGR_MAXFS_Msk | GMAC_NCFGR_MTIHEN_Msk |
8196 GMAC_NCFGR_EFRHD_Msk | GMAC_NCFGR_CAF_Msk;
8197 GMAC_REGS->GMAC_TSR = GMAC_TSR_HRESP_Msk | GMAC_TSR_UND_Msk |
8198 GMAC_TSR_TXCOMP_Msk | GMAC_TSR_TFC_Msk |
8199 GMAC_TSR_TXGO_Msk | GMAC_TSR_RLE_Msk |
8200 GMAC_TSR_COL_Msk | GMAC_TSR_UBR_Msk;
8201 GMAC_REGS->GMAC_RSR = GMAC_RSR_HNO_Msk | GMAC_RSR_RXOVR_Msk |
8202 GMAC_RSR_REC_Msk | GMAC_RSR_BNA_Msk;
8203 GMAC_REGS->GMAC_IDR = ~0U; // Disable interrupts, then enable required
8204 GMAC_REGS->GMAC_IER = GMAC_IER_HRESP_Msk | GMAC_IER_ROVR_Msk |
8205 GMAC_IER_TCOMP_Msk | GMAC_IER_TFC_Msk |
8206 GMAC_IER_RLEX_Msk | GMAC_IER_TUR_Msk |
8207 GMAC_IER_RXUBR_Msk | GMAC_IER_RCOMP_Msk;
8208 GMAC_REGS->GMAC_NCR |= GMAC_NCR_TXEN_Msk | GMAC_NCR_RXEN_Msk;
8209 NVIC_EnableIRQ(GMAC_IRQn);
8214 static size_t mg_tcpip_driver_same54_tx(const void *buf, size_t len,
8215 struct mg_tcpip_if *ifp) {
8216 if (len > sizeof(s_txbuf[s_txno])) {
8217 MG_ERROR(("Frame too big, %ld", (long) len));
8218 len = 0; // Frame is too big
8219 } else if ((s_txdesc[s_txno][1] & BIT(31)) == 0) {
8221 MG_ERROR(("No free descriptors"));
8222 len = 0; // All descriptors are busy, fail
8224 uint32_t status = len | BIT(15); // Frame length, last chunk
8225 if (s_txno == ETH_DESC_CNT - 1) status |= BIT(30); // wrap
8226 memcpy(s_txbuf[s_txno], buf, len); // Copy data
8227 s_txdesc[s_txno][1] = status;
8228 if (++s_txno >= ETH_DESC_CNT) s_txno = 0;
8230 __DSB(); // Ensure descriptors have been written
8231 GMAC_REGS->GMAC_NCR |= GMAC_NCR_TSTART_Msk; // Enable transmission
8235 static bool mg_tcpip_driver_same54_up(struct mg_tcpip_if *ifp) {
8236 uint16_t bsr = eth_read_phy(PHY_ADDR, PHY_BSR);
8237 bool up = bsr & PHY_BSR_LINK_STATUS_Msk ? 1 : 0;
8239 // If PHY is ready, update NCFGR accordingly
8240 if (ifp->state == MG_TCPIP_STATE_DOWN && up) {
8241 uint16_t bcr = eth_read_phy(PHY_ADDR, PHY_BCR);
8242 bool fd = bcr & PHY_BCR_DUPLEX_MODE_Msk ? 1 : 0;
8243 bool spd = bcr & PHY_BCR_SPEED_Msk ? 1 : 0;
8244 GMAC_REGS->GMAC_NCFGR |= GMAC_NCFGR_SPD(spd) | GMAC_NCFGR_FD(fd);
8250 void GMAC_Handler(void);
8251 void GMAC_Handler(void) {
8252 uint32_t isr = GMAC_REGS->GMAC_ISR;
8253 uint32_t rsr = GMAC_REGS->GMAC_RSR;
8254 uint32_t tsr = GMAC_REGS->GMAC_TSR;
8255 if (isr & GMAC_ISR_RCOMP_Msk) {
8256 if (rsr & GMAC_ISR_RCOMP_Msk) {
8257 for (uint8_t i = 0; i < ETH_DESC_CNT; i++) {
8258 if ((s_rxdesc[s_rxno][0] & BIT(0)) == 0) break;
8259 size_t len = s_rxdesc[s_rxno][1] & (BIT(13) - 1);
8260 mg_tcpip_qwrite(s_rxbuf[s_rxno], len, s_ifp);
8261 s_rxdesc[s_rxno][0] &= ~BIT(0); // Disown
8262 if (++s_rxno >= ETH_DESC_CNT) s_rxno = 0;
8267 if ((tsr & (GMAC_TSR_HRESP_Msk | GMAC_TSR_UND_Msk | GMAC_TSR_TXCOMP_Msk |
8268 GMAC_TSR_TFC_Msk | GMAC_TSR_TXGO_Msk | GMAC_TSR_RLE_Msk |
8269 GMAC_TSR_COL_Msk | GMAC_TSR_UBR_Msk)) != 0) {
8270 // MG_INFO((" --> %#x %#x", s_txdesc[s_txno][1], tsr));
8271 if (!(s_txdesc[s_txno][1] & BIT(31))) s_txdesc[s_txno][1] |= BIT(31);
8274 GMAC_REGS->GMAC_RSR = rsr;
8275 GMAC_REGS->GMAC_TSR = tsr;
8278 struct mg_tcpip_driver mg_tcpip_driver_same54 = {
8279 mg_tcpip_driver_same54_init, mg_tcpip_driver_same54_tx, NULL,
8280 mg_tcpip_driver_same54_up};
8283 #ifdef MG_ENABLE_LINES
8284 #line 1 "src/drivers/stm32.c"
8288 #if MG_ENABLE_TCPIP && defined(MG_ENABLE_DRIVER_STM32) && MG_ENABLE_DRIVER_STM32
8290 volatile uint32_t MACCR, MACFFR, MACHTHR, MACHTLR, MACMIIAR, MACMIIDR, MACFCR,
8291 MACVLANTR, RESERVED0[2], MACRWUFFR, MACPMTCSR, RESERVED1, MACDBGR, MACSR,
8292 MACIMR, MACA0HR, MACA0LR, MACA1HR, MACA1LR, MACA2HR, MACA2LR, MACA3HR,
8293 MACA3LR, RESERVED2[40], MMCCR, MMCRIR, MMCTIR, MMCRIMR, MMCTIMR,
8294 RESERVED3[14], MMCTGFSCCR, MMCTGFMSCCR, RESERVED4[5], MMCTGFCR,
8295 RESERVED5[10], MMCRFCECR, MMCRFAECR, RESERVED6[10], MMCRGUFCR,
8296 RESERVED7[334], PTPTSCR, PTPSSIR, PTPTSHR, PTPTSLR, PTPTSHUR, PTPTSLUR,
8297 PTPTSAR, PTPTTHR, PTPTTLR, RESERVED8, PTPTSSR, PTPPPSCR, RESERVED9[564],
8298 DMABMR, DMATPDR, DMARPDR, DMARDLAR, DMATDLAR, DMASR, DMAOMR, DMAIER,
8299 DMAMFBOCR, DMARSWTR, RESERVED10[8], DMACHTDR, DMACHRDR, DMACHTBAR,
8303 #define ETH ((struct stm32_eth *) (uintptr_t) 0x40028000)
8306 #if defined(__CC_ARM)
8307 #define DSB() __dsb(0xF)
8308 #elif defined(__ARMCC_VERSION)
8309 #define DSB() __builtin_arm_dsb(0xF)
8310 #elif defined(__GNUC__) && defined(__arm__) && defined(__thumb__)
8311 #define DSB() asm("DSB 0xF")
8312 #elif defined(__ICCARM__)
8313 #define DSB() __iar_builtin_DSB()
8319 #define BIT(x) ((uint32_t) 1 << (x))
8320 #define ETH_PKT_SIZE 1540 // Max frame size
8321 #define ETH_DESC_CNT 4 // Descriptors count
8322 #define ETH_DS 4 // Descriptor size (words)
8324 static uint32_t s_rxdesc[ETH_DESC_CNT][ETH_DS]; // RX descriptors
8325 static uint32_t s_txdesc[ETH_DESC_CNT][ETH_DS]; // TX descriptors
8326 static uint8_t s_rxbuf[ETH_DESC_CNT][ETH_PKT_SIZE]; // RX ethernet buffers
8327 static uint8_t s_txbuf[ETH_DESC_CNT][ETH_PKT_SIZE]; // TX ethernet buffers
8328 static uint8_t s_txno; // Current TX descriptor
8329 static uint8_t s_rxno; // Current RX descriptor
8331 static struct mg_tcpip_if *s_ifp; // MIP interface
8332 enum { PHY_ADDR = 0, PHY_BCR = 0, PHY_BSR = 1, PHY_CSCR = 31 };
8334 static uint32_t eth_read_phy(uint8_t addr, uint8_t reg) {
8335 ETH->MACMIIAR &= (7 << 2);
8336 ETH->MACMIIAR |= ((uint32_t) addr << 11) | ((uint32_t) reg << 6);
8337 ETH->MACMIIAR |= BIT(0);
8338 while (ETH->MACMIIAR & BIT(0)) (void) 0;
8339 return ETH->MACMIIDR;
8342 static void eth_write_phy(uint8_t addr, uint8_t reg, uint32_t val) {
8343 ETH->MACMIIDR = val;
8344 ETH->MACMIIAR &= (7 << 2);
8345 ETH->MACMIIAR |= ((uint32_t) addr << 11) | ((uint32_t) reg << 6) | BIT(1);
8346 ETH->MACMIIAR |= BIT(0);
8347 while (ETH->MACMIIAR & BIT(0)) (void) 0;
8350 static uint32_t get_hclk(void) {
8352 volatile uint32_t CR, PLLCFGR, CFGR;
8353 } *rcc = (struct rcc *) 0x40023800;
8354 uint32_t clk = 0, hsi = 16000000 /* 16 MHz */, hse = 8000000 /* 8MHz */;
8356 if (rcc->CFGR & (1 << 2)) {
8358 } else if (rcc->CFGR & (1 << 3)) {
8359 uint32_t vco, m, n, p;
8360 m = (rcc->PLLCFGR & (0x3f << 0)) >> 0;
8361 n = (rcc->PLLCFGR & (0x1ff << 6)) >> 6;
8362 p = (((rcc->PLLCFGR & (3 << 16)) >> 16) + 1) * 2;
8363 clk = (rcc->PLLCFGR & (1 << 22)) ? hse : hsi;
8364 vco = (uint32_t) ((uint64_t) clk * n / m);
8369 uint32_t hpre = (rcc->CFGR & (15 << 4)) >> 4;
8370 if (hpre < 8) return clk;
8372 uint8_t ahbptab[8] = {1, 2, 3, 4, 6, 7, 8, 9}; // log2(div)
8373 return ((uint32_t) clk) >> ahbptab[hpre - 8];
8376 // Guess CR from HCLK. MDC clock is generated from HCLK (AHB); as per 802.3,
8377 // it must not exceed 2.5MHz As the AHB clock can be (and usually is) derived
8378 // from the HSI (internal RC), and it can go above specs, the datasheets
8379 // specify a range of frequencies and activate one of a series of dividers to
8380 // keep the MDC clock safely below 2.5MHz. We guess a divider setting based on
8381 // HCLK with a +5% drift. If the user uses a different clock from our
8382 // defaults, needs to set the macros on top Valid for STM32F74xxx/75xxx
8383 // (38.8.1) and STM32F42xxx/43xxx (33.8.1) (both 4.5% worst case drift)
8384 static int guess_mdc_cr(void) {
8385 uint8_t crs[] = {2, 3, 0, 1, 4, 5}; // ETH->MACMIIAR::CR values
8386 uint8_t div[] = {16, 26, 42, 62, 102, 124}; // Respective HCLK dividers
8387 uint32_t hclk = get_hclk(); // Guess system HCLK
8388 int result = -1; // Invalid CR value
8389 if (hclk < 25000000) {
8390 MG_ERROR(("HCLK too low"));
8392 for (int i = 0; i < 6; i++) {
8393 if (hclk / div[i] <= 2375000UL /* 2.5MHz - 5% */) {
8398 if (result < 0) MG_ERROR(("HCLK too high"));
8400 MG_DEBUG(("HCLK: %u, CR: %d", hclk, result));
8404 static bool mg_tcpip_driver_stm32_init(struct mg_tcpip_if *ifp) {
8405 struct mg_tcpip_driver_stm32_data *d =
8406 (struct mg_tcpip_driver_stm32_data *) ifp->driver_data;
8409 // Init RX descriptors
8410 for (int i = 0; i < ETH_DESC_CNT; i++) {
8411 s_rxdesc[i][0] = BIT(31); // Own
8412 s_rxdesc[i][1] = sizeof(s_rxbuf[i]) | BIT(14); // 2nd address chained
8413 s_rxdesc[i][2] = (uint32_t) (uintptr_t) s_rxbuf[i]; // Point to data buffer
8415 (uint32_t) (uintptr_t) s_rxdesc[(i + 1) % ETH_DESC_CNT]; // Chain
8418 // Init TX descriptors
8419 for (int i = 0; i < ETH_DESC_CNT; i++) {
8420 s_txdesc[i][2] = (uint32_t) (uintptr_t) s_txbuf[i]; // Buf pointer
8422 (uint32_t) (uintptr_t) s_txdesc[(i + 1) % ETH_DESC_CNT]; // Chain
8425 ETH->DMABMR |= BIT(0); // Software reset
8426 while ((ETH->DMABMR & BIT(0)) != 0) (void) 0; // Wait until done
8428 // Set MDC clock divider. If user told us the value, use it. Otherwise, guess
8429 int cr = (d == NULL || d->mdc_cr < 0) ? guess_mdc_cr() : d->mdc_cr;
8430 ETH->MACMIIAR = ((uint32_t) cr & 7) << 2;
8432 // NOTE(cpq): we do not use extended descriptor bit 7, and do not use
8433 // hardware checksum. Therefore, descriptor size is 4, not 8
8434 // ETH->DMABMR = BIT(13) | BIT(16) | BIT(22) | BIT(23) | BIT(25);
8435 ETH->MACIMR = BIT(3) | BIT(9); // Mask timestamp & PMT IT
8436 ETH->MACFCR = BIT(7); // Disable zero quarta pause
8437 // ETH->MACFFR = BIT(31); // Receive all
8438 eth_write_phy(PHY_ADDR, PHY_BCR, BIT(15)); // Reset PHY
8439 eth_write_phy(PHY_ADDR, PHY_BCR, BIT(12)); // Set autonegotiation
8440 ETH->DMARDLAR = (uint32_t) (uintptr_t) s_rxdesc; // RX descriptors
8441 ETH->DMATDLAR = (uint32_t) (uintptr_t) s_txdesc; // RX descriptors
8442 ETH->DMAIER = BIT(6) | BIT(16); // RIE, NISE
8443 ETH->MACCR = BIT(2) | BIT(3) | BIT(11) | BIT(14); // RE, TE, Duplex, Fast
8444 ETH->DMAOMR = BIT(1) | BIT(13) | BIT(21) | BIT(25); // SR, ST, TSF, RSF
8446 // MAC address filtering
8447 ETH->MACA0HR = ((uint32_t) ifp->mac[5] << 8U) | ifp->mac[4];
8448 ETH->MACA0LR = (uint32_t) (ifp->mac[3] << 24) |
8449 ((uint32_t) ifp->mac[2] << 16) |
8450 ((uint32_t) ifp->mac[1] << 8) | ifp->mac[0];
8454 static size_t mg_tcpip_driver_stm32_tx(const void *buf, size_t len,
8455 struct mg_tcpip_if *ifp) {
8456 if (len > sizeof(s_txbuf[s_txno])) {
8457 MG_ERROR(("Frame too big, %ld", (long) len));
8458 len = 0; // Frame is too big
8459 } else if ((s_txdesc[s_txno][0] & BIT(31))) {
8461 MG_ERROR(("No free descriptors"));
8462 // printf("D0 %lx SR %lx\n", (long) s_txdesc[0][0], (long) ETH->DMASR);
8463 len = 0; // All descriptors are busy, fail
8465 memcpy(s_txbuf[s_txno], buf, len); // Copy data
8466 s_txdesc[s_txno][1] = (uint32_t) len; // Set data len
8467 s_txdesc[s_txno][0] = BIT(20) | BIT(28) | BIT(29); // Chain,FS,LS
8468 s_txdesc[s_txno][0] |= BIT(31); // Set OWN bit - let DMA take over
8469 if (++s_txno >= ETH_DESC_CNT) s_txno = 0;
8471 DSB(); // ensure descriptors have been written
8472 ETH->DMASR = BIT(2) | BIT(5); // Clear any prior TBUS/TUS
8473 ETH->DMATPDR = 0; // and resume
8477 static bool mg_tcpip_driver_stm32_up(struct mg_tcpip_if *ifp) {
8478 uint32_t bsr = eth_read_phy(PHY_ADDR, PHY_BSR);
8479 bool up = bsr & BIT(2) ? 1 : 0;
8480 if ((ifp->state == MG_TCPIP_STATE_DOWN) && up) { // link state just went up
8481 uint32_t scsr = eth_read_phy(PHY_ADDR, PHY_CSCR);
8482 uint32_t maccr = ETH->MACCR | BIT(14) | BIT(11); // 100M, Full-duplex
8483 if ((scsr & BIT(3)) == 0) maccr &= ~BIT(14); // 10M
8484 if ((scsr & BIT(4)) == 0) maccr &= ~BIT(11); // Half-duplex
8485 ETH->MACCR = maccr; // IRQ handler does not fiddle with this register
8486 MG_DEBUG(("Link is %uM %s-duplex", maccr & BIT(14) ? 100 : 10,
8487 maccr & BIT(11) ? "full" : "half"));
8492 void ETH_IRQHandler(void);
8493 void ETH_IRQHandler(void) {
8494 if (ETH->DMASR & BIT(6)) { // Frame received, loop
8495 ETH->DMASR = BIT(16) | BIT(6); // Clear flag
8496 for (uint32_t i = 0; i < 10; i++) { // read as they arrive but not forever
8497 if (s_rxdesc[s_rxno][0] & BIT(31)) break; // exit when done
8498 if (((s_rxdesc[s_rxno][0] & (BIT(8) | BIT(9))) == (BIT(8) | BIT(9))) &&
8499 !(s_rxdesc[s_rxno][0] & BIT(15))) { // skip partial/errored frames
8500 uint32_t len = ((s_rxdesc[s_rxno][0] >> 16) & (BIT(14) - 1));
8501 // printf("%lx %lu %lx %.8lx\n", s_rxno, len, s_rxdesc[s_rxno][0],
8503 mg_tcpip_qwrite(s_rxbuf[s_rxno], len > 4 ? len - 4 : len, s_ifp);
8505 s_rxdesc[s_rxno][0] = BIT(31);
8506 if (++s_rxno >= ETH_DESC_CNT) s_rxno = 0;
8509 ETH->DMASR = BIT(7); // Clear possible RBUS while processing
8510 ETH->DMARPDR = 0; // and resume RX
8513 struct mg_tcpip_driver mg_tcpip_driver_stm32 = {mg_tcpip_driver_stm32_init,
8514 mg_tcpip_driver_stm32_tx, NULL,
8515 mg_tcpip_driver_stm32_up};
8518 #ifdef MG_ENABLE_LINES
8519 #line 1 "src/drivers/stm32h.c"
8523 #if MG_ENABLE_TCPIP && defined(MG_ENABLE_DRIVER_STM32H) && \
8524 MG_ENABLE_DRIVER_STM32H
8526 volatile uint32_t MACCR, MACECR, MACPFR, MACWTR, MACHT0R, MACHT1R,
8527 RESERVED1[14], MACVTR, RESERVED2, MACVHTR, RESERVED3, MACVIR, MACIVIR,
8528 RESERVED4[2], MACTFCR, RESERVED5[7], MACRFCR, RESERVED6[7], MACISR,
8529 MACIER, MACRXTXSR, RESERVED7, MACPCSR, MACRWKPFR, RESERVED8[2], MACLCSR,
8530 MACLTCR, MACLETR, MAC1USTCR, RESERVED9[12], MACVR, MACDR, RESERVED10,
8531 MACHWF0R, MACHWF1R, MACHWF2R, RESERVED11[54], MACMDIOAR, MACMDIODR,
8532 RESERVED12[2], MACARPAR, RESERVED13[59], MACA0HR, MACA0LR, MACA1HR,
8533 MACA1LR, MACA2HR, MACA2LR, MACA3HR, MACA3LR, RESERVED14[248], MMCCR,
8534 MMCRIR, MMCTIR, MMCRIMR, MMCTIMR, RESERVED15[14], MMCTSCGPR, MMCTMCGPR,
8535 RESERVED16[5], MMCTPCGR, RESERVED17[10], MMCRCRCEPR, MMCRAEPR,
8536 RESERVED18[10], MMCRUPGR, RESERVED19[9], MMCTLPIMSTR, MMCTLPITCR,
8537 MMCRLPIMSTR, MMCRLPITCR, RESERVED20[65], MACL3L4C0R, MACL4A0R,
8538 RESERVED21[2], MACL3A0R0R, MACL3A1R0R, MACL3A2R0R, MACL3A3R0R,
8539 RESERVED22[4], MACL3L4C1R, MACL4A1R, RESERVED23[2], MACL3A0R1R,
8540 MACL3A1R1R, MACL3A2R1R, MACL3A3R1R, RESERVED24[108], MACTSCR, MACSSIR,
8541 MACSTSR, MACSTNR, MACSTSUR, MACSTNUR, MACTSAR, RESERVED25, MACTSSR,
8542 RESERVED26[3], MACTTSSNR, MACTTSSSR, RESERVED27[2], MACACR, RESERVED28,
8543 MACATSNR, MACATSSR, MACTSIACR, MACTSEACR, MACTSICNR, MACTSECNR,
8544 RESERVED29[4], MACPPSCR, RESERVED30[3], MACPPSTTSR, MACPPSTTNR, MACPPSIR,
8545 MACPPSWR, RESERVED31[12], MACPOCR, MACSPI0R, MACSPI1R, MACSPI2R, MACLMIR,
8546 RESERVED32[11], MTLOMR, RESERVED33[7], MTLISR, RESERVED34[55], MTLTQOMR,
8547 MTLTQUR, MTLTQDR, RESERVED35[8], MTLQICSR, MTLRQOMR, MTLRQMPOCR, MTLRQDR,
8548 RESERVED36[177], DMAMR, DMASBMR, DMAISR, DMADSR, RESERVED37[60], DMACCR,
8549 DMACTCR, DMACRCR, RESERVED38[2], DMACTDLAR, RESERVED39, DMACRDLAR,
8550 DMACTDTPR, RESERVED40, DMACRDTPR, DMACTDRLR, DMACRDRLR, DMACIER,
8551 DMACRIWTR, DMACSFCSR, RESERVED41, DMACCATDR, RESERVED42, DMACCARDR,
8552 RESERVED43, DMACCATBR, RESERVED44, DMACCARBR, DMACSR, RESERVED45[2],
8557 ((struct stm32h_eth *) (uintptr_t) (0x40000000UL + 0x00020000UL + 0x8000UL))
8560 #define BIT(x) ((uint32_t) 1 << (x))
8561 #define ETH_PKT_SIZE 1540 // Max frame size
8562 #define ETH_DESC_CNT 4 // Descriptors count
8563 #define ETH_DS 4 // Descriptor size (words)
8565 static volatile uint32_t s_rxdesc[ETH_DESC_CNT][ETH_DS]; // RX descriptors
8566 static volatile uint32_t s_txdesc[ETH_DESC_CNT][ETH_DS]; // TX descriptors
8567 static uint8_t s_rxbuf[ETH_DESC_CNT][ETH_PKT_SIZE]; // RX ethernet buffers
8568 static uint8_t s_txbuf[ETH_DESC_CNT][ETH_PKT_SIZE]; // TX ethernet buffers
8569 static struct mg_tcpip_if *s_ifp; // MIP interface
8577 static uint32_t eth_read_phy(uint8_t addr, uint8_t reg) {
8578 ETH->MACMDIOAR &= (0xF << 8);
8579 ETH->MACMDIOAR |= ((uint32_t) addr << 21) | ((uint32_t) reg << 16) | 3 << 2;
8580 ETH->MACMDIOAR |= BIT(0);
8581 while (ETH->MACMDIOAR & BIT(0)) (void) 0;
8582 return ETH->MACMDIODR;
8585 static void eth_write_phy(uint8_t addr, uint8_t reg, uint32_t val) {
8586 ETH->MACMDIODR = val;
8587 ETH->MACMDIOAR &= (0xF << 8);
8588 ETH->MACMDIOAR |= ((uint32_t) addr << 21) | ((uint32_t) reg << 16) | 1 << 2;
8589 ETH->MACMDIOAR |= BIT(0);
8590 while (ETH->MACMDIOAR & BIT(0)) (void) 0;
8593 static uint32_t get_hclk(void) {
8595 volatile uint32_t CR, HSICFGR, CRRCR, CSICFGR, CFGR, RESERVED1, D1CFGR,
8596 D2CFGR, D3CFGR, RESERVED2, PLLCKSELR, PLLCFGR, PLL1DIVR, PLL1FRACR,
8597 PLL2DIVR, PLL2FRACR, PLL3DIVR, PLL3FRACR, RESERVED3, D1CCIPR, D2CCIP1R,
8598 D2CCIP2R, D3CCIPR, RESERVED4, CIER, CIFR, CICR, RESERVED5, BDCR, CSR,
8599 RESERVED6, AHB3RSTR, AHB1RSTR, AHB2RSTR, AHB4RSTR, APB3RSTR, APB1LRSTR,
8600 APB1HRSTR, APB2RSTR, APB4RSTR, GCR, RESERVED8, D3AMR, RESERVED11[9],
8601 RSR, AHB3ENR, AHB1ENR, AHB2ENR, AHB4ENR, APB3ENR, APB1LENR, APB1HENR,
8602 APB2ENR, APB4ENR, RESERVED12, AHB3LPENR, AHB1LPENR, AHB2LPENR,
8603 AHB4LPENR, APB3LPENR, APB1LLPENR, APB1HLPENR, APB2LPENR, APB4LPENR,
8605 } *rcc = ((struct rcc *) (0x40000000 + 0x18020000 + 0x4400));
8606 uint32_t clk = 0, hsi = 64000000 /* 64 MHz */, hse = 8000000 /* 8MHz */,
8607 csi = 4000000 /* 4MHz */;
8608 unsigned int sel = (rcc->CFGR & (7 << 3)) >> 3;
8612 } else if (sel == 2) {
8614 } else if (sel == 3) {
8615 uint32_t vco, m, n, p;
8616 unsigned int src = (rcc->PLLCKSELR & (3 << 0)) >> 0;
8617 m = ((rcc->PLLCKSELR & (0x3F << 4)) >> 4);
8618 n = ((rcc->PLL1DIVR & (0x1FF << 0)) >> 0) + 1 +
8619 ((rcc->PLLCFGR & BIT(0)) ? 1 : 0); // round-up in fractional mode
8620 p = ((rcc->PLL1DIVR & (0x7F << 9)) >> 9) + 1;
8623 } else if (src == 2) {
8627 clk >>= ((rcc->CR & 3) >> 3);
8629 vco = (uint32_t) ((uint64_t) clk * n / m);
8633 clk >>= ((rcc->CR & 3) >> 3);
8635 const uint8_t cptab[12] = {1, 2, 3, 4, 6, 7, 8, 9}; // log2(div)
8636 uint32_t d1cpre = (rcc->D1CFGR & (0x0F << 8)) >> 8;
8637 if (d1cpre >= 8) clk >>= cptab[d1cpre - 8];
8638 MG_DEBUG(("D1 CLK: %u", clk));
8639 uint32_t hpre = (rcc->D1CFGR & (0x0F << 0)) >> 0;
8640 if (hpre < 8) return clk;
8641 return ((uint32_t) clk) >> cptab[hpre - 8];
8644 // Guess CR from AHB1 clock. MDC clock is generated from the ETH peripheral
8645 // clock (AHB1); as per 802.3, it must not exceed 2. As the AHB clock can
8646 // be derived from HSI or CSI (internal RC) clocks, and those can go above
8647 // specs, the datasheets specify a range of frequencies and activate one of a
8648 // series of dividers to keep the MDC clock safely below 2.5MHz. We guess a
8649 // divider setting based on HCLK with some drift. If the user uses a different
8650 // clock from our defaults, needs to set the macros on top. Valid for
8651 // STM32H74xxx/75xxx (58.11.4)(4.5% worst case drift)(CSI clock has a 7.5 %
8652 // worst case drift @ max temp)
8653 static int guess_mdc_cr(void) {
8654 const uint8_t crs[] = {2, 3, 0, 1, 4, 5}; // ETH->MACMDIOAR::CR values
8655 const uint8_t div[] = {16, 26, 42, 62, 102, 124}; // Respective HCLK dividers
8656 uint32_t hclk = get_hclk(); // Guess system HCLK
8657 int result = -1; // Invalid CR value
8658 for (int i = 0; i < 6; i++) {
8659 if (hclk / div[i] <= 2375000UL /* 2.5MHz - 5% */) {
8664 if (result < 0) MG_ERROR(("HCLK too high"));
8665 MG_DEBUG(("HCLK: %u, CR: %d", hclk, result));
8669 static bool mg_tcpip_driver_stm32h_init(struct mg_tcpip_if *ifp) {
8670 struct mg_tcpip_driver_stm32h_data *d =
8671 (struct mg_tcpip_driver_stm32h_data *) ifp->driver_data;
8674 // Init RX descriptors
8675 for (int i = 0; i < ETH_DESC_CNT; i++) {
8676 s_rxdesc[i][0] = (uint32_t) (uintptr_t) s_rxbuf[i]; // Point to data buffer
8677 s_rxdesc[i][3] = BIT(31) | BIT(30) | BIT(24); // OWN, IOC, BUF1V
8680 // Init TX descriptors
8681 for (int i = 0; i < ETH_DESC_CNT; i++) {
8682 s_txdesc[i][0] = (uint32_t) (uintptr_t) s_txbuf[i]; // Buf pointer
8685 ETH->DMAMR |= BIT(0); // Software reset
8686 while ((ETH->DMAMR & BIT(0)) != 0) (void) 0; // Wait until done
8688 // Set MDC clock divider. If user told us the value, use it. Otherwise, guess
8689 int cr = (d == NULL || d->mdc_cr < 0) ? guess_mdc_cr() : d->mdc_cr;
8690 ETH->MACMDIOAR = ((uint32_t) cr & 0xF) << 8;
8692 // NOTE(scaprile): We do not use timing facilities so the DMA engine does not
8693 // re-write buffer address
8694 ETH->DMAMR = 0 << 16; // use interrupt mode 0 (58.8.1) (reset value)
8695 ETH->DMASBMR |= BIT(12); // AAL NOTE(scaprile): is this actually needed
8696 ETH->MACIER = 0; // Do not enable additional irq sources (reset value)
8697 ETH->MACTFCR = BIT(7); // Disable zero-quanta pause
8698 // ETH->MACPFR = BIT(31); // Receive all
8699 eth_write_phy(PHY_ADDR, PHY_BCR, BIT(15)); // Reset PHY
8700 eth_write_phy(PHY_ADDR, PHY_BCR, BIT(12)); // Set autonegotiation
8702 (uint32_t) (uintptr_t) s_rxdesc; // RX descriptors start address
8703 ETH->DMACRDRLR = ETH_DESC_CNT - 1; // ring length
8705 (uint32_t) (uintptr_t) &s_rxdesc[ETH_DESC_CNT -
8706 1]; // last valid descriptor address
8708 (uint32_t) (uintptr_t) s_txdesc; // TX descriptors start address
8709 ETH->DMACTDRLR = ETH_DESC_CNT - 1; // ring length
8711 (uint32_t) (uintptr_t) s_txdesc; // first available descriptor address
8712 ETH->DMACCR = 0; // DSL = 0 (contiguous descriptor table) (reset value)
8713 ETH->DMACIER = BIT(6) | BIT(15); // RIE, NIE
8714 ETH->MACCR = BIT(0) | BIT(1) | BIT(13) | BIT(14) |
8715 BIT(15); // RE, TE, Duplex, Fast, Reserved
8716 ETH->MTLTQOMR |= BIT(1); // TSF
8717 ETH->MTLRQOMR |= BIT(5); // RSF
8718 ETH->DMACTCR |= BIT(0); // ST
8719 ETH->DMACRCR |= BIT(0); // SR
8721 // MAC address filtering
8722 ETH->MACA0HR = ((uint32_t) ifp->mac[5] << 8U) | ifp->mac[4];
8723 ETH->MACA0LR = (uint32_t) (ifp->mac[3] << 24) |
8724 ((uint32_t) ifp->mac[2] << 16) |
8725 ((uint32_t) ifp->mac[1] << 8) | ifp->mac[0];
8729 static uint32_t s_txno;
8730 static size_t mg_tcpip_driver_stm32h_tx(const void *buf, size_t len,
8731 struct mg_tcpip_if *ifp) {
8732 if (len > sizeof(s_txbuf[s_txno])) {
8733 MG_ERROR(("Frame too big, %ld", (long) len));
8734 len = 0; // Frame is too big
8735 } else if ((s_txdesc[s_txno][3] & BIT(31))) {
8736 MG_ERROR(("No free descriptors: %u %08X %08X %08X", s_txno,
8737 s_txdesc[s_txno][3], ETH->DMACSR, ETH->DMACTCR));
8738 for (int i = 0; i < ETH_DESC_CNT; i++) MG_ERROR(("%08X", s_txdesc[i][3]));
8739 len = 0; // All descriptors are busy, fail
8741 memcpy(s_txbuf[s_txno], buf, len); // Copy data
8742 s_txdesc[s_txno][2] = (uint32_t) len; // Set data len
8743 s_txdesc[s_txno][3] = BIT(28) | BIT(29); // FD, LD
8744 s_txdesc[s_txno][3] |= BIT(31); // Set OWN bit - let DMA take over
8745 if (++s_txno >= ETH_DESC_CNT) s_txno = 0;
8747 ETH->DMACSR |= BIT(2) | BIT(1); // Clear any prior TBU, TPS
8748 ETH->DMACTDTPR = (uint32_t) (uintptr_t) &s_txdesc[s_txno]; // and resume
8753 static bool mg_tcpip_driver_stm32h_up(struct mg_tcpip_if *ifp) {
8754 uint32_t bsr = eth_read_phy(PHY_ADDR, PHY_BSR);
8755 bool up = bsr & BIT(2) ? 1 : 0;
8756 if ((ifp->state == MG_TCPIP_STATE_DOWN) && up) { // link state just went up
8757 uint32_t scsr = eth_read_phy(PHY_ADDR, PHY_CSCR);
8758 uint32_t maccr = ETH->MACCR | BIT(14) | BIT(13); // 100M, Full-duplex
8759 if ((scsr & BIT(3)) == 0) maccr &= ~BIT(14); // 10M
8760 if ((scsr & BIT(4)) == 0) maccr &= ~BIT(13); // Half-duplex
8761 ETH->MACCR = maccr; // IRQ handler does not fiddle with this register
8762 MG_DEBUG(("Link is %uM %s-duplex", maccr & BIT(14) ? 100 : 10,
8763 maccr & BIT(13) ? "full" : "half"));
8768 void ETH_IRQHandler(void);
8769 static uint32_t s_rxno;
8770 void ETH_IRQHandler(void) {
8771 if (ETH->DMACSR & BIT(6)) { // Frame received, loop
8772 ETH->DMACSR = BIT(15) | BIT(6); // Clear flag
8773 for (uint32_t i = 0; i < 10; i++) { // read as they arrive but not forever
8774 if (s_rxdesc[s_rxno][3] & BIT(31)) break; // exit when done
8775 if (((s_rxdesc[s_rxno][3] & (BIT(28) | BIT(29))) ==
8776 (BIT(28) | BIT(29))) &&
8777 !(s_rxdesc[s_rxno][3] & BIT(15))) { // skip partial/errored frames
8778 uint32_t len = s_rxdesc[s_rxno][3] & (BIT(15) - 1);
8779 // MG_DEBUG(("%lx %lu %lx %08lx", s_rxno, len, s_rxdesc[s_rxno][3],
8781 mg_tcpip_qwrite(s_rxbuf[s_rxno], len > 4 ? len - 4 : len, s_ifp);
8783 s_rxdesc[s_rxno][3] = BIT(31) | BIT(30) | BIT(24); // OWN, IOC, BUF1V
8784 if (++s_rxno >= ETH_DESC_CNT) s_rxno = 0;
8787 ETH->DMACSR = BIT(7) | BIT(8); // Clear possible RBU RPS while processing
8789 (uint32_t) (uintptr_t) &s_rxdesc[ETH_DESC_CNT - 1]; // and resume RX
8792 struct mg_tcpip_driver mg_tcpip_driver_stm32h = {
8793 mg_tcpip_driver_stm32h_init, mg_tcpip_driver_stm32h_tx, NULL,
8794 mg_tcpip_driver_stm32h_up};
8797 #ifdef MG_ENABLE_LINES
8798 #line 1 "src/drivers/tm4c.c"
8802 #if MG_ENABLE_TCPIP && defined(MG_ENABLE_DRIVER_TM4C) && MG_ENABLE_DRIVER_TM4C
8804 volatile uint32_t EMACCFG, EMACFRAMEFLTR, EMACHASHTBLH, EMACHASHTBLL,
8805 EMACMIIADDR, EMACMIIDATA, EMACFLOWCTL, EMACVLANTG, RESERVED0, EMACSTATUS,
8806 EMACRWUFF, EMACPMTCTLSTAT, RESERVED1[2], EMACRIS, EMACIM, EMACADDR0H,
8807 EMACADDR0L, EMACADDR1H, EMACADDR1L, EMACADDR2H, EMACADDR2L, EMACADDR3H,
8808 EMACADDR3L, RESERVED2[31], EMACWDOGTO, RESERVED3[8], EMACMMCCTRL,
8809 EMACMMCRXRIS, EMACMMCTXRIS, EMACMMCRXIM, EMACMMCTXIM, RESERVED4,
8810 EMACTXCNTGB, RESERVED5[12], EMACTXCNTSCOL, EMACTXCNTMCOL, RESERVED6[4],
8811 EMACTXOCTCNTG, RESERVED7[6], EMACRXCNTGB, RESERVED8[4], EMACRXCNTCRCERR,
8812 EMACRXCNTALGNERR, RESERVED9[10], EMACRXCNTGUNI, RESERVED10[239],
8813 EMACVLNINCREP, EMACVLANHASH, RESERVED11[93], EMACTIMSTCTRL, EMACSUBSECINC,
8814 EMACTIMSEC, EMACTIMNANO, EMACTIMSECU, EMACTIMNANOU, EMACTIMADD,
8815 EMACTARGSEC, EMACTARGNANO, EMACHWORDSEC, EMACTIMSTAT, EMACPPSCTRL,
8816 RESERVED12[12], EMACPPS0INTVL, EMACPPS0WIDTH, RESERVED13[294],
8817 EMACDMABUSMOD, EMACTXPOLLD, EMACRXPOLLD, EMACRXDLADDR, EMACTXDLADDR,
8818 EMACDMARIS, EMACDMAOPMODE, EMACDMAIM, EMACMFBOC, EMACRXINTWDT,
8819 RESERVED14[8], EMACHOSTXDESC, EMACHOSRXDESC, EMACHOSTXBA, EMACHOSRXBA,
8820 RESERVED15[218], EMACPP, EMACPC, EMACCC, RESERVED16, EMACEPHYRIS,
8821 EMACEPHYIM, EMACEPHYIMSC;
8824 #define EMAC ((struct tm4c_emac *) (uintptr_t) 0x400EC000)
8827 #define BIT(x) ((uint32_t) 1 << (x))
8828 #define ETH_PKT_SIZE 1540 // Max frame size
8829 #define ETH_DESC_CNT 4 // Descriptors count
8830 #define ETH_DS 4 // Descriptor size (words)
8832 static uint32_t s_rxdesc[ETH_DESC_CNT][ETH_DS]; // RX descriptors
8833 static uint32_t s_txdesc[ETH_DESC_CNT][ETH_DS]; // TX descriptors
8834 static uint8_t s_rxbuf[ETH_DESC_CNT][ETH_PKT_SIZE]; // RX ethernet buffers
8835 static uint8_t s_txbuf[ETH_DESC_CNT][ETH_PKT_SIZE]; // TX ethernet buffers
8836 static struct mg_tcpip_if *s_ifp; // MIP interface
8844 static inline void tm4cspin(volatile uint32_t count) {
8845 while (count--) (void) 0;
8848 static uint32_t emac_read_phy(uint8_t addr, uint8_t reg) {
8849 EMAC->EMACMIIADDR &= (0xf << 2);
8850 EMAC->EMACMIIADDR |= ((uint32_t) addr << 11) | ((uint32_t) reg << 6);
8851 EMAC->EMACMIIADDR |= BIT(0);
8852 while (EMAC->EMACMIIADDR & BIT(0)) tm4cspin(1);
8853 return EMAC->EMACMIIDATA;
8856 static void emac_write_phy(uint8_t addr, uint8_t reg, uint32_t val) {
8857 EMAC->EMACMIIDATA = val;
8858 EMAC->EMACMIIADDR &= (0xf << 2);
8859 EMAC->EMACMIIADDR |= ((uint32_t) addr << 11) | ((uint32_t) reg << 6) | BIT(1);
8860 EMAC->EMACMIIADDR |= BIT(0);
8861 while (EMAC->EMACMIIADDR & BIT(0)) tm4cspin(1);
8864 static uint32_t get_sysclk(void) {
8866 volatile uint32_t DONTCARE0[44], RSCLKCFG, DONTCARE1[43], PLLFREQ0,
8868 } *sysctl = (struct sysctl *) 0x400FE000;
8869 uint32_t clk = 0, piosc = 16000000 /* 16 MHz */, mosc = 25000000 /* 25MHz */;
8870 if (sysctl->RSCLKCFG & (1 << 28)) { // USEPLL
8871 uint32_t fin, vco, mdiv, n, q, psysdiv;
8872 uint32_t pllsrc = (sysctl->RSCLKCFG & (0xf << 24)) >> 24;
8875 } else if (pllsrc == 3) {
8878 MG_ERROR(("Unsupported clock source"));
8880 q = (sysctl->PLLFREQ1 & (0x1f << 8)) >> 8;
8881 n = (sysctl->PLLFREQ1 & (0x1f << 0)) >> 0;
8882 fin = clk / ((q + 1) * (n + 1));
8883 mdiv = (sysctl->PLLFREQ0 & (0x3ff << 0)) >>
8884 0; // mint + (mfrac / 1024); MFRAC not supported
8885 psysdiv = (sysctl->RSCLKCFG & (0x3f << 0)) >> 0;
8886 vco = (uint32_t) ((uint64_t) fin * mdiv);
8887 return vco / (psysdiv + 1);
8889 uint32_t oscsrc = (sysctl->RSCLKCFG & (0xf << 20)) >> 20;
8892 } else if (oscsrc == 3) {
8895 MG_ERROR(("Unsupported clock source"));
8897 uint32_t osysdiv = (sysctl->RSCLKCFG & (0xf << 16)) >> 16;
8898 return clk / (osysdiv + 1);
8901 // Guess CR from SYSCLK. MDC clock is generated from SYSCLK (AHB); as per
8902 // 802.3, it must not exceed 2.5MHz (also 20.4.2.6) As the AHB clock can be
8903 // derived from the PIOSC (internal RC), and it can go above specs, the
8904 // datasheets specify a range of frequencies and activate one of a series of
8905 // dividers to keep the MDC clock safely below 2.5MHz. We guess a divider
8906 // setting based on SYSCLK with a +5% drift. If the user uses a different clock
8907 // from our defaults, needs to set the macros on top Valid for TM4C129x (20.7)
8908 // (4.5% worst case drift)
8909 // The PHY receives the main oscillator (MOSC) (20.3.1)
8910 static int guess_mdc_cr(void) {
8911 uint8_t crs[] = {2, 3, 0, 1}; // EMAC->MACMIIAR::CR values
8912 uint8_t div[] = {16, 26, 42, 62}; // Respective HCLK dividers
8913 uint32_t sysclk = get_sysclk(); // Guess system SYSCLK
8914 int result = -1; // Invalid CR value
8915 if (sysclk < 25000000) {
8916 MG_ERROR(("SYSCLK too low"));
8918 for (int i = 0; i < 4; i++) {
8919 if (sysclk / div[i] <= 2375000UL /* 2.5MHz - 5% */) {
8924 if (result < 0) MG_ERROR(("SYSCLK too high"));
8926 MG_DEBUG(("SYSCLK: %u, CR: %d", sysclk, result));
8930 static bool mg_tcpip_driver_tm4c_init(struct mg_tcpip_if *ifp) {
8931 struct mg_tcpip_driver_tm4c_data *d =
8932 (struct mg_tcpip_driver_tm4c_data *) ifp->driver_data;
8935 // Init RX descriptors
8936 for (int i = 0; i < ETH_DESC_CNT; i++) {
8937 s_rxdesc[i][0] = BIT(31); // Own
8938 s_rxdesc[i][1] = sizeof(s_rxbuf[i]) | BIT(14); // 2nd address chained
8939 s_rxdesc[i][2] = (uint32_t) (uintptr_t) s_rxbuf[i]; // Point to data buffer
8941 (uint32_t) (uintptr_t) s_rxdesc[(i + 1) % ETH_DESC_CNT]; // Chain
8942 // MG_DEBUG(("%d %p", i, s_rxdesc[i]));
8945 // Init TX descriptors
8946 for (int i = 0; i < ETH_DESC_CNT; i++) {
8947 s_txdesc[i][2] = (uint32_t) (uintptr_t) s_txbuf[i]; // Buf pointer
8949 (uint32_t) (uintptr_t) s_txdesc[(i + 1) % ETH_DESC_CNT]; // Chain
8952 EMAC->EMACDMABUSMOD |= BIT(0); // Software reset
8953 while ((EMAC->EMACDMABUSMOD & BIT(0)) != 0) tm4cspin(1); // Wait until done
8955 // Set MDC clock divider. If user told us the value, use it. Otherwise, guess
8956 int cr = (d == NULL || d->mdc_cr < 0) ? guess_mdc_cr() : d->mdc_cr;
8957 EMAC->EMACMIIADDR = ((uint32_t) cr & 0xf) << 2;
8959 // NOTE(cpq): we do not use extended descriptor bit 7, and do not use
8960 // hardware checksum. Therefore, descriptor size is 4, not 8
8961 // EMAC->EMACDMABUSMOD = BIT(13) | BIT(16) | BIT(22) | BIT(23) | BIT(25);
8962 EMAC->EMACIM = BIT(3) | BIT(9); // Mask timestamp & PMT IT
8963 EMAC->EMACFLOWCTL = BIT(7); // Disable zero-quanta pause
8964 // EMAC->EMACFRAMEFLTR = BIT(31); // Receive all
8965 // EMAC->EMACPC defaults to internal PHY (EPHY) in MMI mode
8966 emac_write_phy(EPHY_ADDR, EPHYBMCR, BIT(15)); // Reset internal PHY (EPHY)
8967 emac_write_phy(EPHY_ADDR, EPHYBMCR, BIT(12)); // Set autonegotiation
8968 EMAC->EMACRXDLADDR = (uint32_t) (uintptr_t) s_rxdesc; // RX descriptors
8969 EMAC->EMACTXDLADDR = (uint32_t) (uintptr_t) s_txdesc; // TX descriptors
8970 EMAC->EMACDMAIM = BIT(6) | BIT(16); // RIE, NIE
8971 EMAC->EMACCFG = BIT(2) | BIT(3) | BIT(11) | BIT(14); // RE, TE, Duplex, Fast
8972 EMAC->EMACDMAOPMODE =
8973 BIT(1) | BIT(13) | BIT(21) | BIT(25); // SR, ST, TSF, RSF
8974 EMAC->EMACADDR0H = ((uint32_t) ifp->mac[5] << 8U) | ifp->mac[4];
8975 EMAC->EMACADDR0L = (uint32_t) (ifp->mac[3] << 24) |
8976 ((uint32_t) ifp->mac[2] << 16) |
8977 ((uint32_t) ifp->mac[1] << 8) | ifp->mac[0];
8978 // NOTE(scaprile) There are 3 additional slots for filtering, disabled by
8979 // default. This also applies to the STM32 driver (at least for F7)
8983 static uint32_t s_txno;
8984 static size_t mg_tcpip_driver_tm4c_tx(const void *buf, size_t len,
8985 struct mg_tcpip_if *ifp) {
8986 if (len > sizeof(s_txbuf[s_txno])) {
8987 MG_ERROR(("Frame too big, %ld", (long) len));
8989 } else if ((s_txdesc[s_txno][0] & BIT(31))) {
8990 MG_ERROR(("No descriptors available"));
8991 // printf("D0 %lx SR %lx\n", (long) s_txdesc[0][0], (long)
8992 // EMAC->EMACDMARIS);
8995 memcpy(s_txbuf[s_txno], buf, len); // Copy data
8996 s_txdesc[s_txno][1] = (uint32_t) len; // Set data len
8997 s_txdesc[s_txno][0] =
8998 BIT(20) | BIT(28) | BIT(29) | BIT(30); // Chain,FS,LS,IC
8999 s_txdesc[s_txno][0] |= BIT(31); // Set OWN bit - let DMA take over
9000 if (++s_txno >= ETH_DESC_CNT) s_txno = 0;
9002 EMAC->EMACDMARIS = BIT(2) | BIT(5); // Clear any prior TU/UNF
9003 EMAC->EMACTXPOLLD = 0; // and resume
9008 static bool mg_tcpip_driver_tm4c_up(struct mg_tcpip_if *ifp) {
9009 uint32_t bmsr = emac_read_phy(EPHY_ADDR, EPHYBMSR);
9010 bool up = (bmsr & BIT(2)) ? 1 : 0;
9011 if ((ifp->state == MG_TCPIP_STATE_DOWN) && up) { // link state just went up
9012 uint32_t sts = emac_read_phy(EPHY_ADDR, EPHYSTS);
9013 uint32_t emaccfg = EMAC->EMACCFG | BIT(14) | BIT(11); // 100M, Full-duplex
9014 if (sts & BIT(1)) emaccfg &= ~BIT(14); // 10M
9015 if ((sts & BIT(2)) == 0) emaccfg &= ~BIT(11); // Half-duplex
9016 EMAC->EMACCFG = emaccfg; // IRQ handler does not fiddle with this register
9017 MG_DEBUG(("Link is %uM %s-duplex", emaccfg & BIT(14) ? 100 : 10,
9018 emaccfg & BIT(11) ? "full" : "half"));
9023 void EMAC0_IRQHandler(void);
9024 static uint32_t s_rxno;
9025 void EMAC0_IRQHandler(void) {
9026 if (EMAC->EMACDMARIS & BIT(6)) { // Frame received, loop
9027 EMAC->EMACDMARIS = BIT(16) | BIT(6); // Clear flag
9028 for (uint32_t i = 0; i < 10; i++) { // read as they arrive but not forever
9029 if (s_rxdesc[s_rxno][0] & BIT(31)) break; // exit when done
9030 if (((s_rxdesc[s_rxno][0] & (BIT(8) | BIT(9))) == (BIT(8) | BIT(9))) &&
9031 !(s_rxdesc[s_rxno][0] & BIT(15))) { // skip partial/errored frames
9032 uint32_t len = ((s_rxdesc[s_rxno][0] >> 16) & (BIT(14) - 1));
9033 // printf("%lx %lu %lx %.8lx\n", s_rxno, len, s_rxdesc[s_rxno][0],
9034 // EMAC->EMACDMARIS);
9035 mg_tcpip_qwrite(s_rxbuf[s_rxno], len > 4 ? len - 4 : len, s_ifp);
9037 s_rxdesc[s_rxno][0] = BIT(31);
9038 if (++s_rxno >= ETH_DESC_CNT) s_rxno = 0;
9041 EMAC->EMACDMARIS = BIT(7); // Clear possible RU while processing
9042 EMAC->EMACRXPOLLD = 0; // and resume RX
9045 struct mg_tcpip_driver mg_tcpip_driver_tm4c = {mg_tcpip_driver_tm4c_init,
9046 mg_tcpip_driver_tm4c_tx, NULL,
9047 mg_tcpip_driver_tm4c_up};
9050 #ifdef MG_ENABLE_LINES
9051 #line 1 "src/drivers/w5500.c"
9057 enum { W5500_CR = 0, W5500_S0 = 1, W5500_TX0 = 2, W5500_RX0 = 3 };
9059 static void w5500_txn(struct mg_tcpip_spi *s, uint8_t block, uint16_t addr, bool wr,
9060 void *buf, size_t len) {
9061 uint8_t *p = (uint8_t *) buf;
9062 uint8_t cmd[] = {(uint8_t) (addr >> 8), (uint8_t) (addr & 255),
9063 (uint8_t) ((block << 3) | (wr ? 4 : 0))};
9065 for (size_t i = 0; i < sizeof(cmd); i++) s->txn(s->spi, cmd[i]);
9066 for (size_t i = 0; i < len; i++) {
9067 uint8_t r = s->txn(s->spi, p[i]);
9074 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); }
9075 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); }
9076 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)); }
9077 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); }
9078 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; }
9079 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]); }
9082 static size_t w5500_rx(void *buf, size_t buflen, struct mg_tcpip_if *ifp) {
9083 struct mg_tcpip_spi *s = (struct mg_tcpip_spi *) ifp->driver_data;
9084 uint16_t r = 0, n = 0, len = (uint16_t) buflen, n2; // Read recv len
9085 while ((n2 = w5500_r2(s, W5500_S0, 0x26)) > n) n = n2; // Until it is stable
9086 // printf("RSR: %d\n", (int) n);
9088 uint16_t ptr = w5500_r2(s, W5500_S0, 0x28); // Get read pointer
9089 n = w5500_r2(s, W5500_RX0, ptr); // Read frame length
9090 if (n <= len + 2 && n > 1) {
9091 r = (uint16_t) (n - 2);
9092 w5500_rn(s, W5500_RX0, (uint16_t) (ptr + 2), buf, r);
9094 w5500_w2(s, W5500_S0, 0x28, (uint16_t) (ptr + n)); // Advance read pointer
9095 w5500_w1(s, W5500_S0, 1, 0x40); // Sock0 CR -> RECV
9096 // printf(" RX_RD: tot=%u n=%u r=%u\n", n2, n, r);
9101 static size_t w5500_tx(const void *buf, size_t buflen, struct mg_tcpip_if *ifp) {
9102 struct mg_tcpip_spi *s = (struct mg_tcpip_spi *) ifp->driver_data;
9103 uint16_t n = 0, len = (uint16_t) buflen;
9104 while (n < len) n = w5500_r2(s, W5500_S0, 0x20); // Wait for space
9105 uint16_t ptr = w5500_r2(s, W5500_S0, 0x24); // Get write pointer
9106 w5500_wn(s, W5500_TX0, ptr, (void *) buf, len); // Write data
9107 w5500_w2(s, W5500_S0, 0x24, (uint16_t) (ptr + len)); // Advance write pointer
9108 w5500_w1(s, W5500_S0, 1, 0x20); // Sock0 CR -> SEND
9109 for (int i = 0; i < 40; i++) {
9110 uint8_t ir = w5500_r1(s, W5500_S0, 2); // Read S0 IR
9111 if (ir == 0) continue;
9112 // printf("IR %d, len=%d, free=%d, ptr %d\n", ir, (int) len, (int) n, ptr);
9113 w5500_w1(s, W5500_S0, 2, ir); // Write S0 IR: clear it!
9114 if (ir & 8) len = 0; // Timeout. Report error
9115 if (ir & (16 | 8)) break; // Stop on SEND_OK or timeout
9120 static bool w5500_init(struct mg_tcpip_if *ifp) {
9121 struct mg_tcpip_spi *s = (struct mg_tcpip_spi *) ifp->driver_data;
9123 w5500_w1(s, W5500_CR, 0, 0x80); // Reset chip: CR -> 0x80
9124 w5500_w1(s, W5500_CR, 0x2e, 0); // CR PHYCFGR -> reset
9125 w5500_w1(s, W5500_CR, 0x2e, 0xf8); // CR PHYCFGR -> set
9126 // w5500_wn(s, W5500_CR, 9, s->mac, 6); // Set source MAC
9127 w5500_w1(s, W5500_S0, 0x1e, 16); // Sock0 RX buf size
9128 w5500_w1(s, W5500_S0, 0x1f, 16); // Sock0 TX buf size
9129 w5500_w1(s, W5500_S0, 0, 4); // Sock0 MR -> MACRAW
9130 w5500_w1(s, W5500_S0, 1, 1); // Sock0 CR -> OPEN
9131 return w5500_r1(s, W5500_S0, 3) == 0x42; // Sock0 SR == MACRAW
9134 static bool w5500_up(struct mg_tcpip_if *ifp) {
9135 struct mg_tcpip_spi *spi = (struct mg_tcpip_spi *) ifp->driver_data;
9136 uint8_t phycfgr = w5500_r1(spi, W5500_CR, 0x2e);
9137 return phycfgr & 1; // Bit 0 of PHYCFGR is LNK (0 - down, 1 - up)
9140 struct mg_tcpip_driver mg_tcpip_driver_w5500 = {w5500_init, w5500_tx, w5500_rx, w5500_up};