From 736b8ad7b7ae4bcaaba386adc3bb06d5f908c07b Mon Sep 17 00:00:00 2001 From: cpq Date: Fri, 28 May 2021 18:30:42 +0100 Subject: [PATCH] Fix #1285 - __builtin___snprintf_chk warning. Tighten test flags and refactor the code to squash all warnings --- .github/workflows/test.yml | 7 +- Makefile | 9 +- docs/README.md | 10 +- mongoose.c | 601 ++++++++++++++++++------------------- mongoose.h | 46 +-- src/arch_win32.h | 1 + src/base64.c | 18 +- src/dns.c | 10 +- src/event.h | 2 +- src/http.c | 93 +++--- src/http.h | 6 +- src/log.c | 14 +- src/log.h | 2 +- src/mqtt.c | 41 +-- src/mqtt.h | 8 +- src/net.c | 4 +- src/net.h | 2 +- src/sntp.c | 6 +- src/sock.c | 218 +++++++------- src/ssi.c | 8 +- src/timer.c | 4 +- src/timer.h | 7 +- src/tls.c | 82 ++--- src/tls.h | 10 +- src/url.c | 17 +- src/util.c | 80 ++--- src/util.h | 8 +- src/ws.c | 6 +- test/mongoose_custom.h | 22 ++ test/unit_test.c | 57 ++-- 30 files changed, 708 insertions(+), 691 deletions(-) create mode 100644 test/mongoose_custom.h diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 72f6d62e..ecafd099 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -37,4 +37,9 @@ jobs: run: make mingw - name: mingw++ run: make mingw++ - + arm: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v2 + - name: arm + run: make arm diff --git a/Makefile b/Makefile index a5c25cad..fb13e503 100644 --- a/Makefile +++ b/Makefile @@ -1,13 +1,17 @@ SRCS = $(wildcard src/*.c) HDRS = $(wildcard src/*.h) DEFS ?= -DMG_MAX_HTTP_HEADERS=5 -DMG_ENABLE_LINES -DMG_ENABLE_DIRECTORY_LISTING=1 -DMG_ENABLE_SSI=1 -CFLAGS ?= -W -Wall -Werror -Isrc -I. -O0 -g $(DEFS) $(TFLAGS) $(EXTRA) +WARN ?= -W -Wall -Werror -Wshadow -Wdouble-promotion -fno-common -Wconversion +OPTS ?= -O3 -g3 +INCS ?= -Isrc -I. +CFLAGS ?= $(OPTS) $(WARN) $(INCS) $(DEFS) $(TFLAGS) $(EXTRA) SSL ?= MBEDTLS CDIR ?= $(realpath $(CURDIR)) VC98 = docker run --rm -e WINEDEBUG=-all -v $(CDIR):$(CDIR) -w $(CDIR) docker.io/mdashnet/vc98 VC2017 = docker run --rm -e WINEDEBUG=-all -v $(CDIR):$(CDIR) -w $(CDIR) docker.io/mdashnet/vc2017 MINGW = docker run --rm -v $(CDIR):$(CDIR) -w $(CDIR) docker.io/mdashnet/mingw GCC = docker run --rm -v $(CDIR):$(CDIR) -w $(CDIR) mdashnet/cc2 +ARM = docker run -v $(CDIR):$(CDIR) -w $(CDIR) mdashnet/armgcc VCFLAGS = /nologo /W3 /O2 /I. $(DEFS) $(TFLAGS) CLANG ?= clang # /usr/local/opt/llvm\@9/bin/clang IPV6 ?= 1 @@ -95,6 +99,9 @@ linux: Makefile mongoose.c mongoose.h test/unit_test.c linux++: CC = g++ -Wno-missing-field-initializers linux++: linux +arm: Makefile mongoose.c mongoose.h test/unit_test.c + $(ARM) arm-none-eabi-gcc mongoose.c -c -Itest -DMG_ARCH=MG_ARCH_CUSTOM $(OPTS) $(WARN) $(INCS) -DMG_MAX_HTTP_HEADERS=5 -DMG_ENABLE_LINES -DMG_ENABLE_DIRECTORY_LISTING=0 -DMG_ENABLE_SSI=1 + mongoose.c: $(SRCS) Makefile (cat src/license.h; echo; echo '#include "mongoose.h"' ; (for F in src/private.h src/*.c ; do echo; echo '#ifdef MG_ENABLE_LINES'; echo "#line 1 \"$$F\""; echo '#endif'; cat $$F | sed -e 's,#include ".*,,'; done))> $@ diff --git a/docs/README.md b/docs/README.md index 4f74bf7d..c33823a7 100644 --- a/docs/README.md +++ b/docs/README.md @@ -1015,19 +1015,18 @@ Subscribe to topic `topic`. ### mg\_mqtt\_next\_sub() ```c -int mg_mqtt_next_sub(struct mg_mqtt_message *msg, struct mg_str *topic, - uint8_t *qos, int pos); +size_t mg_mqtt_next_sub(struct mg_mqtt_message *msg, struct mg_str *topic, uint8_t *qos, size_t pos); ``` Traverse list of subscribed topics. Used to implement MQTT server when `MQTT_CMD_SUBSCRIBE` is received. -Return next position. Initial position `pos` should be 4. Example: +Return next position, or 0 when done. Initial position `pos` should be 4. Example: ```c if (ev == MG_EV_MQTT_CMD) { struct mg_mqtt_message *mm = (struct mg_mqtt_message *) ev_data; if (mm->cmd == MQTT_CMD_SUBSCRIBE) { - int pos = 4; + size_t pos = 4; uint8_t qos; struct mg_str topic; while ((pos = mg_mqtt_next_sub(mm, &topic, &qos, pos)) > 0) { @@ -1040,8 +1039,7 @@ if (ev == MG_EV_MQTT_CMD) { ### mg\_mqtt\_next\_unsub() ```c -int mg_mqtt_next_unsub(struct mg_mqtt_message *msg, struct mg_str *topic, - int pos); +size_t mg_mqtt_next_unsub(struct mg_mqtt_message *msg, struct mg_str *topic, size_t pos); ``` Same as `mg_mqtt_next_sub()`, but for unsubscribed topics. The difference diff --git a/mongoose.c b/mongoose.c index d7c79f99..e6394504 100644 --- a/mongoose.c +++ b/mongoose.c @@ -60,14 +60,14 @@ static int mg_b64rev(int c) { int mg_base64_update(unsigned char ch, char *to, int n) { unsigned char rem = (n & 3) % 3; if (rem == 0) { - to[n] = mg_b64idx(ch >> 2); - to[++n] = (ch & 3) << 4; + to[n] = (char) mg_b64idx(ch >> 2); + to[++n] = (char) ((ch & 3) << 4); } else if (rem == 1) { - to[n] = mg_b64idx(to[n] | (ch >> 4)); - to[++n] = (ch & 15) << 2; + to[n] = (char) mg_b64idx(to[n] | (ch >> 4)); + to[++n] = (char) ((ch & 15) << 2); } else { - to[n] = mg_b64idx(to[n] | (ch >> 6)); - to[++n] = mg_b64idx(ch & 63); + to[n] = (char) mg_b64idx(to[n] | (ch >> 6)); + to[++n] = (char) mg_b64idx(ch & 63); n++; } return n; @@ -98,10 +98,10 @@ int mg_base64_decode(const char *src, int n, char *dst) { int a = mg_b64rev(src[0]), b = mg_b64rev(src[1]), c = mg_b64rev(src[2]), d = mg_b64rev(src[3]); if (a == 64 || a < 0 || b == 64 || b < 0 || c < 0 || d < 0) return 0; - dst[len++] = (a << 2) | (b >> 4); + dst[len++] = (char) ((a << 2) | (b >> 4)); if (src[2] != '=') { - dst[len++] = (b << 4) | (c >> 2); - if (src[3] != '=') dst[len++] = (c << 6) | d; + dst[len++] = (char) ((b << 4) | (c >> 2)); + if (src[3] != '=') dst[len++] = (char) ((c << 6) | d); } src += 4; } @@ -195,15 +195,15 @@ size_t mg_dns_parse_rr(const uint8_t *buf, size_t len, size_t ofs, return 0; s += rr->nlen + 4; if (s > e) return 0; - rr->atype = ((uint16_t) s[-4] << 8) | s[-3]; - rr->aclass = ((uint16_t) s[-2] << 8) | s[-1]; + rr->atype = (uint16_t)(((uint16_t) s[-4] << 8) | s[-3]); + rr->aclass = (uint16_t)(((uint16_t) s[-2] << 8) | s[-1]); if (is_question) return rr->nlen + 4; s += 6; if (s > e) return 0; - rr->alen = ((uint16_t) s[-2] << 8) | s[-1]; + rr->alen = (uint16_t)(((uint16_t) s[-2] << 8) | s[-1]); if (s + rr->alen > e) return 0; - return rr->nlen + rr->alen + 10; + return (size_t)(rr->nlen + rr->alen + 10); } bool mg_dns_parse(const uint8_t *buf, size_t len, struct mg_dns_message *dm) { @@ -361,7 +361,7 @@ static void mg_sendnsreq(struct mg_connection *c, struct mg_str *name, int ms, d->txnid = s_reqs ? s_reqs->txnid + 1 : 1; d->next = s_reqs; s_reqs = d; - d->expire = mg_millis() + ms; + d->expire = mg_millis() + (unsigned long) ms; d->c = c; c->is_resolving = 1; LOG(LL_VERBOSE_DEBUG, @@ -478,16 +478,20 @@ void mg_http_bauth(struct mg_connection *c, const char *user, size_t need = c->send.len + 36 + (u.len + p.len) * 2; if (c->send.size < need) mg_iobuf_resize(&c->send, need); if (c->send.size >= need) { - size_t i, n = 0; + int i, n = 0; char *buf = (char *) &c->send.buf[c->send.len + 21]; memcpy(&buf[-21], "Authorization: Basic ", 21); // DON'T use mg_send! - for (i = 0; i < u.len; i++) n = mg_base64_update(u.ptr[i], buf, n); + for (i = 0; i < (int) u.len; i++) { + n = mg_base64_update(((unsigned char *) u.ptr)[i], buf, n); + } if (p.len > 0) { n = mg_base64_update(':', buf, n); - for (i = 0; i < p.len; i++) n = mg_base64_update(p.ptr[i], buf, n); + for (i = 0; i < (int) p.len; i++) { + n = mg_base64_update(((unsigned char *) p.ptr)[i], buf, n); + } } n = mg_base64_final(buf, n); - c->send.len += 21 + n + 2; + c->send.len += 21 + (size_t) n + 2; memcpy(&c->send.buf[c->send.len - 2], "\r\n", 2); } else { LOG(LL_ERROR, ("%lu %s cannot resize iobuf %d->%d ", c->id, c->label, @@ -496,7 +500,7 @@ void mg_http_bauth(struct mg_connection *c, const char *user, } int mg_http_get_var(const struct mg_str *buf, const char *name, char *dst, - int dst_len) { + size_t dst_len) { const char *p, *e, *s; size_t name_len; int len; @@ -565,7 +569,7 @@ static const char *skip(const char *s, const char *e, const char *d, struct mg_str *v) { v->ptr = s; while (s < e && *s != '\n' && strchr(d, *s) == NULL) s++; - v->len = s - v->ptr; + v->len = (size_t)(s - v->ptr); while (s < e && strchr(d, *s) != NULL) s++; return s; } @@ -607,7 +611,7 @@ int mg_http_parse(const char *s, size_t len, struct mg_http_message *hm) { hm->message.ptr = hm->head.ptr = s; hm->body.ptr = end; - hm->head.len = req_len; + hm->head.len = (size_t) req_len; hm->chunk.ptr = end; hm->message.len = hm->body.len = (size_t) ~0; // Set body length to infinite @@ -622,15 +626,15 @@ int mg_http_parse(const char *s, size_t len, struct mg_http_message *hm) { // If URI contains '?' character, setup query string if ((qs = (const char *) memchr(hm->uri.ptr, '?', hm->uri.len)) != NULL) { hm->query.ptr = qs + 1; - hm->query.len = &hm->uri.ptr[hm->uri.len] - (qs + 1); - hm->uri.len = qs - hm->uri.ptr; + hm->query.len = (size_t)(&hm->uri.ptr[hm->uri.len] - (qs + 1)); + hm->uri.len = (size_t)(qs - hm->uri.ptr); } mg_http_parse_headers(s, end, hm->headers, sizeof(hm->headers) / sizeof(hm->headers[0])); if ((cl = mg_http_get_header(hm, "Content-Length")) != NULL) { hm->body.len = (size_t) mg_to64(*cl); - hm->message.len = req_len + hm->body.len; + hm->message.len = (size_t) req_len + hm->body.len; } // mg_http_parse() is used to parse both HTTP requests and HTTP @@ -650,14 +654,14 @@ int mg_http_parse(const char *s, size_t len, struct mg_http_message *hm) { mg_vcasecmp(&hm->method, "PUT") != 0 && mg_vcasecmp(&hm->method, "POST") != 0) { hm->body.len = 0; - hm->message.len = req_len; + hm->message.len = (size_t) req_len; } // The 204 (No content) responses also have 0 body length if (hm->body.len == (size_t) ~0 && is_response && mg_vcasecmp(&hm->uri, "204") == 0) { hm->body.len = 0; - hm->message.len = req_len; + hm->message.len = (size_t) req_len; } return req_len; @@ -668,7 +672,7 @@ static void mg_http_vprintf_chunk(struct mg_connection *c, const char *fmt, char mem[256], *buf = mem; int len = mg_vasprintf(&buf, sizeof(mem), fmt, ap); mg_printf(c, "%X\r\n", len); - mg_send(c, buf, len); + mg_send(c, buf, len > 0 ? (size_t) len : 0); mg_send(c, "\r\n", 2); if (buf != mem) free(buf); } @@ -767,7 +771,7 @@ void mg_http_reply(struct mg_connection *c, int code, const char *headers, va_end(ap); mg_printf(c, "HTTP/1.1 %d %s\r\n%sContent-Length: %d\r\n\r\n", code, mg_http_status_code_str(code), headers == NULL ? "" : headers, len); - mg_send(c, buf, len); + mg_send(c, buf, len > 0 ? (size_t) len : 0); if (buf != mem) free(buf); } @@ -806,7 +810,7 @@ int mg_http_upload(struct mg_connection *c, struct mg_http_message *hm, fwrite(hm->body.ptr, 1, hm->body.len, fp); fclose(fp); mg_http_reply(c, 200, "", ""); - return hm->body.len; + return (int) hm->body.len; } } } @@ -891,9 +895,9 @@ static const char *guess_content_type(const char *filename) { } static int getrange(struct mg_str *s, int64_t *a, int64_t *b) { - int i, numparsed = 0; + size_t i, numparsed = 0; LOG(LL_INFO, ("%.*s", (int) s->len, s->ptr)); - for (i = 0; i + 6 < (int) s->len; i++) { + for (i = 0; i + 6 < s->len; i++) { if (memcmp(&s->ptr[i], "bytes=", 6) == 0) { struct mg_str p = mg_str_n(s->ptr + i + 6, s->len - i - 6); if (p.len > 0 && p.ptr[0] >= '0' && p.ptr[0] <= '9') numparsed++; @@ -907,7 +911,7 @@ static int getrange(struct mg_str *s, int64_t *a, int64_t *b) { break; } } - return numparsed; + return (int) numparsed; } void mg_http_serve_file(struct mg_connection *c, struct mg_http_message *hm, @@ -927,7 +931,7 @@ void mg_http_serve_file(struct mg_connection *c, struct mg_http_message *hm, mg_printf(c, "HTTP/1.1 304 Not Modified\r\nContent-Length: 0\r\n\r\n"); } else { int n, status = 200; - char range[70] = ""; + char range[100] = ""; int64_t r1 = 0, r2 = 0, cl = st.st_size; // Handle Range header @@ -950,7 +954,7 @@ void mg_http_serve_file(struct mg_connection *c, struct mg_http_message *hm, r1, r1 + cl - 1, (int64_t) st.st_size); #if _FILE_OFFSET_BITS == 64 || _POSIX_C_SOURCE >= 200112L || \ _XOPEN_SOURCE >= 600 - fseeko(fp, r1, SEEK_SET); + fseeko(fp, (off_t) r1, SEEK_SET); #else fseek(fp, (long) r1, SEEK_SET); #endif @@ -1127,7 +1131,7 @@ static void printdirentry(struct mg_connection *c, const char *name, } } strftime(mod, sizeof(mod), "%d-%b-%Y %H:%M", localtime_r(&stp->st_mtime, &t)); - n = mg_url_encode(name, strlen(name), path, sizeof(path)); + n = (int) mg_url_encode(name, strlen(name), path, sizeof(path)); mg_printf(c, " %s%s" "%s%s\n", @@ -1206,7 +1210,9 @@ static void listdir(struct mg_connection *c, struct mg_http_message *hm, "
" "
Mongoose v.%s
\n", MG_VERSION); - n = snprintf(tmp, sizeof(tmp), "%lu", (unsigned long) (c->send.len - off)); + n = (size_t) snprintf(tmp, sizeof(tmp), "%lu", + (unsigned long) (c->send.len - off)); + if (n > sizeof(tmp)) n = 0; memcpy(c->send.buf + off - 10, tmp, n); // Set content length } else { mg_http_reply(c, 400, "", "Cannot open dir"); @@ -1259,7 +1265,7 @@ void mg_http_serve_dir(struct mg_connection *c, struct mg_http_message *hm, if (is_index && fp == NULL) { char *p = t2 + strlen(t2); while (p > t2 && p[-1] != '/') p--; - strncpy(p, "index.shtml", &t2[sizeof(t2)] - p - 2); + strncpy(p, "index.shtml", (size_t)(&t2[sizeof(t2)] - p - 2)); t2[sizeof(t2) - 1] = '\0'; fp = mg_fopen(t2, "r"); } @@ -1292,7 +1298,7 @@ static bool mg_is_url_safe(int c) { (c >= 'A' && c <= 'Z') || c == '.' || c == '_' || c == '-' || c == '~'; } -int mg_url_encode(const char *s, size_t sl, char *buf, size_t len) { +size_t mg_url_encode(const char *s, size_t sl, char *buf, size_t len) { size_t i, n = 0; for (i = 0; i < sl; i++) { int c = *(unsigned char *) &s[i]; @@ -1308,14 +1314,14 @@ int mg_url_encode(const char *s, size_t sl, char *buf, size_t len) { return n; } -void mg_http_creds(struct mg_http_message *hm, char *user, int userlen, - char *pass, int passlen) { +void mg_http_creds(struct mg_http_message *hm, char *user, size_t userlen, + char *pass, size_t passlen) { struct mg_str *v = mg_http_get_header(hm, "Authorization"); user[0] = pass[0] = '\0'; if (v != NULL && v->len > 6 && memcmp(v->ptr, "Basic ", 6) == 0) { char buf[256]; int n = mg_base64_decode(v->ptr + 6, (int) v->len - 6, buf); - const char *p = (const char *) memchr(buf, ':', n); + const char *p = (const char *) memchr(buf, ':', n > 0 ? (size_t) n : 0); if (p != NULL) { snprintf(user, userlen, "%.*s", (int) (p - buf), buf); snprintf(pass, passlen, "%.*s", n - (int) (p - buf) - 1, p + 1); @@ -1345,7 +1351,7 @@ struct mg_str mg_http_get_header_var(struct mg_str s, struct mg_str v) { while (p < x && (q ? p == b || *p != '"' : *p != ';' && *p != ' ')) p++; // LOG(LL_INFO, ("[%.*s] [%.*s] [%.*s]", (int) s.len, s.ptr, (int) v.len, // v.ptr, (int) (p - b), b)); - return stripquotes(mg_str_n(b, p - b + q)); + return stripquotes(mg_str_n(b, (size_t)(p - b + q))); } } return mg_str_n(NULL, 0); @@ -1369,7 +1375,7 @@ static size_t get_chunk_length(const char *buf, size_t len, size_t *ll) { // Walk through all chunks in the chunked body. For each chunk, fire // an MG_EV_HTTP_CHUNK event. static void walkchunks(struct mg_connection *c, struct mg_http_message *hm, - int reqlen) { + size_t reqlen) { size_t off = 0, bl, ll; while (off + reqlen < c->recv.len) { char *buf = (char *) &c->recv.buf[reqlen]; @@ -1385,14 +1391,14 @@ static void walkchunks(struct mg_connection *c, struct mg_http_message *hm, // Zero chunk - last one. Prepare body - cut off chunk lengths off = bl = 0; while (off + reqlen < c->recv.len) { - char *buf = (char *) &c->recv.buf[reqlen]; - size_t memo = c->recv.len; - size_t cl = get_chunk_length(&buf[off], memo - reqlen - off, &ll); - size_t n = cl < ll + 2 ? 0 : cl - ll - 2; - memmove(buf + bl, buf + off + ll, n); + char *buf2 = (char *) &c->recv.buf[reqlen]; + size_t memo2 = c->recv.len; + size_t cl2 = get_chunk_length(&buf2[off], memo2 - reqlen - off, &ll); + size_t n = cl < ll + 2 ? 0 : cl2 - ll - 2; + memmove(buf2 + bl, buf2 + off + ll, n); bl += n; - off += cl; - if (cl <= 5) break; + off += cl2; + if (cl2 <= 5) break; } // LOG(LL_INFO, ("BL->%d del %d off %d", (int) bl, (int) del, (int) off)); c->recv.len -= off - bl; @@ -1420,8 +1426,10 @@ void mg_http_delete_chunk(struct mg_connection *c, struct mg_http_message *hm) { } { const char *end = &ch.ptr[ch.len]; - size_t n = end - (char *) c->recv.buf; - if (c->recv.len > n) memmove((char *) ch.ptr, end, c->recv.len - n); + size_t n = (size_t)(end - (char *) c->recv.buf); + if (c->recv.len > n) { + memmove((char *) ch.ptr, end, (size_t)(c->recv.len - n)); + } // LOG(LL_INFO, ("DELETING CHUNK: %zu %zu %zu\n%.*s", c->recv.len, n, // ch.len, (int) ch.len, ch.ptr)); } @@ -1436,9 +1444,9 @@ static void http_cb(struct mg_connection *c, int ev, void *evd, void *fnd) { bool is_chunked = n > 0 && mg_is_chunked(&hm); if (ev == MG_EV_CLOSE) { hm.message.len = c->recv.len; - hm.body.len = hm.message.len - (hm.body.ptr - hm.message.ptr); - } else if (is_chunked) { - walkchunks(c, &hm, n); + hm.body.len = hm.message.len - (size_t)(hm.body.ptr - hm.message.ptr); + } else if (is_chunked && n > 0) { + walkchunks(c, &hm, (size_t) n); } // LOG(LL_INFO, //("---->%d %d\n%.*s", n, is_chunked, (int) c->recv.len, c->recv.buf)); @@ -1450,7 +1458,8 @@ static void http_cb(struct mg_connection *c, int ev, void *evd, void *fnd) { mg_iobuf_delete(&c->recv, hm.message.len); } else { if (n > 0 && !is_chunked) { - hm.chunk = mg_str_n((char *) &c->recv.buf[n], c->recv.len - n); + hm.chunk = + mg_str_n((char *) &c->recv.buf[n], c->recv.len - (size_t) n); mg_call(c, MG_EV_HTTP_CHUNK, &hm); } break; @@ -1554,13 +1563,13 @@ void mg_iobuf_free(struct mg_iobuf *io) { #if MG_ENABLE_MGOS #else #if MG_ENABLE_LOG -static void mg_log_stdout(const void *buf, int len, void *userdata) { +static void mg_log_stdout(const void *buf, size_t len, void *userdata) { (void) userdata; fwrite(buf, 1, len, stdout); } static const char *s_spec = "2"; -static void (*s_fn)(const void *, int, void *) = mg_log_stdout; +static void (*s_fn)(const void *, size_t, void *) = mg_log_stdout; static void *s_fn_param = NULL; void mg_log_set(const char *spec) { @@ -1573,10 +1582,12 @@ bool mg_log_prefix(int level, const char *file, int line, const char *fname) { int max = LL_INFO; struct mg_str k, v, s = mg_str(s_spec); const char *p = strrchr(file, '/'); + + if (s_fn == NULL) return false; + if (p == NULL) p = strrchr(file, '\\'); p = p == NULL ? file : p + 1; - if (s_fn == NULL) return false; while (mg_next_comma_entry(&s, &k, &v)) { if (v.len == 0) max = atoi(k.ptr); if (v.len > 0 && strncmp(p, k.ptr, k.len) == 0) max = atoi(v.ptr); @@ -1607,14 +1618,14 @@ void mg_log(const char *fmt, ...) { va_start(ap, fmt); len = mg_vasprintf(&buf, sizeof(mem), fmt, ap); va_end(ap); - s_fn(buf, len, s_fn_param); + s_fn(buf, len > 0 ? (size_t) len : 0, s_fn_param); s_fn("\n", 1, s_fn_param); if (buf != mem) free(buf); } -void mg_log_set_callback(void (*fn)(const void *, int, void *), void *param) { +void mg_log_set_callback(void (*fn)(const void *, size_t, void *), void *fnd) { s_fn = fn; - s_fn_param = param; + s_fn_param = fnd; } #endif #endif @@ -1846,14 +1857,14 @@ enum { MQTT_OK, MQTT_INCOMPLETE, MQTT_MALFORMED }; void mg_mqtt_send_header(struct mg_connection *c, uint8_t cmd, uint8_t flags, uint32_t len) { uint8_t buf[1 + sizeof(len)], *vlen = &buf[1]; - buf[0] = (cmd << 4) | flags; + buf[0] = (uint8_t)((cmd << 4) | flags); do { *vlen = len % 0x80; len /= 0x80; if (len > 0) *vlen |= 0x80; vlen++; } while (len > 0 && vlen < &buf[sizeof(buf)]); - mg_send(c, buf, vlen - buf); + mg_send(c, buf, (size_t)(vlen - buf)); } static void mg_send_u16(struct mg_connection *c, uint16_t value) { @@ -1863,7 +1874,7 @@ static void mg_send_u16(struct mg_connection *c, uint16_t value) { static void mqtt_login(struct mg_connection *c, const char *url, struct mg_mqtt_opts *opts) { uint32_t total_len = 7 + 1 + 2 + 2; - uint16_t flags = (opts->qos & 3) << 3; + uint16_t flags = (uint16_t)(((uint16_t) opts->qos & 3) << 3); struct mg_str user = mg_url_user(url); struct mg_str pass = mg_url_pass(url); @@ -1952,14 +1963,14 @@ int mg_mqtt_parse(const uint8_t *buf, size_t len, struct mg_mqtt_message *m) { p = (uint8_t *) buf + 1; while ((size_t)(p - buf) < len) { lc = *((uint8_t *) p++); - n += (lc & 0x7f) << 7 * len_len; + n += (uint32_t)((lc & 0x7f) << 7 * len_len); len_len++; if (!(lc & 0x80)) break; if (len_len >= 4) return MQTT_MALFORMED; } end = p + n; if (lc & 0x80 || end > buf + len) return MQTT_INCOMPLETE; - m->dgram.len = end - buf; + m->dgram.len = (size_t)(end - buf); switch (m->cmd) { case MQTT_CMD_CONNACK: @@ -1972,28 +1983,28 @@ int mg_mqtt_parse(const uint8_t *buf, size_t len, struct mg_mqtt_message *m) { case MQTT_CMD_PUBCOMP: case MQTT_CMD_SUBACK: if (p + 2 > end) return MQTT_MALFORMED; - m->id = (p[0] << 8) | p[1]; + m->id = (uint16_t)((((uint16_t) p[0]) << 8) | p[1]); break; case MQTT_CMD_SUBSCRIBE: { if (p + 2 > end) return MQTT_MALFORMED; - m->id = (p[0] << 8) | p[1]; + m->id = (uint16_t)((((uint16_t) p[0]) << 8) | p[1]); p += 2; break; } case MQTT_CMD_PUBLISH: { if (p + 2 > end) return MQTT_MALFORMED; - m->topic.len = (p[0] << 8) | p[1]; + m->topic.len = (uint16_t)((((uint16_t) p[0]) << 8) | p[1]); m->topic.ptr = (char *) p + 2; p += 2 + m->topic.len; if (p > end) return MQTT_MALFORMED; if (m->qos > 0) { if (p + 2 > end) return MQTT_MALFORMED; - m->id = (p[0] << 8) | p[1]; + m->id = (uint16_t)((((uint16_t) p[0]) << 8) | p[1]); p += 2; } if (p > end) return MQTT_MALFORMED; m->data.ptr = (char *) p; - m->data.len = end - p; + m->data.len = (size_t)(end - p); break; } default: @@ -2002,28 +2013,29 @@ int mg_mqtt_parse(const uint8_t *buf, size_t len, struct mg_mqtt_message *m) { return MQTT_OK; } -static int mg_mqtt_next_topic(struct mg_mqtt_message *msg, struct mg_str *topic, - uint8_t *qos, int pos) { +static size_t mg_mqtt_next_topic(struct mg_mqtt_message *msg, + struct mg_str *topic, uint8_t *qos, + size_t pos) { unsigned char *buf = (unsigned char *) msg->dgram.ptr + pos; - int new_pos; - if ((size_t) pos >= msg->dgram.len) return -1; + size_t new_pos; + if (pos >= msg->dgram.len) return 0; - topic->len = buf[0] << 8 | buf[1]; + topic->len = (size_t)(((unsigned) buf[0]) << 8 | buf[1]); topic->ptr = (char *) buf + 2; new_pos = pos + 2 + topic->len + (qos == NULL ? 0 : 1); - if ((size_t) new_pos > msg->dgram.len) return -1; + if ((size_t) new_pos > msg->dgram.len) return 0; if (qos != NULL) *qos = buf[2 + topic->len]; return new_pos; } -int mg_mqtt_next_sub(struct mg_mqtt_message *msg, struct mg_str *topic, - uint8_t *qos, int pos) { +size_t mg_mqtt_next_sub(struct mg_mqtt_message *msg, struct mg_str *topic, + uint8_t *qos, size_t pos) { uint8_t tmp; return mg_mqtt_next_topic(msg, topic, qos == NULL ? &tmp : qos, pos); } -int mg_mqtt_next_unsub(struct mg_mqtt_message *msg, struct mg_str *topic, - int pos) { +size_t mg_mqtt_next_unsub(struct mg_mqtt_message *msg, struct mg_str *topic, + size_t pos) { return mg_mqtt_next_topic(msg, topic, NULL, pos); } @@ -2111,7 +2123,7 @@ struct mg_connection *mg_mqtt_listen(struct mg_mgr *mgr, const char *url, int mg_vprintf(struct mg_connection *c, const char *fmt, va_list ap) { char mem[256], *buf = mem; int len = mg_vasprintf(&buf, sizeof(mem), fmt, ap); - len = mg_send(c, buf, len); + len = mg_send(c, buf, len > 0 ? (size_t) len : 0); if (buf != mem) free(buf); return len; } @@ -2162,7 +2174,7 @@ static bool mg_aton4(struct mg_str str, struct mg_addr *addr) { if (str.ptr[i] >= '0' && str.ptr[i] <= '9') { int octet = data[num_dots] * 10 + (str.ptr[i] - '0'); if (octet > 255) return false; - data[num_dots] = octet; + data[num_dots] = (uint8_t) octet; } else if (str.ptr[i] == '.') { if (num_dots >= 3 || i == 0 || str.ptr[i - 1] == '.') return false; num_dots++; @@ -2533,8 +2545,8 @@ int mg_sntp_parse(const unsigned char *buf, size_t len, struct timeval *tv) { } else { uint32_t *data = (uint32_t *) &buf[40]; tv->tv_sec = mg_ntohl(data[0]) - SNTP_TIME_OFFSET; - tv->tv_usec = mg_ntohl(data[1]); - s_sntmp_next = tv->tv_sec + SNTP_INTERVAL_SEC; + tv->tv_usec = (suseconds_t) mg_ntohl(data[1]); + s_sntmp_next = (unsigned long) (tv->tv_sec + SNTP_INTERVAL_SEC); res = 0; } return res; @@ -2550,7 +2562,7 @@ static void sntp_cb(struct mg_connection *c, int ev, void *evd, void *fnd) { } c->recv.len = 0; // Clear receive buffer } else if (ev == MG_EV_RESOLVE) { - mg_sntp_send(c, time(NULL)); + mg_sntp_send(c, (unsigned long) time(NULL)); } else if (ev == MG_EV_CLOSE) { // mg_fn_del(c, sntp_cb); } @@ -2657,19 +2669,19 @@ static union usa tousa(struct mg_addr *a) { return usa; } -static int mg_sock_failed(void) { +static bool mg_sock_would_block(void) { int err = MG_SOCK_ERRNO; - return err != EINPROGRESS && err != EWOULDBLOCK + return err == EINPROGRESS || err == EWOULDBLOCK #ifndef WINCE - && err != EAGAIN && err != EINTR + || err == EAGAIN || err == EINTR #endif #if defined(_WIN32) && MG_ENABLE_WINSOCK - && err != WSAEINTR && err != WSAEWOULDBLOCK + || err == WSAEINTR || err == WSAEWOULDBLOCK #endif ; } -static struct mg_connection *alloc_conn(struct mg_mgr *mgr, int is_client, +static struct mg_connection *alloc_conn(struct mg_mgr *mgr, bool is_client, SOCKET fd) { struct mg_connection *c = (struct mg_connection *) calloc(1, sizeof(*c)); if (c != NULL) { @@ -2681,37 +2693,8 @@ static struct mg_connection *alloc_conn(struct mg_mgr *mgr, int is_client, return c; } -static int mg_sock_recv(struct mg_connection *c, void *buf, int len, - int *fail) { - int n = 0; - if (c->is_udp) { - union usa usa; - socklen_t slen = sizeof(usa.sin); -#if MG_ENABLE_IPV6 - if (c->peer.is_ip6) slen = sizeof(usa.sin6); -#endif - n = recvfrom(FD(c), (char *) buf, len, 0, &usa.sa, &slen); - if (n > 0) { - if (c->peer.is_ip6) { -#if MG_ENABLE_IPV6 - memcpy(c->peer.ip6, &usa.sin6.sin6_addr, sizeof(c->peer.ip6)); - c->peer.port = usa.sin6.sin6_port; -#endif - } else { - c->peer.ip = *(uint32_t *) &usa.sin.sin_addr; - c->peer.port = usa.sin.sin_port; - } - } - } else { - n = recv(FD(c), (char *) buf, len, MSG_NONBLOCKING); - } - *fail = (n == 0) || (n < 0 && mg_sock_failed()); - return n; -} - -static int mg_sock_send(struct mg_connection *c, const void *buf, int len, - int *fail) { - int n = 0; +static long mg_sock_send(struct mg_connection *c, const void *buf, size_t len) { + long n = 0; if (c->is_udp) { union usa usa = tousa(&c->peer); socklen_t slen = sizeof(usa.sin); @@ -2722,47 +2705,12 @@ static int mg_sock_send(struct mg_connection *c, const void *buf, int len, } else { n = send(FD(c), (char *) buf, len, MSG_NONBLOCKING); } - *fail = (n == 0) || (n < 0 && mg_sock_failed()); - return n; + return n == 0 ? -1 : n < 0 && mg_sock_would_block() ? 0 : n; } -static int ll_read(struct mg_connection *c, void *buf, int len, int *fail) { - int n = c->is_tls ? mg_tls_recv(c, buf, len, fail) - : mg_sock_recv(c, buf, len, fail); - LOG(*fail ? LL_DEBUG : LL_VERBOSE_DEBUG, - ("%lu %c%c%c %d/%d %d %d", c->id, c->is_tls ? 'T' : 't', - c->is_udp ? 'U' : 'u', c->is_connecting ? 'C' : 'c', n, len, - MG_SOCK_ERRNO, *fail)); - if (n > 0 && c->is_hexdumping) { - char *s = mg_hexdump(buf, n); - LOG(LL_INFO, ("\n-- %lu %s %s %d\n%s--", c->id, c->label, "<-", n, s)); - free(s); - } - return n; -} - -static int ll_write(struct mg_connection *c, const void *buf, int len, - int *fail) { - int n = c->is_tls ? mg_tls_send(c, buf, len, fail) - : mg_sock_send(c, buf, len, fail); - LOG(*fail ? LL_ERROR : LL_VERBOSE_DEBUG, - ("%lu %c%c%c %d/%d %d", c->id, c->is_tls ? 'T' : 't', - c->is_udp ? 'U' : 'u', c->is_connecting ? 'C' : 'c', n, len, - MG_SOCK_ERRNO)); - if (n > 0 && c->is_hexdumping) { - char *s = mg_hexdump(buf, len); - LOG(LL_INFO, ("\n-- %lu %s %s %d\n%s--", c->id, c->label, "->", len, s)); - free(s); - } - return n; -} - -int mg_send(struct mg_connection *c, const void *buf, size_t len) { - int fail, n = c->is_udp - ? ll_write(c, buf, len, &fail) - : (int) mg_iobuf_append(&c->send, buf, len, MG_IO_SIZE); - if (len > 0 && n == 0) fail = 1; - return n; +bool mg_send(struct mg_connection *c, const void *buf, size_t len) { + return c->is_udp ? mg_sock_send(c, buf, len) > 0 + : mg_iobuf_append(&c->send, buf, len, MG_IO_SIZE); } static void mg_set_non_blocking_mode(SOCKET fd) { @@ -2830,40 +2778,95 @@ SOCKET mg_open_listener(const char *url) { return fd; } -static void read_conn(struct mg_connection *c, - int (*fn)(struct mg_connection *, void *, int, int *)) { - unsigned char *buf; - int rc, len, fail; - - // NOTE(lsm): do only one iteration of reads, cause some systems - // (e.g. FreeRTOS stack) return 0 instead of -1/EWOULDBLOCK when no data - if (c->recv.size - c->recv.len < MG_IO_SIZE && - c->recv.size < MG_MAX_RECV_BUF_SIZE && - !mg_iobuf_resize(&c->recv, c->recv.size + MG_IO_SIZE)) { - c->is_closing = 1; - } - buf = c->recv.buf + c->recv.len; - len = (int) (c->recv.size - c->recv.len); - rc = fn(c, buf, len, &fail); - if (rc > 0) { - struct mg_str evd = mg_str_n((char *) buf, rc); - c->recv.len += rc; - mg_call(c, MG_EV_READ, &evd); +static long mg_sock_recv(struct mg_connection *c, void *buf, size_t len) { + long n = 0; + if (c->is_udp) { + union usa usa; + socklen_t slen = sizeof(usa.sin); +#if MG_ENABLE_IPV6 + if (c->peer.is_ip6) slen = sizeof(usa.sin6); +#endif + n = recvfrom(FD(c), (char *) buf, len, 0, &usa.sa, &slen); + if (n > 0) { + if (c->peer.is_ip6) { +#if MG_ENABLE_IPV6 + memcpy(c->peer.ip6, &usa.sin6.sin6_addr, sizeof(c->peer.ip6)); + c->peer.port = usa.sin6.sin6_port; +#endif + } else { + c->peer.ip = *(uint32_t *) &usa.sin.sin_addr; + c->peer.port = usa.sin.sin_port; + } + } } else { - if (fail) c->is_closing = 1; + n = recv(FD(c), (char *) buf, len, MSG_NONBLOCKING); + } + return n == 0 ? -1 : n < 0 && mg_sock_would_block() ? 0 : n; +} + +// NOTE(lsm): do only one iteration of reads, cause some systems +// (e.g. FreeRTOS stack) return 0 instead of -1/EWOULDBLOCK when no data +static void read_conn(struct mg_connection *c) { + if (c->recv.len >= MG_MAX_RECV_BUF_SIZE) { + mg_error(c, "max_recv_buf_size reached"); + } else if (c->recv.size - c->recv.len < MG_IO_SIZE && + !mg_iobuf_resize(&c->recv, c->recv.size + MG_IO_SIZE)) { + mg_error(c, "oom"); + } else { + char *buf = (char *) &c->recv.buf[c->recv.len]; + size_t len = c->recv.size - c->recv.len; + long n = c->is_tls ? mg_tls_recv(c, buf, len) : mg_sock_recv(c, buf, len); + LOG(n > 0 ? LL_VERBOSE_DEBUG : LL_DEBUG, + ("%-3lu %d%d%d%d%d%d%d%d%d%d%d%d%d%d %7ld %ld/%ld err %d", c->id, + c->is_listening, c->is_client, c->is_accepted, c->is_resolving, + c->is_connecting, c->is_tls, c->is_tls_hs, c->is_udp, c->is_websocket, + c->is_hexdumping, c->is_draining, c->is_closing, c->is_readable, + c->is_writable, (long) c->recv.len, n, (long) len, MG_SOCK_ERRNO)); + if (n == 0) { + // Do nothing + } else if (n < 0) { + c->is_closing = 1; // Error, or normal termination + } else if (n > 0) { + struct mg_str evd = mg_str_n(buf, (size_t) n); + if (c->is_hexdumping) { + char *s = mg_hexdump(buf, (size_t) n); + LOG(LL_INFO, ("\n-- %lu %s %s %ld\n%s", c->id, c->label, "<-", n, s)); + free(s); + } + c->recv.len += (size_t) n; + mg_call(c, MG_EV_READ, &evd); + } } } -static int write_conn(struct mg_connection *c) { - int fail, rc = ll_write(c, c->send.buf, c->send.len, &fail); - if (rc > 0) { - mg_iobuf_delete(&c->send, rc); +static void write_conn(struct mg_connection *c) { + char *buf = (char *) c->send.buf; + size_t len = c->send.len; + long n = c->is_tls ? mg_tls_send(c, buf, len) : mg_sock_send(c, buf, len); + + LOG(n > 0 ? LL_VERBOSE_DEBUG : LL_DEBUG, + ("%-3lu %d%d%d%d%d%d%d%d%d%d%d%d%d%d %7ld %ld err %d", c->id, + c->is_listening, c->is_client, c->is_accepted, c->is_resolving, + c->is_connecting, c->is_tls, c->is_tls_hs, c->is_udp, c->is_websocket, + c->is_hexdumping, c->is_draining, c->is_closing, c->is_readable, + c->is_writable, (long) c->send.len, n, MG_SOCK_ERRNO)); + + if (n == 0) { + // Do nothing + } else if (n < 0) { + c->is_closing = 1; // Error, or normal termination + } else if (n > 0) { + // Hexdump before deleting + if (c->is_hexdumping) { + char *s = mg_hexdump(buf, (size_t) n); + LOG(LL_INFO, ("\n-- %lu %s %s %ld\n%s", c->id, c->label, "<-", n, s)); + free(s); + } + mg_iobuf_delete(&c->send, (size_t) n); if (c->send.len == 0) mg_iobuf_resize(&c->send, 0); - mg_call(c, MG_EV_WRITE, &rc); - } else if (fail) { - c->is_closing = 1; + mg_call(c, MG_EV_WRITE, &n); + // if (c->send.len == 0) mg_iobuf_resize(&c->send, 0); } - return rc; } static void close_conn(struct mg_connection *c) { @@ -2918,7 +2921,7 @@ static void setsockopts(struct mg_connection *c) { void mg_connect_resolved(struct mg_connection *c) { char buf[40]; int type = c->is_udp ? SOCK_DGRAM : SOCK_STREAM; - int af = AF_INET; + int rc, af = AF_INET; #if MG_ENABLE_IPV6 if (c->peer.is_ip6) af = AF_INET6; #endif @@ -2933,19 +2936,16 @@ void mg_connect_resolved(struct mg_connection *c) { mg_call(c, MG_EV_RESOLVE, NULL); if (type == SOCK_STREAM) { union usa usa = tousa(&c->peer); - socklen_t slen = + socklen_t slen = sizeof(usa.sin); #if MG_ENABLE_IPV6 - c->peer.is_ip6 ? sizeof(usa.sin6) : + if (c->peer.is_ip6) slen = sizeof(usa.sin6); #endif - sizeof(usa.sin); - int rc = connect(FD(c), &usa.sa, slen); - int fail = rc < 0 && mg_sock_failed() ? MG_SOCK_ERRNO : 0; - if (fail) { - mg_error(c, "connect: %d", MG_SOCK_ERRNO); - } else { + if ((rc = connect(FD(c), &usa.sa, slen)) == 0 || mg_sock_would_block()) { setsockopts(c); + if (rc != 0) c->is_connecting = 1; + } else { + mg_error(c, "connect: %d", MG_SOCK_ERRNO); } - if (rc < 0) c->is_connecting = 1; } } @@ -3053,7 +3053,7 @@ bool mg_socketpair(int *s1, int *s2) { struct mg_connection *mg_listen(struct mg_mgr *mgr, const char *url, mg_event_handler_t fn, void *fn_data) { struct mg_connection *c = NULL; - int is_udp = strncmp(url, "udp:", 4) == 0; + bool is_udp = strncmp(url, "udp:", 4) == 0; SOCKET fd = mg_open_listener(url); if (fd == INVALID_SOCKET) { } else if ((c = alloc_conn(mgr, 0, fd)) == NULL) { @@ -3167,7 +3167,7 @@ void mg_mgr_poll(struct mg_mgr *mgr, int ms) { } else if (c->is_tls_hs) { if ((c->is_readable || c->is_writable)) mg_tls_handshake(c); } else { - if (c->is_readable) read_conn(c, ll_read); + if (c->is_readable) read_conn(c); if (c->is_writable) write_conn(c); } @@ -3198,7 +3198,7 @@ static char *mg_ssi(const char *path, const char *root, int depth) { size_t len = 0, align = MG_IO_SIZE; while ((ch = fgetc(fp)) != EOF) { if (intag && ch == '>' && buf[len - 1] == '-' && buf[len - 2] == '-') { - buf[len++] = ch & 0xff; + buf[len++] = (char) (ch & 0xff); if (sscanf(buf, "%d %d\n%.*s", n, is_chunked, (int) c->recv.len, c->recv.buf)); @@ -1039,7 +1047,8 @@ static void http_cb(struct mg_connection *c, int ev, void *evd, void *fnd) { mg_iobuf_delete(&c->recv, hm.message.len); } else { if (n > 0 && !is_chunked) { - hm.chunk = mg_str_n((char *) &c->recv.buf[n], c->recv.len - n); + hm.chunk = + mg_str_n((char *) &c->recv.buf[n], c->recv.len - (size_t) n); mg_call(c, MG_EV_HTTP_CHUNK, &hm); } break; diff --git a/src/http.h b/src/http.h index 185fb48d..f6272afb 100644 --- a/src/http.h +++ b/src/http.h @@ -52,10 +52,10 @@ void mg_http_reply(struct mg_connection *, int status_code, const char *headers, const char *body_fmt, ...); struct mg_str *mg_http_get_header(struct mg_http_message *, const char *name); void mg_http_event_handler(struct mg_connection *c, int ev); -int mg_http_get_var(const struct mg_str *, const char *name, char *, int); +int mg_http_get_var(const struct mg_str *, const char *name, char *, size_t); int mg_url_decode(const char *s, size_t n, char *to, size_t to_len, int form); -int mg_url_encode(const char *s, size_t n, char *buf, size_t len); -void mg_http_creds(struct mg_http_message *, char *user, int, char *pass, int); +size_t mg_url_encode(const char *s, size_t n, char *buf, size_t len); +void mg_http_creds(struct mg_http_message *, char *, size_t, char *, size_t); bool mg_http_match_uri(const struct mg_http_message *, const char *glob); int mg_http_upload(struct mg_connection *, struct mg_http_message *hm, const char *dir); diff --git a/src/log.c b/src/log.c index 89e04f9a..5b67879e 100644 --- a/src/log.c +++ b/src/log.c @@ -4,13 +4,13 @@ #if MG_ENABLE_MGOS #else #if MG_ENABLE_LOG -static void mg_log_stdout(const void *buf, int len, void *userdata) { +static void mg_log_stdout(const void *buf, size_t len, void *userdata) { (void) userdata; fwrite(buf, 1, len, stdout); } static const char *s_spec = "2"; -static void (*s_fn)(const void *, int, void *) = mg_log_stdout; +static void (*s_fn)(const void *, size_t, void *) = mg_log_stdout; static void *s_fn_param = NULL; void mg_log_set(const char *spec) { @@ -23,10 +23,12 @@ bool mg_log_prefix(int level, const char *file, int line, const char *fname) { int max = LL_INFO; struct mg_str k, v, s = mg_str(s_spec); const char *p = strrchr(file, '/'); + + if (s_fn == NULL) return false; + if (p == NULL) p = strrchr(file, '\\'); p = p == NULL ? file : p + 1; - if (s_fn == NULL) return false; while (mg_next_comma_entry(&s, &k, &v)) { if (v.len == 0) max = atoi(k.ptr); if (v.len > 0 && strncmp(p, k.ptr, k.len) == 0) max = atoi(v.ptr); @@ -57,14 +59,14 @@ void mg_log(const char *fmt, ...) { va_start(ap, fmt); len = mg_vasprintf(&buf, sizeof(mem), fmt, ap); va_end(ap); - s_fn(buf, len, s_fn_param); + s_fn(buf, len > 0 ? (size_t) len : 0, s_fn_param); s_fn("\n", 1, s_fn_param); if (buf != mem) free(buf); } -void mg_log_set_callback(void (*fn)(const void *, int, void *), void *param) { +void mg_log_set_callback(void (*fn)(const void *, size_t, void *), void *fnd) { s_fn = fn; - s_fn_param = param; + s_fn_param = fnd; } #endif #endif diff --git a/src/log.h b/src/log.h index 3d8fffaa..2e18a0dd 100644 --- a/src/log.h +++ b/src/log.h @@ -12,7 +12,7 @@ enum { LL_NONE, LL_ERROR, LL_INFO, LL_DEBUG, LL_VERBOSE_DEBUG }; bool mg_log_prefix(int ll, const char *file, int line, const char *fname); void mg_log(const char *fmt, ...) PRINTF_LIKE(1, 2); void mg_log_set(const char *spec); -void mg_log_set_callback(void (*fn)(const void *, int, void *), void *param); +void mg_log_set_callback(void (*fn)(const void *, size_t, void *), void *param); #else #define LOG(level, args) (void) 0 #define mg_log_set(x) (void) (x) diff --git a/src/mqtt.c b/src/mqtt.c index 64c6dc12..88276388 100644 --- a/src/mqtt.c +++ b/src/mqtt.c @@ -20,14 +20,14 @@ enum { MQTT_OK, MQTT_INCOMPLETE, MQTT_MALFORMED }; void mg_mqtt_send_header(struct mg_connection *c, uint8_t cmd, uint8_t flags, uint32_t len) { uint8_t buf[1 + sizeof(len)], *vlen = &buf[1]; - buf[0] = (cmd << 4) | flags; + buf[0] = (uint8_t)((cmd << 4) | flags); do { *vlen = len % 0x80; len /= 0x80; if (len > 0) *vlen |= 0x80; vlen++; } while (len > 0 && vlen < &buf[sizeof(buf)]); - mg_send(c, buf, vlen - buf); + mg_send(c, buf, (size_t)(vlen - buf)); } static void mg_send_u16(struct mg_connection *c, uint16_t value) { @@ -37,7 +37,7 @@ static void mg_send_u16(struct mg_connection *c, uint16_t value) { static void mqtt_login(struct mg_connection *c, const char *url, struct mg_mqtt_opts *opts) { uint32_t total_len = 7 + 1 + 2 + 2; - uint16_t flags = (opts->qos & 3) << 3; + uint16_t flags = (uint16_t)(((uint16_t) opts->qos & 3) << 3); struct mg_str user = mg_url_user(url); struct mg_str pass = mg_url_pass(url); @@ -126,14 +126,14 @@ int mg_mqtt_parse(const uint8_t *buf, size_t len, struct mg_mqtt_message *m) { p = (uint8_t *) buf + 1; while ((size_t)(p - buf) < len) { lc = *((uint8_t *) p++); - n += (lc & 0x7f) << 7 * len_len; + n += (uint32_t)((lc & 0x7f) << 7 * len_len); len_len++; if (!(lc & 0x80)) break; if (len_len >= 4) return MQTT_MALFORMED; } end = p + n; if (lc & 0x80 || end > buf + len) return MQTT_INCOMPLETE; - m->dgram.len = end - buf; + m->dgram.len = (size_t)(end - buf); switch (m->cmd) { case MQTT_CMD_CONNACK: @@ -146,28 +146,28 @@ int mg_mqtt_parse(const uint8_t *buf, size_t len, struct mg_mqtt_message *m) { case MQTT_CMD_PUBCOMP: case MQTT_CMD_SUBACK: if (p + 2 > end) return MQTT_MALFORMED; - m->id = (p[0] << 8) | p[1]; + m->id = (uint16_t)((((uint16_t) p[0]) << 8) | p[1]); break; case MQTT_CMD_SUBSCRIBE: { if (p + 2 > end) return MQTT_MALFORMED; - m->id = (p[0] << 8) | p[1]; + m->id = (uint16_t)((((uint16_t) p[0]) << 8) | p[1]); p += 2; break; } case MQTT_CMD_PUBLISH: { if (p + 2 > end) return MQTT_MALFORMED; - m->topic.len = (p[0] << 8) | p[1]; + m->topic.len = (uint16_t)((((uint16_t) p[0]) << 8) | p[1]); m->topic.ptr = (char *) p + 2; p += 2 + m->topic.len; if (p > end) return MQTT_MALFORMED; if (m->qos > 0) { if (p + 2 > end) return MQTT_MALFORMED; - m->id = (p[0] << 8) | p[1]; + m->id = (uint16_t)((((uint16_t) p[0]) << 8) | p[1]); p += 2; } if (p > end) return MQTT_MALFORMED; m->data.ptr = (char *) p; - m->data.len = end - p; + m->data.len = (size_t)(end - p); break; } default: @@ -176,28 +176,29 @@ int mg_mqtt_parse(const uint8_t *buf, size_t len, struct mg_mqtt_message *m) { return MQTT_OK; } -static int mg_mqtt_next_topic(struct mg_mqtt_message *msg, struct mg_str *topic, - uint8_t *qos, int pos) { +static size_t mg_mqtt_next_topic(struct mg_mqtt_message *msg, + struct mg_str *topic, uint8_t *qos, + size_t pos) { unsigned char *buf = (unsigned char *) msg->dgram.ptr + pos; - int new_pos; - if ((size_t) pos >= msg->dgram.len) return -1; + size_t new_pos; + if (pos >= msg->dgram.len) return 0; - topic->len = buf[0] << 8 | buf[1]; + topic->len = (size_t)(((unsigned) buf[0]) << 8 | buf[1]); topic->ptr = (char *) buf + 2; new_pos = pos + 2 + topic->len + (qos == NULL ? 0 : 1); - if ((size_t) new_pos > msg->dgram.len) return -1; + if ((size_t) new_pos > msg->dgram.len) return 0; if (qos != NULL) *qos = buf[2 + topic->len]; return new_pos; } -int mg_mqtt_next_sub(struct mg_mqtt_message *msg, struct mg_str *topic, - uint8_t *qos, int pos) { +size_t mg_mqtt_next_sub(struct mg_mqtt_message *msg, struct mg_str *topic, + uint8_t *qos, size_t pos) { uint8_t tmp; return mg_mqtt_next_topic(msg, topic, qos == NULL ? &tmp : qos, pos); } -int mg_mqtt_next_unsub(struct mg_mqtt_message *msg, struct mg_str *topic, - int pos) { +size_t mg_mqtt_next_unsub(struct mg_mqtt_message *msg, struct mg_str *topic, + size_t pos) { return mg_mqtt_next_topic(msg, topic, NULL, pos); } diff --git a/src/mqtt.h b/src/mqtt.h index ede64c60..695e34e6 100644 --- a/src/mqtt.h +++ b/src/mqtt.h @@ -53,10 +53,10 @@ void mg_mqtt_sub(struct mg_connection *, struct mg_str *topic); int mg_mqtt_parse(const uint8_t *buf, size_t len, struct mg_mqtt_message *m); void mg_mqtt_send_header(struct mg_connection *, uint8_t cmd, uint8_t flags, uint32_t len); -int mg_mqtt_next_sub(struct mg_mqtt_message *msg, struct mg_str *topic, - uint8_t *qos, int pos); -int mg_mqtt_next_unsub(struct mg_mqtt_message *msg, struct mg_str *topic, - int pos); +size_t mg_mqtt_next_sub(struct mg_mqtt_message *msg, struct mg_str *topic, + uint8_t *qos, size_t pos); +size_t mg_mqtt_next_unsub(struct mg_mqtt_message *msg, struct mg_str *topic, + size_t pos); void mg_mqtt_ping(struct mg_connection *); void mg_mqtt_pong(struct mg_connection *); void mg_mqtt_disconnect(struct mg_connection *); diff --git a/src/net.c b/src/net.c index d967aade..c38aafdb 100644 --- a/src/net.c +++ b/src/net.c @@ -5,7 +5,7 @@ int mg_vprintf(struct mg_connection *c, const char *fmt, va_list ap) { char mem[256], *buf = mem; int len = mg_vasprintf(&buf, sizeof(mem), fmt, ap); - len = mg_send(c, buf, len); + len = mg_send(c, buf, len > 0 ? (size_t) len : 0); if (buf != mem) free(buf); return len; } @@ -56,7 +56,7 @@ static bool mg_aton4(struct mg_str str, struct mg_addr *addr) { if (str.ptr[i] >= '0' && str.ptr[i] <= '9') { int octet = data[num_dots] * 10 + (str.ptr[i] - '0'); if (octet > 255) return false; - data[num_dots] = octet; + data[num_dots] = (uint8_t) octet; } else if (str.ptr[i] == '.') { if (num_dots >= 3 || i == 0 || str.ptr[i - 1] == '.') return false; num_dots++; diff --git a/src/net.h b/src/net.h index 72bb83c0..4536c676 100644 --- a/src/net.h +++ b/src/net.h @@ -67,7 +67,7 @@ struct mg_connection *mg_listen(struct mg_mgr *, const char *url, mg_event_handler_t fn, void *fn_data); struct mg_connection *mg_connect(struct mg_mgr *, const char *url, mg_event_handler_t fn, void *fn_data); -int mg_send(struct mg_connection *, const void *, size_t); +bool mg_send(struct mg_connection *, const void *, size_t); int mg_printf(struct mg_connection *, const char *fmt, ...); int mg_vprintf(struct mg_connection *, const char *fmt, va_list ap); char *mg_straddr(struct mg_connection *, char *, size_t); diff --git a/src/sntp.c b/src/sntp.c index 5262e18c..5d814c18 100644 --- a/src/sntp.c +++ b/src/sntp.c @@ -22,8 +22,8 @@ int mg_sntp_parse(const unsigned char *buf, size_t len, struct timeval *tv) { } else { uint32_t *data = (uint32_t *) &buf[40]; tv->tv_sec = mg_ntohl(data[0]) - SNTP_TIME_OFFSET; - tv->tv_usec = mg_ntohl(data[1]); - s_sntmp_next = tv->tv_sec + SNTP_INTERVAL_SEC; + tv->tv_usec = (suseconds_t) mg_ntohl(data[1]); + s_sntmp_next = (unsigned long) (tv->tv_sec + SNTP_INTERVAL_SEC); res = 0; } return res; @@ -39,7 +39,7 @@ static void sntp_cb(struct mg_connection *c, int ev, void *evd, void *fnd) { } c->recv.len = 0; // Clear receive buffer } else if (ev == MG_EV_RESOLVE) { - mg_sntp_send(c, time(NULL)); + mg_sntp_send(c, (unsigned long) time(NULL)); } else if (ev == MG_EV_CLOSE) { // mg_fn_del(c, sntp_cb); } diff --git a/src/sock.c b/src/sock.c index a0cae704..48793cf2 100644 --- a/src/sock.c +++ b/src/sock.c @@ -73,19 +73,19 @@ static union usa tousa(struct mg_addr *a) { return usa; } -static int mg_sock_failed(void) { +static bool mg_sock_would_block(void) { int err = MG_SOCK_ERRNO; - return err != EINPROGRESS && err != EWOULDBLOCK + return err == EINPROGRESS || err == EWOULDBLOCK #ifndef WINCE - && err != EAGAIN && err != EINTR + || err == EAGAIN || err == EINTR #endif #if defined(_WIN32) && MG_ENABLE_WINSOCK - && err != WSAEINTR && err != WSAEWOULDBLOCK + || err == WSAEINTR || err == WSAEWOULDBLOCK #endif ; } -static struct mg_connection *alloc_conn(struct mg_mgr *mgr, int is_client, +static struct mg_connection *alloc_conn(struct mg_mgr *mgr, bool is_client, SOCKET fd) { struct mg_connection *c = (struct mg_connection *) calloc(1, sizeof(*c)); if (c != NULL) { @@ -97,37 +97,8 @@ static struct mg_connection *alloc_conn(struct mg_mgr *mgr, int is_client, return c; } -static int mg_sock_recv(struct mg_connection *c, void *buf, int len, - int *fail) { - int n = 0; - if (c->is_udp) { - union usa usa; - socklen_t slen = sizeof(usa.sin); -#if MG_ENABLE_IPV6 - if (c->peer.is_ip6) slen = sizeof(usa.sin6); -#endif - n = recvfrom(FD(c), (char *) buf, len, 0, &usa.sa, &slen); - if (n > 0) { - if (c->peer.is_ip6) { -#if MG_ENABLE_IPV6 - memcpy(c->peer.ip6, &usa.sin6.sin6_addr, sizeof(c->peer.ip6)); - c->peer.port = usa.sin6.sin6_port; -#endif - } else { - c->peer.ip = *(uint32_t *) &usa.sin.sin_addr; - c->peer.port = usa.sin.sin_port; - } - } - } else { - n = recv(FD(c), (char *) buf, len, MSG_NONBLOCKING); - } - *fail = (n == 0) || (n < 0 && mg_sock_failed()); - return n; -} - -static int mg_sock_send(struct mg_connection *c, const void *buf, int len, - int *fail) { - int n = 0; +static long mg_sock_send(struct mg_connection *c, const void *buf, size_t len) { + long n = 0; if (c->is_udp) { union usa usa = tousa(&c->peer); socklen_t slen = sizeof(usa.sin); @@ -138,47 +109,12 @@ static int mg_sock_send(struct mg_connection *c, const void *buf, int len, } else { n = send(FD(c), (char *) buf, len, MSG_NONBLOCKING); } - *fail = (n == 0) || (n < 0 && mg_sock_failed()); - return n; + return n == 0 ? -1 : n < 0 && mg_sock_would_block() ? 0 : n; } -static int ll_read(struct mg_connection *c, void *buf, int len, int *fail) { - int n = c->is_tls ? mg_tls_recv(c, buf, len, fail) - : mg_sock_recv(c, buf, len, fail); - LOG(*fail ? LL_DEBUG : LL_VERBOSE_DEBUG, - ("%lu %c%c%c %d/%d %d %d", c->id, c->is_tls ? 'T' : 't', - c->is_udp ? 'U' : 'u', c->is_connecting ? 'C' : 'c', n, len, - MG_SOCK_ERRNO, *fail)); - if (n > 0 && c->is_hexdumping) { - char *s = mg_hexdump(buf, n); - LOG(LL_INFO, ("\n-- %lu %s %s %d\n%s--", c->id, c->label, "<-", n, s)); - free(s); - } - return n; -} - -static int ll_write(struct mg_connection *c, const void *buf, int len, - int *fail) { - int n = c->is_tls ? mg_tls_send(c, buf, len, fail) - : mg_sock_send(c, buf, len, fail); - LOG(*fail ? LL_ERROR : LL_VERBOSE_DEBUG, - ("%lu %c%c%c %d/%d %d", c->id, c->is_tls ? 'T' : 't', - c->is_udp ? 'U' : 'u', c->is_connecting ? 'C' : 'c', n, len, - MG_SOCK_ERRNO)); - if (n > 0 && c->is_hexdumping) { - char *s = mg_hexdump(buf, len); - LOG(LL_INFO, ("\n-- %lu %s %s %d\n%s--", c->id, c->label, "->", len, s)); - free(s); - } - return n; -} - -int mg_send(struct mg_connection *c, const void *buf, size_t len) { - int fail, n = c->is_udp - ? ll_write(c, buf, len, &fail) - : (int) mg_iobuf_append(&c->send, buf, len, MG_IO_SIZE); - if (len > 0 && n == 0) fail = 1; - return n; +bool mg_send(struct mg_connection *c, const void *buf, size_t len) { + return c->is_udp ? mg_sock_send(c, buf, len) > 0 + : mg_iobuf_append(&c->send, buf, len, MG_IO_SIZE); } static void mg_set_non_blocking_mode(SOCKET fd) { @@ -246,40 +182,95 @@ SOCKET mg_open_listener(const char *url) { return fd; } -static void read_conn(struct mg_connection *c, - int (*fn)(struct mg_connection *, void *, int, int *)) { - unsigned char *buf; - int rc, len, fail; - - // NOTE(lsm): do only one iteration of reads, cause some systems - // (e.g. FreeRTOS stack) return 0 instead of -1/EWOULDBLOCK when no data - if (c->recv.size - c->recv.len < MG_IO_SIZE && - c->recv.size < MG_MAX_RECV_BUF_SIZE && - !mg_iobuf_resize(&c->recv, c->recv.size + MG_IO_SIZE)) { - c->is_closing = 1; - } - buf = c->recv.buf + c->recv.len; - len = (int) (c->recv.size - c->recv.len); - rc = fn(c, buf, len, &fail); - if (rc > 0) { - struct mg_str evd = mg_str_n((char *) buf, rc); - c->recv.len += rc; - mg_call(c, MG_EV_READ, &evd); +static long mg_sock_recv(struct mg_connection *c, void *buf, size_t len) { + long n = 0; + if (c->is_udp) { + union usa usa; + socklen_t slen = sizeof(usa.sin); +#if MG_ENABLE_IPV6 + if (c->peer.is_ip6) slen = sizeof(usa.sin6); +#endif + n = recvfrom(FD(c), (char *) buf, len, 0, &usa.sa, &slen); + if (n > 0) { + if (c->peer.is_ip6) { +#if MG_ENABLE_IPV6 + memcpy(c->peer.ip6, &usa.sin6.sin6_addr, sizeof(c->peer.ip6)); + c->peer.port = usa.sin6.sin6_port; +#endif + } else { + c->peer.ip = *(uint32_t *) &usa.sin.sin_addr; + c->peer.port = usa.sin.sin_port; + } + } } else { - if (fail) c->is_closing = 1; + n = recv(FD(c), (char *) buf, len, MSG_NONBLOCKING); + } + return n == 0 ? -1 : n < 0 && mg_sock_would_block() ? 0 : n; +} + +// NOTE(lsm): do only one iteration of reads, cause some systems +// (e.g. FreeRTOS stack) return 0 instead of -1/EWOULDBLOCK when no data +static void read_conn(struct mg_connection *c) { + if (c->recv.len >= MG_MAX_RECV_BUF_SIZE) { + mg_error(c, "max_recv_buf_size reached"); + } else if (c->recv.size - c->recv.len < MG_IO_SIZE && + !mg_iobuf_resize(&c->recv, c->recv.size + MG_IO_SIZE)) { + mg_error(c, "oom"); + } else { + char *buf = (char *) &c->recv.buf[c->recv.len]; + size_t len = c->recv.size - c->recv.len; + long n = c->is_tls ? mg_tls_recv(c, buf, len) : mg_sock_recv(c, buf, len); + LOG(n > 0 ? LL_VERBOSE_DEBUG : LL_DEBUG, + ("%-3lu %d%d%d%d%d%d%d%d%d%d%d%d%d%d %7ld %ld/%ld err %d", c->id, + c->is_listening, c->is_client, c->is_accepted, c->is_resolving, + c->is_connecting, c->is_tls, c->is_tls_hs, c->is_udp, c->is_websocket, + c->is_hexdumping, c->is_draining, c->is_closing, c->is_readable, + c->is_writable, (long) c->recv.len, n, (long) len, MG_SOCK_ERRNO)); + if (n == 0) { + // Do nothing + } else if (n < 0) { + c->is_closing = 1; // Error, or normal termination + } else if (n > 0) { + struct mg_str evd = mg_str_n(buf, (size_t) n); + if (c->is_hexdumping) { + char *s = mg_hexdump(buf, (size_t) n); + LOG(LL_INFO, ("\n-- %lu %s %s %ld\n%s", c->id, c->label, "<-", n, s)); + free(s); + } + c->recv.len += (size_t) n; + mg_call(c, MG_EV_READ, &evd); + } } } -static int write_conn(struct mg_connection *c) { - int fail, rc = ll_write(c, c->send.buf, c->send.len, &fail); - if (rc > 0) { - mg_iobuf_delete(&c->send, rc); +static void write_conn(struct mg_connection *c) { + char *buf = (char *) c->send.buf; + size_t len = c->send.len; + long n = c->is_tls ? mg_tls_send(c, buf, len) : mg_sock_send(c, buf, len); + + LOG(n > 0 ? LL_VERBOSE_DEBUG : LL_DEBUG, + ("%-3lu %d%d%d%d%d%d%d%d%d%d%d%d%d%d %7ld %ld err %d", c->id, + c->is_listening, c->is_client, c->is_accepted, c->is_resolving, + c->is_connecting, c->is_tls, c->is_tls_hs, c->is_udp, c->is_websocket, + c->is_hexdumping, c->is_draining, c->is_closing, c->is_readable, + c->is_writable, (long) c->send.len, n, MG_SOCK_ERRNO)); + + if (n == 0) { + // Do nothing + } else if (n < 0) { + c->is_closing = 1; // Error, or normal termination + } else if (n > 0) { + // Hexdump before deleting + if (c->is_hexdumping) { + char *s = mg_hexdump(buf, (size_t) n); + LOG(LL_INFO, ("\n-- %lu %s %s %ld\n%s", c->id, c->label, "<-", n, s)); + free(s); + } + mg_iobuf_delete(&c->send, (size_t) n); if (c->send.len == 0) mg_iobuf_resize(&c->send, 0); - mg_call(c, MG_EV_WRITE, &rc); - } else if (fail) { - c->is_closing = 1; + mg_call(c, MG_EV_WRITE, &n); + // if (c->send.len == 0) mg_iobuf_resize(&c->send, 0); } - return rc; } static void close_conn(struct mg_connection *c) { @@ -334,7 +325,7 @@ static void setsockopts(struct mg_connection *c) { void mg_connect_resolved(struct mg_connection *c) { char buf[40]; int type = c->is_udp ? SOCK_DGRAM : SOCK_STREAM; - int af = AF_INET; + int rc, af = AF_INET; #if MG_ENABLE_IPV6 if (c->peer.is_ip6) af = AF_INET6; #endif @@ -349,19 +340,16 @@ void mg_connect_resolved(struct mg_connection *c) { mg_call(c, MG_EV_RESOLVE, NULL); if (type == SOCK_STREAM) { union usa usa = tousa(&c->peer); - socklen_t slen = + socklen_t slen = sizeof(usa.sin); #if MG_ENABLE_IPV6 - c->peer.is_ip6 ? sizeof(usa.sin6) : + if (c->peer.is_ip6) slen = sizeof(usa.sin6); #endif - sizeof(usa.sin); - int rc = connect(FD(c), &usa.sa, slen); - int fail = rc < 0 && mg_sock_failed() ? MG_SOCK_ERRNO : 0; - if (fail) { - mg_error(c, "connect: %d", MG_SOCK_ERRNO); - } else { + if ((rc = connect(FD(c), &usa.sa, slen)) == 0 || mg_sock_would_block()) { setsockopts(c); + if (rc != 0) c->is_connecting = 1; + } else { + mg_error(c, "connect: %d", MG_SOCK_ERRNO); } - if (rc < 0) c->is_connecting = 1; } } @@ -469,7 +457,7 @@ bool mg_socketpair(int *s1, int *s2) { struct mg_connection *mg_listen(struct mg_mgr *mgr, const char *url, mg_event_handler_t fn, void *fn_data) { struct mg_connection *c = NULL; - int is_udp = strncmp(url, "udp:", 4) == 0; + bool is_udp = strncmp(url, "udp:", 4) == 0; SOCKET fd = mg_open_listener(url); if (fd == INVALID_SOCKET) { } else if ((c = alloc_conn(mgr, 0, fd)) == NULL) { @@ -583,7 +571,7 @@ void mg_mgr_poll(struct mg_mgr *mgr, int ms) { } else if (c->is_tls_hs) { if ((c->is_readable || c->is_writable)) mg_tls_handshake(c); } else { - if (c->is_readable) read_conn(c, ll_read); + if (c->is_readable) read_conn(c); if (c->is_writable) write_conn(c); } diff --git a/src/ssi.c b/src/ssi.c index 8ddba017..3b49e2e6 100644 --- a/src/ssi.c +++ b/src/ssi.c @@ -16,7 +16,7 @@ static char *mg_ssi(const char *path, const char *root, int depth) { size_t len = 0, align = MG_IO_SIZE; while ((ch = fgetc(fp)) != EOF) { if (intag && ch == '>' && buf[len - 1] == '-' && buf[len - 2] == '-') { - buf[len++] = ch & 0xff; + buf[len++] = (char) (ch & 0xff); if (sscanf(buf, "