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, "