From 84a11fe3b1cd82f2790d12e8b963e69dc76b2f2f Mon Sep 17 00:00:00 2001 From: Deomid Ryabkov Date: Thu, 8 Feb 2018 17:42:57 +0000 Subject: [PATCH 01/41] Count both tests and individual checks CL: none PUBLISHED_FROM=ab7f50e1c68154832e862ebfb4a02d385ef7c6be --- src/common/test_util.h | 20 +++++++++++--------- 1 file changed, 11 insertions(+), 9 deletions(-) diff --git a/src/common/test_util.h b/src/common/test_util.h index 61103878..fbc0eae3 100644 --- a/src/common/test_util.h +++ b/src/common/test_util.h @@ -28,6 +28,7 @@ extern "C" { #endif extern int g_num_tests; +extern int g_num_checks; #ifdef MG_TEST_ABORT_ON_FAIL #define MG_TEST_ABORT abort() @@ -48,7 +49,7 @@ void _strfail(const char *a, const char *e, int len); #define ASSERT(expr) \ do { \ - g_num_tests++; \ + g_num_checks++; \ if (!(expr)) FAIL(#expr, __LINE__); \ } while (0) #define ASSERT_TRUE(expr) ASSERT(expr) @@ -71,6 +72,7 @@ void _strfail(const char *a, const char *e, int len); elapsed = cs_time() - elapsed; \ printf(" [%.3f] %s\n", elapsed, test_name); \ fflush(stdout); \ + g_num_tests++; \ } \ if (msg) return msg; \ } while (0) @@ -88,7 +90,7 @@ void _strfail(const char *a, const char *e, int len); */ #define ASSERT_EQ(actual, expected) \ do { \ - g_num_tests++; \ + g_num_checks++; \ if (!((actual) == (expected))) { \ printf("%f != %f\n", AS_DOUBLE(actual), AS_DOUBLE(expected)); \ FAIL(#actual " == " #expected, __LINE__); \ @@ -98,7 +100,7 @@ void _strfail(const char *a, const char *e, int len); /* "Less than" assertion. */ #define ASSERT_LT(a, b) \ do { \ - g_num_tests++; \ + g_num_checks++; \ if (!((a) < (b))) { \ printf("%f >= %f\n", AS_DOUBLE(a), AS_DOUBLE(b)); \ FAIL(#a " < " #b, __LINE__); \ @@ -108,7 +110,7 @@ void _strfail(const char *a, const char *e, int len); /* "Greater than" assertion. */ #define ASSERT_GT(a, b) \ do { \ - g_num_tests++; \ + g_num_checks++; \ if (!((a) > (b))) { \ printf("%f <= %f\n", AS_DOUBLE(a), AS_DOUBLE(b)); \ FAIL(#a " > " #b, __LINE__); \ @@ -118,7 +120,7 @@ void _strfail(const char *a, const char *e, int len); /* Assert that actual == expected, where both are NUL-terminated. */ #define ASSERT_STREQ(actual, expected) \ do { \ - g_num_tests++; \ + g_num_checks++; \ if (!_assert_streq(actual, expected)) { \ FAIL("ASSERT_STREQ(" #actual ", " #expected ")", __LINE__); \ } \ @@ -127,7 +129,7 @@ void _strfail(const char *a, const char *e, int len); /* Assert that actual == expected, where both are pointers */ #define ASSERT_PTREQ(actual, expected) \ do { \ - g_num_tests++; \ + g_num_checks++; \ if (actual != expected) { \ printf("%p != %p\n", actual, expected); \ FAIL("ASSERT_PTREQ(" #actual ", " #expected ")", __LINE__); \ @@ -137,7 +139,7 @@ void _strfail(const char *a, const char *e, int len); /* Assert that actual != expected, where both are pointers */ #define ASSERT_PTRNEQ(actual, expected) \ do { \ - g_num_tests++; \ + g_num_checks++; \ if (actual == expected) { \ printf("%p == %p\n", actual, expected); \ FAIL("ASSERT_PTRNEQ(" #actual ", " #expected ")", __LINE__); \ @@ -147,7 +149,7 @@ void _strfail(const char *a, const char *e, int len); /* Same as STREQ, but only expected is NUL-terminated. */ #define ASSERT_STREQ_NZ(actual, expected) \ do { \ - g_num_tests++; \ + g_num_checks++; \ if (!_assert_streq_nz(actual, expected)) { \ FAIL("ASSERT_STREQ_NZ(" #actual ", " #expected ")", __LINE__); \ } \ @@ -155,7 +157,7 @@ void _strfail(const char *a, const char *e, int len); #define ASSERT_MG_STREQ(actual, expected) \ do { \ - g_num_tests++; \ + g_num_checks++; \ if ((actual).len != strlen(expected) || \ memcmp((actual).p, expected, (actual).len) != 0) { \ printf("'%.*s' (%d) != '%s'\n", (int)(actual).len, (actual).p, \ From a3c4a48ef7e9299b198ad403a9a78ae56adc144c Mon Sep 17 00:00:00 2001 From: Deomid Ryabkov Date: Sat, 10 Feb 2018 10:53:33 +0000 Subject: [PATCH 02/41] Make sure test assertions are evaluated once E.g. if `ASSERT_EQ(myfunc(), 123)` fails, `myfunc()` would be invoked again to print the actual value. This can cause confusion sometimes. To avoid this, we cast arguments to double, which is wide enough for most cases and we provide a variant for 64 bit value types for when it's not. We also perform a check and fail if argument to the check results in loss of precision. CL: none PUBLISHED_FROM=a14551289d92e8a5dead21d16471ebddebe938a8 --- src/common/test_util.h | 128 +++++++++++++++++++++++++++++------------ test/unit_test.c | 6 +- 2 files changed, 95 insertions(+), 39 deletions(-) diff --git a/src/common/test_util.h b/src/common/test_util.h index fbc0eae3..60618f10 100644 --- a/src/common/test_util.h +++ b/src/common/test_util.h @@ -77,51 +77,103 @@ void _strfail(const char *a, const char *e, int len); if (msg) return msg; \ } while (0) -/* VC6 doesn't know how to cast an unsigned 64-bit int to double */ +/* VC6 doesn't have long long. */ #if (defined(_MSC_VER) && _MSC_VER <= 1200) -#define AS_DOUBLE(d) (double)(int64_t)(d) +#define LONG_TYPE int64_t #else -#define AS_DOUBLE(d) (double)(d) +#define LONG_TYPE long long #endif +#define AS_DOUBLE(d) (double)(d) + +#define RANGE_CHECK(x) (fabs(x) > 4503599627370496.0 /* 2 << 51 */) /* - * Numeric equality assertion. Comparison is made in native types but for - * printing both are convetrted to double. + * Numeric equality assertion. + * Args are cast to double to ensure aruemnts are only evaluated once. + * This will work fine for all integer types except large 64-bit values. */ -#define ASSERT_EQ(actual, expected) \ - do { \ - g_num_checks++; \ - if (!((actual) == (expected))) { \ - printf("%f != %f\n", AS_DOUBLE(actual), AS_DOUBLE(expected)); \ - FAIL(#actual " == " #expected, __LINE__); \ - } \ +#define ASSERT_EQ(actual, expected) \ + do { \ + const double ad = AS_DOUBLE(actual); \ + const double ed = AS_DOUBLE(expected); \ + if (RANGE_CHECK(ad) || RANGE_CHECK(ed)) { \ + FAIL("loss of precision, use ASSERT_EQ64", __LINE__); \ + } \ + g_num_checks++; \ + if (!(ad == ed)) { \ + printf("%lf != %lf\n", ad, ed); \ + FAIL(#actual " != " #expected, __LINE__); \ + } \ + } while (0) + +#define ASSERT_EQ64(actual, expected) \ + do { \ + const LONG_TYPE a64 = (LONG_TYPE)(actual); \ + const LONG_TYPE e64 = (LONG_TYPE)(expected); \ + g_num_checks++; \ + if (!(a64 == e64)) { \ + printf("%lld != %lld\n", a64, e64); \ + FAIL(#actual " != " #expected, __LINE__); \ + } \ + } while (0) + +#define ASSERT_NE(actual, expected) \ + do { \ + const double ad = AS_DOUBLE(actual); \ + const double ed = AS_DOUBLE(expected); \ + g_num_checks++; \ + if (RANGE_CHECK(ad) || RANGE_CHECK(ed)) { \ + FAIL("loss of precision, use ASSERT_NE64", __LINE__); \ + } \ + if (!(ad != ed)) { \ + printf("%lf == %lf\n", ad, ed); \ + FAIL(#actual " == " #expected, __LINE__); \ + } \ + } while (0) + +#define ASSERT_NE64(actual, expected) \ + do { \ + const LONG_TYPE a64 = (LONG_TYPE)(actual); \ + const LONG_TYPE e64 = (LONG_TYPE)(expected); \ + g_num_checks++; \ + if (!(a64 != e64)) { \ + printf("%lld == %lld\n", a64, e64); \ + FAIL(#actual " == " #expected, __LINE__); \ + } \ } while (0) /* "Less than" assertion. */ -#define ASSERT_LT(a, b) \ - do { \ - g_num_checks++; \ - if (!((a) < (b))) { \ - printf("%f >= %f\n", AS_DOUBLE(a), AS_DOUBLE(b)); \ - FAIL(#a " < " #b, __LINE__); \ - } \ +#define ASSERT_LT(a, b) \ + do { \ + const double ad = AS_DOUBLE(a); \ + const double bd = AS_DOUBLE(b); \ + g_num_checks++; \ + if (RANGE_CHECK(ad) || RANGE_CHECK(bd)) { \ + FAIL("loss of precision in comparison", __LINE__); \ + } \ + if (!(ad < bd)) { \ + printf("%lf >= %lf\n", ad, bd); \ + FAIL(#a " < " #b, __LINE__); \ + } \ } while (0) /* "Greater than" assertion. */ -#define ASSERT_GT(a, b) \ - do { \ - g_num_checks++; \ - if (!((a) > (b))) { \ - printf("%f <= %f\n", AS_DOUBLE(a), AS_DOUBLE(b)); \ - FAIL(#a " > " #b, __LINE__); \ - } \ +#define ASSERT_GT(a, b) \ + do { \ + const double ad = AS_DOUBLE(a); \ + const double bd = AS_DOUBLE(b); \ + g_num_checks++; \ + if (!(ad > bd)) { \ + printf("%lf <= %lf\n", ad, bd); \ + FAIL(#a " > " #b, __LINE__); \ + } \ } while (0) /* Assert that actual == expected, where both are NUL-terminated. */ #define ASSERT_STREQ(actual, expected) \ do { \ g_num_checks++; \ - if (!_assert_streq(actual, expected)) { \ + if (!_assert_streq((actual), (expected))) { \ FAIL("ASSERT_STREQ(" #actual ", " #expected ")", __LINE__); \ } \ } while (0) @@ -129,21 +181,25 @@ void _strfail(const char *a, const char *e, int len); /* Assert that actual == expected, where both are pointers */ #define ASSERT_PTREQ(actual, expected) \ do { \ + const void *ap = (const void *) (actual); \ + const void *ep = (const void *) (expected); \ g_num_checks++; \ - if (actual != expected) { \ - printf("%p != %p\n", actual, expected); \ + if (!(ap == ep)) { \ + printf("%p != %p\n", ap, ep); \ FAIL("ASSERT_PTREQ(" #actual ", " #expected ")", __LINE__); \ } \ } while (0) /* Assert that actual != expected, where both are pointers */ -#define ASSERT_PTRNEQ(actual, expected) \ - do { \ - g_num_checks++; \ - if (actual == expected) { \ - printf("%p == %p\n", actual, expected); \ - FAIL("ASSERT_PTRNEQ(" #actual ", " #expected ")", __LINE__); \ - } \ +#define ASSERT_PTRNE(actual, expected) \ + do { \ + const void *ap = (const void *) (actual); \ + const void *ep = (const void *) (expected); \ + g_num_checks++; \ + if (!(ap != ep)) { \ + printf("%p == %p\n", ap, ep); \ + FAIL("ASSERT_PTRNE(" #actual ", " #expected ")", __LINE__); \ + } \ } while (0) /* Same as STREQ, but only expected is NUL-terminated. */ diff --git a/test/unit_test.c b/test/unit_test.c index ff080c58..d9cee8a3 100644 --- a/test/unit_test.c +++ b/test/unit_test.c @@ -1533,7 +1533,7 @@ static const char *test_parse_http_message(void) { ASSERT_EQ(mg_vcmp(&req.query_string, "a=b&c=d"), 0); ASSERT_EQ(mg_parse_http(f, strlen(f), &req, 1), (int) strlen(f)); - ASSERT_EQ(req.body.len, (size_t) ~0); + ASSERT_EQ64(req.body.len, (size_t) ~0); ASSERT_EQ(mg_parse_http(g, strlen(g), &req, 1), (int) strlen(g)); ASSERT_EQ(req.body.len, 0); @@ -1542,7 +1542,7 @@ static const char *test_parse_http_message(void) { ASSERT_EQ(mg_vcmp(&req.proto, "HTTP/1.0"), 0); ASSERT_EQ(req.resp_code, 200); ASSERT_EQ(mg_vcmp(&req.resp_status_msg, "OK"), 0); - ASSERT_EQ(req.body.len, (size_t) ~0); + ASSERT_EQ64(req.body.len, (size_t) ~0); ASSERT_EQ(mg_parse_http(i, strlen(i), &req, 0), -1); @@ -3921,7 +3921,7 @@ static const char *test_http_chunk2(void) { strcat(buf, "3\r\n...\r\na\r\n0123456789\r\n0\r"); ASSERT_EQ(mg_handle_chunked(&nc, &hm, buf, strlen(buf)), 13); ASSERT_STREQ(buf, "...01234567890\r"); - ASSERT_EQ(hm.message.len, (size_t) ~0); + ASSERT_EQ64(hm.message.len, (size_t) ~0); strcat(buf, "\n\r\n"); ASSERT_EQ(mg_handle_chunked(&nc, &hm, buf, strlen(buf)), 13); From ad8f1d88d40ce878383fcbfc826adb2fdd2d3f78 Mon Sep 17 00:00:00 2001 From: Deomid Ryabkov Date: Tue, 13 Feb 2018 11:10:07 +0000 Subject: [PATCH 03/41] Fix buffer size passed to inet_ntop() Fixes https://github.com/cesanta/mongoose-os/issues/394 CL: Fix buffer size passed to inet_ntop() PUBLISHED_FROM=4a6702527627ccbb780f45200274b09a28be69ee --- mongoose.c | 2 +- src/mg_util.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/mongoose.c b/mongoose.c index 141e5017..14a9218f 100644 --- a/mongoose.c +++ b/mongoose.c @@ -10093,7 +10093,7 @@ int mg_sock_addr_to_str(const union socket_address *sa, char *buf, size_t len, goto cleanup; } #else - if (inet_ntop(AF_INET, (void *) &sa->sin.sin_addr, buf, len - 1) == NULL) { + if (inet_ntop(AF_INET, (void *) &sa->sin.sin_addr, buf, len) == NULL) { goto cleanup; } #endif diff --git a/src/mg_util.c b/src/mg_util.c index 485ba276..95246a8d 100644 --- a/src/mg_util.c +++ b/src/mg_util.c @@ -144,7 +144,7 @@ int mg_sock_addr_to_str(const union socket_address *sa, char *buf, size_t len, goto cleanup; } #else - if (inet_ntop(AF_INET, (void *) &sa->sin.sin_addr, buf, len - 1) == NULL) { + if (inet_ntop(AF_INET, (void *) &sa->sin.sin_addr, buf, len) == NULL) { goto cleanup; } #endif From 780077d1187ff632bdcbf33d65207a084027aba9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=91=D0=BE=D0=B1=D0=B1=D0=B8?= Date: Sun, 18 Feb 2018 16:34:48 +0000 Subject: [PATCH 04/41] Fix mg_socketpair for lwip + UDP CL: Fix mg_socketpair for lwip + UDP PUBLISHED_FROM=6dd09136b3837016026523fb34acb5cc893cadbe --- mongoose.c | 12 +++++++----- mongoose.h | 4 ++-- src/mg_http_server.h | 4 ++-- src/mg_net_if_socket.c | 12 +++++++----- 4 files changed, 18 insertions(+), 14 deletions(-) diff --git a/mongoose.c b/mongoose.c index 14a9218f..4deea5c4 100644 --- a/mongoose.c +++ b/mongoose.c @@ -3910,7 +3910,7 @@ mg_socketpair_accept(sock_t sock, union socket_address *sa, socklen_t sa_len) { } int mg_socketpair(sock_t sp[2], int sock_type) { - union socket_address sa; + union socket_address sa, sa2; sock_t sock; socklen_t len = sizeof(sa.sin); int ret = 0; @@ -3919,18 +3919,20 @@ int mg_socketpair(sock_t sp[2], int sock_type) { (void) memset(&sa, 0, sizeof(sa)); sa.sin.sin_family = AF_INET; - sa.sin.sin_port = htons(0); sa.sin.sin_addr.s_addr = htonl(0x7f000001); /* 127.0.0.1 */ + sa2 = sa; if ((sock = socket(AF_INET, sock_type, 0)) == INVALID_SOCKET) { } else if (bind(sock, &sa.sa, len) != 0) { } else if (sock_type == SOCK_STREAM && listen(sock, 1) != 0) { } else if (getsockname(sock, &sa.sa, &len) != 0) { } else if ((sp[0] = socket(AF_INET, sock_type, 0)) == INVALID_SOCKET) { - } else if (connect(sp[0], &sa.sa, len) != 0) { + } else if (sock_type == SOCK_STREAM && connect(sp[0], &sa.sa, len) != 0) { } else if (sock_type == SOCK_DGRAM && - (getsockname(sp[0], &sa.sa, &len) != 0 || - connect(sock, &sa.sa, len) != 0)) { + (bind(sp[0], &sa2.sa, len) != 0 || + getsockname(sp[0], &sa2.sa, &len) != 0 || + connect(sp[0], &sa.sa, len) != 0 || + connect(sock, &sa2.sa, len) != 0)) { } else if ((sp[1] = (sock_type == SOCK_DGRAM ? sock : mg_socketpair_accept( sock, &sa, len))) == INVALID_SOCKET) { diff --git a/mongoose.h b/mongoose.h index eecbbeff..f8030d52 100644 --- a/mongoose.h +++ b/mongoose.h @@ -4680,9 +4680,9 @@ int mg_http_parse_header2(struct mg_str *hdr, const char *var_name, char **buf, int mg_http_parse_header(struct mg_str *hdr, const char *var_name, char *buf, size_t buf_size) #ifdef __GNUC__ - __attribute__((deprecated)); + __attribute__((deprecated)) #endif -; + ; /* * Gets and parses the Authorization: Basic header diff --git a/src/mg_http_server.h b/src/mg_http_server.h index c4dfee4d..eacc5721 100644 --- a/src/mg_http_server.h +++ b/src/mg_http_server.h @@ -64,9 +64,9 @@ int mg_http_parse_header2(struct mg_str *hdr, const char *var_name, char **buf, int mg_http_parse_header(struct mg_str *hdr, const char *var_name, char *buf, size_t buf_size) #ifdef __GNUC__ - __attribute__((deprecated)); + __attribute__((deprecated)) #endif -; + ; /* * Gets and parses the Authorization: Basic header diff --git a/src/mg_net_if_socket.c b/src/mg_net_if_socket.c index 0d15764c..c13c300a 100644 --- a/src/mg_net_if_socket.c +++ b/src/mg_net_if_socket.c @@ -652,7 +652,7 @@ mg_socketpair_accept(sock_t sock, union socket_address *sa, socklen_t sa_len) { } int mg_socketpair(sock_t sp[2], int sock_type) { - union socket_address sa; + union socket_address sa, sa2; sock_t sock; socklen_t len = sizeof(sa.sin); int ret = 0; @@ -661,18 +661,20 @@ int mg_socketpair(sock_t sp[2], int sock_type) { (void) memset(&sa, 0, sizeof(sa)); sa.sin.sin_family = AF_INET; - sa.sin.sin_port = htons(0); sa.sin.sin_addr.s_addr = htonl(0x7f000001); /* 127.0.0.1 */ + sa2 = sa; if ((sock = socket(AF_INET, sock_type, 0)) == INVALID_SOCKET) { } else if (bind(sock, &sa.sa, len) != 0) { } else if (sock_type == SOCK_STREAM && listen(sock, 1) != 0) { } else if (getsockname(sock, &sa.sa, &len) != 0) { } else if ((sp[0] = socket(AF_INET, sock_type, 0)) == INVALID_SOCKET) { - } else if (connect(sp[0], &sa.sa, len) != 0) { + } else if (sock_type == SOCK_STREAM && connect(sp[0], &sa.sa, len) != 0) { } else if (sock_type == SOCK_DGRAM && - (getsockname(sp[0], &sa.sa, &len) != 0 || - connect(sock, &sa.sa, len) != 0)) { + (bind(sp[0], &sa2.sa, len) != 0 || + getsockname(sp[0], &sa2.sa, &len) != 0 || + connect(sp[0], &sa.sa, len) != 0 || + connect(sock, &sa2.sa, len) != 0)) { } else if ((sp[1] = (sock_type == SOCK_DGRAM ? sock : mg_socketpair_accept( sock, &sa, len))) == INVALID_SOCKET) { From dab526936f8146b02bffae4f40b5536341a55472 Mon Sep 17 00:00:00 2001 From: Sergey Lyubka Date: Fri, 23 Feb 2018 09:55:57 +0000 Subject: [PATCH 05/41] Add missing test files to mongoose repo PUBLISHED_FROM=9a81cc34aa0039a75c851bc3685055f46936252e --- src/common/test_main.c | 71 ++++++++++++++++++++++++++++++++++++++++++ src/common/test_main.h | 22 +++++++++++++ 2 files changed, 93 insertions(+) create mode 100644 src/common/test_main.c create mode 100644 src/common/test_main.h diff --git a/src/common/test_main.c b/src/common/test_main.c new file mode 100644 index 00000000..53116d92 --- /dev/null +++ b/src/common/test_main.c @@ -0,0 +1,71 @@ +/* + * Copyright (c) 2014-2018 Cesanta Software Limited + * All rights reserved + */ + +#include "common/cs_dbg.h" +#include "common/test_main.h" +#include "common/test_util.h" + +#if defined(_MSC_VER) && _MSC_VER >= 1900 +#include + +int __cdecl CrtDbgHook(int nReportType, char *szMsg, int *pnRet) { + (void) nReportType; + (void) szMsg; + (void) pnRet; + + fprintf(stderr, "CRT debug hook: type: %d, msg: %s\n", nReportType, szMsg); + /* Return true - Abort,Retry,Ignore dialog will *not* be displayed */ + return 1; +} +#endif + +#ifndef __cdecl +#define __cdecl +#endif + +int g_num_tests = 0; +int g_num_checks = 0; +const char *g_argv_0 = NULL; + +int __cdecl main(int argc, char *argv[]) { + const char *fail_msg; + const char *filter = argc > 1 ? argv[1] : ""; + char *seed_str = getenv("TEST_SEED"); + double started; + int seed = 0; + + if (seed_str != NULL) { + seed = atoi(seed_str); + } else { + seed = (int) time(NULL); + } + printf("seed: %d\n", seed); + srand(seed); + + setvbuf(stdout, NULL, _IONBF, 0); + setvbuf(stderr, NULL, _IONBF, 0); +#if defined(_MSC_VER) && _MSC_VER >= 1900 + /* NOTE: not available on wine/vc6 */ + _CrtSetReportHook2(_CRT_RPTHOOK_INSTALL, CrtDbgHook); +#endif + + g_argv_0 = argv[0]; + + tests_setup(); + + started = cs_time(); + fail_msg = tests_run(filter); + printf("%s, ran %d tests (%d checks) in %.3lfs\n", fail_msg ? "FAIL" : "PASS", + g_num_tests, g_num_checks, cs_time() - started); + + tests_teardown(); + + if (fail_msg != NULL) { + /* Prevent leak analyzer from running: there will be "leaks" because of + * premature return from the test, and in this case we don't care. */ + _exit(EXIT_FAILURE); + } + return EXIT_SUCCESS; +} diff --git a/src/common/test_main.h b/src/common/test_main.h new file mode 100644 index 00000000..6b6f5f39 --- /dev/null +++ b/src/common/test_main.h @@ -0,0 +1,22 @@ +/* + * Copyright (c) 2014-2018 Cesanta Software Limited + * All rights reserved + */ + +#ifndef CS_COMMON_TEST_MAIN_H_ +#define CS_COMMON_TEST_MAIN_H_ + +#ifdef __cplusplus +extern "C" { +#endif + +void tests_setup(void); +const char *tests_run(const char *filter); +void tests_teardown(void); +extern const char *g_argv_0; + +#ifdef __cplusplus +} +#endif + +#endif /* CS_COMMON_TEST_MAIN_H_ */ From 0ae2b82b600e44a4c2e44663ad247d25d499562a Mon Sep 17 00:00:00 2001 From: "Serge A. Zaitsev" Date: Fri, 23 Feb 2018 11:34:23 +0100 Subject: [PATCH 06/41] freshen: early attempts to make ota and config work freshen: implement ota rollback freshen: api for rpc freshen: implement rpc api (without transport) PUBLISHED_FROM=9f935f676161c81464a0dc53d5d8d085b2437ffb --- mongoose.c | 6 ++++++ src/mg_ssl_if_mbedtls.c | 6 ++++++ 2 files changed, 12 insertions(+) diff --git a/mongoose.c b/mongoose.c index 4deea5c4..25b57260 100644 --- a/mongoose.c +++ b/mongoose.c @@ -4688,9 +4688,11 @@ static enum mg_ssl_if_result mg_use_ca_cert(struct mg_ssl_if_ctx *ctx, const char *cert); static enum mg_ssl_if_result mg_set_cipher_list(struct mg_ssl_if_ctx *ctx, const char *ciphers); +#ifdef MBEDTLS_KEY_EXCHANGE__SOME__PSK_ENABLED static enum mg_ssl_if_result mg_ssl_if_mbed_set_psk(struct mg_ssl_if_ctx *ctx, const char *identity, const char *key); +#endif enum mg_ssl_if_result mg_ssl_if_conn_init( struct mg_connection *nc, const struct mg_ssl_if_conn_params *params, @@ -4739,11 +4741,13 @@ enum mg_ssl_if_result mg_ssl_if_conn_init( return MG_SSL_ERROR; } +#ifdef MBEDTLS_KEY_EXCHANGE__SOME__PSK_ENABLED if (mg_ssl_if_mbed_set_psk(ctx, params->psk_identity, params->psk_key) != MG_SSL_OK) { MG_SET_PTRPTR(err_msg, "Invalid PSK settings"); return MG_SSL_ERROR; } +#endif if (!(nc->flags & MG_F_LISTENING)) { ctx->ssl = (mbedtls_ssl_context *) MG_CALLOC(1, sizeof(*ctx->ssl)); @@ -5037,6 +5041,7 @@ static enum mg_ssl_if_result mg_set_cipher_list(struct mg_ssl_if_ctx *ctx, return MG_SSL_OK; } +#ifdef MBEDTLS_KEY_EXCHANGE__SOME__PSK_ENABLED static enum mg_ssl_if_result mg_ssl_if_mbed_set_psk(struct mg_ssl_if_ctx *ctx, const char *identity, const char *key_str) { @@ -5073,6 +5078,7 @@ static enum mg_ssl_if_result mg_ssl_if_mbed_set_psk(struct mg_ssl_if_ctx *ctx, } return MG_SSL_OK; } +#endif const char *mg_set_ssl(struct mg_connection *nc, const char *cert, const char *ca_cert) { diff --git a/src/mg_ssl_if_mbedtls.c b/src/mg_ssl_if_mbedtls.c index 4c1c1db1..9bf07fa9 100644 --- a/src/mg_ssl_if_mbedtls.c +++ b/src/mg_ssl_if_mbedtls.c @@ -67,9 +67,11 @@ static enum mg_ssl_if_result mg_use_ca_cert(struct mg_ssl_if_ctx *ctx, const char *cert); static enum mg_ssl_if_result mg_set_cipher_list(struct mg_ssl_if_ctx *ctx, const char *ciphers); +#ifdef MBEDTLS_KEY_EXCHANGE__SOME__PSK_ENABLED static enum mg_ssl_if_result mg_ssl_if_mbed_set_psk(struct mg_ssl_if_ctx *ctx, const char *identity, const char *key); +#endif enum mg_ssl_if_result mg_ssl_if_conn_init( struct mg_connection *nc, const struct mg_ssl_if_conn_params *params, @@ -118,11 +120,13 @@ enum mg_ssl_if_result mg_ssl_if_conn_init( return MG_SSL_ERROR; } +#ifdef MBEDTLS_KEY_EXCHANGE__SOME__PSK_ENABLED if (mg_ssl_if_mbed_set_psk(ctx, params->psk_identity, params->psk_key) != MG_SSL_OK) { MG_SET_PTRPTR(err_msg, "Invalid PSK settings"); return MG_SSL_ERROR; } +#endif if (!(nc->flags & MG_F_LISTENING)) { ctx->ssl = (mbedtls_ssl_context *) MG_CALLOC(1, sizeof(*ctx->ssl)); @@ -416,6 +420,7 @@ static enum mg_ssl_if_result mg_set_cipher_list(struct mg_ssl_if_ctx *ctx, return MG_SSL_OK; } +#ifdef MBEDTLS_KEY_EXCHANGE__SOME__PSK_ENABLED static enum mg_ssl_if_result mg_ssl_if_mbed_set_psk(struct mg_ssl_if_ctx *ctx, const char *identity, const char *key_str) { @@ -452,6 +457,7 @@ static enum mg_ssl_if_result mg_ssl_if_mbed_set_psk(struct mg_ssl_if_ctx *ctx, } return MG_SSL_OK; } +#endif const char *mg_set_ssl(struct mg_connection *nc, const char *cert, const char *ca_cert) { From 6523cc4da04d224aa7bf72173ec8aedd99af5168 Mon Sep 17 00:00:00 2001 From: novlean Date: Mon, 12 Mar 2018 21:15:14 +0000 Subject: [PATCH 07/41] 2018 PUBLISHED_FROM=63ce52177f5f13cb76f0fcb4689efb65a04318a2 --- LICENSE | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/LICENSE b/LICENSE index 9d5778c9..eb38b7a7 100644 --- a/LICENSE +++ b/LICENSE @@ -1,5 +1,5 @@ Copyright (c) 2004-2013 Sergey Lyubka -Copyright (c) 2013-2016 Cesanta Software Limited +Copyright (c) 2013-2018 Cesanta Software Limited All rights reserved This software is dual-licensed: you can redistribute it and/or modify From 127f27e37508e0471eee1acdcd55aa86c9162109 Mon Sep 17 00:00:00 2001 From: "Serge A. Zaitsev" Date: Tue, 13 Mar 2018 20:05:42 +0200 Subject: [PATCH 08/41] mongoose: unit test for http get pipeline PUBLISHED_FROM=00e8634913232eb2e50a0d739f85e81706dbc400 --- test/unit_test.c | 39 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 39 insertions(+) diff --git a/test/unit_test.c b/test/unit_test.c index d9cee8a3..7f587a70 100644 --- a/test/unit_test.c +++ b/test/unit_test.c @@ -2051,6 +2051,44 @@ static const char *test_http(void) { return NULL; } +static void http_pipeline_handler(struct mg_connection *c, int ev, + void *ev_data) { + (void) ev_data; + int *status = (int *) c->mgr->user_data; + if (ev == MG_EV_HTTP_REQUEST) { + /* Server request handler */ + mg_send_response_line(c, 200, "Content-Type: text/plain\r\n"); + mg_printf(c, "Hello"); + c->flags |= MG_F_SEND_AND_CLOSE; + *status = *status + 1; + } else if (ev == MG_EV_HTTP_REPLY) { + /* Client reply handler */ + *status = *status + 10; + c->flags |= MG_F_CLOSE_IMMEDIATELY; + } +} + +static const char *test_http_pipeline(void) { + struct mg_mgr mgr; + struct mg_connection *lc, *nc1, *nc2; + const char *local_addr = "127.0.0.1:7777"; + int status = 0; + + mg_mgr_init(&mgr, (void *) &status); + ASSERT(lc = mg_bind(&mgr, local_addr, http_pipeline_handler)); + mg_set_protocol_http_websocket(lc); + ASSERT(nc1 = mg_connect(&mgr, local_addr, http_pipeline_handler)); + mg_set_protocol_http_websocket(nc1); + mg_printf(nc1, "GET / HTTP/1.1\r\n\r\n"); + ASSERT(nc2 = mg_connect(&mgr, local_addr, http_pipeline_handler)); + mg_set_protocol_http_websocket(nc2); + mg_printf(nc2, "GET / HTTP/1.1\r\n\r\n"); + poll_until(&mgr, 1, c_int_eq, &status, (void *) 22); + ASSERT_EQ(status, 22); + mg_mgr_free(&mgr); + return NULL; +} + static const char *test_http_send_redirect(void) { struct mg_connection nc; init_test_connection(&nc); @@ -5461,6 +5499,7 @@ const char *tests_run(const char *filter) { RUN_TEST(test_http_serve_file); RUN_TEST(test_http_serve_file_streaming); RUN_TEST(test_http); + RUN_TEST(test_http_pipeline); RUN_TEST(test_http_send_redirect); RUN_TEST(test_http_digest_auth); RUN_TEST(test_http_errors); From d16dbc197ff6a07bc8cca4e095029cda95786f10 Mon Sep 17 00:00:00 2001 From: "Serge A. Zaitsev" Date: Tue, 20 Mar 2018 10:33:05 +0200 Subject: [PATCH 09/41] mongoose: fix http pipeline mongoose: fix formatting mongoose: fix formatting mongoose: remove debugging messages PUBLISHED_FROM=1194e018001cc5f2b598096593d7aac4ec8dc04d --- mongoose.c | 6 +++++- src/mg_http.c | 6 +++++- test/unit_test.c | 12 ++++-------- 3 files changed, 14 insertions(+), 10 deletions(-) diff --git a/mongoose.c b/mongoose.c index 25b57260..8e7bd8b2 100644 --- a/mongoose.c +++ b/mongoose.c @@ -6159,6 +6159,7 @@ void mg_http_handler(struct mg_connection *nc, int ev, } #endif /* MG_ENABLE_HTTP_STREAMING_MULTIPART */ + again: req_len = mg_parse_http(io->buf, io->len, hm, is_req); if (req_len > 0 && @@ -6252,7 +6253,10 @@ void mg_http_handler(struct mg_connection *nc, int ev, /* Whole HTTP message is fully buffered, call event handler */ mg_http_call_endpoint_handler(nc, trigger_ev, hm); mbuf_remove(io, hm->message.len); - pd->rcvd = 0; + pd->rcvd -= hm->message.len; + if (io->len > 0) { + goto again; + } } } } diff --git a/src/mg_http.c b/src/mg_http.c index 068d2083..402b8d3b 100644 --- a/src/mg_http.c +++ b/src/mg_http.c @@ -787,6 +787,7 @@ void mg_http_handler(struct mg_connection *nc, int ev, } #endif /* MG_ENABLE_HTTP_STREAMING_MULTIPART */ + again: req_len = mg_parse_http(io->buf, io->len, hm, is_req); if (req_len > 0 && @@ -880,7 +881,10 @@ void mg_http_handler(struct mg_connection *nc, int ev, /* Whole HTTP message is fully buffered, call event handler */ mg_http_call_endpoint_handler(nc, trigger_ev, hm); mbuf_remove(io, hm->message.len); - pd->rcvd = 0; + pd->rcvd -= hm->message.len; + if (io->len > 0) { + goto again; + } } } } diff --git a/test/unit_test.c b/test/unit_test.c index 7f587a70..b6f95989 100644 --- a/test/unit_test.c +++ b/test/unit_test.c @@ -2057,20 +2057,19 @@ static void http_pipeline_handler(struct mg_connection *c, int ev, int *status = (int *) c->mgr->user_data; if (ev == MG_EV_HTTP_REQUEST) { /* Server request handler */ - mg_send_response_line(c, 200, "Content-Type: text/plain\r\n"); + mg_send_response_line(c, 200, + "Content-Type: text/plain\r\nContent-Length: 5\r\n"); mg_printf(c, "Hello"); - c->flags |= MG_F_SEND_AND_CLOSE; *status = *status + 1; } else if (ev == MG_EV_HTTP_REPLY) { /* Client reply handler */ *status = *status + 10; - c->flags |= MG_F_CLOSE_IMMEDIATELY; } } static const char *test_http_pipeline(void) { struct mg_mgr mgr; - struct mg_connection *lc, *nc1, *nc2; + struct mg_connection *lc, *nc1; const char *local_addr = "127.0.0.1:7777"; int status = 0; @@ -2079,10 +2078,7 @@ static const char *test_http_pipeline(void) { mg_set_protocol_http_websocket(lc); ASSERT(nc1 = mg_connect(&mgr, local_addr, http_pipeline_handler)); mg_set_protocol_http_websocket(nc1); - mg_printf(nc1, "GET / HTTP/1.1\r\n\r\n"); - ASSERT(nc2 = mg_connect(&mgr, local_addr, http_pipeline_handler)); - mg_set_protocol_http_websocket(nc2); - mg_printf(nc2, "GET / HTTP/1.1\r\n\r\n"); + mg_printf(nc1, "GET / HTTP/1.1\r\n\r\nGET / HTTP/1.1\r\n\r\n"); poll_until(&mgr, 1, c_int_eq, &status, (void *) 22); ASSERT_EQ(status, 22); mg_mgr_free(&mgr); From 0a90cab44adb08857ca04962072e773cfa73ad8b Mon Sep 17 00:00:00 2001 From: Deomid Ryabkov Date: Wed, 21 Mar 2018 22:00:58 +0000 Subject: [PATCH 10/41] Improve mbuf allocation behavior * Limit total amount of headroom, in absolute terms (`MBUF_SIZE_MAX_HEADROOM`). * If unable to allocate with headroom, fall back to allocating the required minimum. * For mOS, set default `MBUF_SIZE_MULTIPLIER` to 2 to avoid floating point operations. Since max headroom size is now capped to 128 bytes, this will not result in much of a bloat. PUBLISHED_FROM=11d4fc65a46a805bb7c8960f89a3d0b753c58bb8 --- mongoose.c | 17 ++++++++++++++--- mongoose.h | 8 ++++++++ 2 files changed, 22 insertions(+), 3 deletions(-) diff --git a/mongoose.c b/mongoose.c index 8e7bd8b2..5140a0ac 100644 --- a/mongoose.c +++ b/mongoose.c @@ -1470,10 +1470,21 @@ size_t mbuf_insert(struct mbuf *a, size_t off, const void *buf, size_t len) { } a->len += len; } else { - size_t new_size = (size_t)((a->len + len) * MBUF_SIZE_MULTIPLIER); - if ((p = (char *) MBUF_REALLOC(a->buf, new_size)) != NULL) { + size_t min_size = (a->len + len); + size_t new_size = (size_t)(min_size * MBUF_SIZE_MULTIPLIER); + if (new_size - min_size > MBUF_SIZE_MAX_HEADROOM) { + new_size = min_size + MBUF_SIZE_MAX_HEADROOM; + } + p = (char *) MBUF_REALLOC(a->buf, new_size); + if (p == NULL && new_size != min_size) { + new_size = min_size; + p = (char *) MBUF_REALLOC(a->buf, new_size); + } + if (p != NULL) { a->buf = p; - memmove(a->buf + off + len, a->buf + off, a->len - off); + if (off != a->len) { + memmove(a->buf + off + len, a->buf + off, a->len - off); + } if (buf != NULL) memcpy(a->buf + off, buf, len); a->len += len; a->size = new_size; diff --git a/mongoose.h b/mongoose.h index f8030d52..c668594a 100644 --- a/mongoose.h +++ b/mongoose.h @@ -1963,6 +1963,14 @@ extern "C" { #define MBUF_SIZE_MULTIPLIER 1.5 #endif +#ifndef MBUF_SIZE_MAX_HEADROOM +#ifdef BUFSIZ +#define MBUF_SIZE_MAX_HEADROOM BUFSIZ +#else +#define MBUF_SIZE_MAX_HEADROOM 1024 +#endif +#endif + /* Memory buffer descriptor */ struct mbuf { char *buf; /* Buffer pointer */ From 132ecbec2f73e96d9c7691477f089fbe57477da8 Mon Sep 17 00:00:00 2001 From: Deomid Ryabkov Date: Wed, 28 Mar 2018 13:25:30 +0100 Subject: [PATCH 11/41] Fix Mongoose and Frozen include paths In preparation for making moving to lib. Reduce amount of makefile copypasta a bit. CL: none PUBLISHED_FROM=70a016491f9605e37708385bdd698f48a8d64119 --- src/common/platforms/esp8266/esp_crypto.c | 2 +- tools/amalgam.py | 9 ++++++--- 2 files changed, 7 insertions(+), 4 deletions(-) diff --git a/src/common/platforms/esp8266/esp_crypto.c b/src/common/platforms/esp8266/esp_crypto.c index 822dab19..3d2afa14 100644 --- a/src/common/platforms/esp8266/esp_crypto.c +++ b/src/common/platforms/esp8266/esp_crypto.c @@ -7,7 +7,7 @@ #include #include -#include "mongoose/mongoose.h" +#include "mongoose.h" #ifdef RTOS_SDK #include "esp_libc.h" diff --git a/tools/amalgam.py b/tools/amalgam.py index 3776d12a..f40ca7cd 100755 --- a/tools/amalgam.py +++ b/tools/amalgam.py @@ -57,7 +57,7 @@ parser.add_argument('--norel', action='store_true', help="do not try to compute a friendly relative path") parser.add_argument('--exportable-headers', dest="export", action='store_true', help='allow exporting internal headers') -parser.add_argument('-I', default=".", dest='include_path', help='include path') +parser.add_argument('-I', default=['.'], dest='include_path', help='include path', action='append') parser.add_argument('sources', nargs='*', help='sources') class File(object): @@ -97,10 +97,13 @@ def resolve(path, parent_name): elif path_from_parent != None and os.path.exists(path_from_parent): p = path_from_parent else: - p = os.path.join(args.include_path, path) + for ip in args.include_path: + p = os.path.join(ip, path) + if os.path.exists(p): + break if os.path.exists(p) and not args.norel: p = os.path.realpath(p).replace('%s%s' % (os.getcwd(), os.sep), '') - # print >>sys.stderr, '%s -> %s (cwd %s)' % (path, p, os.getcwd()) + # print >>sys.stderr, '%s %s -> %s (cwd %s)' % (path, parent_name, p, os.getcwd()) return p.replace(os.sep, '/') def emit_line_directive(out, name, parent_name): From c80f4c53139b286515d3ecd8fa1a41456d0865f0 Mon Sep 17 00:00:00 2001 From: Deomid Ryabkov Date: Fri, 30 Mar 2018 20:09:42 +0100 Subject: [PATCH 12/41] Fix an edge case in multipart HTTP upload parsing Consume buffer as soon as we know there is no boundary there, no need to delay until next chunk arrives. This prevents stall where buffer fills up in one go and next chunk never arrives. CL: Fix an edge case in multipart HTTP upload parsing PUBLISHED_FROM=025f9001d272df2a75ece22b199b1944d5db9840 --- mongoose.c | 36 +++++++----------------------------- src/mg_http.c | 36 +++++++----------------------------- 2 files changed, 14 insertions(+), 58 deletions(-) diff --git a/mongoose.c b/mongoose.c index 5140a0ac..1630eb36 100644 --- a/mongoose.c +++ b/mongoose.c @@ -5510,7 +5510,6 @@ enum mg_http_multipart_stream_state { MPS_BEGIN, MPS_WAITING_FOR_BOUNDARY, MPS_WAITING_FOR_CHUNK, - MPS_GOT_CHUNK, MPS_GOT_BOUNDARY, MPS_FINALIZE, MPS_FINISHED @@ -5522,7 +5521,6 @@ struct mg_http_multipart_stream { const char *var_name; const char *file_name; void *user_data; - int prev_io_len; enum mg_http_multipart_stream_state state; int processing_part; }; @@ -6358,19 +6356,6 @@ static void mg_http_multipart_call_handler(struct mg_connection *c, int ev, pd->mp_stream.user_data = mp.user_data; } -static int mg_http_multipart_got_chunk(struct mg_connection *c) { - struct mg_http_proto_data *pd = mg_http_get_proto_data(c); - struct mbuf *io = &c->recv_mbuf; - - mg_http_multipart_call_handler(c, MG_EV_HTTP_PART_DATA, io->buf, - pd->mp_stream.prev_io_len); - mbuf_remove(io, pd->mp_stream.prev_io_len); - pd->mp_stream.prev_io_len = 0; - pd->mp_stream.state = MPS_WAITING_FOR_CHUNK; - - return 0; -} - static int mg_http_multipart_finalize(struct mg_connection *c) { struct mg_http_proto_data *pd = mg_http_get_proto_data(c); @@ -6505,19 +6490,18 @@ static int mg_http_multipart_continue_wait_for_chunk(struct mg_connection *c) { } boundary = c_strnstr(io->buf, pd->mp_stream.boundary, io->len); - if (boundary == NULL && pd->mp_stream.prev_io_len == 0) { - pd->mp_stream.prev_io_len = io->len; + if (boundary == NULL) { + int data_size = (io->len - (pd->mp_stream.boundary_len + 6)); + if (data_size > 0) { + mg_http_multipart_call_handler(c, MG_EV_HTTP_PART_DATA, io->buf, + data_size); + mbuf_remove(io, data_size); + } return 0; - } else if (boundary == NULL && - (int) io->len > - pd->mp_stream.prev_io_len + pd->mp_stream.boundary_len + 4) { - pd->mp_stream.state = MPS_GOT_CHUNK; - return 1; } else if (boundary != NULL) { int data_size = (boundary - io->buf - 4); mg_http_multipart_call_handler(c, MG_EV_HTTP_PART_DATA, io->buf, data_size); mbuf_remove(io, (boundary - io->buf)); - pd->mp_stream.prev_io_len = 0; pd->mp_stream.state = MPS_WAITING_FOR_BOUNDARY; return 1; } else { @@ -6551,12 +6535,6 @@ static void mg_http_multipart_continue(struct mg_connection *c) { } break; } - case MPS_GOT_CHUNK: { - if (mg_http_multipart_got_chunk(c) == 0) { - return; - } - break; - } case MPS_FINALIZE: { if (mg_http_multipart_finalize(c) == 0) { return; diff --git a/src/mg_http.c b/src/mg_http.c index 402b8d3b..1fd27d2a 100644 --- a/src/mg_http.c +++ b/src/mg_http.c @@ -127,7 +127,6 @@ enum mg_http_multipart_stream_state { MPS_BEGIN, MPS_WAITING_FOR_BOUNDARY, MPS_WAITING_FOR_CHUNK, - MPS_GOT_CHUNK, MPS_GOT_BOUNDARY, MPS_FINALIZE, MPS_FINISHED @@ -139,7 +138,6 @@ struct mg_http_multipart_stream { const char *var_name; const char *file_name; void *user_data; - int prev_io_len; enum mg_http_multipart_stream_state state; int processing_part; }; @@ -975,19 +973,6 @@ static void mg_http_multipart_call_handler(struct mg_connection *c, int ev, pd->mp_stream.user_data = mp.user_data; } -static int mg_http_multipart_got_chunk(struct mg_connection *c) { - struct mg_http_proto_data *pd = mg_http_get_proto_data(c); - struct mbuf *io = &c->recv_mbuf; - - mg_http_multipart_call_handler(c, MG_EV_HTTP_PART_DATA, io->buf, - pd->mp_stream.prev_io_len); - mbuf_remove(io, pd->mp_stream.prev_io_len); - pd->mp_stream.prev_io_len = 0; - pd->mp_stream.state = MPS_WAITING_FOR_CHUNK; - - return 0; -} - static int mg_http_multipart_finalize(struct mg_connection *c) { struct mg_http_proto_data *pd = mg_http_get_proto_data(c); @@ -1122,19 +1107,18 @@ static int mg_http_multipart_continue_wait_for_chunk(struct mg_connection *c) { } boundary = c_strnstr(io->buf, pd->mp_stream.boundary, io->len); - if (boundary == NULL && pd->mp_stream.prev_io_len == 0) { - pd->mp_stream.prev_io_len = io->len; + if (boundary == NULL) { + int data_size = (io->len - (pd->mp_stream.boundary_len + 6)); + if (data_size > 0) { + mg_http_multipart_call_handler(c, MG_EV_HTTP_PART_DATA, io->buf, + data_size); + mbuf_remove(io, data_size); + } return 0; - } else if (boundary == NULL && - (int) io->len > - pd->mp_stream.prev_io_len + pd->mp_stream.boundary_len + 4) { - pd->mp_stream.state = MPS_GOT_CHUNK; - return 1; } else if (boundary != NULL) { int data_size = (boundary - io->buf - 4); mg_http_multipart_call_handler(c, MG_EV_HTTP_PART_DATA, io->buf, data_size); mbuf_remove(io, (boundary - io->buf)); - pd->mp_stream.prev_io_len = 0; pd->mp_stream.state = MPS_WAITING_FOR_BOUNDARY; return 1; } else { @@ -1168,12 +1152,6 @@ static void mg_http_multipart_continue(struct mg_connection *c) { } break; } - case MPS_GOT_CHUNK: { - if (mg_http_multipart_got_chunk(c) == 0) { - return; - } - break; - } case MPS_FINALIZE: { if (mg_http_multipart_finalize(c) == 0) { return; From 3e33e577079b4c44af15a53d5bbf2acfd723ac6a Mon Sep 17 00:00:00 2001 From: Deomid Ryabkov Date: Tue, 27 Mar 2018 00:25:18 +0100 Subject: [PATCH 13/41] Mongoose net_if and ssl_if refactoring A major cleanup, disentangling net_if and ssl_if. Pulled a lot of common logic into the core and reduced size of net_if implementations. CL: Mongoose net_if and ssl_if refactoring PUBLISHED_FROM=29bd4dcb264a1fd96b3dd164e2d880e1c2c0921e --- mongoose.c | 1653 ++++++++----------- mongoose.h | 25 +- src/common/platforms/lwip/mg_lwip_ev_mgr.c | 94 +- src/common/platforms/lwip/mg_lwip_net_if.c | 242 +-- src/common/platforms/lwip/mg_lwip_net_if.h | 4 +- src/common/platforms/lwip/mg_lwip_ssl_if.c | 197 --- src/common/platforms/platform_cc3220.h | 2 + src/common/platforms/simplelink/sl_net_if.c | 170 +- src/common/platforms/simplelink/sl_ssl_if.c | 112 +- src/mg_modules.mk | 1 - src/mg_net.c | 372 +++-- src/mg_net_if.h | 25 +- src/mg_net_if_socket.c | 259 +-- src/mg_net_if_socks.c | 102 +- src/mg_resolv.c | 10 +- src/mg_ssl_if_mbedtls.c | 88 +- test/unit_test.c | 9 +- 17 files changed, 1358 insertions(+), 2007 deletions(-) delete mode 100644 src/common/platforms/lwip/mg_lwip_ssl_if.c diff --git a/mongoose.c b/mongoose.c index 1630eb36..ce2ed4e6 100644 --- a/mongoose.c +++ b/mongoose.c @@ -2185,6 +2185,13 @@ size_t mg_match_prefix(const char *pattern, int pattern_len, const char *str) { #define MG_MAX_HOST_LEN 200 +#ifndef MG_TCP_IO_SIZE +#define MG_TCP_IO_SIZE 1460 +#endif +#ifndef MG_UDP_IO_SIZE +#define MG_UDP_IO_SIZE 1460 +#endif + #define MG_COPY_COMMON_CONNECTION_OPTIONS(dst, src) \ memcpy(dst, src, sizeof(*dst)); @@ -2225,8 +2232,6 @@ MG_INTERNAL void mg_remove_conn(struct mg_connection *conn) { MG_INTERNAL void mg_call(struct mg_connection *nc, mg_event_handler_t ev_handler, void *user_data, int ev, void *ev_data) { - static int nesting_level = 0; - nesting_level++; if (ev_handler == NULL) { /* * If protocol handler is specified, call it. Otherwise, call user-specified @@ -2235,7 +2240,7 @@ MG_INTERNAL void mg_call(struct mg_connection *nc, ev_handler = nc->proto_handler ? nc->proto_handler : nc->handler; } if (ev != MG_EV_POLL) { - DBG(("%p %s ev=%d ev_data=%p flags=%lu rmbl=%d smbl=%d", nc, + DBG(("%p %s ev=%d ev_data=%p flags=0x%lx rmbl=%d smbl=%d", nc, ev_handler == nc->handler ? "user" : "proto", ev, ev_data, nc->flags, (int) nc->recv_mbuf.len, (int) nc->send_mbuf.len)); } @@ -2248,33 +2253,24 @@ MG_INTERNAL void mg_call(struct mg_connection *nc, #endif if (ev_handler != NULL) { unsigned long flags_before = nc->flags; - size_t recv_mbuf_before = nc->recv_mbuf.len, recved; ev_handler(nc, ev, ev_data MG_UD_ARG(user_data)); - recved = (recv_mbuf_before - nc->recv_mbuf.len); /* Prevent user handler from fiddling with system flags. */ if (ev_handler == nc->handler && nc->flags != flags_before) { nc->flags = (flags_before & ~_MG_CALLBACK_MODIFIABLE_FLAGS_MASK) | (nc->flags & _MG_CALLBACK_MODIFIABLE_FLAGS_MASK); } - /* It's important to not double-count recved bytes, and since mg_call can be - * called recursively (e.g. proto_handler invokes user handler), we keep - * track of recursion and only report received bytes at the top level. */ - if (nesting_level == 1 && recved > 0 && !(nc->flags & MG_F_UDP)) { - nc->iface->vtable->recved(nc, recved); - } } if (ev != MG_EV_POLL) { - DBG(("%p after %s flags=%lu rmbl=%d smbl=%d", nc, + DBG(("%p after %s flags=0x%lx rmbl=%d smbl=%d", nc, ev_handler == nc->handler ? "user" : "proto", nc->flags, (int) nc->recv_mbuf.len, (int) nc->send_mbuf.len)); } - nesting_level--; #if !MG_ENABLE_CALLBACK_USERDATA (void) user_data; #endif } -void mg_if_timer(struct mg_connection *c, double now) { +MG_INTERNAL void mg_timer(struct mg_connection *c, double now) { if (c->ev_timer_time > 0 && now >= c->ev_timer_time) { double old_value = c->ev_timer_time; c->ev_timer_time = 0; @@ -2282,13 +2278,45 @@ void mg_if_timer(struct mg_connection *c, double now) { } } -void mg_if_poll(struct mg_connection *nc, time_t now) { - if (!(nc->flags & MG_F_SSL) || (nc->flags & MG_F_SSL_HANDSHAKE_DONE)) { - mg_call(nc, NULL, nc->user_data, MG_EV_POLL, &now); +MG_INTERNAL size_t recv_avail_size(struct mg_connection *conn, size_t max) { + size_t avail; + if (conn->recv_mbuf_limit < conn->recv_mbuf.len) return 0; + avail = conn->recv_mbuf_limit - conn->recv_mbuf.len; + return avail > max ? max : avail; +} + +static int mg_do_recv(struct mg_connection *nc); + +int mg_if_poll(struct mg_connection *nc, double now) { + if ((nc->flags & MG_F_CLOSE_IMMEDIATELY) || + (nc->send_mbuf.len == 0 && (nc->flags & MG_F_SEND_AND_CLOSE))) { + mg_close_conn(nc); + return 0; } +#if MG_ENABLE_SSL + if ((nc->flags & (MG_F_SSL | MG_F_LISTENING | MG_F_CONNECTING)) == MG_F_SSL) { + /* SSL library may have data to be delivered to the app in its buffers, + * drain them. */ + int recved = 0; + do { + if (nc->flags & (MG_F_WANT_READ | MG_F_WANT_WRITE)) break; + if (recv_avail_size(nc, MG_TCP_IO_SIZE) <= 0) break; + recved = mg_do_recv(nc); + } while (recved > 0); + } +#endif /* MG_ENABLE_SSL */ + mg_timer(nc, now); + { + time_t now_t = (time_t) now; + mg_call(nc, NULL, nc->user_data, MG_EV_POLL, &now_t); + } + return 1; } void mg_destroy_conn(struct mg_connection *conn, int destroy_if) { + if (conn->sock != INVALID_SOCKET) { /* Don't print timer-only conns */ + LOG(LL_DEBUG, ("%p 0x%lx %d", conn, conn->flags, destroy_if)); + } if (destroy_if) conn->iface->vtable->destroy_conn(conn); if (conn->proto_data != NULL && conn->proto_data_destructor != NULL) { conn->proto_data_destructor(conn->proto_data); @@ -2304,7 +2332,6 @@ void mg_destroy_conn(struct mg_connection *conn, int destroy_if) { } void mg_close_conn(struct mg_connection *conn) { - DBG(("%p %lu %d", conn, conn->flags, conn->sock)); #if MG_ENABLE_SSL if (conn->flags & MG_F_SSL_HANDSHAKE_DONE) { mg_ssl_if_conn_close_notify(conn); @@ -2341,15 +2368,6 @@ void mg_mgr_init_opt(struct mg_mgr *m, void *user_data, signal(SIGPIPE, SIG_IGN); #endif -#if MG_ENABLE_SSL - { - static int init_done; - if (!init_done) { - mg_ssl_if_init(); - init_done++; - } - } -#endif { int i; if (opts.num_ifaces == 0) { @@ -2372,6 +2390,15 @@ void mg_mgr_init_opt(struct mg_mgr *m, void *user_data, } DBG(("==================================")); DBG(("init mgr=%p", m)); +#if MG_ENABLE_SSL + { + static int init_done; + if (!init_done) { + mg_ssl_if_init(); + init_done++; + } + } +#endif } void mg_mgr_free(struct mg_mgr *m) { @@ -2614,6 +2641,37 @@ MG_INTERNAL int mg_parse_address(const char *str, union socket_address *sa, return port < 0xffffUL && (ch == '\0' || ch == ',' || isspace(ch)) ? len : -1; } +#if MG_ENABLE_SSL +MG_INTERNAL void mg_ssl_handshake(struct mg_connection *nc) { + int err = 0; + int server_side = (nc->listener != NULL); + enum mg_ssl_if_result res; + if (nc->flags & MG_F_SSL_HANDSHAKE_DONE) return; + res = mg_ssl_if_handshake(nc); + LOG(LL_DEBUG, ("%p %d res %d", nc, server_side, res)); + + if (res == MG_SSL_OK) { + nc->flags |= MG_F_SSL_HANDSHAKE_DONE; + nc->flags &= ~(MG_F_WANT_READ | MG_F_WANT_WRITE); + if (server_side) { + mg_call(nc, NULL, nc->user_data, MG_EV_ACCEPT, &nc->sa); + } else { + mg_call(nc, NULL, nc->user_data, MG_EV_CONNECT, &err); + } + } else if (res == MG_SSL_WANT_READ) { + nc->flags |= MG_F_WANT_READ; + } else if (res == MG_SSL_WANT_WRITE) { + nc->flags |= MG_F_WANT_WRITE; + } else { + if (!server_side) { + err = res; + mg_call(nc, NULL, nc->user_data, MG_EV_CONNECT, &err); + } + nc->flags |= MG_F_CLOSE_IMMEDIATELY; + } +} +#endif /* MG_ENABLE_SSL */ + struct mg_connection *mg_if_accept_new_conn(struct mg_connection *lc) { struct mg_add_sock_opts opts; struct mg_connection *nc; @@ -2627,95 +2685,125 @@ struct mg_connection *mg_if_accept_new_conn(struct mg_connection *lc) { nc->iface = lc->iface; if (lc->flags & MG_F_SSL) nc->flags |= MG_F_SSL; mg_add_conn(nc->mgr, nc); - DBG(("%p %p %d %d", lc, nc, nc->sock, (int) nc->flags)); + LOG(LL_DEBUG, ("%p %p %d %d", lc, nc, nc->sock, (int) nc->flags)); return nc; } void mg_if_accept_tcp_cb(struct mg_connection *nc, union socket_address *sa, size_t sa_len) { - (void) sa_len; + LOG(LL_DEBUG, ("%p %s://%s:%hu", nc, (nc->flags & MG_F_UDP ? "udp" : "tcp"), + inet_ntoa(sa->sin.sin_addr), ntohs(sa->sin.sin_port))); nc->sa = *sa; - mg_call(nc, NULL, nc->user_data, MG_EV_ACCEPT, &nc->sa); +#if MG_ENABLE_SSL + if (nc->listener->flags & MG_F_SSL) { + nc->flags |= MG_F_SSL; + if (mg_ssl_if_conn_accept(nc, nc->listener) == MG_SSL_OK) { + mg_ssl_handshake(nc); + } else { + mg_close_conn(nc); + } + } else +#endif + { + mg_call(nc, NULL, nc->user_data, MG_EV_ACCEPT, &nc->sa); + } + (void) sa_len; } void mg_send(struct mg_connection *nc, const void *buf, int len) { nc->last_io_time = (time_t) mg_time(); + mbuf_append(&nc->send_mbuf, buf, len); +} + +static int mg_recv_tcp(struct mg_connection *nc, char *buf, size_t len); +static int mg_recv_udp(struct mg_connection *nc, char *buf, size_t len); + +static int mg_do_recv(struct mg_connection *nc) { + int res = 0; + char *buf = NULL; + size_t len = (nc->flags & MG_F_UDP ? MG_UDP_IO_SIZE : MG_TCP_IO_SIZE); + if ((nc->flags & (MG_F_CLOSE_IMMEDIATELY | MG_F_CONNECTING)) || + ((nc->flags & MG_F_LISTENING) && !(nc->flags & MG_F_UDP))) { + return -1; + } + len = recv_avail_size(nc, len); + if (len == 0) return -2; + if (nc->recv_mbuf.size < nc->recv_mbuf.len + len) { + mbuf_resize(&nc->recv_mbuf, nc->recv_mbuf.len + len); + } + buf = nc->recv_mbuf.buf + nc->recv_mbuf.len; + len = nc->recv_mbuf.size - nc->recv_mbuf.len; if (nc->flags & MG_F_UDP) { - nc->iface->vtable->udp_send(nc, buf, len); + res = mg_recv_udp(nc, buf, len); } else { - nc->iface->vtable->tcp_send(nc, buf, len); + res = mg_recv_tcp(nc, buf, len); } + return res; } -void mg_if_sent_cb(struct mg_connection *nc, int num_sent) { - DBG(("%p %d", nc, num_sent)); -#if !defined(NO_LIBC) && MG_ENABLE_HEXDUMP - if (nc->mgr && nc->mgr->hexdump_file != NULL) { - char *buf = nc->send_mbuf.buf; - mg_hexdump_connection(nc, nc->mgr->hexdump_file, buf, num_sent, MG_EV_SEND); - } -#endif - if (num_sent < 0) { - nc->flags |= MG_F_CLOSE_IMMEDIATELY; - } else { - mbuf_remove(&nc->send_mbuf, num_sent); - mbuf_trim(&nc->send_mbuf); - } - mg_call(nc, NULL, nc->user_data, MG_EV_SEND, &num_sent); +void mg_if_can_recv_cb(struct mg_connection *nc) { + mg_do_recv(nc); } -MG_INTERNAL void mg_recv_common(struct mg_connection *nc, void *buf, int len, - int own) { - DBG(("%p %d %u", nc, len, (unsigned int) nc->recv_mbuf.len)); - -#if !defined(NO_LIBC) && MG_ENABLE_HEXDUMP - if (nc->mgr && nc->mgr->hexdump_file != NULL) { - mg_hexdump_connection(nc, nc->mgr->hexdump_file, buf, len, MG_EV_RECV); - } -#endif - - if (nc->flags & MG_F_CLOSE_IMMEDIATELY) { - DBG(("%p discarded %d bytes", nc, len)); - /* - * This connection will not survive next poll. Do not deliver events, - * send data to /dev/null without acking. - */ - if (own) { - MG_FREE(buf); +static int mg_recv_tcp(struct mg_connection *nc, char *buf, size_t len) { + int n = 0; +#if MG_ENABLE_SSL + if (nc->flags & MG_F_SSL) { + if (nc->flags & MG_F_SSL_HANDSHAKE_DONE) { + n = mg_ssl_if_read(nc, buf, len); + DBG(("%p <- %d bytes (SSL)", nc, n)); + if (n < 0) { + if (n == MG_SSL_WANT_READ) { + nc->flags |= MG_F_WANT_READ; + n = 0; + } else { + nc->flags |= MG_F_CLOSE_IMMEDIATELY; + } + } else if (n > 0) { + nc->flags &= ~MG_F_WANT_READ; + } + } else { + mg_ssl_handshake(nc); } - return; + } else +#endif + { + n = nc->iface->vtable->tcp_recv(nc, buf, len); + DBG(("%p <- %d bytes", nc, n)); } - nc->last_io_time = (time_t) mg_time(); - if (!own) { - mbuf_append(&nc->recv_mbuf, buf, len); - } else if (nc->recv_mbuf.len == 0) { - /* Adopt buf as recv_mbuf's backing store. */ - mbuf_free(&nc->recv_mbuf); - nc->recv_mbuf.buf = (char *) buf; - nc->recv_mbuf.size = nc->recv_mbuf.len = len; - } else { - mbuf_append(&nc->recv_mbuf, buf, len); - MG_FREE(buf); + if (n > 0) { + nc->recv_mbuf.len += n; + nc->last_io_time = (time_t) mg_time(); +#if !defined(NO_LIBC) && MG_ENABLE_HEXDUMP + if (nc->mgr && nc->mgr->hexdump_file != NULL) { + mg_hexdump_connection(nc, nc->mgr->hexdump_file, buf, n, MG_EV_RECV); + } +#endif + mg_call(nc, NULL, nc->user_data, MG_EV_RECV, &n); + } else if (n < 0) { + nc->flags |= MG_F_CLOSE_IMMEDIATELY; } - mg_call(nc, NULL, nc->user_data, MG_EV_RECV, &len); + return n; } -void mg_if_recv_tcp_cb(struct mg_connection *nc, void *buf, int len, int own) { - mg_recv_common(nc, buf, len, own); -} - -void mg_if_recv_udp_cb(struct mg_connection *nc, void *buf, int len, - union socket_address *sa, size_t sa_len) { - assert(nc->flags & MG_F_UDP); - DBG(("%p %u", nc, (unsigned int) len)); +static int mg_recv_udp(struct mg_connection *nc, char *buf, size_t len) { + int n = 0; + struct mg_connection *lc = nc; + union socket_address sa; + size_t sa_len = sizeof(sa); + n = nc->iface->vtable->udp_recv(lc, buf, len, &sa, &sa_len); + if (n < 0) { + lc->flags |= MG_F_CLOSE_IMMEDIATELY; + goto out; + } if (nc->flags & MG_F_LISTENING) { - struct mg_connection *lc = nc; /* * Do we have an existing connection for this source? * This is very inefficient for long connection lists. */ + lc = nc; for (nc = mg_next(lc->mgr, NULL); nc != NULL; nc = mg_next(lc->mgr, nc)) { - if (memcmp(&nc->sa.sa, &sa->sa, sa_len) == 0 && nc->listener == lc) { + if (memcmp(&nc->sa.sa, &sa.sa, sa_len) == 0 && nc->listener == lc) { break; } } @@ -2727,7 +2815,7 @@ void mg_if_recv_udp_cb(struct mg_connection *nc, void *buf, int len, if (nc != NULL) { nc->sock = lc->sock; nc->listener = lc; - nc->sa = *sa; + nc->sa = sa; nc->proto_handler = lc->proto_handler; nc->user_data = lc->user_data; nc->recv_mbuf_limit = lc->recv_mbuf_limit; @@ -2746,18 +2834,88 @@ void mg_if_recv_udp_cb(struct mg_connection *nc, void *buf, int len, nc->flags |= MG_F_SEND_AND_CLOSE; mg_add_conn(lc->mgr, nc); mg_call(nc, NULL, nc->user_data, MG_EV_ACCEPT, &nc->sa); - } else { - DBG(("OOM")); - /* No return here, we still need to drop on the floor */ } } } if (nc != NULL) { - mg_recv_common(nc, buf, len, 1); - } else { - /* Drop on the floor. */ - MG_FREE(buf); + DBG(("%p <- %d bytes from %s:%d", nc, n, inet_ntoa(nc->sa.sin.sin_addr), + ntohs(nc->sa.sin.sin_port))); + if (nc == lc) { + nc->recv_mbuf.len += n; + } else { + mbuf_append(&nc->recv_mbuf, buf, n); + } + mbuf_trim(&lc->recv_mbuf); + lc->last_io_time = nc->last_io_time = (time_t) mg_time(); +#if !defined(NO_LIBC) && MG_ENABLE_HEXDUMP + if (nc->mgr && nc->mgr->hexdump_file != NULL) { + mg_hexdump_connection(nc, nc->mgr->hexdump_file, buf, n, MG_EV_RECV); + } +#endif + mg_call(nc, NULL, nc->user_data, MG_EV_RECV, &n); } + +out: + mbuf_free(&lc->recv_mbuf); + return n; +} + +void mg_if_can_send_cb(struct mg_connection *nc) { + int n = 0; + const char *buf = nc->send_mbuf.buf; + size_t len = nc->send_mbuf.len; + + if (nc->flags & (MG_F_CLOSE_IMMEDIATELY | MG_F_CONNECTING)) { + return; + } + if (!(nc->flags & MG_F_UDP)) { + if (nc->flags & MG_F_LISTENING) return; + if (len > MG_TCP_IO_SIZE) len = MG_TCP_IO_SIZE; + } +#if MG_ENABLE_SSL + if (nc->flags & MG_F_SSL) { + if (nc->flags & MG_F_SSL_HANDSHAKE_DONE) { + if (len > 0) { + n = mg_ssl_if_write(nc, buf, len); + DBG(("%p -> %d bytes (SSL)", nc, n)); + } + if (n < 0) { + if (n == MG_SSL_WANT_WRITE) { + nc->flags |= MG_F_WANT_WRITE; + n = 0; + } else { + nc->flags |= MG_F_CLOSE_IMMEDIATELY; + } + } else { + nc->flags &= ~MG_F_WANT_WRITE; + } + } else { + mg_ssl_handshake(nc); + } + } else +#endif + { + if (nc->flags & MG_F_UDP) { + n = nc->iface->vtable->udp_send(nc, buf, len); + } else { + n = nc->iface->vtable->tcp_send(nc, buf, len); + } + DBG(("%p -> %d bytes", nc, n)); + } + +#if !defined(NO_LIBC) && MG_ENABLE_HEXDUMP + if (n > 0 && nc->mgr && nc->mgr->hexdump_file != NULL) { + mg_hexdump_connection(nc, nc->mgr->hexdump_file, buf, n, MG_EV_SEND); + } +#endif + if (n < 0) { + nc->flags |= MG_F_CLOSE_IMMEDIATELY; + } else if (n > 0) { + nc->last_io_time = (time_t) mg_time(); + mbuf_remove(&nc->send_mbuf, n); + mbuf_trim(&nc->send_mbuf); + } + if (n != 0) mg_call(nc, NULL, nc->user_data, MG_EV_SEND, &n); } /* @@ -2769,8 +2927,8 @@ void mg_if_recv_udp_cb(struct mg_connection *nc, void *buf, int len, MG_INTERNAL struct mg_connection *mg_do_connect(struct mg_connection *nc, int proto, union socket_address *sa) { - DBG(("%p %s://%s:%hu", nc, proto == SOCK_DGRAM ? "udp" : "tcp", - inet_ntoa(sa->sin.sin_addr), ntohs(sa->sin.sin_port))); + LOG(LL_DEBUG, ("%p %s://%s:%hu", nc, proto == SOCK_DGRAM ? "udp" : "tcp", + inet_ntoa(sa->sin.sin_addr), ntohs(sa->sin.sin_port))); nc->flags |= MG_F_CONNECTING; if (proto == SOCK_DGRAM) { @@ -2783,12 +2941,21 @@ MG_INTERNAL struct mg_connection *mg_do_connect(struct mg_connection *nc, } void mg_if_connect_cb(struct mg_connection *nc, int err) { - DBG(("%p connect, err=%d", nc, err)); + LOG(LL_DEBUG, + ("%p %s://%s:%hu -> %d", nc, (nc->flags & MG_F_UDP ? "udp" : "tcp"), + inet_ntoa(nc->sa.sin.sin_addr), ntohs(nc->sa.sin.sin_port), err)); nc->flags &= ~MG_F_CONNECTING; if (err != 0) { nc->flags |= MG_F_CLOSE_IMMEDIATELY; } - mg_call(nc, NULL, nc->user_data, MG_EV_CONNECT, &err); +#if MG_ENABLE_SSL + if (err == 0 && (nc->flags & MG_F_SSL)) { + mg_ssl_handshake(nc); + } else +#endif + { + mg_call(nc, NULL, nc->user_data, MG_EV_CONNECT, &err); + } } #if MG_ENABLE_ASYNC_RESOLVER @@ -2878,7 +3045,8 @@ struct mg_connection *mg_connect_opt(struct mg_mgr *mgr, const char *address, #endif #if MG_ENABLE_SSL - DBG(("%p %s %s,%s,%s", nc, address, (opts.ssl_cert ? opts.ssl_cert : "-"), + LOG(LL_DEBUG, + ("%p %s %s,%s,%s", nc, address, (opts.ssl_cert ? opts.ssl_cert : "-"), (opts.ssl_key ? opts.ssl_key : "-"), (opts.ssl_ca_cert ? opts.ssl_ca_cert : "-"))); @@ -3124,7 +3292,7 @@ double mg_set_timer(struct mg_connection *c, double timestamp) { DBG(("%p %p %d -> %lu", c, c->priv_2, (c->flags & MG_F_RESOLVING ? 1 : 0), (unsigned long) timestamp)); if ((c->flags & MG_F_RESOLVING) && c->priv_2 != NULL) { - ((struct mg_connection *) c->priv_2)->ev_timer_time = timestamp; + mg_set_timer((struct mg_connection *) c->priv_2, timestamp); } return result; } @@ -3278,14 +3446,8 @@ struct mg_iface *mg_find_iface(struct mg_mgr *mgr, /* Amalgamated: #include "mg_internal.h" */ /* Amalgamated: #include "mg_util.h" */ -#define MG_TCP_RECV_BUFFER_SIZE 1024 -#define MG_UDP_RECV_BUFFER_SIZE 1500 - static sock_t mg_open_listening_socket(union socket_address *sa, int type, int proto); -#if MG_ENABLE_SSL -static void mg_ssl_begin(struct mg_connection *nc); -#endif void mg_set_non_blocking_mode(sock_t sock) { #ifdef _WIN32 @@ -3354,27 +3516,48 @@ int mg_socket_if_listen_tcp(struct mg_connection *nc, return 0; } -int mg_socket_if_listen_udp(struct mg_connection *nc, - union socket_address *sa) { +static int mg_socket_if_listen_udp(struct mg_connection *nc, + union socket_address *sa) { sock_t sock = mg_open_listening_socket(sa, SOCK_DGRAM, 0); if (sock == INVALID_SOCKET) return (mg_get_errno() ? mg_get_errno() : 1); mg_sock_set(nc, sock); return 0; } -void mg_socket_if_tcp_send(struct mg_connection *nc, const void *buf, - size_t len) { - mbuf_append(&nc->send_mbuf, buf, len); +static int mg_socket_if_tcp_send(struct mg_connection *nc, const void *buf, + size_t len) { + int n = (int) MG_SEND_FUNC(nc->sock, buf, len, 0); + if (n < 0 && !mg_is_error()) n = 0; + return n; } -void mg_socket_if_udp_send(struct mg_connection *nc, const void *buf, - size_t len) { - mbuf_append(&nc->send_mbuf, buf, len); +static int mg_socket_if_udp_send(struct mg_connection *nc, const void *buf, + size_t len) { + int n = sendto(nc->sock, buf, len, 0, &nc->sa.sa, sizeof(nc->sa.sin)); + if (n < 0 && !mg_is_error()) n = 0; + return n; } -void mg_socket_if_recved(struct mg_connection *nc, size_t len) { - (void) nc; - (void) len; +static int mg_socket_if_tcp_recv(struct mg_connection *nc, void *buf, + size_t len) { + int n = (int) MG_RECV_FUNC(nc->sock, buf, len, 0); + if (n == 0) { + /* Orderly shutdown of the socket, try flushing output. */ + nc->flags |= MG_F_SEND_AND_CLOSE; + } else if (n < 0 && !mg_is_error()) { + n = 0; + } + return n; +} + +static int mg_socket_if_udp_recv(struct mg_connection *nc, void *buf, + size_t len, union socket_address *sa, + size_t *sa_len) { + socklen_t sa_len_st = *sa_len; + int n = recvfrom(nc->sock, buf, len, 0, &sa->sa, &sa_len_st); + *sa_len = sa_len_st; + if (n < 0 && !mg_is_error()) n = 0; + return n; } int mg_socket_if_create_conn(struct mg_connection *nc) { @@ -3411,14 +3594,7 @@ static int mg_accept_conn(struct mg_connection *lc) { DBG(("%p conn from %s:%d", nc, inet_ntoa(sa.sin.sin_addr), ntohs(sa.sin.sin_port))); mg_sock_set(nc, sock); -#if MG_ENABLE_SSL - if (lc->flags & MG_F_SSL) { - if (mg_ssl_if_conn_accept(nc, lc) != MG_SSL_OK) mg_close_conn(nc); - } else -#endif - { - mg_if_accept_tcp_cb(nc, &sa, sa_len); - } + mg_if_accept_tcp_cb(nc, &sa, sa_len); return 1; } @@ -3469,165 +3645,6 @@ static sock_t mg_open_listening_socket(union socket_address *sa, int type, return sock; } -static void mg_write_to_socket(struct mg_connection *nc) { - struct mbuf *io = &nc->send_mbuf; - int n = 0; - -#if MG_LWIP - /* With LWIP we don't know if the socket is ready */ - if (io->len == 0) return; -#endif - - assert(io->len > 0); - - if (nc->flags & MG_F_UDP) { - int n = - sendto(nc->sock, io->buf, io->len, 0, &nc->sa.sa, sizeof(nc->sa.sin)); - DBG(("%p %d %d %d %s:%hu", nc, nc->sock, n, mg_get_errno(), - inet_ntoa(nc->sa.sin.sin_addr), ntohs(nc->sa.sin.sin_port))); - mg_if_sent_cb(nc, n); - return; - } - -#if MG_ENABLE_SSL - if (nc->flags & MG_F_SSL) { - if (nc->flags & MG_F_SSL_HANDSHAKE_DONE) { - n = mg_ssl_if_write(nc, io->buf, io->len); - DBG(("%p %d bytes -> %d (SSL)", nc, n, nc->sock)); - if (n < 0) { - if (n != MG_SSL_WANT_READ && n != MG_SSL_WANT_WRITE) { - nc->flags |= MG_F_CLOSE_IMMEDIATELY; - } - return; - } else { - /* Successful SSL operation, clear off SSL wait flags */ - nc->flags &= ~(MG_F_WANT_READ | MG_F_WANT_WRITE); - } - } else { - mg_ssl_begin(nc); - return; - } - } else -#endif - { - n = (int) MG_SEND_FUNC(nc->sock, io->buf, io->len, 0); - DBG(("%p %d bytes -> %d", nc, n, nc->sock)); - } - - mg_if_sent_cb(nc, n); -} - -MG_INTERNAL size_t recv_avail_size(struct mg_connection *conn, size_t max) { - size_t avail; - if (conn->recv_mbuf_limit < conn->recv_mbuf.len) return 0; - avail = conn->recv_mbuf_limit - conn->recv_mbuf.len; - return avail > max ? max : avail; -} - -static void mg_handle_tcp_read(struct mg_connection *conn) { - int n = 0; - char *buf = (char *) MG_MALLOC(MG_TCP_RECV_BUFFER_SIZE); - - if (buf == NULL) { - DBG(("OOM")); - return; - } - -#if MG_ENABLE_SSL - if (conn->flags & MG_F_SSL) { - if (conn->flags & MG_F_SSL_HANDSHAKE_DONE) { - /* SSL library may have more bytes ready to read than we ask to read. - * Therefore, read in a loop until we read everything. Without the loop, - * we skip to the next select() cycle which can just timeout. */ - while ((n = mg_ssl_if_read(conn, buf, MG_TCP_RECV_BUFFER_SIZE)) > 0) { - DBG(("%p %d bytes <- %d (SSL)", conn, n, conn->sock)); - mg_if_recv_tcp_cb(conn, buf, n, 1 /* own */); - buf = NULL; - if (conn->flags & MG_F_CLOSE_IMMEDIATELY) break; - /* buf has been freed, we need a new one. */ - buf = (char *) MG_MALLOC(MG_TCP_RECV_BUFFER_SIZE); - if (buf == NULL) break; - } - MG_FREE(buf); - if (n < 0 && n != MG_SSL_WANT_READ) conn->flags |= MG_F_CLOSE_IMMEDIATELY; - } else { - MG_FREE(buf); - mg_ssl_begin(conn); - return; - } - } else -#endif - { - n = (int) MG_RECV_FUNC(conn->sock, buf, - recv_avail_size(conn, MG_TCP_RECV_BUFFER_SIZE), 0); - DBG(("%p %d bytes (PLAIN) <- %d", conn, n, conn->sock)); - if (n > 0) { - mg_if_recv_tcp_cb(conn, buf, n, 1 /* own */); - } else { - MG_FREE(buf); - } - if (n == 0) { - /* Orderly shutdown of the socket, try flushing output. */ - conn->flags |= MG_F_SEND_AND_CLOSE; - } else if (n < 0 && mg_is_error()) { - conn->flags |= MG_F_CLOSE_IMMEDIATELY; - } - } -} - -static int mg_recvfrom(struct mg_connection *nc, union socket_address *sa, - socklen_t *sa_len, char **buf) { - int n; - *buf = (char *) MG_MALLOC(MG_UDP_RECV_BUFFER_SIZE); - if (*buf == NULL) { - DBG(("Out of memory")); - return -ENOMEM; - } - n = recvfrom(nc->sock, *buf, MG_UDP_RECV_BUFFER_SIZE, 0, &sa->sa, sa_len); - if (n <= 0) { - DBG(("%p recvfrom: %s", nc, strerror(mg_get_errno()))); - MG_FREE(*buf); - } - return n; -} - -static void mg_handle_udp_read(struct mg_connection *nc) { - char *buf = NULL; - union socket_address sa; - socklen_t sa_len = sizeof(sa); - int n = mg_recvfrom(nc, &sa, &sa_len, &buf); - DBG(("%p %d bytes from %s:%d", nc, n, inet_ntoa(nc->sa.sin.sin_addr), - ntohs(nc->sa.sin.sin_port))); - mg_if_recv_udp_cb(nc, buf, n, &sa, sa_len); -} - -#if MG_ENABLE_SSL -static void mg_ssl_begin(struct mg_connection *nc) { - int server_side = (nc->listener != NULL); - enum mg_ssl_if_result res = mg_ssl_if_handshake(nc); - DBG(("%p %d res %d", nc, server_side, res)); - - if (res == MG_SSL_OK) { - nc->flags |= MG_F_SSL_HANDSHAKE_DONE; - nc->flags &= ~(MG_F_WANT_READ | MG_F_WANT_WRITE); - - if (server_side) { - union socket_address sa; - socklen_t sa_len = sizeof(sa); - (void) getpeername(nc->sock, &sa.sa, &sa_len); - mg_if_accept_tcp_cb(nc, &sa, sa_len); - } else { - mg_if_connect_cb(nc, 0); - } - } else if (res != MG_SSL_WANT_READ && res != MG_SSL_WANT_WRITE) { - if (!server_side) { - mg_if_connect_cb(nc, res); - } - nc->flags |= MG_F_CLOSE_IMMEDIATELY; - } -} -#endif /* MG_ENABLE_SSL */ - #define _MG_F_FD_CAN_READ 1 #define _MG_F_FD_CAN_WRITE 1 << 1 #define _MG_F_FD_ERROR 1 << 2 @@ -3636,11 +3653,13 @@ void mg_mgr_handle_conn(struct mg_connection *nc, int fd_flags, double now) { int worth_logging = fd_flags != 0 || (nc->flags & (MG_F_WANT_READ | MG_F_WANT_WRITE)); if (worth_logging) { - DBG(("%p fd=%d fd_flags=%d nc_flags=%lu rmbl=%d smbl=%d", nc, nc->sock, + DBG(("%p fd=%d fd_flags=%d nc_flags=0x%lx rmbl=%d smbl=%d", nc, nc->sock, fd_flags, nc->flags, (int) nc->recv_mbuf.len, (int) nc->send_mbuf.len)); } + if (!mg_if_poll(nc, now)) return; + if (nc->flags & MG_F_CONNECTING) { if (fd_flags != 0) { int err = 0; @@ -3661,15 +3680,7 @@ void mg_mgr_handle_conn(struct mg_connection *nc, int fd_flags, double now) { */ err = nc->err; #endif -#if MG_ENABLE_SSL - if ((nc->flags & MG_F_SSL) && err == 0) { - mg_ssl_begin(nc); - } else { - mg_if_connect_cb(nc, err); - } -#else mg_if_connect_cb(nc, err); -#endif } else if (nc->err != 0) { mg_if_connect_cb(nc, nc->err); } @@ -3677,7 +3688,7 @@ void mg_mgr_handle_conn(struct mg_connection *nc, int fd_flags, double now) { if (fd_flags & _MG_F_FD_CAN_READ) { if (nc->flags & MG_F_UDP) { - mg_handle_udp_read(nc); + mg_if_can_recv_cb(nc); } else { if (nc->flags & MG_F_LISTENING) { /* @@ -3687,22 +3698,16 @@ void mg_mgr_handle_conn(struct mg_connection *nc, int fd_flags, double now) { */ mg_accept_conn(nc); } else { - mg_handle_tcp_read(nc); + mg_if_can_recv_cb(nc); } } } - if (!(nc->flags & MG_F_CLOSE_IMMEDIATELY)) { - if ((fd_flags & _MG_F_FD_CAN_WRITE) && nc->send_mbuf.len > 0) { - mg_write_to_socket(nc); - } - mg_if_poll(nc, (time_t) now); - mg_if_timer(nc, now); - } + if (fd_flags & _MG_F_FD_CAN_WRITE) mg_if_can_send_cb(nc); if (worth_logging) { - DBG(("%p after fd=%d nc_flags=%lu rmbl=%d smbl=%d", nc, nc->sock, nc->flags, - (int) nc->recv_mbuf.len, (int) nc->send_mbuf.len)); + DBG(("%p after fd=%d nc_flags=0x%lx rmbl=%d smbl=%d", nc, nc->sock, + nc->flags, (int) nc->recv_mbuf.len, (int) nc->send_mbuf.len)); } } @@ -3816,8 +3821,7 @@ time_t mg_socket_if_poll(struct mg_iface *iface, int timeout_ms) { } #endif - if (!(nc->flags & MG_F_WANT_WRITE) && - nc->recv_mbuf.len < nc->recv_mbuf_limit && + if (nc->recv_mbuf.len < nc->recv_mbuf_limit && (!(nc->flags & MG_F_UDP) || nc->listener == NULL)) { mg_add_to_set(nc->sock, &read_set, &max_fd); } @@ -3888,14 +3892,6 @@ time_t mg_socket_if_poll(struct mg_iface *iface, int timeout_ms) { mg_mgr_handle_conn(nc, fd_flags, now); } - for (nc = mgr->active_connections; nc != NULL; nc = tmp) { - tmp = nc->next; - if ((nc->flags & MG_F_CLOSE_IMMEDIATELY) || - (nc->send_mbuf.len == 0 && (nc->flags & MG_F_SEND_AND_CLOSE))) { - mg_close_conn(nc); - } - } - return (time_t) now; } @@ -4004,7 +4000,8 @@ void mg_socket_if_get_conn_addr(struct mg_connection *nc, int remote, mg_socket_if_connect_udp, \ mg_socket_if_tcp_send, \ mg_socket_if_udp_send, \ - mg_socket_if_recved, \ + mg_socket_if_tcp_recv, \ + mg_socket_if_udp_recv, \ mg_socket_if_create_conn, \ mg_socket_if_destroy_conn, \ mg_socket_if_sock_set, \ @@ -4032,18 +4029,35 @@ struct socksdata { char *proxy_addr; /* HOST:PORT of the socks5 proxy server */ struct mg_connection *s; /* Respective connection to the server */ struct mg_connection *c; /* Connection to the client */ - struct mbuf tmp; /* Temporary buffer for sent data */ }; static void socks_if_disband(struct socksdata *d) { LOG(LL_DEBUG, ("disbanding proxy %p %p", d->c, d->s)); - if (d->c) d->c->flags |= MG_F_SEND_AND_CLOSE; - if (d->s) d->s->flags |= MG_F_SEND_AND_CLOSE; - d->c = d->s = NULL; + if (d->c) { + d->c->flags |= MG_F_SEND_AND_CLOSE; + d->c->user_data = NULL; + d->c = NULL; + } + if (d->s) { + d->s->flags |= MG_F_SEND_AND_CLOSE; + d->s->user_data = NULL; + d->s = NULL; + } +} + +static void socks_if_relay(struct mg_connection *s) { + struct socksdata *d = (struct socksdata *) s->user_data; + if (d == NULL || d->c == NULL || !(s->flags & MG_SOCKS_CONNECT_DONE) || + d->s == NULL) { + return; + } + if (s->recv_mbuf.len > 0) mg_if_can_recv_cb(d->c); + if (d->c->send_mbuf.len > 0 && s->send_mbuf.len == 0) mg_if_can_send_cb(d->c); } static void socks_if_handler(struct mg_connection *c, int ev, void *ev_data) { struct socksdata *d = (struct socksdata *) c->user_data; + if (d == NULL) return; if (ev == MG_EV_CONNECT) { int res = *(int *) ev_data; if (res == 0) { @@ -4076,6 +4090,7 @@ static void socks_if_handler(struct mg_connection *c, int ev, void *ev_data) { memcpy(buf + 4, &d->c->sa.sin.sin_addr, 4); memcpy(buf + 8, &d->c->sa.sin.sin_port, 2); mg_send(c, buf, sizeof(buf)); + LOG(LL_DEBUG, ("%p Sent connect request", c)); } /* Process connect request */ if ((c->flags & MG_SOCKS_HANDSHAKE_DONE) && @@ -4088,17 +4103,12 @@ static void socks_if_handler(struct mg_connection *c, int ev, void *ev_data) { } mbuf_remove(&c->recv_mbuf, 10); c->flags |= MG_SOCKS_CONNECT_DONE; - /* Connected. Move sent data from client, if any, to server */ - if (d->s && d->c) { - mbuf_append(&d->s->send_mbuf, d->tmp.buf, d->tmp.len); - mbuf_free(&d->tmp); - } - } - /* All flags are set, we're in relay mode */ - if ((c->flags & MG_SOCKS_CONNECT_DONE) && d->c && d->s) { - mbuf_append(&d->c->recv_mbuf, d->s->recv_mbuf.buf, d->s->recv_mbuf.len); - mbuf_remove(&d->s->recv_mbuf, d->s->recv_mbuf.len); + LOG(LL_DEBUG, ("%p Connect done %p", c, d->c)); + mg_if_connect_cb(d->c, 0); } + socks_if_relay(c); + } else if (ev == MG_EV_SEND || ev == MG_EV_POLL) { + socks_if_relay(c); } } @@ -4108,7 +4118,7 @@ static void mg_socks_if_connect_tcp(struct mg_connection *c, d->c = c; d->s = mg_connect(c->mgr, d->proxy_addr, socks_if_handler); d->s->user_data = d; - LOG(LL_DEBUG, ("%p %s", c, d->proxy_addr)); + LOG(LL_DEBUG, ("%p %s %p %p", c, d->proxy_addr, d, d->s)); (void) sa; } @@ -4130,29 +4140,44 @@ static int mg_socks_if_listen_udp(struct mg_connection *c, return -1; } -static void mg_socks_if_tcp_send(struct mg_connection *c, const void *buf, - size_t len) { +static int mg_socks_if_tcp_send(struct mg_connection *c, const void *buf, + size_t len) { + int res; struct socksdata *d = (struct socksdata *) c->iface->data; - LOG(LL_DEBUG, ("%p -> %p %d %d", c, buf, (int) len, (int) c->send_mbuf.len)); - if (d && d->s && d->s->flags & MG_SOCKS_CONNECT_DONE) { - mbuf_append(&d->s->send_mbuf, d->tmp.buf, d->tmp.len); - mbuf_append(&d->s->send_mbuf, buf, len); - mbuf_free(&d->tmp); - } else { - mbuf_append(&d->tmp, buf, len); - } + if (d->s == NULL) return -1; + res = (int) mbuf_append(&d->s->send_mbuf, buf, len); + DBG(("%p -> %d -> %p", c, res, d->s)); + return res; } -static void mg_socks_if_udp_send(struct mg_connection *c, const void *buf, - size_t len) { +static int mg_socks_if_udp_send(struct mg_connection *c, const void *buf, + size_t len) { (void) c; (void) buf; (void) len; + return -1; } -static void mg_socks_if_recved(struct mg_connection *c, size_t len) { +int mg_socks_if_tcp_recv(struct mg_connection *c, void *buf, size_t len) { + struct socksdata *d = (struct socksdata *) c->iface->data; + if (d->s == NULL) return -1; + if (len > d->s->recv_mbuf.len) len = d->s->recv_mbuf.len; + if (len > 0) { + memcpy(buf, d->s->recv_mbuf.buf, len); + mbuf_remove(&d->s->recv_mbuf, len); + } + DBG(("%p <- %d <- %p", c, (int) len, d->s)); + return len; +} + +int mg_socks_if_udp_recv(struct mg_connection *c, void *buf, size_t len, + union socket_address *sa, size_t *sa_len) { (void) c; + (void) buf; (void) len; + (void) sa; + (void) sa_len; + return -1; } static int mg_socks_if_create_conn(struct mg_connection *c) { @@ -4181,7 +4206,6 @@ static void mg_socks_if_free(struct mg_iface *iface) { LOG(LL_DEBUG, ("%p", iface)); if (d != NULL) { socks_if_disband(d); - mbuf_free(&d->tmp); MG_FREE(d->proxy_addr); MG_FREE(d); iface->data = NULL; @@ -4212,14 +4236,15 @@ static void mg_socks_if_get_conn_addr(struct mg_connection *c, int remote, } const struct mg_iface_vtable mg_socks_iface_vtable = { - mg_socks_if_init, mg_socks_if_free, - mg_socks_if_add_conn, mg_socks_if_remove_conn, - mg_socks_if_poll, mg_socks_if_listen_tcp, - mg_socks_if_listen_udp, mg_socks_if_connect_tcp, - mg_socks_if_connect_udp, mg_socks_if_tcp_send, - mg_socks_if_udp_send, mg_socks_if_recved, - mg_socks_if_create_conn, mg_socks_if_destroy_conn, - mg_socks_if_sock_set, mg_socks_if_get_conn_addr, + mg_socks_if_init, mg_socks_if_free, + mg_socks_if_add_conn, mg_socks_if_remove_conn, + mg_socks_if_poll, mg_socks_if_listen_tcp, + mg_socks_if_listen_udp, mg_socks_if_connect_tcp, + mg_socks_if_connect_udp, mg_socks_if_tcp_send, + mg_socks_if_udp_send, mg_socks_if_tcp_recv, + mg_socks_if_udp_recv, mg_socks_if_create_conn, + mg_socks_if_destroy_conn, mg_socks_if_sock_set, + mg_socks_if_get_conn_addr, }; struct mg_iface *mg_socks_mk_iface(struct mg_mgr *mgr, const char *proxy_addr) { @@ -4639,9 +4664,12 @@ const char *mg_set_ssl(struct mg_connection *nc, const char *cert, #include #include +#include #include #include +#include #include +#include static void mg_ssl_mbed_log(void *ctx, int level, const char *file, int line, const char *str) { @@ -4651,6 +4679,8 @@ static void mg_ssl_mbed_log(void *ctx, int level, const char *file, int line, cs_level = LL_ERROR; break; case 2: + cs_level = LL_INFO; + break; case 3: cs_level = LL_DEBUG; break; @@ -4670,12 +4700,14 @@ struct mg_ssl_if_ctx { mbedtls_pk_context *key; mbedtls_x509_crt *ca_cert; struct mbuf cipher_suites; + size_t saved_len; }; /* Must be provided by the platform. ctx is struct mg_connection. */ extern int mg_ssl_if_mbed_random(void *ctx, unsigned char *buf, size_t len); void mg_ssl_if_init() { + LOG(LL_INFO, ("%s", MBEDTLS_VERSION_STRING_FULL)); } enum mg_ssl_if_result mg_ssl_if_conn_accept(struct mg_connection *nc, @@ -4796,40 +4828,41 @@ enum mg_ssl_if_result mg_ssl_if_conn_init( return MG_SSL_OK; } -#if MG_NET_IF == MG_NET_IF_LWIP_LOW_LEVEL -int ssl_socket_send(void *ctx, const unsigned char *buf, size_t len); -int ssl_socket_recv(void *ctx, unsigned char *buf, size_t len); -#else -static int ssl_socket_send(void *ctx, const unsigned char *buf, size_t len) { +static int mg_ssl_if_mbed_send(void *ctx, const unsigned char *buf, + size_t len) { struct mg_connection *nc = (struct mg_connection *) ctx; - int n = (int) MG_SEND_FUNC(nc->sock, buf, len, 0); - LOG(LL_DEBUG, ("%p %d -> %d", nc, (int) len, n)); - if (n >= 0) return n; - n = mg_get_errno(); - return ((n == EAGAIN || n == EINPROGRESS) ? MBEDTLS_ERR_SSL_WANT_WRITE : -1); + int n = nc->iface->vtable->tcp_send(nc, buf, len); + if (n > 0) return n; + if (n == 0) return MBEDTLS_ERR_SSL_WANT_WRITE; + return MBEDTLS_ERR_NET_SEND_FAILED; } -static int ssl_socket_recv(void *ctx, unsigned char *buf, size_t len) { +static int mg_ssl_if_mbed_recv(void *ctx, unsigned char *buf, size_t len) { struct mg_connection *nc = (struct mg_connection *) ctx; - int n = (int) MG_RECV_FUNC(nc->sock, buf, len, 0); - LOG(LL_DEBUG, ("%p %d <- %d", nc, (int) len, n)); - if (n >= 0) return n; - n = mg_get_errno(); - return ((n == EAGAIN || n == EINPROGRESS) ? MBEDTLS_ERR_SSL_WANT_READ : -1); + int n = nc->iface->vtable->tcp_recv(nc, buf, len); + if (n > 0) return n; + if (n == 0) return MBEDTLS_ERR_SSL_WANT_READ; + return MBEDTLS_ERR_NET_RECV_FAILED; } -#endif static enum mg_ssl_if_result mg_ssl_if_mbed_err(struct mg_connection *nc, int ret) { - if (ret == MBEDTLS_ERR_SSL_WANT_READ) return MG_SSL_WANT_READ; - if (ret == MBEDTLS_ERR_SSL_WANT_WRITE) return MG_SSL_WANT_WRITE; - if (ret != - MBEDTLS_ERR_SSL_PEER_CLOSE_NOTIFY) { /* CLOSE_NOTIFY = Normal shutdown */ - LOG(LL_ERROR, ("%p SSL error: %d", nc, ret)); + enum mg_ssl_if_result res = MG_SSL_OK; + if (ret == MBEDTLS_ERR_SSL_WANT_READ) { + res = MG_SSL_WANT_READ; + } else if (ret == MBEDTLS_ERR_SSL_WANT_WRITE) { + res = MG_SSL_WANT_WRITE; + } else if (ret == MBEDTLS_ERR_SSL_PEER_CLOSE_NOTIFY) { + LOG(LL_DEBUG, ("%p TLS connection closed by peer", nc)); + nc->flags |= MG_F_CLOSE_IMMEDIATELY; + res = MG_SSL_OK; + } else { + LOG(LL_ERROR, ("%p mbedTLS error: -0x%04x", nc, -ret)); + nc->flags |= MG_F_CLOSE_IMMEDIATELY; + res = MG_SSL_ERROR; } nc->err = ret; - nc->flags |= MG_F_CLOSE_IMMEDIATELY; - return MG_SSL_ERROR; + return res; } static void mg_ssl_if_mbed_free_certs_and_keys(struct mg_ssl_if_ctx *ctx) { @@ -4860,7 +4893,8 @@ enum mg_ssl_if_result mg_ssl_if_handshake(struct mg_connection *nc) { int err; /* If bio is not yet set, do it now. */ if (ctx->ssl->p_bio == NULL) { - mbedtls_ssl_set_bio(ctx->ssl, nc, ssl_socket_send, ssl_socket_recv, NULL); + mbedtls_ssl_set_bio(ctx->ssl, nc, mg_ssl_if_mbed_send, mg_ssl_if_mbed_recv, + NULL); } err = mbedtls_ssl_handshake(ctx->ssl); if (err != 0) return mg_ssl_if_mbed_err(nc, err); @@ -4886,20 +4920,35 @@ enum mg_ssl_if_result mg_ssl_if_handshake(struct mg_connection *nc) { return MG_SSL_OK; } -int mg_ssl_if_read(struct mg_connection *nc, void *buf, size_t buf_size) { +int mg_ssl_if_read(struct mg_connection *nc, void *buf, size_t len) { struct mg_ssl_if_ctx *ctx = (struct mg_ssl_if_ctx *) nc->ssl_if_data; - int n = mbedtls_ssl_read(ctx->ssl, (unsigned char *) buf, buf_size); - DBG(("%p %d -> %d", nc, (int) buf_size, n)); + int n = mbedtls_ssl_read(ctx->ssl, (unsigned char *) buf, len); + DBG(("%p %d -> %d", nc, (int) len, n)); if (n < 0) return mg_ssl_if_mbed_err(nc, n); if (n == 0) nc->flags |= MG_F_CLOSE_IMMEDIATELY; return n; } -int mg_ssl_if_write(struct mg_connection *nc, const void *data, size_t len) { +int mg_ssl_if_write(struct mg_connection *nc, const void *buf, size_t len) { struct mg_ssl_if_ctx *ctx = (struct mg_ssl_if_ctx *) nc->ssl_if_data; - int n = mbedtls_ssl_write(ctx->ssl, (const unsigned char *) data, len); - DBG(("%p %d -> %d", nc, (int) len, n)); - if (n < 0) return mg_ssl_if_mbed_err(nc, n); + /* Per mbedTLS docs, if write returns WANT_READ or WANT_WRITE, the operation + * should be retried with the same data and length. + * Here we assume that the data being pushed will remain the same but the + * amount may grow between calls so we save the length that was used and + * retry. The assumption being that the data itself won't change and won't + * be removed. */ + size_t l = len; + if (ctx->saved_len > 0 && ctx->saved_len < l) l = ctx->saved_len; + int n = mbedtls_ssl_write(ctx->ssl, (const unsigned char *) buf, l); + DBG(("%p %d,%d,%d -> %d", nc, (int) len, (int) ctx->saved_len, (int) l, n)); + if (n < 0) { + if (n == MBEDTLS_ERR_SSL_WANT_READ || n == MBEDTLS_ERR_SSL_WANT_WRITE) { + ctx->saved_len = len; + } + return mg_ssl_if_mbed_err(nc, n); + } else if (n > 0) { + ctx->saved_len = 0; + } return n; } @@ -11557,7 +11606,6 @@ static void mg_resolve_async_eh(struct mg_connection *nc, int ev, time_t now = (time_t) mg_time(); struct mg_resolve_async_request *req; struct mg_dns_message *msg; - int first = 0; #if !MG_ENABLE_CALLBACK_USERDATA void *user_data = nc->user_data; #endif @@ -11571,17 +11619,16 @@ static void mg_resolve_async_eh(struct mg_connection *nc, int ev, } switch (ev) { - case MG_EV_CONNECT: - /* don't depend on timer not being at epoch for sending out first req */ - first = 1; - /* fallthrough */ case MG_EV_POLL: if (req->retries > req->max_retries) { req->err = MG_RESOLVE_EXCEEDED_RETRY_COUNT; nc->flags |= MG_F_CLOSE_IMMEDIATELY; break; } - if (first || now - req->last_time >= req->timeout) { + if (nc->flags & MG_F_CONNECTING) break; + /* fallthrough */ + case MG_EV_CONNECT: + if (req->retries == 0 || now - req->last_time >= req->timeout) { mg_send_dns_query(nc, req->name, req->query); req->last_time = now; req->retries++; @@ -13752,7 +13799,7 @@ static sock_t mg_open_listening_socket(struct mg_connection *nc, union socket_address *sa, int type, int proto); -void mg_set_non_blocking_mode(sock_t sock) { +static void mg_set_non_blocking_mode(sock_t sock) { SlSockNonblocking_t opt; #if SL_MAJOR_VERSION_NUM < 2 opt.NonblockingEnabled = 1; @@ -13766,17 +13813,19 @@ static int mg_is_error(int n) { return (n < 0 && n != SL_ERROR_BSD_EALREADY && n != SL_ERROR_BSD_EAGAIN); } -void mg_sl_if_connect_tcp(struct mg_connection *nc, - const union socket_address *sa) { +static void mg_sl_if_connect_tcp(struct mg_connection *nc, + const union socket_address *sa) { int proto = 0; +#if MG_ENABLE_SSL && MG_SSL_IF == MG_SSL_IF_SIMPLELINK if (nc->flags & MG_F_SSL) proto = SL_SEC_SOCKET; +#endif sock_t sock = sl_Socket(AF_INET, SOCK_STREAM, proto); if (sock < 0) { nc->err = sock; goto out; } mg_sock_set(nc, sock); -#if MG_ENABLE_SSL +#if MG_ENABLE_SSL && MG_SSL_IF == MG_SSL_IF_SIMPLELINK nc->err = sl_set_ssl_opts(sock, nc); if (nc->err != 0) goto out; #endif @@ -13786,7 +13835,7 @@ out: ntohs(sa->sin.sin_port), nc->sock, proto, nc->err)); } -void mg_sl_if_connect_udp(struct mg_connection *nc) { +static void mg_sl_if_connect_udp(struct mg_connection *nc) { sock_t sock = sl_Socket(AF_INET, SOCK_DGRAM, 0); if (sock < 0) { nc->err = sock; @@ -13796,7 +13845,8 @@ void mg_sl_if_connect_udp(struct mg_connection *nc) { nc->err = 0; } -int mg_sl_if_listen_tcp(struct mg_connection *nc, union socket_address *sa) { +static int mg_sl_if_listen_tcp(struct mg_connection *nc, + union socket_address *sa) { int proto = 0; if (nc->flags & MG_F_SSL) proto = SL_SEC_SOCKET; sock_t sock = mg_open_listening_socket(nc, sa, SOCK_STREAM, proto); @@ -13805,27 +13855,50 @@ int mg_sl_if_listen_tcp(struct mg_connection *nc, union socket_address *sa) { return 0; } -int mg_sl_if_listen_udp(struct mg_connection *nc, union socket_address *sa) { +static int mg_sl_if_listen_udp(struct mg_connection *nc, + union socket_address *sa) { sock_t sock = mg_open_listening_socket(nc, sa, SOCK_DGRAM, 0); if (sock == INVALID_SOCKET) return (errno ? errno : 1); mg_sock_set(nc, sock); return 0; } -void mg_sl_if_tcp_send(struct mg_connection *nc, const void *buf, size_t len) { - mbuf_append(&nc->send_mbuf, buf, len); +static int mg_sl_if_tcp_send(struct mg_connection *nc, const void *buf, + size_t len) { + int n = (int) sl_Send(nc->sock, buf, len, 0); + if (n < 0 && !mg_is_error(n)) n = 0; + return n; } -void mg_sl_if_udp_send(struct mg_connection *nc, const void *buf, size_t len) { - mbuf_append(&nc->send_mbuf, buf, len); +static int mg_sl_if_udp_send(struct mg_connection *nc, const void *buf, + size_t len) { + int n = sl_SendTo(nc->sock, buf, len, 0, &nc->sa.sa, sizeof(nc->sa.sin)); + if (n < 0 && !mg_is_error(n)) n = 0; + return n; } -void mg_sl_if_recved(struct mg_connection *nc, size_t len) { - (void) nc; - (void) len; +static int mg_sl_if_tcp_recv(struct mg_connection *nc, void *buf, size_t len) { + int n = sl_Recv(nc->sock, buf, len, 0); + if (n == 0) { + /* Orderly shutdown of the socket, try flushing output. */ + nc->flags |= MG_F_SEND_AND_CLOSE; + } else if (n < 0 && !mg_is_error(n)) { + n = 0; + } + return n; } -int mg_sl_if_create_conn(struct mg_connection *nc) { +static int mg_sl_if_udp_recv(struct mg_connection *nc, void *buf, size_t len, + union socket_address *sa, size_t *sa_len) { + SlSocklen_t sa_len_t = *sa_len; + int n = sl_RecvFrom(nc->sock, buf, MG_UDP_RECV_BUFFER_SIZE, 0, + (SlSockAddr_t *) sa, &sa_len_t); + *sa_len = sa_len_t; + if (n < 0 && !mg_is_error(n)) n = 0; + return n; +} + +static int mg_sl_if_create_conn(struct mg_connection *nc) { (void) nc; return 1; } @@ -13856,7 +13929,6 @@ static int mg_accept_conn(struct mg_connection *lc) { DBG(("%p conn from %s:%d", nc, inet_ntoa(sa.sin.sin_addr), ntohs(sa.sin.sin_port))); mg_sock_set(nc, sock); - if (nc->flags & MG_F_SSL) nc->flags |= MG_F_SSL_HANDSHAKE_DONE; mg_if_accept_tcp_cb(nc, &sa, sa_len); return 1; } @@ -13870,11 +13942,11 @@ static sock_t mg_open_listening_socket(struct mg_connection *nc, (sa->sa.sa_family == AF_INET) ? sizeof(sa->sin) : sizeof(sa->sin6); sock_t sock = sl_Socket(sa->sa.sa_family, type, proto); if (sock < 0) return sock; +#if MG_ENABLE_SSL && MG_SSL_IF == MG_SSL_IF_SIMPLELINK + if ((r = sl_set_ssl_opts(sock, nc)) < 0) goto clean; +#endif if ((r = sl_Bind(sock, &sa->sa, sa_len)) < 0) goto clean; if (type != SOCK_DGRAM) { -#if MG_ENABLE_SSL - if ((r = sl_set_ssl_opts(sock, nc)) < 0) goto clean; -#endif if ((r = sl_Listen(sock, SOMAXCONN)) < 0) goto clean; } mg_set_non_blocking_mode(sock); @@ -13886,86 +13958,18 @@ clean: return sock; } -static void mg_write_to_socket(struct mg_connection *nc) { - struct mbuf *io = &nc->send_mbuf; - int n = 0; - - if (nc->flags & MG_F_UDP) { - n = sl_SendTo(nc->sock, io->buf, io->len, 0, &nc->sa.sa, - sizeof(nc->sa.sin)); - DBG(("%p %d %d %d %s:%hu", nc, nc->sock, n, errno, - inet_ntoa(nc->sa.sin.sin_addr), ntohs(nc->sa.sin.sin_port))); - } else { - n = (int) sl_Send(nc->sock, io->buf, io->len, 0); - DBG(("%p %d bytes -> %d", nc, n, nc->sock)); - } - - if (n > 0) { - mg_if_sent_cb(nc, n); - } else if (n < 0 && mg_is_error(n)) { - /* Something went wrong, drop the connection. */ - nc->flags |= MG_F_CLOSE_IMMEDIATELY; - } -} - -MG_INTERNAL size_t recv_avail_size(struct mg_connection *conn, size_t max) { - size_t avail; - if (conn->recv_mbuf_limit < conn->recv_mbuf.len) return 0; - avail = conn->recv_mbuf_limit - conn->recv_mbuf.len; - return avail > max ? max : avail; -} - -static void mg_handle_tcp_read(struct mg_connection *conn) { - int n = 0; - char *buf = (char *) MG_MALLOC(MG_TCP_RECV_BUFFER_SIZE); - - if (buf == NULL) { - DBG(("OOM")); - return; - } - - n = (int) sl_Recv(conn->sock, buf, - recv_avail_size(conn, MG_TCP_RECV_BUFFER_SIZE), 0); - DBG(("%p %d bytes <- %d", conn, n, conn->sock)); - if (n > 0) { - mg_if_recv_tcp_cb(conn, buf, n, 1 /* own */); - } else { - MG_FREE(buf); - } - if (n == 0) { - /* Orderly shutdown of the socket, try flushing output. */ - conn->flags |= MG_F_SEND_AND_CLOSE; - } else if (mg_is_error(n)) { - conn->flags |= MG_F_CLOSE_IMMEDIATELY; - } -} - -static void mg_handle_udp_read(struct mg_connection *nc) { - char *buf = (char *) MG_MALLOC(MG_UDP_RECV_BUFFER_SIZE); - if (buf == NULL) return; - union socket_address sa; - socklen_t sa_len = sizeof(sa); - int n = sl_RecvFrom(nc->sock, buf, MG_UDP_RECV_BUFFER_SIZE, 0, - (SlSockAddr_t *) &sa, &sa_len); - DBG(("%p %d bytes from %s:%d", nc, n, inet_ntoa(nc->sa.sin.sin_addr), - ntohs(nc->sa.sin.sin_port))); - if (n > 0) { - mg_if_recv_udp_cb(nc, buf, n, &sa, sa_len); - } else { - MG_FREE(buf); - } -} - #define _MG_F_FD_CAN_READ 1 #define _MG_F_FD_CAN_WRITE 1 << 1 #define _MG_F_FD_ERROR 1 << 2 void mg_mgr_handle_conn(struct mg_connection *nc, int fd_flags, double now) { - DBG(("%p fd=%d fd_flags=%d nc_flags=%lu rmbl=%d smbl=%d", nc, nc->sock, + DBG(("%p fd=%d fd_flags=%d nc_flags=0x%lx rmbl=%d smbl=%d", nc, nc->sock, fd_flags, nc->flags, (int) nc->recv_mbuf.len, (int) nc->send_mbuf.len)); + if (!mg_if_poll(nc, now)) return; + if (nc->flags & MG_F_CONNECTING) { - if (nc->flags & MG_F_UDP || nc->err != SL_ERROR_BSD_EALREADY) { + if ((nc->flags & MG_F_UDP) || nc->err != SL_ERROR_BSD_EALREADY) { mg_if_connect_cb(nc, nc->err); } else { /* In SimpleLink, to get status of non-blocking connect() we need to wait @@ -13987,9 +13991,6 @@ void mg_mgr_handle_conn(struct mg_connection *nc, int fd_flags, double now) { ) { nc->err = 0; } - if (nc->flags & MG_F_SSL && nc->err == 0) { - nc->flags |= MG_F_SSL_HANDSHAKE_DONE; - } mg_if_connect_cb(nc, nc->err); } } @@ -13999,28 +14000,21 @@ void mg_mgr_handle_conn(struct mg_connection *nc, int fd_flags, double now) { if (fd_flags & _MG_F_FD_CAN_READ) { if (nc->flags & MG_F_UDP) { - mg_handle_udp_read(nc); + mg_if_can_recv_cb(nc); } else { if (nc->flags & MG_F_LISTENING) { mg_accept_conn(nc); } else { - mg_handle_tcp_read(nc); + mg_if_can_recv_cb(nc); } } } - if (!(nc->flags & MG_F_CLOSE_IMMEDIATELY)) { - if ((fd_flags & _MG_F_FD_CAN_WRITE) && nc->send_mbuf.len > 0) { - mg_write_to_socket(nc); - } - - if (!(fd_flags & (_MG_F_FD_CAN_READ | _MG_F_FD_CAN_WRITE))) { - mg_if_poll(nc, now); - } - mg_if_timer(nc, now); + if (fd_flags & _MG_F_FD_CAN_WRITE) { + mg_if_can_send_cb(nc); } - DBG(("%p after fd=%d nc_flags=%lu rmbl=%d smbl=%d", nc, nc->sock, nc->flags, + DBG(("%p after fd=%d nc_flags=0x%lx rmbl=%d smbl=%d", nc, nc->sock, nc->flags, (int) nc->recv_mbuf.len, (int) nc->send_mbuf.len)); } @@ -14141,14 +14135,6 @@ time_t mg_sl_if_poll(struct mg_iface *iface, int timeout_ms) { mg_mgr_handle_conn(nc, fd_flags, now); } - for (nc = mgr->active_connections; nc != NULL; nc = tmp) { - tmp = nc->next; - if ((nc->flags & MG_F_CLOSE_IMMEDIATELY) || - (nc->send_mbuf.len == 0 && (nc->flags & MG_F_SEND_AND_CLOSE))) { - mg_close_conn(nc); - } - } - return now; } @@ -14199,7 +14185,8 @@ void sl_restart_cb(struct mg_mgr *mgr) { mg_sl_if_connect_udp, \ mg_sl_if_tcp_send, \ mg_sl_if_udp_send, \ - mg_sl_if_recved, \ + mg_sl_if_tcp_recv, \ + mg_sl_if_udp_recv, \ mg_sl_if_create_conn, \ mg_sl_if_destroy_conn, \ mg_sl_if_sock_set, \ @@ -14272,6 +14259,31 @@ enum mg_ssl_if_result mg_ssl_if_conn_init( return MG_SSL_OK; } +enum mg_ssl_if_result mg_ssl_if_conn_accept(struct mg_connection *nc, + struct mg_connection *lc) { + /* SimpleLink does everything for us, nothing for us to do. */ + (void) nc; + (void) lc; + return MG_SSL_OK; +} + +enum mg_ssl_if_result mg_ssl_if_handshake(struct mg_connection *nc) { + /* SimpleLink has already performed the handshake, nothing to do. */ + return MG_SSL_OK; +} + +int mg_ssl_if_read(struct mg_connection *nc, void *buf, size_t len) { + /* SimpelLink handles TLS, so this is just a pass-through. */ + int n = nc->iface->vtable->tcp_recv(nc, buf, len); + if (n == 0) nc->flags |= MG_F_WANT_READ; + return n; +} + +int mg_ssl_if_write(struct mg_connection *nc, const void *buf, size_t len) { + /* SimpelLink handles TLS, so this is just a pass-through. */ + return nc->iface->vtable->tcp_send(nc, buf, len); +} + void mg_ssl_if_conn_close_notify(struct mg_connection *nc) { /* Nothing to do */ (void) nc; @@ -14372,56 +14384,59 @@ int sl_set_ssl_opts(int sock, struct mg_connection *nc) { const struct mg_ssl_if_ctx *ctx = (struct mg_ssl_if_ctx *) nc->ssl_if_data; DBG(("%p ssl ctx: %p", nc, ctx)); - if (ctx != NULL) { - DBG(("%p %s,%s,%s,%s", nc, (ctx->ssl_cert ? ctx->ssl_cert : "-"), - (ctx->ssl_key ? ctx->ssl_cert : "-"), - (ctx->ssl_ca_cert ? ctx->ssl_ca_cert : "-"), - (ctx->ssl_server_name ? ctx->ssl_server_name : "-"))); - if (ctx->ssl_cert != NULL && ctx->ssl_key != NULL) { - char *ssl_cert = sl_pem2der(ctx->ssl_cert); - char *ssl_key = sl_pem2der(ctx->ssl_key); - if (ssl_cert != NULL && ssl_key != NULL) { - err = sl_SetSockOpt(sock, SL_SOL_SOCKET, - SL_SO_SECURE_FILES_CERTIFICATE_FILE_NAME, ssl_cert, - strlen(ssl_cert)); - LOG(LL_INFO, ("CERTIFICATE_FILE_NAME %s -> %d", ssl_cert, err)); + if (ctx == NULL) return 0; + DBG(("%p %s,%s,%s,%s", nc, (ctx->ssl_cert ? ctx->ssl_cert : "-"), + (ctx->ssl_key ? ctx->ssl_cert : "-"), + (ctx->ssl_ca_cert ? ctx->ssl_ca_cert : "-"), + (ctx->ssl_server_name ? ctx->ssl_server_name : "-"))); + if (ctx->ssl_cert != NULL && ctx->ssl_key != NULL) { + char *ssl_cert = sl_pem2der(ctx->ssl_cert), *ssl_key = NULL; + if (ssl_cert != NULL) { + err = sl_SetSockOpt(sock, SL_SOL_SOCKET, + SL_SO_SECURE_FILES_CERTIFICATE_FILE_NAME, ssl_cert, + strlen(ssl_cert)); + MG_FREE(ssl_cert); + LOG(LL_DEBUG, ("CERTIFICATE_FILE_NAME %s -> %d", ssl_cert, err)); + ssl_key = sl_pem2der(ctx->ssl_key); + if (ssl_key != NULL) { err = sl_SetSockOpt(sock, SL_SOL_SOCKET, SL_SO_SECURE_FILES_PRIVATE_KEY_FILE_NAME, ssl_key, strlen(ssl_key)); - LOG(LL_INFO, ("PRIVATE_KEY_FILE_NAME %s -> %d", ssl_key, err)); + MG_FREE(ssl_key); + LOG(LL_DEBUG, ("PRIVATE_KEY_FILE_NAME %s -> %d", ssl_key, err)); } else { err = -1; } - MG_FREE(ssl_cert); - MG_FREE(ssl_key); + } else { + err = -1; + } + if (err != 0) return err; + } + if (ctx->ssl_ca_cert != NULL) { + if (ctx->ssl_ca_cert[0] != '\0') { + char *ssl_ca_cert = sl_pem2der(ctx->ssl_ca_cert); + if (ssl_ca_cert != NULL) { + err = + sl_SetSockOpt(sock, SL_SOL_SOCKET, SL_SO_SECURE_FILES_CA_FILE_NAME, + ssl_ca_cert, strlen(ssl_ca_cert)); + LOG(LL_DEBUG, ("CA_FILE_NAME %s -> %d", ssl_ca_cert, err)); + } else { + err = -1; + } + MG_FREE(ssl_ca_cert); if (err != 0) return err; } - if (ctx->ssl_ca_cert != NULL) { - if (ctx->ssl_ca_cert[0] != '\0') { - char *ssl_ca_cert = sl_pem2der(ctx->ssl_ca_cert); - if (ssl_ca_cert != NULL) { - err = sl_SetSockOpt(sock, SL_SOL_SOCKET, - SL_SO_SECURE_FILES_CA_FILE_NAME, ssl_ca_cert, - strlen(ssl_ca_cert)); - LOG(LL_INFO, ("CA_FILE_NAME %s -> %d", ssl_ca_cert, err)); - } else { - err = -1; - } - MG_FREE(ssl_ca_cert); - if (err != 0) return err; - } - } - if (ctx->ssl_server_name != NULL) { - err = sl_SetSockOpt(sock, SL_SOL_SOCKET, - SL_SO_SECURE_DOMAIN_NAME_VERIFICATION, - ctx->ssl_server_name, strlen(ctx->ssl_server_name)); - DBG(("DOMAIN_NAME_VERIFICATION %s -> %d", ctx->ssl_server_name, err)); - /* Domain name verificationw as added in a NWP service pack, older - * versions return SL_ERROR_BSD_ENOPROTOOPT. There isn't much we can do - * about it, - * so we ignore the error. */ - if (err != 0 && err != SL_ERROR_BSD_ENOPROTOOPT) return err; - } + } + if (ctx->ssl_server_name != NULL) { + err = sl_SetSockOpt(sock, SL_SOL_SOCKET, + SL_SO_SECURE_DOMAIN_NAME_VERIFICATION, + ctx->ssl_server_name, strlen(ctx->ssl_server_name)); + DBG(("DOMAIN_NAME_VERIFICATION %s -> %d", ctx->ssl_server_name, err)); + /* Domain name verificationw as added in a NWP service pack, older + * versions return SL_ERROR_BSD_ENOPROTOOPT. There isn't much we can do + * about it, + * so we ignore the error. */ + if (err != 0 && err != SL_ERROR_BSD_ENOPROTOOPT) return err; } return 0; } @@ -14462,9 +14477,9 @@ struct mg_lwip_conn_state { /* Last SSL write size, for retries. */ int last_ssl_write_size; /* Whether MG_SIG_RECV is already pending for this connection */ - int recv_pending : 1; + int recv_pending; /* Whether the connection is about to close, just `rx_chain` needs to drain */ - int draining_rx_chain : 1; + int draining_rx_chain; }; enum mg_sig_type { @@ -14545,10 +14560,6 @@ void mg_lwip_mgr_schedule_poll(struct mg_mgr *mgr); typedef void (*tcpip_callback_fn)(void *arg); #endif -void mg_lwip_ssl_do_hs(struct mg_connection *nc); -void mg_lwip_ssl_send(struct mg_connection *nc); -void mg_lwip_ssl_recv(struct mg_connection *nc); - void mg_lwip_if_init(struct mg_iface *iface); void mg_lwip_if_free(struct mg_iface *iface); void mg_lwip_if_add_conn(struct mg_connection *nc); @@ -14620,10 +14631,12 @@ static void mg_lwip_tcp_error_cb(void *arg, err_t err) { static err_t mg_lwip_tcp_recv_cb(void *arg, struct tcp_pcb *tpcb, struct pbuf *p, err_t err) { struct mg_connection *nc = (struct mg_connection *) arg; - DBG(("%p %p %u %d", nc, tpcb, (p != NULL ? p->tot_len : 0), err)); + struct mg_lwip_conn_state *cs = + (nc ? (struct mg_lwip_conn_state *) nc->sock : NULL); + DBG(("%p %p %p %p %u %d", nc, cs, tpcb, p, (p != NULL ? p->tot_len : 0), + err)); if (p == NULL) { if (nc != NULL && !(nc->flags & MG_F_CLOSE_IMMEDIATELY)) { - struct mg_lwip_conn_state *cs = (struct mg_lwip_conn_state *) nc->sock; if (cs->rx_chain != NULL) { /* * rx_chain still contains non-consumed data, don't close the @@ -14641,7 +14654,6 @@ static err_t mg_lwip_tcp_recv_cb(void *arg, struct tcp_pcb *tpcb, tcp_abort(tpcb); return ERR_ARG; } - struct mg_lwip_conn_state *cs = (struct mg_lwip_conn_state *) nc->sock; /* * If we get a chain of more than one segment at once, we need to bump * refcount on the subsequent bufs to make them independent. @@ -14656,7 +14668,7 @@ static err_t mg_lwip_tcp_recv_cb(void *arg, struct tcp_pcb *tpcb, } else if (pbuf_clen(cs->rx_chain) >= 4) { /* ESP SDK has a limited pool of 5 pbufs. We must not hog them all or RX * will be completely blocked. We already have at least 4 in the chain, - * this one is, so we have to make a copy and release this one. */ + * this one is the last, so we have to make a copy and release this one. */ struct pbuf *np = pbuf_alloc(PBUF_RAW, p->tot_len, PBUF_RAM); if (np != NULL) { pbuf_copy(np, p); @@ -14664,58 +14676,9 @@ static err_t mg_lwip_tcp_recv_cb(void *arg, struct tcp_pcb *tpcb, p = np; } } - mgos_unlock(); mg_lwip_recv_common(nc, p); - return ERR_OK; -} - -static void mg_lwip_consume_rx_chain_tcp(struct mg_connection *nc) { - struct mg_lwip_conn_state *cs = (struct mg_lwip_conn_state *) nc->sock; - if (cs->rx_chain == NULL) return; -#if MG_ENABLE_SSL - if (nc->flags & MG_F_SSL) { - if (nc->flags & MG_F_SSL_HANDSHAKE_DONE) { - mg_lwip_ssl_recv(nc); - } else { - mg_lwip_ssl_do_hs(nc); - } - return; - } -#endif - mgos_lock(); - while (cs->rx_chain != NULL && nc->recv_mbuf.len < nc->recv_mbuf_limit) { - struct pbuf *seg = cs->rx_chain; - - size_t seg_len = (seg->len - cs->rx_offset); - size_t buf_avail = (nc->recv_mbuf_limit - nc->recv_mbuf.len); - size_t len = MIN(seg_len, buf_avail); - - char *data = (char *) MG_MALLOC(len); - if (data == NULL) { - mgos_unlock(); - DBG(("OOM")); - return; - } - pbuf_copy_partial(seg, data, len, cs->rx_offset); - cs->rx_offset += len; - if (cs->rx_offset == cs->rx_chain->len) { - cs->rx_chain = pbuf_dechain(cs->rx_chain); - pbuf_free(seg); - cs->rx_offset = 0; - } - mgos_unlock(); - mg_if_recv_tcp_cb(nc, data, len, 1 /* own */); - mgos_lock(); - } mgos_unlock(); -} - -static void mg_lwip_handle_recv_tcp(struct mg_connection *nc) { - mg_lwip_consume_rx_chain_tcp(nc); - - if (nc->send_mbuf.len > 0) { - mg_lwip_mgr_schedule_poll(nc->mgr); - } + return ERR_OK; } static err_t mg_lwip_tcp_sent_cb(void *arg, struct tcp_pcb *tpcb, @@ -14801,13 +14764,14 @@ static void mg_lwip_udp_recv_cb(void *arg, struct udp_pcb *pcb, struct pbuf *p, /* Logic in the recv handler requires that there be exactly one data pbuf. */ p = pbuf_coalesce(p, PBUF_RAW); pbuf_chain(sap, p); + mgos_lock(); mg_lwip_recv_common(nc, sap); + mgos_unlock(); (void) pcb; } static void mg_lwip_recv_common(struct mg_connection *nc, struct pbuf *p) { struct mg_lwip_conn_state *cs = (struct mg_lwip_conn_state *) nc->sock; - mgos_lock(); if (cs->rx_chain == NULL) { cs->rx_chain = p; } else { @@ -14817,32 +14781,30 @@ static void mg_lwip_recv_common(struct mg_connection *nc, struct pbuf *p) { cs->recv_pending = 1; mg_lwip_post_signal(MG_SIG_RECV, nc); } - mgos_unlock(); } -static void mg_lwip_handle_recv_udp(struct mg_connection *nc) { - struct mg_lwip_conn_state *cs = (struct mg_lwip_conn_state *) nc->sock; +static int mg_lwip_if_udp_recv(struct mg_connection *nc, void *buf, size_t len, + union socket_address *sa, size_t *sa_len) { /* * For UDP, RX chain consists of interleaved address and packet bufs: * Address pbuf followed by exactly one data pbuf (recv_cb took care of that). */ - while (cs->rx_chain != NULL) { - struct pbuf *sap = cs->rx_chain; - struct pbuf *p = sap->next; - cs->rx_chain = pbuf_dechain(p); - size_t data_len = p->len; - char *data = (char *) MG_MALLOC(data_len); - if (data != NULL) { - pbuf_copy_partial(p, data, data_len, 0); - pbuf_free(p); - mg_if_recv_udp_cb(nc, data, data_len, - (union socket_address *) sap->payload, sap->len); - pbuf_free(sap); - } else { - pbuf_free(p); - pbuf_free(sap); - } + int res = 0; + struct mg_lwip_conn_state *cs = (struct mg_lwip_conn_state *) nc->sock; + if (nc->sock == INVALID_SOCKET) return -1; + mgos_lock(); + if (cs->rx_chain != NULL) { + struct pbuf *ap = cs->rx_chain; + struct pbuf *dp = ap->next; + cs->rx_chain = pbuf_dechain(dp); + res = MIN(dp->len, len); + pbuf_copy_partial(dp, buf, res, 0); + pbuf_free(dp); + pbuf_copy_partial(ap, sa, MIN(*sa_len, ap->len), 0); + pbuf_free(ap); } + mgos_unlock(); + return res; } static void mg_lwip_if_connect_udp_tcpip(void *arg) { @@ -14864,13 +14826,6 @@ void mg_lwip_if_connect_udp(struct mg_connection *nc) { tcpip_callback(mg_lwip_if_connect_udp_tcpip, nc); } -void mg_lwip_accept_conn(struct mg_connection *nc, struct tcp_pcb *tpcb) { - union socket_address sa; - SET_ADDR(&sa, &tpcb->remote_ip); - sa.sin.sin_port = htons(tpcb->remote_port); - mg_if_accept_tcp_cb(nc, &sa, sizeof(sa.sin)); -} - static void tcp_close_tcpip(void *arg) { tcp_close((struct tcp_pcb *) arg); } @@ -14878,17 +14833,11 @@ static void tcp_close_tcpip(void *arg) { void mg_lwip_handle_accept(struct mg_connection *nc) { struct mg_lwip_conn_state *cs = (struct mg_lwip_conn_state *) nc->sock; if (cs->pcb.tcp == NULL) return; -#if MG_ENABLE_SSL - if (cs->lc->flags & MG_F_SSL) { - if (mg_ssl_if_conn_accept(nc, cs->lc) != MG_SSL_OK) { - LOG(LL_ERROR, ("SSL error")); - tcpip_callback(tcp_close_tcpip, cs->pcb.tcp); - } - } else -#endif - { - mg_lwip_accept_conn(nc, cs->pcb.tcp); - } + union socket_address sa; + struct tcp_pcb *tpcb = cs->pcb.tcp; + SET_ADDR(&sa, &tpcb->remote_ip); + sa.sin.sin_port = htons(tpcb->remote_port); + mg_if_accept_tcp_cb(nc, &sa, sizeof(sa.sin)); } static err_t mg_lwip_accept_cb(void *arg, struct tcp_pcb *newtpcb, err_t err) { @@ -15045,14 +14994,13 @@ static void mg_lwip_tcp_write_tcpip(void *arg) { ctx->ret = len; } -static int mg_lwip_tcp_write(struct mg_connection *nc, const void *data, - uint16_t len) { - struct mg_lwip_tcp_write_ctx ctx = {.nc = nc, .data = data, .len = len}; +int mg_lwip_if_tcp_send(struct mg_connection *nc, const void *buf, size_t len) { + struct mg_lwip_tcp_write_ctx ctx = {.nc = nc, .data = buf, .len = len}; struct mg_lwip_conn_state *cs = (struct mg_lwip_conn_state *) nc->sock; + if (nc->sock == INVALID_SOCKET) return -1; struct tcp_pcb *tpcb = cs->pcb.tcp; - if (tpcb == NULL) { - return -1; - } + if (tpcb == NULL) return -1; + if (tpcb->snd_buf <= 0) return 0; tcpip_callback(mg_lwip_tcp_write_tcpip, &ctx); return ctx.ret; } @@ -15070,18 +15018,10 @@ static void udp_sendto_tcpip(void *arg) { ctx->ret = udp_sendto(ctx->upcb, ctx->p, ctx->ip, ctx->port); } -static int mg_lwip_udp_send(struct mg_connection *nc, const void *data, - uint16_t len) { +static int mg_lwip_if_udp_send(struct mg_connection *nc, const void *data, + size_t len) { struct mg_lwip_conn_state *cs = (struct mg_lwip_conn_state *) nc->sock; - if (cs->pcb.udp == NULL) { - /* - * In case of UDP, this usually means, what - * async DNS resolve is still in progress and connection - * is not ready yet - */ - DBG(("%p socket is not connected", nc)); - return -1; - } + if (nc->sock == INVALID_SOCKET || cs->pcb.udp == NULL) return -1; struct udp_pcb *upcb = cs->pcb.udp; struct pbuf *p = pbuf_alloc(PBUF_TRANSPORT, len, PBUF_RAM); #if defined(LWIP_IPV4) && LWIP_IPV4 && defined(LWIP_IPV6) && LWIP_IPV6 @@ -15090,46 +15030,28 @@ static int mg_lwip_udp_send(struct mg_connection *nc, const void *data, ip_addr_t ip = {.addr = nc->sa.sin.sin_addr.s_addr}; #endif u16_t port = ntohs(nc->sa.sin.sin_port); - if (p == NULL) { - DBG(("OOM")); - return 0; - } + if (p == NULL) return 0; memcpy(p->payload, data, len); struct udp_sendto_ctx ctx = {.upcb = upcb, .p = p, .ip = &ip, .port = port}; tcpip_callback(udp_sendto_tcpip, &ctx); cs->err = ctx.ret; pbuf_free(p); - return (cs->err == ERR_OK ? len : -1); + return (cs->err == ERR_OK ? (int) len : -2); } -static void mg_lwip_send_more(struct mg_connection *nc) { - int num_sent = 0; - if (nc->sock == INVALID_SOCKET) return; - if (nc->flags & MG_F_UDP) { - num_sent = mg_lwip_udp_send(nc, nc->send_mbuf.buf, nc->send_mbuf.len); - DBG(("%p mg_lwip_udp_send %u = %d", nc, nc->send_mbuf.len, num_sent)); - } else { - num_sent = mg_lwip_tcp_write(nc, nc->send_mbuf.buf, nc->send_mbuf.len); - DBG(("%p mg_lwip_tcp_write %u = %d", nc, nc->send_mbuf.len, num_sent)); +static int mg_lwip_if_can_send(struct mg_connection *nc, + struct mg_lwip_conn_state *cs) { + int can_send = 0; + if (nc->send_mbuf.len > 0 || (nc->flags & MG_F_WANT_WRITE)) { + /* We have stuff to send, but can we? */ + if (nc->flags & MG_F_UDP) { + /* UDP is always ready for sending. */ + can_send = (cs->pcb.udp != NULL); + } else { + can_send = (cs->pcb.tcp != NULL && cs->pcb.tcp->snd_buf > 0); + } } - if (num_sent == 0) return; - if (num_sent > 0) { - mg_if_sent_cb(nc, num_sent); - } else { - mg_lwip_post_signal(MG_SIG_CLOSE_CONN, nc); - } -} - -void mg_lwip_if_tcp_send(struct mg_connection *nc, const void *buf, - size_t len) { - mbuf_append(&nc->send_mbuf, buf, len); - mg_lwip_mgr_schedule_poll(nc->mgr); -} - -void mg_lwip_if_udp_send(struct mg_connection *nc, const void *buf, - size_t len) { - mbuf_append(&nc->send_mbuf, buf, len); - mg_lwip_mgr_schedule_poll(nc->mgr); + return can_send; } struct tcp_recved_ctx { @@ -15142,27 +15064,35 @@ void tcp_recved_tcpip(void *arg) { tcp_recved(ctx->tpcb, ctx->len); } -void mg_lwip_if_recved(struct mg_connection *nc, size_t len) { - if (nc->flags & MG_F_UDP) return; +static int mg_lwip_if_tcp_recv(struct mg_connection *nc, void *buf, + size_t len) { + int res = 0; + char *bufp = buf; struct mg_lwip_conn_state *cs = (struct mg_lwip_conn_state *) nc->sock; - if (nc->sock == INVALID_SOCKET || cs->pcb.tcp == NULL) { - DBG(("%p invalid socket", nc)); - return; + if (nc->sock == INVALID_SOCKET) return -1; + mgos_lock(); + while (cs->rx_chain != NULL && len > 0) { + struct pbuf *seg = cs->rx_chain; + size_t seg_len = (seg->len - cs->rx_offset); + size_t copy_len = MIN(len, seg_len); + + pbuf_copy_partial(seg, bufp, copy_len, cs->rx_offset); + len -= copy_len; + res += copy_len; + bufp += copy_len; + cs->rx_offset += copy_len; + if (cs->rx_offset == cs->rx_chain->len) { + cs->rx_chain = pbuf_dechain(cs->rx_chain); + pbuf_free(seg); + cs->rx_offset = 0; + } } - DBG(("%p %p %u %u", nc, cs->pcb.tcp, len, - (cs->rx_chain ? cs->rx_chain->tot_len : 0))); - struct tcp_recved_ctx ctx = {.tpcb = cs->pcb.tcp, .len = len}; -#if MG_ENABLE_SSL - if (!(nc->flags & MG_F_SSL)) { + mgos_unlock(); + if (res > 0) { + struct tcp_recved_ctx ctx = {.tpcb = cs->pcb.tcp, .len = res}; tcpip_callback(tcp_recved_tcpip, &ctx); - } else { - /* Currently SSL acknowledges data immediately. - * TODO(rojer): Find a way to propagate mg_lwip_if_recved. */ } -#else - tcpip_callback(tcp_recved_tcpip, &ctx); -#endif - mbuf_trim(&nc->recv_mbuf); + return res; } int mg_lwip_if_create_conn(struct mg_connection *nc) { @@ -15251,7 +15181,8 @@ void mg_lwip_if_sock_set(struct mg_connection *nc, sock_t sock) { mg_lwip_if_connect_udp, \ mg_lwip_if_tcp_send, \ mg_lwip_if_udp_send, \ - mg_lwip_if_recved, \ + mg_lwip_if_tcp_recv, \ + mg_lwip_if_udp_recv, \ mg_lwip_if_create_conn, \ mg_lwip_if_destroy_conn, \ mg_lwip_if_sock_set, \ @@ -15320,15 +15251,7 @@ void mg_ev_mgr_lwip_process_signals(struct mg_mgr *mgr) { if (nc->iface == NULL || nc->mgr == NULL) continue; switch (sig) { case MG_SIG_CONNECT_RESULT: { -#if MG_ENABLE_SSL - if (cs->err == 0 && (nc->flags & MG_F_SSL) && - !(nc->flags & MG_F_SSL_HANDSHAKE_DONE)) { - mg_lwip_ssl_do_hs(nc); - } else -#endif - { - mg_if_connect_cb(nc, cs->err); - } + mg_if_connect_cb(nc, cs->err); break; } case MG_SIG_CLOSE_CONN: { @@ -15338,11 +15261,8 @@ void mg_ev_mgr_lwip_process_signals(struct mg_mgr *mgr) { } case MG_SIG_RECV: { cs->recv_pending = 0; - if (nc->flags & MG_F_UDP) { - mg_lwip_handle_recv_udp(nc); - } else { - mg_lwip_handle_recv_tcp(nc); - } + mg_if_can_recv_cb(nc); + mbuf_trim(&nc->recv_mbuf); break; } case MG_SIG_TOMBSTONE: { @@ -15357,7 +15277,8 @@ void mg_ev_mgr_lwip_process_signals(struct mg_mgr *mgr) { } void mg_lwip_if_init(struct mg_iface *iface) { - LOG(LL_INFO, ("%p Mongoose init", iface)); + LOG(LL_INFO, ("Mongoose %s, LwIP %u.%u.%u", MG_VERSION, LWIP_VERSION_MAJOR, + LWIP_VERSION_MINOR, LWIP_VERSION_REVISION)); iface->data = MG_CALLOC(1, sizeof(struct mg_ev_mgr_lwip_data)); } @@ -15396,42 +15317,7 @@ time_t mg_lwip_if_poll(struct mg_iface *iface, int timeout_ms) { struct mg_lwip_conn_state *cs = (struct mg_lwip_conn_state *) nc->sock; tmp = nc->next; n++; - if ((nc->flags & MG_F_CLOSE_IMMEDIATELY) || - ((nc->flags & MG_F_SEND_AND_CLOSE) && (nc->flags & MG_F_UDP) && - (nc->send_mbuf.len == 0))) { - mg_close_conn(nc); - continue; - } - mg_if_poll(nc, now); - mg_if_timer(nc, now); -#if MG_ENABLE_SSL - if ((nc->flags & MG_F_SSL) && cs != NULL && cs->pcb.tcp != NULL && - cs->pcb.tcp->state == ESTABLISHED) { - if (((nc->flags & MG_F_WANT_WRITE) || - ((nc->send_mbuf.len > 0) && - (nc->flags & MG_F_SSL_HANDSHAKE_DONE))) && - cs->pcb.tcp->snd_buf > 0) { - /* Can write more. */ - if (nc->flags & MG_F_SSL_HANDSHAKE_DONE) { - if (!(nc->flags & MG_F_CONNECTING)) mg_lwip_ssl_send(nc); - } else { - mg_lwip_ssl_do_hs(nc); - } - } - if (cs->rx_chain != NULL || (nc->flags & MG_F_WANT_READ)) { - if (nc->flags & MG_F_SSL_HANDSHAKE_DONE) { - if (!(nc->flags & MG_F_CONNECTING)) mg_lwip_ssl_recv(nc); - } else { - mg_lwip_ssl_do_hs(nc); - } - } - } else -#endif /* MG_ENABLE_SSL */ - { - if (nc->send_mbuf.len > 0 && !(nc->flags & MG_F_CONNECTING)) { - mg_lwip_send_more(nc); - } - } + if (!mg_if_poll(nc, now)) continue; if (nc->sock != INVALID_SOCKET && !(nc->flags & (MG_F_UDP | MG_F_LISTENING)) && cs->pcb.tcp != NULL && cs->pcb.tcp->unsent != NULL) { @@ -15445,14 +15331,17 @@ time_t mg_lwip_if_poll(struct mg_iface *iface, int timeout_ms) { } if (nc->sock != INVALID_SOCKET) { - /* Try to consume data from cs->rx_chain */ - mg_lwip_consume_rx_chain_tcp(nc); - - /* - * If the connection is about to close, and rx_chain is finally empty, - * send the MG_SIG_CLOSE_CONN signal - */ - if (cs->draining_rx_chain && cs->rx_chain == NULL) { + if (mg_lwip_if_can_send(nc, cs)) { + mg_if_can_send_cb(nc); + mbuf_trim(&nc->send_mbuf); + } + if (cs->rx_chain != NULL) { + mg_if_can_recv_cb(nc); + } else if (cs->draining_rx_chain) { + /* + * If the connection is about to close, and rx_chain is finally empty, + * send the MG_SIG_CLOSE_CONN signal + */ mg_lwip_post_signal(MG_SIG_CLOSE_CONN, nc); } } @@ -15480,21 +15369,9 @@ uint32_t mg_lwip_get_poll_delay_ms(struct mg_mgr *mgr) { } num_timers++; } - if (nc->send_mbuf.len > 0 -#if MG_ENABLE_SSL - || (nc->flags & MG_F_WANT_WRITE) -#endif - ) { - int can_send = 0; - /* We have stuff to send, but can we? */ - if (nc->flags & MG_F_UDP) { - /* UDP is always ready for sending. */ - can_send = (cs->pcb.udp != NULL); - } else { - can_send = (cs->pcb.tcp != NULL && cs->pcb.tcp->snd_buf > 0); - } - /* We want and can send, request a poll immediately. */ - if (can_send) return 0; + /* We want and can send data, request a poll immediately. */ + if (nc->sock != INVALID_SOCKET && mg_lwip_if_can_send(nc, cs)) { + return 0; } } uint32_t timeout_ms = ~0; @@ -15512,206 +15389,6 @@ uint32_t mg_lwip_get_poll_delay_ms(struct mg_mgr *mgr) { #endif /* MG_NET_IF == MG_NET_IF_LWIP_LOW_LEVEL */ #ifdef MG_MODULE_LINES -#line 1 "common/platforms/lwip/mg_lwip_ssl_if.c" -#endif -/* - * Copyright (c) 2014-2016 Cesanta Software Limited - * All rights reserved - */ - -#if MG_ENABLE_SSL && MG_NET_IF == MG_NET_IF_LWIP_LOW_LEVEL - -/* Amalgamated: #include "common/mg_mem.h" */ -/* Amalgamated: #include "common/cs_dbg.h" */ - -#include -#include - -#ifndef MG_LWIP_SSL_IO_SIZE -#define MG_LWIP_SSL_IO_SIZE 1024 -#endif - -#ifndef MIN -#define MIN(a, b) ((a) < (b) ? (a) : (b)) -#endif - -void mg_lwip_ssl_do_hs(struct mg_connection *nc) { - struct mg_lwip_conn_state *cs = (struct mg_lwip_conn_state *) nc->sock; - int server_side = (nc->listener != NULL); - enum mg_ssl_if_result res; - if (nc->flags & MG_F_CLOSE_IMMEDIATELY) return; - res = mg_ssl_if_handshake(nc); - DBG(("%p %lu %d %d", nc, nc->flags, server_side, res)); - if (res != MG_SSL_OK) { - if (res == MG_SSL_WANT_WRITE) { - nc->flags |= MG_F_WANT_WRITE; - cs->err = 0; - } else if (res == MG_SSL_WANT_READ) { - /* - * Nothing to do in particular, we are callback-driven. - * What we definitely do not need anymore is SSL reading (nothing left). - */ - nc->flags &= ~MG_F_WANT_READ; - cs->err = 0; - } else { - cs->err = res; - if (server_side) { - mg_lwip_post_signal(MG_SIG_CLOSE_CONN, nc); - } else { - mg_lwip_post_signal(MG_SIG_CONNECT_RESULT, nc); - } - } - } else { - cs->err = 0; - nc->flags &= ~MG_F_WANT_WRITE; - /* - * Handshake is done. Schedule a read immediately to consume app data - * which may already be waiting. - */ - nc->flags |= (MG_F_SSL_HANDSHAKE_DONE | MG_F_WANT_READ); - if (server_side) { - mg_lwip_accept_conn(nc, cs->pcb.tcp); - } else { - mg_lwip_post_signal(MG_SIG_CONNECT_RESULT, nc); - } - } -} - -void mg_lwip_ssl_send(struct mg_connection *nc) { - if (nc->sock == INVALID_SOCKET) { - DBG(("%p invalid socket", nc)); - return; - } - struct mg_lwip_conn_state *cs = (struct mg_lwip_conn_state *) nc->sock; - /* It's ok if the buffer is empty. Return value of 0 may also be valid. */ - int len = cs->last_ssl_write_size; - if (len == 0) { - len = MIN(MG_LWIP_SSL_IO_SIZE, nc->send_mbuf.len); - } - int ret = mg_ssl_if_write(nc, nc->send_mbuf.buf, len); - DBG(("%p SSL_write %u = %d", nc, len, ret)); - if (ret > 0) { - mg_if_sent_cb(nc, ret); - cs->last_ssl_write_size = 0; - } else if (ret < 0) { - /* This is tricky. We must remember the exact data we were sending to retry - * exactly the same send next time. */ - cs->last_ssl_write_size = len; - } - if (ret == len) { - nc->flags &= ~MG_F_WANT_WRITE; - } else if (ret == MG_SSL_WANT_WRITE) { - nc->flags |= MG_F_WANT_WRITE; - } else { - mg_lwip_post_signal(MG_SIG_CLOSE_CONN, nc); - } -} - -void mg_lwip_ssl_recv(struct mg_connection *nc) { - struct mg_lwip_conn_state *cs = (struct mg_lwip_conn_state *) nc->sock; - /* Don't deliver data before connect callback */ - if (nc->flags & MG_F_CONNECTING) return; - while (nc->recv_mbuf.len < nc->recv_mbuf_limit) { - char *buf = (char *) MG_MALLOC(MG_LWIP_SSL_IO_SIZE); - if (buf == NULL) return; - int ret = mg_ssl_if_read(nc, buf, MG_LWIP_SSL_IO_SIZE); - DBG(("%p %p SSL_read %u = %d", nc, cs->rx_chain, MG_LWIP_SSL_IO_SIZE, ret)); - if (ret <= 0) { - MG_FREE(buf); - if (ret == MG_SSL_WANT_WRITE) { - nc->flags |= MG_F_WANT_WRITE; - return; - } else if (ret == MG_SSL_WANT_READ) { - /* - * Nothing to do in particular, we are callback-driven. - * What we definitely do not need anymore is SSL reading (nothing left). - */ - nc->flags &= ~MG_F_WANT_READ; - cs->err = 0; - return; - } else { - mg_lwip_post_signal(MG_SIG_CLOSE_CONN, nc); - return; - } - } else { - mg_if_recv_tcp_cb(nc, buf, ret, 1 /* own */); - } - } -} - -#ifdef KR_VERSION - -ssize_t kr_send(int fd, const void *buf, size_t len) { - struct mg_lwip_conn_state *cs = (struct mg_lwip_conn_state *) fd; - int ret = mg_lwip_tcp_write(cs->nc, buf, len); - DBG(("%p mg_lwip_tcp_write %u = %d", cs->nc, len, ret)); - if (ret == 0) ret = KR_IO_WOULDBLOCK; - return ret; -} - -ssize_t kr_recv(int fd, void *buf, size_t len) { - struct mg_lwip_conn_state *cs = (struct mg_lwip_conn_state *) fd; - struct pbuf *seg = cs->rx_chain; - if (seg == NULL) { - DBG(("%u - nothing to read", len)); - return KR_IO_WOULDBLOCK; - } - size_t seg_len = (seg->len - cs->rx_offset); - DBG(("%u %u %u %u", len, cs->rx_chain->len, seg_len, cs->rx_chain->tot_len)); - len = MIN(len, seg_len); - pbuf_copy_partial(seg, buf, len, cs->rx_offset); - cs->rx_offset += len; - tcp_recved(cs->pcb.tcp, len); - if (cs->rx_offset == cs->rx_chain->len) { - cs->rx_chain = pbuf_dechain(cs->rx_chain); - pbuf_free(seg); - cs->rx_offset = 0; - } - return len; -} - -#elif MG_SSL_IF == MG_SSL_IF_MBEDTLS - -int ssl_socket_send(void *ctx, const unsigned char *buf, size_t len) { - struct mg_connection *nc = (struct mg_connection *) ctx; - struct mg_lwip_conn_state *cs = (struct mg_lwip_conn_state *) nc->sock; - int ret = mg_lwip_tcp_write(cs->nc, buf, len); - if (ret == 0) ret = MBEDTLS_ERR_SSL_WANT_WRITE; - LOG(LL_DEBUG, ("%p %d -> %d", nc, len, ret)); - return ret; -} - -int ssl_socket_recv(void *ctx, unsigned char *buf, size_t len) { - struct mg_connection *nc = (struct mg_connection *) ctx; - struct mg_lwip_conn_state *cs = (struct mg_lwip_conn_state *) nc->sock; - struct pbuf *seg = cs->rx_chain; - if (seg == NULL) { - DBG(("%u - nothing to read", len)); - return MBEDTLS_ERR_SSL_WANT_READ; - } - size_t seg_len = (seg->len - cs->rx_offset); - DBG(("%u %u %u %u", len, cs->rx_chain->len, seg_len, cs->rx_chain->tot_len)); - mgos_lock(); - len = MIN(len, seg_len); - pbuf_copy_partial(seg, buf, len, cs->rx_offset); - cs->rx_offset += len; - /* TCP PCB may be NULL if connection has already been closed - * but we still have data to deliver to SSL. */ - if (cs->pcb.tcp != NULL) tcp_recved(cs->pcb.tcp, len); - if (cs->rx_offset == cs->rx_chain->len) { - cs->rx_chain = pbuf_dechain(cs->rx_chain); - pbuf_free(seg); - cs->rx_offset = 0; - } - mgos_unlock(); - LOG(LL_DEBUG, ("%p <- %d", nc, (int) len)); - return len; -} - -#endif - -#endif /* MG_ENABLE_SSL && MG_NET_IF == MG_NET_IF_LWIP_LOW_LEVEL */ -#ifdef MG_MODULE_LINES #line 1 "common/platforms/wince/wince_libc.c" #endif /* diff --git a/mongoose.h b/mongoose.h index c668594a..e9b1fb17 100644 --- a/mongoose.h +++ b/mongoose.h @@ -3245,10 +3245,12 @@ struct mg_iface_vtable { void (*connect_udp)(struct mg_connection *nc); /* Send functions for TCP and UDP. Sent data is copied before return. */ - void (*tcp_send)(struct mg_connection *nc, const void *buf, size_t len); - void (*udp_send)(struct mg_connection *nc, const void *buf, size_t len); + int (*tcp_send)(struct mg_connection *nc, const void *buf, size_t len); + int (*udp_send)(struct mg_connection *nc, const void *buf, size_t len); - void (*recved)(struct mg_connection *nc, size_t len); + int (*tcp_recv)(struct mg_connection *nc, void *buf, size_t len); + int (*udp_recv)(struct mg_connection *nc, void *buf, size_t len, + union socket_address *sa, size_t *sa_len); /* Perform interface-related connection initialization. Return 1 on ok. */ int (*create_conn)(struct mg_connection *nc); @@ -3289,19 +3291,15 @@ void mg_if_accept_tcp_cb(struct mg_connection *nc, union socket_address *sa, /* Callback invoked by connect methods. err = 0 -> ok, != 0 -> error. */ void mg_if_connect_cb(struct mg_connection *nc, int err); -/* Callback that reports that data has been put on the wire. */ -void mg_if_sent_cb(struct mg_connection *nc, int num_sent); /* - * Receive callback. - * if `own` is true, buf must be heap-allocated and ownership is transferred - * to the core. - * Core will acknowledge consumption by calling iface::recved. + * Callback that tells the core that data can be received. + * Core will use tcp/udp_recv to retrieve the data. */ -void mg_if_recv_tcp_cb(struct mg_connection *nc, void *buf, int len, int own); +void mg_if_can_recv_cb(struct mg_connection *nc); +void mg_if_can_send_cb(struct mg_connection *nc); /* * Receive callback. * buf must be heap-allocated and ownership is transferred to the core. - * Core will acknowledge consumption by calling iface::recved. */ void mg_if_recv_udp_cb(struct mg_connection *nc, void *buf, int len, union socket_address *sa, size_t sa_len); @@ -3309,10 +3307,7 @@ void mg_if_recv_udp_cb(struct mg_connection *nc, void *buf, int len, /* void mg_if_close_conn(struct mg_connection *nc); */ /* Deliver a POLL event to the connection. */ -void mg_if_poll(struct mg_connection *nc, time_t now); - -/* Deliver a TIMER event to the connection. */ -void mg_if_timer(struct mg_connection *c, double now); +int mg_if_poll(struct mg_connection *nc, double now); #ifdef __cplusplus } diff --git a/src/common/platforms/lwip/mg_lwip_ev_mgr.c b/src/common/platforms/lwip/mg_lwip_ev_mgr.c index 5eea26f3..11a1bfc1 100644 --- a/src/common/platforms/lwip/mg_lwip_ev_mgr.c +++ b/src/common/platforms/lwip/mg_lwip_ev_mgr.c @@ -50,15 +50,7 @@ void mg_ev_mgr_lwip_process_signals(struct mg_mgr *mgr) { if (nc->iface == NULL || nc->mgr == NULL) continue; switch (sig) { case MG_SIG_CONNECT_RESULT: { -#if MG_ENABLE_SSL - if (cs->err == 0 && (nc->flags & MG_F_SSL) && - !(nc->flags & MG_F_SSL_HANDSHAKE_DONE)) { - mg_lwip_ssl_do_hs(nc); - } else -#endif - { - mg_if_connect_cb(nc, cs->err); - } + mg_if_connect_cb(nc, cs->err); break; } case MG_SIG_CLOSE_CONN: { @@ -68,11 +60,8 @@ void mg_ev_mgr_lwip_process_signals(struct mg_mgr *mgr) { } case MG_SIG_RECV: { cs->recv_pending = 0; - if (nc->flags & MG_F_UDP) { - mg_lwip_handle_recv_udp(nc); - } else { - mg_lwip_handle_recv_tcp(nc); - } + mg_if_can_recv_cb(nc); + mbuf_trim(&nc->recv_mbuf); break; } case MG_SIG_TOMBSTONE: { @@ -87,7 +76,8 @@ void mg_ev_mgr_lwip_process_signals(struct mg_mgr *mgr) { } void mg_lwip_if_init(struct mg_iface *iface) { - LOG(LL_INFO, ("%p Mongoose init", iface)); + LOG(LL_INFO, ("Mongoose %s, LwIP %u.%u.%u", MG_VERSION, LWIP_VERSION_MAJOR, + LWIP_VERSION_MINOR, LWIP_VERSION_REVISION)); iface->data = MG_CALLOC(1, sizeof(struct mg_ev_mgr_lwip_data)); } @@ -126,42 +116,7 @@ time_t mg_lwip_if_poll(struct mg_iface *iface, int timeout_ms) { struct mg_lwip_conn_state *cs = (struct mg_lwip_conn_state *) nc->sock; tmp = nc->next; n++; - if ((nc->flags & MG_F_CLOSE_IMMEDIATELY) || - ((nc->flags & MG_F_SEND_AND_CLOSE) && (nc->flags & MG_F_UDP) && - (nc->send_mbuf.len == 0))) { - mg_close_conn(nc); - continue; - } - mg_if_poll(nc, now); - mg_if_timer(nc, now); -#if MG_ENABLE_SSL - if ((nc->flags & MG_F_SSL) && cs != NULL && cs->pcb.tcp != NULL && - cs->pcb.tcp->state == ESTABLISHED) { - if (((nc->flags & MG_F_WANT_WRITE) || - ((nc->send_mbuf.len > 0) && - (nc->flags & MG_F_SSL_HANDSHAKE_DONE))) && - cs->pcb.tcp->snd_buf > 0) { - /* Can write more. */ - if (nc->flags & MG_F_SSL_HANDSHAKE_DONE) { - if (!(nc->flags & MG_F_CONNECTING)) mg_lwip_ssl_send(nc); - } else { - mg_lwip_ssl_do_hs(nc); - } - } - if (cs->rx_chain != NULL || (nc->flags & MG_F_WANT_READ)) { - if (nc->flags & MG_F_SSL_HANDSHAKE_DONE) { - if (!(nc->flags & MG_F_CONNECTING)) mg_lwip_ssl_recv(nc); - } else { - mg_lwip_ssl_do_hs(nc); - } - } - } else -#endif /* MG_ENABLE_SSL */ - { - if (nc->send_mbuf.len > 0 && !(nc->flags & MG_F_CONNECTING)) { - mg_lwip_send_more(nc); - } - } + if (!mg_if_poll(nc, now)) continue; if (nc->sock != INVALID_SOCKET && !(nc->flags & (MG_F_UDP | MG_F_LISTENING)) && cs->pcb.tcp != NULL && cs->pcb.tcp->unsent != NULL) { @@ -175,14 +130,17 @@ time_t mg_lwip_if_poll(struct mg_iface *iface, int timeout_ms) { } if (nc->sock != INVALID_SOCKET) { - /* Try to consume data from cs->rx_chain */ - mg_lwip_consume_rx_chain_tcp(nc); - - /* - * If the connection is about to close, and rx_chain is finally empty, - * send the MG_SIG_CLOSE_CONN signal - */ - if (cs->draining_rx_chain && cs->rx_chain == NULL) { + if (mg_lwip_if_can_send(nc, cs)) { + mg_if_can_send_cb(nc); + mbuf_trim(&nc->send_mbuf); + } + if (cs->rx_chain != NULL) { + mg_if_can_recv_cb(nc); + } else if (cs->draining_rx_chain) { + /* + * If the connection is about to close, and rx_chain is finally empty, + * send the MG_SIG_CLOSE_CONN signal + */ mg_lwip_post_signal(MG_SIG_CLOSE_CONN, nc); } } @@ -210,21 +168,9 @@ uint32_t mg_lwip_get_poll_delay_ms(struct mg_mgr *mgr) { } num_timers++; } - if (nc->send_mbuf.len > 0 -#if MG_ENABLE_SSL - || (nc->flags & MG_F_WANT_WRITE) -#endif - ) { - int can_send = 0; - /* We have stuff to send, but can we? */ - if (nc->flags & MG_F_UDP) { - /* UDP is always ready for sending. */ - can_send = (cs->pcb.udp != NULL); - } else { - can_send = (cs->pcb.tcp != NULL && cs->pcb.tcp->snd_buf > 0); - } - /* We want and can send, request a poll immediately. */ - if (can_send) return 0; + /* We want and can send data, request a poll immediately. */ + if (nc->sock != INVALID_SOCKET && mg_lwip_if_can_send(nc, cs)) { + return 0; } } uint32_t timeout_ms = ~0; diff --git a/src/common/platforms/lwip/mg_lwip_net_if.c b/src/common/platforms/lwip/mg_lwip_net_if.c index 460f8f5a..b9042e83 100644 --- a/src/common/platforms/lwip/mg_lwip_net_if.c +++ b/src/common/platforms/lwip/mg_lwip_net_if.c @@ -57,10 +57,6 @@ typedef void (*tcpip_callback_fn)(void *arg); #endif -void mg_lwip_ssl_do_hs(struct mg_connection *nc); -void mg_lwip_ssl_send(struct mg_connection *nc); -void mg_lwip_ssl_recv(struct mg_connection *nc); - void mg_lwip_if_init(struct mg_iface *iface); void mg_lwip_if_free(struct mg_iface *iface); void mg_lwip_if_add_conn(struct mg_connection *nc); @@ -132,10 +128,12 @@ static void mg_lwip_tcp_error_cb(void *arg, err_t err) { static err_t mg_lwip_tcp_recv_cb(void *arg, struct tcp_pcb *tpcb, struct pbuf *p, err_t err) { struct mg_connection *nc = (struct mg_connection *) arg; - DBG(("%p %p %u %d", nc, tpcb, (p != NULL ? p->tot_len : 0), err)); + struct mg_lwip_conn_state *cs = + (nc ? (struct mg_lwip_conn_state *) nc->sock : NULL); + DBG(("%p %p %p %p %u %d", nc, cs, tpcb, p, (p != NULL ? p->tot_len : 0), + err)); if (p == NULL) { if (nc != NULL && !(nc->flags & MG_F_CLOSE_IMMEDIATELY)) { - struct mg_lwip_conn_state *cs = (struct mg_lwip_conn_state *) nc->sock; if (cs->rx_chain != NULL) { /* * rx_chain still contains non-consumed data, don't close the @@ -153,7 +151,6 @@ static err_t mg_lwip_tcp_recv_cb(void *arg, struct tcp_pcb *tpcb, tcp_abort(tpcb); return ERR_ARG; } - struct mg_lwip_conn_state *cs = (struct mg_lwip_conn_state *) nc->sock; /* * If we get a chain of more than one segment at once, we need to bump * refcount on the subsequent bufs to make them independent. @@ -168,7 +165,7 @@ static err_t mg_lwip_tcp_recv_cb(void *arg, struct tcp_pcb *tpcb, } else if (pbuf_clen(cs->rx_chain) >= 4) { /* ESP SDK has a limited pool of 5 pbufs. We must not hog them all or RX * will be completely blocked. We already have at least 4 in the chain, - * this one is, so we have to make a copy and release this one. */ + * this one is the last, so we have to make a copy and release this one. */ struct pbuf *np = pbuf_alloc(PBUF_RAW, p->tot_len, PBUF_RAM); if (np != NULL) { pbuf_copy(np, p); @@ -176,58 +173,9 @@ static err_t mg_lwip_tcp_recv_cb(void *arg, struct tcp_pcb *tpcb, p = np; } } - mgos_unlock(); mg_lwip_recv_common(nc, p); - return ERR_OK; -} - -static void mg_lwip_consume_rx_chain_tcp(struct mg_connection *nc) { - struct mg_lwip_conn_state *cs = (struct mg_lwip_conn_state *) nc->sock; - if (cs->rx_chain == NULL) return; -#if MG_ENABLE_SSL - if (nc->flags & MG_F_SSL) { - if (nc->flags & MG_F_SSL_HANDSHAKE_DONE) { - mg_lwip_ssl_recv(nc); - } else { - mg_lwip_ssl_do_hs(nc); - } - return; - } -#endif - mgos_lock(); - while (cs->rx_chain != NULL && nc->recv_mbuf.len < nc->recv_mbuf_limit) { - struct pbuf *seg = cs->rx_chain; - - size_t seg_len = (seg->len - cs->rx_offset); - size_t buf_avail = (nc->recv_mbuf_limit - nc->recv_mbuf.len); - size_t len = MIN(seg_len, buf_avail); - - char *data = (char *) MG_MALLOC(len); - if (data == NULL) { - mgos_unlock(); - DBG(("OOM")); - return; - } - pbuf_copy_partial(seg, data, len, cs->rx_offset); - cs->rx_offset += len; - if (cs->rx_offset == cs->rx_chain->len) { - cs->rx_chain = pbuf_dechain(cs->rx_chain); - pbuf_free(seg); - cs->rx_offset = 0; - } - mgos_unlock(); - mg_if_recv_tcp_cb(nc, data, len, 1 /* own */); - mgos_lock(); - } mgos_unlock(); -} - -static void mg_lwip_handle_recv_tcp(struct mg_connection *nc) { - mg_lwip_consume_rx_chain_tcp(nc); - - if (nc->send_mbuf.len > 0) { - mg_lwip_mgr_schedule_poll(nc->mgr); - } + return ERR_OK; } static err_t mg_lwip_tcp_sent_cb(void *arg, struct tcp_pcb *tpcb, @@ -313,13 +261,14 @@ static void mg_lwip_udp_recv_cb(void *arg, struct udp_pcb *pcb, struct pbuf *p, /* Logic in the recv handler requires that there be exactly one data pbuf. */ p = pbuf_coalesce(p, PBUF_RAW); pbuf_chain(sap, p); + mgos_lock(); mg_lwip_recv_common(nc, sap); + mgos_unlock(); (void) pcb; } static void mg_lwip_recv_common(struct mg_connection *nc, struct pbuf *p) { struct mg_lwip_conn_state *cs = (struct mg_lwip_conn_state *) nc->sock; - mgos_lock(); if (cs->rx_chain == NULL) { cs->rx_chain = p; } else { @@ -329,32 +278,30 @@ static void mg_lwip_recv_common(struct mg_connection *nc, struct pbuf *p) { cs->recv_pending = 1; mg_lwip_post_signal(MG_SIG_RECV, nc); } - mgos_unlock(); } -static void mg_lwip_handle_recv_udp(struct mg_connection *nc) { - struct mg_lwip_conn_state *cs = (struct mg_lwip_conn_state *) nc->sock; +static int mg_lwip_if_udp_recv(struct mg_connection *nc, void *buf, size_t len, + union socket_address *sa, size_t *sa_len) { /* * For UDP, RX chain consists of interleaved address and packet bufs: * Address pbuf followed by exactly one data pbuf (recv_cb took care of that). */ - while (cs->rx_chain != NULL) { - struct pbuf *sap = cs->rx_chain; - struct pbuf *p = sap->next; - cs->rx_chain = pbuf_dechain(p); - size_t data_len = p->len; - char *data = (char *) MG_MALLOC(data_len); - if (data != NULL) { - pbuf_copy_partial(p, data, data_len, 0); - pbuf_free(p); - mg_if_recv_udp_cb(nc, data, data_len, - (union socket_address *) sap->payload, sap->len); - pbuf_free(sap); - } else { - pbuf_free(p); - pbuf_free(sap); - } + int res = 0; + struct mg_lwip_conn_state *cs = (struct mg_lwip_conn_state *) nc->sock; + if (nc->sock == INVALID_SOCKET) return -1; + mgos_lock(); + if (cs->rx_chain != NULL) { + struct pbuf *ap = cs->rx_chain; + struct pbuf *dp = ap->next; + cs->rx_chain = pbuf_dechain(dp); + res = MIN(dp->len, len); + pbuf_copy_partial(dp, buf, res, 0); + pbuf_free(dp); + pbuf_copy_partial(ap, sa, MIN(*sa_len, ap->len), 0); + pbuf_free(ap); } + mgos_unlock(); + return res; } static void mg_lwip_if_connect_udp_tcpip(void *arg) { @@ -376,13 +323,6 @@ void mg_lwip_if_connect_udp(struct mg_connection *nc) { tcpip_callback(mg_lwip_if_connect_udp_tcpip, nc); } -void mg_lwip_accept_conn(struct mg_connection *nc, struct tcp_pcb *tpcb) { - union socket_address sa; - SET_ADDR(&sa, &tpcb->remote_ip); - sa.sin.sin_port = htons(tpcb->remote_port); - mg_if_accept_tcp_cb(nc, &sa, sizeof(sa.sin)); -} - static void tcp_close_tcpip(void *arg) { tcp_close((struct tcp_pcb *) arg); } @@ -390,17 +330,11 @@ static void tcp_close_tcpip(void *arg) { void mg_lwip_handle_accept(struct mg_connection *nc) { struct mg_lwip_conn_state *cs = (struct mg_lwip_conn_state *) nc->sock; if (cs->pcb.tcp == NULL) return; -#if MG_ENABLE_SSL - if (cs->lc->flags & MG_F_SSL) { - if (mg_ssl_if_conn_accept(nc, cs->lc) != MG_SSL_OK) { - LOG(LL_ERROR, ("SSL error")); - tcpip_callback(tcp_close_tcpip, cs->pcb.tcp); - } - } else -#endif - { - mg_lwip_accept_conn(nc, cs->pcb.tcp); - } + union socket_address sa; + struct tcp_pcb *tpcb = cs->pcb.tcp; + SET_ADDR(&sa, &tpcb->remote_ip); + sa.sin.sin_port = htons(tpcb->remote_port); + mg_if_accept_tcp_cb(nc, &sa, sizeof(sa.sin)); } static err_t mg_lwip_accept_cb(void *arg, struct tcp_pcb *newtpcb, err_t err) { @@ -557,14 +491,13 @@ static void mg_lwip_tcp_write_tcpip(void *arg) { ctx->ret = len; } -static int mg_lwip_tcp_write(struct mg_connection *nc, const void *data, - uint16_t len) { - struct mg_lwip_tcp_write_ctx ctx = {.nc = nc, .data = data, .len = len}; +int mg_lwip_if_tcp_send(struct mg_connection *nc, const void *buf, size_t len) { + struct mg_lwip_tcp_write_ctx ctx = {.nc = nc, .data = buf, .len = len}; struct mg_lwip_conn_state *cs = (struct mg_lwip_conn_state *) nc->sock; + if (nc->sock == INVALID_SOCKET) return -1; struct tcp_pcb *tpcb = cs->pcb.tcp; - if (tpcb == NULL) { - return -1; - } + if (tpcb == NULL) return -1; + if (tpcb->snd_buf <= 0) return 0; tcpip_callback(mg_lwip_tcp_write_tcpip, &ctx); return ctx.ret; } @@ -582,18 +515,10 @@ static void udp_sendto_tcpip(void *arg) { ctx->ret = udp_sendto(ctx->upcb, ctx->p, ctx->ip, ctx->port); } -static int mg_lwip_udp_send(struct mg_connection *nc, const void *data, - uint16_t len) { +static int mg_lwip_if_udp_send(struct mg_connection *nc, const void *data, + size_t len) { struct mg_lwip_conn_state *cs = (struct mg_lwip_conn_state *) nc->sock; - if (cs->pcb.udp == NULL) { - /* - * In case of UDP, this usually means, what - * async DNS resolve is still in progress and connection - * is not ready yet - */ - DBG(("%p socket is not connected", nc)); - return -1; - } + if (nc->sock == INVALID_SOCKET || cs->pcb.udp == NULL) return -1; struct udp_pcb *upcb = cs->pcb.udp; struct pbuf *p = pbuf_alloc(PBUF_TRANSPORT, len, PBUF_RAM); #if defined(LWIP_IPV4) && LWIP_IPV4 && defined(LWIP_IPV6) && LWIP_IPV6 @@ -602,46 +527,28 @@ static int mg_lwip_udp_send(struct mg_connection *nc, const void *data, ip_addr_t ip = {.addr = nc->sa.sin.sin_addr.s_addr}; #endif u16_t port = ntohs(nc->sa.sin.sin_port); - if (p == NULL) { - DBG(("OOM")); - return 0; - } + if (p == NULL) return 0; memcpy(p->payload, data, len); struct udp_sendto_ctx ctx = {.upcb = upcb, .p = p, .ip = &ip, .port = port}; tcpip_callback(udp_sendto_tcpip, &ctx); cs->err = ctx.ret; pbuf_free(p); - return (cs->err == ERR_OK ? len : -1); + return (cs->err == ERR_OK ? (int) len : -2); } -static void mg_lwip_send_more(struct mg_connection *nc) { - int num_sent = 0; - if (nc->sock == INVALID_SOCKET) return; - if (nc->flags & MG_F_UDP) { - num_sent = mg_lwip_udp_send(nc, nc->send_mbuf.buf, nc->send_mbuf.len); - DBG(("%p mg_lwip_udp_send %u = %d", nc, nc->send_mbuf.len, num_sent)); - } else { - num_sent = mg_lwip_tcp_write(nc, nc->send_mbuf.buf, nc->send_mbuf.len); - DBG(("%p mg_lwip_tcp_write %u = %d", nc, nc->send_mbuf.len, num_sent)); +static int mg_lwip_if_can_send(struct mg_connection *nc, + struct mg_lwip_conn_state *cs) { + int can_send = 0; + if (nc->send_mbuf.len > 0 || (nc->flags & MG_F_WANT_WRITE)) { + /* We have stuff to send, but can we? */ + if (nc->flags & MG_F_UDP) { + /* UDP is always ready for sending. */ + can_send = (cs->pcb.udp != NULL); + } else { + can_send = (cs->pcb.tcp != NULL && cs->pcb.tcp->snd_buf > 0); + } } - if (num_sent == 0) return; - if (num_sent > 0) { - mg_if_sent_cb(nc, num_sent); - } else { - mg_lwip_post_signal(MG_SIG_CLOSE_CONN, nc); - } -} - -void mg_lwip_if_tcp_send(struct mg_connection *nc, const void *buf, - size_t len) { - mbuf_append(&nc->send_mbuf, buf, len); - mg_lwip_mgr_schedule_poll(nc->mgr); -} - -void mg_lwip_if_udp_send(struct mg_connection *nc, const void *buf, - size_t len) { - mbuf_append(&nc->send_mbuf, buf, len); - mg_lwip_mgr_schedule_poll(nc->mgr); + return can_send; } struct tcp_recved_ctx { @@ -654,27 +561,35 @@ void tcp_recved_tcpip(void *arg) { tcp_recved(ctx->tpcb, ctx->len); } -void mg_lwip_if_recved(struct mg_connection *nc, size_t len) { - if (nc->flags & MG_F_UDP) return; +static int mg_lwip_if_tcp_recv(struct mg_connection *nc, void *buf, + size_t len) { + int res = 0; + char *bufp = buf; struct mg_lwip_conn_state *cs = (struct mg_lwip_conn_state *) nc->sock; - if (nc->sock == INVALID_SOCKET || cs->pcb.tcp == NULL) { - DBG(("%p invalid socket", nc)); - return; + if (nc->sock == INVALID_SOCKET) return -1; + mgos_lock(); + while (cs->rx_chain != NULL && len > 0) { + struct pbuf *seg = cs->rx_chain; + size_t seg_len = (seg->len - cs->rx_offset); + size_t copy_len = MIN(len, seg_len); + + pbuf_copy_partial(seg, bufp, copy_len, cs->rx_offset); + len -= copy_len; + res += copy_len; + bufp += copy_len; + cs->rx_offset += copy_len; + if (cs->rx_offset == cs->rx_chain->len) { + cs->rx_chain = pbuf_dechain(cs->rx_chain); + pbuf_free(seg); + cs->rx_offset = 0; + } } - DBG(("%p %p %u %u", nc, cs->pcb.tcp, len, - (cs->rx_chain ? cs->rx_chain->tot_len : 0))); - struct tcp_recved_ctx ctx = {.tpcb = cs->pcb.tcp, .len = len}; -#if MG_ENABLE_SSL - if (!(nc->flags & MG_F_SSL)) { + mgos_unlock(); + if (res > 0) { + struct tcp_recved_ctx ctx = {.tpcb = cs->pcb.tcp, .len = res}; tcpip_callback(tcp_recved_tcpip, &ctx); - } else { - /* Currently SSL acknowledges data immediately. - * TODO(rojer): Find a way to propagate mg_lwip_if_recved. */ } -#else - tcpip_callback(tcp_recved_tcpip, &ctx); -#endif - mbuf_trim(&nc->recv_mbuf); + return res; } int mg_lwip_if_create_conn(struct mg_connection *nc) { @@ -763,7 +678,8 @@ void mg_lwip_if_sock_set(struct mg_connection *nc, sock_t sock) { mg_lwip_if_connect_udp, \ mg_lwip_if_tcp_send, \ mg_lwip_if_udp_send, \ - mg_lwip_if_recved, \ + mg_lwip_if_tcp_recv, \ + mg_lwip_if_udp_recv, \ mg_lwip_if_create_conn, \ mg_lwip_if_destroy_conn, \ mg_lwip_if_sock_set, \ diff --git a/src/common/platforms/lwip/mg_lwip_net_if.h b/src/common/platforms/lwip/mg_lwip_net_if.h index d00fd2fd..d94cfdf6 100644 --- a/src/common/platforms/lwip/mg_lwip_net_if.h +++ b/src/common/platforms/lwip/mg_lwip_net_if.h @@ -30,9 +30,9 @@ struct mg_lwip_conn_state { /* Last SSL write size, for retries. */ int last_ssl_write_size; /* Whether MG_SIG_RECV is already pending for this connection */ - int recv_pending : 1; + int recv_pending; /* Whether the connection is about to close, just `rx_chain` needs to drain */ - int draining_rx_chain : 1; + int draining_rx_chain; }; enum mg_sig_type { diff --git a/src/common/platforms/lwip/mg_lwip_ssl_if.c b/src/common/platforms/lwip/mg_lwip_ssl_if.c deleted file mode 100644 index 04ed7784..00000000 --- a/src/common/platforms/lwip/mg_lwip_ssl_if.c +++ /dev/null @@ -1,197 +0,0 @@ -/* - * Copyright (c) 2014-2016 Cesanta Software Limited - * All rights reserved - */ - -#if MG_ENABLE_SSL && MG_NET_IF == MG_NET_IF_LWIP_LOW_LEVEL - -#include "common/mg_mem.h" -#include "common/cs_dbg.h" - -#include -#include - -#ifndef MG_LWIP_SSL_IO_SIZE -#define MG_LWIP_SSL_IO_SIZE 1024 -#endif - -#ifndef MIN -#define MIN(a, b) ((a) < (b) ? (a) : (b)) -#endif - -void mg_lwip_ssl_do_hs(struct mg_connection *nc) { - struct mg_lwip_conn_state *cs = (struct mg_lwip_conn_state *) nc->sock; - int server_side = (nc->listener != NULL); - enum mg_ssl_if_result res; - if (nc->flags & MG_F_CLOSE_IMMEDIATELY) return; - res = mg_ssl_if_handshake(nc); - DBG(("%p %lu %d %d", nc, nc->flags, server_side, res)); - if (res != MG_SSL_OK) { - if (res == MG_SSL_WANT_WRITE) { - nc->flags |= MG_F_WANT_WRITE; - cs->err = 0; - } else if (res == MG_SSL_WANT_READ) { - /* - * Nothing to do in particular, we are callback-driven. - * What we definitely do not need anymore is SSL reading (nothing left). - */ - nc->flags &= ~MG_F_WANT_READ; - cs->err = 0; - } else { - cs->err = res; - if (server_side) { - mg_lwip_post_signal(MG_SIG_CLOSE_CONN, nc); - } else { - mg_lwip_post_signal(MG_SIG_CONNECT_RESULT, nc); - } - } - } else { - cs->err = 0; - nc->flags &= ~MG_F_WANT_WRITE; - /* - * Handshake is done. Schedule a read immediately to consume app data - * which may already be waiting. - */ - nc->flags |= (MG_F_SSL_HANDSHAKE_DONE | MG_F_WANT_READ); - if (server_side) { - mg_lwip_accept_conn(nc, cs->pcb.tcp); - } else { - mg_lwip_post_signal(MG_SIG_CONNECT_RESULT, nc); - } - } -} - -void mg_lwip_ssl_send(struct mg_connection *nc) { - if (nc->sock == INVALID_SOCKET) { - DBG(("%p invalid socket", nc)); - return; - } - struct mg_lwip_conn_state *cs = (struct mg_lwip_conn_state *) nc->sock; - /* It's ok if the buffer is empty. Return value of 0 may also be valid. */ - int len = cs->last_ssl_write_size; - if (len == 0) { - len = MIN(MG_LWIP_SSL_IO_SIZE, nc->send_mbuf.len); - } - int ret = mg_ssl_if_write(nc, nc->send_mbuf.buf, len); - DBG(("%p SSL_write %u = %d", nc, len, ret)); - if (ret > 0) { - mg_if_sent_cb(nc, ret); - cs->last_ssl_write_size = 0; - } else if (ret < 0) { - /* This is tricky. We must remember the exact data we were sending to retry - * exactly the same send next time. */ - cs->last_ssl_write_size = len; - } - if (ret == len) { - nc->flags &= ~MG_F_WANT_WRITE; - } else if (ret == MG_SSL_WANT_WRITE) { - nc->flags |= MG_F_WANT_WRITE; - } else { - mg_lwip_post_signal(MG_SIG_CLOSE_CONN, nc); - } -} - -void mg_lwip_ssl_recv(struct mg_connection *nc) { - struct mg_lwip_conn_state *cs = (struct mg_lwip_conn_state *) nc->sock; - /* Don't deliver data before connect callback */ - if (nc->flags & MG_F_CONNECTING) return; - while (nc->recv_mbuf.len < nc->recv_mbuf_limit) { - char *buf = (char *) MG_MALLOC(MG_LWIP_SSL_IO_SIZE); - if (buf == NULL) return; - int ret = mg_ssl_if_read(nc, buf, MG_LWIP_SSL_IO_SIZE); - DBG(("%p %p SSL_read %u = %d", nc, cs->rx_chain, MG_LWIP_SSL_IO_SIZE, ret)); - if (ret <= 0) { - MG_FREE(buf); - if (ret == MG_SSL_WANT_WRITE) { - nc->flags |= MG_F_WANT_WRITE; - return; - } else if (ret == MG_SSL_WANT_READ) { - /* - * Nothing to do in particular, we are callback-driven. - * What we definitely do not need anymore is SSL reading (nothing left). - */ - nc->flags &= ~MG_F_WANT_READ; - cs->err = 0; - return; - } else { - mg_lwip_post_signal(MG_SIG_CLOSE_CONN, nc); - return; - } - } else { - mg_if_recv_tcp_cb(nc, buf, ret, 1 /* own */); - } - } -} - -#ifdef KR_VERSION - -ssize_t kr_send(int fd, const void *buf, size_t len) { - struct mg_lwip_conn_state *cs = (struct mg_lwip_conn_state *) fd; - int ret = mg_lwip_tcp_write(cs->nc, buf, len); - DBG(("%p mg_lwip_tcp_write %u = %d", cs->nc, len, ret)); - if (ret == 0) ret = KR_IO_WOULDBLOCK; - return ret; -} - -ssize_t kr_recv(int fd, void *buf, size_t len) { - struct mg_lwip_conn_state *cs = (struct mg_lwip_conn_state *) fd; - struct pbuf *seg = cs->rx_chain; - if (seg == NULL) { - DBG(("%u - nothing to read", len)); - return KR_IO_WOULDBLOCK; - } - size_t seg_len = (seg->len - cs->rx_offset); - DBG(("%u %u %u %u", len, cs->rx_chain->len, seg_len, cs->rx_chain->tot_len)); - len = MIN(len, seg_len); - pbuf_copy_partial(seg, buf, len, cs->rx_offset); - cs->rx_offset += len; - tcp_recved(cs->pcb.tcp, len); - if (cs->rx_offset == cs->rx_chain->len) { - cs->rx_chain = pbuf_dechain(cs->rx_chain); - pbuf_free(seg); - cs->rx_offset = 0; - } - return len; -} - -#elif MG_SSL_IF == MG_SSL_IF_MBEDTLS - -int ssl_socket_send(void *ctx, const unsigned char *buf, size_t len) { - struct mg_connection *nc = (struct mg_connection *) ctx; - struct mg_lwip_conn_state *cs = (struct mg_lwip_conn_state *) nc->sock; - int ret = mg_lwip_tcp_write(cs->nc, buf, len); - if (ret == 0) ret = MBEDTLS_ERR_SSL_WANT_WRITE; - LOG(LL_DEBUG, ("%p %d -> %d", nc, len, ret)); - return ret; -} - -int ssl_socket_recv(void *ctx, unsigned char *buf, size_t len) { - struct mg_connection *nc = (struct mg_connection *) ctx; - struct mg_lwip_conn_state *cs = (struct mg_lwip_conn_state *) nc->sock; - struct pbuf *seg = cs->rx_chain; - if (seg == NULL) { - DBG(("%u - nothing to read", len)); - return MBEDTLS_ERR_SSL_WANT_READ; - } - size_t seg_len = (seg->len - cs->rx_offset); - DBG(("%u %u %u %u", len, cs->rx_chain->len, seg_len, cs->rx_chain->tot_len)); - mgos_lock(); - len = MIN(len, seg_len); - pbuf_copy_partial(seg, buf, len, cs->rx_offset); - cs->rx_offset += len; - /* TCP PCB may be NULL if connection has already been closed - * but we still have data to deliver to SSL. */ - if (cs->pcb.tcp != NULL) tcp_recved(cs->pcb.tcp, len); - if (cs->rx_offset == cs->rx_chain->len) { - cs->rx_chain = pbuf_dechain(cs->rx_chain); - pbuf_free(seg); - cs->rx_offset = 0; - } - mgos_unlock(); - LOG(LL_DEBUG, ("%p <- %d", nc, (int) len)); - return len; -} - -#endif - -#endif /* MG_ENABLE_SSL && MG_NET_IF == MG_NET_IF_LWIP_LOW_LEVEL */ diff --git a/src/common/platforms/platform_cc3220.h b/src/common/platforms/platform_cc3220.h index a32264a7..6992e142 100644 --- a/src/common/platforms/platform_cc3220.h +++ b/src/common/platforms/platform_cc3220.h @@ -22,7 +22,9 @@ #endif #define MG_NET_IF MG_NET_IF_SIMPLELINK +#ifndef MG_SSL_IF #define MG_SSL_IF MG_SSL_IF_SIMPLELINK +#endif /* Only SPIFFS supports directories, SLFS does not. */ #if defined(CC3220_FS_SPIFFS) && !defined(MG_ENABLE_DIRECTORY_LISTING) diff --git a/src/common/platforms/simplelink/sl_net_if.c b/src/common/platforms/simplelink/sl_net_if.c index 2a39d140..fcc5632b 100644 --- a/src/common/platforms/simplelink/sl_net_if.c +++ b/src/common/platforms/simplelink/sl_net_if.c @@ -17,7 +17,7 @@ static sock_t mg_open_listening_socket(struct mg_connection *nc, union socket_address *sa, int type, int proto); -void mg_set_non_blocking_mode(sock_t sock) { +static void mg_set_non_blocking_mode(sock_t sock) { SlSockNonblocking_t opt; #if SL_MAJOR_VERSION_NUM < 2 opt.NonblockingEnabled = 1; @@ -31,17 +31,19 @@ static int mg_is_error(int n) { return (n < 0 && n != SL_ERROR_BSD_EALREADY && n != SL_ERROR_BSD_EAGAIN); } -void mg_sl_if_connect_tcp(struct mg_connection *nc, - const union socket_address *sa) { +static void mg_sl_if_connect_tcp(struct mg_connection *nc, + const union socket_address *sa) { int proto = 0; +#if MG_ENABLE_SSL && MG_SSL_IF == MG_SSL_IF_SIMPLELINK if (nc->flags & MG_F_SSL) proto = SL_SEC_SOCKET; +#endif sock_t sock = sl_Socket(AF_INET, SOCK_STREAM, proto); if (sock < 0) { nc->err = sock; goto out; } mg_sock_set(nc, sock); -#if MG_ENABLE_SSL +#if MG_ENABLE_SSL && MG_SSL_IF == MG_SSL_IF_SIMPLELINK nc->err = sl_set_ssl_opts(sock, nc); if (nc->err != 0) goto out; #endif @@ -51,7 +53,7 @@ out: ntohs(sa->sin.sin_port), nc->sock, proto, nc->err)); } -void mg_sl_if_connect_udp(struct mg_connection *nc) { +static void mg_sl_if_connect_udp(struct mg_connection *nc) { sock_t sock = sl_Socket(AF_INET, SOCK_DGRAM, 0); if (sock < 0) { nc->err = sock; @@ -61,7 +63,8 @@ void mg_sl_if_connect_udp(struct mg_connection *nc) { nc->err = 0; } -int mg_sl_if_listen_tcp(struct mg_connection *nc, union socket_address *sa) { +static int mg_sl_if_listen_tcp(struct mg_connection *nc, + union socket_address *sa) { int proto = 0; if (nc->flags & MG_F_SSL) proto = SL_SEC_SOCKET; sock_t sock = mg_open_listening_socket(nc, sa, SOCK_STREAM, proto); @@ -70,27 +73,50 @@ int mg_sl_if_listen_tcp(struct mg_connection *nc, union socket_address *sa) { return 0; } -int mg_sl_if_listen_udp(struct mg_connection *nc, union socket_address *sa) { +static int mg_sl_if_listen_udp(struct mg_connection *nc, + union socket_address *sa) { sock_t sock = mg_open_listening_socket(nc, sa, SOCK_DGRAM, 0); if (sock == INVALID_SOCKET) return (errno ? errno : 1); mg_sock_set(nc, sock); return 0; } -void mg_sl_if_tcp_send(struct mg_connection *nc, const void *buf, size_t len) { - mbuf_append(&nc->send_mbuf, buf, len); +static int mg_sl_if_tcp_send(struct mg_connection *nc, const void *buf, + size_t len) { + int n = (int) sl_Send(nc->sock, buf, len, 0); + if (n < 0 && !mg_is_error(n)) n = 0; + return n; } -void mg_sl_if_udp_send(struct mg_connection *nc, const void *buf, size_t len) { - mbuf_append(&nc->send_mbuf, buf, len); +static int mg_sl_if_udp_send(struct mg_connection *nc, const void *buf, + size_t len) { + int n = sl_SendTo(nc->sock, buf, len, 0, &nc->sa.sa, sizeof(nc->sa.sin)); + if (n < 0 && !mg_is_error(n)) n = 0; + return n; } -void mg_sl_if_recved(struct mg_connection *nc, size_t len) { - (void) nc; - (void) len; +static int mg_sl_if_tcp_recv(struct mg_connection *nc, void *buf, size_t len) { + int n = sl_Recv(nc->sock, buf, len, 0); + if (n == 0) { + /* Orderly shutdown of the socket, try flushing output. */ + nc->flags |= MG_F_SEND_AND_CLOSE; + } else if (n < 0 && !mg_is_error(n)) { + n = 0; + } + return n; } -int mg_sl_if_create_conn(struct mg_connection *nc) { +static int mg_sl_if_udp_recv(struct mg_connection *nc, void *buf, size_t len, + union socket_address *sa, size_t *sa_len) { + SlSocklen_t sa_len_t = *sa_len; + int n = sl_RecvFrom(nc->sock, buf, MG_UDP_RECV_BUFFER_SIZE, 0, + (SlSockAddr_t *) sa, &sa_len_t); + *sa_len = sa_len_t; + if (n < 0 && !mg_is_error(n)) n = 0; + return n; +} + +static int mg_sl_if_create_conn(struct mg_connection *nc) { (void) nc; return 1; } @@ -121,7 +147,6 @@ static int mg_accept_conn(struct mg_connection *lc) { DBG(("%p conn from %s:%d", nc, inet_ntoa(sa.sin.sin_addr), ntohs(sa.sin.sin_port))); mg_sock_set(nc, sock); - if (nc->flags & MG_F_SSL) nc->flags |= MG_F_SSL_HANDSHAKE_DONE; mg_if_accept_tcp_cb(nc, &sa, sa_len); return 1; } @@ -135,11 +160,11 @@ static sock_t mg_open_listening_socket(struct mg_connection *nc, (sa->sa.sa_family == AF_INET) ? sizeof(sa->sin) : sizeof(sa->sin6); sock_t sock = sl_Socket(sa->sa.sa_family, type, proto); if (sock < 0) return sock; +#if MG_ENABLE_SSL && MG_SSL_IF == MG_SSL_IF_SIMPLELINK + if ((r = sl_set_ssl_opts(sock, nc)) < 0) goto clean; +#endif if ((r = sl_Bind(sock, &sa->sa, sa_len)) < 0) goto clean; if (type != SOCK_DGRAM) { -#if MG_ENABLE_SSL - if ((r = sl_set_ssl_opts(sock, nc)) < 0) goto clean; -#endif if ((r = sl_Listen(sock, SOMAXCONN)) < 0) goto clean; } mg_set_non_blocking_mode(sock); @@ -151,86 +176,18 @@ clean: return sock; } -static void mg_write_to_socket(struct mg_connection *nc) { - struct mbuf *io = &nc->send_mbuf; - int n = 0; - - if (nc->flags & MG_F_UDP) { - n = sl_SendTo(nc->sock, io->buf, io->len, 0, &nc->sa.sa, - sizeof(nc->sa.sin)); - DBG(("%p %d %d %d %s:%hu", nc, nc->sock, n, errno, - inet_ntoa(nc->sa.sin.sin_addr), ntohs(nc->sa.sin.sin_port))); - } else { - n = (int) sl_Send(nc->sock, io->buf, io->len, 0); - DBG(("%p %d bytes -> %d", nc, n, nc->sock)); - } - - if (n > 0) { - mg_if_sent_cb(nc, n); - } else if (n < 0 && mg_is_error(n)) { - /* Something went wrong, drop the connection. */ - nc->flags |= MG_F_CLOSE_IMMEDIATELY; - } -} - -MG_INTERNAL size_t recv_avail_size(struct mg_connection *conn, size_t max) { - size_t avail; - if (conn->recv_mbuf_limit < conn->recv_mbuf.len) return 0; - avail = conn->recv_mbuf_limit - conn->recv_mbuf.len; - return avail > max ? max : avail; -} - -static void mg_handle_tcp_read(struct mg_connection *conn) { - int n = 0; - char *buf = (char *) MG_MALLOC(MG_TCP_RECV_BUFFER_SIZE); - - if (buf == NULL) { - DBG(("OOM")); - return; - } - - n = (int) sl_Recv(conn->sock, buf, - recv_avail_size(conn, MG_TCP_RECV_BUFFER_SIZE), 0); - DBG(("%p %d bytes <- %d", conn, n, conn->sock)); - if (n > 0) { - mg_if_recv_tcp_cb(conn, buf, n, 1 /* own */); - } else { - MG_FREE(buf); - } - if (n == 0) { - /* Orderly shutdown of the socket, try flushing output. */ - conn->flags |= MG_F_SEND_AND_CLOSE; - } else if (mg_is_error(n)) { - conn->flags |= MG_F_CLOSE_IMMEDIATELY; - } -} - -static void mg_handle_udp_read(struct mg_connection *nc) { - char *buf = (char *) MG_MALLOC(MG_UDP_RECV_BUFFER_SIZE); - if (buf == NULL) return; - union socket_address sa; - socklen_t sa_len = sizeof(sa); - int n = sl_RecvFrom(nc->sock, buf, MG_UDP_RECV_BUFFER_SIZE, 0, - (SlSockAddr_t *) &sa, &sa_len); - DBG(("%p %d bytes from %s:%d", nc, n, inet_ntoa(nc->sa.sin.sin_addr), - ntohs(nc->sa.sin.sin_port))); - if (n > 0) { - mg_if_recv_udp_cb(nc, buf, n, &sa, sa_len); - } else { - MG_FREE(buf); - } -} - #define _MG_F_FD_CAN_READ 1 #define _MG_F_FD_CAN_WRITE 1 << 1 #define _MG_F_FD_ERROR 1 << 2 void mg_mgr_handle_conn(struct mg_connection *nc, int fd_flags, double now) { - DBG(("%p fd=%d fd_flags=%d nc_flags=%lu rmbl=%d smbl=%d", nc, nc->sock, + DBG(("%p fd=%d fd_flags=%d nc_flags=0x%lx rmbl=%d smbl=%d", nc, nc->sock, fd_flags, nc->flags, (int) nc->recv_mbuf.len, (int) nc->send_mbuf.len)); + if (!mg_if_poll(nc, now)) return; + if (nc->flags & MG_F_CONNECTING) { - if (nc->flags & MG_F_UDP || nc->err != SL_ERROR_BSD_EALREADY) { + if ((nc->flags & MG_F_UDP) || nc->err != SL_ERROR_BSD_EALREADY) { mg_if_connect_cb(nc, nc->err); } else { /* In SimpleLink, to get status of non-blocking connect() we need to wait @@ -252,9 +209,6 @@ void mg_mgr_handle_conn(struct mg_connection *nc, int fd_flags, double now) { ) { nc->err = 0; } - if (nc->flags & MG_F_SSL && nc->err == 0) { - nc->flags |= MG_F_SSL_HANDSHAKE_DONE; - } mg_if_connect_cb(nc, nc->err); } } @@ -264,28 +218,21 @@ void mg_mgr_handle_conn(struct mg_connection *nc, int fd_flags, double now) { if (fd_flags & _MG_F_FD_CAN_READ) { if (nc->flags & MG_F_UDP) { - mg_handle_udp_read(nc); + mg_if_can_recv_cb(nc); } else { if (nc->flags & MG_F_LISTENING) { mg_accept_conn(nc); } else { - mg_handle_tcp_read(nc); + mg_if_can_recv_cb(nc); } } } - if (!(nc->flags & MG_F_CLOSE_IMMEDIATELY)) { - if ((fd_flags & _MG_F_FD_CAN_WRITE) && nc->send_mbuf.len > 0) { - mg_write_to_socket(nc); - } - - if (!(fd_flags & (_MG_F_FD_CAN_READ | _MG_F_FD_CAN_WRITE))) { - mg_if_poll(nc, now); - } - mg_if_timer(nc, now); + if (fd_flags & _MG_F_FD_CAN_WRITE) { + mg_if_can_send_cb(nc); } - DBG(("%p after fd=%d nc_flags=%lu rmbl=%d smbl=%d", nc, nc->sock, nc->flags, + DBG(("%p after fd=%d nc_flags=0x%lx rmbl=%d smbl=%d", nc, nc->sock, nc->flags, (int) nc->recv_mbuf.len, (int) nc->send_mbuf.len)); } @@ -406,14 +353,6 @@ time_t mg_sl_if_poll(struct mg_iface *iface, int timeout_ms) { mg_mgr_handle_conn(nc, fd_flags, now); } - for (nc = mgr->active_connections; nc != NULL; nc = tmp) { - tmp = nc->next; - if ((nc->flags & MG_F_CLOSE_IMMEDIATELY) || - (nc->send_mbuf.len == 0 && (nc->flags & MG_F_SEND_AND_CLOSE))) { - mg_close_conn(nc); - } - } - return now; } @@ -464,7 +403,8 @@ void sl_restart_cb(struct mg_mgr *mgr) { mg_sl_if_connect_udp, \ mg_sl_if_tcp_send, \ mg_sl_if_udp_send, \ - mg_sl_if_recved, \ + mg_sl_if_tcp_recv, \ + mg_sl_if_udp_recv, \ mg_sl_if_create_conn, \ mg_sl_if_destroy_conn, \ mg_sl_if_sock_set, \ diff --git a/src/common/platforms/simplelink/sl_ssl_if.c b/src/common/platforms/simplelink/sl_ssl_if.c index 99642b4b..0cd9c25b 100644 --- a/src/common/platforms/simplelink/sl_ssl_if.c +++ b/src/common/platforms/simplelink/sl_ssl_if.c @@ -54,6 +54,31 @@ enum mg_ssl_if_result mg_ssl_if_conn_init( return MG_SSL_OK; } +enum mg_ssl_if_result mg_ssl_if_conn_accept(struct mg_connection *nc, + struct mg_connection *lc) { + /* SimpleLink does everything for us, nothing for us to do. */ + (void) nc; + (void) lc; + return MG_SSL_OK; +} + +enum mg_ssl_if_result mg_ssl_if_handshake(struct mg_connection *nc) { + /* SimpleLink has already performed the handshake, nothing to do. */ + return MG_SSL_OK; +} + +int mg_ssl_if_read(struct mg_connection *nc, void *buf, size_t len) { + /* SimpelLink handles TLS, so this is just a pass-through. */ + int n = nc->iface->vtable->tcp_recv(nc, buf, len); + if (n == 0) nc->flags |= MG_F_WANT_READ; + return n; +} + +int mg_ssl_if_write(struct mg_connection *nc, const void *buf, size_t len) { + /* SimpelLink handles TLS, so this is just a pass-through. */ + return nc->iface->vtable->tcp_send(nc, buf, len); +} + void mg_ssl_if_conn_close_notify(struct mg_connection *nc) { /* Nothing to do */ (void) nc; @@ -154,56 +179,59 @@ int sl_set_ssl_opts(int sock, struct mg_connection *nc) { const struct mg_ssl_if_ctx *ctx = (struct mg_ssl_if_ctx *) nc->ssl_if_data; DBG(("%p ssl ctx: %p", nc, ctx)); - if (ctx != NULL) { - DBG(("%p %s,%s,%s,%s", nc, (ctx->ssl_cert ? ctx->ssl_cert : "-"), - (ctx->ssl_key ? ctx->ssl_cert : "-"), - (ctx->ssl_ca_cert ? ctx->ssl_ca_cert : "-"), - (ctx->ssl_server_name ? ctx->ssl_server_name : "-"))); - if (ctx->ssl_cert != NULL && ctx->ssl_key != NULL) { - char *ssl_cert = sl_pem2der(ctx->ssl_cert); - char *ssl_key = sl_pem2der(ctx->ssl_key); - if (ssl_cert != NULL && ssl_key != NULL) { - err = sl_SetSockOpt(sock, SL_SOL_SOCKET, - SL_SO_SECURE_FILES_CERTIFICATE_FILE_NAME, ssl_cert, - strlen(ssl_cert)); - LOG(LL_INFO, ("CERTIFICATE_FILE_NAME %s -> %d", ssl_cert, err)); + if (ctx == NULL) return 0; + DBG(("%p %s,%s,%s,%s", nc, (ctx->ssl_cert ? ctx->ssl_cert : "-"), + (ctx->ssl_key ? ctx->ssl_cert : "-"), + (ctx->ssl_ca_cert ? ctx->ssl_ca_cert : "-"), + (ctx->ssl_server_name ? ctx->ssl_server_name : "-"))); + if (ctx->ssl_cert != NULL && ctx->ssl_key != NULL) { + char *ssl_cert = sl_pem2der(ctx->ssl_cert), *ssl_key = NULL; + if (ssl_cert != NULL) { + err = sl_SetSockOpt(sock, SL_SOL_SOCKET, + SL_SO_SECURE_FILES_CERTIFICATE_FILE_NAME, ssl_cert, + strlen(ssl_cert)); + MG_FREE(ssl_cert); + LOG(LL_DEBUG, ("CERTIFICATE_FILE_NAME %s -> %d", ssl_cert, err)); + ssl_key = sl_pem2der(ctx->ssl_key); + if (ssl_key != NULL) { err = sl_SetSockOpt(sock, SL_SOL_SOCKET, SL_SO_SECURE_FILES_PRIVATE_KEY_FILE_NAME, ssl_key, strlen(ssl_key)); - LOG(LL_INFO, ("PRIVATE_KEY_FILE_NAME %s -> %d", ssl_key, err)); + MG_FREE(ssl_key); + LOG(LL_DEBUG, ("PRIVATE_KEY_FILE_NAME %s -> %d", ssl_key, err)); } else { err = -1; } - MG_FREE(ssl_cert); - MG_FREE(ssl_key); + } else { + err = -1; + } + if (err != 0) return err; + } + if (ctx->ssl_ca_cert != NULL) { + if (ctx->ssl_ca_cert[0] != '\0') { + char *ssl_ca_cert = sl_pem2der(ctx->ssl_ca_cert); + if (ssl_ca_cert != NULL) { + err = + sl_SetSockOpt(sock, SL_SOL_SOCKET, SL_SO_SECURE_FILES_CA_FILE_NAME, + ssl_ca_cert, strlen(ssl_ca_cert)); + LOG(LL_DEBUG, ("CA_FILE_NAME %s -> %d", ssl_ca_cert, err)); + } else { + err = -1; + } + MG_FREE(ssl_ca_cert); if (err != 0) return err; } - if (ctx->ssl_ca_cert != NULL) { - if (ctx->ssl_ca_cert[0] != '\0') { - char *ssl_ca_cert = sl_pem2der(ctx->ssl_ca_cert); - if (ssl_ca_cert != NULL) { - err = sl_SetSockOpt(sock, SL_SOL_SOCKET, - SL_SO_SECURE_FILES_CA_FILE_NAME, ssl_ca_cert, - strlen(ssl_ca_cert)); - LOG(LL_INFO, ("CA_FILE_NAME %s -> %d", ssl_ca_cert, err)); - } else { - err = -1; - } - MG_FREE(ssl_ca_cert); - if (err != 0) return err; - } - } - if (ctx->ssl_server_name != NULL) { - err = sl_SetSockOpt(sock, SL_SOL_SOCKET, - SL_SO_SECURE_DOMAIN_NAME_VERIFICATION, - ctx->ssl_server_name, strlen(ctx->ssl_server_name)); - DBG(("DOMAIN_NAME_VERIFICATION %s -> %d", ctx->ssl_server_name, err)); - /* Domain name verificationw as added in a NWP service pack, older - * versions return SL_ERROR_BSD_ENOPROTOOPT. There isn't much we can do - * about it, - * so we ignore the error. */ - if (err != 0 && err != SL_ERROR_BSD_ENOPROTOOPT) return err; - } + } + if (ctx->ssl_server_name != NULL) { + err = sl_SetSockOpt(sock, SL_SOL_SOCKET, + SL_SO_SECURE_DOMAIN_NAME_VERIFICATION, + ctx->ssl_server_name, strlen(ctx->ssl_server_name)); + DBG(("DOMAIN_NAME_VERIFICATION %s -> %d", ctx->ssl_server_name, err)); + /* Domain name verificationw as added in a NWP service pack, older + * versions return SL_ERROR_BSD_ENOPROTOOPT. There isn't much we can do + * about it, + * so we ignore the error. */ + if (err != 0 && err != SL_ERROR_BSD_ENOPROTOOPT) return err; } return 0; } diff --git a/src/mg_modules.mk b/src/mg_modules.mk index 235e0d5f..bf3f5852 100644 --- a/src/mg_modules.mk +++ b/src/mg_modules.mk @@ -96,7 +96,6 @@ SOURCES = $(COMMON)/mg_mem.h \ $(COMMON)/platforms/lwip/mg_lwip_net_if.h \ $(COMMON)/platforms/lwip/mg_lwip_net_if.c \ $(COMMON)/platforms/lwip/mg_lwip_ev_mgr.c \ - $(COMMON)/platforms/lwip/mg_lwip_ssl_if.c \ $(COMMON)/platforms/wince/wince_libc.c \ $(COMMON)/platforms/pic32/pic32_net_if.h \ $(COMMON)/platforms/pic32/pic32_net_if.c \ diff --git a/src/mg_net.c b/src/mg_net.c index 70e2cc84..050ac791 100644 --- a/src/mg_net.c +++ b/src/mg_net.c @@ -24,6 +24,13 @@ #define MG_MAX_HOST_LEN 200 +#ifndef MG_TCP_IO_SIZE +#define MG_TCP_IO_SIZE 1460 +#endif +#ifndef MG_UDP_IO_SIZE +#define MG_UDP_IO_SIZE 1460 +#endif + #define MG_COPY_COMMON_CONNECTION_OPTIONS(dst, src) \ memcpy(dst, src, sizeof(*dst)); @@ -64,8 +71,6 @@ MG_INTERNAL void mg_remove_conn(struct mg_connection *conn) { MG_INTERNAL void mg_call(struct mg_connection *nc, mg_event_handler_t ev_handler, void *user_data, int ev, void *ev_data) { - static int nesting_level = 0; - nesting_level++; if (ev_handler == NULL) { /* * If protocol handler is specified, call it. Otherwise, call user-specified @@ -74,7 +79,7 @@ MG_INTERNAL void mg_call(struct mg_connection *nc, ev_handler = nc->proto_handler ? nc->proto_handler : nc->handler; } if (ev != MG_EV_POLL) { - DBG(("%p %s ev=%d ev_data=%p flags=%lu rmbl=%d smbl=%d", nc, + DBG(("%p %s ev=%d ev_data=%p flags=0x%lx rmbl=%d smbl=%d", nc, ev_handler == nc->handler ? "user" : "proto", ev, ev_data, nc->flags, (int) nc->recv_mbuf.len, (int) nc->send_mbuf.len)); } @@ -87,33 +92,24 @@ MG_INTERNAL void mg_call(struct mg_connection *nc, #endif if (ev_handler != NULL) { unsigned long flags_before = nc->flags; - size_t recv_mbuf_before = nc->recv_mbuf.len, recved; ev_handler(nc, ev, ev_data MG_UD_ARG(user_data)); - recved = (recv_mbuf_before - nc->recv_mbuf.len); /* Prevent user handler from fiddling with system flags. */ if (ev_handler == nc->handler && nc->flags != flags_before) { nc->flags = (flags_before & ~_MG_CALLBACK_MODIFIABLE_FLAGS_MASK) | (nc->flags & _MG_CALLBACK_MODIFIABLE_FLAGS_MASK); } - /* It's important to not double-count recved bytes, and since mg_call can be - * called recursively (e.g. proto_handler invokes user handler), we keep - * track of recursion and only report received bytes at the top level. */ - if (nesting_level == 1 && recved > 0 && !(nc->flags & MG_F_UDP)) { - nc->iface->vtable->recved(nc, recved); - } } if (ev != MG_EV_POLL) { - DBG(("%p after %s flags=%lu rmbl=%d smbl=%d", nc, + DBG(("%p after %s flags=0x%lx rmbl=%d smbl=%d", nc, ev_handler == nc->handler ? "user" : "proto", nc->flags, (int) nc->recv_mbuf.len, (int) nc->send_mbuf.len)); } - nesting_level--; #if !MG_ENABLE_CALLBACK_USERDATA (void) user_data; #endif } -void mg_if_timer(struct mg_connection *c, double now) { +MG_INTERNAL void mg_timer(struct mg_connection *c, double now) { if (c->ev_timer_time > 0 && now >= c->ev_timer_time) { double old_value = c->ev_timer_time; c->ev_timer_time = 0; @@ -121,13 +117,45 @@ void mg_if_timer(struct mg_connection *c, double now) { } } -void mg_if_poll(struct mg_connection *nc, time_t now) { - if (!(nc->flags & MG_F_SSL) || (nc->flags & MG_F_SSL_HANDSHAKE_DONE)) { - mg_call(nc, NULL, nc->user_data, MG_EV_POLL, &now); +MG_INTERNAL size_t recv_avail_size(struct mg_connection *conn, size_t max) { + size_t avail; + if (conn->recv_mbuf_limit < conn->recv_mbuf.len) return 0; + avail = conn->recv_mbuf_limit - conn->recv_mbuf.len; + return avail > max ? max : avail; +} + +static int mg_do_recv(struct mg_connection *nc); + +int mg_if_poll(struct mg_connection *nc, double now) { + if ((nc->flags & MG_F_CLOSE_IMMEDIATELY) || + (nc->send_mbuf.len == 0 && (nc->flags & MG_F_SEND_AND_CLOSE))) { + mg_close_conn(nc); + return 0; } +#if MG_ENABLE_SSL + if ((nc->flags & (MG_F_SSL | MG_F_LISTENING | MG_F_CONNECTING)) == MG_F_SSL) { + /* SSL library may have data to be delivered to the app in its buffers, + * drain them. */ + int recved = 0; + do { + if (nc->flags & (MG_F_WANT_READ | MG_F_WANT_WRITE)) break; + if (recv_avail_size(nc, MG_TCP_IO_SIZE) <= 0) break; + recved = mg_do_recv(nc); + } while (recved > 0); + } +#endif /* MG_ENABLE_SSL */ + mg_timer(nc, now); + { + time_t now_t = (time_t) now; + mg_call(nc, NULL, nc->user_data, MG_EV_POLL, &now_t); + } + return 1; } void mg_destroy_conn(struct mg_connection *conn, int destroy_if) { + if (conn->sock != INVALID_SOCKET) { /* Don't print timer-only conns */ + LOG(LL_DEBUG, ("%p 0x%lx %d", conn, conn->flags, destroy_if)); + } if (destroy_if) conn->iface->vtable->destroy_conn(conn); if (conn->proto_data != NULL && conn->proto_data_destructor != NULL) { conn->proto_data_destructor(conn->proto_data); @@ -143,7 +171,6 @@ void mg_destroy_conn(struct mg_connection *conn, int destroy_if) { } void mg_close_conn(struct mg_connection *conn) { - DBG(("%p %lu %d", conn, conn->flags, conn->sock)); #if MG_ENABLE_SSL if (conn->flags & MG_F_SSL_HANDSHAKE_DONE) { mg_ssl_if_conn_close_notify(conn); @@ -180,15 +207,6 @@ void mg_mgr_init_opt(struct mg_mgr *m, void *user_data, signal(SIGPIPE, SIG_IGN); #endif -#if MG_ENABLE_SSL - { - static int init_done; - if (!init_done) { - mg_ssl_if_init(); - init_done++; - } - } -#endif { int i; if (opts.num_ifaces == 0) { @@ -211,6 +229,15 @@ void mg_mgr_init_opt(struct mg_mgr *m, void *user_data, } DBG(("==================================")); DBG(("init mgr=%p", m)); +#if MG_ENABLE_SSL + { + static int init_done; + if (!init_done) { + mg_ssl_if_init(); + init_done++; + } + } +#endif } void mg_mgr_free(struct mg_mgr *m) { @@ -453,6 +480,37 @@ MG_INTERNAL int mg_parse_address(const char *str, union socket_address *sa, return port < 0xffffUL && (ch == '\0' || ch == ',' || isspace(ch)) ? len : -1; } +#if MG_ENABLE_SSL +MG_INTERNAL void mg_ssl_handshake(struct mg_connection *nc) { + int err = 0; + int server_side = (nc->listener != NULL); + enum mg_ssl_if_result res; + if (nc->flags & MG_F_SSL_HANDSHAKE_DONE) return; + res = mg_ssl_if_handshake(nc); + LOG(LL_DEBUG, ("%p %d res %d", nc, server_side, res)); + + if (res == MG_SSL_OK) { + nc->flags |= MG_F_SSL_HANDSHAKE_DONE; + nc->flags &= ~(MG_F_WANT_READ | MG_F_WANT_WRITE); + if (server_side) { + mg_call(nc, NULL, nc->user_data, MG_EV_ACCEPT, &nc->sa); + } else { + mg_call(nc, NULL, nc->user_data, MG_EV_CONNECT, &err); + } + } else if (res == MG_SSL_WANT_READ) { + nc->flags |= MG_F_WANT_READ; + } else if (res == MG_SSL_WANT_WRITE) { + nc->flags |= MG_F_WANT_WRITE; + } else { + if (!server_side) { + err = res; + mg_call(nc, NULL, nc->user_data, MG_EV_CONNECT, &err); + } + nc->flags |= MG_F_CLOSE_IMMEDIATELY; + } +} +#endif /* MG_ENABLE_SSL */ + struct mg_connection *mg_if_accept_new_conn(struct mg_connection *lc) { struct mg_add_sock_opts opts; struct mg_connection *nc; @@ -466,95 +524,125 @@ struct mg_connection *mg_if_accept_new_conn(struct mg_connection *lc) { nc->iface = lc->iface; if (lc->flags & MG_F_SSL) nc->flags |= MG_F_SSL; mg_add_conn(nc->mgr, nc); - DBG(("%p %p %d %d", lc, nc, nc->sock, (int) nc->flags)); + LOG(LL_DEBUG, ("%p %p %d %d", lc, nc, nc->sock, (int) nc->flags)); return nc; } void mg_if_accept_tcp_cb(struct mg_connection *nc, union socket_address *sa, size_t sa_len) { - (void) sa_len; + LOG(LL_DEBUG, ("%p %s://%s:%hu", nc, (nc->flags & MG_F_UDP ? "udp" : "tcp"), + inet_ntoa(sa->sin.sin_addr), ntohs(sa->sin.sin_port))); nc->sa = *sa; - mg_call(nc, NULL, nc->user_data, MG_EV_ACCEPT, &nc->sa); +#if MG_ENABLE_SSL + if (nc->listener->flags & MG_F_SSL) { + nc->flags |= MG_F_SSL; + if (mg_ssl_if_conn_accept(nc, nc->listener) == MG_SSL_OK) { + mg_ssl_handshake(nc); + } else { + mg_close_conn(nc); + } + } else +#endif + { + mg_call(nc, NULL, nc->user_data, MG_EV_ACCEPT, &nc->sa); + } + (void) sa_len; } void mg_send(struct mg_connection *nc, const void *buf, int len) { nc->last_io_time = (time_t) mg_time(); + mbuf_append(&nc->send_mbuf, buf, len); +} + +static int mg_recv_tcp(struct mg_connection *nc, char *buf, size_t len); +static int mg_recv_udp(struct mg_connection *nc, char *buf, size_t len); + +static int mg_do_recv(struct mg_connection *nc) { + int res = 0; + char *buf = NULL; + size_t len = (nc->flags & MG_F_UDP ? MG_UDP_IO_SIZE : MG_TCP_IO_SIZE); + if ((nc->flags & (MG_F_CLOSE_IMMEDIATELY | MG_F_CONNECTING)) || + ((nc->flags & MG_F_LISTENING) && !(nc->flags & MG_F_UDP))) { + return -1; + } + len = recv_avail_size(nc, len); + if (len == 0) return -2; + if (nc->recv_mbuf.size < nc->recv_mbuf.len + len) { + mbuf_resize(&nc->recv_mbuf, nc->recv_mbuf.len + len); + } + buf = nc->recv_mbuf.buf + nc->recv_mbuf.len; + len = nc->recv_mbuf.size - nc->recv_mbuf.len; if (nc->flags & MG_F_UDP) { - nc->iface->vtable->udp_send(nc, buf, len); + res = mg_recv_udp(nc, buf, len); } else { - nc->iface->vtable->tcp_send(nc, buf, len); + res = mg_recv_tcp(nc, buf, len); } + return res; } -void mg_if_sent_cb(struct mg_connection *nc, int num_sent) { - DBG(("%p %d", nc, num_sent)); -#if !defined(NO_LIBC) && MG_ENABLE_HEXDUMP - if (nc->mgr && nc->mgr->hexdump_file != NULL) { - char *buf = nc->send_mbuf.buf; - mg_hexdump_connection(nc, nc->mgr->hexdump_file, buf, num_sent, MG_EV_SEND); - } -#endif - if (num_sent < 0) { - nc->flags |= MG_F_CLOSE_IMMEDIATELY; - } else { - mbuf_remove(&nc->send_mbuf, num_sent); - mbuf_trim(&nc->send_mbuf); - } - mg_call(nc, NULL, nc->user_data, MG_EV_SEND, &num_sent); +void mg_if_can_recv_cb(struct mg_connection *nc) { + mg_do_recv(nc); } -MG_INTERNAL void mg_recv_common(struct mg_connection *nc, void *buf, int len, - int own) { - DBG(("%p %d %u", nc, len, (unsigned int) nc->recv_mbuf.len)); - -#if !defined(NO_LIBC) && MG_ENABLE_HEXDUMP - if (nc->mgr && nc->mgr->hexdump_file != NULL) { - mg_hexdump_connection(nc, nc->mgr->hexdump_file, buf, len, MG_EV_RECV); - } -#endif - - if (nc->flags & MG_F_CLOSE_IMMEDIATELY) { - DBG(("%p discarded %d bytes", nc, len)); - /* - * This connection will not survive next poll. Do not deliver events, - * send data to /dev/null without acking. - */ - if (own) { - MG_FREE(buf); +static int mg_recv_tcp(struct mg_connection *nc, char *buf, size_t len) { + int n = 0; +#if MG_ENABLE_SSL + if (nc->flags & MG_F_SSL) { + if (nc->flags & MG_F_SSL_HANDSHAKE_DONE) { + n = mg_ssl_if_read(nc, buf, len); + DBG(("%p <- %d bytes (SSL)", nc, n)); + if (n < 0) { + if (n == MG_SSL_WANT_READ) { + nc->flags |= MG_F_WANT_READ; + n = 0; + } else { + nc->flags |= MG_F_CLOSE_IMMEDIATELY; + } + } else if (n > 0) { + nc->flags &= ~MG_F_WANT_READ; + } + } else { + mg_ssl_handshake(nc); } - return; + } else +#endif + { + n = nc->iface->vtable->tcp_recv(nc, buf, len); + DBG(("%p <- %d bytes", nc, n)); } - nc->last_io_time = (time_t) mg_time(); - if (!own) { - mbuf_append(&nc->recv_mbuf, buf, len); - } else if (nc->recv_mbuf.len == 0) { - /* Adopt buf as recv_mbuf's backing store. */ - mbuf_free(&nc->recv_mbuf); - nc->recv_mbuf.buf = (char *) buf; - nc->recv_mbuf.size = nc->recv_mbuf.len = len; - } else { - mbuf_append(&nc->recv_mbuf, buf, len); - MG_FREE(buf); + if (n > 0) { + nc->recv_mbuf.len += n; + nc->last_io_time = (time_t) mg_time(); +#if !defined(NO_LIBC) && MG_ENABLE_HEXDUMP + if (nc->mgr && nc->mgr->hexdump_file != NULL) { + mg_hexdump_connection(nc, nc->mgr->hexdump_file, buf, n, MG_EV_RECV); + } +#endif + mg_call(nc, NULL, nc->user_data, MG_EV_RECV, &n); + } else if (n < 0) { + nc->flags |= MG_F_CLOSE_IMMEDIATELY; } - mg_call(nc, NULL, nc->user_data, MG_EV_RECV, &len); + return n; } -void mg_if_recv_tcp_cb(struct mg_connection *nc, void *buf, int len, int own) { - mg_recv_common(nc, buf, len, own); -} - -void mg_if_recv_udp_cb(struct mg_connection *nc, void *buf, int len, - union socket_address *sa, size_t sa_len) { - assert(nc->flags & MG_F_UDP); - DBG(("%p %u", nc, (unsigned int) len)); +static int mg_recv_udp(struct mg_connection *nc, char *buf, size_t len) { + int n = 0; + struct mg_connection *lc = nc; + union socket_address sa; + size_t sa_len = sizeof(sa); + n = nc->iface->vtable->udp_recv(lc, buf, len, &sa, &sa_len); + if (n < 0) { + lc->flags |= MG_F_CLOSE_IMMEDIATELY; + goto out; + } if (nc->flags & MG_F_LISTENING) { - struct mg_connection *lc = nc; /* * Do we have an existing connection for this source? * This is very inefficient for long connection lists. */ + lc = nc; for (nc = mg_next(lc->mgr, NULL); nc != NULL; nc = mg_next(lc->mgr, nc)) { - if (memcmp(&nc->sa.sa, &sa->sa, sa_len) == 0 && nc->listener == lc) { + if (memcmp(&nc->sa.sa, &sa.sa, sa_len) == 0 && nc->listener == lc) { break; } } @@ -566,7 +654,7 @@ void mg_if_recv_udp_cb(struct mg_connection *nc, void *buf, int len, if (nc != NULL) { nc->sock = lc->sock; nc->listener = lc; - nc->sa = *sa; + nc->sa = sa; nc->proto_handler = lc->proto_handler; nc->user_data = lc->user_data; nc->recv_mbuf_limit = lc->recv_mbuf_limit; @@ -585,18 +673,88 @@ void mg_if_recv_udp_cb(struct mg_connection *nc, void *buf, int len, nc->flags |= MG_F_SEND_AND_CLOSE; mg_add_conn(lc->mgr, nc); mg_call(nc, NULL, nc->user_data, MG_EV_ACCEPT, &nc->sa); - } else { - DBG(("OOM")); - /* No return here, we still need to drop on the floor */ } } } if (nc != NULL) { - mg_recv_common(nc, buf, len, 1); - } else { - /* Drop on the floor. */ - MG_FREE(buf); + DBG(("%p <- %d bytes from %s:%d", nc, n, inet_ntoa(nc->sa.sin.sin_addr), + ntohs(nc->sa.sin.sin_port))); + if (nc == lc) { + nc->recv_mbuf.len += n; + } else { + mbuf_append(&nc->recv_mbuf, buf, n); + } + mbuf_trim(&lc->recv_mbuf); + lc->last_io_time = nc->last_io_time = (time_t) mg_time(); +#if !defined(NO_LIBC) && MG_ENABLE_HEXDUMP + if (nc->mgr && nc->mgr->hexdump_file != NULL) { + mg_hexdump_connection(nc, nc->mgr->hexdump_file, buf, n, MG_EV_RECV); + } +#endif + mg_call(nc, NULL, nc->user_data, MG_EV_RECV, &n); } + +out: + mbuf_free(&lc->recv_mbuf); + return n; +} + +void mg_if_can_send_cb(struct mg_connection *nc) { + int n = 0; + const char *buf = nc->send_mbuf.buf; + size_t len = nc->send_mbuf.len; + + if (nc->flags & (MG_F_CLOSE_IMMEDIATELY | MG_F_CONNECTING)) { + return; + } + if (!(nc->flags & MG_F_UDP)) { + if (nc->flags & MG_F_LISTENING) return; + if (len > MG_TCP_IO_SIZE) len = MG_TCP_IO_SIZE; + } +#if MG_ENABLE_SSL + if (nc->flags & MG_F_SSL) { + if (nc->flags & MG_F_SSL_HANDSHAKE_DONE) { + if (len > 0) { + n = mg_ssl_if_write(nc, buf, len); + DBG(("%p -> %d bytes (SSL)", nc, n)); + } + if (n < 0) { + if (n == MG_SSL_WANT_WRITE) { + nc->flags |= MG_F_WANT_WRITE; + n = 0; + } else { + nc->flags |= MG_F_CLOSE_IMMEDIATELY; + } + } else { + nc->flags &= ~MG_F_WANT_WRITE; + } + } else { + mg_ssl_handshake(nc); + } + } else +#endif + { + if (nc->flags & MG_F_UDP) { + n = nc->iface->vtable->udp_send(nc, buf, len); + } else { + n = nc->iface->vtable->tcp_send(nc, buf, len); + } + DBG(("%p -> %d bytes", nc, n)); + } + +#if !defined(NO_LIBC) && MG_ENABLE_HEXDUMP + if (n > 0 && nc->mgr && nc->mgr->hexdump_file != NULL) { + mg_hexdump_connection(nc, nc->mgr->hexdump_file, buf, n, MG_EV_SEND); + } +#endif + if (n < 0) { + nc->flags |= MG_F_CLOSE_IMMEDIATELY; + } else if (n > 0) { + nc->last_io_time = (time_t) mg_time(); + mbuf_remove(&nc->send_mbuf, n); + mbuf_trim(&nc->send_mbuf); + } + if (n != 0) mg_call(nc, NULL, nc->user_data, MG_EV_SEND, &n); } /* @@ -608,8 +766,8 @@ void mg_if_recv_udp_cb(struct mg_connection *nc, void *buf, int len, MG_INTERNAL struct mg_connection *mg_do_connect(struct mg_connection *nc, int proto, union socket_address *sa) { - DBG(("%p %s://%s:%hu", nc, proto == SOCK_DGRAM ? "udp" : "tcp", - inet_ntoa(sa->sin.sin_addr), ntohs(sa->sin.sin_port))); + LOG(LL_DEBUG, ("%p %s://%s:%hu", nc, proto == SOCK_DGRAM ? "udp" : "tcp", + inet_ntoa(sa->sin.sin_addr), ntohs(sa->sin.sin_port))); nc->flags |= MG_F_CONNECTING; if (proto == SOCK_DGRAM) { @@ -622,12 +780,21 @@ MG_INTERNAL struct mg_connection *mg_do_connect(struct mg_connection *nc, } void mg_if_connect_cb(struct mg_connection *nc, int err) { - DBG(("%p connect, err=%d", nc, err)); + LOG(LL_DEBUG, + ("%p %s://%s:%hu -> %d", nc, (nc->flags & MG_F_UDP ? "udp" : "tcp"), + inet_ntoa(nc->sa.sin.sin_addr), ntohs(nc->sa.sin.sin_port), err)); nc->flags &= ~MG_F_CONNECTING; if (err != 0) { nc->flags |= MG_F_CLOSE_IMMEDIATELY; } - mg_call(nc, NULL, nc->user_data, MG_EV_CONNECT, &err); +#if MG_ENABLE_SSL + if (err == 0 && (nc->flags & MG_F_SSL)) { + mg_ssl_handshake(nc); + } else +#endif + { + mg_call(nc, NULL, nc->user_data, MG_EV_CONNECT, &err); + } } #if MG_ENABLE_ASYNC_RESOLVER @@ -717,7 +884,8 @@ struct mg_connection *mg_connect_opt(struct mg_mgr *mgr, const char *address, #endif #if MG_ENABLE_SSL - DBG(("%p %s %s,%s,%s", nc, address, (opts.ssl_cert ? opts.ssl_cert : "-"), + LOG(LL_DEBUG, + ("%p %s %s,%s,%s", nc, address, (opts.ssl_cert ? opts.ssl_cert : "-"), (opts.ssl_key ? opts.ssl_key : "-"), (opts.ssl_ca_cert ? opts.ssl_ca_cert : "-"))); @@ -963,7 +1131,7 @@ double mg_set_timer(struct mg_connection *c, double timestamp) { DBG(("%p %p %d -> %lu", c, c->priv_2, (c->flags & MG_F_RESOLVING ? 1 : 0), (unsigned long) timestamp)); if ((c->flags & MG_F_RESOLVING) && c->priv_2 != NULL) { - ((struct mg_connection *) c->priv_2)->ev_timer_time = timestamp; + mg_set_timer((struct mg_connection *) c->priv_2, timestamp); } return result; } diff --git a/src/mg_net_if.h b/src/mg_net_if.h index 43eb2d99..cba58fb9 100644 --- a/src/mg_net_if.h +++ b/src/mg_net_if.h @@ -54,10 +54,12 @@ struct mg_iface_vtable { void (*connect_udp)(struct mg_connection *nc); /* Send functions for TCP and UDP. Sent data is copied before return. */ - void (*tcp_send)(struct mg_connection *nc, const void *buf, size_t len); - void (*udp_send)(struct mg_connection *nc, const void *buf, size_t len); + int (*tcp_send)(struct mg_connection *nc, const void *buf, size_t len); + int (*udp_send)(struct mg_connection *nc, const void *buf, size_t len); - void (*recved)(struct mg_connection *nc, size_t len); + int (*tcp_recv)(struct mg_connection *nc, void *buf, size_t len); + int (*udp_recv)(struct mg_connection *nc, void *buf, size_t len, + union socket_address *sa, size_t *sa_len); /* Perform interface-related connection initialization. Return 1 on ok. */ int (*create_conn)(struct mg_connection *nc); @@ -98,19 +100,15 @@ void mg_if_accept_tcp_cb(struct mg_connection *nc, union socket_address *sa, /* Callback invoked by connect methods. err = 0 -> ok, != 0 -> error. */ void mg_if_connect_cb(struct mg_connection *nc, int err); -/* Callback that reports that data has been put on the wire. */ -void mg_if_sent_cb(struct mg_connection *nc, int num_sent); /* - * Receive callback. - * if `own` is true, buf must be heap-allocated and ownership is transferred - * to the core. - * Core will acknowledge consumption by calling iface::recved. + * Callback that tells the core that data can be received. + * Core will use tcp/udp_recv to retrieve the data. */ -void mg_if_recv_tcp_cb(struct mg_connection *nc, void *buf, int len, int own); +void mg_if_can_recv_cb(struct mg_connection *nc); +void mg_if_can_send_cb(struct mg_connection *nc); /* * Receive callback. * buf must be heap-allocated and ownership is transferred to the core. - * Core will acknowledge consumption by calling iface::recved. */ void mg_if_recv_udp_cb(struct mg_connection *nc, void *buf, int len, union socket_address *sa, size_t sa_len); @@ -118,10 +116,7 @@ void mg_if_recv_udp_cb(struct mg_connection *nc, void *buf, int len, /* void mg_if_close_conn(struct mg_connection *nc); */ /* Deliver a POLL event to the connection. */ -void mg_if_poll(struct mg_connection *nc, time_t now); - -/* Deliver a TIMER event to the connection. */ -void mg_if_timer(struct mg_connection *c, double now); +int mg_if_poll(struct mg_connection *nc, double now); #ifdef __cplusplus } diff --git a/src/mg_net_if_socket.c b/src/mg_net_if_socket.c index c13c300a..c713e845 100644 --- a/src/mg_net_if_socket.c +++ b/src/mg_net_if_socket.c @@ -9,14 +9,8 @@ #include "mg_internal.h" #include "mg_util.h" -#define MG_TCP_RECV_BUFFER_SIZE 1024 -#define MG_UDP_RECV_BUFFER_SIZE 1500 - static sock_t mg_open_listening_socket(union socket_address *sa, int type, int proto); -#if MG_ENABLE_SSL -static void mg_ssl_begin(struct mg_connection *nc); -#endif void mg_set_non_blocking_mode(sock_t sock) { #ifdef _WIN32 @@ -85,27 +79,48 @@ int mg_socket_if_listen_tcp(struct mg_connection *nc, return 0; } -int mg_socket_if_listen_udp(struct mg_connection *nc, - union socket_address *sa) { +static int mg_socket_if_listen_udp(struct mg_connection *nc, + union socket_address *sa) { sock_t sock = mg_open_listening_socket(sa, SOCK_DGRAM, 0); if (sock == INVALID_SOCKET) return (mg_get_errno() ? mg_get_errno() : 1); mg_sock_set(nc, sock); return 0; } -void mg_socket_if_tcp_send(struct mg_connection *nc, const void *buf, - size_t len) { - mbuf_append(&nc->send_mbuf, buf, len); +static int mg_socket_if_tcp_send(struct mg_connection *nc, const void *buf, + size_t len) { + int n = (int) MG_SEND_FUNC(nc->sock, buf, len, 0); + if (n < 0 && !mg_is_error()) n = 0; + return n; } -void mg_socket_if_udp_send(struct mg_connection *nc, const void *buf, - size_t len) { - mbuf_append(&nc->send_mbuf, buf, len); +static int mg_socket_if_udp_send(struct mg_connection *nc, const void *buf, + size_t len) { + int n = sendto(nc->sock, buf, len, 0, &nc->sa.sa, sizeof(nc->sa.sin)); + if (n < 0 && !mg_is_error()) n = 0; + return n; } -void mg_socket_if_recved(struct mg_connection *nc, size_t len) { - (void) nc; - (void) len; +static int mg_socket_if_tcp_recv(struct mg_connection *nc, void *buf, + size_t len) { + int n = (int) MG_RECV_FUNC(nc->sock, buf, len, 0); + if (n == 0) { + /* Orderly shutdown of the socket, try flushing output. */ + nc->flags |= MG_F_SEND_AND_CLOSE; + } else if (n < 0 && !mg_is_error()) { + n = 0; + } + return n; +} + +static int mg_socket_if_udp_recv(struct mg_connection *nc, void *buf, + size_t len, union socket_address *sa, + size_t *sa_len) { + socklen_t sa_len_st = *sa_len; + int n = recvfrom(nc->sock, buf, len, 0, &sa->sa, &sa_len_st); + *sa_len = sa_len_st; + if (n < 0 && !mg_is_error()) n = 0; + return n; } int mg_socket_if_create_conn(struct mg_connection *nc) { @@ -142,14 +157,7 @@ static int mg_accept_conn(struct mg_connection *lc) { DBG(("%p conn from %s:%d", nc, inet_ntoa(sa.sin.sin_addr), ntohs(sa.sin.sin_port))); mg_sock_set(nc, sock); -#if MG_ENABLE_SSL - if (lc->flags & MG_F_SSL) { - if (mg_ssl_if_conn_accept(nc, lc) != MG_SSL_OK) mg_close_conn(nc); - } else -#endif - { - mg_if_accept_tcp_cb(nc, &sa, sa_len); - } + mg_if_accept_tcp_cb(nc, &sa, sa_len); return 1; } @@ -200,165 +208,6 @@ static sock_t mg_open_listening_socket(union socket_address *sa, int type, return sock; } -static void mg_write_to_socket(struct mg_connection *nc) { - struct mbuf *io = &nc->send_mbuf; - int n = 0; - -#if MG_LWIP - /* With LWIP we don't know if the socket is ready */ - if (io->len == 0) return; -#endif - - assert(io->len > 0); - - if (nc->flags & MG_F_UDP) { - int n = - sendto(nc->sock, io->buf, io->len, 0, &nc->sa.sa, sizeof(nc->sa.sin)); - DBG(("%p %d %d %d %s:%hu", nc, nc->sock, n, mg_get_errno(), - inet_ntoa(nc->sa.sin.sin_addr), ntohs(nc->sa.sin.sin_port))); - mg_if_sent_cb(nc, n); - return; - } - -#if MG_ENABLE_SSL - if (nc->flags & MG_F_SSL) { - if (nc->flags & MG_F_SSL_HANDSHAKE_DONE) { - n = mg_ssl_if_write(nc, io->buf, io->len); - DBG(("%p %d bytes -> %d (SSL)", nc, n, nc->sock)); - if (n < 0) { - if (n != MG_SSL_WANT_READ && n != MG_SSL_WANT_WRITE) { - nc->flags |= MG_F_CLOSE_IMMEDIATELY; - } - return; - } else { - /* Successful SSL operation, clear off SSL wait flags */ - nc->flags &= ~(MG_F_WANT_READ | MG_F_WANT_WRITE); - } - } else { - mg_ssl_begin(nc); - return; - } - } else -#endif - { - n = (int) MG_SEND_FUNC(nc->sock, io->buf, io->len, 0); - DBG(("%p %d bytes -> %d", nc, n, nc->sock)); - } - - mg_if_sent_cb(nc, n); -} - -MG_INTERNAL size_t recv_avail_size(struct mg_connection *conn, size_t max) { - size_t avail; - if (conn->recv_mbuf_limit < conn->recv_mbuf.len) return 0; - avail = conn->recv_mbuf_limit - conn->recv_mbuf.len; - return avail > max ? max : avail; -} - -static void mg_handle_tcp_read(struct mg_connection *conn) { - int n = 0; - char *buf = (char *) MG_MALLOC(MG_TCP_RECV_BUFFER_SIZE); - - if (buf == NULL) { - DBG(("OOM")); - return; - } - -#if MG_ENABLE_SSL - if (conn->flags & MG_F_SSL) { - if (conn->flags & MG_F_SSL_HANDSHAKE_DONE) { - /* SSL library may have more bytes ready to read than we ask to read. - * Therefore, read in a loop until we read everything. Without the loop, - * we skip to the next select() cycle which can just timeout. */ - while ((n = mg_ssl_if_read(conn, buf, MG_TCP_RECV_BUFFER_SIZE)) > 0) { - DBG(("%p %d bytes <- %d (SSL)", conn, n, conn->sock)); - mg_if_recv_tcp_cb(conn, buf, n, 1 /* own */); - buf = NULL; - if (conn->flags & MG_F_CLOSE_IMMEDIATELY) break; - /* buf has been freed, we need a new one. */ - buf = (char *) MG_MALLOC(MG_TCP_RECV_BUFFER_SIZE); - if (buf == NULL) break; - } - MG_FREE(buf); - if (n < 0 && n != MG_SSL_WANT_READ) conn->flags |= MG_F_CLOSE_IMMEDIATELY; - } else { - MG_FREE(buf); - mg_ssl_begin(conn); - return; - } - } else -#endif - { - n = (int) MG_RECV_FUNC(conn->sock, buf, - recv_avail_size(conn, MG_TCP_RECV_BUFFER_SIZE), 0); - DBG(("%p %d bytes (PLAIN) <- %d", conn, n, conn->sock)); - if (n > 0) { - mg_if_recv_tcp_cb(conn, buf, n, 1 /* own */); - } else { - MG_FREE(buf); - } - if (n == 0) { - /* Orderly shutdown of the socket, try flushing output. */ - conn->flags |= MG_F_SEND_AND_CLOSE; - } else if (n < 0 && mg_is_error()) { - conn->flags |= MG_F_CLOSE_IMMEDIATELY; - } - } -} - -static int mg_recvfrom(struct mg_connection *nc, union socket_address *sa, - socklen_t *sa_len, char **buf) { - int n; - *buf = (char *) MG_MALLOC(MG_UDP_RECV_BUFFER_SIZE); - if (*buf == NULL) { - DBG(("Out of memory")); - return -ENOMEM; - } - n = recvfrom(nc->sock, *buf, MG_UDP_RECV_BUFFER_SIZE, 0, &sa->sa, sa_len); - if (n <= 0) { - DBG(("%p recvfrom: %s", nc, strerror(mg_get_errno()))); - MG_FREE(*buf); - } - return n; -} - -static void mg_handle_udp_read(struct mg_connection *nc) { - char *buf = NULL; - union socket_address sa; - socklen_t sa_len = sizeof(sa); - int n = mg_recvfrom(nc, &sa, &sa_len, &buf); - DBG(("%p %d bytes from %s:%d", nc, n, inet_ntoa(nc->sa.sin.sin_addr), - ntohs(nc->sa.sin.sin_port))); - mg_if_recv_udp_cb(nc, buf, n, &sa, sa_len); -} - -#if MG_ENABLE_SSL -static void mg_ssl_begin(struct mg_connection *nc) { - int server_side = (nc->listener != NULL); - enum mg_ssl_if_result res = mg_ssl_if_handshake(nc); - DBG(("%p %d res %d", nc, server_side, res)); - - if (res == MG_SSL_OK) { - nc->flags |= MG_F_SSL_HANDSHAKE_DONE; - nc->flags &= ~(MG_F_WANT_READ | MG_F_WANT_WRITE); - - if (server_side) { - union socket_address sa; - socklen_t sa_len = sizeof(sa); - (void) getpeername(nc->sock, &sa.sa, &sa_len); - mg_if_accept_tcp_cb(nc, &sa, sa_len); - } else { - mg_if_connect_cb(nc, 0); - } - } else if (res != MG_SSL_WANT_READ && res != MG_SSL_WANT_WRITE) { - if (!server_side) { - mg_if_connect_cb(nc, res); - } - nc->flags |= MG_F_CLOSE_IMMEDIATELY; - } -} -#endif /* MG_ENABLE_SSL */ - #define _MG_F_FD_CAN_READ 1 #define _MG_F_FD_CAN_WRITE 1 << 1 #define _MG_F_FD_ERROR 1 << 2 @@ -367,11 +216,13 @@ void mg_mgr_handle_conn(struct mg_connection *nc, int fd_flags, double now) { int worth_logging = fd_flags != 0 || (nc->flags & (MG_F_WANT_READ | MG_F_WANT_WRITE)); if (worth_logging) { - DBG(("%p fd=%d fd_flags=%d nc_flags=%lu rmbl=%d smbl=%d", nc, nc->sock, + DBG(("%p fd=%d fd_flags=%d nc_flags=0x%lx rmbl=%d smbl=%d", nc, nc->sock, fd_flags, nc->flags, (int) nc->recv_mbuf.len, (int) nc->send_mbuf.len)); } + if (!mg_if_poll(nc, now)) return; + if (nc->flags & MG_F_CONNECTING) { if (fd_flags != 0) { int err = 0; @@ -392,15 +243,7 @@ void mg_mgr_handle_conn(struct mg_connection *nc, int fd_flags, double now) { */ err = nc->err; #endif -#if MG_ENABLE_SSL - if ((nc->flags & MG_F_SSL) && err == 0) { - mg_ssl_begin(nc); - } else { - mg_if_connect_cb(nc, err); - } -#else mg_if_connect_cb(nc, err); -#endif } else if (nc->err != 0) { mg_if_connect_cb(nc, nc->err); } @@ -408,7 +251,7 @@ void mg_mgr_handle_conn(struct mg_connection *nc, int fd_flags, double now) { if (fd_flags & _MG_F_FD_CAN_READ) { if (nc->flags & MG_F_UDP) { - mg_handle_udp_read(nc); + mg_if_can_recv_cb(nc); } else { if (nc->flags & MG_F_LISTENING) { /* @@ -418,22 +261,16 @@ void mg_mgr_handle_conn(struct mg_connection *nc, int fd_flags, double now) { */ mg_accept_conn(nc); } else { - mg_handle_tcp_read(nc); + mg_if_can_recv_cb(nc); } } } - if (!(nc->flags & MG_F_CLOSE_IMMEDIATELY)) { - if ((fd_flags & _MG_F_FD_CAN_WRITE) && nc->send_mbuf.len > 0) { - mg_write_to_socket(nc); - } - mg_if_poll(nc, (time_t) now); - mg_if_timer(nc, now); - } + if (fd_flags & _MG_F_FD_CAN_WRITE) mg_if_can_send_cb(nc); if (worth_logging) { - DBG(("%p after fd=%d nc_flags=%lu rmbl=%d smbl=%d", nc, nc->sock, nc->flags, - (int) nc->recv_mbuf.len, (int) nc->send_mbuf.len)); + DBG(("%p after fd=%d nc_flags=0x%lx rmbl=%d smbl=%d", nc, nc->sock, + nc->flags, (int) nc->recv_mbuf.len, (int) nc->send_mbuf.len)); } } @@ -547,8 +384,7 @@ time_t mg_socket_if_poll(struct mg_iface *iface, int timeout_ms) { } #endif - if (!(nc->flags & MG_F_WANT_WRITE) && - nc->recv_mbuf.len < nc->recv_mbuf_limit && + if (nc->recv_mbuf.len < nc->recv_mbuf_limit && (!(nc->flags & MG_F_UDP) || nc->listener == NULL)) { mg_add_to_set(nc->sock, &read_set, &max_fd); } @@ -619,14 +455,6 @@ time_t mg_socket_if_poll(struct mg_iface *iface, int timeout_ms) { mg_mgr_handle_conn(nc, fd_flags, now); } - for (nc = mgr->active_connections; nc != NULL; nc = tmp) { - tmp = nc->next; - if ((nc->flags & MG_F_CLOSE_IMMEDIATELY) || - (nc->send_mbuf.len == 0 && (nc->flags & MG_F_SEND_AND_CLOSE))) { - mg_close_conn(nc); - } - } - return (time_t) now; } @@ -735,7 +563,8 @@ void mg_socket_if_get_conn_addr(struct mg_connection *nc, int remote, mg_socket_if_connect_udp, \ mg_socket_if_tcp_send, \ mg_socket_if_udp_send, \ - mg_socket_if_recved, \ + mg_socket_if_tcp_recv, \ + mg_socket_if_udp_recv, \ mg_socket_if_create_conn, \ mg_socket_if_destroy_conn, \ mg_socket_if_sock_set, \ diff --git a/src/mg_net_if_socks.c b/src/mg_net_if_socks.c index c5661e97..2a421426 100644 --- a/src/mg_net_if_socks.c +++ b/src/mg_net_if_socks.c @@ -9,18 +9,35 @@ struct socksdata { char *proxy_addr; /* HOST:PORT of the socks5 proxy server */ struct mg_connection *s; /* Respective connection to the server */ struct mg_connection *c; /* Connection to the client */ - struct mbuf tmp; /* Temporary buffer for sent data */ }; static void socks_if_disband(struct socksdata *d) { LOG(LL_DEBUG, ("disbanding proxy %p %p", d->c, d->s)); - if (d->c) d->c->flags |= MG_F_SEND_AND_CLOSE; - if (d->s) d->s->flags |= MG_F_SEND_AND_CLOSE; - d->c = d->s = NULL; + if (d->c) { + d->c->flags |= MG_F_SEND_AND_CLOSE; + d->c->user_data = NULL; + d->c = NULL; + } + if (d->s) { + d->s->flags |= MG_F_SEND_AND_CLOSE; + d->s->user_data = NULL; + d->s = NULL; + } +} + +static void socks_if_relay(struct mg_connection *s) { + struct socksdata *d = (struct socksdata *) s->user_data; + if (d == NULL || d->c == NULL || !(s->flags & MG_SOCKS_CONNECT_DONE) || + d->s == NULL) { + return; + } + if (s->recv_mbuf.len > 0) mg_if_can_recv_cb(d->c); + if (d->c->send_mbuf.len > 0 && s->send_mbuf.len == 0) mg_if_can_send_cb(d->c); } static void socks_if_handler(struct mg_connection *c, int ev, void *ev_data) { struct socksdata *d = (struct socksdata *) c->user_data; + if (d == NULL) return; if (ev == MG_EV_CONNECT) { int res = *(int *) ev_data; if (res == 0) { @@ -53,6 +70,7 @@ static void socks_if_handler(struct mg_connection *c, int ev, void *ev_data) { memcpy(buf + 4, &d->c->sa.sin.sin_addr, 4); memcpy(buf + 8, &d->c->sa.sin.sin_port, 2); mg_send(c, buf, sizeof(buf)); + LOG(LL_DEBUG, ("%p Sent connect request", c)); } /* Process connect request */ if ((c->flags & MG_SOCKS_HANDSHAKE_DONE) && @@ -65,17 +83,12 @@ static void socks_if_handler(struct mg_connection *c, int ev, void *ev_data) { } mbuf_remove(&c->recv_mbuf, 10); c->flags |= MG_SOCKS_CONNECT_DONE; - /* Connected. Move sent data from client, if any, to server */ - if (d->s && d->c) { - mbuf_append(&d->s->send_mbuf, d->tmp.buf, d->tmp.len); - mbuf_free(&d->tmp); - } - } - /* All flags are set, we're in relay mode */ - if ((c->flags & MG_SOCKS_CONNECT_DONE) && d->c && d->s) { - mbuf_append(&d->c->recv_mbuf, d->s->recv_mbuf.buf, d->s->recv_mbuf.len); - mbuf_remove(&d->s->recv_mbuf, d->s->recv_mbuf.len); + LOG(LL_DEBUG, ("%p Connect done %p", c, d->c)); + mg_if_connect_cb(d->c, 0); } + socks_if_relay(c); + } else if (ev == MG_EV_SEND || ev == MG_EV_POLL) { + socks_if_relay(c); } } @@ -85,7 +98,7 @@ static void mg_socks_if_connect_tcp(struct mg_connection *c, d->c = c; d->s = mg_connect(c->mgr, d->proxy_addr, socks_if_handler); d->s->user_data = d; - LOG(LL_DEBUG, ("%p %s", c, d->proxy_addr)); + LOG(LL_DEBUG, ("%p %s %p %p", c, d->proxy_addr, d, d->s)); (void) sa; } @@ -107,29 +120,44 @@ static int mg_socks_if_listen_udp(struct mg_connection *c, return -1; } -static void mg_socks_if_tcp_send(struct mg_connection *c, const void *buf, - size_t len) { +static int mg_socks_if_tcp_send(struct mg_connection *c, const void *buf, + size_t len) { + int res; struct socksdata *d = (struct socksdata *) c->iface->data; - LOG(LL_DEBUG, ("%p -> %p %d %d", c, buf, (int) len, (int) c->send_mbuf.len)); - if (d && d->s && d->s->flags & MG_SOCKS_CONNECT_DONE) { - mbuf_append(&d->s->send_mbuf, d->tmp.buf, d->tmp.len); - mbuf_append(&d->s->send_mbuf, buf, len); - mbuf_free(&d->tmp); - } else { - mbuf_append(&d->tmp, buf, len); - } + if (d->s == NULL) return -1; + res = (int) mbuf_append(&d->s->send_mbuf, buf, len); + DBG(("%p -> %d -> %p", c, res, d->s)); + return res; } -static void mg_socks_if_udp_send(struct mg_connection *c, const void *buf, - size_t len) { +static int mg_socks_if_udp_send(struct mg_connection *c, const void *buf, + size_t len) { (void) c; (void) buf; (void) len; + return -1; } -static void mg_socks_if_recved(struct mg_connection *c, size_t len) { +int mg_socks_if_tcp_recv(struct mg_connection *c, void *buf, size_t len) { + struct socksdata *d = (struct socksdata *) c->iface->data; + if (d->s == NULL) return -1; + if (len > d->s->recv_mbuf.len) len = d->s->recv_mbuf.len; + if (len > 0) { + memcpy(buf, d->s->recv_mbuf.buf, len); + mbuf_remove(&d->s->recv_mbuf, len); + } + DBG(("%p <- %d <- %p", c, (int) len, d->s)); + return len; +} + +int mg_socks_if_udp_recv(struct mg_connection *c, void *buf, size_t len, + union socket_address *sa, size_t *sa_len) { (void) c; + (void) buf; (void) len; + (void) sa; + (void) sa_len; + return -1; } static int mg_socks_if_create_conn(struct mg_connection *c) { @@ -158,7 +186,6 @@ static void mg_socks_if_free(struct mg_iface *iface) { LOG(LL_DEBUG, ("%p", iface)); if (d != NULL) { socks_if_disband(d); - mbuf_free(&d->tmp); MG_FREE(d->proxy_addr); MG_FREE(d); iface->data = NULL; @@ -189,14 +216,15 @@ static void mg_socks_if_get_conn_addr(struct mg_connection *c, int remote, } const struct mg_iface_vtable mg_socks_iface_vtable = { - mg_socks_if_init, mg_socks_if_free, - mg_socks_if_add_conn, mg_socks_if_remove_conn, - mg_socks_if_poll, mg_socks_if_listen_tcp, - mg_socks_if_listen_udp, mg_socks_if_connect_tcp, - mg_socks_if_connect_udp, mg_socks_if_tcp_send, - mg_socks_if_udp_send, mg_socks_if_recved, - mg_socks_if_create_conn, mg_socks_if_destroy_conn, - mg_socks_if_sock_set, mg_socks_if_get_conn_addr, + mg_socks_if_init, mg_socks_if_free, + mg_socks_if_add_conn, mg_socks_if_remove_conn, + mg_socks_if_poll, mg_socks_if_listen_tcp, + mg_socks_if_listen_udp, mg_socks_if_connect_tcp, + mg_socks_if_connect_udp, mg_socks_if_tcp_send, + mg_socks_if_udp_send, mg_socks_if_tcp_recv, + mg_socks_if_udp_recv, mg_socks_if_create_conn, + mg_socks_if_destroy_conn, mg_socks_if_sock_set, + mg_socks_if_get_conn_addr, }; struct mg_iface *mg_socks_mk_iface(struct mg_mgr *mgr, const char *proxy_addr) { diff --git a/src/mg_resolv.c b/src/mg_resolv.c index e445ac50..b8b73a99 100644 --- a/src/mg_resolv.c +++ b/src/mg_resolv.c @@ -148,7 +148,6 @@ static void mg_resolve_async_eh(struct mg_connection *nc, int ev, time_t now = (time_t) mg_time(); struct mg_resolve_async_request *req; struct mg_dns_message *msg; - int first = 0; #if !MG_ENABLE_CALLBACK_USERDATA void *user_data = nc->user_data; #endif @@ -162,17 +161,16 @@ static void mg_resolve_async_eh(struct mg_connection *nc, int ev, } switch (ev) { - case MG_EV_CONNECT: - /* don't depend on timer not being at epoch for sending out first req */ - first = 1; - /* fallthrough */ case MG_EV_POLL: if (req->retries > req->max_retries) { req->err = MG_RESOLVE_EXCEEDED_RETRY_COUNT; nc->flags |= MG_F_CLOSE_IMMEDIATELY; break; } - if (first || now - req->last_time >= req->timeout) { + if (nc->flags & MG_F_CONNECTING) break; + /* fallthrough */ + case MG_EV_CONNECT: + if (req->retries == 0 || now - req->last_time >= req->timeout) { mg_send_dns_query(nc, req->name, req->query); req->last_time = now; req->retries++; diff --git a/src/mg_ssl_if_mbedtls.c b/src/mg_ssl_if_mbedtls.c index 9bf07fa9..38ba1869 100644 --- a/src/mg_ssl_if_mbedtls.c +++ b/src/mg_ssl_if_mbedtls.c @@ -7,9 +7,12 @@ #include #include +#include #include #include +#include #include +#include static void mg_ssl_mbed_log(void *ctx, int level, const char *file, int line, const char *str) { @@ -19,6 +22,8 @@ static void mg_ssl_mbed_log(void *ctx, int level, const char *file, int line, cs_level = LL_ERROR; break; case 2: + cs_level = LL_INFO; + break; case 3: cs_level = LL_DEBUG; break; @@ -38,12 +43,14 @@ struct mg_ssl_if_ctx { mbedtls_pk_context *key; mbedtls_x509_crt *ca_cert; struct mbuf cipher_suites; + size_t saved_len; }; /* Must be provided by the platform. ctx is struct mg_connection. */ extern int mg_ssl_if_mbed_random(void *ctx, unsigned char *buf, size_t len); void mg_ssl_if_init() { + LOG(LL_INFO, ("%s", MBEDTLS_VERSION_STRING_FULL)); } enum mg_ssl_if_result mg_ssl_if_conn_accept(struct mg_connection *nc, @@ -164,40 +171,41 @@ enum mg_ssl_if_result mg_ssl_if_conn_init( return MG_SSL_OK; } -#if MG_NET_IF == MG_NET_IF_LWIP_LOW_LEVEL -int ssl_socket_send(void *ctx, const unsigned char *buf, size_t len); -int ssl_socket_recv(void *ctx, unsigned char *buf, size_t len); -#else -static int ssl_socket_send(void *ctx, const unsigned char *buf, size_t len) { +static int mg_ssl_if_mbed_send(void *ctx, const unsigned char *buf, + size_t len) { struct mg_connection *nc = (struct mg_connection *) ctx; - int n = (int) MG_SEND_FUNC(nc->sock, buf, len, 0); - LOG(LL_DEBUG, ("%p %d -> %d", nc, (int) len, n)); - if (n >= 0) return n; - n = mg_get_errno(); - return ((n == EAGAIN || n == EINPROGRESS) ? MBEDTLS_ERR_SSL_WANT_WRITE : -1); + int n = nc->iface->vtable->tcp_send(nc, buf, len); + if (n > 0) return n; + if (n == 0) return MBEDTLS_ERR_SSL_WANT_WRITE; + return MBEDTLS_ERR_NET_SEND_FAILED; } -static int ssl_socket_recv(void *ctx, unsigned char *buf, size_t len) { +static int mg_ssl_if_mbed_recv(void *ctx, unsigned char *buf, size_t len) { struct mg_connection *nc = (struct mg_connection *) ctx; - int n = (int) MG_RECV_FUNC(nc->sock, buf, len, 0); - LOG(LL_DEBUG, ("%p %d <- %d", nc, (int) len, n)); - if (n >= 0) return n; - n = mg_get_errno(); - return ((n == EAGAIN || n == EINPROGRESS) ? MBEDTLS_ERR_SSL_WANT_READ : -1); + int n = nc->iface->vtable->tcp_recv(nc, buf, len); + if (n > 0) return n; + if (n == 0) return MBEDTLS_ERR_SSL_WANT_READ; + return MBEDTLS_ERR_NET_RECV_FAILED; } -#endif static enum mg_ssl_if_result mg_ssl_if_mbed_err(struct mg_connection *nc, int ret) { - if (ret == MBEDTLS_ERR_SSL_WANT_READ) return MG_SSL_WANT_READ; - if (ret == MBEDTLS_ERR_SSL_WANT_WRITE) return MG_SSL_WANT_WRITE; - if (ret != - MBEDTLS_ERR_SSL_PEER_CLOSE_NOTIFY) { /* CLOSE_NOTIFY = Normal shutdown */ - LOG(LL_ERROR, ("%p SSL error: %d", nc, ret)); + enum mg_ssl_if_result res = MG_SSL_OK; + if (ret == MBEDTLS_ERR_SSL_WANT_READ) { + res = MG_SSL_WANT_READ; + } else if (ret == MBEDTLS_ERR_SSL_WANT_WRITE) { + res = MG_SSL_WANT_WRITE; + } else if (ret == MBEDTLS_ERR_SSL_PEER_CLOSE_NOTIFY) { + LOG(LL_DEBUG, ("%p TLS connection closed by peer", nc)); + nc->flags |= MG_F_CLOSE_IMMEDIATELY; + res = MG_SSL_OK; + } else { + LOG(LL_ERROR, ("%p mbedTLS error: -0x%04x", nc, -ret)); + nc->flags |= MG_F_CLOSE_IMMEDIATELY; + res = MG_SSL_ERROR; } nc->err = ret; - nc->flags |= MG_F_CLOSE_IMMEDIATELY; - return MG_SSL_ERROR; + return res; } static void mg_ssl_if_mbed_free_certs_and_keys(struct mg_ssl_if_ctx *ctx) { @@ -228,7 +236,8 @@ enum mg_ssl_if_result mg_ssl_if_handshake(struct mg_connection *nc) { int err; /* If bio is not yet set, do it now. */ if (ctx->ssl->p_bio == NULL) { - mbedtls_ssl_set_bio(ctx->ssl, nc, ssl_socket_send, ssl_socket_recv, NULL); + mbedtls_ssl_set_bio(ctx->ssl, nc, mg_ssl_if_mbed_send, mg_ssl_if_mbed_recv, + NULL); } err = mbedtls_ssl_handshake(ctx->ssl); if (err != 0) return mg_ssl_if_mbed_err(nc, err); @@ -254,20 +263,35 @@ enum mg_ssl_if_result mg_ssl_if_handshake(struct mg_connection *nc) { return MG_SSL_OK; } -int mg_ssl_if_read(struct mg_connection *nc, void *buf, size_t buf_size) { +int mg_ssl_if_read(struct mg_connection *nc, void *buf, size_t len) { struct mg_ssl_if_ctx *ctx = (struct mg_ssl_if_ctx *) nc->ssl_if_data; - int n = mbedtls_ssl_read(ctx->ssl, (unsigned char *) buf, buf_size); - DBG(("%p %d -> %d", nc, (int) buf_size, n)); + int n = mbedtls_ssl_read(ctx->ssl, (unsigned char *) buf, len); + DBG(("%p %d -> %d", nc, (int) len, n)); if (n < 0) return mg_ssl_if_mbed_err(nc, n); if (n == 0) nc->flags |= MG_F_CLOSE_IMMEDIATELY; return n; } -int mg_ssl_if_write(struct mg_connection *nc, const void *data, size_t len) { +int mg_ssl_if_write(struct mg_connection *nc, const void *buf, size_t len) { struct mg_ssl_if_ctx *ctx = (struct mg_ssl_if_ctx *) nc->ssl_if_data; - int n = mbedtls_ssl_write(ctx->ssl, (const unsigned char *) data, len); - DBG(("%p %d -> %d", nc, (int) len, n)); - if (n < 0) return mg_ssl_if_mbed_err(nc, n); + /* Per mbedTLS docs, if write returns WANT_READ or WANT_WRITE, the operation + * should be retried with the same data and length. + * Here we assume that the data being pushed will remain the same but the + * amount may grow between calls so we save the length that was used and + * retry. The assumption being that the data itself won't change and won't + * be removed. */ + size_t l = len; + if (ctx->saved_len > 0 && ctx->saved_len < l) l = ctx->saved_len; + int n = mbedtls_ssl_write(ctx->ssl, (const unsigned char *) buf, l); + DBG(("%p %d,%d,%d -> %d", nc, (int) len, (int) ctx->saved_len, (int) l, n)); + if (n < 0) { + if (n == MBEDTLS_ERR_SSL_WANT_READ || n == MBEDTLS_ERR_SSL_WANT_WRITE) { + ctx->saved_len = len; + } + return mg_ssl_if_mbed_err(nc, n); + } else if (n > 0) { + ctx->saved_len = 0; + } return n; } diff --git a/test/unit_test.c b/test/unit_test.c index b6f95989..446217b1 100644 --- a/test/unit_test.c +++ b/test/unit_test.c @@ -1145,7 +1145,7 @@ static const char *test_timer(void) { ASSERT((c = mg_connect(&m, "awful.sad:1234", ev_timer_handler)) != NULL); c->user_data = &n; mg_set_timer(c, 1); - mg_mgr_poll(&m, 1); + poll_until(&m, 1, c_int_eq, &n, (void *) 101); ASSERT_EQ(n, 101); mg_mgr_free(&m); @@ -2019,6 +2019,7 @@ static const char *test_http(void) { ASSERT((nc = mg_connect(&mgr, local_addr, cb7)) != NULL); mg_set_protocol_http_websocket(nc); nc->user_data = status; + mbuf_resize(&nc->recv_mbuf, 10000000); /* Wine and GDB set argv0 to full path: strip the dir component */ if ((this_binary = strrchr(g_argv_0, '\\')) != NULL) { @@ -5454,12 +5455,14 @@ static const char *test_socks(void) { this_binary = g_argv_0; } mg_printf(c, "GET /%s HTTP/1.0\n\n", this_binary); + mbuf_resize(&c->recv_mbuf, 10000000); /* Run event loop. Use more cycles to let file download complete. */ - poll_until(&mgr, 5, c_str_ne, status, (void *) ""); - mg_mgr_free(&mgr); + poll_until(&mgr, 10, c_str_ne, status, (void *) ""); ASSERT_STREQ(status, "success"); + mg_mgr_free(&mgr); + return NULL; } #endif From 4650e491df41f35b38d307dc9d1c9c0737a626f7 Mon Sep 17 00:00:00 2001 From: Sergey Lyubka Date: Tue, 3 Apr 2018 12:30:06 +0100 Subject: [PATCH 14/41] Apache license to common/ CL: Apache license to common/ PUBLISHED_FROM=901e9e4b12a31289b3515d1f86dd56a7f0f35c5e --- src/common/cs_dbg.c | 14 +++++++++++- src/common/cs_dbg.h | 14 +++++++++++- src/common/cs_md5.h | 14 +++++++++++- src/common/cs_time.c | 14 +++++++++++- src/common/cs_time.h | 14 +++++++++++- src/common/mg_mem.h | 14 +++++++++++- src/common/platforms/arm/arm_exc.c | 14 +++++++++++- src/common/platforms/cc3200/cc3200_libc.c | 14 +++++++++++- src/common/platforms/esp/stub_flasher.c | 22 +++++++++---------- src/common/platforms/esp32/stubs/led.c | 14 +++++++++++- src/common/platforms/esp32/stubs/led.h | 14 +++++++++++- src/common/platforms/esp32/stubs/stub_hello.c | 13 +++++++++-- src/common/platforms/esp32/stubs/uart.c | 14 +++++++++++- src/common/platforms/esp32/stubs/uart.h | 14 +++++++++++- src/common/platforms/esp8266/esp_crypto.c | 14 +++++++++++- .../platforms/esp8266/esp_hw_wdt_register.h | 14 +++++++++++- .../platforms/esp8266/esp_missing_includes.h | 14 +++++++++++- .../platforms/esp8266/esp_ssl_krypton.h | 14 +++++++++++- src/common/platforms/esp8266/esp_umm_malloc.c | 14 +++++++++++- src/common/platforms/esp8266/esp_umm_malloc.h | 14 +++++++++++- .../platforms/esp8266/stubs/stub_hello.c | 13 +++++++++-- src/common/platforms/esp8266/stubs/uart.c | 14 +++++++++++- src/common/platforms/esp8266/stubs/uart.h | 14 +++++++++++- src/common/platforms/lwip/mg_lwip.h | 14 +++++++++++- src/common/platforms/lwip/mg_lwip_ev_mgr.c | 14 +++++++++++- src/common/platforms/lwip/mg_lwip_net_if.c | 14 +++++++++++- src/common/platforms/lwip/mg_lwip_net_if.h | 14 +++++++++++- src/common/platforms/mbed/mbed_libc.c | 14 +++++++++++- src/common/platforms/msp432/msp432_libc.c | 14 +++++++++++- src/common/platforms/nrf5/nrf5_libc.c | 14 +++++++++++- src/common/platforms/pic32/pic32_net_if.c | 14 +++++++++++- src/common/platforms/pic32/pic32_net_if.h | 14 +++++++++++- src/common/platforms/platform_cc3100.h | 14 +++++++++++- src/common/platforms/platform_cc3200.h | 14 +++++++++++- src/common/platforms/platform_cc3220.h | 14 +++++++++++- src/common/platforms/platform_esp32.h | 14 +++++++++++- src/common/platforms/platform_esp8266.h | 14 +++++++++++- src/common/platforms/platform_mbed.h | 14 +++++++++++- src/common/platforms/platform_msp432.h | 14 +++++++++++- src/common/platforms/platform_nrf51.h | 14 +++++++++++- src/common/platforms/platform_nrf52.h | 14 +++++++++++- src/common/platforms/platform_nxp_kinetis.h | 14 +++++++++++- src/common/platforms/platform_nxp_lpc.h | 14 +++++++++++- src/common/platforms/platform_pic32.h | 14 +++++++++++- src/common/platforms/platform_stm32.h | 14 +++++++++++- src/common/platforms/platform_tm4c129.h | 14 +++++++++++- .../platforms/simplelink/cs_simplelink.h | 14 +++++++++++- src/common/platforms/simplelink/sl_fs.c | 14 +++++++++++- src/common/platforms/simplelink/sl_fs_slfs.c | 14 +++++++++++- src/common/platforms/simplelink/sl_fs_slfs.h | 14 +++++++++++- src/common/platforms/simplelink/sl_net_if.c | 14 +++++++++++- src/common/platforms/simplelink/sl_net_if.h | 14 +++++++++++- src/common/platforms/simplelink/sl_socket.c | 14 +++++++++++- src/common/platforms/simplelink/sl_ssl_if.c | 14 +++++++++++- src/common/platforms/wince/wince_libc.c | 14 +++++++++++- src/common/platforms/windows/windows_direct.c | 14 +++++++++++- src/common/test_main.c | 12 ++++++++++ src/common/test_main.h | 12 ++++++++++ src/common/test_util.c | 14 +++++++++++- src/common/test_util.h | 22 +++++++++---------- 60 files changed, 769 insertions(+), 81 deletions(-) diff --git a/src/common/cs_dbg.c b/src/common/cs_dbg.c index da1bc2e9..62a5816d 100644 --- a/src/common/cs_dbg.c +++ b/src/common/cs_dbg.c @@ -1,6 +1,18 @@ /* - * Copyright (c) 2014-2016 Cesanta Software Limited + * Copyright (c) 2014-2018 Cesanta Software Limited * All rights reserved + * + * Licensed under the Apache License, Version 2.0 (the ""License""); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an ""AS IS"" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. */ #include "common/cs_dbg.h" diff --git a/src/common/cs_dbg.h b/src/common/cs_dbg.h index 24a70220..5e964334 100644 --- a/src/common/cs_dbg.h +++ b/src/common/cs_dbg.h @@ -1,6 +1,18 @@ /* - * Copyright (c) 2014-2016 Cesanta Software Limited + * Copyright (c) 2014-2018 Cesanta Software Limited * All rights reserved + * + * Licensed under the Apache License, Version 2.0 (the ""License""); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an ""AS IS"" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. */ #ifndef CS_COMMON_CS_DBG_H_ diff --git a/src/common/cs_md5.h b/src/common/cs_md5.h index 1450fd26..302b0327 100644 --- a/src/common/cs_md5.h +++ b/src/common/cs_md5.h @@ -1,6 +1,18 @@ /* - * Copyright (c) 2014 Cesanta Software Limited + * Copyright (c) 2014-2018 Cesanta Software Limited * All rights reserved + * + * Licensed under the Apache License, Version 2.0 (the ""License""); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an ""AS IS"" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. */ #ifndef CS_COMMON_MD5_H_ diff --git a/src/common/cs_time.c b/src/common/cs_time.c index f21845cf..f14de39e 100644 --- a/src/common/cs_time.c +++ b/src/common/cs_time.c @@ -1,6 +1,18 @@ /* - * Copyright (c) 2014-2016 Cesanta Software Limited + * Copyright (c) 2014-2018 Cesanta Software Limited * All rights reserved + * + * Licensed under the Apache License, Version 2.0 (the ""License""); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an ""AS IS"" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. */ #include "common/cs_time.h" diff --git a/src/common/cs_time.h b/src/common/cs_time.h index 3b590735..eba53957 100644 --- a/src/common/cs_time.h +++ b/src/common/cs_time.h @@ -1,6 +1,18 @@ /* - * Copyright (c) 2014-2016 Cesanta Software Limited + * Copyright (c) 2014-2018 Cesanta Software Limited * All rights reserved + * + * Licensed under the Apache License, Version 2.0 (the ""License""); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an ""AS IS"" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. */ #ifndef CS_COMMON_CS_TIME_H_ diff --git a/src/common/mg_mem.h b/src/common/mg_mem.h index 65d71c7c..7fe8381d 100644 --- a/src/common/mg_mem.h +++ b/src/common/mg_mem.h @@ -1,6 +1,18 @@ /* - * Copyright (c) 2014-2016 Cesanta Software Limited + * Copyright (c) 2014-2018 Cesanta Software Limited * All rights reserved + * + * Licensed under the Apache License, Version 2.0 (the ""License""); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an ""AS IS"" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. */ #ifndef CS_COMMON_MG_MEM_H_ diff --git a/src/common/platforms/arm/arm_exc.c b/src/common/platforms/arm/arm_exc.c index 60b50c89..7f83b3cc 100644 --- a/src/common/platforms/arm/arm_exc.c +++ b/src/common/platforms/arm/arm_exc.c @@ -1,6 +1,18 @@ /* - * Copyright (c) 2014-2017 Cesanta Software Limited + * Copyright (c) 2014-2018 Cesanta Software Limited * All rights reserved + * + * Licensed under the Apache License, Version 2.0 (the ""License""); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an ""AS IS"" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. */ #include diff --git a/src/common/platforms/cc3200/cc3200_libc.c b/src/common/platforms/cc3200/cc3200_libc.c index f488725b..5262917b 100644 --- a/src/common/platforms/cc3200/cc3200_libc.c +++ b/src/common/platforms/cc3200/cc3200_libc.c @@ -1,6 +1,18 @@ /* - * Copyright (c) 2014-2016 Cesanta Software Limited + * Copyright (c) 2014-2018 Cesanta Software Limited * All rights reserved + * + * Licensed under the Apache License, Version 2.0 (the ""License""); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an ""AS IS"" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. */ #if CS_PLATFORM == CS_P_CC3200 diff --git a/src/common/platforms/esp/stub_flasher.c b/src/common/platforms/esp/stub_flasher.c index be7398cf..d733d359 100644 --- a/src/common/platforms/esp/stub_flasher.c +++ b/src/common/platforms/esp/stub_flasher.c @@ -1,20 +1,18 @@ /* - * Copyright (c) 2014-2016 Cesanta Software Limited + * Copyright (c) 2014-2018 Cesanta Software Limited * All rights reserved * - * Spiffy flasher. Implements strong checksums (MD5) and can use higher - * baud rates. Actual max baud rate will differe from device to device, - * but 921K seems to be common. + * Licensed under the Apache License, Version 2.0 (the ""License""); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at * - * SLIP protocol is used for communication. - * First packet is a single byte - command number. - * After that, a packet with a variable number of 32-bit (LE) arguments, - * depending on command. + * http://www.apache.org/licenses/LICENSE-2.0 * - * Then command produces variable number of packets of output, but first - * packet of length 1 is the response code: 0 for success, non-zero - error. - * - * See individual command description below. + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an ""AS IS"" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. */ #include "stub_flasher.h" diff --git a/src/common/platforms/esp32/stubs/led.c b/src/common/platforms/esp32/stubs/led.c index 6cfc766f..dfa69210 100644 --- a/src/common/platforms/esp32/stubs/led.c +++ b/src/common/platforms/esp32/stubs/led.c @@ -1,6 +1,18 @@ /* - * Copyright (c) 2014-2017 Cesanta Software Limited + * Copyright (c) 2014-2018 Cesanta Software Limited * All rights reserved + * + * Licensed under the Apache License, Version 2.0 (the ""License""); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an ""AS IS"" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. */ #include "soc/gpio_reg.h" diff --git a/src/common/platforms/esp32/stubs/led.h b/src/common/platforms/esp32/stubs/led.h index 505a3f6a..e79733d9 100644 --- a/src/common/platforms/esp32/stubs/led.h +++ b/src/common/platforms/esp32/stubs/led.h @@ -1,6 +1,18 @@ /* - * Copyright (c) 2014-2017 Cesanta Software Limited + * Copyright (c) 2014-2018 Cesanta Software Limited * All rights reserved + * + * Licensed under the Apache License, Version 2.0 (the ""License""); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an ""AS IS"" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. */ #pragma once diff --git a/src/common/platforms/esp32/stubs/stub_hello.c b/src/common/platforms/esp32/stubs/stub_hello.c index a4c75eb9..3f64a406 100644 --- a/src/common/platforms/esp32/stubs/stub_hello.c +++ b/src/common/platforms/esp32/stubs/stub_hello.c @@ -1,9 +1,18 @@ /* - * Copyright (c) 2015 Cesanta Software Limited + * Copyright (c) 2014-2018 Cesanta Software Limited * All rights reserved * + * Licensed under the Apache License, Version 2.0 (the ""License""); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at * - * Stub template. + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an ""AS IS"" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. */ #include diff --git a/src/common/platforms/esp32/stubs/uart.c b/src/common/platforms/esp32/stubs/uart.c index c6eb25dc..8d2bca74 100644 --- a/src/common/platforms/esp32/stubs/uart.c +++ b/src/common/platforms/esp32/stubs/uart.c @@ -1,6 +1,18 @@ /* - * Copyright (c) 2014-2016 Cesanta Software Limited + * Copyright (c) 2014-2018 Cesanta Software Limited * All rights reserved + * + * Licensed under the Apache License, Version 2.0 (the ""License""); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an ""AS IS"" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. */ #include "uart.h" diff --git a/src/common/platforms/esp32/stubs/uart.h b/src/common/platforms/esp32/stubs/uart.h index aa3c4ed0..b28edf88 100644 --- a/src/common/platforms/esp32/stubs/uart.h +++ b/src/common/platforms/esp32/stubs/uart.h @@ -1,6 +1,18 @@ /* - * Copyright (c) 2014-2016 Cesanta Software Limited + * Copyright (c) 2014-2018 Cesanta Software Limited * All rights reserved + * + * Licensed under the Apache License, Version 2.0 (the ""License""); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an ""AS IS"" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. */ #ifndef CS_COMMON_PLATFORMS_ESP32_STUBS_UART_H_ diff --git a/src/common/platforms/esp8266/esp_crypto.c b/src/common/platforms/esp8266/esp_crypto.c index 3d2afa14..6469cae0 100644 --- a/src/common/platforms/esp8266/esp_crypto.c +++ b/src/common/platforms/esp8266/esp_crypto.c @@ -1,6 +1,18 @@ /* - * Copyright (c) 2014-2016 Cesanta Software Limited + * Copyright (c) 2014-2018 Cesanta Software Limited * All rights reserved + * + * Licensed under the Apache License, Version 2.0 (the ""License""); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an ""AS IS"" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. */ #include diff --git a/src/common/platforms/esp8266/esp_hw_wdt_register.h b/src/common/platforms/esp8266/esp_hw_wdt_register.h index 32c2f3cf..681d31ac 100644 --- a/src/common/platforms/esp8266/esp_hw_wdt_register.h +++ b/src/common/platforms/esp8266/esp_hw_wdt_register.h @@ -1,6 +1,18 @@ /* - * Copyright (c) 2014-2017 Cesanta Software Limited + * Copyright (c) 2014-2018 Cesanta Software Limited * All rights reserved + * + * Licensed under the Apache License, Version 2.0 (the ""License""); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an ""AS IS"" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. */ #ifndef CS_COMMON_PLATFORMS_ESP8266_ESP_HW_WDT_REGISTER_H_ diff --git a/src/common/platforms/esp8266/esp_missing_includes.h b/src/common/platforms/esp8266/esp_missing_includes.h index fc7d69f3..e6ef8e7c 100644 --- a/src/common/platforms/esp8266/esp_missing_includes.h +++ b/src/common/platforms/esp8266/esp_missing_includes.h @@ -1,6 +1,18 @@ /* - * Copyright (c) 2014-2016 Cesanta Software Limited + * Copyright (c) 2014-2018 Cesanta Software Limited * All rights reserved + * + * Licensed under the Apache License, Version 2.0 (the ""License""); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an ""AS IS"" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. */ #ifndef CS_COMMON_PLATFORMS_ESP8266_ESP_MISSING_INCLUDES_H_ diff --git a/src/common/platforms/esp8266/esp_ssl_krypton.h b/src/common/platforms/esp8266/esp_ssl_krypton.h index 086c6b50..75a2353b 100644 --- a/src/common/platforms/esp8266/esp_ssl_krypton.h +++ b/src/common/platforms/esp8266/esp_ssl_krypton.h @@ -1,6 +1,18 @@ /* - * Copyright (c) 2014-2016 Cesanta Software Limited + * Copyright (c) 2014-2018 Cesanta Software Limited * All rights reserved + * + * Licensed under the Apache License, Version 2.0 (the ""License""); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an ""AS IS"" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. */ #ifndef CS_COMMON_PLATFORMS_ESP8266_ESP_SSL_KRYPTON_H_ diff --git a/src/common/platforms/esp8266/esp_umm_malloc.c b/src/common/platforms/esp8266/esp_umm_malloc.c index 3dd4a0e7..15869a71 100644 --- a/src/common/platforms/esp8266/esp_umm_malloc.c +++ b/src/common/platforms/esp8266/esp_umm_malloc.c @@ -1,6 +1,18 @@ /* - * Copyright (c) 2014 Cesanta Software Limited + * Copyright (c) 2014-2018 Cesanta Software Limited * All rights reserved + * + * Licensed under the Apache License, Version 2.0 (the ""License""); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an ""AS IS"" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. */ #include diff --git a/src/common/platforms/esp8266/esp_umm_malloc.h b/src/common/platforms/esp8266/esp_umm_malloc.h index efb6f4ba..f838e4f3 100644 --- a/src/common/platforms/esp8266/esp_umm_malloc.h +++ b/src/common/platforms/esp8266/esp_umm_malloc.h @@ -1,6 +1,18 @@ /* - * Copyright (c) 2014 Cesanta Software Limited + * Copyright (c) 2014-2018 Cesanta Software Limited * All rights reserved + * + * Licensed under the Apache License, Version 2.0 (the ""License""); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an ""AS IS"" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. */ #if ESP_UMM_ENABLE diff --git a/src/common/platforms/esp8266/stubs/stub_hello.c b/src/common/platforms/esp8266/stubs/stub_hello.c index 10a827d9..83c035c4 100644 --- a/src/common/platforms/esp8266/stubs/stub_hello.c +++ b/src/common/platforms/esp8266/stubs/stub_hello.c @@ -1,9 +1,18 @@ /* - * Copyright (c) 2015 Cesanta Software Limited + * Copyright (c) 2014-2018 Cesanta Software Limited * All rights reserved * + * Licensed under the Apache License, Version 2.0 (the ""License""); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at * - * Stub template. + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an ""AS IS"" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. */ #include diff --git a/src/common/platforms/esp8266/stubs/uart.c b/src/common/platforms/esp8266/stubs/uart.c index 5651bd84..cb99b2d9 100644 --- a/src/common/platforms/esp8266/stubs/uart.c +++ b/src/common/platforms/esp8266/stubs/uart.c @@ -1,6 +1,18 @@ /* - * Copyright (c) 2014-2016 Cesanta Software Limited + * Copyright (c) 2014-2018 Cesanta Software Limited * All rights reserved + * + * Licensed under the Apache License, Version 2.0 (the ""License""); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an ""AS IS"" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. */ #include "uart.h" diff --git a/src/common/platforms/esp8266/stubs/uart.h b/src/common/platforms/esp8266/stubs/uart.h index fc321c2a..ad3ef1dc 100644 --- a/src/common/platforms/esp8266/stubs/uart.h +++ b/src/common/platforms/esp8266/stubs/uart.h @@ -1,6 +1,18 @@ /* - * Copyright (c) 2014-2016 Cesanta Software Limited + * Copyright (c) 2014-2018 Cesanta Software Limited * All rights reserved + * + * Licensed under the Apache License, Version 2.0 (the ""License""); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an ""AS IS"" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. */ #ifndef CS_COMMON_PLATFORMS_ESP8266_STUBS_UART_H_ diff --git a/src/common/platforms/lwip/mg_lwip.h b/src/common/platforms/lwip/mg_lwip.h index 1a772aa1..c0d4081e 100644 --- a/src/common/platforms/lwip/mg_lwip.h +++ b/src/common/platforms/lwip/mg_lwip.h @@ -1,6 +1,18 @@ /* - * Copyright (c) 2014-2016 Cesanta Software Limited + * Copyright (c) 2014-2018 Cesanta Software Limited * All rights reserved + * + * Licensed under the Apache License, Version 2.0 (the ""License""); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an ""AS IS"" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. */ #ifndef CS_COMMON_PLATFORMS_LWIP_MG_LWIP_H_ diff --git a/src/common/platforms/lwip/mg_lwip_ev_mgr.c b/src/common/platforms/lwip/mg_lwip_ev_mgr.c index 11a1bfc1..1e844a82 100644 --- a/src/common/platforms/lwip/mg_lwip_ev_mgr.c +++ b/src/common/platforms/lwip/mg_lwip_ev_mgr.c @@ -1,6 +1,18 @@ /* - * Copyright (c) 2014-2016 Cesanta Software Limited + * Copyright (c) 2014-2018 Cesanta Software Limited * All rights reserved + * + * Licensed under the Apache License, Version 2.0 (the ""License""); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an ""AS IS"" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. */ #if MG_NET_IF == MG_NET_IF_LWIP_LOW_LEVEL diff --git a/src/common/platforms/lwip/mg_lwip_net_if.c b/src/common/platforms/lwip/mg_lwip_net_if.c index b9042e83..f73f607a 100644 --- a/src/common/platforms/lwip/mg_lwip_net_if.c +++ b/src/common/platforms/lwip/mg_lwip_net_if.c @@ -1,6 +1,18 @@ /* - * Copyright (c) 2014-2016 Cesanta Software Limited + * Copyright (c) 2014-2018 Cesanta Software Limited * All rights reserved + * + * Licensed under the Apache License, Version 2.0 (the ""License""); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an ""AS IS"" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. */ #if MG_ENABLE_NET_IF_LWIP_LOW_LEVEL diff --git a/src/common/platforms/lwip/mg_lwip_net_if.h b/src/common/platforms/lwip/mg_lwip_net_if.h index d94cfdf6..d9827a90 100644 --- a/src/common/platforms/lwip/mg_lwip_net_if.h +++ b/src/common/platforms/lwip/mg_lwip_net_if.h @@ -1,6 +1,18 @@ /* - * Copyright (c) 2014-2016 Cesanta Software Limited + * Copyright (c) 2014-2018 Cesanta Software Limited * All rights reserved + * + * Licensed under the Apache License, Version 2.0 (the ""License""); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an ""AS IS"" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. */ #ifndef CS_COMMON_PLATFORMS_LWIP_MG_NET_IF_LWIP_H_ diff --git a/src/common/platforms/mbed/mbed_libc.c b/src/common/platforms/mbed/mbed_libc.c index a5b35b1f..ef8e6abb 100644 --- a/src/common/platforms/mbed/mbed_libc.c +++ b/src/common/platforms/mbed/mbed_libc.c @@ -1,6 +1,18 @@ /* - * Copyright (c) 2014-2016 Cesanta Software Limited + * Copyright (c) 2014-2018 Cesanta Software Limited * All rights reserved + * + * Licensed under the Apache License, Version 2.0 (the ""License""); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an ""AS IS"" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. */ #include "common/platform.h" diff --git a/src/common/platforms/msp432/msp432_libc.c b/src/common/platforms/msp432/msp432_libc.c index faedadc2..de1e6ba8 100644 --- a/src/common/platforms/msp432/msp432_libc.c +++ b/src/common/platforms/msp432/msp432_libc.c @@ -1,6 +1,18 @@ /* - * Copyright (c) 2014-2016 Cesanta Software Limited + * Copyright (c) 2014-2018 Cesanta Software Limited * All rights reserved + * + * Licensed under the Apache License, Version 2.0 (the ""License""); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an ""AS IS"" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. */ #if CS_PLATFORM == CS_P_MSP432 diff --git a/src/common/platforms/nrf5/nrf5_libc.c b/src/common/platforms/nrf5/nrf5_libc.c index 9cf66dcc..65d05ed4 100644 --- a/src/common/platforms/nrf5/nrf5_libc.c +++ b/src/common/platforms/nrf5/nrf5_libc.c @@ -1,6 +1,18 @@ /* - * Copyright (c) 2014-2016 Cesanta Software Limited + * Copyright (c) 2014-2018 Cesanta Software Limited * All rights reserved + * + * Licensed under the Apache License, Version 2.0 (the ""License""); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an ""AS IS"" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. */ #if (CS_PLATFORM == CS_P_NRF51 || CS_PLATFORM == CS_P_NRF52) && \ diff --git a/src/common/platforms/pic32/pic32_net_if.c b/src/common/platforms/pic32/pic32_net_if.c index d0e67e9a..49618c57 100644 --- a/src/common/platforms/pic32/pic32_net_if.c +++ b/src/common/platforms/pic32/pic32_net_if.c @@ -1,6 +1,18 @@ /* - * Copyright (c) 2014-2016 Cesanta Software Limited + * Copyright (c) 2014-2018 Cesanta Software Limited * All rights reserved + * + * Licensed under the Apache License, Version 2.0 (the ""License""); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an ""AS IS"" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. */ #if MG_ENABLE_NET_IF_PIC32 diff --git a/src/common/platforms/pic32/pic32_net_if.h b/src/common/platforms/pic32/pic32_net_if.h index 2bf66ef6..52ae891d 100644 --- a/src/common/platforms/pic32/pic32_net_if.h +++ b/src/common/platforms/pic32/pic32_net_if.h @@ -1,6 +1,18 @@ /* - * Copyright (c) 2014-2016 Cesanta Software Limited + * Copyright (c) 2014-2018 Cesanta Software Limited * All rights reserved + * + * Licensed under the Apache License, Version 2.0 (the ""License""); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an ""AS IS"" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. */ #ifndef CS_COMMON_PLATFORMS_PIC32_NET_IF_H_ diff --git a/src/common/platforms/platform_cc3100.h b/src/common/platforms/platform_cc3100.h index ba07f220..8e847fcf 100644 --- a/src/common/platforms/platform_cc3100.h +++ b/src/common/platforms/platform_cc3100.h @@ -1,6 +1,18 @@ /* - * Copyright (c) 2014-2016 Cesanta Software Limited + * Copyright (c) 2014-2018 Cesanta Software Limited * All rights reserved + * + * Licensed under the Apache License, Version 2.0 (the ""License""); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an ""AS IS"" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. */ #ifndef CS_COMMON_PLATFORMS_PLATFORM_CC3100_H_ diff --git a/src/common/platforms/platform_cc3200.h b/src/common/platforms/platform_cc3200.h index 1c2033af..00ef9fa3 100644 --- a/src/common/platforms/platform_cc3200.h +++ b/src/common/platforms/platform_cc3200.h @@ -1,6 +1,18 @@ /* - * Copyright (c) 2014-2016 Cesanta Software Limited + * Copyright (c) 2014-2018 Cesanta Software Limited * All rights reserved + * + * Licensed under the Apache License, Version 2.0 (the ""License""); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an ""AS IS"" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. */ #ifndef CS_COMMON_PLATFORMS_PLATFORM_CC3200_H_ diff --git a/src/common/platforms/platform_cc3220.h b/src/common/platforms/platform_cc3220.h index 6992e142..c5336e33 100644 --- a/src/common/platforms/platform_cc3220.h +++ b/src/common/platforms/platform_cc3220.h @@ -1,6 +1,18 @@ /* - * Copyright (c) 2014-2016 Cesanta Software Limited + * Copyright (c) 2014-2018 Cesanta Software Limited * All rights reserved + * + * Licensed under the Apache License, Version 2.0 (the ""License""); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an ""AS IS"" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. */ #ifndef CS_COMMON_PLATFORMS_PLATFORM_CC3220_H_ diff --git a/src/common/platforms/platform_esp32.h b/src/common/platforms/platform_esp32.h index 4580f75a..b1af9da5 100644 --- a/src/common/platforms/platform_esp32.h +++ b/src/common/platforms/platform_esp32.h @@ -1,6 +1,18 @@ /* - * Copyright (c) 2014-2016 Cesanta Software Limited + * Copyright (c) 2014-2018 Cesanta Software Limited * All rights reserved + * + * Licensed under the Apache License, Version 2.0 (the ""License""); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an ""AS IS"" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. */ #ifndef CS_COMMON_PLATFORMS_PLATFORM_ESP32_H_ diff --git a/src/common/platforms/platform_esp8266.h b/src/common/platforms/platform_esp8266.h index b3971013..0428f058 100644 --- a/src/common/platforms/platform_esp8266.h +++ b/src/common/platforms/platform_esp8266.h @@ -1,6 +1,18 @@ /* - * Copyright (c) 2014-2016 Cesanta Software Limited + * Copyright (c) 2014-2018 Cesanta Software Limited * All rights reserved + * + * Licensed under the Apache License, Version 2.0 (the ""License""); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an ""AS IS"" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. */ #ifndef CS_COMMON_PLATFORMS_PLATFORM_ESP8266_H_ diff --git a/src/common/platforms/platform_mbed.h b/src/common/platforms/platform_mbed.h index ab3f5639..5f37862a 100644 --- a/src/common/platforms/platform_mbed.h +++ b/src/common/platforms/platform_mbed.h @@ -1,6 +1,18 @@ /* - * Copyright (c) 2014-2016 Cesanta Software Limited + * Copyright (c) 2014-2018 Cesanta Software Limited * All rights reserved + * + * Licensed under the Apache License, Version 2.0 (the ""License""); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an ""AS IS"" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. */ #ifndef CS_COMMON_PLATFORMS_PLATFORM_MBED_H_ diff --git a/src/common/platforms/platform_msp432.h b/src/common/platforms/platform_msp432.h index d8cf16a1..d9c5e183 100644 --- a/src/common/platforms/platform_msp432.h +++ b/src/common/platforms/platform_msp432.h @@ -1,6 +1,18 @@ /* - * Copyright (c) 2014-2016 Cesanta Software Limited + * Copyright (c) 2014-2018 Cesanta Software Limited * All rights reserved + * + * Licensed under the Apache License, Version 2.0 (the ""License""); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an ""AS IS"" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. */ #ifndef CS_COMMON_PLATFORMS_PLATFORM_MSP432_H_ diff --git a/src/common/platforms/platform_nrf51.h b/src/common/platforms/platform_nrf51.h index 55f89dda..6f1357bd 100644 --- a/src/common/platforms/platform_nrf51.h +++ b/src/common/platforms/platform_nrf51.h @@ -1,6 +1,18 @@ /* - * Copyright (c) 2014-2016 Cesanta Software Limited + * Copyright (c) 2014-2018 Cesanta Software Limited * All rights reserved + * + * Licensed under the Apache License, Version 2.0 (the ""License""); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an ""AS IS"" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. */ #ifndef CS_COMMON_PLATFORMS_PLATFORM_NRF51_H_ #define CS_COMMON_PLATFORMS_PLATFORM_NRF51_H_ diff --git a/src/common/platforms/platform_nrf52.h b/src/common/platforms/platform_nrf52.h index 3516cf90..2b8b882f 100644 --- a/src/common/platforms/platform_nrf52.h +++ b/src/common/platforms/platform_nrf52.h @@ -1,6 +1,18 @@ /* - * Copyright (c) 2014-2016 Cesanta Software Limited + * Copyright (c) 2014-2018 Cesanta Software Limited * All rights reserved + * + * Licensed under the Apache License, Version 2.0 (the ""License""); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an ""AS IS"" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. */ #ifndef CS_COMMON_PLATFORMS_PLATFORM_NRF52_H_ #define CS_COMMON_PLATFORMS_PLATFORM_NRF52_H_ diff --git a/src/common/platforms/platform_nxp_kinetis.h b/src/common/platforms/platform_nxp_kinetis.h index b4ffd531..d9265e91 100644 --- a/src/common/platforms/platform_nxp_kinetis.h +++ b/src/common/platforms/platform_nxp_kinetis.h @@ -1,6 +1,18 @@ /* - * Copyright (c) 2014-2016 Cesanta Software Limited + * Copyright (c) 2014-2018 Cesanta Software Limited * All rights reserved + * + * Licensed under the Apache License, Version 2.0 (the ""License""); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an ""AS IS"" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. */ #ifndef CS_COMMON_PLATFORMS_PLATFORM_NXP_KINETIS_H_ diff --git a/src/common/platforms/platform_nxp_lpc.h b/src/common/platforms/platform_nxp_lpc.h index cf9b7e70..7bb12c5e 100644 --- a/src/common/platforms/platform_nxp_lpc.h +++ b/src/common/platforms/platform_nxp_lpc.h @@ -1,6 +1,18 @@ /* - * Copyright (c) 2014-2016 Cesanta Software Limited + * Copyright (c) 2014-2018 Cesanta Software Limited * All rights reserved + * + * Licensed under the Apache License, Version 2.0 (the ""License""); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an ""AS IS"" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. */ #ifndef CS_COMMON_PLATFORMS_PLATFORM_NXP_LPC_H_ diff --git a/src/common/platforms/platform_pic32.h b/src/common/platforms/platform_pic32.h index b5680252..f2072c3e 100644 --- a/src/common/platforms/platform_pic32.h +++ b/src/common/platforms/platform_pic32.h @@ -1,6 +1,18 @@ /* - * Copyright (c) 2014-2016 Cesanta Software Limited + * Copyright (c) 2014-2018 Cesanta Software Limited * All rights reserved + * + * Licensed under the Apache License, Version 2.0 (the ""License""); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an ""AS IS"" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. */ #ifndef CS_COMMON_PLATFORMS_PLATFORM_PIC32_H_ diff --git a/src/common/platforms/platform_stm32.h b/src/common/platforms/platform_stm32.h index ece78c82..6b937569 100644 --- a/src/common/platforms/platform_stm32.h +++ b/src/common/platforms/platform_stm32.h @@ -1,6 +1,18 @@ /* - * Copyright (c) 2014-2016 Cesanta Software Limited + * Copyright (c) 2014-2018 Cesanta Software Limited * All rights reserved + * + * Licensed under the Apache License, Version 2.0 (the ""License""); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an ""AS IS"" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. */ #ifndef CS_COMMON_PLATFORMS_PLATFORM_STM32_H_ diff --git a/src/common/platforms/platform_tm4c129.h b/src/common/platforms/platform_tm4c129.h index 5e87b948..dc75d79d 100644 --- a/src/common/platforms/platform_tm4c129.h +++ b/src/common/platforms/platform_tm4c129.h @@ -1,6 +1,18 @@ /* - * Copyright (c) 2014-2016 Cesanta Software Limited + * Copyright (c) 2014-2018 Cesanta Software Limited * All rights reserved + * + * Licensed under the Apache License, Version 2.0 (the ""License""); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an ""AS IS"" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. */ #ifndef CS_COMMON_PLATFORMS_PLATFORM_TM4C129_H_ diff --git a/src/common/platforms/simplelink/cs_simplelink.h b/src/common/platforms/simplelink/cs_simplelink.h index ed6afa2e..2b415410 100644 --- a/src/common/platforms/simplelink/cs_simplelink.h +++ b/src/common/platforms/simplelink/cs_simplelink.h @@ -1,6 +1,18 @@ /* - * Copyright (c) 2014-2016 Cesanta Software Limited + * Copyright (c) 2014-2018 Cesanta Software Limited * All rights reserved + * + * Licensed under the Apache License, Version 2.0 (the ""License""); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an ""AS IS"" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. */ #ifndef CS_COMMON_PLATFORMS_SIMPLELINK_CS_SIMPLELINK_H_ diff --git a/src/common/platforms/simplelink/sl_fs.c b/src/common/platforms/simplelink/sl_fs.c index fc093429..bc055c1f 100644 --- a/src/common/platforms/simplelink/sl_fs.c +++ b/src/common/platforms/simplelink/sl_fs.c @@ -1,6 +1,18 @@ /* - * Copyright (c) 2014-2016 Cesanta Software Limited + * Copyright (c) 2014-2018 Cesanta Software Limited * All rights reserved + * + * Licensed under the Apache License, Version 2.0 (the ""License""); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an ""AS IS"" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. */ #if MG_NET_IF == MG_NET_IF_SIMPLELINK && \ diff --git a/src/common/platforms/simplelink/sl_fs_slfs.c b/src/common/platforms/simplelink/sl_fs_slfs.c index 2754b6bf..8170310b 100644 --- a/src/common/platforms/simplelink/sl_fs_slfs.c +++ b/src/common/platforms/simplelink/sl_fs_slfs.c @@ -1,6 +1,18 @@ /* - * Copyright (c) 2014-2016 Cesanta Software Limited + * Copyright (c) 2014-2018 Cesanta Software Limited * All rights reserved + * + * Licensed under the Apache License, Version 2.0 (the ""License""); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an ""AS IS"" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. */ /* Standard libc interface to TI SimpleLink FS. */ diff --git a/src/common/platforms/simplelink/sl_fs_slfs.h b/src/common/platforms/simplelink/sl_fs_slfs.h index 0d8a4b1c..eb909c1b 100644 --- a/src/common/platforms/simplelink/sl_fs_slfs.h +++ b/src/common/platforms/simplelink/sl_fs_slfs.h @@ -1,6 +1,18 @@ /* - * Copyright (c) 2014-2016 Cesanta Software Limited + * Copyright (c) 2014-2018 Cesanta Software Limited * All rights reserved + * + * Licensed under the Apache License, Version 2.0 (the ""License""); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an ""AS IS"" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. */ #ifndef CS_COMMON_PLATFORMS_SIMPLELINK_SL_FS_SLFS_H_ diff --git a/src/common/platforms/simplelink/sl_net_if.c b/src/common/platforms/simplelink/sl_net_if.c index fcc5632b..1a000ce7 100644 --- a/src/common/platforms/simplelink/sl_net_if.c +++ b/src/common/platforms/simplelink/sl_net_if.c @@ -1,6 +1,18 @@ /* - * Copyright (c) 2014-2016 Cesanta Software Limited + * Copyright (c) 2014-2018 Cesanta Software Limited * All rights reserved + * + * Licensed under the Apache License, Version 2.0 (the ""License""); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an ""AS IS"" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. */ #include "common/platforms/simplelink/sl_net_if.h" diff --git a/src/common/platforms/simplelink/sl_net_if.h b/src/common/platforms/simplelink/sl_net_if.h index aa49d5de..c72bd28b 100644 --- a/src/common/platforms/simplelink/sl_net_if.h +++ b/src/common/platforms/simplelink/sl_net_if.h @@ -1,6 +1,18 @@ /* - * Copyright (c) 2014-2016 Cesanta Software Limited + * Copyright (c) 2014-2018 Cesanta Software Limited * All rights reserved + * + * Licensed under the Apache License, Version 2.0 (the ""License""); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an ""AS IS"" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. */ #ifndef CS_COMMON_PLATFORMS_SIMPLELINK_SL_NET_IF_H_ diff --git a/src/common/platforms/simplelink/sl_socket.c b/src/common/platforms/simplelink/sl_socket.c index e4a0c26a..101fb636 100644 --- a/src/common/platforms/simplelink/sl_socket.c +++ b/src/common/platforms/simplelink/sl_socket.c @@ -1,6 +1,18 @@ /* - * Copyright (c) 2014-2016 Cesanta Software Limited + * Copyright (c) 2014-2018 Cesanta Software Limited * All rights reserved + * + * Licensed under the Apache License, Version 2.0 (the ""License""); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an ""AS IS"" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. */ #if MG_NET_IF == MG_NET_IF_SIMPLELINK diff --git a/src/common/platforms/simplelink/sl_ssl_if.c b/src/common/platforms/simplelink/sl_ssl_if.c index 0cd9c25b..6e4daa6e 100644 --- a/src/common/platforms/simplelink/sl_ssl_if.c +++ b/src/common/platforms/simplelink/sl_ssl_if.c @@ -1,6 +1,18 @@ /* - * Copyright (c) 2014-2016 Cesanta Software Limited + * Copyright (c) 2014-2018 Cesanta Software Limited * All rights reserved + * + * Licensed under the Apache License, Version 2.0 (the ""License""); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an ""AS IS"" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. */ #if MG_ENABLE_SSL && MG_SSL_IF == MG_SSL_IF_SIMPLELINK diff --git a/src/common/platforms/wince/wince_libc.c b/src/common/platforms/wince/wince_libc.c index b385fde7..c0f51928 100644 --- a/src/common/platforms/wince/wince_libc.c +++ b/src/common/platforms/wince/wince_libc.c @@ -1,6 +1,18 @@ /* - * Copyright (c) 2016 Cesanta Software Limited + * Copyright (c) 2014-2018 Cesanta Software Limited * All rights reserved + * + * Licensed under the Apache License, Version 2.0 (the ""License""); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an ""AS IS"" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. */ #ifdef WINCE diff --git a/src/common/platforms/windows/windows_direct.c b/src/common/platforms/windows/windows_direct.c index 89328998..796a416d 100644 --- a/src/common/platforms/windows/windows_direct.c +++ b/src/common/platforms/windows/windows_direct.c @@ -1,6 +1,18 @@ /* - * Copyright (c) 2017 Cesanta Software Limited + * Copyright (c) 2014-2018 Cesanta Software Limited * All rights reserved + * + * Licensed under the Apache License, Version 2.0 (the ""License""); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an ""AS IS"" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. */ #ifdef _WIN32 diff --git a/src/common/test_main.c b/src/common/test_main.c index 53116d92..5057cbc9 100644 --- a/src/common/test_main.c +++ b/src/common/test_main.c @@ -1,6 +1,18 @@ /* * Copyright (c) 2014-2018 Cesanta Software Limited * All rights reserved + * + * Licensed under the Apache License, Version 2.0 (the ""License""); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an ""AS IS"" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. */ #include "common/cs_dbg.h" diff --git a/src/common/test_main.h b/src/common/test_main.h index 6b6f5f39..915b560a 100644 --- a/src/common/test_main.h +++ b/src/common/test_main.h @@ -1,6 +1,18 @@ /* * Copyright (c) 2014-2018 Cesanta Software Limited * All rights reserved + * + * Licensed under the Apache License, Version 2.0 (the ""License""); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an ""AS IS"" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. */ #ifndef CS_COMMON_TEST_MAIN_H_ diff --git a/src/common/test_util.c b/src/common/test_util.c index 705a12fb..f2782f83 100644 --- a/src/common/test_util.c +++ b/src/common/test_util.c @@ -1,6 +1,18 @@ /* - * Copyright (c) 2014-2016 Cesanta Software Limited + * Copyright (c) 2014-2018 Cesanta Software Limited * All rights reserved + * + * Licensed under the Apache License, Version 2.0 (the ""License""); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an ""AS IS"" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. */ #include "common/test_util.h" diff --git a/src/common/test_util.h b/src/common/test_util.h index 60618f10..7af3ab5e 100644 --- a/src/common/test_util.h +++ b/src/common/test_util.h @@ -1,18 +1,18 @@ /* - * Copyright (c) 2015 Cesanta Software Limited + * Copyright (c) 2014-2018 Cesanta Software Limited * All rights reserved - * This software is dual-licensed: you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. For the terms of this - * license, see . * - * You are free to use this software under the terms of the GNU General - * Public License, but WITHOUT ANY WARRANTY; without even the implied - * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. - * See the GNU General Public License for more details. + * Licensed under the Apache License, Version 2.0 (the ""License""); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at * - * Alternatively, you can license this software under a commercial - * license, as set out in . + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an ""AS IS"" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. */ #ifndef CS_COMMON_TEST_UTIL_H_ From b8eca17c558525cea5e1e81594897021eef239dd Mon Sep 17 00:00:00 2001 From: Deomid Ryabkov Date: Tue, 3 Apr 2018 16:50:43 +0100 Subject: [PATCH 15/41] Reamalgam mongoose.{c,h} PUBLISHED_FROM=8828792097bd19774472b8a2e61420565684d174 --- mongoose.c | 392 +++++++++++++++++++++++++++++++++++++++++++++++++---- mongoose.h | 308 ++++++++++++++++++++++++++++++++++++++--- 2 files changed, 650 insertions(+), 50 deletions(-) diff --git a/mongoose.c b/mongoose.c index ce2ed4e6..1db2ab10 100644 --- a/mongoose.c +++ b/mongoose.c @@ -163,8 +163,20 @@ MG_INTERNAL int mg_sntp_parse_reply(const char *buf, int len, #line 1 "common/mg_mem.h" #endif /* - * Copyright (c) 2014-2016 Cesanta Software Limited + * Copyright (c) 2014-2018 Cesanta Software Limited * All rights reserved + * + * Licensed under the Apache License, Version 2.0 (the ""License""); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an ""AS IS"" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. */ #ifndef CS_COMMON_MG_MEM_H_ @@ -199,8 +211,20 @@ extern "C" { #line 1 "common/cs_base64.c" #endif /* - * Copyright (c) 2014 Cesanta Software Limited + * Copyright (c) 2014-2018 Cesanta Software Limited * All rights reserved + * + * Licensed under the Apache License, Version 2.0 (the ""License""); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an ""AS IS"" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. */ #ifndef EXCLUDE_COMMON @@ -407,8 +431,20 @@ int cs_base64_decode(const unsigned char *s, int len, char *dst, int *dec_len) { #line 1 "common/cs_dbg.h" #endif /* - * Copyright (c) 2014-2016 Cesanta Software Limited + * Copyright (c) 2014-2018 Cesanta Software Limited * All rights reserved + * + * Licensed under the Apache License, Version 2.0 (the ""License""); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an ""AS IS"" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. */ #ifndef CS_COMMON_CS_DBG_H_ @@ -559,8 +595,20 @@ void cs_log_printf(const char *fmt, ...) #line 1 "common/cs_dbg.c" #endif /* - * Copyright (c) 2014-2016 Cesanta Software Limited + * Copyright (c) 2014-2018 Cesanta Software Limited * All rights reserved + * + * Licensed under the Apache License, Version 2.0 (the ""License""); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an ""AS IS"" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. */ /* Amalgamated: #include "common/cs_dbg.h" */ @@ -667,8 +715,20 @@ void cs_log_set_level(enum cs_log_level level) { #line 1 "common/cs_dirent.h" #endif /* - * Copyright (c) 2014-2016 Cesanta Software Limited + * Copyright (c) 2014-2018 Cesanta Software Limited * All rights reserved + * + * Licensed under the Apache License, Version 2.0 (the ""License""); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an ""AS IS"" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. */ #ifndef CS_COMMON_CS_DIRENT_H_ @@ -709,8 +769,20 @@ struct dirent *readdir(DIR *dir); #line 1 "common/cs_dirent.c" #endif /* - * Copyright (c) 2015 Cesanta Software Limited + * Copyright (c) 2014-2018 Cesanta Software Limited * All rights reserved + * + * Licensed under the Apache License, Version 2.0 (the ""License""); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an ""AS IS"" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. */ #ifndef EXCLUDE_COMMON @@ -808,8 +880,20 @@ typedef int cs_dirent_dummy; #line 1 "common/cs_time.c" #endif /* - * Copyright (c) 2014-2016 Cesanta Software Limited + * Copyright (c) 2014-2018 Cesanta Software Limited * All rights reserved + * + * Licensed under the Apache License, Version 2.0 (the ""License""); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an ""AS IS"" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. */ /* Amalgamated: #include "common/cs_time.h" */ @@ -894,8 +978,20 @@ double cs_timegm(const struct tm *tm) { #line 1 "common/cs_endian.h" #endif /* - * Copyright (c) 2014-2016 Cesanta Software Limited + * Copyright (c) 2014-2018 Cesanta Software Limited * All rights reserved + * + * Licensed under the Apache License, Version 2.0 (the ""License""); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an ""AS IS"" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. */ #ifndef CS_COMMON_CS_ENDIAN_H_ @@ -1399,8 +1495,20 @@ void cs_hmac_sha1(const unsigned char *key, size_t keylen, #line 1 "common/mbuf.c" #endif /* - * Copyright (c) 2014 Cesanta Software Limited + * Copyright (c) 2014-2018 Cesanta Software Limited * All rights reserved + * + * Licensed under the Apache License, Version 2.0 (the ""License""); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an ""AS IS"" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. */ #ifndef EXCLUDE_COMMON @@ -1514,8 +1622,20 @@ void mbuf_remove(struct mbuf *mb, size_t n) { #line 1 "common/mg_str.c" #endif /* - * Copyright (c) 2014-2016 Cesanta Software Limited + * Copyright (c) 2014-2018 Cesanta Software Limited * All rights reserved + * + * Licensed under the Apache License, Version 2.0 (the ""License""); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an ""AS IS"" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. */ /* Amalgamated: #include "common/mg_mem.h" */ @@ -1637,8 +1757,20 @@ const char *mg_strstr(const struct mg_str haystack, #line 1 "common/str_util.c" #endif /* - * Copyright (c) 2015 Cesanta Software Limited + * Copyright (c) 2014-2018 Cesanta Software Limited * All rights reserved + * + * Licensed under the Apache License, Version 2.0 (the ""License""); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an ""AS IS"" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. */ #ifndef EXCLUDE_COMMON @@ -12803,8 +12935,20 @@ void mg_set_protocol_socks(struct mg_connection *c) { #line 1 "common/platforms/cc3200/cc3200_libc.c" #endif /* - * Copyright (c) 2014-2016 Cesanta Software Limited + * Copyright (c) 2014-2018 Cesanta Software Limited * All rights reserved + * + * Licensed under the Apache License, Version 2.0 (the ""License""); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an ""AS IS"" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. */ #if CS_PLATFORM == CS_P_CC3200 @@ -12909,8 +13053,20 @@ int _isatty(int fd) { #line 1 "common/platforms/msp432/msp432_libc.c" #endif /* - * Copyright (c) 2014-2016 Cesanta Software Limited + * Copyright (c) 2014-2018 Cesanta Software Limited * All rights reserved + * + * Licensed under the Apache License, Version 2.0 (the ""License""); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an ""AS IS"" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. */ #if CS_PLATFORM == CS_P_MSP432 @@ -12930,8 +13086,20 @@ int gettimeofday(struct timeval *tp, void *tzp) { #line 1 "common/platforms/nrf5/nrf5_libc.c" #endif /* - * Copyright (c) 2014-2016 Cesanta Software Limited + * Copyright (c) 2014-2018 Cesanta Software Limited * All rights reserved + * + * Licensed under the Apache License, Version 2.0 (the ""License""); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an ""AS IS"" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. */ #if (CS_PLATFORM == CS_P_NRF51 || CS_PLATFORM == CS_P_NRF52) && \ @@ -12947,8 +13115,20 @@ int gettimeofday(struct timeval *tp, void *tzp) { #line 1 "common/platforms/simplelink/sl_fs_slfs.h" #endif /* - * Copyright (c) 2014-2016 Cesanta Software Limited + * Copyright (c) 2014-2018 Cesanta Software Limited * All rights reserved + * + * Licensed under the Apache License, Version 2.0 (the ""License""); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an ""AS IS"" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. */ #ifndef CS_COMMON_PLATFORMS_SIMPLELINK_SL_FS_SLFS_H_ @@ -12984,8 +13164,20 @@ void fs_slfs_set_new_file_size(const char *name, size_t size); #line 1 "common/platforms/simplelink/sl_fs_slfs.c" #endif /* - * Copyright (c) 2014-2016 Cesanta Software Limited + * Copyright (c) 2014-2018 Cesanta Software Limited * All rights reserved + * + * Licensed under the Apache License, Version 2.0 (the ""License""); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an ""AS IS"" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. */ /* Standard libc interface to TI SimpleLink FS. */ @@ -13233,8 +13425,20 @@ void fs_slfs_set_new_file_size(const char *name, size_t size) { #line 1 "common/platforms/simplelink/sl_fs.c" #endif /* - * Copyright (c) 2014-2016 Cesanta Software Limited + * Copyright (c) 2014-2018 Cesanta Software Limited * All rights reserved + * + * Licensed under the Apache License, Version 2.0 (the ""License""); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an ""AS IS"" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. */ #if MG_NET_IF == MG_NET_IF_SIMPLELINK && \ @@ -13647,8 +13851,20 @@ int sl_fs_init(void) { #line 1 "common/platforms/simplelink/sl_socket.c" #endif /* - * Copyright (c) 2014-2016 Cesanta Software Limited + * Copyright (c) 2014-2018 Cesanta Software Limited * All rights reserved + * + * Licensed under the Apache License, Version 2.0 (the ""License""); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an ""AS IS"" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. */ #if MG_NET_IF == MG_NET_IF_SIMPLELINK @@ -13753,8 +13969,20 @@ void mg_run_in_task(void (*cb)(struct mg_mgr *mgr, void *arg), void *cb_arg) { #line 1 "common/platforms/simplelink/sl_net_if.h" #endif /* - * Copyright (c) 2014-2016 Cesanta Software Limited + * Copyright (c) 2014-2018 Cesanta Software Limited * All rights reserved + * + * Licensed under the Apache License, Version 2.0 (the ""License""); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an ""AS IS"" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. */ #ifndef CS_COMMON_PLATFORMS_SIMPLELINK_SL_NET_IF_H_ @@ -13781,8 +14009,20 @@ extern const struct mg_iface_vtable mg_simplelink_iface_vtable; #line 1 "common/platforms/simplelink/sl_net_if.c" #endif /* - * Copyright (c) 2014-2016 Cesanta Software Limited + * Copyright (c) 2014-2018 Cesanta Software Limited * All rights reserved + * + * Licensed under the Apache License, Version 2.0 (the ""License""); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an ""AS IS"" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. */ /* Amalgamated: #include "common/platforms/simplelink/sl_net_if.h" */ @@ -14204,8 +14444,20 @@ const struct mg_iface_vtable mg_default_iface_vtable = MG_SL_IFACE_VTABLE; #line 1 "common/platforms/simplelink/sl_ssl_if.c" #endif /* - * Copyright (c) 2014-2016 Cesanta Software Limited + * Copyright (c) 2014-2018 Cesanta Software Limited * All rights reserved + * + * Licensed under the Apache License, Version 2.0 (the ""License""); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an ""AS IS"" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. */ #if MG_ENABLE_SSL && MG_SSL_IF == MG_SSL_IF_SIMPLELINK @@ -14446,8 +14698,20 @@ int sl_set_ssl_opts(int sock, struct mg_connection *nc) { #line 1 "common/platforms/lwip/mg_lwip_net_if.h" #endif /* - * Copyright (c) 2014-2016 Cesanta Software Limited + * Copyright (c) 2014-2018 Cesanta Software Limited * All rights reserved + * + * Licensed under the Apache License, Version 2.0 (the ""License""); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an ""AS IS"" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. */ #ifndef CS_COMMON_PLATFORMS_LWIP_MG_NET_IF_LWIP_H_ @@ -14502,8 +14766,20 @@ void mg_lwip_mgr_schedule_poll(struct mg_mgr *mgr); #line 1 "common/platforms/lwip/mg_lwip_net_if.c" #endif /* - * Copyright (c) 2014-2016 Cesanta Software Limited + * Copyright (c) 2014-2018 Cesanta Software Limited * All rights reserved + * + * Licensed under the Apache License, Version 2.0 (the ""License""); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an ""AS IS"" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. */ #if MG_ENABLE_NET_IF_LWIP_LOW_LEVEL @@ -15200,8 +15476,20 @@ const struct mg_iface_vtable mg_default_iface_vtable = MG_LWIP_IFACE_VTABLE; #line 1 "common/platforms/lwip/mg_lwip_ev_mgr.c" #endif /* - * Copyright (c) 2014-2016 Cesanta Software Limited + * Copyright (c) 2014-2018 Cesanta Software Limited * All rights reserved + * + * Licensed under the Apache License, Version 2.0 (the ""License""); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an ""AS IS"" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. */ #if MG_NET_IF == MG_NET_IF_LWIP_LOW_LEVEL @@ -15392,8 +15680,20 @@ uint32_t mg_lwip_get_poll_delay_ms(struct mg_mgr *mgr) { #line 1 "common/platforms/wince/wince_libc.c" #endif /* - * Copyright (c) 2016 Cesanta Software Limited + * Copyright (c) 2014-2018 Cesanta Software Limited * All rights reserved + * + * Licensed under the Apache License, Version 2.0 (the ""License""); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an ""AS IS"" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. */ #ifdef WINCE @@ -15469,8 +15769,20 @@ static void mg_gmt_time_string(char *buf, size_t buf_len, time_t *t) { #line 1 "common/platforms/pic32/pic32_net_if.h" #endif /* - * Copyright (c) 2014-2016 Cesanta Software Limited + * Copyright (c) 2014-2018 Cesanta Software Limited * All rights reserved + * + * Licensed under the Apache License, Version 2.0 (the ""License""); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an ""AS IS"" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. */ #ifndef CS_COMMON_PLATFORMS_PIC32_NET_IF_H_ @@ -15497,8 +15809,20 @@ extern const struct mg_iface_vtable mg_pic32_iface_vtable; #line 1 "common/platforms/pic32/pic32_net_if.c" #endif /* - * Copyright (c) 2014-2016 Cesanta Software Limited + * Copyright (c) 2014-2018 Cesanta Software Limited * All rights reserved + * + * Licensed under the Apache License, Version 2.0 (the ""License""); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an ""AS IS"" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. */ #if MG_ENABLE_NET_IF_PIC32 @@ -15792,8 +16116,20 @@ const struct mg_iface_vtable mg_default_iface_vtable = MG_PIC32_IFACE_VTABLE; #line 1 "common/platforms/windows/windows_direct.c" #endif /* - * Copyright (c) 2017 Cesanta Software Limited + * Copyright (c) 2014-2018 Cesanta Software Limited * All rights reserved + * + * Licensed under the Apache License, Version 2.0 (the ""License""); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an ""AS IS"" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. */ #ifdef _WIN32 diff --git a/mongoose.h b/mongoose.h index e9b1fb17..080642c3 100644 --- a/mongoose.h +++ b/mongoose.h @@ -493,8 +493,20 @@ typedef struct stat cs_stat_t; #line 1 "common/platforms/platform_esp32.h" #endif /* - * Copyright (c) 2014-2016 Cesanta Software Limited + * Copyright (c) 2014-2018 Cesanta Software Limited * All rights reserved + * + * Licensed under the Apache License, Version 2.0 (the ""License""); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an ""AS IS"" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. */ #ifndef CS_COMMON_PLATFORMS_PLATFORM_ESP32_H_ @@ -538,8 +550,20 @@ typedef struct stat cs_stat_t; #line 1 "common/platforms/platform_esp8266.h" #endif /* - * Copyright (c) 2014-2016 Cesanta Software Limited + * Copyright (c) 2014-2018 Cesanta Software Limited * All rights reserved + * + * Licensed under the Apache License, Version 2.0 (the ""License""); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an ""AS IS"" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. */ #ifndef CS_COMMON_PLATFORMS_PLATFORM_ESP8266_H_ @@ -603,8 +627,20 @@ typedef struct stat cs_stat_t; #line 1 "common/platforms/platform_cc3100.h" #endif /* - * Copyright (c) 2014-2016 Cesanta Software Limited + * Copyright (c) 2014-2018 Cesanta Software Limited * All rights reserved + * + * Licensed under the Apache License, Version 2.0 (the ""License""); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an ""AS IS"" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. */ #ifndef CS_COMMON_PLATFORMS_PLATFORM_CC3100_H_ @@ -652,8 +688,20 @@ int inet_pton(int af, const char *src, void *dst); #line 1 "common/platforms/platform_cc3200.h" #endif /* - * Copyright (c) 2014-2016 Cesanta Software Limited + * Copyright (c) 2014-2018 Cesanta Software Limited * All rights reserved + * + * Licensed under the Apache License, Version 2.0 (the ""License""); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an ""AS IS"" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. */ #ifndef CS_COMMON_PLATFORMS_PLATFORM_CC3200_H_ @@ -777,8 +825,20 @@ int stat(const char *pathname, struct stat *st); #line 1 "common/platforms/platform_msp432.h" #endif /* - * Copyright (c) 2014-2016 Cesanta Software Limited + * Copyright (c) 2014-2018 Cesanta Software Limited * All rights reserved + * + * Licensed under the Apache License, Version 2.0 (the ""License""); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an ""AS IS"" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. */ #ifndef CS_COMMON_PLATFORMS_PLATFORM_MSP432_H_ @@ -885,8 +945,20 @@ int _stat(const char *pathname, struct stat *st); #line 1 "common/platforms/platform_tm4c129.h" #endif /* - * Copyright (c) 2014-2016 Cesanta Software Limited + * Copyright (c) 2014-2018 Cesanta Software Limited * All rights reserved + * + * Licensed under the Apache License, Version 2.0 (the ""License""); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an ""AS IS"" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. */ #ifndef CS_COMMON_PLATFORMS_PLATFORM_TM4C129_H_ @@ -945,8 +1017,20 @@ typedef struct stat cs_stat_t; #line 1 "common/platforms/platform_mbed.h" #endif /* - * Copyright (c) 2014-2016 Cesanta Software Limited + * Copyright (c) 2014-2018 Cesanta Software Limited * All rights reserved + * + * Licensed under the Apache License, Version 2.0 (the ""License""); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an ""AS IS"" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. */ #ifndef CS_COMMON_PLATFORMS_PLATFORM_MBED_H_ @@ -1029,8 +1113,20 @@ in_addr_t inet_addr(const char *cp); #line 1 "common/platforms/platform_nrf51.h" #endif /* - * Copyright (c) 2014-2016 Cesanta Software Limited + * Copyright (c) 2014-2018 Cesanta Software Limited * All rights reserved + * + * Licensed under the Apache License, Version 2.0 (the ""License""); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an ""AS IS"" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. */ #ifndef CS_COMMON_PLATFORMS_PLATFORM_NRF51_H_ #define CS_COMMON_PLATFORMS_PLATFORM_NRF51_H_ @@ -1074,8 +1170,20 @@ int gettimeofday(struct timeval *tp, void *tzp); #line 1 "common/platforms/platform_nrf52.h" #endif /* - * Copyright (c) 2014-2016 Cesanta Software Limited + * Copyright (c) 2014-2018 Cesanta Software Limited * All rights reserved + * + * Licensed under the Apache License, Version 2.0 (the ""License""); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an ""AS IS"" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. */ #ifndef CS_COMMON_PLATFORMS_PLATFORM_NRF52_H_ #define CS_COMMON_PLATFORMS_PLATFORM_NRF52_H_ @@ -1122,8 +1230,20 @@ int gettimeofday(struct timeval *tp, void *tzp); #line 1 "common/platforms/simplelink/cs_simplelink.h" #endif /* - * Copyright (c) 2014-2016 Cesanta Software Limited + * Copyright (c) 2014-2018 Cesanta Software Limited * All rights reserved + * + * Licensed under the Apache License, Version 2.0 (the ""License""); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an ""AS IS"" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. */ #ifndef CS_COMMON_PLATFORMS_SIMPLELINK_CS_SIMPLELINK_H_ @@ -1493,8 +1613,20 @@ const char *strerror(); #line 1 "common/platforms/platform_nxp_lpc.h" #endif /* - * Copyright (c) 2014-2016 Cesanta Software Limited + * Copyright (c) 2014-2018 Cesanta Software Limited * All rights reserved + * + * Licensed under the Apache License, Version 2.0 (the ""License""); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an ""AS IS"" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. */ #ifndef CS_COMMON_PLATFORMS_PLATFORM_NXP_LPC_H_ @@ -1549,8 +1681,20 @@ typedef struct stat cs_stat_t; #line 1 "common/platforms/platform_nxp_kinetis.h" #endif /* - * Copyright (c) 2014-2016 Cesanta Software Limited + * Copyright (c) 2014-2018 Cesanta Software Limited * All rights reserved + * + * Licensed under the Apache License, Version 2.0 (the ""License""); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an ""AS IS"" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. */ #ifndef CS_COMMON_PLATFORMS_PLATFORM_NXP_KINETIS_H_ @@ -1583,8 +1727,20 @@ typedef struct stat cs_stat_t; #line 1 "common/platforms/platform_pic32.h" #endif /* - * Copyright (c) 2014-2016 Cesanta Software Limited + * Copyright (c) 2014-2018 Cesanta Software Limited * All rights reserved + * + * Licensed under the Apache License, Version 2.0 (the ""License""); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an ""AS IS"" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. */ #ifndef CS_COMMON_PLATFORMS_PLATFORM_PIC32_H_ @@ -1623,8 +1779,20 @@ char *inet_ntoa(struct in_addr in); #line 1 "common/platforms/platform_stm32.h" #endif /* - * Copyright (c) 2014-2016 Cesanta Software Limited + * Copyright (c) 2014-2018 Cesanta Software Limited * All rights reserved + * + * Licensed under the Apache License, Version 2.0 (the ""License""); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an ""AS IS"" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. */ #ifndef CS_COMMON_PLATFORMS_PLATFORM_STM32_H_ @@ -1665,8 +1833,20 @@ typedef struct stat cs_stat_t; #line 1 "common/platforms/lwip/mg_lwip.h" #endif /* - * Copyright (c) 2014-2016 Cesanta Software Limited + * Copyright (c) 2014-2018 Cesanta Software Limited * All rights reserved + * + * Licensed under the Apache License, Version 2.0 (the ""License""); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an ""AS IS"" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. */ #ifndef CS_COMMON_PLATFORMS_LWIP_MG_LWIP_H_ @@ -1737,8 +1917,20 @@ void mg_lwip_set_keepalive_params(struct mg_connection *nc, int idle, #line 1 "common/cs_md5.h" #endif /* - * Copyright (c) 2014 Cesanta Software Limited + * Copyright (c) 2014-2018 Cesanta Software Limited * All rights reserved + * + * Licensed under the Apache License, Version 2.0 (the ""License""); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an ""AS IS"" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. */ #ifndef CS_COMMON_MD5_H_ @@ -1773,8 +1965,20 @@ void cs_md5_final(unsigned char *md, cs_md5_ctx *c); #line 1 "common/cs_sha1.h" #endif /* - * Copyright (c) 2014 Cesanta Software Limited + * Copyright (c) 2014-2018 Cesanta Software Limited * All rights reserved + * + * Licensed under the Apache License, Version 2.0 (the ""License""); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an ""AS IS"" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. */ #ifndef CS_COMMON_SHA1_H_ @@ -1815,8 +2019,20 @@ void cs_hmac_sha1(const unsigned char *key, size_t key_len, #line 1 "common/cs_time.h" #endif /* - * Copyright (c) 2014-2016 Cesanta Software Limited + * Copyright (c) 2014-2018 Cesanta Software Limited * All rights reserved + * + * Licensed under the Apache License, Version 2.0 (the ""License""); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an ""AS IS"" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. */ #ifndef CS_COMMON_CS_TIME_H_ @@ -1848,8 +2064,20 @@ double cs_timegm(const struct tm *tm); #line 1 "common/mg_str.h" #endif /* - * Copyright (c) 2014-2016 Cesanta Software Limited + * Copyright (c) 2014-2018 Cesanta Software Limited * All rights reserved + * + * Licensed under the Apache License, Version 2.0 (the ""License""); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an ""AS IS"" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. */ #ifndef CS_COMMON_MG_STR_H_ @@ -1936,8 +2164,20 @@ const char *mg_strstr(const struct mg_str haystack, const struct mg_str needle); #line 1 "common/mbuf.h" #endif /* - * Copyright (c) 2015 Cesanta Software Limited + * Copyright (c) 2014-2018 Cesanta Software Limited * All rights reserved + * + * Licensed under the Apache License, Version 2.0 (the ""License""); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an ""AS IS"" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. */ /* @@ -2026,8 +2266,20 @@ void mbuf_trim(struct mbuf *); #line 1 "common/cs_base64.h" #endif /* - * Copyright (c) 2014 Cesanta Software Limited + * Copyright (c) 2014-2018 Cesanta Software Limited * All rights reserved + * + * Licensed under the Apache License, Version 2.0 (the ""License""); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an ""AS IS"" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. */ #ifndef CS_COMMON_CS_BASE64_H_ @@ -2075,8 +2327,20 @@ int cs_base64_decode(const unsigned char *s, int len, char *dst, int *dec_len); #line 1 "common/str_util.h" #endif /* - * Copyright (c) 2015 Cesanta Software Limited + * Copyright (c) 2014-2018 Cesanta Software Limited * All rights reserved + * + * Licensed under the Apache License, Version 2.0 (the ""License""); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an ""AS IS"" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. */ #ifndef CS_COMMON_STR_UTIL_H_ From c2fbff6d0ecd01bca8e3a7657ea2fb9d1fc85fd5 Mon Sep 17 00:00:00 2001 From: Deomid Ryabkov Date: Mon, 9 Apr 2018 22:40:39 +0100 Subject: [PATCH 16/41] Fix mg_http_parse_header Per standard, cookies are delimited by `; `. CL: Fix mg_http_parse_header: treat ";" as a delimiter. PUBLISHED_FROM=039243c30f5fabf4a4700a43506f841b3268306a --- mongoose.c | 6 +++--- src/mg_http.c | 6 +++--- test/unit_test.c | 5 ++++- 3 files changed, 10 insertions(+), 7 deletions(-) diff --git a/mongoose.c b/mongoose.c index 1db2ab10..534009b7 100644 --- a/mongoose.c +++ b/mongoose.c @@ -7208,7 +7208,7 @@ void mg_printf_html_escape(struct mg_connection *nc, const char *fmt, ...) { static void mg_http_parse_header_internal(struct mg_str *hdr, const char *var_name, struct altbuf *ab) { - int ch = ' ', ch1 = ',', n = strlen(var_name); + int ch = ' ', ch1 = ',', ch2 = ';', n = strlen(var_name); const char *p, *end = hdr ? hdr->p + hdr->len : NULL, *s = NULL; /* Find where variable starts */ @@ -7221,10 +7221,10 @@ static void mg_http_parse_header_internal(struct mg_str *hdr, if (s != NULL && &s[n + 1] < end) { s += n + 1; if (*s == '"' || *s == '\'') { - ch = ch1 = *s++; + ch = ch1 = ch2 = *s++; } p = s; - while (p < end && p[0] != ch && p[0] != ch1) { + while (p < end && p[0] != ch && p[0] != ch1 && p[0] != ch2) { if (ch != ' ' && p[0] == '\\' && p[1] == ch) p++; altbuf_append(ab, *p++); } diff --git a/src/mg_http.c b/src/mg_http.c index 1fd27d2a..57531c96 100644 --- a/src/mg_http.c +++ b/src/mg_http.c @@ -1644,7 +1644,7 @@ void mg_printf_html_escape(struct mg_connection *nc, const char *fmt, ...) { static void mg_http_parse_header_internal(struct mg_str *hdr, const char *var_name, struct altbuf *ab) { - int ch = ' ', ch1 = ',', n = strlen(var_name); + int ch = ' ', ch1 = ',', ch2 = ';', n = strlen(var_name); const char *p, *end = hdr ? hdr->p + hdr->len : NULL, *s = NULL; /* Find where variable starts */ @@ -1657,10 +1657,10 @@ static void mg_http_parse_header_internal(struct mg_str *hdr, if (s != NULL && &s[n + 1] < end) { s += n + 1; if (*s == '"' || *s == '\'') { - ch = ch1 = *s++; + ch = ch1 = ch2 = *s++; } p = s; - while (p < end && p[0] != ch && p[0] != ch1) { + while (p < end && p[0] != ch && p[0] != ch1 && p[0] != ch2) { if (ch != ' ' && p[0] == '\\' && p[1] == ch) p++; altbuf_append(ab, *p++); } diff --git a/test/unit_test.c b/test/unit_test.c index 446217b1..f496b27c 100644 --- a/test/unit_test.c +++ b/test/unit_test.c @@ -4973,7 +4973,7 @@ static const char *test_buffer_limit(void) { static const char *test_http_parse_header(void) { static struct mg_str h = MG_MK_STR( - "xx=1 kl yy, ert=234 kl=123, " + "xx=1 kl yy, ert=234 kl=123, qq=ww;" "uri=\"/?naii=x,y\";ii=\"12\\\"34\" zz='aa bb',tt=2,gf=\"xx d=1234"); char buf[20]; char *buf2; @@ -5021,6 +5021,9 @@ static const char *test_http_parse_header(void) { ASSERT_EQ(mg_http_parse_header(&h, "tt", buf, sizeof(buf)), 1); ASSERT_STREQ(buf, "2"); ASSERT(mg_http_parse_header(&h, "uri", buf, sizeof(buf)) > 0); + ASSERT_STREQ(buf, "/?naii=x,y"); + ASSERT(mg_http_parse_header(&h, "qq", buf, sizeof(buf)) > 0); + ASSERT_STREQ(buf, "ww"); return NULL; } From e89be2e944ac1dd4d95c65d32b1194fab33ae54d Mon Sep 17 00:00:00 2001 From: Deomid Ryabkov Date: Tue, 10 Apr 2018 02:34:35 +0100 Subject: [PATCH 17/41] Add mg_url_encode_opt() CL: Add `mg_url_encode_opt()` - a parametrized version of `mg_url_encode()` PUBLISHED_FROM=17fa57a7a5325b51b6e3aef3855eac4e82c35782 --- docs/c-api/mg_util.h/mg_url_encode.md | 5 +--- mongoose.c | 16 +++++++++--- mongoose.h | 17 ++++++++++++- src/mg_util.c | 16 +++++++++--- src/mg_util.h | 9 ++++++- test/unit_test.c | 36 ++++++++++++++++++++++++--- 6 files changed, 81 insertions(+), 18 deletions(-) diff --git a/docs/c-api/mg_util.h/mg_url_encode.md b/docs/c-api/mg_util.h/mg_url_encode.md index 105ce947..176ac5f7 100644 --- a/docs/c-api/mg_util.h/mg_url_encode.md +++ b/docs/c-api/mg_util.h/mg_url_encode.md @@ -6,8 +6,5 @@ signature: | struct mg_str mg_url_encode(const struct mg_str src); --- -URL-escape the specified string. -All non-printable characters are escaped, plus `._-$,;~()/`. -Input need not be NUL-terminated, but the returned string is. -Returned string is heap-allocated and must be free()'d. +Same as `mg_url_encode_opt(src, "._-$,;~()/", 0)`. diff --git a/mongoose.c b/mongoose.c index 534009b7..1eb690e7 100644 --- a/mongoose.c +++ b/mongoose.c @@ -10444,17 +10444,21 @@ void mg_basic_auth_header(const struct mg_str user, const struct mg_str pass, mbuf_append(buf, header_suffix, strlen(header_suffix)); } -struct mg_str mg_url_encode(const struct mg_str src) { - static const char *dont_escape = "._-$,;~()/"; - static const char *hex = "0123456789abcdef"; +struct mg_str mg_url_encode_opt(const struct mg_str src, + const struct mg_str safe, unsigned int flags) { + const char *hex = + (flags & MG_URL_ENCODE_F_UPPERCASE_HEX ? "0123456789ABCDEF" + : "0123456789abcdef"); size_t i = 0; struct mbuf mb; mbuf_init(&mb, src.len); for (i = 0; i < src.len; i++) { const unsigned char c = *((const unsigned char *) src.p + i); - if (isalnum(c) || strchr(dont_escape, c) != NULL) { + if (isalnum(c) || mg_strchr(safe, c) != NULL) { mbuf_append(&mb, &c, 1); + } else if (c == ' ' && (flags & MG_URL_ENCODE_F_SPACE_AS_PLUS)) { + mbuf_append(&mb, "+", 1); } else { mbuf_append(&mb, "%", 1); mbuf_append(&mb, &hex[c >> 4], 1); @@ -10465,6 +10469,10 @@ struct mg_str mg_url_encode(const struct mg_str src) { mbuf_trim(&mb); return mg_mk_str_n(mb.buf, mb.len - 1); } + +struct mg_str mg_url_encode(const struct mg_str src) { + return mg_url_encode_opt(src, mg_mk_str("._-$,;~()/"), 0); +} #ifdef MG_MODULE_LINES #line 1 "mongoose/src/mg_mqtt.c" #endif diff --git a/mongoose.h b/mongoose.h index 080642c3..a02d9646 100644 --- a/mongoose.h +++ b/mongoose.h @@ -2314,6 +2314,14 @@ void cs_base64_finish(struct cs_base64_ctx *ctx); void cs_base64_encode(const unsigned char *src, int src_len, char *dst); void cs_fprint_base64(FILE *f, const unsigned char *src, int src_len); + +/* + * Decodes a base64 string `s` length `len` into `dst`. + * `dst` must have enough space to hold the result. + * `*dec_len` will contain the resulting length of the string in `dst` + * while return value will return number of processed bytes in `src`. + * Return value == len indicates successful processing of all the data. + */ int cs_base64_decode(const unsigned char *s, int len, char *dst, int *dec_len); #ifdef __cplusplus @@ -4501,10 +4509,17 @@ void mg_basic_auth_header(const struct mg_str user, const struct mg_str pass, /* * URL-escape the specified string. - * All non-printable characters are escaped, plus `._-$,;~()/`. + * All characters acept letters, numbers and characters listed in + * `safe` are escaped. If `hex_upper`is true, `A-F` are used for hex digits. * Input need not be NUL-terminated, but the returned string is. * Returned string is heap-allocated and must be free()'d. */ +#define MG_URL_ENCODE_F_SPACE_AS_PLUS (1 << 0) +#define MG_URL_ENCODE_F_UPPERCASE_HEX (1 << 1) +struct mg_str mg_url_encode_opt(const struct mg_str src, + const struct mg_str safe, unsigned int flags); + +/* Same as `mg_url_encode_opt(src, "._-$,;~()/", 0)`. */ struct mg_str mg_url_encode(const struct mg_str src); #ifdef __cplusplus diff --git a/src/mg_util.c b/src/mg_util.c index 95246a8d..cfbd87e5 100644 --- a/src/mg_util.c +++ b/src/mg_util.c @@ -313,17 +313,21 @@ void mg_basic_auth_header(const struct mg_str user, const struct mg_str pass, mbuf_append(buf, header_suffix, strlen(header_suffix)); } -struct mg_str mg_url_encode(const struct mg_str src) { - static const char *dont_escape = "._-$,;~()/"; - static const char *hex = "0123456789abcdef"; +struct mg_str mg_url_encode_opt(const struct mg_str src, + const struct mg_str safe, unsigned int flags) { + const char *hex = + (flags & MG_URL_ENCODE_F_UPPERCASE_HEX ? "0123456789ABCDEF" + : "0123456789abcdef"); size_t i = 0; struct mbuf mb; mbuf_init(&mb, src.len); for (i = 0; i < src.len; i++) { const unsigned char c = *((const unsigned char *) src.p + i); - if (isalnum(c) || strchr(dont_escape, c) != NULL) { + if (isalnum(c) || mg_strchr(safe, c) != NULL) { mbuf_append(&mb, &c, 1); + } else if (c == ' ' && (flags & MG_URL_ENCODE_F_SPACE_AS_PLUS)) { + mbuf_append(&mb, "+", 1); } else { mbuf_append(&mb, "%", 1); mbuf_append(&mb, &hex[c >> 4], 1); @@ -334,3 +338,7 @@ struct mg_str mg_url_encode(const struct mg_str src) { mbuf_trim(&mb); return mg_mk_str_n(mb.buf, mb.len - 1); } + +struct mg_str mg_url_encode(const struct mg_str src) { + return mg_url_encode_opt(src, mg_mk_str("._-$,;~()/"), 0); +} diff --git a/src/mg_util.h b/src/mg_util.h index e6f2e481..8ddeb770 100644 --- a/src/mg_util.h +++ b/src/mg_util.h @@ -196,10 +196,17 @@ void mg_basic_auth_header(const struct mg_str user, const struct mg_str pass, /* * URL-escape the specified string. - * All non-printable characters are escaped, plus `._-$,;~()/`. + * All characters acept letters, numbers and characters listed in + * `safe` are escaped. If `hex_upper`is true, `A-F` are used for hex digits. * Input need not be NUL-terminated, but the returned string is. * Returned string is heap-allocated and must be free()'d. */ +#define MG_URL_ENCODE_F_SPACE_AS_PLUS (1 << 0) +#define MG_URL_ENCODE_F_UPPERCASE_HEX (1 << 1) +struct mg_str mg_url_encode_opt(const struct mg_str src, + const struct mg_str safe, unsigned int flags); + +/* Same as `mg_url_encode_opt(src, "._-$,;~()/", 0)`. */ struct mg_str mg_url_encode(const struct mg_str src); #ifdef __cplusplus diff --git a/test/unit_test.c b/test/unit_test.c index f496b27c..48540359 100644 --- a/test/unit_test.c +++ b/test/unit_test.c @@ -928,10 +928,38 @@ static const char *test_mg_uri_to_local_path(void) { static const char *test_mg_url_encode(void) { const struct mg_str encode_me = MG_MK_STR("I'm a.little_tea-pot,here's$my;spout~oink(oink)oink/!"); - struct mg_str encoded = mg_url_encode(encode_me); - ASSERT_MG_STREQ( - encoded, "I%27m%20a.little_tea-pot,here%27s$my;spout~oink(oink)oink/%21"); - free((void *) encoded.p); + { + struct mg_str encoded = mg_url_encode(encode_me); + ASSERT_MG_STREQ( + encoded, + "I%27m%20a.little_tea-pot,here%27s$my;spout~oink(oink)oink/%21"); + free((void *) encoded.p); + } + { + struct mg_str encoded = mg_url_encode_opt(encode_me, mg_mk_str(NULL), 0); + ASSERT_MG_STREQ(encoded, + "I%27m%20a%2elittle%5ftea%2dpot%2chere%27s%24my%3bspout%" + "7eoink%28oink%29oink%2f%21"); + free((void *) encoded.p); + } + { + struct mg_str encoded = mg_url_encode_opt(encode_me, mg_mk_str(" /!"), + MG_URL_ENCODE_F_UPPERCASE_HEX); + ASSERT_MG_STREQ(encoded, + "I%27m " + "a%2Elittle%5Ftea%2Dpot%2Chere%27s%24my%3Bspout%7Eoink%" + "28oink%29oink/!"); + free((void *) encoded.p); + } + { + struct mg_str encoded = mg_url_encode_opt( + encode_me, mg_mk_str("/!"), + MG_URL_ENCODE_F_SPACE_AS_PLUS | MG_URL_ENCODE_F_UPPERCASE_HEX); + ASSERT_MG_STREQ(encoded, + "I%27m+a%2Elittle%5Ftea%2Dpot%2Chere%27s%24my%3Bspout%" + "7Eoink%28oink%29oink/!"); + free((void *) encoded.p); + } return NULL; } From 43191db63e9f4132a29c10160a32742d8165ec76 Mon Sep 17 00:00:00 2001 From: Deomid Ryabkov Date: Wed, 11 Apr 2018 18:31:26 +0100 Subject: [PATCH 18/41] Fix boot loader UART baud rate on soft reboot Also remove `-O3` optimization flasg, it negates `-Os`. Saves ~400 bytes. CL: none PUBLISHED_FROM=f40f42e4f54a8e0e003ab65ec8f5838c2d932876 --- .../platforms/esp8266/rboot/rboot/rboot.c | 20 ++++++++++++++++--- .../platforms/esp8266/rboot/rboot/rboot.mk | 2 +- 2 files changed, 18 insertions(+), 4 deletions(-) diff --git a/src/common/platforms/esp8266/rboot/rboot/rboot.c b/src/common/platforms/esp8266/rboot/rboot/rboot.c index 4ac5df18..6f752142 100644 --- a/src/common/platforms/esp8266/rboot/rboot/rboot.c +++ b/src/common/platforms/esp8266/rboot/rboot/rboot.c @@ -160,7 +160,8 @@ static uint8 calc_chksum(uint8 *start, uint8 *end) { } #endif -#define UART_CLKDIV_26MHZ(B) (52000000 + B / 2) / B +#define UART_CLKDIV_80MHZ(B) (80000000 + B / 2) / B +#define UART_CLKDIV_52MHZ(B) (52000000 + B / 2) / B // prevent this function being placed inline with main // to keep main's stack size as small as possible @@ -182,10 +183,23 @@ uint32 NOINLINE find_image(void) { // delay to slow boot (help see messages when debugging) //ets_delay_us(2000000); - uart_div_modify(0, UART_CLKDIV_26MHZ(115200)); + /* + * UART divider depends on the APB frequency. Cold boot starts with 52MHz APB, + * SDK configures PLL, sets it to 80 and it persists across soft reset + * so on soft reset a different divider should be used. What we really want to + * know is if the PLL is running but since that is completely undocumented + * we use CPU frequency bit as a workaround: mos sets CPU to 160 MHz on startup + * so we assume that if frequency is preserved, then it's soft reset, PLL is + * running and APB is at 80 MHz. + */ + if (READ_PERI_REG(0x3ff00014) & 1) { + uart_div_modify(0, UART_CLKDIV_80MHZ(115200)); + } else { + uart_div_modify(0, UART_CLKDIV_52MHZ(115200)); + } ets_delay_us(1000); - ets_printf("\r\nrBoot v1.2.1 - richardaburton@gmail.com\r\n"); + ets_printf("\r\nrBoot v1.2.1-cesanta1 - richardaburton@gmail.com\r\n"); // read rom header SPIRead(0, header, sizeof(rom_header)); diff --git a/src/common/platforms/esp8266/rboot/rboot/rboot.mk b/src/common/platforms/esp8266/rboot/rboot/rboot.mk index f7f39878..419ba5a8 100644 --- a/src/common/platforms/esp8266/rboot/rboot/rboot.mk +++ b/src/common/platforms/esp8266/rboot/rboot/rboot.mk @@ -23,7 +23,7 @@ LD := $(addprefix $(XTENSA_BINDIR)/,xtensa-lx106-elf-gcc) endif CC_WRAPPER ?= -CFLAGS = -Os -O3 -Wpointer-arith -Wundef -Werror -Wl,-EL \ +CFLAGS = -Os -Wpointer-arith -Wundef -Werror -Wl,-EL \ -fno-inline-functions -nostdlib -mlongcalls -mtext-section-literals \ -D__ets__ -DIRAM='__attribute__((section(".fast.text")))' \ -DNOINSTR='__attribute__((no_instrument_function))' \ From 43b5a4e735474f4cba65e8464182e2ff4678dafa Mon Sep 17 00:00:00 2001 From: Deomid Ryabkov Date: Fri, 13 Apr 2018 16:57:08 +0100 Subject: [PATCH 19/41] Add a special attribute to printf-like funcs Enables extra compile-time checks CL: none PUBLISHED_FROM=9f7d658fbda5c721cf40293bf29967bb056d0437 --- mongoose.c | 6 +----- mongoose.h | 18 +++++++++++++++--- src/common/cs_dbg.h | 6 +----- src/common/platform.h | 12 +++++++++++- 4 files changed, 28 insertions(+), 14 deletions(-) diff --git a/mongoose.c b/mongoose.c index 1eb690e7..cd24eff5 100644 --- a/mongoose.c +++ b/mongoose.c @@ -547,11 +547,7 @@ void cs_log_set_file(FILE *file); * Prints log to the current log file, appends "\n" in the end and flushes the * stream. */ -void cs_log_printf(const char *fmt, ...) -#ifdef __GNUC__ - __attribute__((format(printf, 1, 2))) -#endif - ; +void cs_log_printf(const char *fmt, ...) PRINTF_LIKE(1, 2); /* * Format and print message `x` with the given level `l`. Example: diff --git a/mongoose.h b/mongoose.h index a02d9646..d907c97e 100644 --- a/mongoose.h +++ b/mongoose.h @@ -128,8 +128,18 @@ /* Common stuff */ +#if !defined(PRINTF_LIKE) +#if defined(__GNUC__) || defined(__clang__) || defined(__TI_COMPILER_VERSION__) +#define PRINTF_LIKE(f, a) __attribute__((format(printf, f, a))) +#else +#define PRINTF_LIKE(f, a) +#endif +#endif + #if !defined(WEAK) -#if (defined(__GNUC__) || defined(__TI_COMPILER_VERSION__)) && !defined(_WIN32) +#if (defined(__GNUC__) || defined(__clang__) || \ + defined(__TI_COMPILER_VERSION__)) && \ + !defined(_WIN32) #define WEAK __attribute__((weak)) #else #define WEAK @@ -2397,7 +2407,8 @@ size_t c_strnlen(const char *s, size_t maxlen); /* * Equivalent of standard `snprintf()`. */ -int c_snprintf(char *buf, size_t buf_size, const char *format, ...); +int c_snprintf(char *buf, size_t buf_size, const char *format, ...) + PRINTF_LIKE(3, 4); /* * Equivalent of standard `vsnprintf()`. @@ -2465,7 +2476,8 @@ int mg_casecmp(const char *s1, const char *s2); * * The purpose of this is to avoid malloc-ing if generated strings are small. */ -int mg_asprintf(char **buf, size_t size, const char *fmt, ...); +int mg_asprintf(char **buf, size_t size, const char *fmt, ...) + PRINTF_LIKE(3, 4); /* Same as mg_asprintf, but takes varargs list. */ int mg_avprintf(char **buf, size_t size, const char *fmt, va_list ap); diff --git a/src/common/cs_dbg.h b/src/common/cs_dbg.h index 5e964334..9e0608ef 100644 --- a/src/common/cs_dbg.h +++ b/src/common/cs_dbg.h @@ -115,11 +115,7 @@ void cs_log_set_file(FILE *file); * Prints log to the current log file, appends "\n" in the end and flushes the * stream. */ -void cs_log_printf(const char *fmt, ...) -#ifdef __GNUC__ - __attribute__((format(printf, 1, 2))) -#endif - ; +void cs_log_printf(const char *fmt, ...) PRINTF_LIKE(1, 2); /* * Format and print message `x` with the given level `l`. Example: diff --git a/src/common/platform.h b/src/common/platform.h index b517cab4..1b803c9e 100644 --- a/src/common/platform.h +++ b/src/common/platform.h @@ -92,8 +92,18 @@ /* Common stuff */ +#if !defined(PRINTF_LIKE) +#if defined(__GNUC__) || defined(__clang__) || defined(__TI_COMPILER_VERSION__) +#define PRINTF_LIKE(f, a) __attribute__((format(printf, f, a))) +#else +#define PRINTF_LIKE(f, a) +#endif +#endif + #if !defined(WEAK) -#if (defined(__GNUC__) || defined(__TI_COMPILER_VERSION__)) && !defined(_WIN32) +#if (defined(__GNUC__) || defined(__clang__) || \ + defined(__TI_COMPILER_VERSION__)) && \ + !defined(_WIN32) #define WEAK __attribute__((weak)) #else #define WEAK From 1614e7ba8db0dc7847b0493d01105140b9437b03 Mon Sep 17 00:00:00 2001 From: Deomid Ryabkov Date: Fri, 13 Apr 2018 17:34:03 +0100 Subject: [PATCH 20/41] Restore FFI-ability of struct mg_str mgos_dlsym needs to include mg_str for ffi_exports to be able to use it PUBLISHED_FROM=a2dd167c8e8f9e9b7316a856f19a4603080c3632 --- mongoose.c | 1 + mongoose.h | 2 -- 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/mongoose.c b/mongoose.c index cd24eff5..18c1b642 100644 --- a/mongoose.c +++ b/mongoose.c @@ -1636,6 +1636,7 @@ void mbuf_remove(struct mbuf *mb, size_t n) { /* Amalgamated: #include "common/mg_mem.h" */ /* Amalgamated: #include "common/mg_str.h" */ +/* Amalgamated: #include "common/platform.h" */ #include #include diff --git a/mongoose.h b/mongoose.h index d907c97e..43cfe12e 100644 --- a/mongoose.h +++ b/mongoose.h @@ -2095,8 +2095,6 @@ double cs_timegm(const struct tm *tm); #include -/* Amalgamated: #include "common/platform.h" */ - #ifdef __cplusplus extern "C" { #endif From 7014258c8d4e47304a16b7ea3fd0f6c7d467ffcc Mon Sep 17 00:00:00 2001 From: Sergey Lyubka Date: Tue, 17 Apr 2018 12:02:09 +0100 Subject: [PATCH 21/41] Remove copyright notices - that explained in the CLA. CL: none PUBLISHED_FROM=9cb4b915906d471ef5de4e0825567d0b942d3f7b --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 63d8f8e8..17bbfe45 100644 --- a/README.md +++ b/README.md @@ -62,7 +62,7 @@ the functionality: # Contributions To submit contributions, sign [Cesanta CLA](https://cesanta.com/cla.html) -and send GitHub pull request. You retain the copyright on your contributions. +and send GitHub pull request. # Looking for a pre-compiled Mongoose web server Windows or Mac binary? - [Download pre-compiled Mongoose web server binary.](https://www.cesanta.com/binary.html) From 53f34dea04a16a8f6df074f707e07b4d0100edf3 Mon Sep 17 00:00:00 2001 From: Deomid Ryabkov Date: Thu, 26 Apr 2018 14:50:05 +0100 Subject: [PATCH 22/41] Fix TZ on ESP8266 CL: Fix TZ on ESP8266 PUBLISHED_FROM=435a501a8b52524bccb67bb5a8ae7e09dfb4d44a --- mongoose.h | 4 ---- src/common/platforms/esp8266/common.mk | 2 +- src/common/platforms/platform_esp8266.h | 4 ---- 3 files changed, 1 insertion(+), 9 deletions(-) diff --git a/mongoose.h b/mongoose.h index 43cfe12e..584e3e11 100644 --- a/mongoose.h +++ b/mongoose.h @@ -603,10 +603,6 @@ typedef struct stat cs_stat_t; #define __cdecl #define _FILE_OFFSET_BITS 32 -#if !defined(RTOS_SDK) && !defined(__cplusplus) -#define fileno(x) -1 -#endif - #define MG_LWIP 1 /* struct timeval is defined in sys/time.h. */ diff --git a/src/common/platforms/esp8266/common.mk b/src/common/platforms/esp8266/common.mk index 53452215..5efc4b9a 100644 --- a/src/common/platforms/esp8266/common.mk +++ b/src/common/platforms/esp8266/common.mk @@ -68,7 +68,7 @@ C_CXX_FLAGS = -W -Wall -Werror -Wundef -Wno-comment -Wno-variadic-macros -Wpoin -DCS_PLATFORM=3 \ -ffunction-sections -fdata-sections -CFLAGS = -std=c99 $(C_CXX_FLAGS) +CFLAGS = -std=gnu99 $(C_CXX_FLAGS) CXXFLAGS = -std=gnu++11 -fno-exceptions $(C_CXX_FLAGS) # linker flags used to generate the main object file diff --git a/src/common/platforms/platform_esp8266.h b/src/common/platforms/platform_esp8266.h index 0428f058..3bef0441 100644 --- a/src/common/platforms/platform_esp8266.h +++ b/src/common/platforms/platform_esp8266.h @@ -42,10 +42,6 @@ typedef struct stat cs_stat_t; #define __cdecl #define _FILE_OFFSET_BITS 32 -#if !defined(RTOS_SDK) && !defined(__cplusplus) -#define fileno(x) -1 -#endif - #define MG_LWIP 1 /* struct timeval is defined in sys/time.h. */ From 244ff92e7821bf2010cb12c25ae6a4e7b01a0d64 Mon Sep 17 00:00:00 2001 From: Deomid Ryabkov Date: Wed, 9 May 2018 17:49:05 +0100 Subject: [PATCH 23/41] Minor build optimization PUBLISHED_FROM=9997c64ed0c713b5b8b29df7a49b532e880eac53 --- src/common/platforms/esp8266/common.mk | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/common/platforms/esp8266/common.mk b/src/common/platforms/esp8266/common.mk index 5efc4b9a..ff066c85 100644 --- a/src/common/platforms/esp8266/common.mk +++ b/src/common/platforms/esp8266/common.mk @@ -57,7 +57,7 @@ NO_Os_FLAGS= -fno-expensive-optimizations -fno-thread-jumps \ -fno-tree-pre -fno-tree-vrp C_CXX_FLAGS = -W -Wall -Werror -Wundef -Wno-comment -Wno-variadic-macros -Wpointer-arith \ - -Os $(NO_Os_FLAGS) -g3 \ + -pipe -Os $(NO_Os_FLAGS) -g3 \ -Wl,-EL -fno-inline-functions \ -D_XOPEN_SOURCE=500 \ -nostdlib -mlongcalls -mtext-section-literals -D__ets__ -DSTATIC=static \ From 1299d6118f8f876178d04eb8e14aaaa8dc1d09c7 Mon Sep 17 00:00:00 2001 From: Deomid Ryabkov Date: Thu, 17 May 2018 16:00:09 +0100 Subject: [PATCH 24/41] Add MG_HIDE_SERVER_INFO Closes https://github.com/cesanta/mos-libs/pull/2 CL: Add MG_HIDE_SERVER_INFO PUBLISHED_FROM=ed8a5b65f1c8238df414cd1c1f8bb1f579082f55 --- mongoose.c | 7 +++++-- src/mg_http.c | 7 +++++-- 2 files changed, 10 insertions(+), 4 deletions(-) diff --git a/mongoose.c b/mongoose.c index 18c1b642..82aebae8 100644 --- a/mongoose.c +++ b/mongoose.c @@ -6872,8 +6872,11 @@ const char *mg_status_message(int status_code) { void mg_send_response_line_s(struct mg_connection *nc, int status_code, const struct mg_str extra_headers) { - mg_printf(nc, "HTTP/1.1 %d %s\r\nServer: %s\r\n", status_code, - mg_status_message(status_code), mg_version_header); + mg_printf(nc, "HTTP/1.1 %d %s\r\n", status_code, + mg_status_message(status_code)); +#ifndef MG_HIDE_SERVER_INFO + mg_printf(nc, "Server: %s\r\n", mg_version_header); +#endif if (extra_headers.len > 0) { mg_printf(nc, "%.*s\r\n", (int) extra_headers.len, extra_headers.p); } diff --git a/src/mg_http.c b/src/mg_http.c index 57531c96..e7151aca 100644 --- a/src/mg_http.c +++ b/src/mg_http.c @@ -1311,8 +1311,11 @@ const char *mg_status_message(int status_code) { void mg_send_response_line_s(struct mg_connection *nc, int status_code, const struct mg_str extra_headers) { - mg_printf(nc, "HTTP/1.1 %d %s\r\nServer: %s\r\n", status_code, - mg_status_message(status_code), mg_version_header); + mg_printf(nc, "HTTP/1.1 %d %s\r\n", status_code, + mg_status_message(status_code)); +#ifndef MG_HIDE_SERVER_INFO + mg_printf(nc, "Server: %s\r\n", mg_version_header); +#endif if (extra_headers.len > 0) { mg_printf(nc, "%.*s\r\n", (int) extra_headers.len, extra_headers.p); } From d949c19c7e3360612269bc8365bb82e83a02c40f Mon Sep 17 00:00:00 2001 From: Deomid Ryabkov Date: Tue, 5 Jun 2018 23:19:24 +0100 Subject: [PATCH 25/41] mgos_nsleep100 impl for ARM-based platforms startup cleanup on CC3220 CL: none PUBLISHED_FROM=0998fad82fbcdbde30dca42833f2e48d148592bf --- src/common/platforms/arm/arm_nsleep100.c | 34 +++++++++++++++ src/common/platforms/arm/arm_nsleep100_m4.S | 46 +++++++++++++++++++++ src/common/platforms/arm/arm_nsleep100_m7.S | 45 ++++++++++++++++++++ 3 files changed, 125 insertions(+) create mode 100644 src/common/platforms/arm/arm_nsleep100.c create mode 100644 src/common/platforms/arm/arm_nsleep100_m4.S create mode 100644 src/common/platforms/arm/arm_nsleep100_m7.S diff --git a/src/common/platforms/arm/arm_nsleep100.c b/src/common/platforms/arm/arm_nsleep100.c new file mode 100644 index 00000000..554d2044 --- /dev/null +++ b/src/common/platforms/arm/arm_nsleep100.c @@ -0,0 +1,34 @@ +/* + * Copyright (c) 2014-2018 Cesanta Software Limited + * All rights reserved + * + * Licensed under the Apache License, Version 2.0 (the ""License""); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an ""AS IS"" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include + +#include "mgos.h" +#include "mgos_system.h" + +void (*mgos_nsleep100)(uint32_t n); +uint32_t mgos_nsleep100_loop_count = 0; +/* Provided by arm_nsleep100_{m4,m7}.S for M4 and M7 respectively. */ +extern void mgos_nsleep100_impl(uint32_t n); + +void mgos_nsleep100_cal(void) { + uint32_t cpu_freq = mgos_get_cpu_freq(); + /* # of instruction cycles per 100 ns */ + mgos_nsleep100_loop_count = + roundf((100.0f / 1000000000.0f) / (1.0f / cpu_freq)); + mgos_nsleep100 = mgos_nsleep100_impl; +} diff --git a/src/common/platforms/arm/arm_nsleep100_m4.S b/src/common/platforms/arm/arm_nsleep100_m4.S new file mode 100644 index 00000000..d40820f6 --- /dev/null +++ b/src/common/platforms/arm/arm_nsleep100_m4.S @@ -0,0 +1,46 @@ +/* + * Copyright (c) 2014-2018 Cesanta Software Limited + * All rights reserved + * + * Licensed under the Apache License, Version 2.0 (the ""License""); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an ""AS IS"" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +.arch armv7e-m +.syntax unified +.thumb + +/* These are required to satisfy TI linker. */ +.eabi_attribute Tag_ABI_align_needed, 1 +.eabi_attribute Tag_ABI_align_preserved, 1 + +.global mgos_nsleep100_impl +.global mgos_nsleep100_loop_count + +.section .iram.mgos_nsleep100_impl +.type mgos_nsleep100_impl, %function +.align 4 + +mgos_nsleep100_impl: + ldr r3, =mgos_nsleep100_loop_count + ldr r3, [r3] + mul r0, r3 + mov r1, #6 + udiv r0, r0, r1 + cbz r0, xxx +lxx: + subs r0, #1 + bne lxx +xxx: + bx lr +.align 4 +.size mgos_nsleep100_impl, . - mgos_nsleep100_impl diff --git a/src/common/platforms/arm/arm_nsleep100_m7.S b/src/common/platforms/arm/arm_nsleep100_m7.S new file mode 100644 index 00000000..c0e8f490 --- /dev/null +++ b/src/common/platforms/arm/arm_nsleep100_m7.S @@ -0,0 +1,45 @@ +/* + * Copyright (c) 2014-2018 Cesanta Software Limited + * All rights reserved + * + * Licensed under the Apache License, Version 2.0 (the ""License""); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an ""AS IS"" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +.arch armv7e-m +.syntax unified +.thumb + +/* These are required to satisfy TI linker. */ +.eabi_attribute Tag_ABI_align_needed, 1 +.eabi_attribute Tag_ABI_align_preserved, 1 + +.global mgos_nsleep100_impl +.global mgos_nsleep100_loop_count + +.section .iram.mgos_nsleep100_impl +.type mgos_nsleep100_impl, %function +.align 4 + +mgos_nsleep100_impl: + ldr r3, =mgos_nsleep100_loop_count + ldr r3, [r3] + /* Because of speculative fetch, the core loop only takes 1 cycle. */ + muls r0, r3 + cbz r0, xxx +lxx: + subs r0, #1 + bne lxx +xxx: + bx lr +.align 4 +.size mgos_nsleep100_impl, . - mgos_nsleep100_impl From 9ba6eb716d65cf391a20ea2894193604bced670b Mon Sep 17 00:00:00 2001 From: Deomid Ryabkov Date: Mon, 18 Jun 2018 16:59:15 +0100 Subject: [PATCH 26/41] mg_lwip: Fix race during clean conenction teardown Set CLOSE_IMMEDIATELY flag when destroying conn. This avoid some races in LWIP adapter. CL: mg_lwip: Fix race during clean conenction teardown PUBLISHED_FROM=5c67982390dfaf83527e85d1291f64c6050aa932 --- mongoose.c | 14 ++++++++++---- src/common/platforms/lwip/mg_lwip_ev_mgr.c | 7 ++++--- src/common/platforms/lwip/mg_lwip_net_if.c | 2 +- src/mg_net.c | 5 +++++ 4 files changed, 20 insertions(+), 8 deletions(-) diff --git a/mongoose.c b/mongoose.c index 82aebae8..f19033d8 100644 --- a/mongoose.c +++ b/mongoose.c @@ -2466,6 +2466,11 @@ void mg_close_conn(struct mg_connection *conn) { mg_ssl_if_conn_close_notify(conn); } #endif + /* + * Clearly mark the connection as going away (if not already). + * Some net_if impls (LwIP) need this for cleanly handling half-dead conns. + */ + conn->flags |= MG_F_CLOSE_IMMEDIATELY; mg_remove_conn(conn); conn->iface->vtable->destroy_conn(conn); mg_call(conn, NULL, conn->user_data, MG_EV_CLOSE, NULL); @@ -14901,7 +14906,7 @@ static err_t mg_lwip_tcp_conn_cb(void *arg, struct tcp_pcb *tpcb, err_t err) { static void mg_lwip_tcp_error_cb(void *arg, err_t err) { struct mg_connection *nc = (struct mg_connection *) arg; DBG(("%p conn error %d", nc, err)); - if (nc == NULL) return; + if (nc == NULL || (nc->flags & MG_F_CLOSE_IMMEDIATELY)) return; struct mg_lwip_conn_state *cs = (struct mg_lwip_conn_state *) nc->sock; cs->pcb.tcp = NULL; /* Has already been deallocated */ if (nc->flags & MG_F_CONNECTING) { @@ -15538,10 +15543,11 @@ void mg_ev_mgr_lwip_process_signals(struct mg_mgr *mgr) { (struct mg_ev_mgr_lwip_data *) mgr->ifaces[MG_MAIN_IFACE]->data; while (md->sig_queue_len > 0) { mgos_lock(); - int sig = md->sig_queue[md->start_index].sig; - struct mg_connection *nc = md->sig_queue[md->start_index].nc; + int i = md->start_index; + int sig = md->sig_queue[i].sig; + struct mg_connection *nc = md->sig_queue[i].nc; struct mg_lwip_conn_state *cs = (struct mg_lwip_conn_state *) nc->sock; - md->start_index = (md->start_index + 1) % MG_SIG_QUEUE_LEN; + md->start_index = (i + 1) % MG_SIG_QUEUE_LEN; md->sig_queue_len--; mgos_unlock(); if (nc->iface == NULL || nc->mgr == NULL) continue; diff --git a/src/common/platforms/lwip/mg_lwip_ev_mgr.c b/src/common/platforms/lwip/mg_lwip_ev_mgr.c index 1e844a82..39937fc9 100644 --- a/src/common/platforms/lwip/mg_lwip_ev_mgr.c +++ b/src/common/platforms/lwip/mg_lwip_ev_mgr.c @@ -53,10 +53,11 @@ void mg_ev_mgr_lwip_process_signals(struct mg_mgr *mgr) { (struct mg_ev_mgr_lwip_data *) mgr->ifaces[MG_MAIN_IFACE]->data; while (md->sig_queue_len > 0) { mgos_lock(); - int sig = md->sig_queue[md->start_index].sig; - struct mg_connection *nc = md->sig_queue[md->start_index].nc; + int i = md->start_index; + int sig = md->sig_queue[i].sig; + struct mg_connection *nc = md->sig_queue[i].nc; struct mg_lwip_conn_state *cs = (struct mg_lwip_conn_state *) nc->sock; - md->start_index = (md->start_index + 1) % MG_SIG_QUEUE_LEN; + md->start_index = (i + 1) % MG_SIG_QUEUE_LEN; md->sig_queue_len--; mgos_unlock(); if (nc->iface == NULL || nc->mgr == NULL) continue; diff --git a/src/common/platforms/lwip/mg_lwip_net_if.c b/src/common/platforms/lwip/mg_lwip_net_if.c index f73f607a..2090fca3 100644 --- a/src/common/platforms/lwip/mg_lwip_net_if.c +++ b/src/common/platforms/lwip/mg_lwip_net_if.c @@ -126,7 +126,7 @@ static err_t mg_lwip_tcp_conn_cb(void *arg, struct tcp_pcb *tpcb, err_t err) { static void mg_lwip_tcp_error_cb(void *arg, err_t err) { struct mg_connection *nc = (struct mg_connection *) arg; DBG(("%p conn error %d", nc, err)); - if (nc == NULL) return; + if (nc == NULL || (nc->flags & MG_F_CLOSE_IMMEDIATELY)) return; struct mg_lwip_conn_state *cs = (struct mg_lwip_conn_state *) nc->sock; cs->pcb.tcp = NULL; /* Has already been deallocated */ if (nc->flags & MG_F_CONNECTING) { diff --git a/src/mg_net.c b/src/mg_net.c index 050ac791..ad9a8fb0 100644 --- a/src/mg_net.c +++ b/src/mg_net.c @@ -176,6 +176,11 @@ void mg_close_conn(struct mg_connection *conn) { mg_ssl_if_conn_close_notify(conn); } #endif + /* + * Clearly mark the connection as going away (if not already). + * Some net_if impls (LwIP) need this for cleanly handling half-dead conns. + */ + conn->flags |= MG_F_CLOSE_IMMEDIATELY; mg_remove_conn(conn); conn->iface->vtable->destroy_conn(conn); mg_call(conn, NULL, conn->user_data, MG_EV_CLOSE, NULL); From 339bbee0df8914370bfba201ea637ba9457de5e9 Mon Sep 17 00:00:00 2001 From: Deomid Ryabkov Date: Wed, 20 Jun 2018 13:51:57 +0100 Subject: [PATCH 27/41] mg_file_upload_handler: Support multiple files curl -F file1 -F file2 ... Add a unit test and fix a minor memory leak when returning an error. CL: mg_file_upload_handler: Support multiple files PUBLISHED_FROM=5c4bf2be676346fb782e80f50f79df6a6721ac88 --- mongoose.c | 23 +++++++----- src/mg_http.c | 23 +++++++----- test/test.mk | 2 +- test/unit_test.c | 94 ++++++++++++++++++++++++++++++++++++++++++++++-- 4 files changed, 122 insertions(+), 20 deletions(-) diff --git a/mongoose.c b/mongoose.c index f19033d8..a5ad3e7f 100644 --- a/mongoose.c +++ b/mongoose.c @@ -8279,8 +8279,7 @@ void mg_file_upload_handler(struct mg_connection *nc, int ev, void *ev_data, case MG_EV_HTTP_PART_BEGIN: { struct mg_http_multipart_part *mp = (struct mg_http_multipart_part *) ev_data; - struct file_upload_state *fus = - (struct file_upload_state *) MG_CALLOC(1, sizeof(*fus)); + struct file_upload_state *fus; struct mg_str lfn = local_name_fn(nc, mg_mk_str(mp->file_name)); mp->user_data = NULL; if (lfn.p == NULL || lfn.len == 0) { @@ -8294,6 +8293,11 @@ void mg_file_upload_handler(struct mg_connection *nc, int ev, void *ev_data, nc->flags |= MG_F_SEND_AND_CLOSE; return; } + fus = (struct file_upload_state *) MG_CALLOC(1, sizeof(*fus)); + if (fus == NULL) { + nc->flags |= MG_F_CLOSE_IMMEDIATELY; + return; + } fus->lfn = (char *) MG_MALLOC(lfn.len + 1); memcpy(fus->lfn, lfn.p, lfn.len); fus->lfn[lfn.len] = '\0'; @@ -8365,12 +8369,6 @@ void mg_file_upload_handler(struct mg_connection *nc, int ev, void *ev_data, if (mp->status >= 0 && fus->fp != NULL) { LOG(LL_DEBUG, ("%p Uploaded %s (%s), %d bytes", nc, mp->file_name, fus->lfn, (int) fus->num_recd)); - mg_printf(nc, - "HTTP/1.1 200 OK\r\n" - "Content-Type: text/plain\r\n" - "Connection: close\r\n\r\n" - "Ok, %s - %d bytes.\r\n", - mp->file_name, (int) fus->num_recd); } else { LOG(LL_ERROR, ("Failed to store %s (%s)", mp->file_name, fus->lfn)); /* @@ -8382,6 +8380,15 @@ void mg_file_upload_handler(struct mg_connection *nc, int ev, void *ev_data, MG_FREE(fus->lfn); MG_FREE(fus); mp->user_data = NULL; + /* Don't close the connection yet, there may be more files to come. */ + break; + } + case MG_EV_HTTP_MULTIPART_REQUEST_END: { + mg_printf(nc, + "HTTP/1.1 200 OK\r\n" + "Content-Type: text/plain\r\n" + "Connection: close\r\n\r\n" + "Ok.\r\n"); nc->flags |= MG_F_SEND_AND_CLOSE; break; } diff --git a/src/mg_http.c b/src/mg_http.c index e7151aca..8c9fd5f1 100644 --- a/src/mg_http.c +++ b/src/mg_http.c @@ -2713,8 +2713,7 @@ void mg_file_upload_handler(struct mg_connection *nc, int ev, void *ev_data, case MG_EV_HTTP_PART_BEGIN: { struct mg_http_multipart_part *mp = (struct mg_http_multipart_part *) ev_data; - struct file_upload_state *fus = - (struct file_upload_state *) MG_CALLOC(1, sizeof(*fus)); + struct file_upload_state *fus; struct mg_str lfn = local_name_fn(nc, mg_mk_str(mp->file_name)); mp->user_data = NULL; if (lfn.p == NULL || lfn.len == 0) { @@ -2728,6 +2727,11 @@ void mg_file_upload_handler(struct mg_connection *nc, int ev, void *ev_data, nc->flags |= MG_F_SEND_AND_CLOSE; return; } + fus = (struct file_upload_state *) MG_CALLOC(1, sizeof(*fus)); + if (fus == NULL) { + nc->flags |= MG_F_CLOSE_IMMEDIATELY; + return; + } fus->lfn = (char *) MG_MALLOC(lfn.len + 1); memcpy(fus->lfn, lfn.p, lfn.len); fus->lfn[lfn.len] = '\0'; @@ -2799,12 +2803,6 @@ void mg_file_upload_handler(struct mg_connection *nc, int ev, void *ev_data, if (mp->status >= 0 && fus->fp != NULL) { LOG(LL_DEBUG, ("%p Uploaded %s (%s), %d bytes", nc, mp->file_name, fus->lfn, (int) fus->num_recd)); - mg_printf(nc, - "HTTP/1.1 200 OK\r\n" - "Content-Type: text/plain\r\n" - "Connection: close\r\n\r\n" - "Ok, %s - %d bytes.\r\n", - mp->file_name, (int) fus->num_recd); } else { LOG(LL_ERROR, ("Failed to store %s (%s)", mp->file_name, fus->lfn)); /* @@ -2816,6 +2814,15 @@ void mg_file_upload_handler(struct mg_connection *nc, int ev, void *ev_data, MG_FREE(fus->lfn); MG_FREE(fus); mp->user_data = NULL; + /* Don't close the connection yet, there may be more files to come. */ + break; + } + case MG_EV_HTTP_MULTIPART_REQUEST_END: { + mg_printf(nc, + "HTTP/1.1 200 OK\r\n" + "Content-Type: text/plain\r\n" + "Connection: close\r\n\r\n" + "Ok.\r\n"); nc->flags |= MG_F_SEND_AND_CLOSE; break; } diff --git a/test/test.mk b/test/test.mk index 23ad747d..36df546e 100644 --- a/test/test.mk +++ b/test/test.mk @@ -28,7 +28,7 @@ # OSX clang doesn't build ASAN. Use brew: # $ brew tap homebrew/versions # $ brew install llvm36 --with-clang --with-asan -CLANG:=clang-3.6 +CLANG:=clang PEDANTIC=$(shell gcc --version 2>/dev/null | grep -q clang && echo -pedantic) diff --git a/test/unit_test.c b/test/unit_test.c index 48540359..763b683b 100644 --- a/test/unit_test.c +++ b/test/unit_test.c @@ -4076,14 +4076,19 @@ static void cb_mp_srv(struct mg_connection *nc, int ev, void *p) { } static void cb_mp_send_one_byte(struct mg_connection *nc, int ev, void *p) { - static int i; + static int i = -1; (void) p; - if (ev == MG_EV_POLL) { + if (ev == MG_EV_CONNECT) { + i = 0; + } else if (i >= 0 && ev == MG_EV_POLL) { char ch = ((char *) nc->user_data)[i++]; int l = strlen((char *) nc->user_data); if (ch != '\0') { mg_send(nc, &ch, 1); DBG(("%p sent %d of %d", (void *) nc, i, l)); + } else { + nc->flags |= MG_F_SEND_AND_CLOSE; + i = -1; } } } @@ -4209,7 +4214,6 @@ static const char *test_http_multipart2(void) { if ((r = test_http_multipart_check_res(&mpd.res)) != NULL) return r; - c->flags |= MG_F_CLOSE_IMMEDIATELY; mbuf_free(&mpd.res); memset(&mpd, 0, sizeof(mpd)); mbuf_init(&mpd.res, 0); @@ -4316,6 +4320,89 @@ static const char *test_http_multipart2(void) { return NULL; } + +static struct mg_str upload_lfn_same(struct mg_connection *nc, + struct mg_str fn) { + if (fn.len == 0) { + fn = mg_strdup(mg_mk_str("bar")); + } + (void) nc; + return fn; +} + +static void cb_mp_srv_upload(struct mg_connection *nc, int ev, void *p) { + mg_file_upload_handler(nc, ev, p, upload_lfn_same); + if (ev == MG_EV_CLOSE && nc->listener != NULL) { + *((int *) nc->listener->user_data) = 1; + } + (void) p; +} + +static const char *test_http_multipart_upload(void) { + struct mg_mgr mgr; + const char req_fmt[] = + "%s" + "Content-Disposition: form-data; name=\"a\"; filename=\"foo\"\r\n" + "\r\n" + "%s" + "\r\n--Asrf456BGe4h\r\n" + "Content-Disposition: form-data; name=\"b\"\r\n" + "\r\n" + "%s" + "\r\n--Asrf456BGe4h\r\n" + "Content-Disposition: form-data; name=\"c\"; filename=\"baz\"\r\n" + "\r\n" + "%s" + "\r\n--Asrf456BGe4h--\r\n" + "\r\n"; + + char req[1024 * 5], *data; + struct mg_connection *c, *lc; + size_t size; + int done = 0; + + mg_mgr_init(&mgr, NULL); + lc = mg_bind(&mgr, "8766", cb_mp_srv_upload); + mg_set_protocol_http_websocket(lc); + lc->user_data = &done; + + (void) remove("foo"); + (void) remove("bar"); + (void) remove("baz"); + + snprintf(req, sizeof(req), req_fmt, "", b1, b2, b4); + + ASSERT((c = mg_connect_http(&mgr, cb_mp_send_one_byte, + "http://127.0.0.1:8766/test", + "Content-Type: " + "multipart/form-data;boundary=Asrf456BGe4h", + "\r\n--Asrf456BGe4h\r\n")) != NULL); + c->user_data = req; + + poll_until(&mgr, 5, c_int_eq, &done, (void *) 1); + + data = read_file("foo", &size); + ASSERT_PTRNE(data, NULL); + ASSERT_STREQ_NZ(data, b1); + (void) remove("foo"); + free(data); + + data = read_file("bar", &size); + ASSERT_PTRNE(data, NULL); + ASSERT_STREQ_NZ(data, b2); + (void) remove("bar"); + free(data); + + data = read_file("baz", &size); + ASSERT_PTRNE(data, NULL); + ASSERT_STREQ_NZ(data, b4); + (void) remove("baz"); + free(data); + + mg_mgr_free(&mgr); + return NULL; +} + #endif /* MG_ENABLE_HTTP_STREAMING_MULTIPART */ static const char *test_http_multipart(void) { @@ -5545,6 +5632,7 @@ const char *tests_run(const char *filter) { RUN_TEST(test_http_multipart); #if MG_ENABLE_HTTP_STREAMING_MULTIPART RUN_TEST(test_http_multipart2); + RUN_TEST(test_http_multipart_upload); #endif RUN_TEST(test_parse_date_string); RUN_TEST(test_websocket); From 3bbbd41196c976282e63cb5a9e9dc402198ee7fd Mon Sep 17 00:00:00 2001 From: Deomid Ryabkov Date: Thu, 21 Jun 2018 17:08:41 +0100 Subject: [PATCH 28/41] Add missing CC3220 sub-header to mongoose.h CL: Add missing CC3220 sub-header to mongoose.h PUBLISHED_FROM=a143485b629109c6e16c66b035f02f7552f76129 --- mongoose.h | 124 ++++++++++++++++++++++++++++++++++++++++++++++ src/mg_modules.mk | 1 + 2 files changed, 125 insertions(+) diff --git a/mongoose.h b/mongoose.h index 584e3e11..4550c481 100644 --- a/mongoose.h +++ b/mongoose.h @@ -828,6 +828,130 @@ int stat(const char *pathname, struct stat *st); #endif /* CS_PLATFORM == CS_P_CC3200 */ #endif /* CS_COMMON_PLATFORMS_PLATFORM_CC3200_H_ */ #ifdef MG_MODULE_LINES +#line 1 "common/platforms/platform_cc3220.h" +#endif +/* + * Copyright (c) 2014-2018 Cesanta Software Limited + * All rights reserved + * + * Licensed under the Apache License, Version 2.0 (the ""License""); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an ""AS IS"" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef CS_COMMON_PLATFORMS_PLATFORM_CC3220_H_ +#define CS_COMMON_PLATFORMS_PLATFORM_CC3220_H_ +#if CS_PLATFORM == CS_P_CC3220 + +#include +#include +#include +#include +#include +#include +#include +#include + +#ifndef __TI_COMPILER_VERSION__ +#include +#include +#endif + +#define MG_NET_IF MG_NET_IF_SIMPLELINK +#ifndef MG_SSL_IF +#define MG_SSL_IF MG_SSL_IF_SIMPLELINK +#endif + +/* Only SPIFFS supports directories, SLFS does not. */ +#if defined(CC3220_FS_SPIFFS) && !defined(MG_ENABLE_DIRECTORY_LISTING) +#define MG_ENABLE_DIRECTORY_LISTING 1 +#endif + +/* Amalgamated: #include "common/platforms/simplelink/cs_simplelink.h" */ + +typedef int sock_t; +#define INVALID_SOCKET (-1) +#define SIZE_T_FMT "u" +typedef struct stat cs_stat_t; +#define DIRSEP '/' +#define to64(x) strtoll(x, NULL, 10) +#define INT64_FMT PRId64 +#define INT64_X_FMT PRIx64 +#define __cdecl + +#define fileno(x) -1 + +/* Some functions we implement for Mongoose. */ + +#ifdef __cplusplus +extern "C" { +#endif + +#ifdef __TI_COMPILER_VERSION__ +struct SlTimeval_t; +#define timeval SlTimeval_t +int gettimeofday(struct timeval *t, void *tz); +int settimeofday(const struct timeval *tv, const void *tz); + +int asprintf(char **strp, const char *fmt, ...); + +#endif + +/* TI's libc does not have stat & friends, add them. */ +#ifdef __TI_COMPILER_VERSION__ + +#include + +typedef unsigned int mode_t; +typedef size_t _off_t; +typedef long ssize_t; + +struct stat { + int st_ino; + mode_t st_mode; + int st_nlink; + time_t st_mtime; + off_t st_size; +}; + +int _stat(const char *pathname, struct stat *st); +int stat(const char *pathname, struct stat *st); + +#define __S_IFMT 0170000 + +#define __S_IFDIR 0040000 +#define __S_IFCHR 0020000 +#define __S_IFREG 0100000 + +#define __S_ISTYPE(mode, mask) (((mode) &__S_IFMT) == (mask)) + +#define S_IFDIR __S_IFDIR +#define S_IFCHR __S_IFCHR +#define S_IFREG __S_IFREG +#define S_ISDIR(mode) __S_ISTYPE((mode), __S_IFDIR) +#define S_ISREG(mode) __S_ISTYPE((mode), __S_IFREG) + +#endif /* __TI_COMPILER_VERSION__ */ + +#ifndef CS_ENABLE_STDIO +#define CS_ENABLE_STDIO 1 +#endif + +#ifdef __cplusplus +} +#endif + +#endif /* CS_PLATFORM == CS_P_CC3220 */ +#endif /* CS_COMMON_PLATFORMS_PLATFORM_CC3200_H_ */ +#ifdef MG_MODULE_LINES #line 1 "common/platforms/platform_msp432.h" #endif /* diff --git a/src/mg_modules.mk b/src/mg_modules.mk index bf3f5852..4bc76026 100644 --- a/src/mg_modules.mk +++ b/src/mg_modules.mk @@ -8,6 +8,7 @@ HEADERS = mg_common.h \ $(COMMON)/platforms/platform_esp8266.h \ $(COMMON)/platforms/platform_cc3100.h \ $(COMMON)/platforms/platform_cc3200.h \ + $(COMMON)/platforms/platform_cc3220.h \ $(COMMON)/platforms/platform_msp432.h \ $(COMMON)/platforms/platform_tm4c129.h \ $(COMMON)/platforms/platform_mbed.h \ From 1c8449cea61cce3870482e743fad4b38ccfeea7a Mon Sep 17 00:00:00 2001 From: Deomid Ryabkov Date: Tue, 26 Jun 2018 12:46:26 +0100 Subject: [PATCH 29/41] Fix pipelining issue with multipart upload Do not clear buffer at the end of multipart request to allow following request to proceed. Closes https://github.com/cesanta/mongoose/pull/940 CL: mg: Fix pipelining issue with multipart upload PUBLISHED_FROM=cc7d38b126eaa863553ee4e124cfafcd72030fcf --- mongoose.c | 1 - src/mg_http.c | 1 - test/unit_test.c | 90 ++++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 90 insertions(+), 2 deletions(-) diff --git a/mongoose.c b/mongoose.c index a5ad3e7f..9cb7816c 100644 --- a/mongoose.c +++ b/mongoose.c @@ -6725,7 +6725,6 @@ static void mg_http_multipart_continue(struct mg_connection *c) { break; } case MPS_FINISHED: { - mbuf_remove(&c->recv_mbuf, c->recv_mbuf.len); return; } } diff --git a/src/mg_http.c b/src/mg_http.c index 8c9fd5f1..9f456856 100644 --- a/src/mg_http.c +++ b/src/mg_http.c @@ -1159,7 +1159,6 @@ static void mg_http_multipart_continue(struct mg_connection *c) { break; } case MPS_FINISHED: { - mbuf_remove(&c->recv_mbuf, c->recv_mbuf.len); return; } } diff --git a/test/unit_test.c b/test/unit_test.c index 763b683b..2cf5aa1e 100644 --- a/test/unit_test.c +++ b/test/unit_test.c @@ -4321,6 +4321,95 @@ static const char *test_http_multipart2(void) { return NULL; } +static const char *test_http_multipart_pipeline(void) { + struct mg_mgr mgr; + struct mg_connection *nc_listen; + + const char multi_part_req_fmt[] = + "%s" + "Content-Disposition: form-data; name=\"a\"; filename=\"foo\"\r\n" + "\r\n" + "%s" + "\r\n--Asrf456BGe4h\r\n" + "Content-Disposition: form-data; name=\"b\"\r\n" + "\r\n" + "%s" + "\r\n--Asrf456BGe4h\r\n" + "Content-Disposition: form-data; name=\"c\"; filename=\"bar\"\r\n" + "\r\n" + "%s" + "\r\n--Asrf456BGe4h--\r\n" + "\r\n"; + + char multi_part_req[1024 * 5]; + struct mg_connection *c; + const char *ptr; + int i; + + struct cb_mp_srv_data mpd; + memset(&mpd, 0, sizeof(mpd)); + mbuf_init(&mpd.res, 0); + + mg_mgr_init(&mgr, NULL); + nc_listen = mg_bind(&mgr, "8765", cb_mp_srv); + nc_listen->user_data = &mpd; + + mg_set_protocol_http_websocket(nc_listen); + + snprintf(multi_part_req, sizeof(multi_part_req), multi_part_req_fmt, + "\r\n--Asrf456BGe4h\r\n", b1, b2, b4); + + ASSERT((c = mg_connect_http(&mgr, cb_mp_empty, "http://127.0.0.1:8765/test", + "Content-Type: " + "multipart/form-data;boundary=Asrf456BGe4h\r\n" + "Connection: keep-alive", + multi_part_req)) != NULL); + + c->user_data = multi_part_req; + + mg_printf(c, + "POST /test HTTP/1.1\r\n" + "Connection: keep-alive\r\n" + "Content-Type: multipart/form-data;boundary=Asrf456BGe4h\r\n" + "Content-Length: %d\r\n%s", + (int) strlen(multi_part_req), multi_part_req); + + poll_until(&mgr, 10, c_int_eq, &mpd.request_end, (void *) 1); + + ptr = mpd.res.buf; + for (i = 0; i < 2; i++) { + ASSERT_STREQ_NZ(ptr, ""); + ptr += 8; + } + ASSERT_EQ((size_t)(ptr - mpd.res.buf), mpd.res.len); + + mbuf_free(&mpd.res); + mg_mgr_free(&mgr); + + return NULL; +} + static struct mg_str upload_lfn_same(struct mg_connection *nc, struct mg_str fn) { if (fn.len == 0) { @@ -5632,6 +5721,7 @@ const char *tests_run(const char *filter) { RUN_TEST(test_http_multipart); #if MG_ENABLE_HTTP_STREAMING_MULTIPART RUN_TEST(test_http_multipart2); + RUN_TEST(test_http_multipart_pipeline); RUN_TEST(test_http_multipart_upload); #endif RUN_TEST(test_parse_date_string); From 9d73b3470bbb7879155444cb7be3fb58a737cd3d Mon Sep 17 00:00:00 2001 From: Deomid Ryabkov Date: Fri, 22 Jun 2018 22:08:29 +0100 Subject: [PATCH 30/41] Add LFS (littleFS) library CL: mos support for LFS (littlefs) https://github.com/ARMmbed/littlefs PUBLISHED_FROM=e72957b4fb2c78949af4cf6d5bfef135ddba9fd9 --- src/common/platforms/esp8266/common.mk | 1 + 1 file changed, 1 insertion(+) diff --git a/src/common/platforms/esp8266/common.mk b/src/common/platforms/esp8266/common.mk index ff066c85..bfe0f609 100644 --- a/src/common/platforms/esp8266/common.mk +++ b/src/common/platforms/esp8266/common.mk @@ -57,6 +57,7 @@ NO_Os_FLAGS= -fno-expensive-optimizations -fno-thread-jumps \ -fno-tree-pre -fno-tree-vrp C_CXX_FLAGS = -W -Wall -Werror -Wundef -Wno-comment -Wno-variadic-macros -Wpointer-arith \ + -Wno-missing-field-initializers \ -pipe -Os $(NO_Os_FLAGS) -g3 \ -Wl,-EL -fno-inline-functions \ -D_XOPEN_SOURCE=500 \ From 6a51af9efe738f303e5813db578d61e3844ffc2f Mon Sep 17 00:00:00 2001 From: Deomid Ryabkov Date: Wed, 27 Jun 2018 09:16:17 +0100 Subject: [PATCH 31/41] Fix a bug in mg_mgr_init_opt with opts.num_ifaces h/t @YankunLi Closes https://github.com/cesanta/mongoose/pull/939 CL: mg: Fix a bug in mg_mgr_init_opt with opts.num_ifaces PUBLISHED_FROM=a87518b3505429a3cf9cd6d84b3b781e7dbdcfd5 --- mongoose.c | 2 +- src/mg_net.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/mongoose.c b/mongoose.c index 9cb7816c..a9ea7c8d 100644 --- a/mongoose.c +++ b/mongoose.c @@ -2514,7 +2514,7 @@ void mg_mgr_init_opt(struct mg_mgr *m, void *user_data, m->num_ifaces = opts.num_ifaces; m->ifaces = (struct mg_iface **) MG_MALLOC(sizeof(*m->ifaces) * opts.num_ifaces); - for (i = 0; i < mg_num_ifaces; i++) { + for (i = 0; i < opts.num_ifaces; i++) { m->ifaces[i] = mg_if_create_iface(opts.ifaces[i], m); m->ifaces[i]->vtable->init(m->ifaces[i]); } diff --git a/src/mg_net.c b/src/mg_net.c index ad9a8fb0..5c961409 100644 --- a/src/mg_net.c +++ b/src/mg_net.c @@ -224,7 +224,7 @@ void mg_mgr_init_opt(struct mg_mgr *m, void *user_data, m->num_ifaces = opts.num_ifaces; m->ifaces = (struct mg_iface **) MG_MALLOC(sizeof(*m->ifaces) * opts.num_ifaces); - for (i = 0; i < mg_num_ifaces; i++) { + for (i = 0; i < opts.num_ifaces; i++) { m->ifaces[i] = mg_if_create_iface(opts.ifaces[i], m); m->ifaces[i]->vtable->init(m->ifaces[i]); } From 93ac3e19f06c31535f50a1aa04c31fb6d0326261 Mon Sep 17 00:00:00 2001 From: Deomid Ryabkov Date: Tue, 3 Jul 2018 17:23:22 +0300 Subject: [PATCH 32/41] Stringify multi-word macros correctly Use vararg macros for this. PUBLISHED_FROM=735c40b79dedef17a1fdbb5b846e984df0ae7018 --- mongoose.h | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/mongoose.h b/mongoose.h index 4550c481..5eeaee66 100644 --- a/mongoose.h +++ b/mongoose.h @@ -2500,7 +2500,11 @@ int cs_base64_decode(const unsigned char *s, int len, char *dst, int *dec_len); * Expands to a string representation of its argument: e.g. * `CS_STRINGIFY_LIT(5) expands to "5"` */ +#if !defined(_MSC_VER) || _MSC_VER >= 1900 +#define CS_STRINGIFY_LIT(...) #__VA_ARGS__ +#else #define CS_STRINGIFY_LIT(x) #x +#endif /* * Expands to a string representation of its argument, which is allowed From cdb8d7b692cc75a0ab5c68b5fb09a0647c15d6f5 Mon Sep 17 00:00:00 2001 From: Deomid Ryabkov Date: Sat, 7 Jul 2018 16:45:52 +0300 Subject: [PATCH 33/41] Add mg_strstrip: trims whitespace at the ends of s CL: Add mg_strstrip: trims whitespace at the ends of s PUBLISHED_FROM=a7e10054ac25fa2b3a878876da93a6b30d9507b3 --- mongoose.c | 12 ++++++++++++ mongoose.h | 3 +++ 2 files changed, 15 insertions(+) diff --git a/mongoose.c b/mongoose.c index a9ea7c8d..587422d3 100644 --- a/mongoose.c +++ b/mongoose.c @@ -1750,6 +1750,18 @@ const char *mg_strstr(const struct mg_str haystack, } return NULL; } + +struct mg_str mg_strstrip(struct mg_str s) WEAK; +struct mg_str mg_strstrip(struct mg_str s) { + while (s.len > 0 && isspace((int) *s.p)) { + s.p++; + s.len--; + } + while (s.len > 0 && isspace((int) *(s.p + s.len - 1))) { + s.len--; + } + return s; +} #ifdef MG_MODULE_LINES #line 1 "common/str_util.c" #endif diff --git a/mongoose.h b/mongoose.h index 5eeaee66..5f9219db 100644 --- a/mongoose.h +++ b/mongoose.h @@ -2283,6 +2283,9 @@ int mg_strncmp(const struct mg_str str1, const struct mg_str str2, size_t n); */ const char *mg_strstr(const struct mg_str haystack, const struct mg_str needle); +/* Strip whitespace at the start and the end of s */ +struct mg_str mg_strstrip(struct mg_str s); + #ifdef __cplusplus } #endif From 98c99279c3c2594e14002743031266021fd50af8 Mon Sep 17 00:00:00 2001 From: Deomid Ryabkov Date: Mon, 9 Jul 2018 11:01:54 +0300 Subject: [PATCH 34/41] Fix warnings on newer versions of GCC PUBLISHED_FROM=f1d25145446057fed9e8d634ca637364ca43a5e8 --- mongoose.c | 2 +- src/mg_http.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/mongoose.c b/mongoose.c index 587422d3..a92ee7b7 100644 --- a/mongoose.c +++ b/mongoose.c @@ -7604,7 +7604,7 @@ static void mg_scan_directory(struct mg_connection *nc, const char *dir, const struct mg_serve_http_opts *opts, void (*func)(struct mg_connection *, const char *, cs_stat_t *)) { - char path[MG_MAX_PATH]; + char path[MG_MAX_PATH + 1]; cs_stat_t st; struct dirent *dp; DIR *dirp; diff --git a/src/mg_http.c b/src/mg_http.c index 9f456856..257bde4c 100644 --- a/src/mg_http.c +++ b/src/mg_http.c @@ -2026,7 +2026,7 @@ static void mg_scan_directory(struct mg_connection *nc, const char *dir, const struct mg_serve_http_opts *opts, void (*func)(struct mg_connection *, const char *, cs_stat_t *)) { - char path[MG_MAX_PATH]; + char path[MG_MAX_PATH + 1]; cs_stat_t st; struct dirent *dp; DIR *dirp; From 31632c63617fefd4606f8176465f34d2c18fa109 Mon Sep 17 00:00:00 2001 From: Deomid Ryabkov Date: Thu, 12 Jul 2018 23:28:51 +0300 Subject: [PATCH 35/41] Fix build with CS_ENABLE_STDIO=0 Closes https://github.com/cesanta/mongoose/pull/945 CL: Fix build with CS_ENABLE_STDIO=0 PUBLISHED_FROM=7d15f17fc42241facdba5b1004b5b7f3dda599dc --- mongoose.c | 18 +++++++++++++++--- src/common/cs_dbg.c | 3 +-- src/common/cs_dbg.h | 8 ++++++++ src/common/platforms/lwip/mg_lwip_net_if.c | 2 ++ src/mg_net_if_socket.c | 4 +++- src/mg_ssl_if_mbedtls.c | 1 + 6 files changed, 30 insertions(+), 6 deletions(-) diff --git a/mongoose.c b/mongoose.c index a92ee7b7..ddbed16b 100644 --- a/mongoose.c +++ b/mongoose.c @@ -549,6 +549,8 @@ void cs_log_set_file(FILE *file); */ void cs_log_printf(const char *fmt, ...) PRINTF_LIKE(1, 2); +#if CS_ENABLE_STDIO + /* * Format and print message `x` with the given level `l`. Example: * @@ -562,6 +564,12 @@ void cs_log_printf(const char *fmt, ...) PRINTF_LIKE(1, 2); if (cs_log_print_prefix(l, __func__, __FILE__)) cs_log_printf x; \ } while (0) +#else + +#define LOG(l, x) ((void) l) + +#endif + #ifndef CS_NDEBUG /* @@ -623,13 +631,12 @@ enum cs_log_level cs_log_threshold WEAK = LL_ERROR; #endif +#if CS_ENABLE_STDIO static char *s_filter_pattern = NULL; static size_t s_filter_pattern_len; void cs_log_set_filter(const char *pattern) WEAK; -#if CS_ENABLE_STDIO - FILE *cs_log_file WEAK = NULL; #if CS_LOG_ENABLE_TS_DIFF @@ -3729,7 +3736,9 @@ static int mg_accept_conn(struct mg_connection *lc) { /* NOTE(lsm): on Windows, sock is always > FD_SETSIZE */ sock_t sock = accept(lc->sock, &sa.sa, &sa_len); if (sock == INVALID_SOCKET) { - if (mg_is_error()) DBG(("%p: failed to accept: %d", lc, mg_get_errno())); + if (mg_is_error()) { + DBG(("%p: failed to accept: %d", lc, mg_get_errno())); + } return 0; } nc = mg_if_accept_new_conn(lc); @@ -4837,6 +4846,7 @@ static void mg_ssl_mbed_log(void *ctx, int level, const char *file, int line, LOG(cs_level, ("%p %.*s", ctx, (int) (strlen(str) - 1), str)); (void) file; (void) line; + (void) cs_level; } struct mg_ssl_if_ctx { @@ -15299,6 +15309,8 @@ static void mg_lwip_tcp_write_tcpip(void *arg) { return; } ctx->ret = len; + (void) unsent; + (void) unacked; } int mg_lwip_if_tcp_send(struct mg_connection *nc, const void *buf, size_t len) { diff --git a/src/common/cs_dbg.c b/src/common/cs_dbg.c index 62a5816d..594aa153 100644 --- a/src/common/cs_dbg.c +++ b/src/common/cs_dbg.c @@ -31,13 +31,12 @@ enum cs_log_level cs_log_threshold WEAK = LL_ERROR; #endif +#if CS_ENABLE_STDIO static char *s_filter_pattern = NULL; static size_t s_filter_pattern_len; void cs_log_set_filter(const char *pattern) WEAK; -#if CS_ENABLE_STDIO - FILE *cs_log_file WEAK = NULL; #if CS_LOG_ENABLE_TS_DIFF diff --git a/src/common/cs_dbg.h b/src/common/cs_dbg.h index 9e0608ef..5b9777c1 100644 --- a/src/common/cs_dbg.h +++ b/src/common/cs_dbg.h @@ -117,6 +117,8 @@ void cs_log_set_file(FILE *file); */ void cs_log_printf(const char *fmt, ...) PRINTF_LIKE(1, 2); +#if CS_ENABLE_STDIO + /* * Format and print message `x` with the given level `l`. Example: * @@ -130,6 +132,12 @@ void cs_log_printf(const char *fmt, ...) PRINTF_LIKE(1, 2); if (cs_log_print_prefix(l, __func__, __FILE__)) cs_log_printf x; \ } while (0) +#else + +#define LOG(l, x) ((void) l) + +#endif + #ifndef CS_NDEBUG /* diff --git a/src/common/platforms/lwip/mg_lwip_net_if.c b/src/common/platforms/lwip/mg_lwip_net_if.c index 2090fca3..c6cbf492 100644 --- a/src/common/platforms/lwip/mg_lwip_net_if.c +++ b/src/common/platforms/lwip/mg_lwip_net_if.c @@ -501,6 +501,8 @@ static void mg_lwip_tcp_write_tcpip(void *arg) { return; } ctx->ret = len; + (void) unsent; + (void) unacked; } int mg_lwip_if_tcp_send(struct mg_connection *nc, const void *buf, size_t len) { diff --git a/src/mg_net_if_socket.c b/src/mg_net_if_socket.c index c713e845..607e2b53 100644 --- a/src/mg_net_if_socket.c +++ b/src/mg_net_if_socket.c @@ -146,7 +146,9 @@ static int mg_accept_conn(struct mg_connection *lc) { /* NOTE(lsm): on Windows, sock is always > FD_SETSIZE */ sock_t sock = accept(lc->sock, &sa.sa, &sa_len); if (sock == INVALID_SOCKET) { - if (mg_is_error()) DBG(("%p: failed to accept: %d", lc, mg_get_errno())); + if (mg_is_error()) { + DBG(("%p: failed to accept: %d", lc, mg_get_errno())); + } return 0; } nc = mg_if_accept_new_conn(lc); diff --git a/src/mg_ssl_if_mbedtls.c b/src/mg_ssl_if_mbedtls.c index 38ba1869..021addcf 100644 --- a/src/mg_ssl_if_mbedtls.c +++ b/src/mg_ssl_if_mbedtls.c @@ -34,6 +34,7 @@ static void mg_ssl_mbed_log(void *ctx, int level, const char *file, int line, LOG(cs_level, ("%p %.*s", ctx, (int) (strlen(str) - 1), str)); (void) file; (void) line; + (void) cs_level; } struct mg_ssl_if_ctx { From ac6ec15aed513046e94e10cc001c13750e58a828 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=91=D0=BE=D0=B1=D0=B1=D0=B8?= Date: Mon, 23 Jul 2018 16:10:52 +0100 Subject: [PATCH 36/41] Make esp8266 compilation a little less verbose CL: Make esp8266 compilation a little less verbose PUBLISHED_FROM=0ec1412ea32243f263d52fbe0877ecca1efc5aef --- src/common/platforms/esp8266/common.mk | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/common/platforms/esp8266/common.mk b/src/common/platforms/esp8266/common.mk index bfe0f609..8ce894ed 100644 --- a/src/common/platforms/esp8266/common.mk +++ b/src/common/platforms/esp8266/common.mk @@ -25,7 +25,7 @@ $(Q) $(CC_WRAPPER) $(LD) $(LIBDIRS) -T$(LD_SCRIPT) $(LDFLAGS) -o $@ \ endef define compile_params -$(vecho) "$5 $1 -> $2" +$(vecho) "$5 $1" $(Q) $(CC_WRAPPER) $3 -MD -MP $(INCDIRS) $4 -c $1 -o $2 endef From 86b8a56b053b0aa9a00a1cefc5cd2faeabcad40f Mon Sep 17 00:00:00 2001 From: Deomid Ryabkov Date: Fri, 10 Aug 2018 14:31:21 +0300 Subject: [PATCH 37/41] Add host name verification for OpenSSL Closes https://github.com/cesanta/mongoose/pull/955 CL: mg: Add host name verification for OpenSSL PUBLISHED_FROM=e35dd636ba7ce63116f0a38031074d22f6cd5dac --- mongoose.c | 19 +++++++++++-------- src/mg_ssl_if_openssl.c | 19 +++++++++++-------- 2 files changed, 22 insertions(+), 16 deletions(-) diff --git a/mongoose.c b/mongoose.c index ddbed16b..1088cbcf 100644 --- a/mongoose.c +++ b/mongoose.c @@ -4425,6 +4425,9 @@ struct mg_iface *mg_socks_mk_iface(struct mg_mgr *mgr, const char *proxy_addr) { #endif #include +#ifndef KR_VERSION +#include +#endif struct mg_ssl_if_ctx { SSL *ssl; @@ -4509,14 +4512,6 @@ enum mg_ssl_if_result mg_ssl_if_conn_init( return MG_SSL_ERROR; } - if (params->server_name != NULL) { -#ifdef KR_VERSION - SSL_CTX_kr_set_verify_name(ctx->ssl_ctx, params->server_name); -#else -/* TODO(rojer): Implement server name verification on OpenSSL. */ -#endif - } - if (mg_set_cipher_list(ctx->ssl_ctx, params->cipher_suites) != MG_SSL_OK) { MG_SET_PTRPTR(err_msg, "Invalid cipher suite list"); return MG_SSL_ERROR; @@ -4535,6 +4530,14 @@ enum mg_ssl_if_result mg_ssl_if_conn_init( return MG_SSL_ERROR; } + if (params->server_name != NULL) { +#ifdef KR_VERSION + SSL_CTX_kr_set_verify_name(ctx->ssl_ctx, params->server_name); +#else + SSL_set_tlsext_host_name(ctx->ssl, params->server_name); +#endif + } + nc->flags |= MG_F_SSL; return MG_SSL_OK; diff --git a/src/mg_ssl_if_openssl.c b/src/mg_ssl_if_openssl.c index 2f3da5ea..ef8342fc 100644 --- a/src/mg_ssl_if_openssl.c +++ b/src/mg_ssl_if_openssl.c @@ -10,6 +10,9 @@ #endif #include +#ifndef KR_VERSION +#include +#endif struct mg_ssl_if_ctx { SSL *ssl; @@ -94,14 +97,6 @@ enum mg_ssl_if_result mg_ssl_if_conn_init( return MG_SSL_ERROR; } - if (params->server_name != NULL) { -#ifdef KR_VERSION - SSL_CTX_kr_set_verify_name(ctx->ssl_ctx, params->server_name); -#else -/* TODO(rojer): Implement server name verification on OpenSSL. */ -#endif - } - if (mg_set_cipher_list(ctx->ssl_ctx, params->cipher_suites) != MG_SSL_OK) { MG_SET_PTRPTR(err_msg, "Invalid cipher suite list"); return MG_SSL_ERROR; @@ -120,6 +115,14 @@ enum mg_ssl_if_result mg_ssl_if_conn_init( return MG_SSL_ERROR; } + if (params->server_name != NULL) { +#ifdef KR_VERSION + SSL_CTX_kr_set_verify_name(ctx->ssl_ctx, params->server_name); +#else + SSL_set_tlsext_host_name(ctx->ssl, params->server_name); +#endif + } + nc->flags |= MG_F_SSL; return MG_SSL_OK; From f33d3a4e0225d6e009b90193402141025e9ea74d Mon Sep 17 00:00:00 2001 From: Deomid Ryabkov Date: Mon, 13 Aug 2018 15:50:01 +0300 Subject: [PATCH 38/41] Fix body length calculation in mg_handle_cgi Fixes https://nvd.nist.gov/vuln/detail/CVE-2018-10945 CL: mg: Fix body length calculation in mg_handle_cgi PUBLISHED_FROM=0c30cf36fdb67c75f6148468701e23d6ee72d953 --- mongoose.c | 5 ++--- src/mg_http_cgi.c | 5 ++--- 2 files changed, 4 insertions(+), 6 deletions(-) diff --git a/mongoose.c b/mongoose.c index 1088cbcf..08addd02 100644 --- a/mongoose.c +++ b/mongoose.c @@ -9140,7 +9140,6 @@ MG_INTERNAL void mg_handle_cgi(struct mg_connection *nc, const char *prog, if (mg_start_process(opts->cgi_interpreter, prog, blk.buf, blk.vars, dir, fds[1]) != 0) { - size_t n = nc->recv_mbuf.len - (hm->message.len - hm->body.len); struct mg_connection *cgi_nc = mg_add_sock(nc->mgr, fds[0], mg_cgi_ev_handler MG_UD_ARG(nc)); struct mg_http_proto_data *cgi_pd = mg_http_get_proto_data(nc); @@ -9150,8 +9149,8 @@ MG_INTERNAL void mg_handle_cgi(struct mg_connection *nc, const char *prog, #endif nc->flags |= MG_F_HTTP_CGI_PARSE_HEADERS; /* Push POST data to the CGI */ - if (n > 0 && n < nc->recv_mbuf.len) { - mg_send(cgi_pd->cgi.cgi_nc, hm->body.p, n); + if (hm->body.len > 0) { + mg_send(cgi_pd->cgi.cgi_nc, hm->body.p, hm->body.len); } mbuf_remove(&nc->recv_mbuf, nc->recv_mbuf.len); } else { diff --git a/src/mg_http_cgi.c b/src/mg_http_cgi.c index 437c93c1..b06c5f80 100644 --- a/src/mg_http_cgi.c +++ b/src/mg_http_cgi.c @@ -478,7 +478,6 @@ MG_INTERNAL void mg_handle_cgi(struct mg_connection *nc, const char *prog, if (mg_start_process(opts->cgi_interpreter, prog, blk.buf, blk.vars, dir, fds[1]) != 0) { - size_t n = nc->recv_mbuf.len - (hm->message.len - hm->body.len); struct mg_connection *cgi_nc = mg_add_sock(nc->mgr, fds[0], mg_cgi_ev_handler MG_UD_ARG(nc)); struct mg_http_proto_data *cgi_pd = mg_http_get_proto_data(nc); @@ -488,8 +487,8 @@ MG_INTERNAL void mg_handle_cgi(struct mg_connection *nc, const char *prog, #endif nc->flags |= MG_F_HTTP_CGI_PARSE_HEADERS; /* Push POST data to the CGI */ - if (n > 0 && n < nc->recv_mbuf.len) { - mg_send(cgi_pd->cgi.cgi_nc, hm->body.p, n); + if (hm->body.len > 0) { + mg_send(cgi_pd->cgi.cgi_nc, hm->body.p, hm->body.len); } mbuf_remove(&nc->recv_mbuf, nc->recv_mbuf.len); } else { From c2d83a9db0c737313e7a3b318e92631949ae4305 Mon Sep 17 00:00:00 2001 From: Deomid Ryabkov Date: Mon, 13 Aug 2018 16:24:12 +0300 Subject: [PATCH 39/41] Don't touch send_mbuf when sending MQTT messages h/t @M4GNV5 Fixes https://github.com/cesanta/mongoose/issues/943 Closes https://github.com/cesanta/mongoose/issues/944 CL: mg: Don't touch send_mbuf when sending MQTT messages PUBLISHED_FROM=da7b4f8acec2e403caa4addd5739d036a6a74c76 --- mongoose.c | 191 ++++++++++++++++++++++++++++---------------------- src/mg_mqtt.c | 191 ++++++++++++++++++++++++++++---------------------- 2 files changed, 218 insertions(+), 164 deletions(-) diff --git a/mongoose.c b/mongoose.c index 08addd02..d1175649 100644 --- a/mongoose.c +++ b/mongoose.c @@ -10741,18 +10741,13 @@ void mg_set_protocol_mqtt(struct mg_connection *nc) { nc->proto_data_destructor = mg_mqtt_proto_data_destructor; } -static void mg_mqtt_prepend_header(struct mg_connection *nc, uint8_t cmd, - uint8_t flags, size_t len) { +static void mg_send_mqtt_header(struct mg_connection *nc, uint8_t cmd, + uint8_t flags, size_t len) { struct mg_mqtt_proto_data *pd = (struct mg_mqtt_proto_data *) nc->proto_data; - size_t off = nc->send_mbuf.len - len; - uint8_t header = cmd << 4 | (uint8_t) flags; - uint8_t buf[1 + sizeof(size_t)]; uint8_t *vlen = &buf[1]; - assert(nc->send_mbuf.len >= len); - - buf[0] = header; + buf[0] = (cmd << 4) | flags; /* mqtt variable length encoding */ do { @@ -10762,7 +10757,7 @@ static void mg_mqtt_prepend_header(struct mg_connection *nc, uint8_t cmd, vlen++; } while (len > 0); - mbuf_insert(&nc->send_mbuf, off, buf, vlen - buf); + mg_send(nc, buf, vlen - buf); pd->last_control_time = mg_time(); } @@ -10773,11 +10768,16 @@ void mg_send_mqtt_handshake(struct mg_connection *nc, const char *client_id) { void mg_send_mqtt_handshake_opt(struct mg_connection *nc, const char *client_id, struct mg_send_mqtt_handshake_opts opts) { - uint16_t hlen, nlen, rem_len = 0; struct mg_mqtt_proto_data *pd = (struct mg_mqtt_proto_data *) nc->proto_data; + uint16_t id_len = 0, wt_len = 0, wm_len = 0, user_len = 0, pw_len = 0; + uint16_t netbytes; + size_t total_len; - mg_send(nc, "\00\04MQTT\04", 7); - rem_len += 7; + if (client_id != NULL) { + id_len = strlen(client_id); + } + + total_len = 7 + 1 + 2 + 2 + id_len; if (opts.user_name != NULL) { opts.flags |= MG_MQTT_HAS_USER_NAME; @@ -10786,56 +10786,58 @@ void mg_send_mqtt_handshake_opt(struct mg_connection *nc, const char *client_id, opts.flags |= MG_MQTT_HAS_PASSWORD; } if (opts.will_topic != NULL && opts.will_message != NULL) { + wt_len = strlen(opts.will_topic); + wm_len = strlen(opts.will_message); opts.flags |= MG_MQTT_HAS_WILL; } if (opts.keep_alive == 0) { opts.keep_alive = 60; } + if (opts.flags & MG_MQTT_HAS_WILL) { + total_len += 2 + wt_len + 2 + wm_len; + } + if (opts.flags & MG_MQTT_HAS_USER_NAME) { + user_len = strlen(opts.user_name); + total_len += 2 + user_len; + } + if (opts.flags & MG_MQTT_HAS_PASSWORD) { + pw_len = strlen(opts.password); + total_len += 2 + pw_len; + } + + mg_send_mqtt_header(nc, MG_MQTT_CMD_CONNECT, 0, total_len); + mg_send(nc, "\00\04MQTT\04", 7); mg_send(nc, &opts.flags, 1); - rem_len += 1; - nlen = htons(opts.keep_alive); - mg_send(nc, &nlen, 2); - rem_len += 2; + netbytes = htons(opts.keep_alive); + mg_send(nc, &netbytes, 2); - hlen = strlen(client_id); - nlen = htons((uint16_t) hlen); - mg_send(nc, &nlen, 2); - mg_send(nc, client_id, hlen); - rem_len += 2 + hlen; + netbytes = htons(id_len); + mg_send(nc, &netbytes, 2); + mg_send(nc, client_id, id_len); if (opts.flags & MG_MQTT_HAS_WILL) { - hlen = strlen(opts.will_topic); - nlen = htons((uint16_t) hlen); - mg_send(nc, &nlen, 2); - mg_send(nc, opts.will_topic, hlen); - rem_len += 2 + hlen; + netbytes = htons(wt_len); + mg_send(nc, &netbytes, 2); + mg_send(nc, opts.will_topic, wt_len); - hlen = strlen(opts.will_message); - nlen = htons((uint16_t) hlen); - mg_send(nc, &nlen, 2); - mg_send(nc, opts.will_message, hlen); - rem_len += 2 + hlen; + netbytes = htons(wm_len); + mg_send(nc, &netbytes, 2); + mg_send(nc, opts.will_message, wm_len); } if (opts.flags & MG_MQTT_HAS_USER_NAME) { - hlen = strlen(opts.user_name); - nlen = htons((uint16_t) hlen); - mg_send(nc, &nlen, 2); - mg_send(nc, opts.user_name, hlen); - rem_len += 2 + hlen; + netbytes = htons(user_len); + mg_send(nc, &netbytes, 2); + mg_send(nc, opts.user_name, user_len); } if (opts.flags & MG_MQTT_HAS_PASSWORD) { - hlen = strlen(opts.password); - nlen = htons((uint16_t) hlen); - mg_send(nc, &nlen, 2); - mg_send(nc, opts.password, hlen); - rem_len += 2 + hlen; + netbytes = htons(pw_len); + mg_send(nc, &netbytes, 2); + mg_send(nc, opts.password, pw_len); } - mg_mqtt_prepend_header(nc, MG_MQTT_CMD_CONNECT, 0, rem_len); - if (pd != NULL) { pd->keep_alive = opts.keep_alive; } @@ -10844,40 +10846,52 @@ void mg_send_mqtt_handshake_opt(struct mg_connection *nc, const char *client_id, void mg_mqtt_publish(struct mg_connection *nc, const char *topic, uint16_t message_id, int flags, const void *data, size_t len) { - size_t old_len = nc->send_mbuf.len; + uint16_t netbytes; + uint16_t topic_len = strlen(topic); - uint16_t topic_len = htons((uint16_t) strlen(topic)); - uint16_t message_id_net = htons(message_id); - - mg_send(nc, &topic_len, 2); - mg_send(nc, topic, strlen(topic)); + size_t total_len = 2 + topic_len + len; if (MG_MQTT_GET_QOS(flags) > 0) { - mg_send(nc, &message_id_net, 2); + total_len += 2; } - mg_send(nc, data, len); - mg_mqtt_prepend_header(nc, MG_MQTT_CMD_PUBLISH, flags, - nc->send_mbuf.len - old_len); + mg_send_mqtt_header(nc, MG_MQTT_CMD_PUBLISH, flags, total_len); + + netbytes = htons(topic_len); + mg_send(nc, &netbytes, 2); + mg_send(nc, topic, topic_len); + + if (MG_MQTT_GET_QOS(flags) > 0) { + netbytes = htons(message_id); + mg_send(nc, &netbytes, 2); + } + + mg_send(nc, data, len); } void mg_mqtt_subscribe(struct mg_connection *nc, const struct mg_mqtt_topic_expression *topics, size_t topics_len, uint16_t message_id) { - size_t old_len = nc->send_mbuf.len; - - uint16_t message_id_n = htons(message_id); + uint16_t netbytes; size_t i; + uint16_t topic_len; + size_t total_len = 2; - mg_send(nc, (char *) &message_id_n, 2); for (i = 0; i < topics_len; i++) { - uint16_t topic_len_n = htons((uint16_t) strlen(topics[i].topic)); - mg_send(nc, &topic_len_n, 2); - mg_send(nc, topics[i].topic, strlen(topics[i].topic)); - mg_send(nc, &topics[i].qos, 1); + total_len += 2 + strlen(topics[i].topic) + 1; } - mg_mqtt_prepend_header(nc, MG_MQTT_CMD_SUBSCRIBE, MG_MQTT_QOS(1), - nc->send_mbuf.len - old_len); + mg_send_mqtt_header(nc, MG_MQTT_CMD_SUBSCRIBE, MG_MQTT_QOS(1), total_len); + + netbytes = htons(message_id); + mg_send(nc, (char *) &netbytes, 2); + + for (i = 0; i < topics_len; i++) { + topic_len = strlen(topics[i].topic); + netbytes = htons(topic_len); + mg_send(nc, &netbytes, 2); + mg_send(nc, topics[i].topic, topic_len); + mg_send(nc, &topics[i].qos, 1); + } } int mg_mqtt_next_subscribe_topic(struct mg_mqtt_message *msg, @@ -10897,27 +10911,33 @@ int mg_mqtt_next_subscribe_topic(struct mg_mqtt_message *msg, void mg_mqtt_unsubscribe(struct mg_connection *nc, char **topics, size_t topics_len, uint16_t message_id) { - size_t old_len = nc->send_mbuf.len; - - uint16_t message_id_n = htons(message_id); + uint16_t netbytes; size_t i; + uint16_t topic_len; + size_t total_len = 2; - mg_send(nc, (char *) &message_id_n, 2); for (i = 0; i < topics_len; i++) { - uint16_t topic_len_n = htons((uint16_t) strlen(topics[i])); - mg_send(nc, &topic_len_n, 2); - mg_send(nc, topics[i], strlen(topics[i])); + total_len += 2 + strlen(topics[i]); } - mg_mqtt_prepend_header(nc, MG_MQTT_CMD_UNSUBSCRIBE, MG_MQTT_QOS(1), - nc->send_mbuf.len - old_len); + mg_send_mqtt_header(nc, MG_MQTT_CMD_UNSUBSCRIBE, MG_MQTT_QOS(1), total_len); + + netbytes = htons(message_id); + mg_send(nc, (char *) &netbytes, 2); + + for (i = 0; i < topics_len; i++) { + topic_len = strlen(topics[i]); + netbytes = htons(topic_len); + mg_send(nc, &netbytes, 2); + mg_send(nc, topics[i], topic_len); + } } void mg_mqtt_connack(struct mg_connection *nc, uint8_t return_code) { uint8_t unused = 0; + mg_send_mqtt_header(nc, MG_MQTT_CMD_CONNACK, 0, 2); mg_send(nc, &unused, 1); mg_send(nc, &return_code, 1); - mg_mqtt_prepend_header(nc, MG_MQTT_CMD_CONNACK, 0, 2); } /* @@ -10927,10 +10947,13 @@ void mg_mqtt_connack(struct mg_connection *nc, uint8_t return_code) { */ static void mg_send_mqtt_short_command(struct mg_connection *nc, uint8_t cmd, uint16_t message_id) { - uint16_t message_id_net = htons(message_id); + uint16_t netbytes; uint8_t flags = (cmd == MG_MQTT_CMD_PUBREL ? 2 : 0); - mg_send(nc, &message_id_net, 2); - mg_mqtt_prepend_header(nc, cmd, flags, 2 /* len */); + + mg_send_mqtt_header(nc, cmd, flags, 2 /* len */); + + netbytes = htons(message_id); + mg_send(nc, &netbytes, 2); } void mg_mqtt_puback(struct mg_connection *nc, uint16_t message_id) { @@ -10952,12 +10975,16 @@ void mg_mqtt_pubcomp(struct mg_connection *nc, uint16_t message_id) { void mg_mqtt_suback(struct mg_connection *nc, uint8_t *qoss, size_t qoss_len, uint16_t message_id) { size_t i; - uint16_t message_id_net = htons(message_id); - mg_send(nc, &message_id_net, 2); + uint16_t netbytes; + + mg_send_mqtt_header(nc, MG_MQTT_CMD_SUBACK, MG_MQTT_QOS(1), 2 + qoss_len); + + netbytes = htons(message_id); + mg_send(nc, &netbytes, 2); + for (i = 0; i < qoss_len; i++) { mg_send(nc, &qoss[i], 1); } - mg_mqtt_prepend_header(nc, MG_MQTT_CMD_SUBACK, MG_MQTT_QOS(1), 2 + qoss_len); } void mg_mqtt_unsuback(struct mg_connection *nc, uint16_t message_id) { @@ -10965,15 +10992,15 @@ void mg_mqtt_unsuback(struct mg_connection *nc, uint16_t message_id) { } void mg_mqtt_ping(struct mg_connection *nc) { - mg_mqtt_prepend_header(nc, MG_MQTT_CMD_PINGREQ, 0, 0); + mg_send_mqtt_header(nc, MG_MQTT_CMD_PINGREQ, 0, 0); } void mg_mqtt_pong(struct mg_connection *nc) { - mg_mqtt_prepend_header(nc, MG_MQTT_CMD_PINGRESP, 0, 0); + mg_send_mqtt_header(nc, MG_MQTT_CMD_PINGRESP, 0, 0); } void mg_mqtt_disconnect(struct mg_connection *nc) { - mg_mqtt_prepend_header(nc, MG_MQTT_CMD_DISCONNECT, 0, 0); + mg_send_mqtt_header(nc, MG_MQTT_CMD_DISCONNECT, 0, 0); } #endif /* MG_ENABLE_MQTT */ diff --git a/src/mg_mqtt.c b/src/mg_mqtt.c index 369b4561..5c0b194e 100644 --- a/src/mg_mqtt.c +++ b/src/mg_mqtt.c @@ -228,18 +228,13 @@ void mg_set_protocol_mqtt(struct mg_connection *nc) { nc->proto_data_destructor = mg_mqtt_proto_data_destructor; } -static void mg_mqtt_prepend_header(struct mg_connection *nc, uint8_t cmd, - uint8_t flags, size_t len) { +static void mg_send_mqtt_header(struct mg_connection *nc, uint8_t cmd, + uint8_t flags, size_t len) { struct mg_mqtt_proto_data *pd = (struct mg_mqtt_proto_data *) nc->proto_data; - size_t off = nc->send_mbuf.len - len; - uint8_t header = cmd << 4 | (uint8_t) flags; - uint8_t buf[1 + sizeof(size_t)]; uint8_t *vlen = &buf[1]; - assert(nc->send_mbuf.len >= len); - - buf[0] = header; + buf[0] = (cmd << 4) | flags; /* mqtt variable length encoding */ do { @@ -249,7 +244,7 @@ static void mg_mqtt_prepend_header(struct mg_connection *nc, uint8_t cmd, vlen++; } while (len > 0); - mbuf_insert(&nc->send_mbuf, off, buf, vlen - buf); + mg_send(nc, buf, vlen - buf); pd->last_control_time = mg_time(); } @@ -260,11 +255,16 @@ void mg_send_mqtt_handshake(struct mg_connection *nc, const char *client_id) { void mg_send_mqtt_handshake_opt(struct mg_connection *nc, const char *client_id, struct mg_send_mqtt_handshake_opts opts) { - uint16_t hlen, nlen, rem_len = 0; struct mg_mqtt_proto_data *pd = (struct mg_mqtt_proto_data *) nc->proto_data; + uint16_t id_len = 0, wt_len = 0, wm_len = 0, user_len = 0, pw_len = 0; + uint16_t netbytes; + size_t total_len; - mg_send(nc, "\00\04MQTT\04", 7); - rem_len += 7; + if (client_id != NULL) { + id_len = strlen(client_id); + } + + total_len = 7 + 1 + 2 + 2 + id_len; if (opts.user_name != NULL) { opts.flags |= MG_MQTT_HAS_USER_NAME; @@ -273,56 +273,58 @@ void mg_send_mqtt_handshake_opt(struct mg_connection *nc, const char *client_id, opts.flags |= MG_MQTT_HAS_PASSWORD; } if (opts.will_topic != NULL && opts.will_message != NULL) { + wt_len = strlen(opts.will_topic); + wm_len = strlen(opts.will_message); opts.flags |= MG_MQTT_HAS_WILL; } if (opts.keep_alive == 0) { opts.keep_alive = 60; } + if (opts.flags & MG_MQTT_HAS_WILL) { + total_len += 2 + wt_len + 2 + wm_len; + } + if (opts.flags & MG_MQTT_HAS_USER_NAME) { + user_len = strlen(opts.user_name); + total_len += 2 + user_len; + } + if (opts.flags & MG_MQTT_HAS_PASSWORD) { + pw_len = strlen(opts.password); + total_len += 2 + pw_len; + } + + mg_send_mqtt_header(nc, MG_MQTT_CMD_CONNECT, 0, total_len); + mg_send(nc, "\00\04MQTT\04", 7); mg_send(nc, &opts.flags, 1); - rem_len += 1; - nlen = htons(opts.keep_alive); - mg_send(nc, &nlen, 2); - rem_len += 2; + netbytes = htons(opts.keep_alive); + mg_send(nc, &netbytes, 2); - hlen = strlen(client_id); - nlen = htons((uint16_t) hlen); - mg_send(nc, &nlen, 2); - mg_send(nc, client_id, hlen); - rem_len += 2 + hlen; + netbytes = htons(id_len); + mg_send(nc, &netbytes, 2); + mg_send(nc, client_id, id_len); if (opts.flags & MG_MQTT_HAS_WILL) { - hlen = strlen(opts.will_topic); - nlen = htons((uint16_t) hlen); - mg_send(nc, &nlen, 2); - mg_send(nc, opts.will_topic, hlen); - rem_len += 2 + hlen; + netbytes = htons(wt_len); + mg_send(nc, &netbytes, 2); + mg_send(nc, opts.will_topic, wt_len); - hlen = strlen(opts.will_message); - nlen = htons((uint16_t) hlen); - mg_send(nc, &nlen, 2); - mg_send(nc, opts.will_message, hlen); - rem_len += 2 + hlen; + netbytes = htons(wm_len); + mg_send(nc, &netbytes, 2); + mg_send(nc, opts.will_message, wm_len); } if (opts.flags & MG_MQTT_HAS_USER_NAME) { - hlen = strlen(opts.user_name); - nlen = htons((uint16_t) hlen); - mg_send(nc, &nlen, 2); - mg_send(nc, opts.user_name, hlen); - rem_len += 2 + hlen; + netbytes = htons(user_len); + mg_send(nc, &netbytes, 2); + mg_send(nc, opts.user_name, user_len); } if (opts.flags & MG_MQTT_HAS_PASSWORD) { - hlen = strlen(opts.password); - nlen = htons((uint16_t) hlen); - mg_send(nc, &nlen, 2); - mg_send(nc, opts.password, hlen); - rem_len += 2 + hlen; + netbytes = htons(pw_len); + mg_send(nc, &netbytes, 2); + mg_send(nc, opts.password, pw_len); } - mg_mqtt_prepend_header(nc, MG_MQTT_CMD_CONNECT, 0, rem_len); - if (pd != NULL) { pd->keep_alive = opts.keep_alive; } @@ -331,40 +333,52 @@ void mg_send_mqtt_handshake_opt(struct mg_connection *nc, const char *client_id, void mg_mqtt_publish(struct mg_connection *nc, const char *topic, uint16_t message_id, int flags, const void *data, size_t len) { - size_t old_len = nc->send_mbuf.len; + uint16_t netbytes; + uint16_t topic_len = strlen(topic); - uint16_t topic_len = htons((uint16_t) strlen(topic)); - uint16_t message_id_net = htons(message_id); - - mg_send(nc, &topic_len, 2); - mg_send(nc, topic, strlen(topic)); + size_t total_len = 2 + topic_len + len; if (MG_MQTT_GET_QOS(flags) > 0) { - mg_send(nc, &message_id_net, 2); + total_len += 2; } - mg_send(nc, data, len); - mg_mqtt_prepend_header(nc, MG_MQTT_CMD_PUBLISH, flags, - nc->send_mbuf.len - old_len); + mg_send_mqtt_header(nc, MG_MQTT_CMD_PUBLISH, flags, total_len); + + netbytes = htons(topic_len); + mg_send(nc, &netbytes, 2); + mg_send(nc, topic, topic_len); + + if (MG_MQTT_GET_QOS(flags) > 0) { + netbytes = htons(message_id); + mg_send(nc, &netbytes, 2); + } + + mg_send(nc, data, len); } void mg_mqtt_subscribe(struct mg_connection *nc, const struct mg_mqtt_topic_expression *topics, size_t topics_len, uint16_t message_id) { - size_t old_len = nc->send_mbuf.len; - - uint16_t message_id_n = htons(message_id); + uint16_t netbytes; size_t i; + uint16_t topic_len; + size_t total_len = 2; - mg_send(nc, (char *) &message_id_n, 2); for (i = 0; i < topics_len; i++) { - uint16_t topic_len_n = htons((uint16_t) strlen(topics[i].topic)); - mg_send(nc, &topic_len_n, 2); - mg_send(nc, topics[i].topic, strlen(topics[i].topic)); - mg_send(nc, &topics[i].qos, 1); + total_len += 2 + strlen(topics[i].topic) + 1; } - mg_mqtt_prepend_header(nc, MG_MQTT_CMD_SUBSCRIBE, MG_MQTT_QOS(1), - nc->send_mbuf.len - old_len); + mg_send_mqtt_header(nc, MG_MQTT_CMD_SUBSCRIBE, MG_MQTT_QOS(1), total_len); + + netbytes = htons(message_id); + mg_send(nc, (char *) &netbytes, 2); + + for (i = 0; i < topics_len; i++) { + topic_len = strlen(topics[i].topic); + netbytes = htons(topic_len); + mg_send(nc, &netbytes, 2); + mg_send(nc, topics[i].topic, topic_len); + mg_send(nc, &topics[i].qos, 1); + } } int mg_mqtt_next_subscribe_topic(struct mg_mqtt_message *msg, @@ -384,27 +398,33 @@ int mg_mqtt_next_subscribe_topic(struct mg_mqtt_message *msg, void mg_mqtt_unsubscribe(struct mg_connection *nc, char **topics, size_t topics_len, uint16_t message_id) { - size_t old_len = nc->send_mbuf.len; - - uint16_t message_id_n = htons(message_id); + uint16_t netbytes; size_t i; + uint16_t topic_len; + size_t total_len = 2; - mg_send(nc, (char *) &message_id_n, 2); for (i = 0; i < topics_len; i++) { - uint16_t topic_len_n = htons((uint16_t) strlen(topics[i])); - mg_send(nc, &topic_len_n, 2); - mg_send(nc, topics[i], strlen(topics[i])); + total_len += 2 + strlen(topics[i]); } - mg_mqtt_prepend_header(nc, MG_MQTT_CMD_UNSUBSCRIBE, MG_MQTT_QOS(1), - nc->send_mbuf.len - old_len); + mg_send_mqtt_header(nc, MG_MQTT_CMD_UNSUBSCRIBE, MG_MQTT_QOS(1), total_len); + + netbytes = htons(message_id); + mg_send(nc, (char *) &netbytes, 2); + + for (i = 0; i < topics_len; i++) { + topic_len = strlen(topics[i]); + netbytes = htons(topic_len); + mg_send(nc, &netbytes, 2); + mg_send(nc, topics[i], topic_len); + } } void mg_mqtt_connack(struct mg_connection *nc, uint8_t return_code) { uint8_t unused = 0; + mg_send_mqtt_header(nc, MG_MQTT_CMD_CONNACK, 0, 2); mg_send(nc, &unused, 1); mg_send(nc, &return_code, 1); - mg_mqtt_prepend_header(nc, MG_MQTT_CMD_CONNACK, 0, 2); } /* @@ -414,10 +434,13 @@ void mg_mqtt_connack(struct mg_connection *nc, uint8_t return_code) { */ static void mg_send_mqtt_short_command(struct mg_connection *nc, uint8_t cmd, uint16_t message_id) { - uint16_t message_id_net = htons(message_id); + uint16_t netbytes; uint8_t flags = (cmd == MG_MQTT_CMD_PUBREL ? 2 : 0); - mg_send(nc, &message_id_net, 2); - mg_mqtt_prepend_header(nc, cmd, flags, 2 /* len */); + + mg_send_mqtt_header(nc, cmd, flags, 2 /* len */); + + netbytes = htons(message_id); + mg_send(nc, &netbytes, 2); } void mg_mqtt_puback(struct mg_connection *nc, uint16_t message_id) { @@ -439,12 +462,16 @@ void mg_mqtt_pubcomp(struct mg_connection *nc, uint16_t message_id) { void mg_mqtt_suback(struct mg_connection *nc, uint8_t *qoss, size_t qoss_len, uint16_t message_id) { size_t i; - uint16_t message_id_net = htons(message_id); - mg_send(nc, &message_id_net, 2); + uint16_t netbytes; + + mg_send_mqtt_header(nc, MG_MQTT_CMD_SUBACK, MG_MQTT_QOS(1), 2 + qoss_len); + + netbytes = htons(message_id); + mg_send(nc, &netbytes, 2); + for (i = 0; i < qoss_len; i++) { mg_send(nc, &qoss[i], 1); } - mg_mqtt_prepend_header(nc, MG_MQTT_CMD_SUBACK, MG_MQTT_QOS(1), 2 + qoss_len); } void mg_mqtt_unsuback(struct mg_connection *nc, uint16_t message_id) { @@ -452,15 +479,15 @@ void mg_mqtt_unsuback(struct mg_connection *nc, uint16_t message_id) { } void mg_mqtt_ping(struct mg_connection *nc) { - mg_mqtt_prepend_header(nc, MG_MQTT_CMD_PINGREQ, 0, 0); + mg_send_mqtt_header(nc, MG_MQTT_CMD_PINGREQ, 0, 0); } void mg_mqtt_pong(struct mg_connection *nc) { - mg_mqtt_prepend_header(nc, MG_MQTT_CMD_PINGRESP, 0, 0); + mg_send_mqtt_header(nc, MG_MQTT_CMD_PINGRESP, 0, 0); } void mg_mqtt_disconnect(struct mg_connection *nc) { - mg_mqtt_prepend_header(nc, MG_MQTT_CMD_DISCONNECT, 0, 0); + mg_send_mqtt_header(nc, MG_MQTT_CMD_DISCONNECT, 0, 0); } #endif /* MG_ENABLE_MQTT */ From 0a3e186f111bfd062926525d1a68c7bc0cbd894d Mon Sep 17 00:00:00 2001 From: Deomid Ryabkov Date: Mon, 13 Aug 2018 16:50:27 +0300 Subject: [PATCH 40/41] Mongoose 6.12 CL: Mongoose 6.12 PUBLISHED_FROM=8008e4db2f6d94d972fb6e1077525e262c8744aa --- mongoose.h | 2 +- src/mg_common.h | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/mongoose.h b/mongoose.h index 5f9219db..2667c759 100644 --- a/mongoose.h +++ b/mongoose.h @@ -23,7 +23,7 @@ #ifndef CS_MONGOOSE_SRC_COMMON_H_ #define CS_MONGOOSE_SRC_COMMON_H_ -#define MG_VERSION "6.11" +#define MG_VERSION "6.12" /* Local tweaks, applied before any of Mongoose's own headers. */ #ifdef MG_LOCALS diff --git a/src/mg_common.h b/src/mg_common.h index 81ecdf97..adb99e8f 100644 --- a/src/mg_common.h +++ b/src/mg_common.h @@ -20,7 +20,7 @@ #ifndef CS_MONGOOSE_SRC_COMMON_H_ #define CS_MONGOOSE_SRC_COMMON_H_ -#define MG_VERSION "6.11" +#define MG_VERSION "6.12" /* Local tweaks, applied before any of Mongoose's own headers. */ #ifdef MG_LOCALS From 6df642623a9dc6c00a4f716c26be315267de4422 Mon Sep 17 00:00:00 2001 From: Sergey Lyubka Date: Tue, 17 Apr 2018 15:08:35 +0100 Subject: [PATCH 41/41] Delete CONTRIBUTING.md --- CONTRIBUTING.md | 8 -------- 1 file changed, 8 deletions(-) delete mode 100644 CONTRIBUTING.md diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md deleted file mode 100644 index 4581b014..00000000 --- a/CONTRIBUTING.md +++ /dev/null @@ -1,8 +0,0 @@ -People who have agreed to the -[Cesanta CLA](https://docs.cesanta.com/contributors_la.shtml) -can make contributions. Note that the CLA isn't a copyright -_assigment_ but rather a copyright _license_. -You retain the copyright on your contributions. - -We follow the Google C/C++ style guide: https://google.github.io/styleguide/cppguide.html -We'd appreciate if your contribution follows the same style guide.