From 70b5f4130ed57c3f33b2bf689c3d5cc59aab61f7 Mon Sep 17 00:00:00 2001 From: Sergey Lyubka Date: Thu, 23 Feb 2017 19:45:58 +0200 Subject: [PATCH 001/137] Add http post example PUBLISHED_FROM=94f830a5fa4b806fb2cf60c93a9e8744022ff8d7 --- mongoose.c | 21 ++++++++++----------- 1 file changed, 10 insertions(+), 11 deletions(-) diff --git a/mongoose.c b/mongoose.c index d0dcf8b8..11a089db 100644 --- a/mongoose.c +++ b/mongoose.c @@ -4968,10 +4968,10 @@ int mg_normalize_uri_path(const struct mg_str *in, struct mg_str *out) { #if MG_ENABLE_HTTP +/* Amalgamated: #include "common/md5.h" */ +/* Amalgamated: #include "common/sha1.h" */ /* Amalgamated: #include "mongoose/src/internal.h" */ /* Amalgamated: #include "mongoose/src/util.h" */ -/* Amalgamated: #include "common/sha1.h" */ -/* Amalgamated: #include "common/md5.h" */ static const char *mg_version_header = "Mongoose/" MG_VERSION; @@ -5825,8 +5825,7 @@ static void mg_http_multipart_begin(struct mg_connection *nc, mbuf_remove(io, req_len); } -exit_mp: - ; +exit_mp:; } #define CONTENT_DISPOSITION "Content-Disposition: " @@ -7189,8 +7188,7 @@ MG_INTERNAL int mg_uri_to_local_path(struct http_message *hm, if (*p == '\0' || *p == DIRSEP #ifdef _WIN32 /* On Windows, "/" is also accepted, so check for that too. */ - || - *p == '/' + || *p == '/' #endif ) { ok = 0; @@ -7732,13 +7730,14 @@ struct mg_connection *mg_connect_http_opt(struct mg_mgr *mgr, mg_basic_auth_header(user, pass, &auth); } + if (post_data == NULL) post_data = ""; + if (extra_headers == NULL) extra_headers = ""; + mg_printf(nc, "%s %s HTTP/1.1\r\nHost: %s\r\nContent-Length: %" SIZE_T_FMT "\r\n%.*s%s\r\n%s", - post_data == NULL ? "GET" : "POST", path, addr, - post_data == NULL ? 0 : strlen(post_data), (int) auth.len, - (auth.buf == NULL ? "" : auth.buf), - extra_headers == NULL ? "" : extra_headers, - post_data == NULL ? "" : post_data); + post_data[0] == '\0' ? "GET" : "POST", path, addr, + strlen(post_data), (int) auth.len, + (auth.buf == NULL ? "" : auth.buf), extra_headers, post_data); mbuf_free(&auth); MG_FREE(user); From 60c16bbb5d4ca7c6dbc735c3f4e12e0566c923ef Mon Sep 17 00:00:00 2001 From: Dmitry Frank Date: Thu, 23 Feb 2017 23:26:15 +0200 Subject: [PATCH 002/137] Fix mos docker image name PUBLISHED_FROM=91016ab1629a65976d2cc2f00aec4e1667cb4a8f --- mongoose.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/mongoose.c b/mongoose.c index 11a089db..0bda1e29 100644 --- a/mongoose.c +++ b/mongoose.c @@ -5825,7 +5825,8 @@ static void mg_http_multipart_begin(struct mg_connection *nc, mbuf_remove(io, req_len); } -exit_mp:; +exit_mp: + ; } #define CONTENT_DISPOSITION "Content-Disposition: " @@ -7188,7 +7189,8 @@ MG_INTERNAL int mg_uri_to_local_path(struct http_message *hm, if (*p == '\0' || *p == DIRSEP #ifdef _WIN32 /* On Windows, "/" is also accepted, so check for that too. */ - || *p == '/' + || + *p == '/' #endif ) { ok = 0; From 3942914945d13316b72d5d9057479c9a8cbdeb06 Mon Sep 17 00:00:00 2001 From: Dmitry Frank Date: Fri, 24 Feb 2017 14:10:58 +0000 Subject: [PATCH 003/137] Fix subscription to wildcard topics `mg_mqtt_match_topic_expression()` and friends are public now. So far, only `#` is supported. PUBLISHED_FROM=20c031bcf34be84771c4a9c456318634eb9a517c --- docs/c-api/mqtt.h/intro.md | 2 + .../mqtt.h/mg_mqtt_match_topic_expression.md | 12 ++++++ .../mqtt.h/mg_mqtt_vmatch_topic_expression.md | 11 ++++++ mongoose.c | 39 ++++++++----------- mongoose.h | 13 +++++++ 5 files changed, 55 insertions(+), 22 deletions(-) create mode 100644 docs/c-api/mqtt.h/mg_mqtt_match_topic_expression.md create mode 100644 docs/c-api/mqtt.h/mg_mqtt_vmatch_topic_expression.md diff --git a/docs/c-api/mqtt.h/intro.md b/docs/c-api/mqtt.h/intro.md index 5ae849aa..bb5d31b4 100644 --- a/docs/c-api/mqtt.h/intro.md +++ b/docs/c-api/mqtt.h/intro.md @@ -5,6 +5,7 @@ decl_name: "mqtt.h" items: - { name: mg_mqtt_connack.md } - { name: mg_mqtt_disconnect.md } + - { name: mg_mqtt_match_topic_expression.md } - { name: mg_mqtt_next_subscribe_topic.md } - { name: mg_mqtt_ping.md } - { name: mg_mqtt_pong.md } @@ -17,6 +18,7 @@ items: - { name: mg_mqtt_subscribe.md } - { name: mg_mqtt_unsuback.md } - { name: mg_mqtt_unsubscribe.md } + - { name: mg_mqtt_vmatch_topic_expression.md } - { name: mg_send_mqtt_handshake.md } - { name: mg_send_mqtt_handshake_opt.md } - { name: mg_set_protocol_mqtt.md } diff --git a/docs/c-api/mqtt.h/mg_mqtt_match_topic_expression.md b/docs/c-api/mqtt.h/mg_mqtt_match_topic_expression.md new file mode 100644 index 00000000..81575b47 --- /dev/null +++ b/docs/c-api/mqtt.h/mg_mqtt_match_topic_expression.md @@ -0,0 +1,12 @@ +--- +title: "mg_mqtt_match_topic_expression()" +decl_name: "mg_mqtt_match_topic_expression" +symbol_kind: "func" +signature: | + int mg_mqtt_match_topic_expression(struct mg_str exp, struct mg_str topic); +--- + +Matches a topic against a topic expression + +Returns 1 if it matches; 0 otherwise. + diff --git a/docs/c-api/mqtt.h/mg_mqtt_vmatch_topic_expression.md b/docs/c-api/mqtt.h/mg_mqtt_vmatch_topic_expression.md new file mode 100644 index 00000000..4b0a4231 --- /dev/null +++ b/docs/c-api/mqtt.h/mg_mqtt_vmatch_topic_expression.md @@ -0,0 +1,11 @@ +--- +title: "mg_mqtt_vmatch_topic_expression()" +decl_name: "mg_mqtt_vmatch_topic_expression" +symbol_kind: "func" +signature: | + int mg_mqtt_vmatch_topic_expression(const char *exp, struct mg_str topic); +--- + +Same as `mg_mqtt_match_topic_expression()`, but takes `exp` as a +NULL-terminated string. + diff --git a/mongoose.c b/mongoose.c index 0bda1e29..b5ba29a8 100644 --- a/mongoose.c +++ b/mongoose.c @@ -9703,6 +9703,21 @@ static void mg_mqtt_proto_data_destructor(void *proto_data) { MG_FREE(proto_data); } +int mg_mqtt_match_topic_expression(struct mg_str exp, struct mg_str topic) { + /* TODO(mkm): implement real matching */ + if (memchr(exp.p, '#', exp.len)) { + exp.len -= 2; + if (topic.len < exp.len) { + exp.len = topic.len; + } + } + return strncmp(topic.p, exp.p, exp.len) == 0; +} + +int mg_mqtt_vmatch_topic_expression(const char *exp, struct mg_str topic) { + return mg_mqtt_match_topic_expression(mg_mk_str(exp), topic); +} + void mg_set_protocol_mqtt(struct mg_connection *nc) { nc->proto_handler = mqtt_handler; nc->proto_data = MG_CALLOC(1, sizeof(struct mg_mqtt_proto_data)); @@ -10040,26 +10055,6 @@ static void mg_mqtt_broker_handle_subscribe(struct mg_connection *nc, mg_mqtt_suback(nc, qoss, qoss_len, msg->message_id); } -/* - * Matches a topic against a topic expression - * - * See http://goo.gl/iWk21X - * - * Returns 1 if it matches; 0 otherwise. - */ -static int mg_mqtt_match_topic_expression(const char *exp, - const struct mg_str *topic) { - /* TODO(mkm): implement real matching */ - size_t len = strlen(exp); - if (strchr(exp, '#')) { - len -= 2; - if (topic->len < len) { - len = topic->len; - } - } - return strncmp(topic->p, exp, len) == 0; -} - static void mg_mqtt_broker_handle_publish(struct mg_mqtt_broker *brk, struct mg_mqtt_message *msg) { struct mg_mqtt_session *s; @@ -10067,8 +10062,8 @@ static void mg_mqtt_broker_handle_publish(struct mg_mqtt_broker *brk, for (s = mg_mqtt_next(brk, NULL); s != NULL; s = mg_mqtt_next(brk, s)) { for (i = 0; i < s->num_subscriptions; i++) { - if (mg_mqtt_match_topic_expression(s->subscriptions[i].topic, - &msg->topic)) { + if (mg_mqtt_vmatch_topic_expression(s->subscriptions[i].topic, + msg->topic)) { char buf[100], *p = buf; mg_asprintf(&p, sizeof(buf), "%.*s", (int) msg->topic.len, msg->topic.p); diff --git a/mongoose.h b/mongoose.h index 1ec11e51..2933d48a 100644 --- a/mongoose.h +++ b/mongoose.h @@ -5152,6 +5152,19 @@ void mg_mqtt_pong(struct mg_connection *nc); int mg_mqtt_next_subscribe_topic(struct mg_mqtt_message *msg, struct mg_str *topic, uint8_t *qos, int pos); +/* + * Matches a topic against a topic expression + * + * Returns 1 if it matches; 0 otherwise. + */ +int mg_mqtt_match_topic_expression(struct mg_str exp, struct mg_str topic); + +/* + * Same as `mg_mqtt_match_topic_expression()`, but takes `exp` as a + * NULL-terminated string. + */ +int mg_mqtt_vmatch_topic_expression(const char *exp, struct mg_str topic); + #ifdef __cplusplus } #endif /* __cplusplus */ From 349d25dccfacb314dc54a809f7b54b641a3ee172 Mon Sep 17 00:00:00 2001 From: Dmitry Frank Date: Fri, 24 Feb 2017 17:28:47 +0200 Subject: [PATCH 004/137] Fix # matching logic E.g. given the expression `foo/#`: - `foo/bar` matches - `foo/` should not match - `foo` should not match PUBLISHED_FROM=40f3290cb9a478b22d9f1ab6382884b5de70e266 --- mongoose.c | 17 ++++++++++++++--- 1 file changed, 14 insertions(+), 3 deletions(-) diff --git a/mongoose.c b/mongoose.c index b5ba29a8..5f84b7b1 100644 --- a/mongoose.c +++ b/mongoose.c @@ -9706,10 +9706,21 @@ static void mg_mqtt_proto_data_destructor(void *proto_data) { int mg_mqtt_match_topic_expression(struct mg_str exp, struct mg_str topic) { /* TODO(mkm): implement real matching */ if (memchr(exp.p, '#', exp.len)) { - exp.len -= 2; - if (topic.len < exp.len) { - exp.len = topic.len; + /* exp `foo/#` will become `foo/` */ + exp.len -= 1; + /* + * topic should be longer than the expression: e.g. topic `foo/bar` does + * match `foo/#`, but neither `foo` nor `foo/` do. + */ + if (topic.len <= exp.len) { + return 0; } + + /* Truncate topic so that it'll pass the next length check */ + topic.len = exp.len; + } + if (topic.len != exp.len) { + return 0; } return strncmp(topic.p, exp.p, exp.len) == 0; } From 71d09722bebf8b70dfc2208a65374a4798732b2f Mon Sep 17 00:00:00 2001 From: Yiming Sun Date: Mon, 27 Feb 2017 20:06:19 +0000 Subject: [PATCH 005/137] Fix http_client doc PUBLISHED_FROM=f415ddbac47e3069d3ab29467a23f6b8dab0066f --- docs/http/client_example.md | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/docs/http/client_example.md b/docs/http/client_example.md index 9f7e06e0..2b159a65 100644 --- a/docs/http/client_example.md +++ b/docs/http/client_example.md @@ -18,8 +18,9 @@ static int exit_flag = 0; static void ev_handler(struct mg_connection *c, int ev, void *p) { if (ev == MG_EV_HTTP_REPLY) { + struct http_message *hm = (struct http_message *)p; c->flags |= MG_F_CLOSE_IMMEDIATELY; - fwrite(hm->message.p, 1, hm->message.len, stdout); + fwrite(hm->message.p, 1, (int)hm->message.len, stdout); putchar('\n'); exit_flag = 1; } else if (ev == MG_EV_CLOSE) { @@ -31,7 +32,7 @@ int main(void) { struct mg_mgr mgr; mg_mgr_init(&mgr, NULL); - mg_connect_http(mgr, ev_handler, url, NULL, NULL); + mg_connect_http(&mgr, ev_handler, url, NULL, NULL); while (exit_flag == 0) { From 874b5bfdbff2a4f47aa2629211ef9360b32d04fd Mon Sep 17 00:00:00 2001 From: Yiming Sun Date: Tue, 28 Feb 2017 12:33:56 +0200 Subject: [PATCH 006/137] Fix comment in mongoose.h PUBLISHED_FROM=35e8f18aa611b45c271d0178d9197291bfa9726d --- docs/c-api/http_server.h/mg_register_http_endpoint.md | 2 +- mongoose.h | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/c-api/http_server.h/mg_register_http_endpoint.md b/docs/c-api/http_server.h/mg_register_http_endpoint.md index 752eaae6..99418caa 100644 --- a/docs/c-api/http_server.h/mg_register_http_endpoint.md +++ b/docs/c-api/http_server.h/mg_register_http_endpoint.md @@ -20,7 +20,7 @@ static void handle_hello1(struct mg_connection *nc, int ev, void *ev_data) { nc->flags |= MG_F_SEND_AND_CLOSE; } -static void handle_hello1(struct mg_connection *nc, int ev, void *ev_data) { +static void handle_hello2(struct mg_connection *nc, int ev, void *ev_data) { (void) ev; (void) ev_data; mg_printf(nc, "HTTP/1.0 200 OK\r\n\r\n[I am Hello2]"); nc->flags |= MG_F_SEND_AND_CLOSE; diff --git a/mongoose.h b/mongoose.h index 2933d48a..ab74b05a 100644 --- a/mongoose.h +++ b/mongoose.h @@ -4742,7 +4742,7 @@ void mg_file_upload_handler(struct mg_connection *nc, int ev, void *ev_data, * nc->flags |= MG_F_SEND_AND_CLOSE; * } * - * static void handle_hello1(struct mg_connection *nc, int ev, void *ev_data) { + * static void handle_hello2(struct mg_connection *nc, int ev, void *ev_data) { * (void) ev; (void) ev_data; * mg_printf(nc, "HTTP/1.0 200 OK\r\n\r\n[I am Hello2]"); * nc->flags |= MG_F_SEND_AND_CLOSE; From f7c0a2ee15044d543921e84897f0e2a3753323b9 Mon Sep 17 00:00:00 2001 From: Yiming Sun Date: Tue, 28 Feb 2017 12:52:45 +0200 Subject: [PATCH 007/137] Fix server_example.md PUBLISHED_FROM=dfbfeaae983daa0412964ac0402759f632bf7aeb --- docs/http/server_example.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/http/server_example.md b/docs/http/server_example.md index a244d647..225beb40 100644 --- a/docs/http/server_example.md +++ b/docs/http/server_example.md @@ -30,8 +30,8 @@ static void ev_handler(struct mg_connection *c, int ev, void *p) { // We have received an HTTP request. Parsed request is contained in `hm`. // Send HTTP reply to the client which shows full original request. - mg_send_head(c, 200, hm.message.len, "Content-Type: text/plain"); - mg_printf(c, "%.*s", hm.message.len, hm.message.p); + mg_send_head(c, 200, hm->message.len, "Content-Type: text/plain"); + mg_printf(c, "%.*s", (int)hm->message.len, hm->message.p); } } From b5dd54a404dccd4f80811368a52d46996aed058d Mon Sep 17 00:00:00 2001 From: Alexander Alashkin Date: Wed, 1 Mar 2017 08:03:50 +0200 Subject: [PATCH 008/137] Fix doc typos PUBLISHED_FROM=1bdacf793b35ebe70d0a3a9d64260dd2bd135c73 --- docs/c-api/coap.h/mg_coap_free_options.md | 2 +- docs/c-api/dns.h/mg_dns_encode_record.md | 2 +- docs/c-api/http_server.h/mg_http_send_redirect.md | 2 +- docs/c-api/http_server.h/mg_send_response_line.md | 2 +- docs/c-api/net.h/mg_bind_opt.md | 2 +- docs/c-api/net.h/mg_check_ip_acl.md | 2 +- docs/http/ssi.md | 2 +- mongoose.c | 6 +++--- mongoose.h | 14 +++++++------- 9 files changed, 17 insertions(+), 17 deletions(-) diff --git a/docs/c-api/coap.h/mg_coap_free_options.md b/docs/c-api/coap.h/mg_coap_free_options.md index 9dcc816f..d429cf49 100644 --- a/docs/c-api/coap.h/mg_coap_free_options.md +++ b/docs/c-api/coap.h/mg_coap_free_options.md @@ -7,5 +7,5 @@ signature: | --- Frees the memory allocated for options. -If the cm paramater doesn't contain any option it does nothing. +If the cm parameter doesn't contain any option it does nothing. diff --git a/docs/c-api/dns.h/mg_dns_encode_record.md b/docs/c-api/dns.h/mg_dns_encode_record.md index c52cf26f..7c9f2cf2 100644 --- a/docs/c-api/dns.h/mg_dns_encode_record.md +++ b/docs/c-api/dns.h/mg_dns_encode_record.md @@ -21,5 +21,5 @@ This function doesn't update the `name` and `rdata` pointers in the `rr` struct because they might be invalidated as soon as the IO buffer grows again. -Returns the number of bytes appened or -1 in case of error. +Returns the number of bytes appended or -1 in case of error. diff --git a/docs/c-api/http_server.h/mg_http_send_redirect.md b/docs/c-api/http_server.h/mg_http_send_redirect.md index 8d7d3b2e..00d704e0 100644 --- a/docs/c-api/http_server.h/mg_http_send_redirect.md +++ b/docs/c-api/http_server.h/mg_http_send_redirect.md @@ -12,7 +12,7 @@ Sends a redirect response. `status_code` should be either 301 or 302 and `location` point to the new location. If `extra_headers` is not empty, then `extra_headers` are also sent -after the reponse line. `extra_headers` must NOT end end with new line. +after the response line. `extra_headers` must NOT end end with new line. Example: diff --git a/docs/c-api/http_server.h/mg_send_response_line.md b/docs/c-api/http_server.h/mg_send_response_line.md index 4bd22639..5daa74fe 100644 --- a/docs/c-api/http_server.h/mg_send_response_line.md +++ b/docs/c-api/http_server.h/mg_send_response_line.md @@ -9,7 +9,7 @@ signature: | Sends the response status line. If `extra_headers` is not NULL, then `extra_headers` are also sent -after the reponse line. `extra_headers` must NOT end end with new line. +after the response line. `extra_headers` must NOT end end with new line. Example: mg_send_response_line(nc, 200, "Access-Control-Allow-Origin: *"); diff --git a/docs/c-api/net.h/mg_bind_opt.md b/docs/c-api/net.h/mg_bind_opt.md index a9cbf953..5fc46054 100644 --- a/docs/c-api/net.h/mg_bind_opt.md +++ b/docs/c-api/net.h/mg_bind_opt.md @@ -15,7 +15,7 @@ the same as for the `mg_connect()` call, where `HOST` part is optional. `address` can be just a port number, e.g. `:8000`. To bind to a specific interface, an IP address can be specified, e.g. `1.2.3.4:8000`. By default, a TCP connection is created. To create UDP connection, prepend `udp://` -prefix, e.g. `udp://:8000`. To summarize, `address` paramer has following +prefix, e.g. `udp://:8000`. To summarize, `address` parameter has following format: `[PROTO://][IP_ADDRESS]:PORT`, where `PROTO` could be `tcp` or `udp`. diff --git a/docs/c-api/net.h/mg_check_ip_acl.md b/docs/c-api/net.h/mg_check_ip_acl.md index e3087e2b..83c2c7ba 100644 --- a/docs/c-api/net.h/mg_check_ip_acl.md +++ b/docs/c-api/net.h/mg_check_ip_acl.md @@ -18,7 +18,7 @@ Subnet masks may vary from 0 to 32, inclusive. The default setting is to allow all access. On each request the full list is traversed, and the last match wins. Example: -`-0.0.0.0/0,+192.168/16` - deny all acccesses, only allow 192.168/16 subnet +`-0.0.0.0/0,+192.168/16` - deny all accesses, only allow 192.168/16 subnet To learn more about subnet masks, see this link:https://en.wikipedia.org/wiki/Subnetwork[Wikipedia page on Subnetwork]. diff --git a/docs/http/ssi.md b/docs/http/ssi.md index 2fcfbc4d..23c390e1 100644 --- a/docs/http/ssi.md +++ b/docs/http/ssi.md @@ -35,7 +35,7 @@ The exec directive is used to execute a command on a server, and show command's output. Example: `` The call directive is a way to invoke a C handler from the HTML page. -On each occurence of `` directive, +On each occurrence of `` directive, Mongoose calls a registered event handler with `MG_EV_SSI_CALL` event. Event parameter will point to the `PARAMS` string. An event handler can output any text, for example by calling diff --git a/mongoose.c b/mongoose.c index 5f84b7b1..8199252e 100644 --- a/mongoose.c +++ b/mongoose.c @@ -2342,7 +2342,7 @@ MG_INTERNAL struct mg_connection *mg_create_connection( * Address format: [PROTO://][HOST]:PORT * * HOST could be IPv4/IPv6 address or a host name. - * `host` is a destination buffer to hold parsed HOST part. Shoud be at least + * `host` is a destination buffer to hold parsed HOST part. Should be at least * MG_MAX_HOST_LEN bytes long. * `proto` is a returned socket type, either SOCK_STREAM or SOCK_DGRAM * @@ -13395,7 +13395,7 @@ time_t mg_sl_if_poll(struct mg_iface *iface, int timeout_ms) { (SL_FD_ISSET(nc->sock, &write_set) ? _MG_F_FD_CAN_WRITE : 0) | (SL_FD_ISSET(nc->sock, &err_set) ? _MG_F_FD_ERROR : 0); } - /* SimpleLink does not report UDP sockets as writeable. */ + /* SimpleLink does not report UDP sockets as writable. */ if (nc->flags & MG_F_UDP && nc->send_mbuf.len > 0) { fd_flags |= _MG_F_FD_CAN_WRITE; } @@ -13418,7 +13418,7 @@ time_t mg_sl_if_poll(struct mg_iface *iface, int timeout_ms) { void mg_sl_if_get_conn_addr(struct mg_connection *nc, int remote, union socket_address *sa) { /* SimpleLink does not provide a way to get socket's peer address after - * accept or connect. Address hould have been preserved in the connection, + * accept or connect. Address should have been preserved in the connection, * so we do our best here by using it. */ if (remote) memcpy(sa, &nc->sa, sizeof(*sa)); } diff --git a/mongoose.h b/mongoose.h index ab74b05a..192677ad 100644 --- a/mongoose.h +++ b/mongoose.h @@ -3235,7 +3235,7 @@ typedef void (*mg_event_handler_t)(struct mg_connection *nc, int ev, #define MG_EV_POLL 0 /* Sent to each connection on each mg_mgr_poll() call */ #define MG_EV_ACCEPT 1 /* New connection accepted. union socket_address * */ #define MG_EV_CONNECT 2 /* connect() succeeded or failed. int * */ -#define MG_EV_RECV 3 /* Data has benn received. int *num_bytes */ +#define MG_EV_RECV 3 /* Data has been received. int *num_bytes */ #define MG_EV_SEND 4 /* Data has been written to a socket. int *num_bytes */ #define MG_EV_CLOSE 5 /* Connection is closed. NULL */ #define MG_EV_TIMER 6 /* now >= conn->ev_timer_time. double * */ @@ -3495,7 +3495,7 @@ struct mg_connection *mg_bind(struct mg_mgr *, const char *, * `address` can be just a port number, e.g. `:8000`. To bind to a specific * interface, an IP address can be specified, e.g. `1.2.3.4:8000`. By default, * a TCP connection is created. To create UDP connection, prepend `udp://` - * prefix, e.g. `udp://:8000`. To summarize, `address` paramer has following + * prefix, e.g. `udp://:8000`. To summarize, `address` parameter has following * format: `[PROTO://][IP_ADDRESS]:PORT`, where `PROTO` could be `tcp` or * `udp`. * @@ -3701,7 +3701,7 @@ int mg_resolve(const char *domain_name, char *ip_addr_buf, size_t buf_len); * is to allow all access. On each request the full list is traversed, * and the last match wins. Example: * - * `-0.0.0.0/0,+192.168/16` - deny all acccesses, only allow 192.168/16 subnet + * `-0.0.0.0/0,+192.168/16` - deny all accesses, only allow 192.168/16 subnet * * To learn more about subnet masks, see this * link:https://en.wikipedia.org/wiki/Subnetwork[Wikipedia page on Subnetwork]. @@ -4794,7 +4794,7 @@ void mg_printf_http_chunk(struct mg_connection *nc, const char *fmt, ...); /* * Sends the response status line. * If `extra_headers` is not NULL, then `extra_headers` are also sent - * after the reponse line. `extra_headers` must NOT end end with new line. + * after the response line. `extra_headers` must NOT end end with new line. * Example: * * mg_send_response_line(nc, 200, "Access-Control-Allow-Origin: *"); @@ -4818,7 +4818,7 @@ void mg_http_send_error(struct mg_connection *nc, int code, const char *reason); * `status_code` should be either 301 or 302 and `location` point to the * new location. * If `extra_headers` is not empty, then `extra_headers` are also sent - * after the reponse line. `extra_headers` must NOT end end with new line. + * after the response line. `extra_headers` must NOT end end with new line. * * Example: * @@ -5392,7 +5392,7 @@ int mg_dns_copy_questions(struct mbuf *io, struct mg_dns_message *msg); * struct because they might be invalidated as soon as the IO buffer grows * again. * - * Returns the number of bytes appened or -1 in case of error. + * Returns the number of bytes appended or -1 in case of error. */ int mg_dns_encode_record(struct mbuf *io, struct mg_dns_resource_record *rr, const char *name, size_t nlen, const void *rdata, @@ -5730,7 +5730,7 @@ struct mg_coap_option *mg_coap_add_option(struct mg_coap_message *cm, /* * Frees the memory allocated for options. - * If the cm paramater doesn't contain any option it does nothing. + * If the cm parameter doesn't contain any option it does nothing. */ void mg_coap_free_options(struct mg_coap_message *cm); From d85d95a40bb3f11a0be6adc6da56f6ca31b37737 Mon Sep 17 00:00:00 2001 From: Alexander Alashkin Date: Wed, 1 Mar 2017 09:49:37 +0000 Subject: [PATCH 009/137] Fix potential out-of-bound PUBLISHED_FROM=71b40189bcedbe9338915c1aad939835125dad26 --- mongoose.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mongoose.c b/mongoose.c index 8199252e..914879e1 100644 --- a/mongoose.c +++ b/mongoose.c @@ -1136,7 +1136,7 @@ struct mg_str mg_mk_str_n(const char *s, size_t len) { int mg_vcmp(const struct mg_str *str1, const char *str2) WEAK; int mg_vcmp(const struct mg_str *str1, const char *str2) { size_t n2 = strlen(str2), n1 = str1->len; - int r = memcmp(str1->p, str2, (n1 < n2) ? n1 : n2); + int r = strncmp(str1->p, str2, (n1 < n2) ? n1 : n2); if (r == 0) { return n1 - n2; } From aed6d05d8c52345840379a0ca1a303da4eee5647 Mon Sep 17 00:00:00 2001 From: Alexander Alashkin Date: Wed, 1 Mar 2017 09:50:12 +0000 Subject: [PATCH 010/137] Do not test reassembled buffer for WS_OP_CLOSE PUBLISHED_FROM=0e8de208b553b63c8367f66893389587bd17359f --- mongoose.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/mongoose.c b/mongoose.c index 914879e1..e4c210e7 100644 --- a/mongoose.c +++ b/mongoose.c @@ -8888,8 +8888,8 @@ static int mg_deliver_websocket_data(struct mg_connection *nc) { mbuf_remove(&nc->recv_mbuf, (size_t) frame_len); /* Cleanup frame */ } - /* If client closes, close too */ - if ((buf[0] & 0x0f) == WEBSOCKET_OP_CLOSE) { + /* If the frame is not reassembled - client closes and close too */ + if (!reass && (buf[0] & 0x0f) == WEBSOCKET_OP_CLOSE) { nc->flags |= MG_F_SEND_AND_CLOSE; } } From 920e8d914567da18b64a6aa89542457ef0f911c2 Mon Sep 17 00:00:00 2001 From: Alexander Alashkin Date: Wed, 1 Mar 2017 09:50:46 +0000 Subject: [PATCH 011/137] Add shims for mongoose file operations PUBLISHED_FROM=b5b12cdf4273f21dbcdac9bfb6a06063152914c9 --- docs/c-api/util.h/intro.md | 2 ++ docs/c-api/util.h/mg_fread.md | 12 ++++++++++++ docs/c-api/util.h/mg_fwrite.md | 12 ++++++++++++ docs/overview/build-options/tunables.md | 1 + mongoose.c | 18 +++++++++++++----- mongoose.h | 15 +++++++++++++++ 6 files changed, 55 insertions(+), 5 deletions(-) create mode 100644 docs/c-api/util.h/mg_fread.md create mode 100644 docs/c-api/util.h/mg_fwrite.md diff --git a/docs/c-api/util.h/intro.md b/docs/c-api/util.h/intro.md index 9b30d680..4a390e48 100644 --- a/docs/c-api/util.h/intro.md +++ b/docs/c-api/util.h/intro.md @@ -8,6 +8,8 @@ items: - { name: mg_basic_auth_header.md } - { name: mg_conn_addr_to_str.md } - { name: mg_fopen.md } + - { name: mg_fread.md } + - { name: mg_fwrite.md } - { name: mg_hexdump.md } - { name: mg_hexdump_connection.md } - { name: mg_hexdumpf.md } diff --git a/docs/c-api/util.h/mg_fread.md b/docs/c-api/util.h/mg_fread.md new file mode 100644 index 00000000..0ff4994a --- /dev/null +++ b/docs/c-api/util.h/mg_fread.md @@ -0,0 +1,12 @@ +--- +title: "mg_fread()" +decl_name: "mg_fread" +symbol_kind: "func" +signature: | + size_t mg_fread(void *ptr, size_t size, size_t count, FILE *f); +--- + +Reads data from the given file stream. + +Return value is a number of bytes readen. + diff --git a/docs/c-api/util.h/mg_fwrite.md b/docs/c-api/util.h/mg_fwrite.md new file mode 100644 index 00000000..5ddbbbce --- /dev/null +++ b/docs/c-api/util.h/mg_fwrite.md @@ -0,0 +1,12 @@ +--- +title: "mg_fwrite()" +decl_name: "mg_fwrite" +symbol_kind: "func" +signature: | + size_t mg_fwrite(const void *ptr, size_t size, size_t count, FILE *f); +--- + +Writes data to the given file stream. + +Return value is a number of bytes wtitten. + diff --git a/docs/overview/build-options/tunables.md b/docs/overview/build-options/tunables.md index e1ca4c63..c9944c4c 100644 --- a/docs/overview/build-options/tunables.md +++ b/docs/overview/build-options/tunables.md @@ -9,3 +9,4 @@ title: Tunables - `MG_SSL_CRYPTO_MODERN`, `MG_SSL_CRYPTO_OLD` - choose either "Modern" or "Old" ciphers instead of the default "Intermediate" setting. See [this article](https://wiki.mozilla.org/Security/Server_Side_TLS#Recommended_configurations) for details. +- `MG_USER_FILE_FUNCTIONS` allow you to use custom file operation, by defining you own `mg_stat`, `mg_fopen`, `mg_open`, `mg_fread` and `mg_fwrite` functions \ No newline at end of file diff --git a/mongoose.c b/mongoose.c index e4c210e7..19c75e19 100644 --- a/mongoose.c +++ b/mongoose.c @@ -5374,7 +5374,7 @@ static void mg_http_transfer_file_data(struct mg_connection *nc) { if (to_read == 0) { /* Rate limiting. send_mbuf is too full, wait until it's drained. */ } else if (pd->file.sent < pd->file.cl && - (n = fread(buf, 1, to_read, pd->file.fp)) > 0) { + (n = mg_fread(buf, 1, to_read, pd->file.fp)) > 0) { mg_send(nc, buf, n); pd->file.sent += n; } else { @@ -5384,7 +5384,7 @@ static void mg_http_transfer_file_data(struct mg_connection *nc) { } else if (pd->file.type == DATA_PUT) { struct mbuf *io = &nc->recv_mbuf; size_t to_write = left <= 0 ? 0 : left < io->len ? (size_t) left : io->len; - size_t n = fwrite(io->buf, 1, to_write, pd->file.fp); + size_t n = mg_fwrite(io->buf, 1, to_write, pd->file.fp); if (n > 0) { mbuf_remove(io, n); pd->file.sent += n; @@ -7515,7 +7515,7 @@ void mg_file_upload_handler(struct mg_connection *nc, int ev, void *ev_data, struct file_upload_state *fus = (struct file_upload_state *) mp->user_data; if (fus == NULL || fus->fp == NULL) break; - if (fwrite(mp->data.p, 1, mp->data.len, fus->fp) != mp->data.len) { + if (mg_fwrite(mp->data.p, 1, mp->data.len, fus->fp) != mp->data.len) { LOG(LL_ERROR, ("Failed to write to %s: %d, wrote %d", fus->lfn, mg_get_errno(), (int) fus->num_recd)); if (mg_get_errno() == ENOSPC @@ -8328,7 +8328,7 @@ static void mg_send_ssi_file(struct mg_connection *nc, struct http_message *hm, static void mg_send_file_data(struct mg_connection *nc, FILE *fp) { char buf[BUFSIZ]; size_t n; - while ((n = fread(buf, 1, sizeof(buf), fp)) > 0) { + while ((n = mg_fread(buf, 1, sizeof(buf), fp)) > 0) { mg_send(nc, buf, n); } } @@ -9209,7 +9209,7 @@ static int lowercase(const char *s) { return tolower(*(const unsigned char *) s); } -#if MG_ENABLE_FILESYSTEM +#if MG_ENABLE_FILESYSTEM && !defined(MG_USER_FILE_FUNCTIONS) int mg_stat(const char *path, cs_stat_t *st) { #ifdef _WIN32 wchar_t wpath[MAX_PATH_SIZE]; @@ -9241,6 +9241,14 @@ int mg_open(const char *path, int flag, int mode) { /* LCOV_EXCL_LINE */ return open(path, flag, mode); /* LCOV_EXCL_LINE */ #endif } + +size_t mg_fread(void *ptr, size_t size, size_t count, FILE *f) { + return fread(ptr, size, count, f); +} + +size_t mg_fwrite(const void *ptr, size_t size, size_t count, FILE *f) { + return fwrite(ptr, size, count, f); +} #endif void mg_base64_encode(const unsigned char *src, int src_len, char *dst) { diff --git a/mongoose.h b/mongoose.h index 192677ad..45fab927 100644 --- a/mongoose.h +++ b/mongoose.h @@ -3898,6 +3898,21 @@ FILE *mg_fopen(const char *path, const char *mode); * Return value is the same as for the `open()` syscall. */ int mg_open(const char *path, int flag, int mode); + +/* + * Reads data from the given file stream. + * + * Return value is a number of bytes readen. + */ +size_t mg_fread(void *ptr, size_t size, size_t count, FILE *f); + +/* + * Writes data to the given file stream. + * + * Return value is a number of bytes wtitten. + */ +size_t mg_fwrite(const void *ptr, size_t size, size_t count, FILE *f); + #endif /* MG_ENABLE_FILESYSTEM */ #if MG_ENABLE_THREADS From 39a3bb7e44e29024b7da254884ff0817a412f8f5 Mon Sep 17 00:00:00 2001 From: Deomid Ryabkov Date: Thu, 2 Mar 2017 11:21:24 +0200 Subject: [PATCH 012/137] Log method and URI in mg_http_handler PUBLISHED_FROM=34c3e49d523b0f5c7056f91e4b422f21f5694df9 --- mongoose.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/mongoose.c b/mongoose.c index 19c75e19..4d74e142 100644 --- a/mongoose.c +++ b/mongoose.c @@ -5706,6 +5706,11 @@ void mg_http_handler(struct mg_connection *nc, int ev, void *ev_data) { #endif /* MG_ENABLE_HTTP_WEBSOCKET */ else if (hm->message.len <= io->len) { int trigger_ev = nc->listener ? MG_EV_HTTP_REQUEST : MG_EV_HTTP_REPLY; + char addr[32]; + mg_sock_addr_to_str(&nc->sa, addr, sizeof(addr), + MG_SOCK_STRINGIFY_IP | MG_SOCK_STRINGIFY_PORT); + DBG(("%p %s %.*s %.*s", nc, addr, (int) hm->method.len, hm->method.p, + (int) hm->uri.len, hm->uri.p)); /* Whole HTTP message is fully buffered, call event handler */ From 38efe632aeac2ba367f410adc0bda0f102018f0a Mon Sep 17 00:00:00 2001 From: Sergey Lyubka Date: Mon, 6 Mar 2017 21:43:03 +0000 Subject: [PATCH 013/137] Squash warning PUBLISHED_FROM=72d80f8ed2c10866b44d56d8133c76b22bc105b0 --- mongoose.c | 1 + 1 file changed, 1 insertion(+) diff --git a/mongoose.c b/mongoose.c index 4d74e142..1ba3440d 100644 --- a/mongoose.c +++ b/mongoose.c @@ -274,6 +274,7 @@ void cs_log_printf(const char *fmt, ...); #include #include +#include /* Amalgamated: #include "common/cs_time.h" */ From 49ca223e9cb7c724decf1e8e1bf41dd725684c0b Mon Sep 17 00:00:00 2001 From: Deomid Ryabkov Date: Tue, 7 Mar 2017 19:04:58 +0200 Subject: [PATCH 014/137] Minor memory optimization Release pbuf sooner: after copying data from, before invoking user code PUBLISHED_FROM=b877c96ef602bbca26762b18b9dde17eb880d1f9 --- mongoose.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/mongoose.c b/mongoose.c index 1ba3440d..4dadab9b 100644 --- a/mongoose.c +++ b/mongoose.c @@ -13928,15 +13928,15 @@ static void mg_lwip_handle_recv_tcp(struct mg_connection *nc) { return; } pbuf_copy_partial(seg, data, len, cs->rx_offset); - mgos_unlock(); - mg_if_recv_tcp_cb(nc, data, len, 1 /* own */); - mgos_lock(); 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(); From 16700244b0e930187953d44a8f3e7671eeeab94a Mon Sep 17 00:00:00 2001 From: Deomid Ryabkov Date: Tue, 7 Mar 2017 23:35:22 +0000 Subject: [PATCH 015/137] Fix parsing of MQTT QoS > 0 PUBLISH messages Message ID comes after topic, not before. PUBLISHED_FROM=1ec2a56e290b67061b18c745671dc7f089b9cc0d --- mongoose.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/mongoose.c b/mongoose.c index 4dadab9b..26c15baa 100644 --- a/mongoose.c +++ b/mongoose.c @@ -9667,12 +9667,11 @@ MG_INTERNAL int parse_mqtt(struct mbuf *io, struct mg_mqtt_message *mm) { mm->message_id = getu16(p); break; case MG_MQTT_CMD_PUBLISH: { - if (MG_MQTT_GET_QOS(header) > 0) { + p = scanto(p, &mm->topic); + if (mm->qos > 0) { mm->message_id = getu16(p); p += 2; } - p = scanto(p, &mm->topic); - mm->payload.p = p; mm->payload.len = end - p; break; From 08353731ef55c40cfbb1310d361602882ba94f41 Mon Sep 17 00:00:00 2001 From: Deomid Ryabkov Date: Wed, 8 Mar 2017 00:05:12 +0000 Subject: [PATCH 016/137] Fix MQTT PUB{ACK,REC,REL,COMP} and UNSUBACK flags Flags should be 0 for all of these, except PUBREL (flags = 2). PUBLISHED_FROM=46bf63fe12020d4cb493e52ceb3bae0291484b40 --- mongoose.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/mongoose.c b/mongoose.c index 26c15baa..3f7534f8 100644 --- a/mongoose.c +++ b/mongoose.c @@ -9933,8 +9933,9 @@ 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); + uint8_t flags = (cmd == MG_MQTT_CMD_PUBREL ? 2 : 0); mg_send(nc, &message_id_net, 2); - mg_mqtt_prepend_header(nc, cmd, MG_MQTT_QOS(1), 2); + mg_mqtt_prepend_header(nc, cmd, flags, 2 /* len */); } void mg_mqtt_puback(struct mg_connection *nc, uint16_t message_id) { From d3a8862bd8ba87c7a48819a93ff14524fbb9fe06 Mon Sep 17 00:00:00 2001 From: Deomid Ryabkov Date: Sat, 11 Mar 2017 02:03:01 +0200 Subject: [PATCH 017/137] Make interface vtables const Frees up a bit of ram on ESP PUBLISHED_FROM=0ea046cc63704481bca138b3096937669b94733d --- docs/c-api/net.h/struct_mg_mgr_init_opts.md | 4 +-- mongoose.c | 40 ++++++++++----------- mongoose.h | 12 +++---- 3 files changed, 28 insertions(+), 28 deletions(-) diff --git a/docs/c-api/net.h/struct_mg_mgr_init_opts.md b/docs/c-api/net.h/struct_mg_mgr_init_opts.md index da3e4951..c0b65816 100644 --- a/docs/c-api/net.h/struct_mg_mgr_init_opts.md +++ b/docs/c-api/net.h/struct_mg_mgr_init_opts.md @@ -4,9 +4,9 @@ decl_name: "struct mg_mgr_init_opts" symbol_kind: "struct" signature: | struct mg_mgr_init_opts { - struct mg_iface_vtable *main_iface; + const struct mg_iface_vtable *main_iface; int num_ifaces; - struct mg_iface_vtable **ifaces; + const struct mg_iface_vtable **ifaces; }; --- diff --git a/mongoose.c b/mongoose.c index 3f7534f8..91dc8b9f 100644 --- a/mongoose.c +++ b/mongoose.c @@ -2975,7 +2975,7 @@ extern "C" { #define MG_ENABLE_NET_IF_SOCKET MG_NET_IF == MG_NET_IF_SOCKET #endif -extern struct mg_iface_vtable mg_socket_iface_vtable; +extern const struct mg_iface_vtable mg_socket_iface_vtable; #ifdef __cplusplus } @@ -3003,7 +3003,7 @@ struct mg_tun_client; extern "C" { #endif /* __cplusplus */ -extern struct mg_iface_vtable mg_tun_iface_vtable; +extern const struct mg_iface_vtable mg_tun_iface_vtable; struct mg_connection *mg_tun_if_find_conn(struct mg_tun_client *client, uint32_t stream_id); @@ -3023,18 +3023,18 @@ struct mg_connection *mg_tun_if_find_conn(struct mg_tun_client *client, /* Amalgamated: #include "mongoose/src/net_if_socket.h" */ /* Amalgamated: #include "mongoose/src/net_if_tun.h" */ -extern struct mg_iface_vtable mg_default_iface_vtable; +extern const struct mg_iface_vtable mg_default_iface_vtable; #if MG_ENABLE_TUN -struct mg_iface_vtable *mg_ifaces[] = {&mg_default_iface_vtable, - &mg_tun_iface_vtable}; +const struct mg_iface_vtable *mg_ifaces[] = {&mg_default_iface_vtable, + &mg_tun_iface_vtable}; #else -struct mg_iface_vtable *mg_ifaces[] = {&mg_default_iface_vtable}; +const struct mg_iface_vtable *mg_ifaces[] = {&mg_default_iface_vtable}; #endif int mg_num_ifaces = (int) (sizeof(mg_ifaces) / sizeof(mg_ifaces[0])); -struct mg_iface *mg_if_create_iface(struct mg_iface_vtable *vtable, +struct mg_iface *mg_if_create_iface(const struct mg_iface_vtable *vtable, struct mg_mgr *mgr) { struct mg_iface *iface = (struct mg_iface *) MG_CALLOC(1, sizeof(*iface)); iface->mgr = mgr; @@ -3044,7 +3044,7 @@ struct mg_iface *mg_if_create_iface(struct mg_iface_vtable *vtable, } struct mg_iface *mg_find_iface(struct mg_mgr *mgr, - struct mg_iface_vtable *vtable, + const struct mg_iface_vtable *vtable, struct mg_iface *from) { int i = 0; if (from != NULL) { @@ -3790,9 +3790,9 @@ void mg_socket_if_get_conn_addr(struct mg_connection *nc, int remote, } /* clang-format on */ -struct mg_iface_vtable mg_socket_iface_vtable = MG_SOCKET_IFACE_VTABLE; +const struct mg_iface_vtable mg_socket_iface_vtable = MG_SOCKET_IFACE_VTABLE; #if MG_NET_IF == MG_NET_IF_SOCKET -struct mg_iface_vtable mg_default_iface_vtable = MG_SOCKET_IFACE_VTABLE; +const struct mg_iface_vtable mg_default_iface_vtable = MG_SOCKET_IFACE_VTABLE; #endif #endif /* MG_ENABLE_NET_IF_SOCKET */ @@ -3966,7 +3966,7 @@ struct mg_connection *mg_tun_if_find_conn(struct mg_tun_client *client, } /* clang-format on */ -struct mg_iface_vtable mg_tun_iface_vtable = MG_TUN_IFACE_VTABLE; +const struct mg_iface_vtable mg_tun_iface_vtable = MG_TUN_IFACE_VTABLE; #endif /* MG_ENABLE_TUN */ #ifdef MG_MODULE_LINES @@ -13012,7 +13012,7 @@ extern "C" { #define MG_ENABLE_NET_IF_SIMPLELINK MG_NET_IF == MG_NET_IF_SIMPLELINK #endif -extern struct mg_iface_vtable mg_simplelink_iface_vtable; +extern const struct mg_iface_vtable mg_simplelink_iface_vtable; #ifdef __cplusplus } @@ -13484,9 +13484,9 @@ void sl_restart_cb(struct mg_mgr *mgr) { } /* clang-format on */ -struct mg_iface_vtable mg_simplelink_iface_vtable = MG_SL_IFACE_VTABLE; +const struct mg_iface_vtable mg_simplelink_iface_vtable = MG_SL_IFACE_VTABLE; #if MG_NET_IF == MG_NET_IF_SIMPLELINK -struct mg_iface_vtable mg_default_iface_vtable = MG_SL_IFACE_VTABLE; +const struct mg_iface_vtable mg_default_iface_vtable = MG_SL_IFACE_VTABLE; #endif #endif /* MG_ENABLE_NET_IF_SIMPLELINK */ @@ -13706,7 +13706,7 @@ int sl_set_ssl_opts(struct mg_connection *nc) { #include -extern struct mg_iface_vtable mg_lwip_iface_vtable; +extern const struct mg_iface_vtable mg_lwip_iface_vtable; struct mg_lwip_conn_state { struct mg_connection *nc; @@ -14355,9 +14355,9 @@ void mg_lwip_if_sock_set(struct mg_connection *nc, sock_t sock) { } /* clang-format on */ -struct mg_iface_vtable mg_lwip_iface_vtable = MG_LWIP_IFACE_VTABLE; +const struct mg_iface_vtable mg_lwip_iface_vtable = MG_LWIP_IFACE_VTABLE; #if MG_NET_IF == MG_NET_IF_LWIP_LOW_LEVEL -struct mg_iface_vtable mg_default_iface_vtable = MG_LWIP_IFACE_VTABLE; +const struct mg_iface_vtable mg_default_iface_vtable = MG_LWIP_IFACE_VTABLE; #endif #endif /* MG_ENABLE_NET_IF_LWIP_LOW_LEVEL */ @@ -14902,7 +14902,7 @@ extern "C" { #define MG_ENABLE_NET_IF_PIC32 MG_NET_IF == MG_NET_IF_PIC32 #endif -extern struct mg_iface_vtable mg_pic32_iface_vtable; +extern const struct mg_iface_vtable mg_pic32_iface_vtable; #ifdef __cplusplus } @@ -15201,9 +15201,9 @@ void mg_pic32_if_connect_udp(struct mg_connection *nc) { } /* clang-format on */ -struct mg_iface_vtable mg_pic32_iface_vtable = MG_PIC32_IFACE_VTABLE; +const struct mg_iface_vtable mg_pic32_iface_vtable = MG_PIC32_IFACE_VTABLE; #if MG_NET_IF == MG_NET_IF_PIC32 -struct mg_iface_vtable mg_default_iface_vtable = MG_PIC32_IFACE_VTABLE; +const struct mg_iface_vtable mg_default_iface_vtable = MG_PIC32_IFACE_VTABLE; #endif #endif /* MG_ENABLE_NET_IF_PIC32 */ diff --git a/mongoose.h b/mongoose.h index 45fab927..0812f9a5 100644 --- a/mongoose.h +++ b/mongoose.h @@ -3002,7 +3002,7 @@ struct mg_iface_vtable; struct mg_iface { struct mg_mgr *mgr; void *data; /* Implementation-specific data */ - struct mg_iface_vtable *vtable; + const struct mg_iface_vtable *vtable; }; struct mg_iface_vtable { @@ -3041,11 +3041,11 @@ struct mg_iface_vtable { union socket_address *sa); }; -extern struct mg_iface_vtable *mg_ifaces[]; +extern const struct mg_iface_vtable *mg_ifaces[]; extern int mg_num_ifaces; /* Creates a new interface instance. */ -struct mg_iface *mg_if_create_iface(struct mg_iface_vtable *vtable, +struct mg_iface *mg_if_create_iface(const struct mg_iface_vtable *vtable, struct mg_mgr *mgr); /* @@ -3053,7 +3053,7 @@ struct mg_iface *mg_if_create_iface(struct mg_iface_vtable *vtable, * interface `from`, exclusive. Returns NULL if none is found. */ struct mg_iface *mg_find_iface(struct mg_mgr *mgr, - struct mg_iface_vtable *vtable, + const struct mg_iface_vtable *vtable, struct mg_iface *from); /* * Deliver a new TCP connection. Returns NULL in case on error (unable to @@ -3348,9 +3348,9 @@ void mg_mgr_init(struct mg_mgr *mgr, void *user_data); * `num_ifaces` pointers it contains will be reclaimed by `mg_mgr_free`. */ struct mg_mgr_init_opts { - struct mg_iface_vtable *main_iface; + const struct mg_iface_vtable *main_iface; int num_ifaces; - struct mg_iface_vtable **ifaces; + const struct mg_iface_vtable **ifaces; }; /* From c416012f9702794c33d29ecc2445ac6e828f2aef Mon Sep 17 00:00:00 2001 From: Deomid Ryabkov Date: Mon, 13 Mar 2017 19:46:44 +0200 Subject: [PATCH 018/137] MGOS SNTP support for ESP8266 and ESP32 PUBLISHED_FROM=8e07541e7a3b951dcfd08381b46f6143773eae45 --- mongoose.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mongoose.c b/mongoose.c index 91dc8b9f..926fd574 100644 --- a/mongoose.c +++ b/mongoose.c @@ -11845,7 +11845,7 @@ void mg_sntp_send_request(struct mg_connection *c) { */ #ifndef MG_SNMP_NO_DELAY_CORRECTION uint32_t sec; - sec = htonl(mg_time() + SNTP_TIME_OFFSET); + sec = htonl((uint32_t)(mg_time() + SNTP_TIME_OFFSET)); memcpy(&buf[40], &sec, sizeof(sec)); #endif From 0fc3370859365deddc8b0f757b68e94ea6ddbc48 Mon Sep 17 00:00:00 2001 From: Dmitry Frank Date: Wed, 15 Mar 2017 02:37:45 +0200 Subject: [PATCH 019/137] First step towards separate userdata argument PUBLISHED_FROM=93fe1cc2c5e2513509511a81e5919cbd37056b10 --- docs/c-api/http.h/mg_connect_ws.md | 5 +- docs/c-api/http.h/mg_connect_ws_opt.md | 7 +- docs/c-api/http_client.h/mg_connect_http.md | 8 +- .../http_client.h/mg_connect_http_opt.md | 8 +- .../http_server.h/mg_file_upload_handler.md | 3 +- docs/c-api/net.h/mg_add_sock.md | 4 +- docs/c-api/net.h/mg_add_sock_opt.md | 6 +- docs/c-api/net.h/mg_bind.md | 5 +- docs/c-api/net.h/mg_bind_opt.md | 4 +- docs/c-api/net.h/mg_broadcast.md | 3 +- docs/c-api/net.h/mg_connect.md | 3 +- docs/c-api/net.h/mg_connect_opt.md | 4 +- docs/c-api/net.h/mg_event_handler_t.md | 2 +- docs/c-api/net.h/mg_next.md | 2 +- mongoose.c | 254 +++++++++++------- mongoose.h | 81 +++--- 16 files changed, 241 insertions(+), 158 deletions(-) diff --git a/docs/c-api/http.h/mg_connect_ws.md b/docs/c-api/http.h/mg_connect_ws.md index b0f38d74..7a5b517d 100644 --- a/docs/c-api/http.h/mg_connect_ws.md +++ b/docs/c-api/http.h/mg_connect_ws.md @@ -4,9 +4,8 @@ decl_name: "mg_connect_ws" symbol_kind: "func" signature: | struct mg_connection *mg_connect_ws(struct mg_mgr *mgr, - mg_event_handler_t event_handler, - const char *url, const char *protocol, - const char *extra_headers); + MG_CB(mg_event_handler_t event_handler, + void *user_data); --- Helper function that creates an outbound WebSocket connection. diff --git a/docs/c-api/http.h/mg_connect_ws_opt.md b/docs/c-api/http.h/mg_connect_ws_opt.md index 57956ddb..e2203cff 100644 --- a/docs/c-api/http.h/mg_connect_ws_opt.md +++ b/docs/c-api/http.h/mg_connect_ws_opt.md @@ -3,11 +3,8 @@ title: "mg_connect_ws_opt()" decl_name: "mg_connect_ws_opt" symbol_kind: "func" signature: | - struct mg_connection *mg_connect_ws_opt(struct mg_mgr *mgr, - mg_event_handler_t ev_handler, - struct mg_connect_opts opts, - const char *url, const char *protocol, - const char *extra_headers); + struct mg_connection *mg_connect_ws_opt( + struct mg_mgr *mgr, MG_CB(mg_event_handler_t ev_handler, void *user_data); --- Helper function that creates an outbound WebSocket connection diff --git a/docs/c-api/http_client.h/mg_connect_http.md b/docs/c-api/http_client.h/mg_connect_http.md index fcf5f046..4664fcd9 100644 --- a/docs/c-api/http_client.h/mg_connect_http.md +++ b/docs/c-api/http_client.h/mg_connect_http.md @@ -3,11 +3,9 @@ title: "mg_connect_http()" decl_name: "mg_connect_http" symbol_kind: "func" signature: | - struct mg_connection *mg_connect_http(struct mg_mgr *mgr, - mg_event_handler_t event_handler, - const char *url, - const char *extra_headers, - const char *post_data); + struct mg_connection *mg_connect_http( + struct mg_mgr *mgr, + MG_CB(mg_event_handler_t event_handler, void *user_data); --- Helper function that creates an outbound HTTP connection. diff --git a/docs/c-api/http_client.h/mg_connect_http_opt.md b/docs/c-api/http_client.h/mg_connect_http_opt.md index 2454cb10..29df1d75 100644 --- a/docs/c-api/http_client.h/mg_connect_http_opt.md +++ b/docs/c-api/http_client.h/mg_connect_http_opt.md @@ -3,12 +3,8 @@ title: "mg_connect_http_opt()" decl_name: "mg_connect_http_opt" symbol_kind: "func" signature: | - struct mg_connection *mg_connect_http_opt(struct mg_mgr *mgr, - mg_event_handler_t ev_handler, - struct mg_connect_opts opts, - const char *url, - const char *extra_headers, - const char *post_data); + struct mg_connection *mg_connect_http_opt( + struct mg_mgr *mgr, MG_CB(mg_event_handler_t ev_handler, void *user_data); --- Helper function that creates an outbound HTTP connection. diff --git a/docs/c-api/http_server.h/mg_file_upload_handler.md b/docs/c-api/http_server.h/mg_file_upload_handler.md index 444c106f..a2c9e016 100644 --- a/docs/c-api/http_server.h/mg_file_upload_handler.md +++ b/docs/c-api/http_server.h/mg_file_upload_handler.md @@ -4,7 +4,8 @@ decl_name: "mg_file_upload_handler" symbol_kind: "func" signature: | void mg_file_upload_handler(struct mg_connection *nc, int ev, void *ev_data, - mg_fu_fname_fn local_name_fn); + mg_fu_fname_fn local_name_fn + MG_UD_ARG(void *user_data); --- File upload handler. diff --git a/docs/c-api/net.h/mg_add_sock.md b/docs/c-api/net.h/mg_add_sock.md index 511ae841..e63ce2e4 100644 --- a/docs/c-api/net.h/mg_add_sock.md +++ b/docs/c-api/net.h/mg_add_sock.md @@ -3,7 +3,9 @@ title: "mg_add_sock()" decl_name: "mg_add_sock" symbol_kind: "func" signature: | - struct mg_connection *mg_add_sock(struct mg_mgr *, sock_t, mg_event_handler_t); + struct mg_connection *mg_add_sock(struct mg_mgr *mgr, sock_t sock, + MG_CB(mg_event_handler_t handler, + void *user_data); --- Creates a connection, associates it with the given socket and event handler diff --git a/docs/c-api/net.h/mg_add_sock_opt.md b/docs/c-api/net.h/mg_add_sock_opt.md index 678a91cb..de2a22e9 100644 --- a/docs/c-api/net.h/mg_add_sock_opt.md +++ b/docs/c-api/net.h/mg_add_sock_opt.md @@ -3,9 +3,9 @@ title: "mg_add_sock_opt()" decl_name: "mg_add_sock_opt" symbol_kind: "func" signature: | - struct mg_connection *mg_add_sock_opt(struct mg_mgr *, sock_t, - mg_event_handler_t, - struct mg_add_sock_opts); + struct mg_connection *mg_add_sock_opt(struct mg_mgr *mgr, sock_t sock, + MG_CB(mg_event_handler_t handler, + void *user_data); --- Creates a connection, associates it with the given socket and event handler diff --git a/docs/c-api/net.h/mg_bind.md b/docs/c-api/net.h/mg_bind.md index 800bba95..9507d51c 100644 --- a/docs/c-api/net.h/mg_bind.md +++ b/docs/c-api/net.h/mg_bind.md @@ -3,8 +3,9 @@ title: "mg_bind()" decl_name: "mg_bind" symbol_kind: "func" signature: | - struct mg_connection *mg_bind(struct mg_mgr *, const char *, - mg_event_handler_t); + struct mg_connection *mg_bind(struct mg_mgr *mgr, const char *address, + MG_CB(mg_event_handler_t handler, + void *user_data); --- Creates a listening connection. diff --git a/docs/c-api/net.h/mg_bind_opt.md b/docs/c-api/net.h/mg_bind_opt.md index 5fc46054..823dd0c0 100644 --- a/docs/c-api/net.h/mg_bind_opt.md +++ b/docs/c-api/net.h/mg_bind_opt.md @@ -4,8 +4,8 @@ decl_name: "mg_bind_opt" symbol_kind: "func" signature: | struct mg_connection *mg_bind_opt(struct mg_mgr *mgr, const char *address, - mg_event_handler_t handler, - struct mg_bind_opts opts); + MG_CB(mg_event_handler_t handler, + void *user_data); --- Creates a listening connection. diff --git a/docs/c-api/net.h/mg_broadcast.md b/docs/c-api/net.h/mg_broadcast.md index 4eda7f3c..cef0b379 100644 --- a/docs/c-api/net.h/mg_broadcast.md +++ b/docs/c-api/net.h/mg_broadcast.md @@ -3,7 +3,8 @@ title: "mg_broadcast()" decl_name: "mg_broadcast" symbol_kind: "func" signature: | - void mg_broadcast(struct mg_mgr *, mg_event_handler_t func, void *, size_t); + void mg_broadcast(struct mg_mgr *mgr, mg_event_handler_t cb, void *data, + size_t len); --- Passes a message of a given length to all connections. diff --git a/docs/c-api/net.h/mg_connect.md b/docs/c-api/net.h/mg_connect.md index bbacd8f4..788be84e 100644 --- a/docs/c-api/net.h/mg_connect.md +++ b/docs/c-api/net.h/mg_connect.md @@ -4,7 +4,8 @@ decl_name: "mg_connect" symbol_kind: "func" signature: | struct mg_connection *mg_connect(struct mg_mgr *mgr, const char *address, - mg_event_handler_t handler); + MG_CB(mg_event_handler_t handler, + void *user_data); --- Connects to a remote host. diff --git a/docs/c-api/net.h/mg_connect_opt.md b/docs/c-api/net.h/mg_connect_opt.md index de7e7139..3ae818a4 100644 --- a/docs/c-api/net.h/mg_connect_opt.md +++ b/docs/c-api/net.h/mg_connect_opt.md @@ -4,8 +4,8 @@ decl_name: "mg_connect_opt" symbol_kind: "func" signature: | struct mg_connection *mg_connect_opt(struct mg_mgr *mgr, const char *address, - mg_event_handler_t handler, - struct mg_connect_opts opts); + MG_CB(mg_event_handler_t handler, + void *user_data); --- Connects to a remote host. diff --git a/docs/c-api/net.h/mg_event_handler_t.md b/docs/c-api/net.h/mg_event_handler_t.md index 191805c8..5a482224 100644 --- a/docs/c-api/net.h/mg_event_handler_t.md +++ b/docs/c-api/net.h/mg_event_handler_t.md @@ -4,7 +4,7 @@ decl_name: "mg_event_handler_t" symbol_kind: "typedef" signature: | typedef void (*mg_event_handler_t)(struct mg_connection *nc, int ev, - void *ev_data); + void *ev_data MG_UD_ARG(void *user_data)); --- Callback function (event handler) prototype. Must be defined by the user. diff --git a/docs/c-api/net.h/mg_next.md b/docs/c-api/net.h/mg_next.md index fcd5e1d1..423af6fd 100644 --- a/docs/c-api/net.h/mg_next.md +++ b/docs/c-api/net.h/mg_next.md @@ -3,7 +3,7 @@ title: "mg_next()" decl_name: "mg_next" symbol_kind: "func" signature: | - struct mg_connection *mg_next(struct mg_mgr *, struct mg_connection *); + struct mg_connection *mg_next(struct mg_mgr *mgr, struct mg_connection *c); --- Iterates over all active connections. diff --git a/mongoose.c b/mongoose.c index 926fd574..a694cd51 100644 --- a/mongoose.c +++ b/mongoose.c @@ -155,7 +155,8 @@ MG_INTERNAL void mg_handle_put(struct mg_connection *nc, const char *path, struct http_message *hm); #endif #if MG_ENABLE_HTTP_WEBSOCKET -MG_INTERNAL void mg_ws_handler(struct mg_connection *nc, int ev, void *ev_data); +MG_INTERNAL void mg_ws_handler(struct mg_connection *nc, int ev, + void *ev_data MG_UD_ARG(void *user_data)); MG_INTERNAL void mg_ws_handshake(struct mg_connection *nc, const struct mg_str *key); #endif @@ -1934,7 +1935,8 @@ extern "C" { struct mg_connection *mg_tun_bind_opt(struct mg_mgr *mgr, const char *dispatcher, - mg_event_handler_t handler, + MG_CB(mg_event_handler_t handler, + void *user_data), struct mg_bind_opts opts); int mg_tun_parse_frame(void *data, size_t len, struct mg_tun_frame *frame); @@ -2049,7 +2051,7 @@ MG_INTERNAL void mg_call(struct mg_connection *nc, 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); + ev_handler(nc, ev, ev_data MG_UD_ARG(nc->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) { @@ -2643,14 +2645,16 @@ static void resolve_cb(struct mg_dns_message *msg, void *data, #endif struct mg_connection *mg_connect(struct mg_mgr *mgr, const char *address, - mg_event_handler_t callback) { + MG_CB(mg_event_handler_t callback, + void *user_data)) { struct mg_connect_opts opts; memset(&opts, 0, sizeof(opts)); - return mg_connect_opt(mgr, address, callback, opts); + return mg_connect_opt(mgr, address, MG_CB(callback, user_data), opts); } struct mg_connection *mg_connect_opt(struct mg_mgr *mgr, const char *address, - mg_event_handler_t callback, + MG_CB(mg_event_handler_t callback, + void *user_data), struct mg_connect_opts opts) { struct mg_connection *nc = NULL; int proto, rc; @@ -2673,7 +2677,11 @@ struct mg_connection *mg_connect_opt(struct mg_mgr *mgr, const char *address, nc->flags |= opts.flags & _MG_ALLOWED_CONNECT_FLAGS_MASK; nc->flags |= (proto == SOCK_DGRAM) ? MG_F_UDP : 0; +#if MG_ENABLE_CALLBACK_USERDATA + nc->user_data = user_data; +#else nc->user_data = opts.user_data; +#endif #if MG_ENABLE_SSL DBG(("%p %s %s,%s,%s", nc, address, (opts.ssl_cert ? opts.ssl_cert : "-"), @@ -2745,14 +2753,16 @@ struct mg_connection *mg_connect_opt(struct mg_mgr *mgr, const char *address, } struct mg_connection *mg_bind(struct mg_mgr *srv, const char *address, - mg_event_handler_t event_handler) { + MG_CB(mg_event_handler_t event_handler, + void *user_data)) { struct mg_bind_opts opts; memset(&opts, 0, sizeof(opts)); - return mg_bind_opt(srv, address, event_handler, opts); + return mg_bind_opt(srv, address, MG_CB(event_handler, user_data), opts); } struct mg_connection *mg_bind_opt(struct mg_mgr *mgr, const char *address, - mg_event_handler_t callback, + MG_CB(mg_event_handler_t callback, + void *user_data), struct mg_bind_opts opts) { union socket_address sa; struct mg_connection *nc = NULL; @@ -2765,7 +2775,7 @@ struct mg_connection *mg_bind_opt(struct mg_mgr *mgr, const char *address, #if MG_ENABLE_TUN if (mg_strncmp(mg_mk_str(address), mg_mk_str("ws://"), 5) == 0 || mg_strncmp(mg_mk_str(address), mg_mk_str("wss://"), 6) == 0) { - return mg_tun_bind_opt(mgr, address, callback, opts); + return mg_tun_bind_opt(mgr, address, MG_CB(callback, user_data), opts); } #endif @@ -2823,6 +2833,9 @@ struct mg_connection *mg_bind_opt(struct mg_mgr *mgr, const char *address, } mg_add_conn(nc->mgr, nc); +#if MG_ENABLE_CALLBACK_USERDATA + (void) user_data; +#endif return nc; } @@ -2934,8 +2947,13 @@ void mg_if_get_conn_addr(struct mg_connection *nc, int remote, } struct mg_connection *mg_add_sock_opt(struct mg_mgr *s, sock_t sock, - mg_event_handler_t callback, + MG_CB(mg_event_handler_t callback, + void *user_data), struct mg_add_sock_opts opts) { +#if MG_ENABLE_CALLBACK_USERDATA + opts.user_data = user_data; +#endif + struct mg_connection *nc = mg_create_connection_base(s, callback, opts); if (nc != NULL) { mg_sock_set(nc, sock); @@ -2945,10 +2963,11 @@ struct mg_connection *mg_add_sock_opt(struct mg_mgr *s, sock_t sock, } struct mg_connection *mg_add_sock(struct mg_mgr *s, sock_t sock, - mg_event_handler_t callback) { + MG_CB(mg_event_handler_t callback, + void *user_data)) { struct mg_add_sock_opts opts; memset(&opts, 0, sizeof(opts)); - return mg_add_sock_opt(s, sock, callback, opts); + return mg_add_sock_opt(s, sock, MG_CB(callback, user_data), opts); } double mg_time(void) { @@ -3525,7 +3544,8 @@ static void mg_mgr_handle_ctl_sock(struct mg_mgr *mgr) { if (len >= (int) sizeof(ctl_msg.callback) && ctl_msg.callback != NULL) { struct mg_connection *nc; for (nc = mg_next(mgr, NULL); nc != NULL; nc = mg_next(mgr, nc)) { - ctl_msg.callback(nc, MG_EV_POLL, ctl_msg.message); + ctl_msg.callback(nc, MG_EV_POLL, + ctl_msg.message MG_UD_ARG(nc->user_data)); } } } @@ -5046,7 +5066,7 @@ struct mg_http_proto_data { static void mg_http_conn_destructor(void *proto_data); struct mg_connection *mg_connect_http_base( - struct mg_mgr *mgr, mg_event_handler_t ev_handler, + struct mg_mgr *mgr, MG_CB(mg_event_handler_t ev_handler, void *user_data), struct mg_connect_opts opts, const char *schema, const char *schema_ssl, const char *url, const char **path, char **user, char **pass, char **addr); @@ -5561,18 +5581,22 @@ static void mg_http_multipart_begin(struct mg_connection *nc, * even bigger (round up to 4k, from 700 bytes of actual size). */ #ifdef __xtensa__ -static void mg_http_handler2(struct mg_connection *nc, int ev, void *ev_data, +static void mg_http_handler2(struct mg_connection *nc, int ev, + void *ev_data MG_UD_ARG(void *user_data), struct http_message *hm) __attribute__((noinline)); -void mg_http_handler(struct mg_connection *nc, int ev, void *ev_data) { +void mg_http_handler(struct mg_connection *nc, int ev, + void *ev_data MG_UD_ARG(void *user_data)) { struct http_message hm; - mg_http_handler2(nc, ev, ev_data, &hm); + mg_http_handler2(nc, ev, ev_data MG_UD_ARG(user_data), &hm); } -static void mg_http_handler2(struct mg_connection *nc, int ev, void *ev_data, +static void mg_http_handler2(struct mg_connection *nc, int ev, + void *ev_data MG_UD_ARG(void *user_data), struct http_message *hm) { #else /* !__XTENSA__ */ -void mg_http_handler(struct mg_connection *nc, int ev, void *ev_data) { +void mg_http_handler(struct mg_connection *nc, int ev, + void *ev_data MG_UD_ARG(void *user_data)) { struct http_message shm; struct http_message *hm = &shm; #endif /* __XTENSA__ */ @@ -5674,7 +5698,7 @@ void mg_http_handler(struct mg_connection *nc, int ev, void *ev_data) { nc->proto_handler = mg_ws_handler; nc->flags |= MG_F_IS_WEBSOCKET; mg_call(nc, nc->handler, MG_EV_WEBSOCKET_HANDSHAKE_DONE, NULL); - mg_ws_handler(nc, MG_EV_RECV, ev_data); + mg_ws_handler(nc, MG_EV_RECV, ev_data MG_UD_ARG(user_data)); } else if (nc->listener != NULL && (vec = mg_get_http_header(hm, "Sec-WebSocket-Key")) != NULL) { mg_event_handler_t handler; @@ -5701,7 +5725,7 @@ void mg_http_handler(struct mg_connection *nc, int ev, void *ev_data) { mg_ws_handshake(nc, vec); } mg_call(nc, nc->handler, MG_EV_WEBSOCKET_HANDSHAKE_DONE, NULL); - mg_ws_handler(nc, MG_EV_RECV, ev_data); + mg_ws_handler(nc, MG_EV_RECV, ev_data MG_UD_ARG(user_data)); } } #endif /* MG_ENABLE_HTTP_WEBSOCKET */ @@ -6950,7 +6974,7 @@ static int mg_http_send_port_based_redirect( } static void mg_reverse_proxy_handler(struct mg_connection *nc, int ev, - void *ev_data) { + void *ev_data MG_UD_ARG(void *user_data)) { struct http_message *hm = (struct http_message *) ev_data; struct mg_http_proto_data *pd = mg_http_get_proto_data(nc); @@ -6976,6 +7000,10 @@ static void mg_reverse_proxy_handler(struct mg_connection *nc, int ev, pd->reverse_proxy_data.linked_conn->flags |= MG_F_SEND_AND_CLOSE; break; } + +#if MG_ENABLE_CALLBACK_USERDATA + (void) user_data; +#endif } void mg_http_reverse_proxy(struct mg_connection *nc, @@ -6994,9 +7022,9 @@ void mg_http_reverse_proxy(struct mg_connection *nc, mg_asprintf(&purl, sizeof(burl), "%.*s%.*s", (int) upstream.len, upstream.p, (int) (hm->uri.len - mount.len), hm->uri.p + mount.len); - be = mg_connect_http_base(nc->mgr, mg_reverse_proxy_handler, opts, "http://", - "https://", purl, &path, NULL /* user */, - NULL /* pass */, &addr); + be = mg_connect_http_base(nc->mgr, MG_CB(mg_reverse_proxy_handler, NULL), + opts, "http://", "https://", purl, &path, + NULL /* user */, NULL /* pass */, &addr); LOG(LL_DEBUG, ("Proxying %.*s to %s (rule: %.*s)", (int) hm->uri.len, hm->uri.p, purl, (int) mount.len, mount.p)); @@ -7474,7 +7502,8 @@ void mg_serve_http(struct mg_connection *nc, struct http_message *hm, #if MG_ENABLE_HTTP_STREAMING_MULTIPART void mg_file_upload_handler(struct mg_connection *nc, int ev, void *ev_data, - mg_fu_fname_fn local_name_fn) { + mg_fu_fname_fn local_name_fn + MG_UD_ARG(void *user_data)) { switch (ev) { case MG_EV_HTTP_PART_BEGIN: { struct mg_http_multipart_part *mp = @@ -7586,6 +7615,10 @@ void mg_file_upload_handler(struct mg_connection *nc, int ev, void *ev_data, break; } } + +#if MG_ENABLE_CALLBACK_USERDATA + (void) user_data; +#endif } #endif /* MG_ENABLE_HTTP_STREAMING_MULTIPART */ @@ -7674,7 +7707,7 @@ cleanup: } struct mg_connection *mg_connect_http_base( - struct mg_mgr *mgr, mg_event_handler_t ev_handler, + struct mg_mgr *mgr, MG_CB(mg_event_handler_t ev_handler, void *user_data), struct mg_connect_opts opts, const char *schema, const char *schema_ssl, const char *url, const char **path, char **user, char **pass, char **addr) { struct mg_connection *nc = NULL; @@ -7707,7 +7740,8 @@ struct mg_connection *mg_connect_http_base( #endif } - if ((nc = mg_connect_opt(mgr, *addr, ev_handler, opts)) != NULL) { + if ((nc = mg_connect_opt(mgr, *addr, MG_CB(ev_handler, user_data), opts)) != + NULL) { mg_set_protocol_http_websocket(nc); /* If the port was addred by us, restore the original host. */ if (port_i >= 0) (*addr)[port_i] = '\0'; @@ -7716,18 +7750,16 @@ struct mg_connection *mg_connect_http_base( return nc; } -struct mg_connection *mg_connect_http_opt(struct mg_mgr *mgr, - mg_event_handler_t ev_handler, - struct mg_connect_opts opts, - const char *url, - const char *extra_headers, - const char *post_data) { +struct mg_connection *mg_connect_http_opt( + struct mg_mgr *mgr, MG_CB(mg_event_handler_t ev_handler, void *user_data), + struct mg_connect_opts opts, const char *url, const char *extra_headers, + const char *post_data) { char *user = NULL, *pass = NULL, *addr = NULL; const char *path = NULL; struct mbuf auth; struct mg_connection *nc = - mg_connect_http_base(mgr, ev_handler, opts, "http://", "https://", url, - &path, &user, &pass, &addr); + mg_connect_http_base(mgr, MG_CB(ev_handler, user_data), opts, "http://", + "https://", url, &path, &user, &pass, &addr); if (nc == NULL) { return NULL; @@ -7754,15 +7786,13 @@ struct mg_connection *mg_connect_http_opt(struct mg_mgr *mgr, return nc; } -struct mg_connection *mg_connect_http(struct mg_mgr *mgr, - mg_event_handler_t ev_handler, - const char *url, - const char *extra_headers, - const char *post_data) { +struct mg_connection *mg_connect_http( + struct mg_mgr *mgr, MG_CB(mg_event_handler_t ev_handler, void *user_data), + const char *url, const char *extra_headers, const char *post_data) { struct mg_connect_opts opts; memset(&opts, 0, sizeof(opts)); - return mg_connect_http_opt(mgr, ev_handler, opts, url, extra_headers, - post_data); + return mg_connect_http_opt(mgr, MG_CB(ev_handler, user_data), opts, url, + extra_headers, post_data); } size_t mg_parse_multipart(const char *buf, size_t buf_len, char *var_name, @@ -8196,8 +8226,11 @@ static void mg_prepare_cgi_environment(struct mg_connection *nc, } static void mg_cgi_ev_handler(struct mg_connection *cgi_nc, int ev, - void *ev_data) { - struct mg_connection *nc = (struct mg_connection *) cgi_nc->user_data; + void *ev_data MG_UD_ARG(void *user_data)) { +#if !MG_ENABLE_CALLBACK_USERDATA + void *user_data = cgi_nc->user_data; +#endif + struct mg_connection *nc = (struct mg_connection *) user_data; (void) ev_data; if (nc == NULL) { @@ -8289,10 +8322,12 @@ MG_INTERNAL void mg_handle_cgi(struct mg_connection *nc, const char *prog, 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_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); cgi_pd->cgi.cgi_nc = cgi_nc; +#if !MG_ENABLE_CALLBACK_USERDATA cgi_pd->cgi.cgi_nc->user_data = nc; +#endif nc->flags |= MG_F_USER_1; /* Push POST data to the CGI */ if (n > 0 && n < nc->recv_mbuf.len) { @@ -9035,7 +9070,7 @@ void mg_printf_websocket_frame(struct mg_connection *nc, int op, } MG_INTERNAL void mg_ws_handler(struct mg_connection *nc, int ev, - void *ev_data) { + void *ev_data MG_UD_ARG(void *user_data)) { mg_call(nc, nc->handler, ev, ev_data); switch (ev) { @@ -9056,6 +9091,9 @@ MG_INTERNAL void mg_ws_handler(struct mg_connection *nc, int ev, default: break; } +#if MG_ENABLE_CALLBACK_USERDATA + (void) user_data; +#endif } #ifndef MG_EXT_SHA1 @@ -9154,16 +9192,15 @@ void mg_send_websocket_handshake(struct mg_connection *nc, const char *path, extra_headers); } -struct mg_connection *mg_connect_ws_opt(struct mg_mgr *mgr, - mg_event_handler_t ev_handler, - struct mg_connect_opts opts, - const char *url, const char *protocol, - const char *extra_headers) { +struct mg_connection *mg_connect_ws_opt( + struct mg_mgr *mgr, MG_CB(mg_event_handler_t ev_handler, void *user_data), + struct mg_connect_opts opts, const char *url, const char *protocol, + const char *extra_headers) { char *user = NULL, *pass = NULL, *addr = NULL; const char *path = NULL; struct mg_connection *nc = - mg_connect_http_base(mgr, ev_handler, opts, "ws://", "wss://", url, &path, - &user, &pass, &addr); + mg_connect_http_base(mgr, MG_CB(ev_handler, user_data), opts, "ws://", + "wss://", url, &path, &user, &pass, &addr); if (nc != NULL) { mg_send_websocket_handshake3(nc, path, addr, protocol, extra_headers, user, @@ -9176,13 +9213,13 @@ struct mg_connection *mg_connect_ws_opt(struct mg_mgr *mgr, return nc; } -struct mg_connection *mg_connect_ws(struct mg_mgr *mgr, - mg_event_handler_t ev_handler, - const char *url, const char *protocol, - const char *extra_headers) { +struct mg_connection *mg_connect_ws( + struct mg_mgr *mgr, MG_CB(mg_event_handler_t ev_handler, void *user_data), + const char *url, const char *protocol, const char *extra_headers) { struct mg_connect_opts opts; memset(&opts, 0, sizeof(opts)); - return mg_connect_ws_opt(mgr, ev_handler, opts, url, protocol, extra_headers); + return mg_connect_ws_opt(mgr, MG_CB(ev_handler, user_data), opts, url, + protocol, extra_headers); } #endif /* MG_ENABLE_HTTP && MG_ENABLE_HTTP_WEBSOCKET */ #ifdef MG_MODULE_LINES @@ -9694,19 +9731,20 @@ MG_INTERNAL int parse_mqtt(struct mbuf *io, struct mg_mqtt_message *mm) { return end - io->buf; } -static void mqtt_handler(struct mg_connection *nc, int ev, void *ev_data) { +static void mqtt_handler(struct mg_connection *nc, int ev, + void *ev_data MG_UD_ARG(void *user_data)) { int len; struct mbuf *io = &nc->recv_mbuf; struct mg_mqtt_message mm; memset(&mm, 0, sizeof(mm)); - nc->handler(nc, ev, ev_data); + nc->handler(nc, ev, ev_data MG_UD_ARG(user_data)); switch (ev) { case MG_EV_RECV: len = parse_mqtt(io, &mm); if (len == -1) break; /* not fully buffered */ - nc->handler(nc, MG_MQTT_EVENT_BASE + mm.cmd, &mm); + nc->handler(nc, MG_MQTT_EVENT_BASE + mm.cmd, &mm MG_UD_ARG(user_data)); mbuf_remove(io, len); break; } @@ -10479,12 +10517,13 @@ size_t mg_dns_uncompress_name(struct mg_dns_message *msg, struct mg_str *name, return dst - old_dst; } -static void dns_handler(struct mg_connection *nc, int ev, void *ev_data) { +static void dns_handler(struct mg_connection *nc, int ev, + void *ev_data MG_UD_ARG(void *user_data)) { struct mbuf *io = &nc->recv_mbuf; struct mg_dns_message msg; /* Pass low-level events to the user handler */ - nc->handler(nc, ev, ev_data); + nc->handler(nc, ev, ev_data MG_UD_ARG(user_data)); switch (ev) { case MG_EV_RECV: @@ -10503,7 +10542,7 @@ static void dns_handler(struct mg_connection *nc, int ev, void *ev_data) { mg_send(nc, io->buf, io->len); } else { /* Call user handler with parsed message */ - nc->handler(nc, MG_DNS_MESSAGE, &msg); + nc->handler(nc, MG_DNS_MESSAGE, &msg MG_UD_ARG(user_data)); } mbuf_remove(io, io->len); break; @@ -10741,15 +10780,19 @@ int mg_resolve_from_hosts_file(const char *name, union socket_address *usa) { return -1; } -static void mg_resolve_async_eh(struct mg_connection *nc, int ev, void *data) { +static void mg_resolve_async_eh(struct mg_connection *nc, int ev, + void *data MG_UD_ARG(void *user_data)) { 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 - if (ev != MG_EV_POLL) DBG(("ev=%d user_data=%p", ev, nc->user_data)); + if (ev != MG_EV_POLL) DBG(("ev=%d user_data=%p", ev, user_data)); - req = (struct mg_resolve_async_request *) nc->user_data; + req = (struct mg_resolve_async_request *) user_data; if (req == NULL) { return; @@ -10849,7 +10892,7 @@ int mg_resolve_async_opt(struct mg_mgr *mgr, const char *name, int query, nameserver = mg_dns_server; } - dns_nc = mg_connect(mgr, nameserver, mg_resolve_async_eh); + dns_nc = mg_connect(mgr, nameserver, MG_CB(mg_resolve_async_eh, NULL)); if (dns_nc == NULL) { free(req); return -1; @@ -11523,8 +11566,13 @@ static void mg_tun_close_all(struct mg_tun_client *client) { } static void mg_tun_client_handler(struct mg_connection *nc, int ev, - void *ev_data) { - struct mg_tun_client *client = (struct mg_tun_client *) nc->user_data; + void *ev_data MG_UD_ARG(void *user_data)) { +#if !MG_ENABLE_CALLBACK_USERDATA + void *user_data = nc->user_data; +#else + (void) nc; +#endif + struct mg_tun_client *client = (struct mg_tun_client *) user_data; switch (ev) { case MG_EV_CONNECT: { @@ -11611,21 +11659,28 @@ static void mg_tun_do_reconnect(struct mg_tun_client *client) { opts.ssl_ca_cert = client->ssl.ssl_ca_cert; #endif /* HTTP/Websocket listener */ - if ((dc = mg_connect_ws_opt(client->mgr, mg_tun_client_handler, opts, - client->disp_url, MG_TUN_PROTO_NAME, NULL)) == - NULL) { + if ((dc = mg_connect_ws_opt(client->mgr, MG_CB(mg_tun_client_handler, client), + opts, client->disp_url, MG_TUN_PROTO_NAME, + NULL)) == NULL) { LOG(LL_ERROR, ("Cannot connect to WS server on addr [%s]\n", client->disp_url)); return; } client->disp = dc; +#if !MG_ENABLE_CALLBACK_USERDATA dc->user_data = client; +#endif } void mg_tun_reconnect_ev_handler(struct mg_connection *nc, int ev, - void *ev_data) { - struct mg_tun_client *client = (struct mg_tun_client *) nc->user_data; + void *ev_data MG_UD_ARG(void *user_data)) { +#if !MG_ENABLE_CALLBACK_USERDATA + void *user_data = nc->user_data; +#else + (void) nc; +#endif + struct mg_tun_client *client = (struct mg_tun_client *) user_data; (void) ev_data; switch (ev) { @@ -11642,9 +11697,11 @@ void mg_tun_reconnect_ev_handler(struct mg_connection *nc, int ev, static void mg_tun_reconnect(struct mg_tun_client *client, int timeout) { if (client->reconnect == NULL) { - client->reconnect = - mg_add_sock(client->mgr, INVALID_SOCKET, mg_tun_reconnect_ev_handler); + client->reconnect = mg_add_sock(client->mgr, INVALID_SOCKET, + MG_CB(mg_tun_reconnect_ev_handler, client)); +#if !MG_ENABLE_CALLBACK_USERDATA client->reconnect->user_data = client; +#endif } client->reconnect->ev_timer_time = mg_time() + timeout; } @@ -11700,18 +11757,21 @@ void mg_tun_destroy_client(struct mg_tun_client *client) { } static struct mg_connection *mg_tun_do_bind(struct mg_tun_client *client, - mg_event_handler_t handler, + MG_CB(mg_event_handler_t handler, + void *user_data), struct mg_bind_opts opts) { struct mg_connection *lc; opts.iface = client->iface; - lc = mg_bind_opt(client->mgr, ":1234" /* dummy port */, handler, opts); + lc = mg_bind_opt(client->mgr, ":1234" /* dummy port */, + MG_CB(handler, user_data), opts); client->listener = lc; return lc; } struct mg_connection *mg_tun_bind_opt(struct mg_mgr *mgr, const char *dispatcher, - mg_event_handler_t handler, + MG_CB(mg_event_handler_t handler, + void *user_data), struct mg_bind_opts opts) { #if MG_ENABLE_SSL struct mg_tun_ssl_opts ssl = {opts.ssl_cert, opts.ssl_key, opts.ssl_ca_cert}; @@ -11728,7 +11788,7 @@ struct mg_connection *mg_tun_bind_opt(struct mg_mgr *mgr, opts.ssl_key = NULL; opts.ssl_ca_cert = NULL; #endif - return mg_tun_do_bind(client, handler, opts); + return mg_tun_do_bind(client, MG_CB(handler, user_data), opts); } int mg_tun_parse_frame(void *data, size_t len, struct mg_tun_frame *frame) { @@ -11909,19 +11969,20 @@ MG_INTERNAL int mg_sntp_parse_reply(const char *buf, int len, return 0; } -static void mg_sntp_handler(struct mg_connection *c, int ev, void *ev_data) { +static void mg_sntp_handler(struct mg_connection *c, int ev, + void *ev_data MG_UD_ARG(void *user_data)) { struct mbuf *io = &c->recv_mbuf; struct mg_sntp_message msg; - c->handler(c, ev, ev_data); + c->handler(c, ev, ev_data MG_UD_ARG(user_data)); switch (ev) { case MG_EV_RECV: { if (mg_sntp_parse_reply(io->buf, io->len, &msg) < 0) { DBG(("Invalid SNTP packet received (%d)", (int) io->len)); - c->handler(c, MG_SNTP_MALFORMED_REPLY, NULL); + c->handler(c, MG_SNTP_MALFORMED_REPLY, NULL MG_UD_ARG(user_data)); } else { - c->handler(c, MG_SNTP_REPLY, (void *) &msg); + c->handler(c, MG_SNTP_REPLY, (void *) &msg MG_UD_ARG(user_data)); } mbuf_remove(io, io->len); @@ -11941,7 +12002,8 @@ int mg_set_protocol_sntp(struct mg_connection *c) { } struct mg_connection *mg_sntp_connect(struct mg_mgr *mgr, - mg_event_handler_t event_handler, + MG_CB(mg_event_handler_t event_handler, + void *user_data), const char *sntp_server_name) { struct mg_connection *c = NULL; char url[100], *p_url = url; @@ -11964,7 +12026,7 @@ struct mg_connection *mg_sntp_connect(struct mg_mgr *mgr, mg_asprintf(&p_url, sizeof(url), "%s%s%s", proto, sntp_server_name, port); - c = mg_connect(mgr, p_url, event_handler); + c = mg_connect(mgr, p_url, event_handler MG_UD_ARG(user_data)); if (c == NULL) { goto cleanup; @@ -11986,8 +12048,11 @@ struct sntp_data { }; static void mg_sntp_util_ev_handler(struct mg_connection *c, int ev, - void *ev_data) { - struct sntp_data *sd = (struct sntp_data *) c->user_data; + void *ev_data MG_UD_ARG(void *user_data)) { +#if !MG_ENABLE_CALLBACK_USERDATA + void *user_data = c->user_data; +#endif + struct sntp_data *sd = (struct sntp_data *) user_data; switch (ev) { case MG_EV_CONNECT: @@ -12015,7 +12080,7 @@ static void mg_sntp_util_ev_handler(struct mg_connection *c, int ev, c->flags |= MG_F_CLOSE_IMMEDIATELY; break; case MG_EV_CLOSE: - MG_FREE(c->user_data); + MG_FREE(user_data); c->user_data = NULL; break; } @@ -12030,14 +12095,17 @@ struct mg_connection *mg_sntp_get_time(struct mg_mgr *mgr, return NULL; } - c = mg_sntp_connect(mgr, mg_sntp_util_ev_handler, sntp_server_name); + c = mg_sntp_connect(mgr, MG_CB(mg_sntp_util_ev_handler, sd), + sntp_server_name); if (c == NULL) { MG_FREE(sd); return NULL; } sd->hander = event_handler; +#if !MG_ENABLE_CALLBACK_USERDATA c->user_data = sd; +#endif return c; } diff --git a/mongoose.h b/mongoose.h index 0812f9a5..6f697185 100644 --- a/mongoose.h +++ b/mongoose.h @@ -2963,6 +2963,18 @@ struct { \ #define MG_ENABLE_EXTRA_ERRORS_DESC 0 #endif +#ifndef MG_ENABLE_CALLBACK_USERDATA +#define MG_ENABLE_CALLBACK_USERDATA 0 +#endif + +#if MG_ENABLE_CALLBACK_USERDATA +#define MG_UD_ARG(ud) , ud +#define MG_CB(cb, ud) cb, ud +#else +#define MG_UD_ARG(ud) +#define MG_CB(cb, ud) cb +#endif + #endif /* CS_MONGOOSE_SRC_FEATURES_H_ */ #ifdef MG_MODULE_LINES #line 1 "mongoose/src/net_if.h" @@ -3229,7 +3241,7 @@ struct mg_connection; * Mongoose calls the event handler, passing the events defined below. */ typedef void (*mg_event_handler_t)(struct mg_connection *nc, int ev, - void *ev_data); + void *ev_data MG_UD_ARG(void *user_data)); /* Events. Meaning of event parameter (evp) is given in the comment. */ #define MG_EV_POLL 0 /* Sent to each connection on each mg_mgr_poll() call */ @@ -3392,7 +3404,8 @@ time_t mg_mgr_poll(struct mg_mgr *, int milli); * be passed as the `ev_data` pointer. Maximum message size is capped * by `MG_CTL_MSG_MESSAGE_SIZE` which is set to 8192 bytes. */ -void mg_broadcast(struct mg_mgr *, mg_event_handler_t func, void *, size_t); +void mg_broadcast(struct mg_mgr *mgr, mg_event_handler_t cb, void *data, + size_t len); #endif /* @@ -3408,7 +3421,7 @@ void mg_broadcast(struct mg_mgr *, mg_event_handler_t func, void *, size_t); * } * ``` */ -struct mg_connection *mg_next(struct mg_mgr *, struct mg_connection *); +struct mg_connection *mg_next(struct mg_mgr *mgr, struct mg_connection *c); /* * Optional parameters to `mg_add_sock_opt()`. @@ -3429,7 +3442,9 @@ struct mg_add_sock_opts { * * For more options see the `mg_add_sock_opt` variant. */ -struct mg_connection *mg_add_sock(struct mg_mgr *, sock_t, mg_event_handler_t); +struct mg_connection *mg_add_sock(struct mg_mgr *mgr, sock_t sock, + MG_CB(mg_event_handler_t handler, + void *user_data)); /* * Creates a connection, associates it with the given socket and event handler @@ -3437,9 +3452,10 @@ struct mg_connection *mg_add_sock(struct mg_mgr *, sock_t, mg_event_handler_t); * * See the `mg_add_sock_opts` structure for a description of the options. */ -struct mg_connection *mg_add_sock_opt(struct mg_mgr *, sock_t, - mg_event_handler_t, - struct mg_add_sock_opts); +struct mg_connection *mg_add_sock_opt(struct mg_mgr *mgr, sock_t sock, + MG_CB(mg_event_handler_t handler, + void *user_data), + struct mg_add_sock_opts opts); /* * Optional parameters to `mg_bind_opt()`. @@ -3485,8 +3501,9 @@ struct mg_bind_opts { * * See `mg_bind_opt` for full documentation. */ -struct mg_connection *mg_bind(struct mg_mgr *, const char *, - mg_event_handler_t); +struct mg_connection *mg_bind(struct mg_mgr *mgr, const char *address, + MG_CB(mg_event_handler_t handler, + void *user_data)); /* * Creates a listening connection. * @@ -3506,7 +3523,8 @@ struct mg_connection *mg_bind(struct mg_mgr *, const char *, * NOTE: The connection remains owned by the manager, do not free(). */ struct mg_connection *mg_bind_opt(struct mg_mgr *mgr, const char *address, - mg_event_handler_t handler, + MG_CB(mg_event_handler_t handler, + void *user_data), struct mg_bind_opts opts); /* Optional parameters to `mg_connect_opt()` */ @@ -3569,7 +3587,8 @@ struct mg_connect_opts { * See `mg_connect_opt()` for full documentation. */ struct mg_connection *mg_connect(struct mg_mgr *mgr, const char *address, - mg_event_handler_t handler); + MG_CB(mg_event_handler_t handler, + void *user_data)); /* * Connects to a remote host. @@ -3620,7 +3639,8 @@ struct mg_connection *mg_connect(struct mg_mgr *mgr, const char *address, * ``` */ struct mg_connection *mg_connect_opt(struct mg_mgr *mgr, const char *address, - mg_event_handler_t handler, + MG_CB(mg_event_handler_t handler, + void *user_data), struct mg_connect_opts opts); #if MG_ENABLE_SSL && MG_NET_IF != MG_NET_IF_SIMPLELINK @@ -4274,7 +4294,8 @@ void mg_send_websocket_handshake3(struct mg_connection *nc, const char *path, * ``` */ struct mg_connection *mg_connect_ws(struct mg_mgr *mgr, - mg_event_handler_t event_handler, + MG_CB(mg_event_handler_t event_handler, + void *user_data), const char *url, const char *protocol, const char *extra_headers); @@ -4284,11 +4305,10 @@ struct mg_connection *mg_connect_ws(struct mg_mgr *mgr, * Mostly identical to `mg_connect_ws`, but allows to provide extra parameters * (for example, SSL parameters) */ -struct mg_connection *mg_connect_ws_opt(struct mg_mgr *mgr, - mg_event_handler_t ev_handler, - struct mg_connect_opts opts, - const char *url, const char *protocol, - const char *extra_headers); +struct mg_connection *mg_connect_ws_opt( + struct mg_mgr *mgr, MG_CB(mg_event_handler_t ev_handler, void *user_data), + struct mg_connect_opts opts, const char *url, const char *protocol, + const char *extra_headers); /* * Send WebSocket frame to the remote end. @@ -4739,7 +4759,8 @@ typedef struct mg_str (*mg_fu_fname_fn)(struct mg_connection *nc, * ``` */ void mg_file_upload_handler(struct mg_connection *nc, int ev, void *ev_data, - mg_fu_fname_fn local_name_fn); + mg_fu_fname_fn local_name_fn + MG_UD_ARG(void *user_data)); #endif /* MG_ENABLE_HTTP_STREAMING_MULTIPART */ #endif /* MG_ENABLE_FILESYSTEM */ @@ -4926,11 +4947,10 @@ extern "C" { * "var_1=value_1&var_2=value_2"); * ``` */ -struct mg_connection *mg_connect_http(struct mg_mgr *mgr, - mg_event_handler_t event_handler, - const char *url, - const char *extra_headers, - const char *post_data); +struct mg_connection *mg_connect_http( + struct mg_mgr *mgr, + MG_CB(mg_event_handler_t event_handler, void *user_data), const char *url, + const char *extra_headers, const char *post_data); /* * Helper function that creates an outbound HTTP connection. @@ -4939,12 +4959,10 @@ struct mg_connection *mg_connect_http(struct mg_mgr *mgr, *parameters * (for example, SSL parameters) */ -struct mg_connection *mg_connect_http_opt(struct mg_mgr *mgr, - mg_event_handler_t ev_handler, - struct mg_connect_opts opts, - const char *url, - const char *extra_headers, - const char *post_data); +struct mg_connection *mg_connect_http_opt( + struct mg_mgr *mgr, MG_CB(mg_event_handler_t ev_handler, void *user_data), + struct mg_connect_opts opts, const char *url, const char *extra_headers, + const char *post_data); /* Creates digest authentication header for a client request. */ int mg_http_create_digest_auth_header(char *buf, size_t buf_len, @@ -5837,7 +5855,8 @@ struct mg_sntp_message { /* Establishes connection to given sntp server */ struct mg_connection *mg_sntp_connect(struct mg_mgr *mgr, - mg_event_handler_t event_handler, + MG_CB(mg_event_handler_t event_handler, + void *user_data), const char *sntp_server_name); /* Sends time request to given connection */ From bf7dd7ac6301b34368e08e2e754eb879fe40b677 Mon Sep 17 00:00:00 2001 From: Dmitry Frank Date: Wed, 15 Mar 2017 17:20:04 +0000 Subject: [PATCH 020/137] Add separate userdata for each http endpoint hdlr PUBLISHED_FROM=29a204c2c7f35724b6f1e8435edb94869da2362c --- .../mg_register_http_endpoint.md | 3 +- examples/big_upload/big_upload.c | 2 +- mongoose.c | 132 +++++++++++------- mongoose.h | 3 +- 4 files changed, 86 insertions(+), 54 deletions(-) diff --git a/docs/c-api/http_server.h/mg_register_http_endpoint.md b/docs/c-api/http_server.h/mg_register_http_endpoint.md index 99418caa..394bbb51 100644 --- a/docs/c-api/http_server.h/mg_register_http_endpoint.md +++ b/docs/c-api/http_server.h/mg_register_http_endpoint.md @@ -4,7 +4,8 @@ decl_name: "mg_register_http_endpoint" symbol_kind: "func" signature: | void mg_register_http_endpoint(struct mg_connection *nc, const char *uri_path, - mg_event_handler_t handler); + MG_CB(mg_event_handler_t handler, + void *user_data); --- Registers a callback for a specified http endpoint diff --git a/examples/big_upload/big_upload.c b/examples/big_upload/big_upload.c index 8bd3cc5a..682a0c31 100644 --- a/examples/big_upload/big_upload.c +++ b/examples/big_upload/big_upload.c @@ -98,7 +98,7 @@ int main(void) { mg_mgr_init(&mgr, NULL); nc = mg_bind(&mgr, s_http_port, ev_handler); - mg_register_http_endpoint(nc, "/upload", handle_upload); + mg_register_http_endpoint(nc, "/upload", handle_upload MG_UD_ARG(NULL)); // Set up HTTP server parameters mg_set_protocol_http_websocket(nc); diff --git a/mongoose.c b/mongoose.c index a694cd51..a24c89f2 100644 --- a/mongoose.c +++ b/mongoose.c @@ -62,7 +62,8 @@ MG_INTERNAL struct mg_connection *mg_do_connect(struct mg_connection *nc, MG_INTERNAL int mg_parse_address(const char *str, union socket_address *sa, int *proto, char *host, size_t host_len); MG_INTERNAL void mg_call(struct mg_connection *nc, - mg_event_handler_t ev_handler, int ev, void *ev_data); + mg_event_handler_t ev_handler, void *user_data, int ev, + void *ev_data); void mg_forward(struct mg_connection *from, struct mg_connection *to); MG_INTERNAL void mg_add_conn(struct mg_mgr *mgr, struct mg_connection *c); MG_INTERNAL void mg_remove_conn(struct mg_connection *c); @@ -2021,7 +2022,8 @@ 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, int ev, void *ev_data) { + mg_event_handler_t ev_handler, void *user_data, int ev, + void *ev_data) { if (ev_handler == NULL) { /* * If protocol handler is specified, call it. Otherwise, call user-specified @@ -2051,7 +2053,7 @@ MG_INTERNAL void mg_call(struct mg_connection *nc, 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(nc->user_data)); + 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) { @@ -2067,12 +2069,15 @@ MG_INTERNAL void mg_call(struct mg_connection *nc, ev_handler == nc->handler ? "user" : "proto", nc->flags, (int) nc->recv_mbuf.len, (int) nc->send_mbuf.len)); } +#if !MG_ENABLE_CALLBACK_USERDATA + (void) user_data; +#endif } void mg_if_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; - mg_call(c, NULL, MG_EV_TIMER, &now); + mg_call(c, NULL, c->user_data, MG_EV_TIMER, &now); /* * To prevent timer firing all the time, reset the timer after delivery. * However, in case user sets it to new value, do not reset. @@ -2085,7 +2090,7 @@ 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, MG_EV_POLL, &now); + mg_call(nc, NULL, nc->user_data, MG_EV_POLL, &now); } } @@ -2108,7 +2113,7 @@ void mg_close_conn(struct mg_connection *conn) { DBG(("%p %lu %d", conn, conn->flags, conn->sock)); mg_remove_conn(conn); conn->iface->vtable->destroy_conn(conn); - mg_call(conn, NULL, MG_EV_CLOSE, NULL); + mg_call(conn, NULL, conn->user_data, MG_EV_CLOSE, NULL); mg_destroy_conn(conn, 0 /* destroy_if */); } @@ -2452,7 +2457,7 @@ void mg_if_accept_tcp_cb(struct mg_connection *nc, union socket_address *sa, size_t sa_len) { (void) sa_len; nc->sa = *sa; - mg_call(nc, NULL, MG_EV_ACCEPT, &nc->sa); + mg_call(nc, NULL, nc->user_data, MG_EV_ACCEPT, &nc->sa); } void mg_send(struct mg_connection *nc, const void *buf, int len) { @@ -2473,7 +2478,7 @@ void mg_if_sent_cb(struct mg_connection *nc, int num_sent) { if (num_sent < 0) { nc->flags |= MG_F_CLOSE_IMMEDIATELY; } - mg_call(nc, NULL, MG_EV_SEND, &num_sent); + mg_call(nc, NULL, nc->user_data, MG_EV_SEND, &num_sent); } MG_INTERNAL void mg_recv_common(struct mg_connection *nc, void *buf, int len, @@ -2502,7 +2507,7 @@ MG_INTERNAL void mg_recv_common(struct mg_connection *nc, void *buf, int len, mbuf_append(&nc->recv_mbuf, buf, len); MG_FREE(buf); } - mg_call(nc, NULL, MG_EV_RECV, &len); + mg_call(nc, NULL, nc->user_data, MG_EV_RECV, &len); } void mg_if_recv_tcp_cb(struct mg_connection *nc, void *buf, int len, int own) { @@ -2550,7 +2555,7 @@ 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, MG_EV_ACCEPT, &nc->sa); + 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 */ @@ -2594,7 +2599,7 @@ void mg_if_connect_cb(struct mg_connection *nc, int err) { if (err != 0) { nc->flags |= MG_F_CLOSE_IMMEDIATELY; } - mg_call(nc, NULL, MG_EV_CONNECT, &err); + mg_call(nc, NULL, nc->user_data, MG_EV_CONNECT, &err); } #if MG_ENABLE_ASYNC_RESOLVER @@ -2632,14 +2637,14 @@ static void resolve_cb(struct mg_dns_message *msg, void *data, if (e == MG_RESOLVE_TIMEOUT) { double now = mg_time(); - mg_call(nc, NULL, MG_EV_TIMER, &now); + mg_call(nc, NULL, nc->user_data, MG_EV_TIMER, &now); } /* * If we get there was no MG_DNS_A_RECORD in the answer */ - mg_call(nc, NULL, MG_EV_CONNECT, &failure); - mg_call(nc, NULL, MG_EV_CLOSE, NULL); + mg_call(nc, NULL, nc->user_data, MG_EV_CONNECT, &failure); + mg_call(nc, NULL, nc->user_data, MG_EV_CLOSE, NULL); mg_destroy_conn(nc, 1 /* destroy_if */); } #endif @@ -5021,6 +5026,9 @@ struct mg_http_endpoint { const char *name; size_t name_len; mg_event_handler_t handler; +#if MG_ENABLE_CALLBACK_USERDATA + void *user_data; +#endif }; enum mg_http_multipart_stream_state { @@ -5502,7 +5510,7 @@ MG_INTERNAL size_t mg_handle_chunked(struct mg_connection *nc, /* Send MG_EV_HTTP_CHUNK event */ nc->flags &= ~MG_F_DELETE_CHUNK; - mg_call(nc, nc->handler, MG_EV_HTTP_CHUNK, hm); + mg_call(nc, nc->handler, nc->user_data, MG_EV_HTTP_CHUNK, hm); /* Delete processed data if user set MG_F_DELETE_CHUNK flag */ if (nc->flags & MG_F_DELETE_CHUNK) { @@ -5523,10 +5531,10 @@ MG_INTERNAL size_t mg_handle_chunked(struct mg_connection *nc, return body_len; } -static mg_event_handler_t mg_http_get_endpoint_handler( - struct mg_connection *nc, struct mg_str *uri_path) { +struct mg_http_endpoint *mg_http_get_endpoint_handler(struct mg_connection *nc, + struct mg_str *uri_path) { struct mg_http_proto_data *pd; - mg_event_handler_t ret = NULL; + struct mg_http_endpoint *ret = NULL; int matched, matched_max = 0; struct mg_http_endpoint *ep; @@ -5542,7 +5550,7 @@ static mg_event_handler_t mg_http_get_endpoint_handler( if ((matched = mg_match_prefix_n(name_s, *uri_path)) != -1) { if (matched > matched_max) { /* Looking for the longest suitable handler */ - ret = ep->handler; + ret = ep; matched_max = matched; } } @@ -5556,15 +5564,20 @@ static mg_event_handler_t mg_http_get_endpoint_handler( static void mg_http_call_endpoint_handler(struct mg_connection *nc, int ev, struct http_message *hm) { struct mg_http_proto_data *pd = mg_http_get_proto_data(nc); + void *user_data = nc->user_data; - if (pd->endpoint_handler == NULL || ev == MG_EV_HTTP_REQUEST) { - pd->endpoint_handler = - ev == MG_EV_HTTP_REQUEST - ? mg_http_get_endpoint_handler(nc->listener, &hm->uri) - : NULL; + if (ev == MG_EV_HTTP_REQUEST) { + struct mg_http_endpoint *ep = + mg_http_get_endpoint_handler(nc->listener, &hm->uri); + if (ep != NULL) { + pd->endpoint_handler = ep->handler; +#if MG_ENABLE_CALLBACK_USERDATA + user_data = ep->user_data; +#endif + } } - mg_call(nc, pd->endpoint_handler ? pd->endpoint_handler : nc->handler, ev, - hm); + mg_call(nc, pd->endpoint_handler ? pd->endpoint_handler : nc->handler, + user_data, ev, hm); } #if MG_ENABLE_HTTP_STREAMING_MULTIPART @@ -5627,11 +5640,11 @@ void mg_http_handler(struct mg_connection *nc, int ev, mp.var_name = pd->mp_stream.var_name; mp.file_name = pd->mp_stream.file_name; mg_call(nc, (pd->endpoint_handler ? pd->endpoint_handler : nc->handler), - MG_EV_HTTP_PART_END, &mp); + nc->user_data, MG_EV_HTTP_PART_END, &mp); mp.var_name = NULL; mp.file_name = NULL; mg_call(nc, (pd->endpoint_handler ? pd->endpoint_handler : nc->handler), - MG_EV_HTTP_MULTIPART_REQUEST_END, &mp); + nc->user_data, MG_EV_HTTP_MULTIPART_REQUEST_END, &mp); } else #endif if (io->len > 0 && mg_parse_http(io->buf, io->len, hm, is_req) > 0) { @@ -5652,7 +5665,7 @@ void mg_http_handler(struct mg_connection *nc, int ev, } #endif - mg_call(nc, nc->handler, ev, ev_data); + mg_call(nc, nc->handler, nc->user_data, ev, ev_data); if (ev == MG_EV_RECV) { struct mg_str *s; @@ -5697,11 +5710,12 @@ void mg_http_handler(struct mg_connection *nc, int ev, mbuf_remove(io, req_len); nc->proto_handler = mg_ws_handler; nc->flags |= MG_F_IS_WEBSOCKET; - mg_call(nc, nc->handler, MG_EV_WEBSOCKET_HANDSHAKE_DONE, NULL); + mg_call(nc, nc->handler, nc->user_data, MG_EV_WEBSOCKET_HANDSHAKE_DONE, + NULL); mg_ws_handler(nc, MG_EV_RECV, ev_data MG_UD_ARG(user_data)); } else if (nc->listener != NULL && (vec = mg_get_http_header(hm, "Sec-WebSocket-Key")) != NULL) { - mg_event_handler_t handler; + struct mg_http_endpoint *ep; /* This is a websocket request. Switch protocol handlers. */ mbuf_remove(io, req_len); @@ -5713,18 +5727,23 @@ void mg_http_handler(struct mg_connection *nc, int ev, * deliver subsequent websocket events to this handler after the * protocol switch. */ - handler = mg_http_get_endpoint_handler(nc->listener, &hm->uri); - if (handler != NULL) { - nc->handler = handler; + ep = mg_http_get_endpoint_handler(nc->listener, &hm->uri); + if (ep != NULL) { + nc->handler = ep->handler; +#if MG_ENABLE_CALLBACK_USERDATA + nc->user_data = ep->user_data; +#endif } /* Send handshake */ - mg_call(nc, nc->handler, MG_EV_WEBSOCKET_HANDSHAKE_REQUEST, hm); + mg_call(nc, nc->handler, nc->user_data, MG_EV_WEBSOCKET_HANDSHAKE_REQUEST, + hm); if (!(nc->flags & (MG_F_CLOSE_IMMEDIATELY | MG_F_SEND_AND_CLOSE))) { if (nc->send_mbuf.len == 0) { mg_ws_handshake(nc, vec); } - mg_call(nc, nc->handler, MG_EV_WEBSOCKET_HANDSHAKE_DONE, NULL); + mg_call(nc, nc->handler, nc->user_data, MG_EV_WEBSOCKET_HANDSHAKE_DONE, + NULL); mg_ws_handler(nc, MG_EV_RECV, ev_data MG_UD_ARG(user_data)); } } @@ -5805,6 +5824,7 @@ static void mg_http_multipart_begin(struct mg_connection *nc, struct mg_http_proto_data *pd = mg_http_get_proto_data(nc); struct mg_str *ct; struct mbuf *io = &nc->recv_mbuf; + void *user_data = nc->user_data; char boundary[100]; int boundary_len; @@ -5841,17 +5861,23 @@ static void mg_http_multipart_begin(struct mg_connection *nc, */ nc->flags |= MG_F_CLOSE_IMMEDIATELY; } else { + struct mg_http_endpoint *ep = NULL; pd->mp_stream.state = MPS_BEGIN; pd->mp_stream.boundary = strdup(boundary); pd->mp_stream.boundary_len = strlen(boundary); pd->mp_stream.var_name = pd->mp_stream.file_name = NULL; + pd->endpoint_handler = nc->handler; - pd->endpoint_handler = mg_http_get_endpoint_handler(nc->listener, &hm->uri); - if (pd->endpoint_handler == NULL) { - pd->endpoint_handler = nc->handler; + ep = mg_http_get_endpoint_handler(nc->listener, &hm->uri); + if (ep != NULL) { + pd->endpoint_handler = ep->handler; +#if MG_ENABLE_CALLBACK_USERDATA + user_data = ep->user_data; +#endif } - mg_call(nc, pd->endpoint_handler, MG_EV_HTTP_MULTIPART_REQUEST, hm); + mg_call(nc, pd->endpoint_handler, user_data, MG_EV_HTTP_MULTIPART_REQUEST, + hm); mbuf_remove(io, req_len); } @@ -5872,7 +5898,7 @@ static void mg_http_multipart_call_handler(struct mg_connection *c, int ev, mp.user_data = pd->mp_stream.user_data; mp.data.p = data; mp.data.len = data_len; - mg_call(c, pd->endpoint_handler, ev, &mp); + mg_call(c, pd->endpoint_handler, c->user_data, ev, &mp); pd->mp_stream.user_data = mp.user_data; } @@ -7834,7 +7860,8 @@ size_t mg_parse_multipart(const char *buf, size_t buf_len, char *var_name, } void mg_register_http_endpoint(struct mg_connection *nc, const char *uri_path, - mg_event_handler_t handler) { + MG_CB(mg_event_handler_t handler, + void *user_data)) { struct mg_http_proto_data *pd = NULL; struct mg_http_endpoint *new_ep = NULL; @@ -7846,6 +7873,9 @@ void mg_register_http_endpoint(struct mg_connection *nc, const char *uri_path, new_ep->name = strdup(uri_path); new_ep->name_len = strlen(new_ep->name); new_ep->handler = handler; +#if MG_ENABLE_CALLBACK_USERDATA + new_ep->user_data = user_data; +#endif new_ep->next = pd->endpoints; pd->endpoints = new_ep; } @@ -8480,9 +8510,9 @@ static void mg_send_ssi_file(struct mg_connection *nc, struct http_message *hm, cctx.req = hm; cctx.file = mg_mk_str(path); cctx.arg = mg_mk_str(p + d_call.len + 1); - mg_call(nc, NULL, MG_EV_SSI_CALL, + mg_call(nc, NULL, nc->user_data, MG_EV_SSI_CALL, (void *) cctx.arg.p); /* NUL added above */ - mg_call(nc, NULL, MG_EV_SSI_CALL_CTX, &cctx); + mg_call(nc, NULL, nc->user_data, MG_EV_SSI_CALL_CTX, &cctx); #if MG_ENABLE_HTTP_SSI_EXEC } else if (strncmp(p, d_exec.p, d_exec.len) == 0) { do_ssi_exec(nc, p + d_exec.len + 1); @@ -8846,9 +8876,9 @@ static int mg_is_ws_first_fragment(unsigned char flags) { static void mg_handle_incoming_websocket_frame(struct mg_connection *nc, struct websocket_message *wsm) { if (wsm->flags & 0x8) { - mg_call(nc, nc->handler, MG_EV_WEBSOCKET_CONTROL_FRAME, wsm); + mg_call(nc, nc->handler, nc->user_data, MG_EV_WEBSOCKET_CONTROL_FRAME, wsm); } else { - mg_call(nc, nc->handler, MG_EV_WEBSOCKET_FRAME, wsm); + mg_call(nc, nc->handler, nc->user_data, MG_EV_WEBSOCKET_FRAME, wsm); } } @@ -9071,7 +9101,7 @@ void mg_printf_websocket_frame(struct mg_connection *nc, int op, MG_INTERNAL void mg_ws_handler(struct mg_connection *nc, int ev, void *ev_data MG_UD_ARG(void *user_data)) { - mg_call(nc, nc->handler, ev, ev_data); + mg_call(nc, nc->handler, nc->user_data, ev, ev_data); switch (ev) { case MG_EV_RECV: @@ -12057,7 +12087,7 @@ static void mg_sntp_util_ev_handler(struct mg_connection *c, int ev, switch (ev) { case MG_EV_CONNECT: if (*(int *) ev_data != 0) { - mg_call(c, sd->hander, MG_SNTP_FAILED, NULL); + mg_call(c, sd->hander, c->user_data, MG_SNTP_FAILED, NULL); break; } /* fallthrough */ @@ -12067,16 +12097,16 @@ static void mg_sntp_util_ev_handler(struct mg_connection *c, int ev, mg_set_timer(c, mg_time() + 10); sd->count++; } else { - mg_call(c, sd->hander, MG_SNTP_FAILED, NULL); + mg_call(c, sd->hander, c->user_data, MG_SNTP_FAILED, NULL); c->flags |= MG_F_CLOSE_IMMEDIATELY; } break; case MG_SNTP_MALFORMED_REPLY: - mg_call(c, sd->hander, MG_SNTP_FAILED, NULL); + mg_call(c, sd->hander, c->user_data, MG_SNTP_FAILED, NULL); c->flags |= MG_F_CLOSE_IMMEDIATELY; break; case MG_SNTP_REPLY: - mg_call(c, sd->hander, MG_SNTP_REPLY, ev_data); + mg_call(c, sd->hander, c->user_data, MG_SNTP_REPLY, ev_data); c->flags |= MG_F_CLOSE_IMMEDIATELY; break; case MG_EV_CLOSE: diff --git a/mongoose.h b/mongoose.h index 6f697185..bc8c8c21 100644 --- a/mongoose.h +++ b/mongoose.h @@ -4792,7 +4792,8 @@ void mg_file_upload_handler(struct mg_connection *nc, int ev, void *ev_data, * ``` */ void mg_register_http_endpoint(struct mg_connection *nc, const char *uri_path, - mg_event_handler_t handler); + MG_CB(mg_event_handler_t handler, + void *user_data)); /* * Authenticates a HTTP request against an opened password file. From a83e7d8c4294b2644d83386a8a44b541a0a2786c Mon Sep 17 00:00:00 2001 From: Deomid Ryabkov Date: Thu, 16 Mar 2017 00:53:01 +0200 Subject: [PATCH 021/137] Properly shut down the SSL connection By sending close_notify PUBLISHED_FROM=028a001cb9470a16cc7a6544805bfb042a435779 --- mongoose.c | 22 ++++++++++++++++++++++ mongoose.h | 1 + 2 files changed, 23 insertions(+) diff --git a/mongoose.c b/mongoose.c index a24c89f2..3db5e813 100644 --- a/mongoose.c +++ b/mongoose.c @@ -2111,6 +2111,11 @@ static 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); + } +#endif mg_remove_conn(conn); conn->iface->vtable->destroy_conn(conn); mg_call(conn, NULL, conn->user_data, MG_EV_CLOSE, NULL); @@ -4150,6 +4155,12 @@ int mg_ssl_if_write(struct mg_connection *nc, const void *data, size_t len) { return n; } +void mg_ssl_if_conn_close_notify(struct mg_connection *nc) { + struct mg_ssl_if_ctx *ctx = (struct mg_ssl_if_ctx *) nc->ssl_if_data; + if (ctx == NULL) return; + SSL_shutdown(ctx->ssl); +} + void mg_ssl_if_conn_free(struct mg_connection *nc) { struct mg_ssl_if_ctx *ctx = (struct mg_ssl_if_ctx *) nc->ssl_if_data; if (ctx == NULL) return; @@ -4637,6 +4648,12 @@ int mg_ssl_if_write(struct mg_connection *nc, const void *data, size_t len) { return n; } +void mg_ssl_if_conn_close_notify(struct mg_connection *nc) { + struct mg_ssl_if_ctx *ctx = (struct mg_ssl_if_ctx *) nc->ssl_if_data; + if (ctx == NULL) return; + mbedtls_ssl_close_notify(ctx->ssl); +} + void mg_ssl_if_conn_free(struct mg_connection *nc) { struct mg_ssl_if_ctx *ctx = (struct mg_ssl_if_ctx *) nc->ssl_if_data; if (ctx == NULL) return; @@ -13638,6 +13655,11 @@ enum mg_ssl_if_result mg_ssl_if_conn_init( return MG_SSL_OK; } +void mg_ssl_if_conn_close_notify(struct mg_connection *nc) { + /* Nothing to do */ + (void) nc; +} + void mg_ssl_if_conn_free(struct mg_connection *nc) { struct mg_ssl_if_ctx *ctx = (struct mg_ssl_if_ctx *) nc->ssl_if_data; if (ctx == NULL) return; diff --git a/mongoose.h b/mongoose.h index bc8c8c21..5109171d 100644 --- a/mongoose.h +++ b/mongoose.h @@ -3153,6 +3153,7 @@ enum mg_ssl_if_result mg_ssl_if_conn_init( const char **err_msg); enum mg_ssl_if_result mg_ssl_if_conn_accept(struct mg_connection *nc, struct mg_connection *lc); +void mg_ssl_if_conn_close_notify(struct mg_connection *nc); void mg_ssl_if_conn_free(struct mg_connection *nc); enum mg_ssl_if_result mg_ssl_if_handshake(struct mg_connection *nc); From e9a7a2af1800955c808749bf9ed93e30ebd96ea2 Mon Sep 17 00:00:00 2001 From: Alexander Alashkin Date: Fri, 17 Mar 2017 13:26:24 +0200 Subject: [PATCH 022/137] Fix WinCE compilation PUBLISHED_FROM=51d68829414739b04fafc9198d86b817c38d71d2 --- mongoose.h | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/mongoose.h b/mongoose.h index 5109171d..6fdf3bb1 100644 --- a/mongoose.h +++ b/mongoose.h @@ -1235,6 +1235,10 @@ int sl_set_ssl_opts(struct mg_connection *nc); #define EWOULDBLOCK WSAEWOULDBLOCK #endif +#ifndef EAGAIN +#define EAGAIN EWOULDBLOCK +#endif + #ifndef __func__ #define STRX(x) #x #define STR(x) STRX(x) From 380e87ddfac09c59fddb48a300227c1f4ffe6ee0 Mon Sep 17 00:00:00 2001 From: Alexander Alashkin Date: Mon, 20 Mar 2017 09:43:05 +0000 Subject: [PATCH 023/137] Honor DNS server from DHCP PUBLISHED_FROM=10772301ef115c31ada3521ff4235c33a421b782 --- docs/c-api/net.h/struct_mg_connect_opts.md | 1 + docs/c-api/net.h/struct_mg_mgr.md | 1 + docs/c-api/net.h/struct_mg_mgr_init_opts.md | 1 + docs/c-api/resolv.h/intro.md | 1 + docs/c-api/resolv.h/mg_set_nameserver.md | 10 ++++ .../resolv.h/struct_mg_resolve_async_opts.md | 2 +- mongoose.c | 48 ++++++++++++------- mongoose.h | 8 +++- 8 files changed, 54 insertions(+), 18 deletions(-) create mode 100644 docs/c-api/resolv.h/mg_set_nameserver.md diff --git a/docs/c-api/net.h/struct_mg_connect_opts.md b/docs/c-api/net.h/struct_mg_connect_opts.md index f4ef502d..f05bf25f 100644 --- a/docs/c-api/net.h/struct_mg_connect_opts.md +++ b/docs/c-api/net.h/struct_mg_connect_opts.md @@ -8,6 +8,7 @@ signature: | unsigned int flags; /* Extra connection flags */ const char **error_string; /* Placeholder for the error string */ struct mg_iface *iface; /* Interface instance */ + const char *nameserver; /* DNS server to use, NULL for default */ #if MG_ENABLE_SSL /* * SSL settings. diff --git a/docs/c-api/net.h/struct_mg_mgr.md b/docs/c-api/net.h/struct_mg_mgr.md index dcc2b523..63d94633 100644 --- a/docs/c-api/net.h/struct_mg_mgr.md +++ b/docs/c-api/net.h/struct_mg_mgr.md @@ -17,6 +17,7 @@ signature: | #if MG_ENABLE_JAVASCRIPT struct v7 *v7; #endif + const char *nameserver; /* DNS server to use */ }; --- diff --git a/docs/c-api/net.h/struct_mg_mgr_init_opts.md b/docs/c-api/net.h/struct_mg_mgr_init_opts.md index c0b65816..7db23de5 100644 --- a/docs/c-api/net.h/struct_mg_mgr_init_opts.md +++ b/docs/c-api/net.h/struct_mg_mgr_init_opts.md @@ -7,6 +7,7 @@ signature: | const struct mg_iface_vtable *main_iface; int num_ifaces; const struct mg_iface_vtable **ifaces; + const char *nameserver; }; --- diff --git a/docs/c-api/resolv.h/intro.md b/docs/c-api/resolv.h/intro.md index 3fc5fc06..f77184f9 100644 --- a/docs/c-api/resolv.h/intro.md +++ b/docs/c-api/resolv.h/intro.md @@ -6,6 +6,7 @@ items: - { name: mg_resolve_async.md } - { name: mg_resolve_async_opt.md } - { name: mg_resolve_from_hosts_file.md } + - { name: mg_set_nameserver.md } - { name: struct_mg_resolve_async_opts.md } --- diff --git a/docs/c-api/resolv.h/mg_set_nameserver.md b/docs/c-api/resolv.h/mg_set_nameserver.md new file mode 100644 index 00000000..2e33c629 --- /dev/null +++ b/docs/c-api/resolv.h/mg_set_nameserver.md @@ -0,0 +1,10 @@ +--- +title: "mg_set_nameserver()" +decl_name: "mg_set_nameserver" +symbol_kind: "func" +signature: | + void mg_set_nameserver(struct mg_mgr *mgr, const char *nameserver); +--- + +Set default DNS server + diff --git a/docs/c-api/resolv.h/struct_mg_resolve_async_opts.md b/docs/c-api/resolv.h/struct_mg_resolve_async_opts.md index 6c39e2f1..8a836b9a 100644 --- a/docs/c-api/resolv.h/struct_mg_resolve_async_opts.md +++ b/docs/c-api/resolv.h/struct_mg_resolve_async_opts.md @@ -4,7 +4,7 @@ decl_name: "struct mg_resolve_async_opts" symbol_kind: "struct" signature: | struct mg_resolve_async_opts { - const char *nameserver_url; + const char *nameserver; int max_retries; /* defaults to 2 if zero */ int timeout; /* in seconds; defaults to 5 if zero */ int accept_literal; /* pseudo-resolve literal ipv4 and ipv6 addrs */ diff --git a/mongoose.c b/mongoose.c index 3db5e813..4780bdda 100644 --- a/mongoose.c +++ b/mongoose.c @@ -2173,6 +2173,9 @@ void mg_mgr_init_opt(struct mg_mgr *m, void *user_data, m->ifaces[i]->vtable->init(m->ifaces[i]); } } + if (opts.nameserver != NULL) { + m->nameserver = strdup(opts.nameserver); + } DBG(("==================================")); DBG(("init mgr=%p", m)); } @@ -2230,6 +2233,8 @@ void mg_mgr_free(struct mg_mgr *m) { } MG_FREE(m->ifaces); } + + MG_FREE((char *) m->nameserver); } time_t mg_mgr_poll(struct mg_mgr *m, int timeout_ms) { @@ -2742,6 +2747,7 @@ struct mg_connection *mg_connect_opt(struct mg_mgr *mgr, const char *address, struct mg_resolve_async_opts o; memset(&o, 0, sizeof(o)); o.dns_conn = &dns_conn; + o.nameserver = opts.nameserver; if (mg_resolve_async_opt(nc->mgr, host, MG_DNS_A_RECORD, resolve_cb, nc, o) != 0) { MG_SET_PTRPTR(opts.error_string, "cannot schedule DNS lookup"); @@ -10692,10 +10698,6 @@ int mg_dns_reply_record(struct mg_dns_reply *reply, #define MG_DEFAULT_NAMESERVER "8.8.8.8" #endif -static const char *mg_default_dns_server = "udp://" MG_DEFAULT_NAMESERVER ":53"; - -MG_INTERNAL char mg_dns_server[256]; - struct mg_resolve_async_request { char name[1024]; int query; @@ -10755,7 +10757,8 @@ static int mg_get_ip_address_of_nameserver(char *name, size_t name_len) { if (comma != NULL) { *comma = '\0'; } - snprintf(name, name_len, "udp://%S:53", value); + /* %S will convert wchar_t -> char */ + snprintf(name, name_len, "%S", value); ret = 0; RegCloseKey(hSub); break; @@ -10774,7 +10777,7 @@ static int mg_get_ip_address_of_nameserver(char *name, size_t name_len) { for (ret = -1; fgets(line, sizeof(line), fp) != NULL;) { unsigned int a, b, c, d; if (sscanf(line, "nameserver %u.%u.%u.%u", &a, &b, &c, &d) == 4) { - snprintf(name, name_len, "udp://%u.%u.%u.%u:53", a, b, c, d); + snprintf(name, name_len, "%u.%u.%u.%u", a, b, c, d); ret = 0; break; } @@ -10782,7 +10785,7 @@ static int mg_get_ip_address_of_nameserver(char *name, size_t name_len) { (void) fclose(fp); } #else - snprintf(name, name_len, "%s", mg_default_dns_server); + snprintf(name, name_len, "%s", MG_DEFAULT_NAMESERVER); #endif /* _WIN32 */ return ret; @@ -10910,7 +10913,12 @@ int mg_resolve_async_opt(struct mg_mgr *mgr, const char *name, int query, struct mg_resolve_async_opts opts) { struct mg_resolve_async_request *req; struct mg_connection *dns_nc; - const char *nameserver = opts.nameserver_url; + const char *nameserver = opts.nameserver; + char dns_server_buff[17], nameserver_url[26]; + + if (nameserver == NULL) { + nameserver = mgr->nameserver; + } DBG(("%s %d %p", name, query, opts.dns_conn)); @@ -10929,17 +10937,18 @@ int mg_resolve_async_opt(struct mg_mgr *mgr, const char *name, int query, req->timeout = opts.timeout ? opts.timeout : 5; /* Lazily initialize dns server */ - if (nameserver == NULL && mg_dns_server[0] == '\0' && - mg_get_ip_address_of_nameserver(mg_dns_server, sizeof(mg_dns_server)) == - -1) { - strncpy(mg_dns_server, mg_default_dns_server, sizeof(mg_dns_server)); - } - if (nameserver == NULL) { - nameserver = mg_dns_server; + if (mg_get_ip_address_of_nameserver(dns_server_buff, + sizeof(dns_server_buff)) != -1) { + nameserver = dns_server_buff; + } else { + nameserver = MG_DEFAULT_NAMESERVER; + } } - dns_nc = mg_connect(mgr, nameserver, MG_CB(mg_resolve_async_eh, NULL)); + snprintf(nameserver_url, sizeof(nameserver_url), "udp://%s:53", nameserver); + + dns_nc = mg_connect(mgr, nameserver_url, MG_CB(mg_resolve_async_eh, NULL)); if (dns_nc == NULL) { free(req); return -1; @@ -10952,6 +10961,13 @@ int mg_resolve_async_opt(struct mg_mgr *mgr, const char *name, int query, return 0; } +void mg_set_nameserver(struct mg_mgr *mgr, const char *nameserver) { + free((char *) mgr->nameserver); + if (nameserver != NULL) { + mgr->nameserver = strdup(nameserver); + } +} + #endif /* MG_ENABLE_ASYNC_RESOLVER */ #ifdef MG_MODULE_LINES #line 1 "mongoose/src/coap.c" diff --git a/mongoose.h b/mongoose.h index 6fdf3bb1..6b37f418 100644 --- a/mongoose.h +++ b/mongoose.h @@ -3274,6 +3274,7 @@ struct mg_mgr { #if MG_ENABLE_JAVASCRIPT struct v7 *v7; #endif + const char *nameserver; /* DNS server to use */ }; /* @@ -3368,6 +3369,7 @@ struct mg_mgr_init_opts { const struct mg_iface_vtable *main_iface; int num_ifaces; const struct mg_iface_vtable **ifaces; + const char *nameserver; }; /* @@ -3538,6 +3540,7 @@ struct mg_connect_opts { unsigned int flags; /* Extra connection flags */ const char **error_string; /* Placeholder for the error string */ struct mg_iface *iface; /* Interface instance */ + const char *nameserver; /* DNS server to use, NULL for default */ #if MG_ENABLE_SSL /* * SSL settings. @@ -5609,7 +5612,7 @@ typedef void (*mg_resolve_callback_t)(struct mg_dns_message *dns_message, /* Options for `mg_resolve_async_opt`. */ struct mg_resolve_async_opts { - const char *nameserver_url; + const char *nameserver; int max_retries; /* defaults to 2 if zero */ int timeout; /* in seconds; defaults to 5 if zero */ int accept_literal; /* pseudo-resolve literal ipv4 and ipv6 addrs */ @@ -5621,6 +5624,9 @@ struct mg_resolve_async_opts { int mg_resolve_async(struct mg_mgr *mgr, const char *name, int query, mg_resolve_callback_t cb, void *data); +/* Set default DNS server */ +void mg_set_nameserver(struct mg_mgr *mgr, const char *nameserver); + /* * Resolved a DNS name asynchronously. * From 066be0fe3099e8bb0aee540881c4793988d18fbd Mon Sep 17 00:00:00 2001 From: Alexander Alashkin Date: Mon, 20 Mar 2017 10:41:42 +0000 Subject: [PATCH 024/137] Add ajax_upload example PUBLISHED_FROM=c5691d4321fff2e03f689b0195abd1ec6a188418 --- examples/ajax_upload/Makefile | 3 ++ examples/ajax_upload/ajax_upload.c | 85 ++++++++++++++++++++++++++++++ examples/ajax_upload/index.html | 47 +++++++++++++++++ 3 files changed, 135 insertions(+) create mode 100644 examples/ajax_upload/Makefile create mode 100644 examples/ajax_upload/ajax_upload.c create mode 100644 examples/ajax_upload/index.html diff --git a/examples/ajax_upload/Makefile b/examples/ajax_upload/Makefile new file mode 100644 index 00000000..678f6ba6 --- /dev/null +++ b/examples/ajax_upload/Makefile @@ -0,0 +1,3 @@ +PROG = ajax_upload +MODULE_CFLAGS = -DMG_ENABLE_HTTP_STREAMING_MULTIPART +include ../examples.mk diff --git a/examples/ajax_upload/ajax_upload.c b/examples/ajax_upload/ajax_upload.c new file mode 100644 index 00000000..662aa2d6 --- /dev/null +++ b/examples/ajax_upload/ajax_upload.c @@ -0,0 +1,85 @@ +// Copyright (c) 2017 Cesanta Software Limited +// All rights reserved + +#include "mongoose.h" + +static const char *s_http_port = "8000"; +static struct mg_serve_http_opts s_http_server_opts; + +static void ev_handler(struct mg_connection *nc, int ev, void *p) { + if (ev == MG_EV_HTTP_REQUEST) { + mg_serve_http(nc, (struct http_message *) p, s_http_server_opts); + } +} + +static void upload_handler(struct mg_connection *nc, int ev, void *p) { + (void) nc; + struct http_message *hm = (struct http_message *) p; + if (ev == MG_EV_HTTP_REQUEST) { + char file_name[256]; + FILE *f = NULL; + if (mg_get_http_var(&hm->query_string, "file_name", file_name, + sizeof(file_name)) <= 0) { + mg_printf(nc, "%s", + "HTTP/1.1 500 File name is not specified\r\n" + "Content-Length: 0\r\n\r\n"); + nc->flags |= MG_F_SEND_AND_CLOSE; + goto cleanup; + } + printf("Saving file %s, size %d bytes\n", file_name, (int) hm->body.len); + f = fopen(file_name, "w"); + if (f == NULL) { + mg_printf(nc, "%s", + "HTTP/1.1 500 Failed to open a file\r\n" + "Content-Length: 0\r\n\r\n"); + nc->flags |= MG_F_SEND_AND_CLOSE; + goto cleanup; + } + if (fwrite(hm->body.p, 1, hm->body.len, f) != hm->body.len) { + mg_printf(nc, "%s", + "HTTP/1.1 500 Failed to write to a file\r\n" + "Content-Length: 0\r\n\r\n"); + nc->flags |= MG_F_SEND_AND_CLOSE; + goto cleanup; + } + mg_printf(nc, "%s", + "HTTP/1.1 200 OK\r\n" + "Content-Type: text/html\r\n" + "Connection: close\r\n" + "\r\n" + "File upload successfully"); + nc->flags |= MG_F_SEND_AND_CLOSE; + printf("Done.\n"); + cleanup: + if (f != NULL) { + fclose(f); + } + } +} + +int main(void) { + struct mg_mgr mgr; + struct mg_connection *nc; + + mg_mgr_init(&mgr, NULL); + printf("Starting web server on port %s\n", s_http_port); + nc = mg_bind(&mgr, s_http_port, ev_handler); + if (nc == NULL) { + printf("Failed to create listener\n"); + return 1; + } + + mg_register_http_endpoint(nc, "/upload", upload_handler MG_UD_ARG(NULL)); + + // Set up HTTP server parameters + mg_set_protocol_http_websocket(nc); + s_http_server_opts.document_root = "."; // Serve current directory + s_http_server_opts.enable_directory_listing = "yes"; + + for (;;) { + mg_mgr_poll(&mgr, 1000); + } + mg_mgr_free(&mgr); + + return 0; +} diff --git a/examples/ajax_upload/index.html b/examples/ajax_upload/index.html new file mode 100644 index 00000000..c6e1ccb9 --- /dev/null +++ b/examples/ajax_upload/index.html @@ -0,0 +1,47 @@ + + + + AJAX Upload Example + + + + + +
+
+ + +
+

+ + From aab857a66e78251222552d709ade9c99b4ca673d Mon Sep 17 00:00:00 2001 From: Alexander Alashkin Date: Mon, 20 Mar 2017 16:45:57 +0000 Subject: [PATCH 025/137] Add ajax_upload to big_upload PUBLISHED_FROM=7c919ba3a2afa74cec9947e78299b4bb7a64b4bc --- .../big_upload/ajax_upload_demo/index.html | 45 +++++++++++++++++++ examples/big_upload/big_upload.c | 40 ++++++++++++++--- 2 files changed, 80 insertions(+), 5 deletions(-) create mode 100644 examples/big_upload/ajax_upload_demo/index.html diff --git a/examples/big_upload/ajax_upload_demo/index.html b/examples/big_upload/ajax_upload_demo/index.html new file mode 100644 index 00000000..9ba5d63c --- /dev/null +++ b/examples/big_upload/ajax_upload_demo/index.html @@ -0,0 +1,45 @@ + + + + AJAX Upload Example + + + + + +
+
+ + +
+

+ + diff --git a/examples/big_upload/big_upload.c b/examples/big_upload/big_upload.c index 682a0c31..5514d7b7 100644 --- a/examples/big_upload/big_upload.c +++ b/examples/big_upload/big_upload.c @@ -10,6 +10,7 @@ #include "mongoose.h" static const char *s_http_port = "8000"; +static struct mg_serve_http_opts s_http_server_opts; struct file_writer_data { FILE *fp; @@ -83,11 +84,33 @@ static void handle_upload(struct mg_connection *nc, int ev, void *p) { static void ev_handler(struct mg_connection *nc, int ev, void *ev_data) { (void) ev_data; - switch (ev) { - case MG_EV_HTTP_REQUEST: - // Invoked when the full HTTP request is in the buffer (including body). - handle_request(nc); - break; + if (ev == MG_EV_HTTP_REQUEST) { + mg_printf(nc, "%s", + "HTTP/1.1 200 OK\r\n" + "Content-Type: text/html\r\n" + "Connection: close\r\n" + "\r\n" + "Upload example." + "Navigate to /simple_upload_demo for " + "uploading using submit " + "or to /ajax_upload_demo for " + "uploading using ajax" + ""); + nc->flags |= MG_F_SEND_AND_CLOSE; + } +} + +static void upload_demo_handler(struct mg_connection *nc, int ev, void *p) { + if (ev == MG_EV_HTTP_REQUEST) { + (void) p; + handle_request(nc); + } +} + +static void ajax_demo_handler(struct mg_connection *nc, int ev, void *p) { + if (ev == MG_EV_HTTP_REQUEST) { + mg_serve_http(nc, (struct http_message *) p, s_http_server_opts); } } @@ -98,7 +121,14 @@ int main(void) { mg_mgr_init(&mgr, NULL); nc = mg_bind(&mgr, s_http_port, ev_handler); + s_http_server_opts.document_root = "."; // Serve current directory + mg_register_http_endpoint(nc, "/upload", handle_upload MG_UD_ARG(NULL)); + mg_register_http_endpoint(nc, "/ajax_upload_demo", + ajax_demo_handler MG_UD_ARG(NULL)); + mg_register_http_endpoint(nc, "/simple_upload_demo", + upload_demo_handler MG_UD_ARG(NULL)); + // Set up HTTP server parameters mg_set_protocol_http_websocket(nc); From ceb2f1da41d1876132b0753291f57ecf4bee5df8 Mon Sep 17 00:00:00 2001 From: Sergey Lyubka Date: Mon, 20 Mar 2017 17:14:39 +0000 Subject: [PATCH 026/137] Update upload example PUBLISHED_FROM=a28c1da3f0dd597792439246313ca39984ab7536 --- examples/big_upload/big_upload.c | 61 +++---------------- .../{ajax_upload_demo => }/index.html | 9 +++ 2 files changed, 18 insertions(+), 52 deletions(-) rename examples/big_upload/{ajax_upload_demo => }/index.html (80%) diff --git a/examples/big_upload/big_upload.c b/examples/big_upload/big_upload.c index 5514d7b7..56343650 100644 --- a/examples/big_upload/big_upload.c +++ b/examples/big_upload/big_upload.c @@ -17,22 +17,6 @@ struct file_writer_data { size_t bytes_written; }; -static void handle_request(struct mg_connection *nc) { - // This handler gets for all endpoints but /upload - mg_printf(nc, "%s", - "HTTP/1.1 200 OK\r\n" - "Content-Type: text/html\r\n" - "Connection: close\r\n" - "\r\n" - "Upload example." - "
" - "
" - "" - "
"); - nc->flags |= MG_F_SEND_AND_CLOSE; -} - static void handle_upload(struct mg_connection *nc, int ev, void *p) { struct file_writer_data *data = (struct file_writer_data *) nc->user_data; struct mg_http_multipart_part *mp = (struct mg_http_multipart_part *) p; @@ -83,54 +67,27 @@ static void handle_upload(struct mg_connection *nc, int ev, void *p) { } static void ev_handler(struct mg_connection *nc, int ev, void *ev_data) { - (void) ev_data; if (ev == MG_EV_HTTP_REQUEST) { - mg_printf(nc, "%s", - "HTTP/1.1 200 OK\r\n" - "Content-Type: text/html\r\n" - "Connection: close\r\n" - "\r\n" - "Upload example." - "Navigate to /simple_upload_demo for " - "uploading using submit " - "or to /ajax_upload_demo for " - "uploading using ajax" - ""); - nc->flags |= MG_F_SEND_AND_CLOSE; - } -} - -static void upload_demo_handler(struct mg_connection *nc, int ev, void *p) { - if (ev == MG_EV_HTTP_REQUEST) { - (void) p; - handle_request(nc); - } -} - -static void ajax_demo_handler(struct mg_connection *nc, int ev, void *p) { - if (ev == MG_EV_HTTP_REQUEST) { - mg_serve_http(nc, (struct http_message *) p, s_http_server_opts); + mg_serve_http(nc, ev_data, s_http_server_opts); } } int main(void) { struct mg_mgr mgr; - struct mg_connection *nc; + struct mg_connection *c; mg_mgr_init(&mgr, NULL); - nc = mg_bind(&mgr, s_http_port, ev_handler); + c = mg_bind(&mgr, s_http_port, ev_handler); + if (c == NULL) { + fprintf(stderr, "Cannot start server on port %s\n", s_http_port); + exit(EXIT_FAILURE); + } s_http_server_opts.document_root = "."; // Serve current directory - - mg_register_http_endpoint(nc, "/upload", handle_upload MG_UD_ARG(NULL)); - mg_register_http_endpoint(nc, "/ajax_upload_demo", - ajax_demo_handler MG_UD_ARG(NULL)); - mg_register_http_endpoint(nc, "/simple_upload_demo", - upload_demo_handler MG_UD_ARG(NULL)); + mg_register_http_endpoint(c, "/upload", handle_upload MG_UD_ARG(NULL)); // Set up HTTP server parameters - mg_set_protocol_http_websocket(nc); + mg_set_protocol_http_websocket(c); printf("Starting web server on port %s\n", s_http_port); for (;;) { diff --git a/examples/big_upload/ajax_upload_demo/index.html b/examples/big_upload/index.html similarity index 80% rename from examples/big_upload/ajax_upload_demo/index.html rename to examples/big_upload/index.html index 9ba5d63c..c162c653 100644 --- a/examples/big_upload/ajax_upload_demo/index.html +++ b/examples/big_upload/index.html @@ -35,6 +35,15 @@ +

Upload file using standard form upload

+ +
+
+ + +
+ +

Upload file using Ajax - that also gives progress report


From ec752645ee0cc3c7fd738ff6ac5b3b6f480fa97c Mon Sep 17 00:00:00 2001 From: Alexander Alashkin Date: Tue, 21 Mar 2017 07:24:36 +0000 Subject: [PATCH 027/137] Remove ajax_upload PUBLISHED_FROM=599ccd99e7bf422cac5e8b1f5ccebe3cac2780e8 --- examples/ajax_upload/Makefile | 3 -- examples/ajax_upload/ajax_upload.c | 85 ------------------------------ examples/ajax_upload/index.html | 47 ----------------- 3 files changed, 135 deletions(-) delete mode 100644 examples/ajax_upload/Makefile delete mode 100644 examples/ajax_upload/ajax_upload.c delete mode 100644 examples/ajax_upload/index.html diff --git a/examples/ajax_upload/Makefile b/examples/ajax_upload/Makefile deleted file mode 100644 index 678f6ba6..00000000 --- a/examples/ajax_upload/Makefile +++ /dev/null @@ -1,3 +0,0 @@ -PROG = ajax_upload -MODULE_CFLAGS = -DMG_ENABLE_HTTP_STREAMING_MULTIPART -include ../examples.mk diff --git a/examples/ajax_upload/ajax_upload.c b/examples/ajax_upload/ajax_upload.c deleted file mode 100644 index 662aa2d6..00000000 --- a/examples/ajax_upload/ajax_upload.c +++ /dev/null @@ -1,85 +0,0 @@ -// Copyright (c) 2017 Cesanta Software Limited -// All rights reserved - -#include "mongoose.h" - -static const char *s_http_port = "8000"; -static struct mg_serve_http_opts s_http_server_opts; - -static void ev_handler(struct mg_connection *nc, int ev, void *p) { - if (ev == MG_EV_HTTP_REQUEST) { - mg_serve_http(nc, (struct http_message *) p, s_http_server_opts); - } -} - -static void upload_handler(struct mg_connection *nc, int ev, void *p) { - (void) nc; - struct http_message *hm = (struct http_message *) p; - if (ev == MG_EV_HTTP_REQUEST) { - char file_name[256]; - FILE *f = NULL; - if (mg_get_http_var(&hm->query_string, "file_name", file_name, - sizeof(file_name)) <= 0) { - mg_printf(nc, "%s", - "HTTP/1.1 500 File name is not specified\r\n" - "Content-Length: 0\r\n\r\n"); - nc->flags |= MG_F_SEND_AND_CLOSE; - goto cleanup; - } - printf("Saving file %s, size %d bytes\n", file_name, (int) hm->body.len); - f = fopen(file_name, "w"); - if (f == NULL) { - mg_printf(nc, "%s", - "HTTP/1.1 500 Failed to open a file\r\n" - "Content-Length: 0\r\n\r\n"); - nc->flags |= MG_F_SEND_AND_CLOSE; - goto cleanup; - } - if (fwrite(hm->body.p, 1, hm->body.len, f) != hm->body.len) { - mg_printf(nc, "%s", - "HTTP/1.1 500 Failed to write to a file\r\n" - "Content-Length: 0\r\n\r\n"); - nc->flags |= MG_F_SEND_AND_CLOSE; - goto cleanup; - } - mg_printf(nc, "%s", - "HTTP/1.1 200 OK\r\n" - "Content-Type: text/html\r\n" - "Connection: close\r\n" - "\r\n" - "File upload successfully"); - nc->flags |= MG_F_SEND_AND_CLOSE; - printf("Done.\n"); - cleanup: - if (f != NULL) { - fclose(f); - } - } -} - -int main(void) { - struct mg_mgr mgr; - struct mg_connection *nc; - - mg_mgr_init(&mgr, NULL); - printf("Starting web server on port %s\n", s_http_port); - nc = mg_bind(&mgr, s_http_port, ev_handler); - if (nc == NULL) { - printf("Failed to create listener\n"); - return 1; - } - - mg_register_http_endpoint(nc, "/upload", upload_handler MG_UD_ARG(NULL)); - - // Set up HTTP server parameters - mg_set_protocol_http_websocket(nc); - s_http_server_opts.document_root = "."; // Serve current directory - s_http_server_opts.enable_directory_listing = "yes"; - - for (;;) { - mg_mgr_poll(&mgr, 1000); - } - mg_mgr_free(&mgr); - - return 0; -} diff --git a/examples/ajax_upload/index.html b/examples/ajax_upload/index.html deleted file mode 100644 index c6e1ccb9..00000000 --- a/examples/ajax_upload/index.html +++ /dev/null @@ -1,47 +0,0 @@ - - - - AJAX Upload Example - - - - - - -
- - - -

- - From 14094aaef70ce535984702ff6507e23486e0d47b Mon Sep 17 00:00:00 2001 From: Yiming Sun Date: Tue, 21 Mar 2017 10:37:38 +0200 Subject: [PATCH 028/137] Fix typo PUBLISHED_FROM=56fdeaf4965ef26c398267c8656735bb52e45085 --- docs/c-api/http_server.h/mg_send_http_chunk.md | 2 +- mongoose.h | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/c-api/http_server.h/mg_send_http_chunk.md b/docs/c-api/http_server.h/mg_send_http_chunk.md index 2ce64a1a..6a2a4d83 100644 --- a/docs/c-api/http_server.h/mg_send_http_chunk.md +++ b/docs/c-api/http_server.h/mg_send_http_chunk.md @@ -9,7 +9,7 @@ signature: | Sends buffer `buf` of size `len` to the client using chunked HTTP encoding. This function sends the buffer size as hex number + newline first, then the buffer itself, then the newline. For example, -`mg_send_http_chunk(nc, "foo", 3)` whill append the `3\r\nfoo\r\n` string +`mg_send_http_chunk(nc, "foo", 3)` will append the `3\r\nfoo\r\n` string to the `nc->send_mbuf` output IO buffer. NOTE: The HTTP header "Transfer-Encoding: chunked" should be sent prior to diff --git a/mongoose.h b/mongoose.h index 6b37f418..22a85666 100644 --- a/mongoose.h +++ b/mongoose.h @@ -4814,7 +4814,7 @@ int mg_http_check_digest_auth(struct http_message *hm, const char *auth_domain, * Sends buffer `buf` of size `len` to the client using chunked HTTP encoding. * This function sends the buffer size as hex number + newline first, then * the buffer itself, then the newline. For example, - * `mg_send_http_chunk(nc, "foo", 3)` whill append the `3\r\nfoo\r\n` string + * `mg_send_http_chunk(nc, "foo", 3)` will append the `3\r\nfoo\r\n` string * to the `nc->send_mbuf` output IO buffer. * * NOTE: The HTTP header "Transfer-Encoding: chunked" should be sent prior to From 2fb145d39d87c7ef36c12c47881fa259f28b2ce3 Mon Sep 17 00:00:00 2001 From: Alexander Alashkin Date: Tue, 21 Mar 2017 10:09:02 +0000 Subject: [PATCH 029/137] Fix DISABLE_MD5 and DISABLE_SHA1 naming PUBLISHED_FROM=2babde0d0c6add14aa500f4bf1c833715d979c6c --- docs/overview/build-options/disabling-flags.md | 4 ++-- examples/nRF51/http/boards/pca10028/armgcc/Makefile | 8 ++++---- examples/nRF52/http/boards/pca10040/armgcc/Makefile | 8 ++++---- mongoose.c | 6 +++--- mongoose.h | 12 ++++++------ 5 files changed, 19 insertions(+), 19 deletions(-) diff --git a/docs/overview/build-options/disabling-flags.md b/docs/overview/build-options/disabling-flags.md index 8633083f..767438fe 100644 --- a/docs/overview/build-options/disabling-flags.md +++ b/docs/overview/build-options/disabling-flags.md @@ -3,6 +3,6 @@ title: Disabling flags --- - `MG_DISABLE_HTTP_DIGEST_AUTH` disable HTTP Digest (MD5) authorisation support -- `MG_DISABLE_SHA1` disable SHA1 support (used by WebSocket) -- `MG_DISABLE_MD5` disable MD5 support (used by HTTP auth) +- `CS_DISABLE_SHA1` disable SHA1 support (used by WebSocket) +- `CS_DISABLE_MD5` disable MD5 support (used by HTTP auth) - `MG_DISABLE_HTTP_KEEP_ALIVE` useful for embedded systems to save resources diff --git a/examples/nRF51/http/boards/pca10028/armgcc/Makefile b/examples/nRF51/http/boards/pca10028/armgcc/Makefile index d2cde039..07534aa2 100644 --- a/examples/nRF51/http/boards/pca10028/armgcc/Makefile +++ b/examples/nRF51/http/boards/pca10028/armgcc/Makefile @@ -3,7 +3,7 @@ PROJECT_NAME := iot_lwip_tcp_server_pca10028 export OUTPUT_FILENAME #MAKEFILE_NAME := $(CURDIR)/$(word $(words $(MAKEFILE_LIST)),$(MAKEFILE_LIST)) MAKEFILE_NAME := $(MAKEFILE_LIST) -MAKEFILE_DIR := $(dir $(MAKEFILE_NAME) ) +MAKEFILE_DIR := $(dir $(MAKEFILE_NAME) ) TEMPLATE_PATH = ../../../../nrf51_iot_sdk/components/toolchain/gcc ifeq ($(OS),Windows_NT) @@ -17,7 +17,7 @@ RM := rm -rf #echo suspend ifeq ("$(VERBOSE)","1") -NO_ECHO := +NO_ECHO := else NO_ECHO := @ endif @@ -118,7 +118,7 @@ BUILD_DIRECTORIES := $(sort $(OBJECT_DIRECTORY) $(OUTPUT_BINARY_DIRECTORY) $(LIS # Mongoose features MG_FEATURES_TINY = \ -DMG_DISABLE_HTTP_DIGEST_AUTH \ - -DMG_DISABLE_MD5 \ + -DCS_DISABLE_MD5 \ -DMG_DISABLE_HTTP_KEEP_ALIVE \ -DMG_ENABLE_HTTP_SSI=0 \ -DMG_ENABLE_HTTP_STREAMING_MULTIPART @@ -251,7 +251,7 @@ genbin: $(NO_ECHO)$(OBJCOPY) -O binary $(OUTPUT_BINARY_DIRECTORY)/$(OUTPUT_FILENAME).out $(OUTPUT_BINARY_DIRECTORY)/$(OUTPUT_FILENAME).bin ## Create binary .hex file from the .out file -genhex: +genhex: @echo Preparing: $(OUTPUT_FILENAME).hex $(NO_ECHO)$(OBJCOPY) -O ihex $(OUTPUT_BINARY_DIRECTORY)/$(OUTPUT_FILENAME).out $(OUTPUT_BINARY_DIRECTORY)/$(OUTPUT_FILENAME).hex diff --git a/examples/nRF52/http/boards/pca10040/armgcc/Makefile b/examples/nRF52/http/boards/pca10040/armgcc/Makefile index 073af2b8..bd2aa6cc 100644 --- a/examples/nRF52/http/boards/pca10040/armgcc/Makefile +++ b/examples/nRF52/http/boards/pca10040/armgcc/Makefile @@ -3,7 +3,7 @@ PROJECT_NAME := iot_lwip_tcp_server_pca10040 export OUTPUT_FILENAME #MAKEFILE_NAME := $(CURDIR)/$(word $(words $(MAKEFILE_LIST)),$(MAKEFILE_LIST)) MAKEFILE_NAME := $(MAKEFILE_LIST) -MAKEFILE_DIR := $(dir $(MAKEFILE_NAME) ) +MAKEFILE_DIR := $(dir $(MAKEFILE_NAME) ) TEMPLATE_PATH = ../../../../nrf5_iot_sdk/components/toolchain/gcc ifeq ($(OS),Windows_NT) @@ -17,7 +17,7 @@ RM := rm -rf #echo suspend ifeq ("$(VERBOSE)","1") -NO_ECHO := +NO_ECHO := else NO_ECHO := @ endif @@ -165,7 +165,7 @@ BUILD_DIRECTORIES := $(sort $(OBJECT_DIRECTORY) $(OUTPUT_BINARY_DIRECTORY) $(LIS # Mongoose features MG_FEATURES_TINY = \ -DMG_DISABLE_HTTP_DIGEST_AUTH \ - -DMG_DISABLE_MD5 \ + -DCS_DISABLE_MD5 \ -DMG_DISABLE_HTTP_KEEP_ALIVE \ -DMG_ENABLE_HTTP_SSI=0 \ -DMG_ENABLE_HTTP_STREAMING_MULTIPART @@ -297,7 +297,7 @@ genbin: $(NO_ECHO)$(OBJCOPY) -O binary $(OUTPUT_BINARY_DIRECTORY)/$(OUTPUT_FILENAME).out $(OUTPUT_BINARY_DIRECTORY)/$(OUTPUT_FILENAME).bin ## Create binary .hex file from the .out file -genhex: +genhex: @echo Preparing: $(OUTPUT_FILENAME).hex $(NO_ECHO)$(OBJCOPY) -O ihex $(OUTPUT_BINARY_DIRECTORY)/$(OUTPUT_FILENAME).out $(OUTPUT_BINARY_DIRECTORY)/$(OUTPUT_FILENAME).hex echosize: diff --git a/mongoose.c b/mongoose.c index 4780bdda..43c7c905 100644 --- a/mongoose.c +++ b/mongoose.c @@ -793,7 +793,7 @@ double cs_time(void) { /* Amalgamated: #include "common/str_util.h" */ #if !defined(EXCLUDE_COMMON) -#if !DISABLE_MD5 +#if !CS_DISABLE_MD5 /* Amalgamated: #include "common/cs_endian.h" */ @@ -980,7 +980,7 @@ void MD5_Final(unsigned char digest[16], MD5_CTX *ctx) { memcpy(digest, ctx->buf, 16); memset((char *) ctx, 0, sizeof(*ctx)); } -#endif /* DISABLE_MD5 */ +#endif /* CS_DISABLE_MD5 */ char *cs_md5(char buf[33], ...) { unsigned char hash[16]; @@ -1203,7 +1203,7 @@ int mg_strncmp(const struct mg_str str1, const struct mg_str str2, size_t n) { /* Amalgamated: #include "common/sha1.h" */ -#if !DISABLE_SHA1 && !defined(EXCLUDE_COMMON) +#if !CS_DISABLE_SHA1 && !defined(EXCLUDE_COMMON) /* Amalgamated: #include "common/cs_endian.h" */ diff --git a/mongoose.h b/mongoose.h index 22a85666..5b17bdbf 100644 --- a/mongoose.h +++ b/mongoose.h @@ -1802,11 +1802,11 @@ void mbuf_trim(struct mbuf *); #ifndef CS_COMMON_SHA1_H_ #define CS_COMMON_SHA1_H_ -#ifndef DISABLE_SHA1 -#define DISABLE_SHA1 0 +#ifndef CS_DISABLE_SHA1 +#define CS_DISABLE_SHA1 0 #endif -#if !DISABLE_SHA1 +#if !CS_DISABLE_SHA1 /* Amalgamated: #include "common/platform.h" */ @@ -1830,7 +1830,7 @@ void cs_hmac_sha1(const unsigned char *key, size_t key_len, } #endif /* __cplusplus */ -#endif /* DISABLE_SHA1 */ +#endif /* CS_DISABLE_SHA1 */ #endif /* CS_COMMON_SHA1_H_ */ #ifdef MG_MODULE_LINES @@ -1846,8 +1846,8 @@ void cs_hmac_sha1(const unsigned char *key, size_t key_len, /* Amalgamated: #include "common/platform.h" */ -#ifndef DISABLE_MD5 -#define DISABLE_MD5 0 +#ifndef CS_DISABLE_MD5 +#define CS_DISABLE_MD5 0 #endif #ifdef __cplusplus From d9243d1c0b1e895e6cebf3971162efcdd79e9214 Mon Sep 17 00:00:00 2001 From: benrubson Date: Tue, 21 Mar 2017 12:40:29 +0200 Subject: [PATCH 030/137] Fix MD5 disabling PUBLISHED_FROM=bb03593fb2abfb79daa3118b786428ee3e693e3d --- mongoose.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mongoose.c b/mongoose.c index 43c7c905..fe7f25c0 100644 --- a/mongoose.c +++ b/mongoose.c @@ -980,7 +980,6 @@ void MD5_Final(unsigned char digest[16], MD5_CTX *ctx) { memcpy(digest, ctx->buf, 16); memset((char *) ctx, 0, sizeof(*ctx)); } -#endif /* CS_DISABLE_MD5 */ char *cs_md5(char buf[33], ...) { unsigned char hash[16]; @@ -1003,6 +1002,7 @@ char *cs_md5(char buf[33], ...) { return buf; } +#endif /* CS_DISABLE_MD5 */ #endif /* EXCLUDE_COMMON */ #ifdef MG_MODULE_LINES #line 1 "common/mbuf.c" From df5fff5e72f012b20da55151940fd1cf7ea32edb Mon Sep 17 00:00:00 2001 From: David Hargat Date: Thu, 23 Mar 2017 20:39:57 +0200 Subject: [PATCH 031/137] Consistent MG_MALLOC, MG_REALLOC and MG_FREE calls PUBLISHED_FROM=e7f306b5d1a1366d3ec71fa238c5e18c03aadf8d --- mongoose.c | 144 ++++++++++++++++++++++++++++------------------------- 1 file changed, 77 insertions(+), 67 deletions(-) diff --git a/mongoose.c b/mongoose.c index fe7f25c0..fd1068ed 100644 --- a/mongoose.c +++ b/mongoose.c @@ -10,21 +10,7 @@ #ifndef CS_MONGOOSE_SRC_INTERNAL_H_ #define CS_MONGOOSE_SRC_INTERNAL_H_ -#ifndef MG_MALLOC -#define MG_MALLOC malloc -#endif - -#ifndef MG_CALLOC -#define MG_CALLOC calloc -#endif - -#ifndef MG_REALLOC -#define MG_REALLOC realloc -#endif - -#ifndef MG_FREE -#define MG_FREE free -#endif +/* Amalgamated: #include "common/mg_mem.h" */ #ifndef MBUF_REALLOC #define MBUF_REALLOC MG_REALLOC @@ -179,6 +165,34 @@ MG_INTERNAL int mg_sntp_parse_reply(const char *buf, int len, #endif /* CS_MONGOOSE_SRC_INTERNAL_H_ */ #ifdef MG_MODULE_LINES +#line 1 "common/mg_mem.h" +#endif +/* + * Copyright (c) 2014-2016 Cesanta Software Limited + * All rights reserved + */ + +#ifndef CS_COMMON_MG_MEM_H_ +#define CS_COMMON_MG_MEM_H_ + +#ifndef MG_MALLOC +#define MG_MALLOC malloc +#endif + +#ifndef MG_CALLOC +#define MG_CALLOC calloc +#endif + +#ifndef MG_REALLOC +#define MG_REALLOC realloc +#endif + +#ifndef MG_FREE +#define MG_FREE free +#endif + +#endif /* CS_COMMON_MG_MEM_H_ */ +#ifdef MG_MODULE_LINES #line 1 "common/cs_dbg.h" #endif /* @@ -595,6 +609,7 @@ struct dirent *readdir(DIR *dir); #ifndef EXCLUDE_COMMON +/* Amalgamated: #include "common/mg_mem.h" */ /* Amalgamated: #include "common/cs_dirent.h" */ /* @@ -602,14 +617,6 @@ struct dirent *readdir(DIR *dir); * for systems which do not natively support it (e.g. Windows). */ -#ifndef MG_FREE -#define MG_FREE free -#endif - -#ifndef MG_MALLOC -#define MG_MALLOC malloc -#endif - #ifdef _WIN32 struct win32_dir { DIR d; @@ -1116,6 +1123,7 @@ void mbuf_remove(struct mbuf *mb, size_t n) { * All rights reserved */ +/* Amalgamated: #include "common/mg_mem.h" */ /* Amalgamated: #include "common/mg_str.h" */ #include @@ -1160,7 +1168,7 @@ struct mg_str mg_strdup(const struct mg_str s) WEAK; struct mg_str mg_strdup(const struct mg_str s) { struct mg_str r = {NULL, 0}; if (s.len > 0 && s.p != NULL) { - r.p = (char *) malloc(s.len); + r.p = (char *) MG_MALLOC(s.len); if (r.p != NULL) { memcpy((char *) r.p, s.p, s.len); r.len = s.len; @@ -1468,13 +1476,7 @@ void cs_hmac_sha1(const unsigned char *key, size_t keylen, #define C_DISABLE_BUILTIN_SNPRINTF 0 #endif -#ifndef MG_MALLOC -#define MG_MALLOC malloc -#endif - -#ifndef MG_FREE -#define MG_FREE free -#endif +/* Amalgamated: #include "common/mg_mem.h" */ size_t c_strnlen(const char *s, size_t maxlen) WEAK; size_t c_strnlen(const char *s, size_t maxlen) { @@ -1740,7 +1742,7 @@ const char *c_strnstr(const char *s, const char *find, size_t slen) { char *strdup(const char *src) WEAK; char *strdup(const char *src) { size_t len = strlen(src) + 1; - char *ret = malloc(len); + char *ret = MG_MALLOC(len); if (ret != NULL) { strcpy(ret, src); } @@ -5114,9 +5116,9 @@ static struct mg_http_proto_data *mg_http_get_proto_data( #if MG_ENABLE_HTTP_STREAMING_MULTIPART static void mg_http_free_proto_data_mp_stream( struct mg_http_multipart_stream *mp) { - free((void *) mp->boundary); - free((void *) mp->var_name); - free((void *) mp->file_name); + MG_FREE((void *) mp->boundary); + MG_FREE((void *) mp->var_name); + MG_FREE((void *) mp->file_name); memset(mp, 0, sizeof(*mp)); } #endif @@ -5137,8 +5139,8 @@ static void mg_http_free_proto_data_endpoints(struct mg_http_endpoint **ep) { while (current != NULL) { struct mg_http_endpoint *tmp = current->next; - free((void *) current->name); - free(current); + MG_FREE((void *) current->name); + MG_FREE(current); current = tmp; } @@ -5174,7 +5176,7 @@ static void mg_http_conn_destructor(void *proto_data) { #endif mg_http_free_proto_data_endpoints(&pd->endpoints); mg_http_free_reverse_proxy_data(&pd->reverse_proxy_data); - free(proto_data); + MG_FREE(proto_data); } #if MG_ENABLE_FILESYSTEM @@ -5942,9 +5944,9 @@ static int mg_http_multipart_finalize(struct mg_connection *c) { struct mg_http_proto_data *pd = mg_http_get_proto_data(c); mg_http_multipart_call_handler(c, MG_EV_HTTP_PART_END, NULL, 0); - free((void *) pd->mp_stream.file_name); + MG_FREE((void *) pd->mp_stream.file_name); pd->mp_stream.file_name = NULL; - free((void *) pd->mp_stream.var_name); + MG_FREE((void *) pd->mp_stream.var_name); pd->mp_stream.var_name = NULL; mg_http_multipart_call_handler(c, MG_EV_HTTP_MULTIPART_REQUEST_END, NULL, 0); mg_http_free_proto_data_mp_stream(&pd->mp_stream); @@ -6016,9 +6018,9 @@ static int mg_http_multipart_process_boundary(struct mg_connection *c) { mg_http_multipart_call_handler(c, MG_EV_HTTP_PART_END, NULL, 0); } - free((void *) pd->mp_stream.file_name); + MG_FREE((void *) pd->mp_stream.file_name); pd->mp_stream.file_name = strdup(file_name); - free((void *) pd->mp_stream.var_name); + MG_FREE((void *) pd->mp_stream.var_name); pd->mp_stream.var_name = strdup(var_name); mg_http_multipart_call_handler(c, MG_EV_HTTP_PART_BEGIN, NULL, 0); @@ -7558,7 +7560,7 @@ void mg_file_upload_handler(struct mg_connection *nc, int ev, void *ev_data, struct mg_http_multipart_part *mp = (struct mg_http_multipart_part *) ev_data; struct file_upload_state *fus = - (struct file_upload_state *) calloc(1, sizeof(*fus)); + (struct file_upload_state *) MG_CALLOC(1, sizeof(*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) { @@ -7572,10 +7574,10 @@ void mg_file_upload_handler(struct mg_connection *nc, int ev, void *ev_data, nc->flags |= MG_F_SEND_AND_CLOSE; return; } - fus->lfn = (char *) malloc(lfn.len + 1); + fus->lfn = (char *) MG_MALLOC(lfn.len + 1); memcpy(fus->lfn, lfn.p, lfn.len); fus->lfn[lfn.len] = '\0'; - if (lfn.p != mp->file_name) free((char *) lfn.p); + if (lfn.p != mp->file_name) MG_FREE((char *) lfn.p); LOG(LL_DEBUG, ("%p Receiving file %s -> %s", nc, mp->file_name, fus->lfn)); fus->fp = mg_fopen(fus->lfn, "w"); @@ -7657,8 +7659,8 @@ void mg_file_upload_handler(struct mg_connection *nc, int ev, void *ev_data, */ } if (fus->fp != NULL) fclose(fus->fp); - free(fus->lfn); - free(fus); + MG_FREE(fus->lfn); + MG_FREE(fus); mp->user_data = NULL; nc->flags |= MG_F_SEND_AND_CLOSE; break; @@ -7889,7 +7891,7 @@ void mg_register_http_endpoint(struct mg_connection *nc, const char *uri_path, struct mg_http_endpoint *new_ep = NULL; if (nc == NULL) return; - new_ep = (struct mg_http_endpoint *) calloc(1, sizeof(*new_ep)); + new_ep = (struct mg_http_endpoint *) MG_CALLOC(1, sizeof(*new_ep)); if (new_ep == NULL) return; pd = mg_http_get_proto_data(nc); @@ -10124,7 +10126,8 @@ void mg_mqtt_broker_init(struct mg_mqtt_broker *brk, void *user_data) { static void mg_mqtt_broker_handle_connect(struct mg_mqtt_broker *brk, struct mg_connection *nc) { - struct mg_mqtt_session *s = (struct mg_mqtt_session *) calloc(1, sizeof *s); + struct mg_mqtt_session *s = + (struct mg_mqtt_session *) MG_CALLOC(1, sizeof *s); if (s == NULL) { /* LCOV_EXCL_START */ mg_mqtt_connack(nc, MG_EV_MQTT_CONNACK_SERVER_UNAVAILABLE); @@ -10157,13 +10160,13 @@ static void mg_mqtt_broker_handle_subscribe(struct mg_connection *nc, qoss[qoss_len++] = qos; } - ss->subscriptions = (struct mg_mqtt_topic_expression *) realloc( + ss->subscriptions = (struct mg_mqtt_topic_expression *) MG_REALLOC( ss->subscriptions, sizeof(*ss->subscriptions) * qoss_len); for (pos = 0; (pos = mg_mqtt_next_subscribe_topic(msg, &topic, &qos, pos)) != -1; ss->num_subscriptions++) { te = &ss->subscriptions[ss->num_subscriptions]; - te->topic = (char *) malloc(topic.len + 1); + te->topic = (char *) MG_MALLOC(topic.len + 1); te->qos = qos; strncpy((char *) te->topic, topic.p, topic.len + 1); } @@ -10950,7 +10953,7 @@ int mg_resolve_async_opt(struct mg_mgr *mgr, const char *name, int query, dns_nc = mg_connect(mgr, nameserver_url, MG_CB(mg_resolve_async_eh, NULL)); if (dns_nc == NULL) { - free(req); + MG_FREE(req); return -1; } dns_nc->user_data = req; @@ -10962,7 +10965,7 @@ int mg_resolve_async_opt(struct mg_mgr *mgr, const char *name, int query, } void mg_set_nameserver(struct mg_mgr *mgr, const char *nameserver) { - free((char *) mgr->nameserver); + MG_FREE((char *) mgr->nameserver); if (nameserver != NULL) { mgr->nameserver = strdup(nameserver); } @@ -12184,6 +12187,7 @@ struct mg_connection *mg_sntp_get_time(struct mg_mgr *mgr, #if CS_PLATFORM == CS_P_CC3200 +/* Amalgamated: #include "common/mg_mem.h" */ #include #include @@ -12209,7 +12213,7 @@ int asprintf(char **strp, const char *fmt, ...) { va_list ap; int len; - *strp = malloc(BUFSIZ); + *strp = MG_MALLOC(BUFSIZ); if (*strp == NULL) return -1; va_start(ap, fmt); @@ -12217,7 +12221,7 @@ int asprintf(char **strp, const char *fmt, ...) { va_end(ap); if (len > 0) { - *strp = realloc(*strp, len + 1); + *strp = MG_REALLOC(*strp, len + 1); if (*strp == NULL) return -1; } @@ -12396,6 +12400,7 @@ void fs_slfs_set_new_file_size(const char *name, size_t size); #include /* Amalgamated: #include "common/cs_dbg.h" */ +/* Amalgamated: #include "common/mg_mem.h" */ /* From sl_fs.c */ extern int set_errno(int e); @@ -12481,7 +12486,7 @@ int fs_slfs_open(const char *pathname, int flags, mode_t mode) { if (s_sl_file_size_hints[i].name != NULL && strcmp(s_sl_file_size_hints[i].name, pathname) == 0) { size = s_sl_file_size_hints[i].size; - free(s_sl_file_size_hints[i].name); + MG_FREE(s_sl_file_size_hints[i].name); s_sl_file_size_hints[i].name = NULL; break; } @@ -13631,6 +13636,8 @@ const struct mg_iface_vtable mg_default_iface_vtable = MG_SL_IFACE_VTABLE; #if MG_ENABLE_SSL && MG_SSL_IF == MG_SSL_IF_SIMPLELINK +/* Amalgamated: #include "common/mg_mem.h" */ + struct mg_ssl_if_ctx { char *ssl_cert; char *ssl_key; @@ -13753,7 +13760,7 @@ static char *sl_pem2der(const char *pem_file) { /* Strip the SL: prefix we added since NWP does not expect it. */ memmove(der_file, der_file + 3, l - 2 /* including \0 */); } else { - free(der_file); + MG_FREE(der_file); der_file = NULL; } return der_file; @@ -13789,8 +13796,8 @@ int sl_set_ssl_opts(struct mg_connection *nc) { } else { err = -1; } - free(ssl_cert); - free(ssl_key); + MG_FREE(ssl_cert); + MG_FREE(ssl_key); if (err != 0) return err; } if (ctx->ssl_ca_cert != NULL) { @@ -13804,7 +13811,7 @@ int sl_set_ssl_opts(struct mg_connection *nc) { } else { err = -1; } - free(ssl_ca_cert); + MG_FREE(ssl_ca_cert); if (err != 0) return err; } } @@ -13888,6 +13895,8 @@ void mg_lwip_mgr_schedule_poll(struct mg_mgr *mgr); #if MG_ENABLE_NET_IF_LWIP_LOW_LEVEL +/* Amalgamated: #include "common/mg_mem.h" */ + #include #include #if CS_PLATFORM != CS_P_STM32 @@ -14057,7 +14066,7 @@ static void mg_lwip_handle_recv_tcp(struct mg_connection *nc) { while (cs->rx_chain != NULL) { struct pbuf *seg = cs->rx_chain; size_t len = (seg->len - cs->rx_offset); - char *data = (char *) malloc(len); + char *data = (char *) MG_MALLOC(len); if (data == NULL) { mgos_unlock(); DBG(("OOM")); @@ -14179,7 +14188,7 @@ static void mg_lwip_handle_recv_udp(struct mg_connection *nc) { struct pbuf *p = sap->next; cs->rx_chain = pbuf_dechain(p); size_t data_len = p->len; - char *data = (char *) malloc(data_len); + char *data = (char *) MG_MALLOC(data_len); if (data != NULL) { pbuf_copy_partial(p, data, data_len, 0); pbuf_free(p); @@ -14402,7 +14411,7 @@ void mg_lwip_if_recved(struct mg_connection *nc, size_t len) { int mg_lwip_if_create_conn(struct mg_connection *nc) { struct mg_lwip_conn_state *cs = - (struct mg_lwip_conn_state *) calloc(1, sizeof(*cs)); + (struct mg_lwip_conn_state *) MG_CALLOC(1, sizeof(*cs)); if (cs == NULL) return 0; cs->nc = nc; nc->sock = (intptr_t) cs; @@ -14426,7 +14435,7 @@ void mg_lwip_if_destroy_conn(struct mg_connection *nc) { pbuf_free(seg); } memset(cs, 0, sizeof(*cs)); - free(cs); + MG_FREE(cs); } else if (nc->listener == NULL) { /* Only close outgoing UDP pcb or listeners. */ struct udp_pcb *upcb = cs->pcb.udp; @@ -14435,7 +14444,7 @@ void mg_lwip_if_destroy_conn(struct mg_connection *nc) { udp_remove(upcb); } memset(cs, 0, sizeof(*cs)); - free(cs); + MG_FREE(cs); } nc->sock = INVALID_SOCKET; } @@ -14744,6 +14753,7 @@ uint32_t mg_lwip_get_poll_delay_ms(struct mg_mgr *mgr) { #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 @@ -14843,12 +14853,12 @@ void mg_lwip_ssl_recv(struct mg_connection *nc) { /* Don't deliver data before connect callback */ if (nc->flags & MG_F_CONNECTING) return; while (nc->recv_mbuf.len < MG_LWIP_SSL_RECV_MBUF_LIMIT) { - char *buf = (char *) malloc(MG_LWIP_SSL_IO_SIZE); + 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) { - free(buf); + MG_FREE(buf); if (ret == MG_SSL_WANT_WRITE) { nc->flags |= MG_F_WANT_WRITE; return; From af22fb7a0695e0112b4bcf1fae1729b78cbe1c10 Mon Sep 17 00:00:00 2001 From: Dmitry Frank Date: Thu, 23 Mar 2017 23:56:05 +0200 Subject: [PATCH 032/137] Include mg_mem.h into str_util PUBLISHED_FROM=990564aa54946b2a5b52d3a9c31f80b8e93c6b44 --- mongoose.c | 1 + 1 file changed, 1 insertion(+) diff --git a/mongoose.c b/mongoose.c index fd1068ed..611b50a4 100644 --- a/mongoose.c +++ b/mongoose.c @@ -1469,6 +1469,7 @@ void cs_hmac_sha1(const unsigned char *key, size_t keylen, #ifndef EXCLUDE_COMMON +/* Amalgamated: #include "common/mg_mem.h" */ /* Amalgamated: #include "common/platform.h" */ /* Amalgamated: #include "common/str_util.h" */ From 8b67274cc0b45a1fe8bb2ceabac57b5432d65abb Mon Sep 17 00:00:00 2001 From: Alexander Alashkin Date: Fri, 24 Mar 2017 15:11:35 +0200 Subject: [PATCH 033/137] Fix mg_get_http_var retval PUBLISHED_FROM=257deff5ea20302627e77a0f29cf2359276a41d4 --- docs/c-api/http_server.h/mg_get_http_var.md | 3 ++- mongoose.c | 12 ++++++++++-- mongoose.h | 3 ++- 3 files changed, 14 insertions(+), 4 deletions(-) diff --git a/docs/c-api/http_server.h/mg_get_http_var.md b/docs/c-api/http_server.h/mg_get_http_var.md index 55ee3e6f..8ca1d915 100644 --- a/docs/c-api/http_server.h/mg_get_http_var.md +++ b/docs/c-api/http_server.h/mg_get_http_var.md @@ -12,5 +12,6 @@ Fetches a HTTP form variable. Fetches a variable `name` from a `buf` into a buffer specified by `dst`, `dst_len`. The destination is always zero-terminated. Returns the length of a fetched variable. If not found, 0 is returned. `buf` must be valid -url-encoded buffer. If destination is too small, `-1` is returned. +url-encoded buffer. If destination is too small or an error occured, +negative number is returned. diff --git a/mongoose.c b/mongoose.c index 611b50a4..fc5c91bc 100644 --- a/mongoose.c +++ b/mongoose.c @@ -6492,6 +6492,13 @@ int mg_get_http_var(const struct mg_str *buf, const char *name, char *dst, size_t name_len; int len; + /* + * According to the documentation function returns negative + * value in case of error. For debug purposes it returns: + * -1 - src is wrong (NUUL) + * -2 - dst is wrong (NULL) + * -3 - failed to decode url or dst is to small + */ if (dst == NULL || dst_len == 0) { len = -2; } else if (buf->p == NULL || name == NULL || buf->len == 0) { @@ -6500,7 +6507,7 @@ int mg_get_http_var(const struct mg_str *buf, const char *name, char *dst, } else { name_len = strlen(name); e = buf->p + buf->len; - len = -1; + len = 0; dst[0] = '\0'; for (p = buf->p; p + name_len < e; p++) { @@ -6512,8 +6519,9 @@ int mg_get_http_var(const struct mg_str *buf, const char *name, char *dst, s = e; } len = mg_url_decode(p, (size_t)(s - p), dst, dst_len, 1); + /* -1 means: failed to decode or dst is too small */ if (len == -1) { - len = -2; + len = -3; } break; } diff --git a/mongoose.h b/mongoose.h index 5b17bdbf..eb18954b 100644 --- a/mongoose.h +++ b/mongoose.h @@ -4516,7 +4516,8 @@ size_t mg_parse_multipart(const char *buf, size_t buf_len, char *var_name, * Fetches a variable `name` from a `buf` into a buffer specified by `dst`, * `dst_len`. The destination is always zero-terminated. Returns the length of * a fetched variable. If not found, 0 is returned. `buf` must be valid - * url-encoded buffer. If destination is too small, `-1` is returned. + * url-encoded buffer. If destination is too small or an error occured, + * negative number is returned. */ int mg_get_http_var(const struct mg_str *buf, const char *name, char *dst, size_t dst_len); From 8ec47111d527fe02aacc15e45d8edac5ba3231b8 Mon Sep 17 00:00:00 2001 From: Ilia Penev Date: Wed, 29 Mar 2017 15:32:26 +0300 Subject: [PATCH 034/137] Fix COAP compilation PUBLISHED_FROM=0a0ef6f68d743cbba91d9ba911f1c5be69e6aac7 --- mongoose.c | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/mongoose.c b/mongoose.c index fc5c91bc..5697d5ed 100644 --- a/mongoose.c +++ b/mongoose.c @@ -11529,14 +11529,15 @@ uint32_t mg_coap_send_ack(struct mg_connection *nc, uint16_t msg_id) { return mg_coap_send_message(nc, &cm); } -static void coap_handler(struct mg_connection *nc, int ev, void *ev_data) { +static void coap_handler(struct mg_connection *nc, int ev, + void *ev_data MG_UD_ARG(void *user_data)) { struct mbuf *io = &nc->recv_mbuf; struct mg_coap_message cm; uint32_t parse_res; memset(&cm, 0, sizeof(cm)); - nc->handler(nc, ev, ev_data); + nc->handler(nc, ev, ev_data MG_UD_ARG(user_data)); switch (ev) { case MG_EV_RECV: @@ -11549,7 +11550,8 @@ static void coap_handler(struct mg_connection *nc, int ev, void *ev_data) { */ cm.flags |= MG_COAP_FORMAT_ERROR; /* LCOV_EXCL_LINE */ } /* LCOV_EXCL_LINE */ - nc->handler(nc, MG_COAP_EVENT_BASE + cm.msg_type, &cm); + nc->handler(nc, MG_COAP_EVENT_BASE + cm.msg_type, + &cm MG_UD_ARG(user_data)); } mg_coap_free_options(&cm); From 511c9a6d4a47447eb493707c6cc5e58b1759ae49 Mon Sep 17 00:00:00 2001 From: Alexander Alashkin Date: Wed, 29 Mar 2017 14:40:52 +0100 Subject: [PATCH 035/137] Add simple mongoose/esp32 example (w/out mOS) PUBLISHED_FROM=0e407a2fb328107540d753123fe027f43860d0ef --- examples/ESP32_IDF/Makefile | 16 +++++ examples/ESP32_IDF/Makefile.build | 9 +++ examples/ESP32_IDF/README.md | 18 ++++++ examples/ESP32_IDF/main/component.mk | 17 +++++ examples/ESP32_IDF/main/main.c | 93 ++++++++++++++++++++++++++++ examples/ESP32_IDF/sdk.version | 1 + examples/Makefile | 2 +- 7 files changed, 155 insertions(+), 1 deletion(-) create mode 100644 examples/ESP32_IDF/Makefile create mode 100644 examples/ESP32_IDF/Makefile.build create mode 100644 examples/ESP32_IDF/README.md create mode 100644 examples/ESP32_IDF/main/component.mk create mode 100644 examples/ESP32_IDF/main/main.c create mode 100644 examples/ESP32_IDF/sdk.version diff --git a/examples/ESP32_IDF/Makefile b/examples/ESP32_IDF/Makefile new file mode 100644 index 00000000..e40fd4c0 --- /dev/null +++ b/examples/ESP32_IDF/Makefile @@ -0,0 +1,16 @@ +SDK_VER=$(shell cat sdk.version) + +.PHONY: all + +MG_PATH = $(realpath $(PWD)/../../) + +all: + docker run --rm -it -v $(MG_PATH):/esp32_idf \ + $(SDK_VER) \ + bash -c "cd esp32_idf/examples/ESP32_IDF && \ + make -f Makefile.build defconfig && make -f Makefile.build" + +clean: + docker run --rm -it -v $(MG_PATH):/esp32_idf \ + $(SDK_VER) \ + bash -c "rm -rf esp32_idf/examples/ESP32_IDF/build" diff --git a/examples/ESP32_IDF/Makefile.build b/examples/ESP32_IDF/Makefile.build new file mode 100644 index 00000000..5a6de248 --- /dev/null +++ b/examples/ESP32_IDF/Makefile.build @@ -0,0 +1,9 @@ +# +# This is a project Makefile. It is assumed the directory this Makefile resides in is a +# project subdirectory. +# + +PROJECT_NAME := esp32_idf + +include $(IDF_PATH)/make/project.mk + diff --git a/examples/ESP32_IDF/README.md b/examples/ESP32_IDF/README.md new file mode 100644 index 00000000..4af679a0 --- /dev/null +++ b/examples/ESP32_IDF/README.md @@ -0,0 +1,18 @@ +This is a Mongoose "Hello, world" that can be compiled under Espressif IoT Development Framework for ESP32 + +It connects to WiFi network and serves a "hello world" page. + +Most of the the boilerplate comes from [project_template](https://github.com/espressif/esp-idf-template) with minimal changes. + +For building the example, you need to have [Docker](https://www.docker.com/products/docker) and use our pre-built SDK container. +To build just run in the example directory +``` +$ make +``` + +Note: before building, change `WIFI_SSID` and `WIFI_PASS` macros in main/main.c file + +Once built, use [esptool](https://github.com/espressif/esptool) for flashing +``` +$ python esptool.py --chip esp32 --port /dev/ttyUSB0 --baud 115200 --before default_reset --after hard_reset write_flash -u --flash_mode dio --flash_freq 40m --flash_size detect 0x1000 build/bootloader/bootloader.bin 0x10000 build/esp32_idf.bin 0x8000 build/partitions_singleapp.bin +``` diff --git a/examples/ESP32_IDF/main/component.mk b/examples/ESP32_IDF/main/component.mk new file mode 100644 index 00000000..f8659a72 --- /dev/null +++ b/examples/ESP32_IDF/main/component.mk @@ -0,0 +1,17 @@ +# +# Main component makefile. +# +# This Makefile can be left empty. By default, it will take the sources in the +# src/ directory, compile them and link them into lib(subdirectory_name).a +# in the build directory. This behaviour is entirely configurable, +# please read the ESP-IDF documents if you need to do this. +# + +COMPONENT_OBJS = main.o mongoose.o + +mongoose.o: ../../../../mongoose.c + $(summary) "CC $@" + $(CC) $(CFLAGS) $(CPPFLAGS) \ + $(addprefix -I ,$(COMPONENT_INCLUDES)) \ + $(addprefix -I ,$(COMPONENT_EXTRA_INCLUDES)) \ + -c $< -o $@ diff --git a/examples/ESP32_IDF/main/main.c b/examples/ESP32_IDF/main/main.c new file mode 100644 index 00000000..3b9a0ee7 --- /dev/null +++ b/examples/ESP32_IDF/main/main.c @@ -0,0 +1,93 @@ +#include + +#include "freertos/FreeRTOS.h" + +#include "esp_event.h" +#include "esp_event_loop.h" +#include "esp_system.h" +#include "esp_wifi.h" +#include "nvs_flash.h" + +#include "./../../../mongoose.h" + +#define WIFI_SSID "ssid" +#define WIFI_PASS "pass" + +#define MG_LISTEN_ADDR "80" + +static esp_err_t event_handler(void *ctx, system_event_t *event) { + (void) ctx; + (void) event; + return ESP_OK; +} + +static void mg_ev_handler(struct mg_connection *nc, int ev, void *p) { + static const char *reply_fmt = + "HTTP/1.0 200 OK\r\n" + "Connection: close\r\n" + "Content-Type: text/plain\r\n" + "\r\n" + "Hello %s\n"; + + switch (ev) { + case MG_EV_ACCEPT: { + char addr[32]; + mg_sock_addr_to_str(&nc->sa, addr, sizeof(addr), + MG_SOCK_STRINGIFY_IP | MG_SOCK_STRINGIFY_PORT); + printf("Connection %p from %s\n", nc, addr); + break; + } + case MG_EV_HTTP_REQUEST: { + char addr[32]; + struct http_message *hm = (struct http_message *) p; + mg_sock_addr_to_str(&nc->sa, addr, sizeof(addr), + MG_SOCK_STRINGIFY_IP | MG_SOCK_STRINGIFY_PORT); + printf("HTTP request from %s: %.*s %.*s\n", addr, (int) hm->method.len, + hm->method.p, (int) hm->uri.len, hm->uri.p); + mg_printf(nc, reply_fmt, addr); + nc->flags |= MG_F_SEND_AND_CLOSE; + break; + } + case MG_EV_CLOSE: { + printf("Connection %p closed\n", nc); + break; + } + } +} + +void app_main(void) { + nvs_flash_init(); + tcpip_adapter_init(); + ESP_ERROR_CHECK(esp_event_loop_init(event_handler, NULL)); + + /* Initializing WiFi */ + wifi_init_config_t cfg = WIFI_INIT_CONFIG_DEFAULT(); + ESP_ERROR_CHECK(esp_wifi_init(&cfg)); + ESP_ERROR_CHECK(esp_wifi_set_storage(WIFI_STORAGE_RAM)); + ESP_ERROR_CHECK(esp_wifi_set_mode(WIFI_MODE_STA)); + wifi_config_t sta_config = { + .sta = {.ssid = WIFI_SSID, .password = WIFI_PASS, .bssid_set = false}}; + ESP_ERROR_CHECK(esp_wifi_set_config(WIFI_IF_STA, &sta_config)); + ESP_ERROR_CHECK(esp_wifi_start()); + ESP_ERROR_CHECK(esp_wifi_connect()); + + /* Starting Mongoose */ + struct mg_mgr mgr; + struct mg_connection *nc; + + printf("Starting web-server on port %s\n", MG_LISTEN_ADDR); + + mg_mgr_init(&mgr, NULL); + + nc = mg_bind(&mgr, MG_LISTEN_ADDR, mg_ev_handler); + if (nc == NULL) { + printf("Error setting up listener!\n"); + return; + } + mg_set_protocol_http_websocket(nc); + + /* Processing events */ + while (1) { + mg_mgr_poll(&mgr, 1000); + } +} diff --git a/examples/ESP32_IDF/sdk.version b/examples/ESP32_IDF/sdk.version new file mode 100644 index 00000000..174eac89 --- /dev/null +++ b/examples/ESP32_IDF/sdk.version @@ -0,0 +1 @@ +docker.cesanta.com/esp32-build:1.0-r13 diff --git a/examples/Makefile b/examples/Makefile index a6c96ddc..9f364d2e 100644 --- a/examples/Makefile +++ b/examples/Makefile @@ -3,7 +3,7 @@ # `wildcard ./*/` works in both linux and linux/wine, while `wildcard */` enumerates nothing under wine SUBDIRS = $(sort $(dir $(wildcard ./*/))) -SUBDIRS:=$(filter-out ./ ./CC3200/ ./ESP8266_RTOS/ ./mbed/ ./MSP432/ ./nRF51/ ./nRF52/ ./NXP_K64/ ./NXP_LPC4088/ ./PIC32/ ./STM32F4_CC3100/ ./TM4C129/ ./WinCE/, $(SUBDIRS)) +SUBDIRS:=$(filter-out ./ ./CC3200/ ./ESP32_IDF/ ./ESP8266_RTOS/ ./mbed/ ./MSP432/ ./nRF51/ ./nRF52/ ./NXP_K64/ ./NXP_LPC4088/ ./PIC32/ ./STM32F4_CC3100/ ./TM4C129/ ./WinCE/, $(SUBDIRS)) ifeq ($(OS), Windows_NT) SUBDIRS:=$(filter-out ./netcat/ ./raspberry_pi_mjpeg_led/ ./captive_dns_server/, $(SUBDIRS)) From 57a4ec31d10d8b30a465354567b010ed726189f6 Mon Sep 17 00:00:00 2001 From: Alexander Alashkin Date: Thu, 30 Mar 2017 15:02:21 +0300 Subject: [PATCH 036/137] Fix MinGW compilation PUBLISHED_FROM=66b2dee87dc50de5f2891dee789beec89c3f6fb4 --- mongoose.h | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/mongoose.h b/mongoose.h index eb18954b..6dbe7659 100644 --- a/mongoose.h +++ b/mongoose.h @@ -195,6 +195,7 @@ #include #include #include +#include #ifdef _MSC_VER #pragma comment(lib, "ws2_32.lib") /* Linking with winsock library */ @@ -221,13 +222,13 @@ #define __func__ __FILE__ ":" STR(__LINE__) #endif #define snprintf _snprintf -#define fileno _fileno #define vsnprintf _vsnprintf #define sleep(x) Sleep((x) *1000) #define to64(x) _atoi64(x) #if !defined(__MINGW32__) && !defined(__MINGW64__) #define popen(x, y) _popen((x), (y)) #define pclose(x) _pclose(x) +#define fileno _fileno #endif #define rmdir _rmdir #if defined(_MSC_VER) && _MSC_VER >= 1400 From 06c5c4d2a428b3320cb4eb335975a803c6b5f6d5 Mon Sep 17 00:00:00 2001 From: Deomid Ryabkov Date: Thu, 30 Mar 2017 16:19:02 +0100 Subject: [PATCH 037/137] Handle NULL tpcb in mg_lwip_tcp_write This can happen if the underlying LWIP TCP PCB has been destroyed (we got tcp_error_cb). PUBLISHED_FROM=7a060aa4ca2a0c5a818fe9bc6b08cd0733c0ef8f --- mongoose.c | 1 + 1 file changed, 1 insertion(+) diff --git a/mongoose.c b/mongoose.c index 5697d5ed..8bc2546b 100644 --- a/mongoose.c +++ b/mongoose.c @@ -14313,6 +14313,7 @@ int mg_lwip_tcp_write(struct mg_connection *nc, const void *data, uint16_t len) { struct mg_lwip_conn_state *cs = (struct mg_lwip_conn_state *) nc->sock; struct tcp_pcb *tpcb = cs->pcb.tcp; + if (tpcb == NULL) return -1; len = MIN(tpcb->mss, MIN(len, tpcb->snd_buf)); if (len == 0) { DBG(("%p no buf avail %u %u %u %p %p", tpcb, tpcb->acked, tpcb->snd_buf, From b8402ed0733e3f244588b61ad5fedd093e3cf9cc Mon Sep 17 00:00:00 2001 From: Alexander Alashkin Date: Mon, 3 Apr 2017 10:14:16 +0100 Subject: [PATCH 038/137] Fix crash in multipart handling Close cesanta/dev#6974 PUBLISHED_FROM=4d4e4a46eceba10aec8dacb7f8f58bd078c92307 --- mongoose.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/mongoose.c b/mongoose.c index 8bc2546b..bd953571 100644 --- a/mongoose.c +++ b/mongoose.c @@ -5961,6 +5961,12 @@ static int mg_http_multipart_wait_for_boundary(struct mg_connection *c) { struct mbuf *io = &c->recv_mbuf; struct mg_http_proto_data *pd = mg_http_get_proto_data(c); + if (pd->mp_stream.boundary == NULL) { + pd->mp_stream.state = MPS_FINALIZE; + DBG(("Invalid request: boundary not initilaized")); + return 0; + } + if ((int) io->len < pd->mp_stream.boundary_len + 2) { return 0; } From 02b7399f9a81ff74f7794cdfd7b5b2fc260f235d Mon Sep 17 00:00:00 2001 From: Deomid Ryabkov Date: Mon, 3 Apr 2017 17:04:50 +0300 Subject: [PATCH 039/137] Fix a typo PUBLISHED_FROM=183a1bb571d0e2f5c23181107d30417f73c1eeb1 --- mongoose.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mongoose.c b/mongoose.c index bd953571..ff74b884 100644 --- a/mongoose.c +++ b/mongoose.c @@ -5963,7 +5963,7 @@ static int mg_http_multipart_wait_for_boundary(struct mg_connection *c) { if (pd->mp_stream.boundary == NULL) { pd->mp_stream.state = MPS_FINALIZE; - DBG(("Invalid request: boundary not initilaized")); + DBG(("Invalid request: boundary not initialized")); return 0; } From 920abd627b09dd8b07c69b964041e89d9e19c1d7 Mon Sep 17 00:00:00 2001 From: Deomid Ryabkov Date: Fri, 7 Apr 2017 11:51:40 +0100 Subject: [PATCH 040/137] Minor SNTP fixes PUBLISHED_FROM=03d04996f160f777339eec9528f2f187e1051ff9 --- mongoose.c | 19 ++++++++++--------- 1 file changed, 10 insertions(+), 9 deletions(-) diff --git a/mongoose.c b/mongoose.c index ff74b884..c9e9becb 100644 --- a/mongoose.c +++ b/mongoose.c @@ -11986,7 +11986,7 @@ void mg_sntp_send_request(struct mg_connection *c) { * but if local clock is absolutely broken (and doesn't work even * as simple timer), it is better to disable it */ -#ifndef MG_SNMP_NO_DELAY_CORRECTION +#ifndef MG_SNTP_NO_DELAY_CORRECTION uint32_t sec; sec = htonl((uint32_t)(mg_time() + SNTP_TIME_OFFSET)); memcpy(&buf[40], &sec, sizeof(sec)); @@ -11995,7 +11995,7 @@ void mg_sntp_send_request(struct mg_connection *c) { mg_send(c, buf, sizeof(buf)); } -#ifndef MG_SNMP_NO_DELAY_CORRECTION +#ifndef MG_SNTP_NO_DELAY_CORRECTION static uint64_t mg_calculate_delay(uint64_t t1, uint64_t t2, uint64_t t3) { /* roundloop delay = (T4 - T1) - (T3 - T2) */ uint64_t d1 = ((mg_time() + SNTP_TIME_OFFSET) * 1000000) - @@ -12010,12 +12010,10 @@ static uint64_t mg_calculate_delay(uint64_t t1, uint64_t t2, uint64_t t3) { MG_INTERNAL int mg_sntp_parse_reply(const char *buf, int len, struct mg_sntp_message *msg) { uint8_t hdr; - uint64_t orig_ts_T1, recv_ts_T2, trsm_ts_T3, delay = 0; + uint64_t trsm_ts_T3, delay = 0; int mode; struct timeval tv; - (void) orig_ts_T1; - (void) recv_ts_T2; if (len < 48) { return -1; } @@ -12039,10 +12037,13 @@ MG_INTERNAL int mg_sntp_parse_reply(const char *buf, int len, mg_get_ntp_ts(&buf[40], &trsm_ts_T3); -#ifndef MG_SNMP_NO_DELAY_CORRECTION - mg_get_ntp_ts(&buf[24], &orig_ts_T1); - mg_get_ntp_ts(&buf[32], &recv_ts_T2); - delay = mg_calculate_delay(orig_ts_T1, recv_ts_T2, trsm_ts_T3); +#ifndef MG_SNTP_NO_DELAY_CORRECTION + { + uint64_t orig_ts_T1, recv_ts_T2; + mg_get_ntp_ts(&buf[24], &orig_ts_T1); + mg_get_ntp_ts(&buf[32], &recv_ts_T2); + delay = mg_calculate_delay(orig_ts_T1, recv_ts_T2, trsm_ts_T3); + } #endif mg_ntp_to_tv(trsm_ts_T3, &tv); From 4172c190e5efc21cec85f28d597bcc3292d5d5ce Mon Sep 17 00:00:00 2001 From: Deomid Ryabkov Date: Sat, 8 Apr 2017 08:08:27 +0100 Subject: [PATCH 041/137] Fix MQTT handshake; change to version 3.1.1 Differences between 3.1 and 3.1.1: https://github.com/mqtt/mqtt.github.io/wiki/Differences-between-3.1.0-and-3.1.1 None of them are breaking. PUBLISHED_FROM=cf2abd28deb1dabf787e07bcfdb335ff72462865 --- mongoose.c | 151 ++++++++++++++++++++++++++--------------------------- 1 file changed, 75 insertions(+), 76 deletions(-) diff --git a/mongoose.c b/mongoose.c index c9e9becb..c7056262 100644 --- a/mongoose.c +++ b/mongoose.c @@ -9856,82 +9856,6 @@ void mg_set_protocol_mqtt(struct mg_connection *nc) { nc->proto_data_destructor = mg_mqtt_proto_data_destructor; } -void mg_send_mqtt_handshake(struct mg_connection *nc, const char *client_id) { - static struct mg_send_mqtt_handshake_opts opts; - mg_send_mqtt_handshake_opt(nc, client_id, opts); -} - -void mg_send_mqtt_handshake_opt(struct mg_connection *nc, const char *client_id, - struct mg_send_mqtt_handshake_opts opts) { - uint8_t header = MG_MQTT_CMD_CONNECT << 4; - uint8_t rem_len; - uint16_t keep_alive; - uint16_t len; - struct mg_mqtt_proto_data *pd = (struct mg_mqtt_proto_data *) nc->proto_data; - - /* - * 9: version_header(len, magic_string, version_number), 1: flags, 2: - * keep-alive timer, - * 2: client_identifier_len, n: client_id - */ - rem_len = 9 + 1 + 2 + 2 + (uint8_t) strlen(client_id); - - if (opts.user_name != NULL) { - opts.flags |= MG_MQTT_HAS_USER_NAME; - rem_len += (uint8_t) strlen(opts.user_name) + 2; - } - if (opts.password != NULL) { - opts.flags |= MG_MQTT_HAS_PASSWORD; - rem_len += (uint8_t) strlen(opts.password) + 2; - } - if (opts.will_topic != NULL && opts.will_message != NULL) { - opts.flags |= MG_MQTT_HAS_WILL; - rem_len += (uint8_t) strlen(opts.will_topic) + 2; - rem_len += (uint8_t) strlen(opts.will_message) + 2; - } - - mg_send(nc, &header, 1); - mg_send(nc, &rem_len, 1); - mg_send(nc, "\00\06MQIsdp\03", 9); - mg_send(nc, &opts.flags, 1); - - if (opts.keep_alive == 0) { - opts.keep_alive = 60; - } - - keep_alive = htons(opts.keep_alive); - mg_send(nc, &keep_alive, 2); - - len = htons((uint16_t) strlen(client_id)); - mg_send(nc, &len, 2); - mg_send(nc, client_id, strlen(client_id)); - - if (opts.flags & MG_MQTT_HAS_WILL) { - len = htons((uint16_t) strlen(opts.will_topic)); - mg_send(nc, &len, 2); - mg_send(nc, opts.will_topic, strlen(opts.will_topic)); - - len = htons((uint16_t) strlen(opts.will_message)); - mg_send(nc, &len, 2); - mg_send(nc, opts.will_message, strlen(opts.will_message)); - } - - if (opts.flags & MG_MQTT_HAS_USER_NAME) { - len = htons((uint16_t) strlen(opts.user_name)); - mg_send(nc, &len, 2); - mg_send(nc, opts.user_name, strlen(opts.user_name)); - } - if (opts.flags & MG_MQTT_HAS_PASSWORD) { - len = htons((uint16_t) strlen(opts.password)); - mg_send(nc, &len, 2); - mg_send(nc, opts.password, strlen(opts.password)); - } - - if (pd != NULL) { - pd->keep_alive = opts.keep_alive; - } -} - static void mg_mqtt_prepend_header(struct mg_connection *nc, uint8_t cmd, uint8_t flags, size_t len) { size_t off = nc->send_mbuf.len - len; @@ -9955,6 +9879,81 @@ static void mg_mqtt_prepend_header(struct mg_connection *nc, uint8_t cmd, mbuf_insert(&nc->send_mbuf, off, buf, vlen - buf); } +void mg_send_mqtt_handshake(struct mg_connection *nc, const char *client_id) { + static struct mg_send_mqtt_handshake_opts opts; + mg_send_mqtt_handshake_opt(nc, client_id, opts); +} + +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; + + mg_send(nc, "\00\04MQTT\04", 7); + rem_len += 7; + + if (opts.user_name != NULL) { + opts.flags |= MG_MQTT_HAS_USER_NAME; + } + if (opts.password != NULL) { + opts.flags |= MG_MQTT_HAS_PASSWORD; + } + if (opts.will_topic != NULL && opts.will_message != NULL) { + opts.flags |= MG_MQTT_HAS_WILL; + } + if (opts.keep_alive == 0) { + opts.keep_alive = 60; + } + + mg_send(nc, &opts.flags, 1); + rem_len += 1; + + nlen = htons(opts.keep_alive); + mg_send(nc, &nlen, 2); + rem_len += 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; + + 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; + + hlen = strlen(opts.will_message); + nlen = htons((uint16_t) nlen); + mg_send(nc, &nlen, 2); + mg_send(nc, opts.will_message, hlen); + rem_len += 2 + hlen; + } + + 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; + } + 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; + } + + mg_mqtt_prepend_header(nc, MG_MQTT_CMD_CONNECT, 0, rem_len); + + if (pd != NULL) { + pd->keep_alive = opts.keep_alive; + } +} + void mg_mqtt_publish(struct mg_connection *nc, const char *topic, uint16_t message_id, int flags, const void *data, size_t len) { From fb04203b721f0f6eefb3b054396a115e05d71195 Mon Sep 17 00:00:00 2001 From: Ruslan Valiullin Date: Sun, 9 Apr 2017 16:57:34 +0100 Subject: [PATCH 042/137] Fix eintr, zombie PUBLISHED_FROM=f6d7d0f9c6de8ffeeb3bcd8aace6c1434281ddf7 --- mongoose.c | 61 +++++++++++++++++++++++++++++++++++++++--------------- 1 file changed, 44 insertions(+), 17 deletions(-) diff --git a/mongoose.c b/mongoose.c index c7056262..6345501f 100644 --- a/mongoose.c +++ b/mongoose.c @@ -3582,9 +3582,7 @@ void mg_socket_if_init(struct mg_iface *iface) { (void) iface; DBG(("%p using select()", iface->mgr)); #if MG_ENABLE_BROADCAST - do { - mg_socketpair(iface->mgr->ctl, SOCK_DGRAM); - } while (iface->mgr->ctl[0] == INVALID_SOCKET); + mg_socketpair(iface->mgr->ctl, SOCK_DGRAM); #endif } @@ -3742,6 +3740,27 @@ time_t mg_socket_if_poll(struct mg_iface *iface, int timeout_ms) { } #if MG_ENABLE_BROADCAST +MG_INTERNAL void mg_socketpair_close(sock_t *sock) { + while (1) { + if (closesocket(*sock) == -1 && errno == EINTR) + continue; + break; + } + *sock = INVALID_SOCKET; +} + +MG_INTERNAL sock_t mg_socketpair_accept(sock_t sock, + union socket_address *sa, + socklen_t sa_len) { + sock_t rc; + while(1) { + if ((rc = accept(sock, &sa->sa, &sa_len)) == INVALID_SOCKET && errno == EINTR) + continue; + break; + } + return rc; +} + int mg_socketpair(sock_t sp[2], int sock_type) { union socket_address sa; sock_t sock; @@ -3765,20 +3784,19 @@ int mg_socketpair(sock_t sp[2], int sock_type) { (getsockname(sp[0], &sa.sa, &len) != 0 || connect(sock, &sa.sa, len) != 0)) { } else if ((sp[1] = (sock_type == SOCK_DGRAM ? sock - : accept(sock, &sa.sa, &len))) == + : mg_socketpair_accept(sock, &sa, len))) == INVALID_SOCKET) { } else { mg_set_close_on_exec(sp[0]); mg_set_close_on_exec(sp[1]); - if (sock_type == SOCK_STREAM) closesocket(sock); + if (sock_type == SOCK_STREAM) mg_socketpair_close(&sock); ret = 1; } if (!ret) { - if (sp[0] != INVALID_SOCKET) closesocket(sp[0]); - if (sp[1] != INVALID_SOCKET) closesocket(sp[1]); - if (sock != INVALID_SOCKET) closesocket(sock); - sock = sp[0] = sp[1] = INVALID_SOCKET; + if (sp[0] != INVALID_SOCKET) mg_socketpair_close(&sp[0]); + if (sp[1] != INVALID_SOCKET) mg_socketpair_close(&sp[1]); + if (sock != INVALID_SOCKET) mg_socketpair_close(&sock); } return ret; @@ -7929,6 +7947,10 @@ void mg_register_http_endpoint(struct mg_connection *nc, const char *uri_path, * All rights reserved */ +#ifndef _WIN32 +#include +#endif + #if MG_ENABLE_HTTP && MG_ENABLE_HTTP_CGI #ifndef MG_MAX_CGI_ENVIR_VARS @@ -8379,14 +8401,19 @@ MG_INTERNAL void mg_handle_cgi(struct mg_connection *nc, const char *prog, prog = p + 1; } - /* - * Try to create socketpair in a loop until success. mg_socketpair() - * can be interrupted by a signal and fail. - * TODO(lsm): use sigaction to restart interrupted syscall - */ - do { - mg_socketpair(fds, SOCK_STREAM); - } while (fds[0] == INVALID_SOCKET); + if (!mg_socketpair(fds, SOCK_STREAM)) { + nc->flags |= MG_F_CLOSE_IMMEDIATELY; + return; + } + +#ifndef _WIN32 + struct sigaction sa; + + sigemptyset(&sa.sa_mask); + sa.sa_handler = SIG_IGN; + sa.sa_flags = 0; + sigaction(SIGCHLD, &sa, NULL); +#endif if (mg_start_process(opts->cgi_interpreter, prog, blk.buf, blk.vars, dir, fds[1]) != 0) { From bd130136bcf745b7387708b7f867a1a88a82ef9e Mon Sep 17 00:00:00 2001 From: Dmitry Frank Date: Mon, 10 Apr 2017 10:58:45 +0100 Subject: [PATCH 043/137] Commonize arg checking in cfunctions Add `mjs_check_arg()` which checks whether argument is provided, and checks its type. It simplifies code and makes it smaller (because error strings are not ad-hoc, so they are not duplicated) As part of that, also commonize type stringifying: implement `mjs_stringify_type` and reimplement `mjs_typeof` on top of that. Use `mjs_check_arg()` in `mjs_string_slice()` and `mjs_string_char_code_at()`. PUBLISHED_FROM=0b72cf479738ff405d991cbd4bf9e75edda0f111 --- mongoose.c | 19 +++++++++---------- 1 file changed, 9 insertions(+), 10 deletions(-) diff --git a/mongoose.c b/mongoose.c index 6345501f..fcc50833 100644 --- a/mongoose.c +++ b/mongoose.c @@ -3742,20 +3742,19 @@ time_t mg_socket_if_poll(struct mg_iface *iface, int timeout_ms) { #if MG_ENABLE_BROADCAST MG_INTERNAL void mg_socketpair_close(sock_t *sock) { while (1) { - if (closesocket(*sock) == -1 && errno == EINTR) - continue; + if (closesocket(*sock) == -1 && errno == EINTR) continue; break; } *sock = INVALID_SOCKET; } -MG_INTERNAL sock_t mg_socketpair_accept(sock_t sock, - union socket_address *sa, - socklen_t sa_len) { +MG_INTERNAL sock_t +mg_socketpair_accept(sock_t sock, union socket_address *sa, socklen_t sa_len) { sock_t rc; - while(1) { - if ((rc = accept(sock, &sa->sa, &sa_len)) == INVALID_SOCKET && errno == EINTR) - continue; + while (1) { + if ((rc = accept(sock, &sa->sa, &sa_len)) == INVALID_SOCKET && + errno == EINTR) + continue; break; } return rc; @@ -3783,8 +3782,8 @@ int mg_socketpair(sock_t sp[2], int sock_type) { } else if (sock_type == SOCK_DGRAM && (getsockname(sp[0], &sa.sa, &len) != 0 || connect(sock, &sa.sa, len) != 0)) { - } else if ((sp[1] = (sock_type == SOCK_DGRAM ? sock - : mg_socketpair_accept(sock, &sa, len))) == + } else if ((sp[1] = (sock_type == SOCK_DGRAM ? sock : mg_socketpair_accept( + sock, &sa, len))) == INVALID_SOCKET) { } else { mg_set_close_on_exec(sp[0]); From 08a10a8af5684409c815fea3867512565496a534 Mon Sep 17 00:00:00 2001 From: Deomid Ryabkov Date: Mon, 10 Apr 2017 18:34:35 +0300 Subject: [PATCH 044/137] Handle multiple MQTT messages per RECV event PUBLISHED_FROM=fc98c51254dd94d3f443fb66e49449da7d9e754c --- mongoose.c | 30 +++++++++++++++++++----------- 1 file changed, 19 insertions(+), 11 deletions(-) diff --git a/mongoose.c b/mongoose.c index fcc50833..32fe0d70 100644 --- a/mongoose.c +++ b/mongoose.c @@ -9740,21 +9740,27 @@ static const char *scanto(const char *p, struct mg_str *s) { MG_INTERNAL int parse_mqtt(struct mbuf *io, struct mg_mqtt_message *mm) { uint8_t header; - size_t len = 0; + size_t len = 0, len_len = 0; + const char *p, *end; + unsigned char lc = 0; int cmd; - const char *p = &io->buf[1], *end; if (io->len < 2) return -1; header = io->buf[0]; cmd = header >> 4; /* decode mqtt variable length */ - do { - len += (*p & 127) << 7 * (p - &io->buf[1]); - } while ((*p++ & 128) != 0 && ((size_t)(p - io->buf) <= io->len)); + len = len_len = 0; + p = io->buf + 1; + while ((size_t)(p - io->buf) < io->len) { + lc = *((const unsigned char *) p++); + len += (lc & 0x7f) << 7 * len_len; + len_len++; + if (!(lc & 0x80) || (len_len > sizeof(len))) break; + } end = p + len; - if (end > io->buf + io->len + 1) { + if (lc & 0x80 || end > io->buf + io->len) { return -1; } @@ -9829,7 +9835,6 @@ MG_INTERNAL int parse_mqtt(struct mbuf *io, struct mg_mqtt_message *mm) { static void mqtt_handler(struct mg_connection *nc, int ev, void *ev_data MG_UD_ARG(void *user_data)) { - int len; struct mbuf *io = &nc->recv_mbuf; struct mg_mqtt_message mm; memset(&mm, 0, sizeof(mm)); @@ -9838,10 +9843,13 @@ static void mqtt_handler(struct mg_connection *nc, int ev, switch (ev) { case MG_EV_RECV: - len = parse_mqtt(io, &mm); - if (len == -1) break; /* not fully buffered */ - nc->handler(nc, MG_MQTT_EVENT_BASE + mm.cmd, &mm MG_UD_ARG(user_data)); - mbuf_remove(io, len); + /* There can be multiple messages in the buffer, process them all. */ + while (1) { + int len = parse_mqtt(io, &mm); + if (len == -1) break; /* not fully buffered */ + nc->handler(nc, MG_MQTT_EVENT_BASE + mm.cmd, &mm MG_UD_ARG(user_data)); + mbuf_remove(io, len); + } break; } } From 82761bb87566fde0739303b2e8cf6e2362f54daf Mon Sep 17 00:00:00 2001 From: Sergey Lyubka Date: Mon, 10 Apr 2017 23:35:24 +0100 Subject: [PATCH 045/137] Bobify format targets PUBLISHED_FROM=2c1d372e4db856e23266c29195c07968abc2ec81 --- examples/ESP8266_RTOS/user/mongoose.h | 5895 ++++++++++++++++++++++++- 1 file changed, 5894 insertions(+), 1 deletion(-) mode change 120000 => 100644 examples/ESP8266_RTOS/user/mongoose.h diff --git a/examples/ESP8266_RTOS/user/mongoose.h b/examples/ESP8266_RTOS/user/mongoose.h deleted file mode 120000 index ee4ac823..00000000 --- a/examples/ESP8266_RTOS/user/mongoose.h +++ /dev/null @@ -1 +0,0 @@ -../../../mongoose.h \ No newline at end of file diff --git a/examples/ESP8266_RTOS/user/mongoose.h b/examples/ESP8266_RTOS/user/mongoose.h new file mode 100644 index 00000000..4fb82737 --- /dev/null +++ b/examples/ESP8266_RTOS/user/mongoose.h @@ -0,0 +1,5894 @@ +#ifdef MG_MODULE_LINES +#line 1 "mongoose/src/common.h" +#endif +/* + * Copyright (c) 2004-2013 Sergey Lyubka + * Copyright (c) 2013-2015 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. + * + * Alternatively, you can license this software under a commercial + * license, as set out in . + */ + +#ifndef CS_MONGOOSE_SRC_COMMON_H_ +#define CS_MONGOOSE_SRC_COMMON_H_ + +#define MG_VERSION "6.7" + +/* Local tweaks, applied before any of Mongoose's own headers. */ +#ifdef MG_LOCALS +#include +#endif + +#endif /* CS_MONGOOSE_SRC_COMMON_H_ */ +#ifdef MG_MODULE_LINES +#line 1 "common/platform.h" +#endif +#ifndef CS_COMMON_PLATFORM_H_ +#define CS_COMMON_PLATFORM_H_ + +/* + * For the "custom" platform, includes and dependencies can be + * provided through mg_locals.h. + */ +#define CS_P_CUSTOM 0 +#define CS_P_UNIX 1 +#define CS_P_WINDOWS 2 +#define CS_P_ESP32 15 +#define CS_P_ESP8266 3 +#define CS_P_CC3200 4 +#define CS_P_MSP432 5 +#define CS_P_CC3100 6 +#define CS_P_TM4C129 14 +#define CS_P_MBED 7 +#define CS_P_WINCE 8 +#define CS_P_NXP_LPC 13 +#define CS_P_NXP_KINETIS 9 +#define CS_P_NRF51 12 +#define CS_P_NRF52 10 +#define CS_P_PIC32 11 +#define CS_P_STM32 16 +/* Next id: 17 */ + +/* If not specified explicitly, we guess platform by defines. */ +#ifndef CS_PLATFORM + +#if defined(TARGET_IS_MSP432P4XX) || defined(__MSP432P401R__) +#define CS_PLATFORM CS_P_MSP432 +#elif defined(cc3200) +#define CS_PLATFORM CS_P_CC3200 +#elif defined(__unix__) || defined(__APPLE__) +#define CS_PLATFORM CS_P_UNIX +#elif defined(WINCE) +#define CS_PLATFORM CS_P_WINCE +#elif defined(_WIN32) +#define CS_PLATFORM CS_P_WINDOWS +#elif defined(__MBED__) +#define CS_PLATFORM CS_P_MBED +#elif defined(__USE_LPCOPEN) +#define CS_PLATFORM CS_P_NXP_LPC +#elif defined(FRDM_K64F) || defined(FREEDOM) +#define CS_PLATFORM CS_P_NXP_KINETIS +#elif defined(PIC32) +#define CS_PLATFORM CS_P_PIC32 +#elif defined(ESP_PLATFORM) +#define CS_PLATFORM CS_P_ESP32 +#elif defined(ICACHE_FLASH) +#define CS_PLATFORM CS_P_ESP8266 +#elif defined(TARGET_IS_TM4C129_RA0) || defined(TARGET_IS_TM4C129_RA1) || \ + defined(TARGET_IS_TM4C129_RA2) +#define CS_PLATFORM CS_P_TM4C129 +#elif defined(STM32) +#define CS_PLATFORM CS_P_STM32 +#endif + +#ifndef CS_PLATFORM +#error "CS_PLATFORM is not specified and we couldn't guess it." +#endif + +#endif /* !defined(CS_PLATFORM) */ + +#define MG_NET_IF_SOCKET 1 +#define MG_NET_IF_SIMPLELINK 2 +#define MG_NET_IF_LWIP_LOW_LEVEL 3 +#define MG_NET_IF_PIC32 4 + +#define MG_SSL_IF_OPENSSL 1 +#define MG_SSL_IF_MBEDTLS 2 +#define MG_SSL_IF_SIMPLELINK 3 + +/* Amalgamated: #include "common/platforms/platform_unix.h" */ +/* Amalgamated: #include "common/platforms/platform_windows.h" */ +/* Amalgamated: #include "common/platforms/platform_esp32.h" */ +/* Amalgamated: #include "common/platforms/platform_esp8266.h" */ +/* Amalgamated: #include "common/platforms/platform_cc3200.h" */ +/* Amalgamated: #include "common/platforms/platform_cc3100.h" */ +/* Amalgamated: #include "common/platforms/platform_mbed.h" */ +/* Amalgamated: #include "common/platforms/platform_nrf51.h" */ +/* Amalgamated: #include "common/platforms/platform_nrf52.h" */ +/* Amalgamated: #include "common/platforms/platform_wince.h" */ +/* Amalgamated: #include "common/platforms/platform_nxp_lpc.h" */ +/* Amalgamated: #include "common/platforms/platform_nxp_kinetis.h" */ +/* Amalgamated: #include "common/platforms/platform_pic32.h" */ +/* Amalgamated: #include "common/platforms/platform_stm32.h" */ + +/* Common stuff */ + +#if !defined(WEAK) +#if (defined(__GNUC__) || defined(__TI_COMPILER_VERSION__)) && !defined(_WIN32) +#define WEAK __attribute__((weak)) +#else +#define WEAK +#endif +#endif + +#ifdef __GNUC__ +#define NORETURN __attribute__((noreturn)) +#define NOINLINE __attribute__((noinline)) +#define WARN_UNUSED_RESULT __attribute__((warn_unused_result)) +#define NOINSTR __attribute__((no_instrument_function)) +#define DO_NOT_WARN_UNUSED __attribute__((unused)) +#else +#define NORETURN +#define NOINLINE +#define WARN_UNUSED_RESULT +#define NOINSTR +#define DO_NOT_WARN_UNUSED +#endif /* __GNUC__ */ + +#ifndef ARRAY_SIZE +#define ARRAY_SIZE(array) (sizeof(array) / sizeof(array[0])) +#endif + +#endif /* CS_COMMON_PLATFORM_H_ */ +#ifdef MG_MODULE_LINES +#line 1 "common/platforms/platform_windows.h" +#endif +#ifndef CS_COMMON_PLATFORMS_PLATFORM_WINDOWS_H_ +#define CS_COMMON_PLATFORMS_PLATFORM_WINDOWS_H_ +#if CS_PLATFORM == CS_P_WINDOWS + +/* + * MSVC++ 14.0 _MSC_VER == 1900 (Visual Studio 2015) + * MSVC++ 12.0 _MSC_VER == 1800 (Visual Studio 2013) + * MSVC++ 11.0 _MSC_VER == 1700 (Visual Studio 2012) + * MSVC++ 10.0 _MSC_VER == 1600 (Visual Studio 2010) + * MSVC++ 9.0 _MSC_VER == 1500 (Visual Studio 2008) + * MSVC++ 8.0 _MSC_VER == 1400 (Visual Studio 2005) + * MSVC++ 7.1 _MSC_VER == 1310 (Visual Studio 2003) + * MSVC++ 7.0 _MSC_VER == 1300 + * MSVC++ 6.0 _MSC_VER == 1200 + * MSVC++ 5.0 _MSC_VER == 1100 + */ +#ifdef _MSC_VER +#pragma warning(disable : 4127) /* FD_SET() emits warning, disable it */ +#pragma warning(disable : 4204) /* missing c99 support */ +#endif + +#ifndef _WINSOCK_DEPRECATED_NO_WARNINGS +#define _WINSOCK_DEPRECATED_NO_WARNINGS 1 +#endif + +#ifndef _CRT_SECURE_NO_WARNINGS +#define _CRT_SECURE_NO_WARNINGS +#endif + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#ifdef _MSC_VER +#pragma comment(lib, "ws2_32.lib") /* Linking with winsock library */ +#endif + +#include +#include +#include +#include + +#if defined(_MSC_VER) && _MSC_VER >= 1800 +#define strdup _strdup +#endif + +#ifndef EINPROGRESS +#define EINPROGRESS WSAEINPROGRESS +#endif +#ifndef EWOULDBLOCK +#define EWOULDBLOCK WSAEWOULDBLOCK +#endif +#ifndef __func__ +#define STRX(x) #x +#define STR(x) STRX(x) +#define __func__ __FILE__ ":" STR(__LINE__) +#endif +#define snprintf _snprintf +#define vsnprintf _vsnprintf +#define sleep(x) Sleep((x) *1000) +#define to64(x) _atoi64(x) +#if !defined(__MINGW32__) && !defined(__MINGW64__) +#define popen(x, y) _popen((x), (y)) +#define pclose(x) _pclose(x) +#define fileno _fileno +#endif +#define rmdir _rmdir +#if defined(_MSC_VER) && _MSC_VER >= 1400 +#define fseeko(x, y, z) _fseeki64((x), (y), (z)) +#else +#define fseeko(x, y, z) fseek((x), (y), (z)) +#endif +#if defined(_MSC_VER) && _MSC_VER <= 1200 +typedef unsigned long uintptr_t; +typedef long intptr_t; +#endif +typedef int socklen_t; +#if _MSC_VER >= 1700 +#include +#else +typedef signed char int8_t; +typedef unsigned char uint8_t; +typedef int int32_t; +typedef unsigned int uint32_t; +typedef short int16_t; +typedef unsigned short uint16_t; +typedef __int64 int64_t; +typedef unsigned __int64 uint64_t; +#endif +typedef SOCKET sock_t; +typedef uint32_t in_addr_t; +#ifndef UINT16_MAX +#define UINT16_MAX 65535 +#endif +#ifndef UINT32_MAX +#define UINT32_MAX 4294967295 +#endif +#ifndef pid_t +#define pid_t HANDLE +#endif +#define INT64_FMT "I64d" +#define INT64_X_FMT "I64x" +#define SIZE_T_FMT "Iu" +typedef struct _stati64 cs_stat_t; +#ifndef S_ISDIR +#define S_ISDIR(x) (((x) &_S_IFMT) == _S_IFDIR) +#endif +#ifndef S_ISREG +#define S_ISREG(x) (((x) &_S_IFMT) == _S_IFREG) +#endif +#define DIRSEP '\\' +#define CS_DEFINE_DIRENT + +#ifndef va_copy +#ifdef __va_copy +#define va_copy __va_copy +#else +#define va_copy(x, y) (x) = (y) +#endif +#endif + +#ifndef MG_MAX_HTTP_REQUEST_SIZE +#define MG_MAX_HTTP_REQUEST_SIZE 8192 +#endif + +#ifndef MG_MAX_HTTP_SEND_MBUF +#define MG_MAX_HTTP_SEND_MBUF 4096 +#endif + +#ifndef MG_MAX_HTTP_HEADERS +#define MG_MAX_HTTP_HEADERS 40 +#endif + +#ifndef CS_ENABLE_STDIO +#define CS_ENABLE_STDIO 1 +#endif + +#ifndef MG_ENABLE_BROADCAST +#define MG_ENABLE_BROADCAST 1 +#endif + +#ifndef MG_ENABLE_DIRECTORY_LISTING +#define MG_ENABLE_DIRECTORY_LISTING 1 +#endif + +#ifndef MG_ENABLE_FILESYSTEM +#define MG_ENABLE_FILESYSTEM 1 +#endif + +#ifndef MG_ENABLE_HTTP_CGI +#define MG_ENABLE_HTTP_CGI MG_ENABLE_FILESYSTEM +#endif + +#ifndef MG_NET_IF +#define MG_NET_IF MG_NET_IF_SOCKET +#endif + +#endif /* CS_PLATFORM == CS_P_WINDOWS */ +#endif /* CS_COMMON_PLATFORMS_PLATFORM_WINDOWS_H_ */ +#ifdef MG_MODULE_LINES +#line 1 "common/platforms/platform_unix.h" +#endif +#ifndef CS_COMMON_PLATFORMS_PLATFORM_UNIX_H_ +#define CS_COMMON_PLATFORMS_PLATFORM_UNIX_H_ +#if CS_PLATFORM == CS_P_UNIX + +#ifndef _XOPEN_SOURCE +#define _XOPEN_SOURCE 600 +#endif + +/* wants this for C++ */ +#ifndef __STDC_FORMAT_MACROS +#define __STDC_FORMAT_MACROS +#endif + +/* C++ wants that for INT64_MAX */ +#ifndef __STDC_LIMIT_MACROS +#define __STDC_LIMIT_MACROS +#endif + +/* Enable fseeko() and ftello() functions */ +#ifndef _LARGEFILE_SOURCE +#define _LARGEFILE_SOURCE +#endif + +/* Enable 64-bit file offsets */ +#ifndef _FILE_OFFSET_BITS +#define _FILE_OFFSET_BITS 64 +#endif + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#ifdef __APPLE__ +#include +#ifndef BYTE_ORDER +#define LITTLE_ENDIAN __DARWIN_LITTLE_ENDIAN +#define BIG_ENDIAN __DARWIN_BIG_ENDIAN +#define PDP_ENDIAN __DARWIN_PDP_ENDIAN +#define BYTE_ORDER __DARWIN_BYTE_ORDER +#endif +#endif + +/* + * osx correctly avoids defining strtoll when compiling in strict ansi mode. + * c++ 11 standard defines strtoll as well. + * We require strtoll, and if your embedded pre-c99 compiler lacks one, please + * implement a shim. + */ +#if !(defined(__cplusplus) && __cplusplus >= 201103L) && \ + !(defined(__DARWIN_C_LEVEL) && __DARWIN_C_LEVEL >= 200809L) +long long strtoll(const char *, char **, int); +#endif + +typedef int sock_t; +#define INVALID_SOCKET (-1) +#define SIZE_T_FMT "zu" +typedef struct stat cs_stat_t; +#define DIRSEP '/' +#define to64(x) strtoll(x, NULL, 10) +#define INT64_FMT PRId64 +#define INT64_X_FMT PRIx64 + +#ifndef __cdecl +#define __cdecl +#endif + +#ifndef va_copy +#ifdef __va_copy +#define va_copy __va_copy +#else +#define va_copy(x, y) (x) = (y) +#endif +#endif + +#define closesocket(x) close(x) + +#ifndef MG_MAX_HTTP_REQUEST_SIZE +#define MG_MAX_HTTP_REQUEST_SIZE 8192 +#endif + +#ifndef MG_MAX_HTTP_SEND_MBUF +#define MG_MAX_HTTP_SEND_MBUF 4096 +#endif + +#ifndef MG_MAX_HTTP_HEADERS +#define MG_MAX_HTTP_HEADERS 40 +#endif + +#ifndef CS_ENABLE_STDIO +#define CS_ENABLE_STDIO 1 +#endif + +#ifndef MG_ENABLE_BROADCAST +#define MG_ENABLE_BROADCAST 1 +#endif + +#ifndef MG_ENABLE_DIRECTORY_LISTING +#define MG_ENABLE_DIRECTORY_LISTING 1 +#endif + +#ifndef MG_ENABLE_FILESYSTEM +#define MG_ENABLE_FILESYSTEM 1 +#endif + +#ifndef MG_ENABLE_HTTP_CGI +#define MG_ENABLE_HTTP_CGI MG_ENABLE_FILESYSTEM +#endif + +#ifndef MG_NET_IF +#define MG_NET_IF MG_NET_IF_SOCKET +#endif + +#endif /* CS_PLATFORM == CS_P_UNIX */ +#endif /* CS_COMMON_PLATFORMS_PLATFORM_UNIX_H_ */ +#ifdef MG_MODULE_LINES +#line 1 "common/platforms/platform_esp32.h" +#endif +/* + * Copyright (c) 2014-2016 Cesanta Software Limited + * All rights reserved + */ + +#ifndef CS_COMMON_PLATFORMS_PLATFORM_ESP32_H_ +#define CS_COMMON_PLATFORMS_PLATFORM_ESP32_H_ +#if CS_PLATFORM == CS_P_ESP32 + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#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 _FILE_OFFSET_BITS 32 + +#define MG_LWIP 1 + +#ifndef MG_NET_IF +#define MG_NET_IF MG_NET_IF_SOCKET +#endif + +#ifndef CS_ENABLE_STDIO +#define CS_ENABLE_STDIO 1 +#endif + +#endif /* CS_PLATFORM == CS_P_ESP32 */ +#endif /* CS_COMMON_PLATFORMS_PLATFORM_ESP32_H_ */ +#ifdef MG_MODULE_LINES +#line 1 "common/platforms/platform_esp8266.h" +#endif +/* + * Copyright (c) 2014-2016 Cesanta Software Limited + * All rights reserved + */ + +#ifndef CS_COMMON_PLATFORMS_PLATFORM_ESP8266_H_ +#define CS_COMMON_PLATFORMS_PLATFORM_ESP8266_H_ +#if CS_PLATFORM == CS_P_ESP8266 + +#include +#include +#include +#include +#include +#include +#include +#include + +#define SIZE_T_FMT "u" +typedef struct stat cs_stat_t; +#define DIRSEP '/' +#define CS_DEFINE_DIRENT + +#define to64(x) strtoll(x, NULL, 10) +#define INT64_FMT PRId64 +#define INT64_X_FMT PRIx64 +#define __cdecl +#define _FILE_OFFSET_BITS 32 + +#ifndef RTOS_SDK +#define fileno(x) -1 +#endif + +#define MG_LWIP 1 + +/* struct timeval is defined in sys/time.h. */ +#define LWIP_TIMEVAL_PRIVATE 0 + +#ifndef MG_NET_IF +#include +#if LWIP_SOCKET /* RTOS SDK has LWIP sockets */ +#define MG_NET_IF MG_NET_IF_SOCKET +#else +#define MG_NET_IF MG_NET_IF_LWIP_LOW_LEVEL +#endif +#endif + +#ifndef CS_ENABLE_STDIO +#define CS_ENABLE_STDIO 1 +#endif + +#endif /* CS_PLATFORM == CS_P_ESP8266 */ +#endif /* CS_COMMON_PLATFORMS_PLATFORM_ESP8266_H_ */ +#ifdef MG_MODULE_LINES +#line 1 "common/platforms/platform_cc3100.h" +#endif +/* + * Copyright (c) 2014-2016 Cesanta Software Limited + * All rights reserved + */ + +#ifndef CS_COMMON_PLATFORMS_PLATFORM_CC3100_H_ +#define CS_COMMON_PLATFORMS_PLATFORM_CC3100_H_ +#if CS_PLATFORM == CS_P_CC3100 + +#include +#include +#include +#include +#include +#include +#include + +#define MG_NET_IF MG_NET_IF_SIMPLELINK +#define MG_SSL_IF MG_SSL_IF_SIMPLELINK + +/* + * CC3100 SDK and STM32 SDK include headers w/out path, just like + * #include "simplelink.h". As result, we have to add all required directories + * into Makefile IPATH and do the same thing (include w/out path) + */ + +#include +#include +#undef timeval + +typedef int sock_t; +#define INVALID_SOCKET (-1) + +#define to64(x) strtoll(x, NULL, 10) +#define INT64_FMT PRId64 +#define INT64_X_FMT PRIx64 +#define SIZE_T_FMT "u" + +#define SOMAXCONN 8 + +const char *inet_ntop(int af, const void *src, char *dst, socklen_t size); +char *inet_ntoa(struct in_addr in); +int inet_pton(int af, const char *src, void *dst); + +#endif /* CS_PLATFORM == CS_P_CC3100 */ +#endif /* CS_COMMON_PLATFORMS_PLATFORM_CC3100_H_ */ +#ifdef MG_MODULE_LINES +#line 1 "common/platforms/platform_cc3200.h" +#endif +/* + * Copyright (c) 2014-2016 Cesanta Software Limited + * All rights reserved + */ + +#ifndef CS_COMMON_PLATFORMS_PLATFORM_CC3200_H_ +#define CS_COMMON_PLATFORMS_PLATFORM_CC3200_H_ +#if CS_PLATFORM == CS_P_CC3200 + +#include +#include +#include +#include +#include +#include +#include + +#ifndef __TI_COMPILER_VERSION__ +#include +#include +#endif + +#define MG_NET_IF MG_NET_IF_SIMPLELINK +#define MG_SSL_IF MG_SSL_IF_SIMPLELINK + +/* Only SPIFFS supports directories, SLFS does not. */ +#if defined(CC3200_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 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); +#define stat(a, b) _stat(a, b) + +#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) + +/* As of 5.2.7, TI compiler does not support va_copy() yet. */ +#define va_copy(apc, ap) ((apc) = (ap)) + +#endif /* __TI_COMPILER_VERSION__ */ + +#ifdef CC3200_FS_SLFS +#define MG_FS_SLFS +#endif + +#if (defined(CC3200_FS_SPIFFS) || defined(CC3200_FS_SLFS)) && \ + !defined(MG_ENABLE_FILESYSTEM) +#define MG_ENABLE_FILESYSTEM 1 +#define CS_DEFINE_DIRENT +#endif + +#ifndef CS_ENABLE_STDIO +#define CS_ENABLE_STDIO 1 +#endif + +#ifdef __cplusplus +} +#endif + +#endif /* CS_PLATFORM == CS_P_CC3200 */ +#endif /* CS_COMMON_PLATFORMS_PLATFORM_CC3200_H_ */ +#ifdef MG_MODULE_LINES +#line 1 "common/platforms/platform_msp432.h" +#endif +/* + * Copyright (c) 2014-2016 Cesanta Software Limited + * All rights reserved + */ + +#ifndef CS_COMMON_PLATFORMS_PLATFORM_MSP432_H_ +#define CS_COMMON_PLATFORMS_PLATFORM_MSP432_H_ +#if CS_PLATFORM == CS_P_MSP432 + +#include +#include +#include +#include +#include +#include +#include + +#ifndef __TI_COMPILER_VERSION__ +#include +#include +#endif + +#define MG_NET_IF MG_NET_IF_SIMPLELINK +#define MG_SSL_IF MG_SSL_IF_SIMPLELINK + +/* 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); +#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); +#define stat(a, b) _stat(a, b) + +#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) + +/* As of 5.2.7, TI compiler does not support va_copy() yet. */ +#define va_copy(apc, ap) ((apc) = (ap)) + +#endif /* __TI_COMPILER_VERSION__ */ + +#ifndef CS_ENABLE_STDIO +#define CS_ENABLE_STDIO 1 +#endif + +#if (defined(CC3200_FS_SPIFFS) || defined(CC3200_FS_SLFS)) && \ + !defined(MG_ENABLE_FILESYSTEM) +#define MG_ENABLE_FILESYSTEM 1 +#endif + +#ifdef __cplusplus +} +#endif + +#endif /* CS_PLATFORM == CS_P_MSP432 */ +#endif /* CS_COMMON_PLATFORMS_PLATFORM_MSP432_H_ */ +#ifdef MG_MODULE_LINES +#line 1 "common/platforms/platform_tm4c129.h" +#endif +/* + * Copyright (c) 2014-2016 Cesanta Software Limited + * All rights reserved + */ + +#ifndef CS_COMMON_PLATFORMS_PLATFORM_TM4C129_H_ +#define CS_COMMON_PLATFORMS_PLATFORM_TM4C129_H_ +#if CS_PLATFORM == CS_P_TM4C129 + +#include +#include +#include +#include +#include +#include +#include + +#ifndef __TI_COMPILER_VERSION__ +#include +#include +#endif + +#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 + +#ifndef MG_NET_IF +#include +#if LWIP_SOCKET +#define MG_NET_IF MG_NET_IF_SOCKET +#else +#define MG_NET_IF MG_NET_IF_LWIP_LOW_LEVEL +#endif +#define MG_LWIP 1 +#elif MG_NET_IF == MG_NET_IF_SIMPLELINK +#include "common/platforms/simplelink/cs_simplelink.h" +#endif + +#ifndef CS_ENABLE_STDIO +#define CS_ENABLE_STDIO 1 +#endif + +#ifdef __TI_COMPILER_VERSION__ +/* As of 5.2.8, TI compiler does not support va_copy() yet. */ +#define va_copy(apc, ap) ((apc) = (ap)) +#endif /* __TI_COMPILER_VERSION__ */ + +#ifdef __cplusplus +} +#endif + +#endif /* CS_PLATFORM == CS_P_TM4C129 */ +#endif /* CS_COMMON_PLATFORMS_PLATFORM_TM4C129_H_ */ +#ifdef MG_MODULE_LINES +#line 1 "common/platforms/platform_mbed.h" +#endif +/* + * Copyright (c) 2014-2016 Cesanta Software Limited + * All rights reserved + */ + +#ifndef CS_COMMON_PLATFORMS_PLATFORM_MBED_H_ +#define CS_COMMON_PLATFORMS_PLATFORM_MBED_H_ +#if CS_PLATFORM == CS_P_MBED + +/* + * mbed.h contains C++ code (e.g. templates), thus, it should be processed + * only if included directly to startup file (ex: main.cpp) + */ +#ifdef __cplusplus +/* Amalgamated: #include "mbed.h" */ +#endif /* __cplusplus */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +typedef struct stat cs_stat_t; +#define DIRSEP '/' + +#ifndef CS_ENABLE_STDIO +#define CS_ENABLE_STDIO 1 +#endif + +/* + * mbed can be compiled with the ARM compiler which + * just doesn't come with a gettimeofday shim + * because it's a BSD API and ARM targets embedded + * non-unix platforms. + */ +#if defined(__ARMCC_VERSION) || defined(__ICCARM__) +#define _TIMEVAL_DEFINED +#define gettimeofday _gettimeofday + +/* copied from GCC on ARM; for some reason useconds are signed */ +typedef long suseconds_t; /* microseconds (signed) */ +struct timeval { + time_t tv_sec; /* seconds */ + suseconds_t tv_usec; /* and microseconds */ +}; + +#endif + +#if MG_NET_IF == MG_NET_IF_SIMPLELINK + +#define MG_SIMPLELINK_NO_OSI 1 + +#include + +typedef int sock_t; +#define INVALID_SOCKET (-1) + +#define to64(x) strtoll(x, NULL, 10) +#define INT64_FMT PRId64 +#define INT64_X_FMT PRIx64 +#define SIZE_T_FMT "u" + +#define SOMAXCONN 8 + +const char *inet_ntop(int af, const void *src, char *dst, socklen_t size); +char *inet_ntoa(struct in_addr in); +int inet_pton(int af, const char *src, void *dst); +int inet_aton(const char *cp, struct in_addr *inp); +in_addr_t inet_addr(const char *cp); + +#endif /* MG_NET_IF == MG_NET_IF_SIMPLELINK */ + +#endif /* CS_PLATFORM == CS_P_MBED */ +#endif /* CS_COMMON_PLATFORMS_PLATFORM_MBED_H_ */ +#ifdef MG_MODULE_LINES +#line 1 "common/platforms/platform_nrf51.h" +#endif +/* + * Copyright (c) 2014-2016 Cesanta Software Limited + * All rights reserved + */ +#ifndef CS_COMMON_PLATFORMS_PLATFORM_NRF51_H_ +#define CS_COMMON_PLATFORMS_PLATFORM_NRF51_H_ +#if CS_PLATFORM == CS_P_NRF51 + +#include +#include +#include +#include +#include +#include + +#define to64(x) strtoll(x, NULL, 10) + +#define MG_NET_IF MG_NET_IF_LWIP_LOW_LEVEL +#define MG_LWIP 1 +#define MG_ENABLE_IPV6 1 + +/* + * For ARM C Compiler, make lwip to export `struct timeval`; for other + * compilers, suppress it. + */ +#if !defined(__ARMCC_VERSION) +#define LWIP_TIMEVAL_PRIVATE 0 +#else +struct timeval; +int gettimeofday(struct timeval *tp, void *tzp); +#endif + +#define INT64_FMT PRId64 +#define SIZE_T_FMT "u" + +/* + * ARM C Compiler doesn't have strdup, so we provide it + */ +#define CS_ENABLE_STRDUP defined(__ARMCC_VERSION) + +#endif /* CS_PLATFORM == CS_P_NRF51 */ +#endif /* CS_COMMON_PLATFORMS_PLATFORM_NRF51_H_ */ +#ifdef MG_MODULE_LINES +#line 1 "common/platforms/platform_nrf52.h" +#endif +/* + * Copyright (c) 2014-2016 Cesanta Software Limited + * All rights reserved + */ +#ifndef CS_COMMON_PLATFORMS_PLATFORM_NRF52_H_ +#define CS_COMMON_PLATFORMS_PLATFORM_NRF52_H_ +#if CS_PLATFORM == CS_P_NRF52 + +#include +#include +#include +#include +#include +#include +#include + +#define to64(x) strtoll(x, NULL, 10) + +#define MG_NET_IF MG_NET_IF_LWIP_LOW_LEVEL +#define MG_LWIP 1 +#define MG_ENABLE_IPV6 1 + +#if !defined(ENOSPC) +#define ENOSPC 28 /* No space left on device */ +#endif + +/* + * For ARM C Compiler, make lwip to export `struct timeval`; for other + * compilers, suppress it. + */ +#if !defined(__ARMCC_VERSION) +#define LWIP_TIMEVAL_PRIVATE 0 +#endif + +#define INT64_FMT PRId64 +#define SIZE_T_FMT "u" + +/* + * ARM C Compiler doesn't have strdup, so we provide it + */ +#define CS_ENABLE_STRDUP defined(__ARMCC_VERSION) + +#endif /* CS_PLATFORM == CS_P_NRF52 */ +#endif /* CS_COMMON_PLATFORMS_PLATFORM_NRF52_H_ */ +#ifdef MG_MODULE_LINES +#line 1 "common/platforms/simplelink/cs_simplelink.h" +#endif +/* + * Copyright (c) 2014-2016 Cesanta Software Limited + * All rights reserved + */ + +#ifndef CS_COMMON_PLATFORMS_SIMPLELINK_CS_SIMPLELINK_H_ +#define CS_COMMON_PLATFORMS_SIMPLELINK_CS_SIMPLELINK_H_ + +/* If simplelink.h is already included, all bets are off. */ +#if defined(MG_NET_IF) && MG_NET_IF == MG_NET_IF_SIMPLELINK && \ + !defined(__SIMPLELINK_H__) + +#include + +#ifndef __TI_COMPILER_VERSION__ +#undef __CONCAT +#undef FD_CLR +#undef FD_ISSET +#undef FD_SET +#undef FD_SETSIZE +#undef FD_ZERO +#undef fd_set +#endif + +/* We want to disable SL_INC_STD_BSD_API_NAMING, so we include user.h ourselves + * and undef it. */ +#define PROVISIONING_API_H_ +#include +#undef PROVISIONING_API_H_ +#undef SL_INC_STD_BSD_API_NAMING + +#include +#include + +/* Now define only the subset of the BSD API that we use. + * Notably, close(), read() and write() are not defined. */ +#define AF_INET SL_AF_INET + +#define socklen_t SlSocklen_t +#define sockaddr SlSockAddr_t +#define sockaddr_in SlSockAddrIn_t +#define in_addr SlInAddr_t + +#define SOCK_STREAM SL_SOCK_STREAM +#define SOCK_DGRAM SL_SOCK_DGRAM + +#define htonl sl_Htonl +#define ntohl sl_Ntohl +#define htons sl_Htons +#define ntohs sl_Ntohs + +#ifndef EACCES +#define EACCES SL_EACCES +#endif +#ifndef EAFNOSUPPORT +#define EAFNOSUPPORT SL_EAFNOSUPPORT +#endif +#ifndef EAGAIN +#define EAGAIN SL_EAGAIN +#endif +#ifndef EBADF +#define EBADF SL_EBADF +#endif +#ifndef EINVAL +#define EINVAL SL_EINVAL +#endif +#ifndef ENOMEM +#define ENOMEM SL_ENOMEM +#endif +#ifndef EWOULDBLOCK +#define EWOULDBLOCK SL_EWOULDBLOCK +#endif + +#define SOMAXCONN 8 + +#ifdef __cplusplus +extern "C" { +#endif + +const char *inet_ntop(int af, const void *src, char *dst, socklen_t size); +char *inet_ntoa(struct in_addr in); +int inet_pton(int af, const char *src, void *dst); + +struct mg_mgr; +struct mg_connection; + +typedef void (*mg_init_cb)(struct mg_mgr *mgr); +bool mg_start_task(int priority, int stack_size, mg_init_cb mg_init); + +void mg_run_in_task(void (*cb)(struct mg_mgr *mgr, void *arg), void *cb_arg); + +int sl_fs_init(void); + +void sl_restart_cb(struct mg_mgr *mgr); + +int sl_set_ssl_opts(struct mg_connection *nc); + +#ifdef __cplusplus +} +#endif + +#endif /* MG_NET_IF == MG_NET_IF_SIMPLELINK && !defined(__SIMPLELINK_H__) */ + +#endif /* CS_COMMON_PLATFORMS_SIMPLELINK_CS_SIMPLELINK_H_ */ +#ifdef MG_MODULE_LINES +#line 1 "common/platforms/platform_wince.h" +#endif +#ifndef CS_COMMON_PLATFORMS_PLATFORM_WINCE_H_ +#define CS_COMMON_PLATFORMS_PLATFORM_WINCE_H_ + +#if CS_PLATFORM == CS_P_WINCE + +/* + * MSVC++ 14.0 _MSC_VER == 1900 (Visual Studio 2015) + * MSVC++ 12.0 _MSC_VER == 1800 (Visual Studio 2013) + * MSVC++ 11.0 _MSC_VER == 1700 (Visual Studio 2012) + * MSVC++ 10.0 _MSC_VER == 1600 (Visual Studio 2010) + * MSVC++ 9.0 _MSC_VER == 1500 (Visual Studio 2008) + * MSVC++ 8.0 _MSC_VER == 1400 (Visual Studio 2005) + * MSVC++ 7.1 _MSC_VER == 1310 (Visual Studio 2003) + * MSVC++ 7.0 _MSC_VER == 1300 + * MSVC++ 6.0 _MSC_VER == 1200 + * MSVC++ 5.0 _MSC_VER == 1100 + */ +#pragma warning(disable : 4127) /* FD_SET() emits warning, disable it */ +#pragma warning(disable : 4204) /* missing c99 support */ + +#ifndef _WINSOCK_DEPRECATED_NO_WARNINGS +#define _WINSOCK_DEPRECATED_NO_WARNINGS 1 +#endif + +#ifndef _CRT_SECURE_NO_WARNINGS +#define _CRT_SECURE_NO_WARNINGS +#endif + +#include +#include +#include +#include +#include +#include + +#pragma comment(lib, "ws2.lib") /* Linking with WinCE winsock library */ + +#include +#include +#include + +#define strdup _strdup + +#ifndef EINPROGRESS +#define EINPROGRESS WSAEINPROGRESS +#endif + +#ifndef EWOULDBLOCK +#define EWOULDBLOCK WSAEWOULDBLOCK +#endif + +#ifndef EAGAIN +#define EAGAIN EWOULDBLOCK +#endif + +#ifndef __func__ +#define STRX(x) #x +#define STR(x) STRX(x) +#define __func__ __FILE__ ":" STR(__LINE__) +#endif + +#define snprintf _snprintf +#define fileno _fileno +#define vsnprintf _vsnprintf +#define sleep(x) Sleep((x) *1000) +#define to64(x) _atoi64(x) +#define rmdir _rmdir + +#if defined(_MSC_VER) && _MSC_VER >= 1400 +#define fseeko(x, y, z) _fseeki64((x), (y), (z)) +#else +#define fseeko(x, y, z) fseek((x), (y), (z)) +#endif + +typedef int socklen_t; + +#if _MSC_VER >= 1700 +#include +#else +typedef signed char int8_t; +typedef unsigned char uint8_t; +typedef int int32_t; +typedef unsigned int uint32_t; +typedef short int16_t; +typedef unsigned short uint16_t; +typedef __int64 int64_t; +typedef unsigned __int64 uint64_t; +#endif + +typedef SOCKET sock_t; +typedef uint32_t in_addr_t; + +#ifndef UINT16_MAX +#define UINT16_MAX 65535 +#endif + +#ifndef UINT32_MAX +#define UINT32_MAX 4294967295 +#endif + +#ifndef pid_t +#define pid_t HANDLE +#endif + +#define INT64_FMT "I64d" +#define INT64_X_FMT "I64x" +/* TODO(alashkin): check if this is correct */ +#define SIZE_T_FMT "u" + +#define DIRSEP '\\' +#define CS_DEFINE_DIRENT + +#ifndef va_copy +#ifdef __va_copy +#define va_copy __va_copy +#else +#define va_copy(x, y) (x) = (y) +#endif +#endif + +#ifndef MG_MAX_HTTP_REQUEST_SIZE +#define MG_MAX_HTTP_REQUEST_SIZE 8192 +#endif + +#ifndef MG_MAX_HTTP_SEND_MBUF +#define MG_MAX_HTTP_SEND_MBUF 4096 +#endif + +#ifndef MG_MAX_HTTP_HEADERS +#define MG_MAX_HTTP_HEADERS 40 +#endif + +#ifndef CS_ENABLE_STDIO +#define CS_ENABLE_STDIO 1 +#endif + +#define abort() DebugBreak(); + +#ifndef BUFSIZ +#define BUFSIZ 4096 +#endif +/* + * Explicitly disabling MG_ENABLE_THREADS for WinCE + * because they are enabled for _WIN32 by default + */ +#ifndef MG_ENABLE_THREADS +#define MG_ENABLE_THREADS 0 +#endif + +#ifndef MG_ENABLE_FILESYSTEM +#define MG_ENABLE_FILESYSTEM 1 +#endif + +#ifndef MG_NET_IF +#define MG_NET_IF MG_NET_IF_SOCKET +#endif + +typedef struct _stati64 { + uint32_t st_mtime; + uint32_t st_size; + uint32_t st_mode; +} cs_stat_t; + +/* + * WinCE 6.0 has a lot of useful definitions in ATL (not windows.h) headers + * use #ifdefs to avoid conflicts + */ + +#ifndef ENOENT +#define ENOENT ERROR_PATH_NOT_FOUND +#endif + +#ifndef EACCES +#define EACCES ERROR_ACCESS_DENIED +#endif + +#ifndef ENOMEM +#define ENOMEM ERROR_NOT_ENOUGH_MEMORY +#endif + +#ifndef _UINTPTR_T_DEFINED +typedef unsigned int *uintptr_t; +#endif + +#define _S_IFREG 2 +#define _S_IFDIR 4 + +#ifndef S_ISDIR +#define S_ISDIR(x) (((x) &_S_IFDIR) != 0) +#endif + +#ifndef S_ISREG +#define S_ISREG(x) (((x) &_S_IFREG) != 0) +#endif + +int open(const char *filename, int oflag, int pmode); +int _wstati64(const wchar_t *path, cs_stat_t *st); +const char *strerror(); + +#endif /* CS_PLATFORM == CS_P_WINCE */ +#endif /* CS_COMMON_PLATFORMS_PLATFORM_WINCE_H_ */ +#ifdef MG_MODULE_LINES +#line 1 "common/platforms/platform_nxp_lpc.h" +#endif +/* + * Copyright (c) 2014-2016 Cesanta Software Limited + * All rights reserved + */ + +#ifndef CS_COMMON_PLATFORMS_PLATFORM_NXP_LPC_H_ +#define CS_COMMON_PLATFORMS_PLATFORM_NXP_LPC_H_ + +#if CS_PLATFORM == CS_P_NXP_LPC + +#include +#include +#include + +#define SIZE_T_FMT "u" +typedef struct stat cs_stat_t; +#define INT64_FMT "lld" +#define INT64_X_FMT "llx" +#define __cdecl + +#define MG_LWIP 1 + +#define MG_NET_IF MG_NET_IF_LWIP_LOW_LEVEL + +/* + * LPCXpress comes with 3 C library implementations: Newlib, NewlibNano and + *Redlib. + * See https://community.nxp.com/message/630860 for more details. + * + * Redlib is the default and lacks certain things, so we provide them. + */ +#ifdef __REDLIB_INTERFACE_VERSION__ + +/* Let LWIP define timeval for us. */ +#define LWIP_TIMEVAL_PRIVATE 1 + +#define va_copy(d, s) __builtin_va_copy(d, s) + +#define CS_ENABLE_TO64 1 +#define to64(x) cs_to64(x) + +#define CS_ENABLE_STRDUP 1 + +#else + +#include +#define LWIP_TIMEVAL_PRIVATE 0 +#define to64(x) strtoll(x, NULL, 10) + +#endif + +#endif /* CS_PLATFORM == CS_P_NXP_LPC */ +#endif /* CS_COMMON_PLATFORMS_PLATFORM_NXP_LPC_H_ */ +#ifdef MG_MODULE_LINES +#line 1 "common/platforms/platform_nxp_kinetis.h" +#endif +/* + * Copyright (c) 2014-2016 Cesanta Software Limited + * All rights reserved + */ + +#ifndef CS_COMMON_PLATFORMS_PLATFORM_NXP_KINETIS_H_ +#define CS_COMMON_PLATFORMS_PLATFORM_NXP_KINETIS_H_ + +#if CS_PLATFORM == CS_P_NXP_KINETIS + +#include +#include +#include +#include + +#define SIZE_T_FMT "u" +typedef struct stat cs_stat_t; +#define to64(x) strtoll(x, NULL, 10) +#define INT64_FMT "lld" +#define INT64_X_FMT "llx" +#define __cdecl + +#define MG_LWIP 1 + +#define MG_NET_IF MG_NET_IF_LWIP_LOW_LEVEL + +/* struct timeval is defined in sys/time.h. */ +#define LWIP_TIMEVAL_PRIVATE 0 + +#endif /* CS_PLATFORM == CS_P_NXP_KINETIS */ +#endif /* CS_COMMON_PLATFORMS_PLATFORM_NXP_KINETIS_H_ */ +#ifdef MG_MODULE_LINES +#line 1 "common/platforms/platform_pic32.h" +#endif +/* + * Copyright (c) 2014-2016 Cesanta Software Limited + * All rights reserved + */ + +#ifndef CS_COMMON_PLATFORMS_PLATFORM_PIC32_H_ +#define CS_COMMON_PLATFORMS_PLATFORM_PIC32_H_ + +#if CS_PLATFORM == CS_P_PIC32 + +#define MG_NET_IF MG_NET_IF_PIC32 + +#include +#include +#include +#include + +#include +#include + +#include + +typedef TCP_SOCKET sock_t; +#define to64(x) strtoll(x, NULL, 10) + +#define SIZE_T_FMT "lu" +#define INT64_FMT "lld" + +#ifndef CS_ENABLE_STDIO +#define CS_ENABLE_STDIO 1 +#endif + +char *inet_ntoa(struct in_addr in); + +#endif /* CS_PLATFORM == CS_P_PIC32 */ + +#endif /* CS_COMMON_PLATFORMS_PLATFORM_PIC32_H_ */ +#ifdef MG_MODULE_LINES +#line 1 "common/platforms/platform_stm32.h" +#endif +/* + * Copyright (c) 2014-2016 Cesanta Software Limited + * All rights reserved + */ + +#ifndef CS_COMMON_PLATFORMS_PLATFORM_STM32_H_ +#define CS_COMMON_PLATFORMS_PLATFORM_STM32_H_ +#if CS_PLATFORM == CS_P_STM32 + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define to64(x) strtoll(x, NULL, 10) +#define INT64_FMT PRId64 +#define SIZE_T_FMT "u" +typedef struct stat cs_stat_t; +#define DIRSEP '/' + +#ifndef CS_ENABLE_STDIO +#define CS_ENABLE_STDIO 1 +#endif + +#ifndef MG_ENABLE_FILESYSTEM +#define MG_ENABLE_FILESYSTEM 1 +#endif + +#define CS_DEFINE_DIRENT + +#endif /* CS_PLATFORM == CS_P_STM32 */ +#endif /* CS_COMMON_PLATFORMS_PLATFORM_STM32_H_ */ +#ifdef MG_MODULE_LINES +#line 1 "common/platforms/lwip/mg_lwip.h" +#endif +/* + * Copyright (c) 2014-2016 Cesanta Software Limited + * All rights reserved + */ + +#ifndef CS_COMMON_PLATFORMS_LWIP_MG_LWIP_H_ +#define CS_COMMON_PLATFORMS_LWIP_MG_LWIP_H_ + +#ifndef MG_LWIP +#define MG_LWIP 0 +#endif + +#if MG_LWIP + +/* + * When compiling for nRF5x chips with arm-none-eabi-gcc, it has BYTE_ORDER + * already defined, so in order to avoid warnings in lwip, we have to undefine + * it. + * + * TODO: Check if in the future versions of nRF5 SDK that changes. + * Current version of nRF51 SDK: 0.8.0 + * nRF5 SDK: 0.9.0 + */ +#if CS_PLATFORM == CS_P_NRF51 || CS_PLATFORM == CS_P_NRF52 +#undef BYTE_ORDER +#endif + +#include +#include +#include +#include +#include +#include + +#ifndef LWIP_PROVIDE_ERRNO +#include +#endif + +#if LWIP_SOCKET +#include +#else +/* We really need the definitions from sockets.h. */ +#undef LWIP_SOCKET +#define LWIP_SOCKET 1 +#include +#undef LWIP_SOCKET +#define LWIP_SOCKET 0 +#endif + +#define INVALID_SOCKET (-1) +#define SOMAXCONN 10 +typedef int sock_t; + +#if MG_NET_IF == MG_NET_IF_LWIP_LOW_LEVEL +struct mg_mgr; +struct mg_connection; +uint32_t mg_lwip_get_poll_delay_ms(struct mg_mgr *mgr); +void mg_lwip_set_keepalive_params(struct mg_connection *nc, int idle, + int interval, int count); +#endif + +/* For older version of LWIP */ +#ifndef ipX_2_ip +#define ipX_2_ip(x) (x) +#endif + +#endif /* MG_LWIP */ + +#endif /* CS_COMMON_PLATFORMS_LWIP_MG_LWIP_H_ */ +#ifdef MG_MODULE_LINES +#line 1 "common/cs_time.h" +#endif +/* + * Copyright (c) 2014-2016 Cesanta Software Limited + * All rights reserved + */ + +#ifndef CS_COMMON_CS_TIME_H_ +#define CS_COMMON_CS_TIME_H_ + +/* Amalgamated: #include "common/platform.h" */ + +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + +/* Sub-second granularity time(). */ +double cs_time(void); + +#ifdef __cplusplus +} +#endif /* __cplusplus */ + +#endif /* CS_COMMON_CS_TIME_H_ */ +#ifdef MG_MODULE_LINES +#line 1 "common/mg_str.h" +#endif +/* + * Copyright (c) 2014-2016 Cesanta Software Limited + * All rights reserved + */ + +#ifndef CS_COMMON_MG_STR_H_ +#define CS_COMMON_MG_STR_H_ + +#include + +/* Amalgamated: #include "common/platform.h" */ + +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + +/* Describes chunk of memory */ +struct mg_str { + const char *p; /* Memory chunk pointer */ + size_t len; /* Memory chunk length */ +}; + +/* + * Helper functions for creating mg_str struct from plain C string. + * `NULL` is allowed and becomes `{NULL, 0}`. + */ +struct mg_str mg_mk_str(const char *s); +struct mg_str mg_mk_str_n(const char *s, size_t len); + +/* Macro for initializing mg_str. */ +#define MG_MK_STR(str_literal) \ + { str_literal, sizeof(str_literal) - 1 } + +/* + * Cross-platform version of `strcmp()` where where first string is + * specified by `struct mg_str`. + */ +int mg_vcmp(const struct mg_str *str2, const char *str1); + +/* + * Cross-platform version of `strncasecmp()` where first string is + * specified by `struct mg_str`. + */ +int mg_vcasecmp(const struct mg_str *str2, const char *str1); + +struct mg_str mg_strdup(const struct mg_str s); +int mg_strcmp(const struct mg_str str1, const struct mg_str str2); +int mg_strncmp(const struct mg_str str1, const struct mg_str str2, size_t n); + +#ifdef __cplusplus +} +#endif /* __cplusplus */ + +#endif /* CS_COMMON_MG_STR_H_ */ +#ifdef MG_MODULE_LINES +#line 1 "common/mbuf.h" +#endif +/* + * Copyright (c) 2015 Cesanta Software Limited + * All rights reserved + */ + +/* + * === Memory Buffers + * + * Mbufs are mutable/growing memory buffers, like C++ strings. + * Mbuf can append data to the end of a buffer or insert data into arbitrary + * position in the middle of a buffer. The buffer grows automatically when + * needed. + */ + +#ifndef CS_COMMON_MBUF_H_ +#define CS_COMMON_MBUF_H_ + +#include +/* Amalgamated: #include "common/platform.h" */ + +#if defined(__cplusplus) +extern "C" { +#endif + +#ifndef MBUF_SIZE_MULTIPLIER +#define MBUF_SIZE_MULTIPLIER 1.5 +#endif + +/* Memory buffer descriptor */ +struct mbuf { + char *buf; /* Buffer pointer */ + size_t len; /* Data length. Data is located between offset 0 and len. */ + size_t size; /* Buffer size allocated by realloc(1). Must be >= len */ +}; + +/* + * Initialises an Mbuf. + * `initial_capacity` specifies the initial capacity of the mbuf. + */ +void mbuf_init(struct mbuf *, size_t initial_capacity); + +/* Frees the space allocated for the mbuffer and resets the mbuf structure. */ +void mbuf_free(struct mbuf *); + +/* + * Appends data to the Mbuf. + * + * Returns the number of bytes appended or 0 if out of memory. + */ +size_t mbuf_append(struct mbuf *, const void *data, size_t data_size); + +/* + * Inserts data at a specified offset in the Mbuf. + * + * Existing data will be shifted forwards and the buffer will + * be grown if necessary. + * Returns the number of bytes inserted. + */ +size_t mbuf_insert(struct mbuf *, size_t, const void *, size_t); + +/* Removes `data_size` bytes from the beginning of the buffer. */ +void mbuf_remove(struct mbuf *, size_t data_size); + +/* + * Resizes an Mbuf. + * + * If `new_size` is smaller than buffer's `len`, the + * resize is not performed. + */ +void mbuf_resize(struct mbuf *, size_t new_size); + +/* Shrinks an Mbuf by resizing its `size` to `len`. */ +void mbuf_trim(struct mbuf *); + +#if defined(__cplusplus) +} +#endif /* __cplusplus */ + +#endif /* CS_COMMON_MBUF_H_ */ +#ifdef MG_MODULE_LINES +#line 1 "common/sha1.h" +#endif +/* + * Copyright (c) 2014 Cesanta Software Limited + * All rights reserved + */ + +#ifndef CS_COMMON_SHA1_H_ +#define CS_COMMON_SHA1_H_ + +#ifndef CS_DISABLE_SHA1 +#define CS_DISABLE_SHA1 0 +#endif + +#if !CS_DISABLE_SHA1 + +/* Amalgamated: #include "common/platform.h" */ + +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + +typedef struct { + uint32_t state[5]; + uint32_t count[2]; + unsigned char buffer[64]; +} cs_sha1_ctx; + +void cs_sha1_init(cs_sha1_ctx *); +void cs_sha1_update(cs_sha1_ctx *, const unsigned char *data, uint32_t len); +void cs_sha1_final(unsigned char digest[20], cs_sha1_ctx *); +void cs_hmac_sha1(const unsigned char *key, size_t key_len, + const unsigned char *text, size_t text_len, + unsigned char out[20]); +#ifdef __cplusplus +} +#endif /* __cplusplus */ + +#endif /* CS_DISABLE_SHA1 */ + +#endif /* CS_COMMON_SHA1_H_ */ +#ifdef MG_MODULE_LINES +#line 1 "common/md5.h" +#endif +/* + * Copyright (c) 2014 Cesanta Software Limited + * All rights reserved + */ + +#ifndef CS_COMMON_MD5_H_ +#define CS_COMMON_MD5_H_ + +/* Amalgamated: #include "common/platform.h" */ + +#ifndef CS_DISABLE_MD5 +#define CS_DISABLE_MD5 0 +#endif + +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + +typedef struct MD5Context { + uint32_t buf[4]; + uint32_t bits[2]; + unsigned char in[64]; +} MD5_CTX; + +void MD5_Init(MD5_CTX *c); +void MD5_Update(MD5_CTX *c, const unsigned char *data, size_t len); +void MD5_Final(unsigned char *md, MD5_CTX *c); + +/* + * Return stringified MD5 hash for NULL terminated list of pointer/length pairs. + * A length should be specified as size_t variable. + * Example: + * + * char buf[33]; + * cs_md5(buf, "foo", (size_t) 3, "bar", (size_t) 3, NULL); + */ +char *cs_md5(char buf[33], ...); + +#ifdef __cplusplus +} +#endif /* __cplusplus */ + +#endif /* CS_COMMON_MD5_H_ */ +#ifdef MG_MODULE_LINES +#line 1 "common/base64.h" +#endif +/* + * Copyright (c) 2014 Cesanta Software Limited + * All rights reserved + */ + +#ifndef CS_COMMON_BASE64_H_ +#define CS_COMMON_BASE64_H_ + +#ifndef DISABLE_BASE64 +#define DISABLE_BASE64 0 +#endif + +#if !DISABLE_BASE64 + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +typedef void (*cs_base64_putc_t)(char, void *); + +struct cs_base64_ctx { + /* cannot call it putc because it's a macro on some environments */ + cs_base64_putc_t b64_putc; + unsigned char chunk[3]; + int chunk_size; + void *user_data; +}; + +void cs_base64_init(struct cs_base64_ctx *ctx, cs_base64_putc_t putc, + void *user_data); +void cs_base64_update(struct cs_base64_ctx *ctx, const char *str, size_t len); +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); +int cs_base64_decode(const unsigned char *s, int len, char *dst, int *dec_len); + +#ifdef __cplusplus +} +#endif + +#endif /* DISABLE_BASE64 */ + +#endif /* CS_COMMON_BASE64_H_ */ +#ifdef MG_MODULE_LINES +#line 1 "common/str_util.h" +#endif +/* + * Copyright (c) 2015 Cesanta Software Limited + * All rights reserved + */ + +#ifndef CS_COMMON_STR_UTIL_H_ +#define CS_COMMON_STR_UTIL_H_ + +#include +#include + +/* Amalgamated: #include "common/platform.h" */ + +#ifndef CS_ENABLE_STRDUP +#define CS_ENABLE_STRDUP 0 +#endif + +#ifndef CS_ENABLE_TO64 +#define CS_ENABLE_TO64 0 +#endif + +/* + * Expands to a string representation of its argument: e.g. + * `CS_STRINGIFY_LIT(5) expands to "5"` + */ +#define CS_STRINGIFY_LIT(x) #x + +/* + * Expands to a string representation of its argument, which is allowed + * to be a macro: e.g. + * + * #define FOO 123 + * CS_STRINGIFY_MACRO(FOO) + * + * expands to 123. + */ +#define CS_STRINGIFY_MACRO(x) CS_STRINGIFY_LIT(x) + +#ifdef __cplusplus +extern "C" { +#endif + +size_t c_strnlen(const char *s, size_t maxlen); +int c_snprintf(char *buf, size_t buf_size, const char *format, ...); +int c_vsnprintf(char *buf, size_t buf_size, const char *format, va_list ap); +/* + * Find the first occurrence of find in s, where the search is limited to the + * first slen characters of s. + */ +const char *c_strnstr(const char *s, const char *find, size_t slen); + +/* + * Stringify binary data. Output buffer size must be 2 * size_of_input + 1 + * because each byte of input takes 2 bytes in string representation + * plus 1 byte for the terminating \0 character. + */ +void cs_to_hex(char *to, const unsigned char *p, size_t len); + +/* + * Convert stringified binary data back to binary. + * Does the reverse of `cs_to_hex()`. + */ +void cs_from_hex(char *to, const char *p, size_t len); + +#if CS_ENABLE_STRDUP +char *strdup(const char *src); +#endif + +#if CS_ENABLE_TO64 +#include +/* + * Simple string -> int64 conversion routine. + */ +int64_t cs_to64(const char *s); +#endif + +/* + * Cross-platform version of `strncasecmp()`. + */ +int mg_ncasecmp(const char *s1, const char *s2, size_t len); + +/* + * Cross-platform version of `strcasecmp()`. + */ +int mg_casecmp(const char *s1, const char *s2); + +/* + * Prints message to the buffer. If the buffer is large enough to hold the + * message, it returns buffer. If buffer is to small, it allocates a large + * enough buffer on heap and returns allocated buffer. + * This is a supposed use case: + * + * char buf[5], *p = buf; + * mg_avprintf(&p, sizeof(buf), "%s", "hi there"); + * use_p_somehow(p); + * if (p != buf) { + * free(p); + * } + * + * 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, ...); + +/* Same as mg_asprintf, but takes varargs list. */ +int mg_avprintf(char **buf, size_t size, const char *fmt, va_list ap); + +#ifdef __cplusplus +} +#endif + +#endif /* CS_COMMON_STR_UTIL_H_ */ +#ifdef MG_MODULE_LINES +#line 1 "common/queue.h" +#endif +/* clang-format off */ +/*- + * Copyright (c) 1991, 1993 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * @(#)queue.h 8.5 (Berkeley) 8/20/94 + * $FreeBSD$ + */ + +#ifndef _SYS_QUEUE_H_ +#define _SYS_QUEUE_H_ + +/* + * This file defines four types of data structures: singly-linked lists, + * singly-linked tail queues, lists and tail queues. + * + * A singly-linked list is headed by a single forward pointer. The elements + * are singly linked for minimum space and pointer manipulation overhead at + * the expense of O(n) removal for arbitrary elements. New elements can be + * added to the list after an existing element or at the head of the list. + * Elements being removed from the head of the list should use the explicit + * macro for this purpose for optimum efficiency. A singly-linked list may + * only be traversed in the forward direction. Singly-linked lists are ideal + * for applications with large datasets and few or no removals or for + * implementing a LIFO queue. + * + * A singly-linked tail queue is headed by a pair of pointers, one to the + * head of the list and the other to the tail of the list. The elements are + * singly linked for minimum space and pointer manipulation overhead at the + * expense of O(n) removal for arbitrary elements. New elements can be added + * to the list after an existing element, at the head of the list, or at the + * end of the list. Elements being removed from the head of the tail queue + * should use the explicit macro for this purpose for optimum efficiency. + * A singly-linked tail queue may only be traversed in the forward direction. + * Singly-linked tail queues are ideal for applications with large datasets + * and few or no removals or for implementing a FIFO queue. + * + * A list is headed by a single forward pointer (or an array of forward + * pointers for a hash table header). The elements are doubly linked + * so that an arbitrary element can be removed without a need to + * traverse the list. New elements can be added to the list before + * or after an existing element or at the head of the list. A list + * may be traversed in either direction. + * + * A tail queue is headed by a pair of pointers, one to the head of the + * list and the other to the tail of the list. The elements are doubly + * linked so that an arbitrary element can be removed without a need to + * traverse the list. New elements can be added to the list before or + * after an existing element, at the head of the list, or at the end of + * the list. A tail queue may be traversed in either direction. + * + * For details on the use of these macros, see the queue(3) manual page. + * + * + * SLIST LIST STAILQ TAILQ + * _HEAD + + + + + * _CLASS_HEAD + + + + + * _HEAD_INITIALIZER + + + + + * _ENTRY + + + + + * _CLASS_ENTRY + + + + + * _INIT + + + + + * _EMPTY + + + + + * _FIRST + + + + + * _NEXT + + + + + * _PREV - + - + + * _LAST - - + + + * _FOREACH + + + + + * _FOREACH_FROM + + + + + * _FOREACH_SAFE + + + + + * _FOREACH_FROM_SAFE + + + + + * _FOREACH_REVERSE - - - + + * _FOREACH_REVERSE_FROM - - - + + * _FOREACH_REVERSE_SAFE - - - + + * _FOREACH_REVERSE_FROM_SAFE - - - + + * _INSERT_HEAD + + + + + * _INSERT_BEFORE - + - + + * _INSERT_AFTER + + + + + * _INSERT_TAIL - - + + + * _CONCAT - - + + + * _REMOVE_AFTER + - + - + * _REMOVE_HEAD + - + - + * _REMOVE + + + + + * _SWAP + + + + + * + */ +#ifdef QUEUE_MACRO_DEBUG +/* Store the last 2 places the queue element or head was altered */ +struct qm_trace { + unsigned long lastline; + unsigned long prevline; + const char *lastfile; + const char *prevfile; +}; + +#define TRACEBUF struct qm_trace trace; +#define TRACEBUF_INITIALIZER { __LINE__, 0, __FILE__, NULL } , +#define TRASHIT(x) do {(x) = (void *)-1;} while (0) +#define QMD_SAVELINK(name, link) void **name = (void *)&(link) + +#define QMD_TRACE_HEAD(head) do { \ + (head)->trace.prevline = (head)->trace.lastline; \ + (head)->trace.prevfile = (head)->trace.lastfile; \ + (head)->trace.lastline = __LINE__; \ + (head)->trace.lastfile = __FILE__; \ +} while (0) + +#define QMD_TRACE_ELEM(elem) do { \ + (elem)->trace.prevline = (elem)->trace.lastline; \ + (elem)->trace.prevfile = (elem)->trace.lastfile; \ + (elem)->trace.lastline = __LINE__; \ + (elem)->trace.lastfile = __FILE__; \ +} while (0) + +#else +#define QMD_TRACE_ELEM(elem) +#define QMD_TRACE_HEAD(head) +#define QMD_SAVELINK(name, link) +#define TRACEBUF +#define TRACEBUF_INITIALIZER +#define TRASHIT(x) +#endif /* QUEUE_MACRO_DEBUG */ + +#ifdef __cplusplus +/* + * In C++ there can be structure lists and class lists: + */ +#define QUEUE_TYPEOF(type) type +#else +#define QUEUE_TYPEOF(type) struct type +#endif + +/* + * Singly-linked List declarations. + */ +#define SLIST_HEAD(name, type) \ +struct name { \ + struct type *slh_first; /* first element */ \ +} + +#define SLIST_CLASS_HEAD(name, type) \ +struct name { \ + class type *slh_first; /* first element */ \ +} + +#define SLIST_HEAD_INITIALIZER(head) \ + { NULL } + +#define SLIST_ENTRY(type) \ +struct { \ + struct type *sle_next; /* next element */ \ +} + +#define SLIST_CLASS_ENTRY(type) \ +struct { \ + class type *sle_next; /* next element */ \ +} + +/* + * Singly-linked List functions. + */ +#define SLIST_EMPTY(head) ((head)->slh_first == NULL) + +#define SLIST_FIRST(head) ((head)->slh_first) + +#define SLIST_FOREACH(var, head, field) \ + for ((var) = SLIST_FIRST((head)); \ + (var); \ + (var) = SLIST_NEXT((var), field)) + +#define SLIST_FOREACH_FROM(var, head, field) \ + for ((var) = ((var) ? (var) : SLIST_FIRST((head))); \ + (var); \ + (var) = SLIST_NEXT((var), field)) + +#define SLIST_FOREACH_SAFE(var, head, field, tvar) \ + for ((var) = SLIST_FIRST((head)); \ + (var) && ((tvar) = SLIST_NEXT((var), field), 1); \ + (var) = (tvar)) + +#define SLIST_FOREACH_FROM_SAFE(var, head, field, tvar) \ + for ((var) = ((var) ? (var) : SLIST_FIRST((head))); \ + (var) && ((tvar) = SLIST_NEXT((var), field), 1); \ + (var) = (tvar)) + +#define SLIST_FOREACH_PREVPTR(var, varp, head, field) \ + for ((varp) = &SLIST_FIRST((head)); \ + ((var) = *(varp)) != NULL; \ + (varp) = &SLIST_NEXT((var), field)) + +#define SLIST_INIT(head) do { \ + SLIST_FIRST((head)) = NULL; \ +} while (0) + +#define SLIST_INSERT_AFTER(slistelm, elm, field) do { \ + SLIST_NEXT((elm), field) = SLIST_NEXT((slistelm), field); \ + SLIST_NEXT((slistelm), field) = (elm); \ +} while (0) + +#define SLIST_INSERT_HEAD(head, elm, field) do { \ + SLIST_NEXT((elm), field) = SLIST_FIRST((head)); \ + SLIST_FIRST((head)) = (elm); \ +} while (0) + +#define SLIST_NEXT(elm, field) ((elm)->field.sle_next) + +#define SLIST_REMOVE(head, elm, type, field) do { \ + QMD_SAVELINK(oldnext, (elm)->field.sle_next); \ + if (SLIST_FIRST((head)) == (elm)) { \ + SLIST_REMOVE_HEAD((head), field); \ + } \ + else { \ + QUEUE_TYPEOF(type) *curelm = SLIST_FIRST(head); \ + while (SLIST_NEXT(curelm, field) != (elm)) \ + curelm = SLIST_NEXT(curelm, field); \ + SLIST_REMOVE_AFTER(curelm, field); \ + } \ + TRASHIT(*oldnext); \ +} while (0) + +#define SLIST_REMOVE_AFTER(elm, field) do { \ + SLIST_NEXT(elm, field) = \ + SLIST_NEXT(SLIST_NEXT(elm, field), field); \ +} while (0) + +#define SLIST_REMOVE_HEAD(head, field) do { \ + SLIST_FIRST((head)) = SLIST_NEXT(SLIST_FIRST((head)), field); \ +} while (0) + +#define SLIST_SWAP(head1, head2, type) do { \ + QUEUE_TYPEOF(type) *swap_first = SLIST_FIRST(head1); \ + SLIST_FIRST(head1) = SLIST_FIRST(head2); \ + SLIST_FIRST(head2) = swap_first; \ +} while (0) + +/* + * Singly-linked Tail queue declarations. + */ +#define STAILQ_HEAD(name, type) \ +struct name { \ + struct type *stqh_first;/* first element */ \ + struct type **stqh_last;/* addr of last next element */ \ +} + +#define STAILQ_CLASS_HEAD(name, type) \ +struct name { \ + class type *stqh_first; /* first element */ \ + class type **stqh_last; /* addr of last next element */ \ +} + +#define STAILQ_HEAD_INITIALIZER(head) \ + { NULL, &(head).stqh_first } + +#define STAILQ_ENTRY(type) \ +struct { \ + struct type *stqe_next; /* next element */ \ +} + +#define STAILQ_CLASS_ENTRY(type) \ +struct { \ + class type *stqe_next; /* next element */ \ +} + +/* + * Singly-linked Tail queue functions. + */ +#define STAILQ_CONCAT(head1, head2) do { \ + if (!STAILQ_EMPTY((head2))) { \ + *(head1)->stqh_last = (head2)->stqh_first; \ + (head1)->stqh_last = (head2)->stqh_last; \ + STAILQ_INIT((head2)); \ + } \ +} while (0) + +#define STAILQ_EMPTY(head) ((head)->stqh_first == NULL) + +#define STAILQ_FIRST(head) ((head)->stqh_first) + +#define STAILQ_FOREACH(var, head, field) \ + for((var) = STAILQ_FIRST((head)); \ + (var); \ + (var) = STAILQ_NEXT((var), field)) + +#define STAILQ_FOREACH_FROM(var, head, field) \ + for ((var) = ((var) ? (var) : STAILQ_FIRST((head))); \ + (var); \ + (var) = STAILQ_NEXT((var), field)) + +#define STAILQ_FOREACH_SAFE(var, head, field, tvar) \ + for ((var) = STAILQ_FIRST((head)); \ + (var) && ((tvar) = STAILQ_NEXT((var), field), 1); \ + (var) = (tvar)) + +#define STAILQ_FOREACH_FROM_SAFE(var, head, field, tvar) \ + for ((var) = ((var) ? (var) : STAILQ_FIRST((head))); \ + (var) && ((tvar) = STAILQ_NEXT((var), field), 1); \ + (var) = (tvar)) + +#define STAILQ_INIT(head) do { \ + STAILQ_FIRST((head)) = NULL; \ + (head)->stqh_last = &STAILQ_FIRST((head)); \ +} while (0) + +#define STAILQ_INSERT_AFTER(head, tqelm, elm, field) do { \ + if ((STAILQ_NEXT((elm), field) = STAILQ_NEXT((tqelm), field)) == NULL)\ + (head)->stqh_last = &STAILQ_NEXT((elm), field); \ + STAILQ_NEXT((tqelm), field) = (elm); \ +} while (0) + +#define STAILQ_INSERT_HEAD(head, elm, field) do { \ + if ((STAILQ_NEXT((elm), field) = STAILQ_FIRST((head))) == NULL) \ + (head)->stqh_last = &STAILQ_NEXT((elm), field); \ + STAILQ_FIRST((head)) = (elm); \ +} while (0) + +#define STAILQ_INSERT_TAIL(head, elm, field) do { \ + STAILQ_NEXT((elm), field) = NULL; \ + *(head)->stqh_last = (elm); \ + (head)->stqh_last = &STAILQ_NEXT((elm), field); \ +} while (0) + +#define STAILQ_LAST(head, type, field) \ + (STAILQ_EMPTY((head)) ? NULL : \ + __containerof((head)->stqh_last, \ + QUEUE_TYPEOF(type), field.stqe_next)) + +#define STAILQ_NEXT(elm, field) ((elm)->field.stqe_next) + +#define STAILQ_REMOVE(head, elm, type, field) do { \ + QMD_SAVELINK(oldnext, (elm)->field.stqe_next); \ + if (STAILQ_FIRST((head)) == (elm)) { \ + STAILQ_REMOVE_HEAD((head), field); \ + } \ + else { \ + QUEUE_TYPEOF(type) *curelm = STAILQ_FIRST(head); \ + while (STAILQ_NEXT(curelm, field) != (elm)) \ + curelm = STAILQ_NEXT(curelm, field); \ + STAILQ_REMOVE_AFTER(head, curelm, field); \ + } \ + TRASHIT(*oldnext); \ +} while (0) + +#define STAILQ_REMOVE_AFTER(head, elm, field) do { \ + if ((STAILQ_NEXT(elm, field) = \ + STAILQ_NEXT(STAILQ_NEXT(elm, field), field)) == NULL) \ + (head)->stqh_last = &STAILQ_NEXT((elm), field); \ +} while (0) + +#define STAILQ_REMOVE_HEAD(head, field) do { \ + if ((STAILQ_FIRST((head)) = \ + STAILQ_NEXT(STAILQ_FIRST((head)), field)) == NULL) \ + (head)->stqh_last = &STAILQ_FIRST((head)); \ +} while (0) + +#define STAILQ_SWAP(head1, head2, type) do { \ + QUEUE_TYPEOF(type) *swap_first = STAILQ_FIRST(head1); \ + QUEUE_TYPEOF(type) **swap_last = (head1)->stqh_last; \ + STAILQ_FIRST(head1) = STAILQ_FIRST(head2); \ + (head1)->stqh_last = (head2)->stqh_last; \ + STAILQ_FIRST(head2) = swap_first; \ + (head2)->stqh_last = swap_last; \ + if (STAILQ_EMPTY(head1)) \ + (head1)->stqh_last = &STAILQ_FIRST(head1); \ + if (STAILQ_EMPTY(head2)) \ + (head2)->stqh_last = &STAILQ_FIRST(head2); \ +} while (0) + + +/* + * List declarations. + */ +#define LIST_HEAD(name, type) \ +struct name { \ + struct type *lh_first; /* first element */ \ +} + +#define LIST_CLASS_HEAD(name, type) \ +struct name { \ + class type *lh_first; /* first element */ \ +} + +#define LIST_HEAD_INITIALIZER(head) \ + { NULL } + +#define LIST_ENTRY(type) \ +struct { \ + struct type *le_next; /* next element */ \ + struct type **le_prev; /* address of previous next element */ \ +} + +#define LIST_CLASS_ENTRY(type) \ +struct { \ + class type *le_next; /* next element */ \ + class type **le_prev; /* address of previous next element */ \ +} + +/* + * List functions. + */ + +#if (defined(_KERNEL) && defined(INVARIANTS)) +#define QMD_LIST_CHECK_HEAD(head, field) do { \ + if (LIST_FIRST((head)) != NULL && \ + LIST_FIRST((head))->field.le_prev != \ + &LIST_FIRST((head))) \ + panic("Bad list head %p first->prev != head", (head)); \ +} while (0) + +#define QMD_LIST_CHECK_NEXT(elm, field) do { \ + if (LIST_NEXT((elm), field) != NULL && \ + LIST_NEXT((elm), field)->field.le_prev != \ + &((elm)->field.le_next)) \ + panic("Bad link elm %p next->prev != elm", (elm)); \ +} while (0) + +#define QMD_LIST_CHECK_PREV(elm, field) do { \ + if (*(elm)->field.le_prev != (elm)) \ + panic("Bad link elm %p prev->next != elm", (elm)); \ +} while (0) +#else +#define QMD_LIST_CHECK_HEAD(head, field) +#define QMD_LIST_CHECK_NEXT(elm, field) +#define QMD_LIST_CHECK_PREV(elm, field) +#endif /* (_KERNEL && INVARIANTS) */ + +#define LIST_EMPTY(head) ((head)->lh_first == NULL) + +#define LIST_FIRST(head) ((head)->lh_first) + +#define LIST_FOREACH(var, head, field) \ + for ((var) = LIST_FIRST((head)); \ + (var); \ + (var) = LIST_NEXT((var), field)) + +#define LIST_FOREACH_FROM(var, head, field) \ + for ((var) = ((var) ? (var) : LIST_FIRST((head))); \ + (var); \ + (var) = LIST_NEXT((var), field)) + +#define LIST_FOREACH_SAFE(var, head, field, tvar) \ + for ((var) = LIST_FIRST((head)); \ + (var) && ((tvar) = LIST_NEXT((var), field), 1); \ + (var) = (tvar)) + +#define LIST_FOREACH_FROM_SAFE(var, head, field, tvar) \ + for ((var) = ((var) ? (var) : LIST_FIRST((head))); \ + (var) && ((tvar) = LIST_NEXT((var), field), 1); \ + (var) = (tvar)) + +#define LIST_INIT(head) do { \ + LIST_FIRST((head)) = NULL; \ +} while (0) + +#define LIST_INSERT_AFTER(listelm, elm, field) do { \ + QMD_LIST_CHECK_NEXT(listelm, field); \ + if ((LIST_NEXT((elm), field) = LIST_NEXT((listelm), field)) != NULL)\ + LIST_NEXT((listelm), field)->field.le_prev = \ + &LIST_NEXT((elm), field); \ + LIST_NEXT((listelm), field) = (elm); \ + (elm)->field.le_prev = &LIST_NEXT((listelm), field); \ +} while (0) + +#define LIST_INSERT_BEFORE(listelm, elm, field) do { \ + QMD_LIST_CHECK_PREV(listelm, field); \ + (elm)->field.le_prev = (listelm)->field.le_prev; \ + LIST_NEXT((elm), field) = (listelm); \ + *(listelm)->field.le_prev = (elm); \ + (listelm)->field.le_prev = &LIST_NEXT((elm), field); \ +} while (0) + +#define LIST_INSERT_HEAD(head, elm, field) do { \ + QMD_LIST_CHECK_HEAD((head), field); \ + if ((LIST_NEXT((elm), field) = LIST_FIRST((head))) != NULL) \ + LIST_FIRST((head))->field.le_prev = &LIST_NEXT((elm), field);\ + LIST_FIRST((head)) = (elm); \ + (elm)->field.le_prev = &LIST_FIRST((head)); \ +} while (0) + +#define LIST_NEXT(elm, field) ((elm)->field.le_next) + +#define LIST_PREV(elm, head, type, field) \ + ((elm)->field.le_prev == &LIST_FIRST((head)) ? NULL : \ + __containerof((elm)->field.le_prev, \ + QUEUE_TYPEOF(type), field.le_next)) + +#define LIST_REMOVE(elm, field) do { \ + QMD_SAVELINK(oldnext, (elm)->field.le_next); \ + QMD_SAVELINK(oldprev, (elm)->field.le_prev); \ + QMD_LIST_CHECK_NEXT(elm, field); \ + QMD_LIST_CHECK_PREV(elm, field); \ + if (LIST_NEXT((elm), field) != NULL) \ + LIST_NEXT((elm), field)->field.le_prev = \ + (elm)->field.le_prev; \ + *(elm)->field.le_prev = LIST_NEXT((elm), field); \ + TRASHIT(*oldnext); \ + TRASHIT(*oldprev); \ +} while (0) + +#define LIST_SWAP(head1, head2, type, field) do { \ + QUEUE_TYPEOF(type) *swap_tmp = LIST_FIRST(head1); \ + LIST_FIRST((head1)) = LIST_FIRST((head2)); \ + LIST_FIRST((head2)) = swap_tmp; \ + if ((swap_tmp = LIST_FIRST((head1))) != NULL) \ + swap_tmp->field.le_prev = &LIST_FIRST((head1)); \ + if ((swap_tmp = LIST_FIRST((head2))) != NULL) \ + swap_tmp->field.le_prev = &LIST_FIRST((head2)); \ +} while (0) + +/* + * Tail queue declarations. + */ +#define TAILQ_HEAD(name, type) \ +struct name { \ + struct type *tqh_first; /* first element */ \ + struct type **tqh_last; /* addr of last next element */ \ + TRACEBUF \ +} + +#define TAILQ_CLASS_HEAD(name, type) \ +struct name { \ + class type *tqh_first; /* first element */ \ + class type **tqh_last; /* addr of last next element */ \ + TRACEBUF \ +} + +#define TAILQ_HEAD_INITIALIZER(head) \ + { NULL, &(head).tqh_first, TRACEBUF_INITIALIZER } + +#define TAILQ_ENTRY(type) \ +struct { \ + struct type *tqe_next; /* next element */ \ + struct type **tqe_prev; /* address of previous next element */ \ + TRACEBUF \ +} + +#define TAILQ_CLASS_ENTRY(type) \ +struct { \ + class type *tqe_next; /* next element */ \ + class type **tqe_prev; /* address of previous next element */ \ + TRACEBUF \ +} + +/* + * Tail queue functions. + */ +#if (defined(_KERNEL) && defined(INVARIANTS)) +#define QMD_TAILQ_CHECK_HEAD(head, field) do { \ + if (!TAILQ_EMPTY(head) && \ + TAILQ_FIRST((head))->field.tqe_prev != \ + &TAILQ_FIRST((head))) \ + panic("Bad tailq head %p first->prev != head", (head)); \ +} while (0) + +#define QMD_TAILQ_CHECK_TAIL(head, field) do { \ + if (*(head)->tqh_last != NULL) \ + panic("Bad tailq NEXT(%p->tqh_last) != NULL", (head)); \ +} while (0) + +#define QMD_TAILQ_CHECK_NEXT(elm, field) do { \ + if (TAILQ_NEXT((elm), field) != NULL && \ + TAILQ_NEXT((elm), field)->field.tqe_prev != \ + &((elm)->field.tqe_next)) \ + panic("Bad link elm %p next->prev != elm", (elm)); \ +} while (0) + +#define QMD_TAILQ_CHECK_PREV(elm, field) do { \ + if (*(elm)->field.tqe_prev != (elm)) \ + panic("Bad link elm %p prev->next != elm", (elm)); \ +} while (0) +#else +#define QMD_TAILQ_CHECK_HEAD(head, field) +#define QMD_TAILQ_CHECK_TAIL(head, headname) +#define QMD_TAILQ_CHECK_NEXT(elm, field) +#define QMD_TAILQ_CHECK_PREV(elm, field) +#endif /* (_KERNEL && INVARIANTS) */ + +#define TAILQ_CONCAT(head1, head2, field) do { \ + if (!TAILQ_EMPTY(head2)) { \ + *(head1)->tqh_last = (head2)->tqh_first; \ + (head2)->tqh_first->field.tqe_prev = (head1)->tqh_last; \ + (head1)->tqh_last = (head2)->tqh_last; \ + TAILQ_INIT((head2)); \ + QMD_TRACE_HEAD(head1); \ + QMD_TRACE_HEAD(head2); \ + } \ +} while (0) + +#define TAILQ_EMPTY(head) ((head)->tqh_first == NULL) + +#define TAILQ_FIRST(head) ((head)->tqh_first) + +#define TAILQ_FOREACH(var, head, field) \ + for ((var) = TAILQ_FIRST((head)); \ + (var); \ + (var) = TAILQ_NEXT((var), field)) + +#define TAILQ_FOREACH_FROM(var, head, field) \ + for ((var) = ((var) ? (var) : TAILQ_FIRST((head))); \ + (var); \ + (var) = TAILQ_NEXT((var), field)) + +#define TAILQ_FOREACH_SAFE(var, head, field, tvar) \ + for ((var) = TAILQ_FIRST((head)); \ + (var) && ((tvar) = TAILQ_NEXT((var), field), 1); \ + (var) = (tvar)) + +#define TAILQ_FOREACH_FROM_SAFE(var, head, field, tvar) \ + for ((var) = ((var) ? (var) : TAILQ_FIRST((head))); \ + (var) && ((tvar) = TAILQ_NEXT((var), field), 1); \ + (var) = (tvar)) + +#define TAILQ_FOREACH_REVERSE(var, head, headname, field) \ + for ((var) = TAILQ_LAST((head), headname); \ + (var); \ + (var) = TAILQ_PREV((var), headname, field)) + +#define TAILQ_FOREACH_REVERSE_FROM(var, head, headname, field) \ + for ((var) = ((var) ? (var) : TAILQ_LAST((head), headname)); \ + (var); \ + (var) = TAILQ_PREV((var), headname, field)) + +#define TAILQ_FOREACH_REVERSE_SAFE(var, head, headname, field, tvar) \ + for ((var) = TAILQ_LAST((head), headname); \ + (var) && ((tvar) = TAILQ_PREV((var), headname, field), 1); \ + (var) = (tvar)) + +#define TAILQ_FOREACH_REVERSE_FROM_SAFE(var, head, headname, field, tvar) \ + for ((var) = ((var) ? (var) : TAILQ_LAST((head), headname)); \ + (var) && ((tvar) = TAILQ_PREV((var), headname, field), 1); \ + (var) = (tvar)) + +#define TAILQ_INIT(head) do { \ + TAILQ_FIRST((head)) = NULL; \ + (head)->tqh_last = &TAILQ_FIRST((head)); \ + QMD_TRACE_HEAD(head); \ +} while (0) + +#define TAILQ_INSERT_AFTER(head, listelm, elm, field) do { \ + QMD_TAILQ_CHECK_NEXT(listelm, field); \ + if ((TAILQ_NEXT((elm), field) = TAILQ_NEXT((listelm), field)) != NULL)\ + TAILQ_NEXT((elm), field)->field.tqe_prev = \ + &TAILQ_NEXT((elm), field); \ + else { \ + (head)->tqh_last = &TAILQ_NEXT((elm), field); \ + QMD_TRACE_HEAD(head); \ + } \ + TAILQ_NEXT((listelm), field) = (elm); \ + (elm)->field.tqe_prev = &TAILQ_NEXT((listelm), field); \ + QMD_TRACE_ELEM(&(elm)->field); \ + QMD_TRACE_ELEM(&(listelm)->field); \ +} while (0) + +#define TAILQ_INSERT_BEFORE(listelm, elm, field) do { \ + QMD_TAILQ_CHECK_PREV(listelm, field); \ + (elm)->field.tqe_prev = (listelm)->field.tqe_prev; \ + TAILQ_NEXT((elm), field) = (listelm); \ + *(listelm)->field.tqe_prev = (elm); \ + (listelm)->field.tqe_prev = &TAILQ_NEXT((elm), field); \ + QMD_TRACE_ELEM(&(elm)->field); \ + QMD_TRACE_ELEM(&(listelm)->field); \ +} while (0) + +#define TAILQ_INSERT_HEAD(head, elm, field) do { \ + QMD_TAILQ_CHECK_HEAD(head, field); \ + if ((TAILQ_NEXT((elm), field) = TAILQ_FIRST((head))) != NULL) \ + TAILQ_FIRST((head))->field.tqe_prev = \ + &TAILQ_NEXT((elm), field); \ + else \ + (head)->tqh_last = &TAILQ_NEXT((elm), field); \ + TAILQ_FIRST((head)) = (elm); \ + (elm)->field.tqe_prev = &TAILQ_FIRST((head)); \ + QMD_TRACE_HEAD(head); \ + QMD_TRACE_ELEM(&(elm)->field); \ +} while (0) + +#define TAILQ_INSERT_TAIL(head, elm, field) do { \ + QMD_TAILQ_CHECK_TAIL(head, field); \ + TAILQ_NEXT((elm), field) = NULL; \ + (elm)->field.tqe_prev = (head)->tqh_last; \ + *(head)->tqh_last = (elm); \ + (head)->tqh_last = &TAILQ_NEXT((elm), field); \ + QMD_TRACE_HEAD(head); \ + QMD_TRACE_ELEM(&(elm)->field); \ +} while (0) + +#define TAILQ_LAST(head, headname) \ + (*(((struct headname *)((head)->tqh_last))->tqh_last)) + +#define TAILQ_NEXT(elm, field) ((elm)->field.tqe_next) + +#define TAILQ_PREV(elm, headname, field) \ + (*(((struct headname *)((elm)->field.tqe_prev))->tqh_last)) + +#define TAILQ_REMOVE(head, elm, field) do { \ + QMD_SAVELINK(oldnext, (elm)->field.tqe_next); \ + QMD_SAVELINK(oldprev, (elm)->field.tqe_prev); \ + QMD_TAILQ_CHECK_NEXT(elm, field); \ + QMD_TAILQ_CHECK_PREV(elm, field); \ + if ((TAILQ_NEXT((elm), field)) != NULL) \ + TAILQ_NEXT((elm), field)->field.tqe_prev = \ + (elm)->field.tqe_prev; \ + else { \ + (head)->tqh_last = (elm)->field.tqe_prev; \ + QMD_TRACE_HEAD(head); \ + } \ + *(elm)->field.tqe_prev = TAILQ_NEXT((elm), field); \ + TRASHIT(*oldnext); \ + TRASHIT(*oldprev); \ + QMD_TRACE_ELEM(&(elm)->field); \ +} while (0) + +#define TAILQ_SWAP(head1, head2, type, field) do { \ + QUEUE_TYPEOF(type) *swap_first = (head1)->tqh_first; \ + QUEUE_TYPEOF(type) **swap_last = (head1)->tqh_last; \ + (head1)->tqh_first = (head2)->tqh_first; \ + (head1)->tqh_last = (head2)->tqh_last; \ + (head2)->tqh_first = swap_first; \ + (head2)->tqh_last = swap_last; \ + if ((swap_first = (head1)->tqh_first) != NULL) \ + swap_first->field.tqe_prev = &(head1)->tqh_first; \ + else \ + (head1)->tqh_last = &(head1)->tqh_first; \ + if ((swap_first = (head2)->tqh_first) != NULL) \ + swap_first->field.tqe_prev = &(head2)->tqh_first; \ + else \ + (head2)->tqh_last = &(head2)->tqh_first; \ +} while (0) + +#endif /* !_SYS_QUEUE_H_ */ +#ifdef MG_MODULE_LINES +#line 1 "mongoose/src/features.h" +#endif +/* + * Copyright (c) 2014-2016 Cesanta Software Limited + * All rights reserved + */ + +#ifndef CS_MONGOOSE_SRC_FEATURES_H_ +#define CS_MONGOOSE_SRC_FEATURES_H_ + +#ifndef MG_DISABLE_HTTP_DIGEST_AUTH +#define MG_DISABLE_HTTP_DIGEST_AUTH 0 +#endif + +#ifndef MG_DISABLE_HTTP_KEEP_ALIVE +#define MG_DISABLE_HTTP_KEEP_ALIVE 0 +#endif + +#ifndef MG_DISABLE_PFS +#define MG_DISABLE_PFS 0 +#endif + +#ifndef MG_DISABLE_WS_RANDOM_MASK +#define MG_DISABLE_WS_RANDOM_MASK 0 +#endif + +#ifndef MG_ENABLE_ASYNC_RESOLVER +#define MG_ENABLE_ASYNC_RESOLVER 1 +#endif + +#ifndef MG_ENABLE_BROADCAST +#define MG_ENABLE_BROADCAST 0 +#endif + +#ifndef MG_ENABLE_COAP +#define MG_ENABLE_COAP 0 +#endif + +#ifndef MG_ENABLE_DEBUG +#define MG_ENABLE_DEBUG 0 +#endif + +#ifndef MG_ENABLE_DIRECTORY_LISTING +#define MG_ENABLE_DIRECTORY_LISTING 0 +#endif + +#ifndef MG_ENABLE_DNS +#define MG_ENABLE_DNS 1 +#endif + +#ifndef MG_ENABLE_DNS_SERVER +#define MG_ENABLE_DNS_SERVER 0 +#endif + +#ifndef MG_ENABLE_FAKE_DAVLOCK +#define MG_ENABLE_FAKE_DAVLOCK 0 +#endif + +#ifndef MG_ENABLE_FILESYSTEM +#define MG_ENABLE_FILESYSTEM 0 +#endif + +#ifndef MG_ENABLE_GETADDRINFO +#define MG_ENABLE_GETADDRINFO 0 +#endif + +#ifndef MG_ENABLE_HEXDUMP +#define MG_ENABLE_HEXDUMP CS_ENABLE_STDIO +#endif + +#ifndef MG_ENABLE_HTTP +#define MG_ENABLE_HTTP 1 +#endif + +#ifndef MG_ENABLE_HTTP_CGI +#define MG_ENABLE_HTTP_CGI 0 +#endif + +#ifndef MG_ENABLE_HTTP_SSI +#define MG_ENABLE_HTTP_SSI MG_ENABLE_FILESYSTEM +#endif + +#ifndef MG_ENABLE_HTTP_SSI_EXEC +#define MG_ENABLE_HTTP_SSI_EXEC 0 +#endif + +#ifndef MG_ENABLE_HTTP_STREAMING_MULTIPART +#define MG_ENABLE_HTTP_STREAMING_MULTIPART 0 +#endif + +#ifndef MG_ENABLE_HTTP_WEBDAV +#define MG_ENABLE_HTTP_WEBDAV 0 +#endif + +#ifndef MG_ENABLE_HTTP_WEBSOCKET +#define MG_ENABLE_HTTP_WEBSOCKET MG_ENABLE_HTTP +#endif + +#ifndef MG_ENABLE_IPV6 +#define MG_ENABLE_IPV6 0 +#endif + +#ifndef MG_ENABLE_JAVASCRIPT +#define MG_ENABLE_JAVASCRIPT 0 +#endif + +#ifndef MG_ENABLE_MQTT +#define MG_ENABLE_MQTT 1 +#endif + +#ifndef MG_ENABLE_MQTT_BROKER +#define MG_ENABLE_MQTT_BROKER 0 +#endif + +#ifndef MG_ENABLE_SSL +#define MG_ENABLE_SSL 0 +#endif + +#ifndef MG_ENABLE_SYNC_RESOLVER +#define MG_ENABLE_SYNC_RESOLVER 0 +#endif + +#ifndef MG_ENABLE_STDIO +#define MG_ENABLE_STDIO CS_ENABLE_STDIO +#endif + +#ifndef MG_NET_IF +#define MG_NET_IF MG_NET_IF_SOCKET +#endif + +#ifndef MG_SSL_IF +#define MG_SSL_IF MG_SSL_IF_OPENSSL +#endif + +#ifndef MG_ENABLE_THREADS /* ifdef-ok */ +#ifdef _WIN32 +#define MG_ENABLE_THREADS 1 +#else +#define MG_ENABLE_THREADS 0 +#endif +#endif + +#if MG_ENABLE_DEBUG && !defined(CS_ENABLE_DEBUG) +#define CS_ENABLE_DEBUG 1 +#endif + +/* MQTT broker requires MQTT */ +#if MG_ENABLE_MQTT_BROKER && !MG_ENABLE_MQTT +#undef MG_ENABLE_MQTT +#define MG_ENABLE_MQTT 1 +#endif + +#ifndef MG_ENABLE_HTTP_URL_REWRITES +#define MG_ENABLE_HTTP_URL_REWRITES \ + (CS_PLATFORM == CS_P_WINDOWS || CS_PLATFORM == CS_P_UNIX) +#endif + +#ifndef MG_ENABLE_TUN +#define MG_ENABLE_TUN MG_ENABLE_HTTP_WEBSOCKET +#endif + +#ifndef MG_ENABLE_SNTP +#define MG_ENABLE_SNTP 0 +#endif + +#ifndef MG_ENABLE_EXTRA_ERRORS_DESC +#define MG_ENABLE_EXTRA_ERRORS_DESC 0 +#endif + +#ifndef MG_ENABLE_CALLBACK_USERDATA +#define MG_ENABLE_CALLBACK_USERDATA 0 +#endif + +#if MG_ENABLE_CALLBACK_USERDATA +#define MG_UD_ARG(ud) , ud +#define MG_CB(cb, ud) cb, ud +#else +#define MG_UD_ARG(ud) +#define MG_CB(cb, ud) cb +#endif + +#endif /* CS_MONGOOSE_SRC_FEATURES_H_ */ +#ifdef MG_MODULE_LINES +#line 1 "mongoose/src/net_if.h" +#endif +/* + * Copyright (c) 2014-2016 Cesanta Software Limited + * All rights reserved + */ + +#ifndef CS_MONGOOSE_SRC_NET_IF_H_ +#define CS_MONGOOSE_SRC_NET_IF_H_ + +/* Amalgamated: #include "common/platform.h" */ + +/* + * Internal async networking core interface. + * Consists of calls made by the core, which should not block, + * and callbacks back into the core ("..._cb"). + * Callbacks may (will) cause methods to be invoked from within, + * but methods are not allowed to invoke callbacks inline. + * + * Implementation must ensure that only one callback is invoked at any time. + */ + +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + +#define MG_MAIN_IFACE 0 + +struct mg_mgr; +struct mg_connection; +union socket_address; + +struct mg_iface_vtable; + +struct mg_iface { + struct mg_mgr *mgr; + void *data; /* Implementation-specific data */ + const struct mg_iface_vtable *vtable; +}; + +struct mg_iface_vtable { + void (*init)(struct mg_iface *iface); + void (*free)(struct mg_iface *iface); + void (*add_conn)(struct mg_connection *nc); + void (*remove_conn)(struct mg_connection *nc); + time_t (*poll)(struct mg_iface *iface, int timeout_ms); + + /* Set up a listening TCP socket on a given address. rv = 0 -> ok. */ + int (*listen_tcp)(struct mg_connection *nc, union socket_address *sa); + /* Request that a "listening" UDP socket be created. */ + int (*listen_udp)(struct mg_connection *nc, union socket_address *sa); + + /* Request that a TCP connection is made to the specified address. */ + void (*connect_tcp)(struct mg_connection *nc, const union socket_address *sa); + /* Open a UDP socket. Doesn't actually connect anything. */ + 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); + + void (*recved)(struct mg_connection *nc, size_t len); + + /* Perform interface-related connection initialization. Return 1 on ok. */ + int (*create_conn)(struct mg_connection *nc); + /* Perform interface-related cleanup on connection before destruction. */ + void (*destroy_conn)(struct mg_connection *nc); + + /* Associate a socket to a connection. */ + void (*sock_set)(struct mg_connection *nc, sock_t sock); + + /* Put connection's address into *sa, local (remote = 0) or remote. */ + void (*get_conn_addr)(struct mg_connection *nc, int remote, + union socket_address *sa); +}; + +extern const struct mg_iface_vtable *mg_ifaces[]; +extern int mg_num_ifaces; + +/* Creates a new interface instance. */ +struct mg_iface *mg_if_create_iface(const struct mg_iface_vtable *vtable, + struct mg_mgr *mgr); + +/* + * Find an interface with a given implementation. The search is started from + * interface `from`, exclusive. Returns NULL if none is found. + */ +struct mg_iface *mg_find_iface(struct mg_mgr *mgr, + const struct mg_iface_vtable *vtable, + struct mg_iface *from); +/* + * Deliver a new TCP connection. Returns NULL in case on error (unable to + * create connection, in which case interface state should be discarded. + * This is phase 1 of the two-phase process - MG_EV_ACCEPT will be delivered + * when mg_if_accept_tcp_cb is invoked. + */ +struct mg_connection *mg_if_accept_new_conn(struct mg_connection *lc); +void mg_if_accept_tcp_cb(struct mg_connection *nc, union socket_address *sa, + size_t sa_len); + +/* 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. + */ +void mg_if_recv_tcp_cb(struct mg_connection *nc, void *buf, int len, int own); +/* + * 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); + +/* 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); + +#ifdef __cplusplus +} +#endif /* __cplusplus */ + +#endif /* CS_MONGOOSE_SRC_NET_IF_H_ */ +#ifdef MG_MODULE_LINES +#line 1 "mongoose/src/ssl_if.h" +#endif +/* + * Copyright (c) 2014-2016 Cesanta Software Limited + * All rights reserved + */ + +#ifndef CS_MONGOOSE_SRC_SSL_IF_H_ +#define CS_MONGOOSE_SRC_SSL_IF_H_ + +#if MG_ENABLE_SSL + +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + +struct mg_ssl_if_ctx; +struct mg_connection; + +void mg_ssl_if_init(); + +enum mg_ssl_if_result { + MG_SSL_OK = 0, + MG_SSL_WANT_READ = -1, + MG_SSL_WANT_WRITE = -2, + MG_SSL_ERROR = -3, +}; + +struct mg_ssl_if_conn_params { + const char *cert; + const char *key; + const char *ca_cert; + const char *server_name; + const char *cipher_suites; + const char *psk_identity; + const char *psk_key; +}; + +enum mg_ssl_if_result mg_ssl_if_conn_init( + struct mg_connection *nc, const struct mg_ssl_if_conn_params *params, + const char **err_msg); +enum mg_ssl_if_result mg_ssl_if_conn_accept(struct mg_connection *nc, + struct mg_connection *lc); +void mg_ssl_if_conn_close_notify(struct mg_connection *nc); +void mg_ssl_if_conn_free(struct mg_connection *nc); + +enum mg_ssl_if_result mg_ssl_if_handshake(struct mg_connection *nc); +int mg_ssl_if_read(struct mg_connection *nc, void *buf, size_t buf_size); +int mg_ssl_if_write(struct mg_connection *nc, const void *data, size_t len); + +#ifdef __cplusplus +} +#endif /* __cplusplus */ + +#endif /* MG_ENABLE_SSL */ + +#endif /* CS_MONGOOSE_SRC_SSL_IF_H_ */ +#ifdef MG_MODULE_LINES +#line 1 "mongoose/src/net.h" +#endif +/* + * Copyright (c) 2014 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. + * + * Alternatively, you can license this software under a commercial + * license, as set out in . + */ + +/* + * === Core API: TCP/UDP/SSL + * + * NOTE: Mongoose manager is single threaded. It does not protect + * its data structures by mutexes, therefore all functions that are dealing + * with a particular event manager should be called from the same thread, + * with exception of the `mg_broadcast()` function. It is fine to have different + * event managers handled by different threads. + */ + +#ifndef CS_MONGOOSE_SRC_NET_H_ +#define CS_MONGOOSE_SRC_NET_H_ + +#if MG_ENABLE_JAVASCRIPT +#define EXCLUDE_COMMON +#include +#endif + +/* Amalgamated: #include "mongoose/src/common.h" */ +/* Amalgamated: #include "mongoose/src/net_if.h" */ +/* Amalgamated: #include "common/mbuf.h" */ + +#ifndef MG_VPRINTF_BUFFER_SIZE +#define MG_VPRINTF_BUFFER_SIZE 100 +#endif + +#ifdef MG_USE_READ_WRITE +#define MG_RECV_FUNC(s, b, l, f) read(s, b, l) +#define MG_SEND_FUNC(s, b, l, f) write(s, b, l) +#else +#define MG_RECV_FUNC(s, b, l, f) recv(s, b, l, f) +#define MG_SEND_FUNC(s, b, l, f) send(s, b, l, f) +#endif + +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + +union socket_address { + struct sockaddr sa; + struct sockaddr_in sin; +#if MG_ENABLE_IPV6 + struct sockaddr_in6 sin6; +#else + struct sockaddr sin6; +#endif +}; + +struct mg_connection; + +/* + * Callback function (event handler) prototype. Must be defined by the user. + * Mongoose calls the event handler, passing the events defined below. + */ +typedef void (*mg_event_handler_t)(struct mg_connection *nc, int ev, + void *ev_data MG_UD_ARG(void *user_data)); + +/* Events. Meaning of event parameter (evp) is given in the comment. */ +#define MG_EV_POLL 0 /* Sent to each connection on each mg_mgr_poll() call */ +#define MG_EV_ACCEPT 1 /* New connection accepted. union socket_address * */ +#define MG_EV_CONNECT 2 /* connect() succeeded or failed. int * */ +#define MG_EV_RECV 3 /* Data has been received. int *num_bytes */ +#define MG_EV_SEND 4 /* Data has been written to a socket. int *num_bytes */ +#define MG_EV_CLOSE 5 /* Connection is closed. NULL */ +#define MG_EV_TIMER 6 /* now >= conn->ev_timer_time. double * */ + +/* + * Mongoose event manager. + */ +struct mg_mgr { + struct mg_connection *active_connections; +#if MG_ENABLE_HEXDUMP + const char *hexdump_file; /* Debug hexdump file path */ +#endif +#if MG_ENABLE_BROADCAST + sock_t ctl[2]; /* Socketpair for mg_broadcast() */ +#endif + void *user_data; /* User data */ + int num_ifaces; + struct mg_iface **ifaces; /* network interfaces */ +#if MG_ENABLE_JAVASCRIPT + struct v7 *v7; +#endif + const char *nameserver; /* DNS server to use */ +}; + +/* + * Mongoose connection. + */ +struct mg_connection { + struct mg_connection *next, *prev; /* mg_mgr::active_connections linkage */ + struct mg_connection *listener; /* Set only for accept()-ed connections */ + struct mg_mgr *mgr; /* Pointer to containing manager */ + + sock_t sock; /* Socket to the remote peer */ + int err; + union socket_address sa; /* Remote peer address */ + size_t recv_mbuf_limit; /* Max size of recv buffer */ + struct mbuf recv_mbuf; /* Received data */ + struct mbuf send_mbuf; /* Data scheduled for sending */ + time_t last_io_time; /* Timestamp of the last socket IO */ + double ev_timer_time; /* Timestamp of the future MG_EV_TIMER */ +#if MG_ENABLE_SSL + void *ssl_if_data; /* SSL library data. */ +#endif + mg_event_handler_t proto_handler; /* Protocol-specific event handler */ + void *proto_data; /* Protocol-specific data */ + void (*proto_data_destructor)(void *proto_data); + mg_event_handler_t handler; /* Event handler function */ + void *user_data; /* User-specific data */ + union { + void *v; + /* + * the C standard is fussy about fitting function pointers into + * void pointers, since some archs might have fat pointers for functions. + */ + mg_event_handler_t f; + } priv_1; + void *priv_2; + void *mgr_data; /* Implementation-specific event manager's data. */ + struct mg_iface *iface; + unsigned long flags; +/* Flags set by Mongoose */ +#define MG_F_LISTENING (1 << 0) /* This connection is listening */ +#define MG_F_UDP (1 << 1) /* This connection is UDP */ +#define MG_F_RESOLVING (1 << 2) /* Waiting for async resolver */ +#define MG_F_CONNECTING (1 << 3) /* connect() call in progress */ +#define MG_F_SSL (1 << 4) /* SSL is enabled on the connection */ +#define MG_F_SSL_HANDSHAKE_DONE (1 << 5) /* SSL hanshake has completed */ +#define MG_F_WANT_READ (1 << 6) /* SSL specific */ +#define MG_F_WANT_WRITE (1 << 7) /* SSL specific */ +#define MG_F_IS_WEBSOCKET (1 << 8) /* Websocket specific */ + +/* Flags that are settable by user */ +#define MG_F_SEND_AND_CLOSE (1 << 10) /* Push remaining data and close */ +#define MG_F_CLOSE_IMMEDIATELY (1 << 11) /* Disconnect */ +#define MG_F_WEBSOCKET_NO_DEFRAG (1 << 12) /* Websocket specific */ +#define MG_F_DELETE_CHUNK (1 << 13) /* HTTP specific */ +#define MG_F_ENABLE_BROADCAST (1 << 14) /* Allow broadcast address usage */ +#define MG_F_TUN_DO_NOT_RECONNECT (1 << 15) /* Don't reconnect tunnel */ + +#define MG_F_USER_1 (1 << 20) /* Flags left for application */ +#define MG_F_USER_2 (1 << 21) +#define MG_F_USER_3 (1 << 22) +#define MG_F_USER_4 (1 << 23) +#define MG_F_USER_5 (1 << 24) +#define MG_F_USER_6 (1 << 25) +}; + +/* + * Initialise Mongoose manager. Side effect: ignores SIGPIPE signal. + * `mgr->user_data` field will be initialised with a `user_data` parameter. + * That is an arbitrary pointer, where the user code can associate some data + * with the particular Mongoose manager. For example, a C++ wrapper class + * could be written in which case `user_data` can hold a pointer to the + * class instance. + */ +void mg_mgr_init(struct mg_mgr *mgr, void *user_data); + +/* + * Optional parameters to `mg_mgr_init_opt()`. + * + * If `main_iface` is not NULL, it will be used as the main interface in the + * default interface set. The pointer will be free'd by `mg_mgr_free`. + * Otherwise, the main interface will be autodetected based on the current + * platform. + * + * If `num_ifaces` is 0 and `ifaces` is NULL, the default interface set will be + * used. + * This is an advanced option, as it requires you to construct a full interface + * set, including special networking interfaces required by some optional + * features such as TCP tunneling. Memory backing `ifaces` and each of the + * `num_ifaces` pointers it contains will be reclaimed by `mg_mgr_free`. + */ +struct mg_mgr_init_opts { + const struct mg_iface_vtable *main_iface; + int num_ifaces; + const struct mg_iface_vtable **ifaces; + const char *nameserver; +}; + +/* + * Like `mg_mgr_init` but with more options. + * + * Notably, this allows you to create a manger and choose + * dynamically which networking interface implementation to use. + */ +void mg_mgr_init_opt(struct mg_mgr *mgr, void *user_data, + struct mg_mgr_init_opts opts); + +/* + * De-initialises Mongoose manager. + * + * Closes and deallocates all active connections. + */ +void mg_mgr_free(struct mg_mgr *); + +/* + * This function performs the actual IO and must be called in a loop + * (an event loop). It returns the current timestamp. + * `milli` is the maximum number of milliseconds to sleep. + * `mg_mgr_poll()` checks all connections for IO readiness. If at least one + * of the connections is IO-ready, `mg_mgr_poll()` triggers the respective + * event handlers and returns. + */ +time_t mg_mgr_poll(struct mg_mgr *, int milli); + +#if MG_ENABLE_BROADCAST +/* + * Passes a message of a given length to all connections. + * + * Must be called from a thread that does NOT call `mg_mgr_poll()`. + * Note that `mg_broadcast()` is the only function + * that can be, and must be, called from a different (non-IO) thread. + * + * `func` callback function will be called by the IO thread for each + * connection. When called, the event will be `MG_EV_POLL`, and a message will + * be passed as the `ev_data` pointer. Maximum message size is capped + * by `MG_CTL_MSG_MESSAGE_SIZE` which is set to 8192 bytes. + */ +void mg_broadcast(struct mg_mgr *mgr, mg_event_handler_t cb, void *data, + size_t len); +#endif + +/* + * Iterates over all active connections. + * + * Returns the next connection from the list + * of active connections or `NULL` if there are no more connections. Below + * is the iteration idiom: + * + * ```c + * for (c = mg_next(srv, NULL); c != NULL; c = mg_next(srv, c)) { + * // Do something with connection `c` + * } + * ``` + */ +struct mg_connection *mg_next(struct mg_mgr *mgr, struct mg_connection *c); + +/* + * Optional parameters to `mg_add_sock_opt()`. + * + * `flags` is an initial `struct mg_connection::flags` bitmask to set, + * see `MG_F_*` flags definitions. + */ +struct mg_add_sock_opts { + void *user_data; /* Initial value for connection's user_data */ + unsigned int flags; /* Initial connection flags */ + const char **error_string; /* Placeholder for the error string */ + struct mg_iface *iface; /* Interface instance */ +}; + +/* + * Creates a connection, associates it with the given socket and event handler + * and adds it to the manager. + * + * For more options see the `mg_add_sock_opt` variant. + */ +struct mg_connection *mg_add_sock(struct mg_mgr *mgr, sock_t sock, + MG_CB(mg_event_handler_t handler, + void *user_data)); + +/* + * Creates a connection, associates it with the given socket and event handler + * and adds to the manager. + * + * See the `mg_add_sock_opts` structure for a description of the options. + */ +struct mg_connection *mg_add_sock_opt(struct mg_mgr *mgr, sock_t sock, + MG_CB(mg_event_handler_t handler, + void *user_data), + struct mg_add_sock_opts opts); + +/* + * Optional parameters to `mg_bind_opt()`. + * + * `flags` is an initial `struct mg_connection::flags` bitmask to set, + * see `MG_F_*` flags definitions. + */ +struct mg_bind_opts { + void *user_data; /* Initial value for connection's user_data */ + unsigned int flags; /* Extra connection flags */ + const char **error_string; /* Placeholder for the error string */ + struct mg_iface *iface; /* Interface instance */ +#if MG_ENABLE_SSL + /* + * SSL settings. + * + * Server certificate to present to clients or client certificate to + * present to tunnel dispatcher (for tunneled connections). + */ + const char *ssl_cert; + /* Private key corresponding to the certificate. If ssl_cert is set but + * ssl_key is not, ssl_cert is used. */ + const char *ssl_key; + /* CA bundle used to verify client certificates or tunnel dispatchers. */ + const char *ssl_ca_cert; + /* Colon-delimited list of acceptable cipher suites. + * Names depend on the library used, for example: + * + * ECDH-ECDSA-AES128-GCM-SHA256:DHE-RSA-AES128-SHA256 (OpenSSL) + * TLS-ECDH-ECDSA-WITH-AES-128-GCM-SHA256:TLS-DHE-RSA-WITH-AES-128-GCM-SHA256 + * (mbedTLS) + * + * For OpenSSL the list can be obtained by running "openssl ciphers". + * For mbedTLS, names can be found in library/ssl_ciphersuites.c + * If NULL, a reasonable default is used. + */ + const char *ssl_cipher_suites; +#endif +}; + +/* + * Creates a listening connection. + * + * See `mg_bind_opt` for full documentation. + */ +struct mg_connection *mg_bind(struct mg_mgr *mgr, const char *address, + MG_CB(mg_event_handler_t handler, + void *user_data)); +/* + * Creates a listening connection. + * + * The `address` parameter specifies which address to bind to. It's format is + * the same as for the `mg_connect()` call, where `HOST` part is optional. + * `address` can be just a port number, e.g. `:8000`. To bind to a specific + * interface, an IP address can be specified, e.g. `1.2.3.4:8000`. By default, + * a TCP connection is created. To create UDP connection, prepend `udp://` + * prefix, e.g. `udp://:8000`. To summarize, `address` parameter has following + * format: `[PROTO://][IP_ADDRESS]:PORT`, where `PROTO` could be `tcp` or + * `udp`. + * + * See the `mg_bind_opts` structure for a description of the optional + * parameters. + * + * Returns a new listening connection or `NULL` on error. + * NOTE: The connection remains owned by the manager, do not free(). + */ +struct mg_connection *mg_bind_opt(struct mg_mgr *mgr, const char *address, + MG_CB(mg_event_handler_t handler, + void *user_data), + struct mg_bind_opts opts); + +/* Optional parameters to `mg_connect_opt()` */ +struct mg_connect_opts { + void *user_data; /* Initial value for connection's user_data */ + unsigned int flags; /* Extra connection flags */ + const char **error_string; /* Placeholder for the error string */ + struct mg_iface *iface; /* Interface instance */ + const char *nameserver; /* DNS server to use, NULL for default */ +#if MG_ENABLE_SSL + /* + * SSL settings. + * Client certificate to present to the server. + */ + const char *ssl_cert; + /* + * Private key corresponding to the certificate. + * If ssl_cert is set but ssl_key is not, ssl_cert is used. + */ + const char *ssl_key; + /* + * Verify server certificate using this CA bundle. If set to "*", then SSL + * is enabled but no cert verification is performed. + */ + const char *ssl_ca_cert; + /* Colon-delimited list of acceptable cipher suites. + * Names depend on the library used, for example: + * + * ECDH-ECDSA-AES128-GCM-SHA256:DHE-RSA-AES128-SHA256 (OpenSSL) + * TLS-ECDH-ECDSA-WITH-AES-128-GCM-SHA256:TLS-DHE-RSA-WITH-AES-128-GCM-SHA256 + * (mbedTLS) + * + * For OpenSSL the list can be obtained by running "openssl ciphers". + * For mbedTLS, names can be found in library/ssl_ciphersuites.c + * If NULL, a reasonable default is used. + */ + const char *ssl_cipher_suites; + /* + * Server name verification. If ssl_ca_cert is set and the certificate has + * passed verification, its subject will be verified against this string. + * By default (if ssl_server_name is NULL) hostname part of the address will + * be used. Wildcard matching is supported. A special value of "*" disables + * name verification. + */ + const char *ssl_server_name; + /* + * PSK identity and key. Identity is a NUL-terminated string and key is a hex + * string. Key must be either 16 or 32 bytes (32 or 64 hex digits) for AES-128 + * or AES-256 respectively. + * Note: Default list of cipher suites does not include PSK suites, if you + * want to use PSK you will need to set ssl_cipher_suites as well. + */ + const char *ssl_psk_identity; + const char *ssl_psk_key; +#endif +}; + +/* + * Connects to a remote host. + * + * See `mg_connect_opt()` for full documentation. + */ +struct mg_connection *mg_connect(struct mg_mgr *mgr, const char *address, + MG_CB(mg_event_handler_t handler, + void *user_data)); + +/* + * Connects to a remote host. + * + * The `address` format is `[PROTO://]HOST:PORT`. `PROTO` could be `tcp` or + * `udp`. `HOST` could be an IP address, + * IPv6 address (if Mongoose is compiled with `-DMG_ENABLE_IPV6`) or a host + * name. If `HOST` is a name, Mongoose will resolve it asynchronously. Examples + * of valid addresses: `google.com:80`, `udp://1.2.3.4:53`, `10.0.0.1:443`, + * `[::1]:80` + * + * See the `mg_connect_opts` structure for a description of the optional + * parameters. + * + * Returns a new outbound connection or `NULL` on error. + * + * NOTE: The connection remains owned by the manager, do not free(). + * + * NOTE: To enable IPv6 addresses `-DMG_ENABLE_IPV6` should be specified + * in the compilation flags. + * + * NOTE: The new connection will receive `MG_EV_CONNECT` as its first event + * which will report the connect success status. + * If the asynchronous resolution fails or the `connect()` syscall fails for + * whatever reason (e.g. with `ECONNREFUSED` or `ENETUNREACH`), then + * `MG_EV_CONNECT` event will report failure. Code example below: + * + * ```c + * static void ev_handler(struct mg_connection *nc, int ev, void *ev_data) { + * int connect_status; + * + * switch (ev) { + * case MG_EV_CONNECT: + * connect_status = * (int *) ev_data; + * if (connect_status == 0) { + * // Success + * } else { + * // Error + * printf("connect() error: %s\n", strerror(connect_status)); + * } + * break; + * ... + * } + * } + * + * ... + * mg_connect(mgr, "my_site.com:80", ev_handler); + * ``` + */ +struct mg_connection *mg_connect_opt(struct mg_mgr *mgr, const char *address, + MG_CB(mg_event_handler_t handler, + void *user_data), + struct mg_connect_opts opts); + +#if MG_ENABLE_SSL && MG_NET_IF != MG_NET_IF_SIMPLELINK +/* + * Note: This function is deprecated. Please, use SSL options in + * mg_connect_opt. + * + * Enables SSL for a given connection. + * `cert` is a server certificate file name for a listening connection + * or a client certificate file name for an outgoing connection. + * The certificate files must be in PEM format. The server certificate file + * must contain a certificate, concatenated with a private key, optionally + * concatenated with DH parameters. + * `ca_cert` is a CA certificate or NULL if peer verification is not + * required. + * Return: NULL on success or error message on error. + */ +const char *mg_set_ssl(struct mg_connection *nc, const char *cert, + const char *ca_cert); +#endif + +/* + * Sends data to the connection. + * + * Note that sending functions do not actually push data to the socket. + * They just append data to the output buffer. MG_EV_SEND will be delivered when + * the data has actually been pushed out. + */ +void mg_send(struct mg_connection *, const void *buf, int len); + +/* Enables format string warnings for mg_printf */ +#if defined(__GNUC__) +__attribute__((format(printf, 2, 3))) +#endif +/* don't separate from mg_printf declaration */ + +/* + * Sends `printf`-style formatted data to the connection. + * + * See `mg_send` for more details on send semantics. + */ +int mg_printf(struct mg_connection *, const char *fmt, ...); + +/* Same as `mg_printf()`, but takes `va_list ap` as an argument. */ +int mg_vprintf(struct mg_connection *, const char *fmt, va_list ap); + +/* + * Creates a socket pair. + * `sock_type` can be either `SOCK_STREAM` or `SOCK_DGRAM`. + * Returns 0 on failure and 1 on success. + */ +int mg_socketpair(sock_t[2], int sock_type); + +#if MG_ENABLE_SYNC_RESOLVER +/* + * Convert domain name into IP address. + * + * This is a utility function. If compilation flags have + * `-DMG_ENABLE_GETADDRINFO`, then `getaddrinfo()` call is used for name + * resolution. Otherwise, `gethostbyname()` is used. + * + * CAUTION: this function can block. + * Return 1 on success, 0 on failure. + */ +int mg_resolve(const char *domain_name, char *ip_addr_buf, size_t buf_len); +#endif + +/* + * Verify given IP address against the ACL. + * + * `remote_ip` - an IPv4 address to check, in host byte order + * `acl` - a comma separated list of IP subnets: `x.x.x.x/x` or `x.x.x.x`. + * Each subnet is + * prepended by either a - or a + sign. A plus sign means allow, where a + * minus sign means deny. If a subnet mask is omitted, such as `-1.2.3.4`, + * it means that only that single IP address is denied. + * Subnet masks may vary from 0 to 32, inclusive. The default setting + * is to allow all access. On each request the full list is traversed, + * and the last match wins. Example: + * + * `-0.0.0.0/0,+192.168/16` - deny all accesses, only allow 192.168/16 subnet + * + * To learn more about subnet masks, see this + * link:https://en.wikipedia.org/wiki/Subnetwork[Wikipedia page on Subnetwork]. + * + * Returns -1 if ACL is malformed, 0 if address is disallowed, 1 if allowed. + */ +int mg_check_ip_acl(const char *acl, uint32_t remote_ip); + +#if MG_ENABLE_JAVASCRIPT +/* + * Enables server-side JavaScript scripting. + * Requires a `-DMG_ENABLE_JAVASCRIPT` compilation flag and V7 engine sources. + * V7 instance must not be destroyed during manager's lifetime. + * Returns a V7 error. + */ +enum v7_err mg_enable_javascript(struct mg_mgr *m, struct v7 *v7, + const char *init_js_file_name); +#endif + +/* + * Schedules an MG_EV_TIMER event to be delivered at `timestamp` time. + * `timestamp` is UNIX time (the number of seconds since Epoch). It is + * `double` instead of `time_t` to allow for sub-second precision. + * Returns the old timer value. + * + * Example: set the connect timeout to 1.5 seconds: + * + * ``` + * c = mg_connect(&mgr, "cesanta.com", ev_handler); + * mg_set_timer(c, mg_time() + 1.5); + * ... + * + * void ev_handler(struct mg_connection *c, int ev, void *ev_data) { + * switch (ev) { + * case MG_EV_CONNECT: + * mg_set_timer(c, 0); // Clear connect timer + * break; + * case MG_EV_TIMER: + * log("Connect timeout"); + * c->flags |= MG_F_CLOSE_IMMEDIATELY; + * break; + * ``` + */ +double mg_set_timer(struct mg_connection *c, double timestamp); + +/* + * A sub-second precision version of time(). + */ +double mg_time(void); + +#ifdef __cplusplus +} +#endif /* __cplusplus */ + +#endif /* CS_MONGOOSE_SRC_NET_H_ */ +#ifdef MG_MODULE_LINES +#line 1 "mongoose/src/uri.h" +#endif +/* + * Copyright (c) 2014 Cesanta Software Limited + * All rights reserved + */ + +/* + * === URI + */ + +#ifndef CS_MONGOOSE_SRC_URI_H_ +#define CS_MONGOOSE_SRC_URI_H_ + +/* Amalgamated: #include "mongoose/src/net.h" */ + +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + +/* + * Parses an URI and fills string chunks with locations of the respective + * uri components within the input uri string. NULL pointers will be + * ignored. + * + * General syntax: + * + * [scheme://[user_info@]]host[:port][/path][?query][#fragment] + * + * Example: + * + * foo.com:80 + * tcp://foo.com:1234 + * http://foo.com:80/bar?baz=1 + * https://user:pw@foo.com:443/blah + * + * `path` will include the leading slash. `query` won't include the leading `?`. + * `host` can contain embedded colons if surrounded by square brackets in order + * to support IPv6 literal addresses. + * + * + * Returns 0 on success, -1 on error. + */ +int mg_parse_uri(struct mg_str uri, struct mg_str *scheme, + struct mg_str *user_info, struct mg_str *host, + unsigned int *port, struct mg_str *path, struct mg_str *query, + struct mg_str *fragment); + +int mg_normalize_uri_path(const struct mg_str *in, struct mg_str *out); + +#ifdef __cplusplus +} +#endif /* __cplusplus */ +#endif /* CS_MONGOOSE_SRC_URI_H_ */ +#ifdef MG_MODULE_LINES +#line 1 "mongoose/src/util.h" +#endif +/* + * Copyright (c) 2014 Cesanta Software Limited + * All rights reserved + */ + +/* + * === Utility API + */ + +#ifndef CS_MONGOOSE_SRC_UTIL_H_ +#define CS_MONGOOSE_SRC_UTIL_H_ + +#include + +/* Amalgamated: #include "mongoose/src/common.h" */ +/* Amalgamated: #include "mongoose/src/net_if.h" */ + +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + +#ifndef MAX_PATH_SIZE +#define MAX_PATH_SIZE 500 +#endif + +/* + * Fetches substring from input string `s`, `end` into `v`. + * Skips initial delimiter characters. Records first non-delimiter character + * at the beginning of substring `v`. Then scans the rest of the string + * until a delimiter character or end-of-string is found. + * `delimiters` is a 0-terminated string containing delimiter characters. + * Either one of `delimiters` or `end_string` terminates the search. + * Returns an `s` pointer, advanced forward where parsing has stopped. + */ +const char *mg_skip(const char *s, const char *end_string, + const char *delimiters, struct mg_str *v); + +/* + * Decodes base64-encoded string `s`, `len` into the destination `dst`. + * The destination has to have enough space to hold the decoded buffer. + * Decoding stops either when all strings have been decoded or invalid an + * character appeared. + * Destination is '\0'-terminated. + * Returns the number of decoded characters. On success, that should be equal + * to `len`. On error (invalid character) the return value is smaller then + * `len`. + */ +int mg_base64_decode(const unsigned char *s, int len, char *dst); + +/* + * Base64-encode chunk of memory `src`, `src_len` into the destination `dst`. + * Destination has to have enough space to hold encoded buffer. + * Destination is '\0'-terminated. + */ +void mg_base64_encode(const unsigned char *src, int src_len, char *dst); + +#if MG_ENABLE_FILESYSTEM +/* + * Performs a 64-bit `stat()` call against a given file. + * + * `path` should be UTF8 encoded. + * + * Return value is the same as for `stat()` syscall. + */ +int mg_stat(const char *path, cs_stat_t *st); + +/* + * Opens the given file and returns a file stream. + * + * `path` and `mode` should be UTF8 encoded. + * + * Return value is the same as for the `fopen()` call. + */ +FILE *mg_fopen(const char *path, const char *mode); + +/* + * Opens the given file and returns a file stream. + * + * `path` should be UTF8 encoded. + * + * Return value is the same as for the `open()` syscall. + */ +int mg_open(const char *path, int flag, int mode); + +/* + * Reads data from the given file stream. + * + * Return value is a number of bytes readen. + */ +size_t mg_fread(void *ptr, size_t size, size_t count, FILE *f); + +/* + * Writes data to the given file stream. + * + * Return value is a number of bytes wtitten. + */ +size_t mg_fwrite(const void *ptr, size_t size, size_t count, FILE *f); + +#endif /* MG_ENABLE_FILESYSTEM */ + +#if MG_ENABLE_THREADS +/* + * Starts a new detached thread. + * Arguments and semantics are the same as pthead's `pthread_create()`. + * `thread_func` is a thread function, `thread_func_param` is a parameter + * that is passed to the thread function. + */ +void *mg_start_thread(void *(*thread_func)(void *), void *thread_func_param); +#endif + +void mg_set_close_on_exec(sock_t); + +#define MG_SOCK_STRINGIFY_IP 1 +#define MG_SOCK_STRINGIFY_PORT 2 +#define MG_SOCK_STRINGIFY_REMOTE 4 +/* + * Converts a connection's local or remote address into string. + * + * The `flags` parameter is a bit mask that controls the behaviour, + * see `MG_SOCK_STRINGIFY_*` definitions. + * + * - MG_SOCK_STRINGIFY_IP - print IP address + * - MG_SOCK_STRINGIFY_PORT - print port number + * - MG_SOCK_STRINGIFY_REMOTE - print remote peer's IP/port, not local address + * + * If both port number and IP address are printed, they are separated by `:`. + * If compiled with `-DMG_ENABLE_IPV6`, IPv6 addresses are supported. + */ +void mg_conn_addr_to_str(struct mg_connection *nc, char *buf, size_t len, + int flags); +#if MG_NET_IF == MG_NET_IF_SOCKET +/* Legacy interface. */ +void mg_sock_to_str(sock_t sock, char *buf, size_t len, int flags); +#endif + +/* + * Convert the socket's address into string. + * + * `flags` is MG_SOCK_STRINGIFY_IP and/or MG_SOCK_STRINGIFY_PORT. + */ +void mg_sock_addr_to_str(const union socket_address *sa, char *buf, size_t len, + int flags); + +#if MG_ENABLE_HEXDUMP +/* + * Generates a human-readable hexdump of memory chunk. + * + * Takes a memory buffer `buf` of length `len` and creates a hex dump of that + * buffer in `dst`. The generated output is a-la hexdump(1). + * Returns the length of generated string, excluding terminating `\0`. If + * returned length is bigger than `dst_len`, the overflow bytes are discarded. + */ +int mg_hexdump(const void *buf, int len, char *dst, int dst_len); + +/* Same as mg_hexdump, but with output going to file instead of a buffer. */ +void mg_hexdumpf(FILE *fp, const void *buf, int len); + +/* + * Generates human-readable hexdump of the data sent or received by the + * connection. `path` is a file name where hexdump should be written. + * `num_bytes` is a number of bytes sent/received. `ev` is one of the `MG_*` + * events sent to an event handler. This function is supposed to be called from + * the event handler. + */ +void mg_hexdump_connection(struct mg_connection *nc, const char *path, + const void *buf, int num_bytes, int ev); +#endif + +/* + * Returns true if target platform is big endian. + */ +int mg_is_big_endian(void); + +/* + * A helper function for traversing a comma separated list of values. + * It returns a list pointer shifted to the next value or NULL if the end + * of the list found. + * The value is stored in a val vector. If the value has a form "x=y", then + * eq_val vector is initialised to point to the "y" part, and val vector length + * is adjusted to point only to "x". + * If the list is just a comma separated list of entries, like "aa,bb,cc" then + * `eq_val` will contain zero-length string. + * + * The purpose of this function is to parse comma separated string without + * any copying/memory allocation. + */ +const char *mg_next_comma_list_entry(const char *list, struct mg_str *val, + struct mg_str *eq_val); + +/* + * Matches 0-terminated string (mg_match_prefix) or string with given length + * mg_match_prefix_n against a glob pattern. + * + * Match is case-insensitive. Returns number of bytes matched, or -1 if no + * match. + */ +int mg_match_prefix(const char *pattern, int pattern_len, const char *str); +int mg_match_prefix_n(const struct mg_str pattern, const struct mg_str str); + +/* + * Use with cs_base64_init/update/finish in order to write out base64 in chunks. + */ +void mg_mbuf_append_base64_putc(char ch, void *user_data); + +/* + * Encode `len` bytes starting at `data` as base64 and append them to an mbuf. + */ +void mg_mbuf_append_base64(struct mbuf *mbuf, const void *data, size_t len); + +/* + * Generate a Basic Auth header and appends it to buf. + * If pass is NULL, then user is expected to contain the credentials pair + * already encoded as `user:pass`. + */ +void mg_basic_auth_header(const char *user, const char *pass, struct mbuf *buf); + +#ifdef __cplusplus +} +#endif /* __cplusplus */ +#endif /* CS_MONGOOSE_SRC_UTIL_H_ */ +#ifdef MG_MODULE_LINES +#line 1 "mongoose/src/http.h" +#endif +/* + * Copyright (c) 2014 Cesanta Software Limited + * All rights reserved + */ + +/* + * === Common API reference + */ + +#ifndef CS_MONGOOSE_SRC_HTTP_H_ +#define CS_MONGOOSE_SRC_HTTP_H_ + +#if MG_ENABLE_HTTP + +/* Amalgamated: #include "mongoose/src/net.h" */ +/* Amalgamated: #include "common/mg_str.h" */ + +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + +#ifndef MG_MAX_HTTP_HEADERS +#define MG_MAX_HTTP_HEADERS 20 +#endif + +#ifndef MG_MAX_HTTP_REQUEST_SIZE +#define MG_MAX_HTTP_REQUEST_SIZE 1024 +#endif + +#ifndef MG_MAX_PATH +#ifdef PATH_MAX +#define MG_MAX_PATH PATH_MAX +#else +#define MG_MAX_PATH 256 +#endif +#endif + +#ifndef MG_MAX_HTTP_SEND_MBUF +#define MG_MAX_HTTP_SEND_MBUF 1024 +#endif + +#ifndef MG_CGI_ENVIRONMENT_SIZE +#define MG_CGI_ENVIRONMENT_SIZE 8192 +#endif + +/* HTTP message */ +struct http_message { + struct mg_str message; /* Whole message: request line + headers + body */ + + /* HTTP Request line (or HTTP response line) */ + struct mg_str method; /* "GET" */ + struct mg_str uri; /* "/my_file.html" */ + struct mg_str proto; /* "HTTP/1.1" -- for both request and response */ + + /* For responses, code and response status message are set */ + int resp_code; + struct mg_str resp_status_msg; + + /* + * Query-string part of the URI. For example, for HTTP request + * GET /foo/bar?param1=val1¶m2=val2 + * | uri | query_string | + * + * Note that question mark character doesn't belong neither to the uri, + * nor to the query_string + */ + struct mg_str query_string; + + /* Headers */ + struct mg_str header_names[MG_MAX_HTTP_HEADERS]; + struct mg_str header_values[MG_MAX_HTTP_HEADERS]; + + /* Message body */ + struct mg_str body; /* Zero-length for requests with no body */ +}; + +#if MG_ENABLE_HTTP_WEBSOCKET +/* WebSocket message */ +struct websocket_message { + unsigned char *data; + size_t size; + unsigned char flags; +}; +#endif + +/* HTTP multipart part */ +struct mg_http_multipart_part { + const char *file_name; + const char *var_name; + struct mg_str data; + int status; /* <0 on error */ + void *user_data; +}; + +/* SSI call context */ +struct mg_ssi_call_ctx { + struct http_message *req; /* The request being processed. */ + struct mg_str file; /* Filesystem path of the file being processed. */ + struct mg_str arg; /* The argument passed to the tag: . */ +}; + +/* HTTP and websocket events. void *ev_data is described in a comment. */ +#define MG_EV_HTTP_REQUEST 100 /* struct http_message * */ +#define MG_EV_HTTP_REPLY 101 /* struct http_message * */ +#define MG_EV_HTTP_CHUNK 102 /* struct http_message * */ +#define MG_EV_SSI_CALL 105 /* char * */ +#define MG_EV_SSI_CALL_CTX 106 /* struct mg_ssi_call_ctx * */ + +#if MG_ENABLE_HTTP_WEBSOCKET +#define MG_EV_WEBSOCKET_HANDSHAKE_REQUEST 111 /* struct http_message * */ +#define MG_EV_WEBSOCKET_HANDSHAKE_DONE 112 /* NULL */ +#define MG_EV_WEBSOCKET_FRAME 113 /* struct websocket_message * */ +#define MG_EV_WEBSOCKET_CONTROL_FRAME 114 /* struct websocket_message * */ +#endif + +#if MG_ENABLE_HTTP_STREAMING_MULTIPART +#define MG_EV_HTTP_MULTIPART_REQUEST 121 /* struct http_message */ +#define MG_EV_HTTP_PART_BEGIN 122 /* struct mg_http_multipart_part */ +#define MG_EV_HTTP_PART_DATA 123 /* struct mg_http_multipart_part */ +#define MG_EV_HTTP_PART_END 124 /* struct mg_http_multipart_part */ +/* struct mg_http_multipart_part */ +#define MG_EV_HTTP_MULTIPART_REQUEST_END 125 +#endif + +/* + * Attaches a built-in HTTP event handler to the given connection. + * The user-defined event handler will receive following extra events: + * + * - MG_EV_HTTP_REQUEST: HTTP request has arrived. Parsed HTTP request + * is passed as + * `struct http_message` through the handler's `void *ev_data` pointer. + * - MG_EV_HTTP_REPLY: The HTTP reply has arrived. The parsed HTTP reply is + * passed as `struct http_message` through the handler's `void *ev_data` + * pointer. + * - MG_EV_HTTP_CHUNK: The HTTP chunked-encoding chunk has arrived. + * The parsed HTTP reply is passed as `struct http_message` through the + * handler's `void *ev_data` pointer. `http_message::body` would contain + * incomplete, reassembled HTTP body. + * It will grow with every new chunk that arrives, and it can + * potentially consume a lot of memory. An event handler may process + * the body as chunks are coming, and signal Mongoose to delete processed + * body by setting `MG_F_DELETE_CHUNK` in `mg_connection::flags`. When + * the last zero chunk is received, + * Mongoose sends `MG_EV_HTTP_REPLY` event with + * full reassembled body (if handler did not signal to delete chunks) or + * with empty body (if handler did signal to delete chunks). + * - MG_EV_WEBSOCKET_HANDSHAKE_REQUEST: server has received the WebSocket + * handshake request. `ev_data` contains parsed HTTP request. + * - MG_EV_WEBSOCKET_HANDSHAKE_DONE: server has completed the WebSocket + * handshake. `ev_data` is `NULL`. + * - MG_EV_WEBSOCKET_FRAME: new WebSocket frame has arrived. `ev_data` is + * `struct websocket_message *` + * + * When compiled with MG_ENABLE_HTTP_STREAMING_MULTIPART, Mongoose parses + * multipart requests and splits them into separate events: + * - MG_EV_HTTP_MULTIPART_REQUEST: Start of the request. + * This event is sent before body is parsed. After this, the user + * should expect a sequence of PART_BEGIN/DATA/END requests. + * This is also the last time when headers and other request fields are + * accessible. + * - MG_EV_HTTP_PART_BEGIN: Start of a part of a multipart message. + * Argument: mg_http_multipart_part with var_name and file_name set + * (if present). No data is passed in this message. + * - MG_EV_HTTP_PART_DATA: new portion of data from the multipart message. + * Argument: mg_http_multipart_part. var_name and file_name are preserved, + * data is available in mg_http_multipart_part.data. + * - MG_EV_HTTP_PART_END: End of the current part. var_name, file_name are + * the same, no data in the message. If status is 0, then the part is + * properly terminated with a boundary, status < 0 means that connection + * was terminated. + * - MG_EV_HTTP_MULTIPART_REQUEST_END: End of the multipart request. + * Argument: mg_http_multipart_part, var_name and file_name are NULL, + * status = 0 means request was properly closed, < 0 means connection + * was terminated (note: in this case both PART_END and REQUEST_END are + * delivered). + */ +void mg_set_protocol_http_websocket(struct mg_connection *nc); + +#if MG_ENABLE_HTTP_WEBSOCKET +/* + * Send websocket handshake to the server. + * + * `nc` must be a valid connection, connected to a server. `uri` is an URI + * to fetch, extra_headers` is extra HTTP headers to send or `NULL`. + * + * This function is intended to be used by websocket client. + * + * Note that the Host header is mandatory in HTTP/1.1 and must be + * included in `extra_headers`. `mg_send_websocket_handshake2` offers + * a better API for that. + * + * Deprecated in favour of `mg_send_websocket_handshake2` + */ +void mg_send_websocket_handshake(struct mg_connection *nc, const char *uri, + const char *extra_headers); + +/* + * Send websocket handshake to the server. + * + * `nc` must be a valid connection, connected to a server. `uri` is an URI + * to fetch, `host` goes into the `Host` header, `protocol` goes into the + * `Sec-WebSocket-Proto` header (NULL to omit), extra_headers` is extra HTTP + * headers to send or `NULL`. + * + * This function is intended to be used by websocket client. + */ +void mg_send_websocket_handshake2(struct mg_connection *nc, const char *path, + const char *host, const char *protocol, + const char *extra_headers); + +/* Like mg_send_websocket_handshake2 but also passes basic auth header */ +void mg_send_websocket_handshake3(struct mg_connection *nc, const char *path, + const char *host, const char *protocol, + const char *extra_headers, const char *user, + const char *pass); +/* + * Helper function that creates an outbound WebSocket connection. + * + * `url` is a URL to connect to. It must be properly URL-encoded, e.g. have + * no spaces, etc. By default, `mg_connect_ws()` sends Connection and + * Host headers. `extra_headers` is an extra HTTP header to send, e.g. + * `"User-Agent: my-app\r\n"`. + * If `protocol` is not NULL, then a `Sec-WebSocket-Protocol` header is sent. + * + * Examples: + * + * ```c + * nc1 = mg_connect_ws(mgr, ev_handler_1, "ws://echo.websocket.org", NULL, + * NULL); + * nc2 = mg_connect_ws(mgr, ev_handler_1, "wss://echo.websocket.org", NULL, + * NULL); + * nc3 = mg_connect_ws(mgr, ev_handler_1, "ws://api.cesanta.com", + * "clubby.cesanta.com", NULL); + * ``` + */ +struct mg_connection *mg_connect_ws(struct mg_mgr *mgr, + MG_CB(mg_event_handler_t event_handler, + void *user_data), + const char *url, const char *protocol, + const char *extra_headers); + +/* + * Helper function that creates an outbound WebSocket connection + * + * Mostly identical to `mg_connect_ws`, but allows to provide extra parameters + * (for example, SSL parameters) + */ +struct mg_connection *mg_connect_ws_opt( + struct mg_mgr *mgr, MG_CB(mg_event_handler_t ev_handler, void *user_data), + struct mg_connect_opts opts, const char *url, const char *protocol, + const char *extra_headers); + +/* + * Send WebSocket frame to the remote end. + * + * `op_and_flags` specifies the frame's type. It's one of: + * + * - WEBSOCKET_OP_CONTINUE + * - WEBSOCKET_OP_TEXT + * - WEBSOCKET_OP_BINARY + * - WEBSOCKET_OP_CLOSE + * - WEBSOCKET_OP_PING + * - WEBSOCKET_OP_PONG + * + * Orred with one of the flags: + * + * - WEBSOCKET_DONT_FIN: Don't set the FIN flag on the frame to be sent. + * + * `data` and `data_len` contain frame data. + */ +void mg_send_websocket_frame(struct mg_connection *nc, int op_and_flags, + const void *data, size_t data_len); + +/* + * Sends multiple websocket frames. + * + * Like `mg_send_websocket_frame()`, but composes a frame from multiple buffers. + */ +void mg_send_websocket_framev(struct mg_connection *nc, int op_and_flags, + const struct mg_str *strings, int num_strings); + +/* + * Sends WebSocket frame to the remote end. + * + * Like `mg_send_websocket_frame()`, but allows to create formatted messages + * with `printf()`-like semantics. + */ +void mg_printf_websocket_frame(struct mg_connection *nc, int op_and_flags, + const char *fmt, ...); + +/* Websocket opcodes, from http://tools.ietf.org/html/rfc6455 */ +#define WEBSOCKET_OP_CONTINUE 0 +#define WEBSOCKET_OP_TEXT 1 +#define WEBSOCKET_OP_BINARY 2 +#define WEBSOCKET_OP_CLOSE 8 +#define WEBSOCKET_OP_PING 9 +#define WEBSOCKET_OP_PONG 10 + +/* + * If set causes the FIN flag to not be set on outbound + * frames. This enables sending multiple fragments of a single + * logical message. + * + * The WebSocket protocol mandates that if the FIN flag of a data + * frame is not set, the next frame must be a WEBSOCKET_OP_CONTINUE. + * The last frame must have the FIN bit set. + * + * Note that mongoose will automatically defragment incoming messages, + * so this flag is used only on outbound messages. + */ +#define WEBSOCKET_DONT_FIN 0x100 + +#endif /* MG_ENABLE_HTTP_WEBSOCKET */ + +/* + * Decodes a URL-encoded string. + * + * Source string is specified by (`src`, `src_len`), and destination is + * (`dst`, `dst_len`). If `is_form_url_encoded` is non-zero, then + * `+` character is decoded as a blank space character. This function + * guarantees to NUL-terminate the destination. If destination is too small, + * then the source string is partially decoded and `-1` is returned. Otherwise, + * a length of the decoded string is returned, not counting final NUL. + */ +int mg_url_decode(const char *src, int src_len, char *dst, int dst_len, + int is_form_url_encoded); + +#ifdef __cplusplus +} +#endif /* __cplusplus */ + +#endif /* MG_ENABLE_HTTP */ + +#endif /* CS_MONGOOSE_SRC_HTTP_H_ */ +#ifdef MG_MODULE_LINES +#line 1 "mongoose/src/http_server.h" +#endif +/* + * === Server API reference + */ + +#ifndef CS_MONGOOSE_SRC_HTTP_SERVER_H_ +#define CS_MONGOOSE_SRC_HTTP_SERVER_H_ + +#if MG_ENABLE_HTTP + +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + +/* + * Parses a HTTP message. + * + * `is_req` should be set to 1 if parsing a request, 0 if reply. + * + * Returns the number of bytes parsed. If HTTP message is + * incomplete `0` is returned. On parse error, a negative number is returned. + */ +int mg_parse_http(const char *s, int n, struct http_message *hm, int is_req); + +/* + * Searches and returns the header `name` in parsed HTTP message `hm`. + * If header is not found, NULL is returned. Example: + * + * struct mg_str *host_hdr = mg_get_http_header(hm, "Host"); + */ +struct mg_str *mg_get_http_header(struct http_message *hm, const char *name); + +/* + * Parses the HTTP header `hdr`. Finds variable `var_name` and stores its value + * in the buffer `buf`, `buf_size`. Returns 0 if variable not found, non-zero + * otherwise. + * + * This function is supposed to parse cookies, authentication headers, etc. + * Example (error handling omitted): + * + * char user[20]; + * struct mg_str *hdr = mg_get_http_header(hm, "Authorization"); + * mg_http_parse_header(hdr, "username", user, sizeof(user)); + * + * Returns the length of the variable's value. If buffer is not large enough, + * or variable not found, 0 is returned. + */ +int mg_http_parse_header(struct mg_str *hdr, const char *var_name, char *buf, + size_t buf_size); + +/* + * Gets and parses the Authorization: Basic header + * Returns -1 if no Authorization header is found, or if + * mg_parse_http_basic_auth + * fails parsing the resulting header. + */ +int mg_get_http_basic_auth(struct http_message *hm, char *user, size_t user_len, + char *pass, size_t pass_len); + +/* + * Parses the Authorization: Basic header + * Returns -1 iif the authorization type is not "Basic" or any other error such + * as incorrectly encoded base64 user password pair. + */ +int mg_parse_http_basic_auth(struct mg_str *hdr, char *user, size_t user_len, + char *pass, size_t pass_len); + +/* + * Parses the buffer `buf`, `buf_len` that contains multipart form data chunks. + * Stores the chunk name in a `var_name`, `var_name_len` buffer. + * If a chunk is an uploaded file, then `file_name`, `file_name_len` is + * filled with an uploaded file name. `chunk`, `chunk_len` + * points to the chunk data. + * + * Return: number of bytes to skip to the next chunk or 0 if there are + * no more chunks. + * + * Usage example: + * + * ```c + * static void ev_handler(struct mg_connection *nc, int ev, void *ev_data) { + * switch(ev) { + * case MG_EV_HTTP_REQUEST: { + * struct http_message *hm = (struct http_message *) ev_data; + * char var_name[100], file_name[100]; + * const char *chunk; + * size_t chunk_len, n1, n2; + * + * n1 = n2 = 0; + * while ((n2 = mg_parse_multipart(hm->body.p + n1, + * hm->body.len - n1, + * var_name, sizeof(var_name), + * file_name, sizeof(file_name), + * &chunk, &chunk_len)) > 0) { + * printf("var: %s, file_name: %s, size: %d, chunk: [%.*s]\n", + * var_name, file_name, (int) chunk_len, + * (int) chunk_len, chunk); + * n1 += n2; + * } + * } + * break; + * ``` + */ +size_t mg_parse_multipart(const char *buf, size_t buf_len, char *var_name, + size_t var_name_len, char *file_name, + size_t file_name_len, const char **chunk, + size_t *chunk_len); + +/* + * Fetches a HTTP form variable. + * + * Fetches a variable `name` from a `buf` into a buffer specified by `dst`, + * `dst_len`. The destination is always zero-terminated. Returns the length of + * a fetched variable. If not found, 0 is returned. `buf` must be valid + * url-encoded buffer. If destination is too small or an error occured, + * negative number is returned. + */ +int mg_get_http_var(const struct mg_str *buf, const char *name, char *dst, + size_t dst_len); + +#if MG_ENABLE_FILESYSTEM +/* + * This structure defines how `mg_serve_http()` works. + * Best practice is to set only required settings, and leave the rest as NULL. + */ +struct mg_serve_http_opts { + /* Path to web root directory */ + const char *document_root; + + /* List of index files. Default is "" */ + const char *index_files; + + /* + * Leave as NULL to disable authentication. + * To enable directory protection with authentication, set this to ".htpasswd" + * Then, creating ".htpasswd" file in any directory automatically protects + * it with digest authentication. + * Use `mongoose` web server binary, or `htdigest` Apache utility to + * create/manipulate passwords file. + * Make sure `auth_domain` is set to a valid domain name. + */ + const char *per_directory_auth_file; + + /* Authorization domain (domain name of this web server) */ + const char *auth_domain; + + /* + * Leave as NULL to disable authentication. + * Normally, only selected directories in the document root are protected. + * If absolutely every access to the web server needs to be authenticated, + * regardless of the URI, set this option to the path to the passwords file. + * Format of that file is the same as ".htpasswd" file. Make sure that file + * is located outside document root to prevent people fetching it. + */ + const char *global_auth_file; + + /* Set to "no" to disable directory listing. Enabled by default. */ + const char *enable_directory_listing; + + /* + * SSI files pattern. If not set, "**.shtml$|**.shtm$" is used. + * + * All files that match ssi_pattern are treated as SSI. + * + * Server Side Includes (SSI) is a simple interpreted server-side scripting + * language which is most commonly used to include the contents of a file + * into a web page. It can be useful when it is desirable to include a common + * piece of code throughout a website, for example, headers and footers. + * + * In order for a webpage to recognize an SSI-enabled HTML file, the + * filename should end with a special extension, by default the extension + * should be either .shtml or .shtm + * + * Unknown SSI directives are silently ignored by Mongoose. Currently, + * the following SSI directives are supported: + * <!--#include FILE_TO_INCLUDE --> + * <!--#exec "COMMAND_TO_EXECUTE" --> + * <!--#call COMMAND --> + * + * Note that <!--#include ...> directive supports three path + *specifications: + * + * <!--#include virtual="path" --> Path is relative to web server root + * <!--#include abspath="path" --> Path is absolute or relative to the + * web server working dir + * <!--#include file="path" -->, Path is relative to current document + * <!--#include "path" --> + * + * The include directive may be used to include the contents of a file or + * the result of running a CGI script. + * + * The exec directive is used to execute + * a command on a server, and show command's output. Example: + * + * <!--#exec "ls -l" --> + * + * The call directive is a way to invoke a C handler from the HTML page. + * On each occurence of <!--#call COMMAND OPTIONAL_PARAMS> directive, + * Mongoose calls a registered event handler with MG_EV_SSI_CALL event, + * and event parameter will point to the COMMAND OPTIONAL_PARAMS string. + * An event handler can output any text, for example by calling + * `mg_printf()`. This is a flexible way of generating a web page on + * server side by calling a C event handler. Example: + * + * <!--#call foo --> ... <!--#call bar --> + * + * In the event handler: + * case MG_EV_SSI_CALL: { + * const char *param = (const char *) ev_data; + * if (strcmp(param, "foo") == 0) { + * mg_printf(c, "hello from foo"); + * } else if (strcmp(param, "bar") == 0) { + * mg_printf(c, "hello from bar"); + * } + * break; + * } + */ + const char *ssi_pattern; + + /* IP ACL. By default, NULL, meaning all IPs are allowed to connect */ + const char *ip_acl; + +#if MG_ENABLE_HTTP_URL_REWRITES + /* URL rewrites. + * + * Comma-separated list of `uri_pattern=url_file_or_directory_path` rewrites. + * When HTTP request is received, Mongoose constructs a file name from the + * requested URI by combining `document_root` and the URI. However, if the + * rewrite option is used and `uri_pattern` matches requested URI, then + * `document_root` is ignored. Instead, `url_file_or_directory_path` is used, + * which should be a full path name or a path relative to the web server's + * current working directory. It can also be an URI (http:// or https://) + * in which case mongoose will behave as a reverse proxy for that destination. + * + * Note that `uri_pattern`, as all Mongoose patterns, is a prefix pattern. + * + * If uri_pattern starts with `@` symbol, then Mongoose compares it with the + * HOST header of the request. If they are equal, Mongoose sets document root + * to `file_or_directory_path`, implementing virtual hosts support. + * Example: `@foo.com=/document/root/for/foo.com` + * + * If `uri_pattern` starts with `%` symbol, then Mongoose compares it with + * the listening port. If they match, then Mongoose issues a 301 redirect. + * For example, to redirect all HTTP requests to the + * HTTPS port, do `%80=https://my.site.com`. Note that the request URI is + * automatically appended to the redirect location. + */ + const char *url_rewrites; +#endif + + /* DAV document root. If NULL, DAV requests are going to fail. */ + const char *dav_document_root; + + /* + * DAV passwords file. If NULL, DAV requests are going to fail. + * If passwords file is set to "-", then DAV auth is disabled. + */ + const char *dav_auth_file; + + /* Glob pattern for the files to hide. */ + const char *hidden_file_pattern; + + /* Set to non-NULL to enable CGI, e.g. **.cgi$|**.php$" */ + const char *cgi_file_pattern; + + /* If not NULL, ignore CGI script hashbang and use this interpreter */ + const char *cgi_interpreter; + + /* + * Comma-separated list of Content-Type overrides for path suffixes, e.g. + * ".txt=text/plain; charset=utf-8,.c=text/plain" + */ + const char *custom_mime_types; + + /* + * Extra HTTP headers to add to each server response. + * Example: to enable CORS, set this to "Access-Control-Allow-Origin: *". + */ + const char *extra_headers; +}; + +/* + * Serves given HTTP request according to the `options`. + * + * Example code snippet: + * + * ```c + * static void ev_handler(struct mg_connection *nc, int ev, void *ev_data) { + * struct http_message *hm = (struct http_message *) ev_data; + * struct mg_serve_http_opts opts = { .document_root = "/var/www" }; // C99 + * + * switch (ev) { + * case MG_EV_HTTP_REQUEST: + * mg_serve_http(nc, hm, opts); + * break; + * default: + * break; + * } + * } + * ``` + */ +void mg_serve_http(struct mg_connection *nc, struct http_message *hm, + struct mg_serve_http_opts opts); + +/* + * Serves a specific file with a given MIME type and optional extra headers. + * + * Example code snippet: + * + * ```c + * static void ev_handler(struct mg_connection *nc, int ev, void *ev_data) { + * switch (ev) { + * case MG_EV_HTTP_REQUEST: { + * struct http_message *hm = (struct http_message *) ev_data; + * mg_http_serve_file(nc, hm, "file.txt", + * mg_mk_str("text/plain"), mg_mk_str("")); + * break; + * } + * ... + * } + * } + * ``` + */ +void mg_http_serve_file(struct mg_connection *nc, struct http_message *hm, + const char *path, const struct mg_str mime_type, + const struct mg_str extra_headers); + +#if MG_ENABLE_HTTP_STREAMING_MULTIPART + +/* Callback prototype for `mg_file_upload_handler()`. */ +typedef struct mg_str (*mg_fu_fname_fn)(struct mg_connection *nc, + struct mg_str fname); + +/* + * File upload handler. + * This handler can be used to implement file uploads with minimum code. + * This handler will process MG_EV_HTTP_PART_* events and store file data into + * a local file. + * `local_name_fn` will be invoked with whatever name was provided by the client + * and will expect the name of the local file to open. A return value of NULL + * will abort file upload (client will get a "403 Forbidden" response). If + * non-null, the returned string must be heap-allocated and will be freed by + * the caller. + * Exception: it is ok to return the same string verbatim. + * + * Example: + * + * ```c + * struct mg_str upload_fname(struct mg_connection *nc, struct mg_str fname) { + * // Just return the same filename. Do not actually do this except in test! + * // fname is user-controlled and needs to be sanitized. + * return fname; + * } + * void ev_handler(struct mg_connection *nc, int ev, void *ev_data) { + * switch (ev) { + * ... + * case MG_EV_HTTP_PART_BEGIN: + * case MG_EV_HTTP_PART_DATA: + * case MG_EV_HTTP_PART_END: + * mg_file_upload_handler(nc, ev, ev_data, upload_fname); + * break; + * } + * } + * ``` + */ +void mg_file_upload_handler(struct mg_connection *nc, int ev, void *ev_data, + mg_fu_fname_fn local_name_fn + MG_UD_ARG(void *user_data)); +#endif /* MG_ENABLE_HTTP_STREAMING_MULTIPART */ +#endif /* MG_ENABLE_FILESYSTEM */ + +/* + * Registers a callback for a specified http endpoint + * Note: if callback is registered it is called instead of the + * callback provided in mg_bind + * + * Example code snippet: + * + * ```c + * static void handle_hello1(struct mg_connection *nc, int ev, void *ev_data) { + * (void) ev; (void) ev_data; + * mg_printf(nc, "HTTP/1.0 200 OK\r\n\r\n[I am Hello1]"); + * nc->flags |= MG_F_SEND_AND_CLOSE; + * } + * + * static void handle_hello2(struct mg_connection *nc, int ev, void *ev_data) { + * (void) ev; (void) ev_data; + * mg_printf(nc, "HTTP/1.0 200 OK\r\n\r\n[I am Hello2]"); + * nc->flags |= MG_F_SEND_AND_CLOSE; + * } + * + * void init() { + * nc = mg_bind(&mgr, local_addr, cb1); + * mg_register_http_endpoint(nc, "/hello1", handle_hello1); + * mg_register_http_endpoint(nc, "/hello1/hello2", handle_hello2); + * } + * ``` + */ +void mg_register_http_endpoint(struct mg_connection *nc, const char *uri_path, + MG_CB(mg_event_handler_t handler, + void *user_data)); + +/* + * Authenticates a HTTP request against an opened password file. + * Returns 1 if authenticated, 0 otherwise. + */ +int mg_http_check_digest_auth(struct http_message *hm, const char *auth_domain, + FILE *fp); + +/* + * Sends buffer `buf` of size `len` to the client using chunked HTTP encoding. + * This function sends the buffer size as hex number + newline first, then + * the buffer itself, then the newline. For example, + * `mg_send_http_chunk(nc, "foo", 3)` will append the `3\r\nfoo\r\n` string + * to the `nc->send_mbuf` output IO buffer. + * + * NOTE: The HTTP header "Transfer-Encoding: chunked" should be sent prior to + * using this function. + * + * NOTE: do not forget to send an empty chunk at the end of the response, + * to tell the client that everything was sent. Example: + * + * ``` + * mg_printf_http_chunk(nc, "%s", "my response!"); + * mg_send_http_chunk(nc, "", 0); // Tell the client we're finished + * ``` + */ +void mg_send_http_chunk(struct mg_connection *nc, const char *buf, size_t len); + +/* + * Sends a printf-formatted HTTP chunk. + * Functionality is similar to `mg_send_http_chunk()`. + */ +void mg_printf_http_chunk(struct mg_connection *nc, const char *fmt, ...); + +/* + * Sends the response status line. + * If `extra_headers` is not NULL, then `extra_headers` are also sent + * after the response line. `extra_headers` must NOT end end with new line. + * Example: + * + * mg_send_response_line(nc, 200, "Access-Control-Allow-Origin: *"); + * + * Will result in: + * + * HTTP/1.1 200 OK\r\n + * Access-Control-Allow-Origin: *\r\n + */ +void mg_send_response_line(struct mg_connection *nc, int status_code, + const char *extra_headers); + +/* + * Sends an error response. If reason is NULL, the message will be inferred + * from the error code (if supported). + */ +void mg_http_send_error(struct mg_connection *nc, int code, const char *reason); + +/* + * Sends a redirect response. + * `status_code` should be either 301 or 302 and `location` point to the + * new location. + * If `extra_headers` is not empty, then `extra_headers` are also sent + * after the response line. `extra_headers` must NOT end end with new line. + * + * Example: + * + * mg_http_send_redirect(nc, 302, mg_mk_str("/login"), mg_mk_str(NULL)); + */ +void mg_http_send_redirect(struct mg_connection *nc, int status_code, + const struct mg_str location, + const struct mg_str extra_headers); + +/* + * Sends the response line and headers. + * This function sends the response line with the `status_code`, and + * automatically + * sends one header: either "Content-Length" or "Transfer-Encoding". + * If `content_length` is negative, then "Transfer-Encoding: chunked" header + * is sent, otherwise, "Content-Length" header is sent. + * + * NOTE: If `Transfer-Encoding` is `chunked`, then message body must be sent + * using `mg_send_http_chunk()` or `mg_printf_http_chunk()` functions. + * Otherwise, `mg_send()` or `mg_printf()` must be used. + * Extra headers could be set through `extra_headers`. Note `extra_headers` + * must NOT be terminated by a new line. + */ +void mg_send_head(struct mg_connection *n, int status_code, + int64_t content_length, const char *extra_headers); + +/* + * Sends a printf-formatted HTTP chunk, escaping HTML tags. + */ +void mg_printf_html_escape(struct mg_connection *nc, const char *fmt, ...); + +#if MG_ENABLE_HTTP_URL_REWRITES +/* + * Proxies a given request to a given upstream http server. The path prefix + * in `mount` will be stripped of the path requested to the upstream server, + * e.g. if mount is /api and upstream is http://localhost:8001/foo + * then an incoming request to /api/bar will cause a request to + * http://localhost:8001/foo/bar + * + * EXPERIMENTAL API. Please use http_serve_http + url_rewrites if a static + * mapping is good enough. + */ +void mg_http_reverse_proxy(struct mg_connection *nc, + const struct http_message *hm, struct mg_str mount, + struct mg_str upstream); +#endif + +#ifdef __cplusplus +} +#endif /* __cplusplus */ + +#endif /* MG_ENABLE_HTTP */ + +#endif /* CS_MONGOOSE_SRC_HTTP_SERVER_H_ */ +#ifdef MG_MODULE_LINES +#line 1 "mongoose/src/http_client.h" +#endif +/* + * === Client API reference + */ + +#ifndef CS_MONGOOSE_SRC_HTTP_CLIENT_H_ +#define CS_MONGOOSE_SRC_HTTP_CLIENT_H_ + +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + +/* + * Helper function that creates an outbound HTTP connection. + * + * `url` is the URL to fetch. It must be properly URL-encoded, e.g. have + * no spaces, etc. By default, `mg_connect_http()` sends the Connection and + * Host headers. `extra_headers` is an extra HTTP header to send, e.g. + * `"User-Agent: my-app\r\n"`. + * If `post_data` is NULL, then a GET request is created. Otherwise, a POST + * request is created with the specified POST data. Note that if the data being + * posted is a form submission, the `Content-Type` header should be set + * accordingly (see example below). + * + * Examples: + * + * ```c + * nc1 = mg_connect_http(mgr, ev_handler_1, "http://www.google.com", NULL, + * NULL); + * nc2 = mg_connect_http(mgr, ev_handler_1, "https://github.com", NULL, NULL); + * nc3 = mg_connect_http( + * mgr, ev_handler_1, "my_server:8000/form_submit/", + * "Content-Type: application/x-www-form-urlencoded\r\n", + * "var_1=value_1&var_2=value_2"); + * ``` + */ +struct mg_connection *mg_connect_http( + struct mg_mgr *mgr, + MG_CB(mg_event_handler_t event_handler, void *user_data), const char *url, + const char *extra_headers, const char *post_data); + +/* + * Helper function that creates an outbound HTTP connection. + * + * Mostly identical to mg_connect_http, but allows you to provide extra + *parameters + * (for example, SSL parameters) + */ +struct mg_connection *mg_connect_http_opt( + struct mg_mgr *mgr, MG_CB(mg_event_handler_t ev_handler, void *user_data), + struct mg_connect_opts opts, const char *url, const char *extra_headers, + const char *post_data); + +/* Creates digest authentication header for a client request. */ +int mg_http_create_digest_auth_header(char *buf, size_t buf_len, + const char *method, const char *uri, + const char *auth_domain, const char *user, + const char *passwd); + +#ifdef __cplusplus +} +#endif /* __cplusplus */ +#endif /* CS_MONGOOSE_SRC_HTTP_CLIENT_H_ */ +#ifdef MG_MODULE_LINES +#line 1 "mongoose/src/mqtt.h" +#endif +/* + * Copyright (c) 2014 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. + * + * Alternatively, you can license this software under a commercial + * license, as set out in . + */ + +/* + * === MQTT API reference + */ + +#ifndef CS_MONGOOSE_SRC_MQTT_H_ +#define CS_MONGOOSE_SRC_MQTT_H_ + +/* Amalgamated: #include "mongoose/src/net.h" */ + +struct mg_mqtt_message { + int cmd; + int qos; + struct mg_str topic; + struct mg_str payload; + + uint8_t connack_ret_code; /* connack */ + uint16_t message_id; /* puback */ + + /* connect */ + uint8_t protocol_version; + uint8_t connect_flags; + uint16_t keep_alive_timer; + struct mg_str protocol_name; + struct mg_str client_id; + struct mg_str will_topic; + struct mg_str will_message; + struct mg_str user_name; + struct mg_str password; +}; + +struct mg_mqtt_topic_expression { + const char *topic; + uint8_t qos; +}; + +struct mg_send_mqtt_handshake_opts { + unsigned char flags; /* connection flags */ + uint16_t keep_alive; + const char *will_topic; + const char *will_message; + const char *user_name; + const char *password; +}; + +/* mg_mqtt_proto_data should be in header to allow external access to it */ +struct mg_mqtt_proto_data { + uint16_t keep_alive; +}; + +/* Message types */ +#define MG_MQTT_CMD_CONNECT 1 +#define MG_MQTT_CMD_CONNACK 2 +#define MG_MQTT_CMD_PUBLISH 3 +#define MG_MQTT_CMD_PUBACK 4 +#define MG_MQTT_CMD_PUBREC 5 +#define MG_MQTT_CMD_PUBREL 6 +#define MG_MQTT_CMD_PUBCOMP 7 +#define MG_MQTT_CMD_SUBSCRIBE 8 +#define MG_MQTT_CMD_SUBACK 9 +#define MG_MQTT_CMD_UNSUBSCRIBE 10 +#define MG_MQTT_CMD_UNSUBACK 11 +#define MG_MQTT_CMD_PINGREQ 12 +#define MG_MQTT_CMD_PINGRESP 13 +#define MG_MQTT_CMD_DISCONNECT 14 + +/* MQTT event types */ +#define MG_MQTT_EVENT_BASE 200 +#define MG_EV_MQTT_CONNECT (MG_MQTT_EVENT_BASE + MG_MQTT_CMD_CONNECT) +#define MG_EV_MQTT_CONNACK (MG_MQTT_EVENT_BASE + MG_MQTT_CMD_CONNACK) +#define MG_EV_MQTT_PUBLISH (MG_MQTT_EVENT_BASE + MG_MQTT_CMD_PUBLISH) +#define MG_EV_MQTT_PUBACK (MG_MQTT_EVENT_BASE + MG_MQTT_CMD_PUBACK) +#define MG_EV_MQTT_PUBREC (MG_MQTT_EVENT_BASE + MG_MQTT_CMD_PUBREC) +#define MG_EV_MQTT_PUBREL (MG_MQTT_EVENT_BASE + MG_MQTT_CMD_PUBREL) +#define MG_EV_MQTT_PUBCOMP (MG_MQTT_EVENT_BASE + MG_MQTT_CMD_PUBCOMP) +#define MG_EV_MQTT_SUBSCRIBE (MG_MQTT_EVENT_BASE + MG_MQTT_CMD_SUBSCRIBE) +#define MG_EV_MQTT_SUBACK (MG_MQTT_EVENT_BASE + MG_MQTT_CMD_SUBACK) +#define MG_EV_MQTT_UNSUBSCRIBE (MG_MQTT_EVENT_BASE + MG_MQTT_CMD_UNSUBSCRIBE) +#define MG_EV_MQTT_UNSUBACK (MG_MQTT_EVENT_BASE + MG_MQTT_CMD_UNSUBACK) +#define MG_EV_MQTT_PINGREQ (MG_MQTT_EVENT_BASE + MG_MQTT_CMD_PINGREQ) +#define MG_EV_MQTT_PINGRESP (MG_MQTT_EVENT_BASE + MG_MQTT_CMD_PINGRESP) +#define MG_EV_MQTT_DISCONNECT (MG_MQTT_EVENT_BASE + MG_MQTT_CMD_DISCONNECT) + +/* Message flags */ +#define MG_MQTT_RETAIN 0x1 +#define MG_MQTT_DUP 0x4 +#define MG_MQTT_QOS(qos) ((qos) << 1) +#define MG_MQTT_GET_QOS(flags) (((flags) &0x6) >> 1) +#define MG_MQTT_SET_QOS(flags, qos) (flags) = ((flags) & ~0x6) | ((qos) << 1) + +/* Connection flags */ +#define MG_MQTT_CLEAN_SESSION 0x02 +#define MG_MQTT_HAS_WILL 0x04 +#define MG_MQTT_WILL_RETAIN 0x20 +#define MG_MQTT_HAS_PASSWORD 0x40 +#define MG_MQTT_HAS_USER_NAME 0x80 +#define MG_MQTT_GET_WILL_QOS(flags) (((flags) &0x18) >> 3) +#define MG_MQTT_SET_WILL_QOS(flags, qos) \ + (flags) = ((flags) & ~0x18) | ((qos) << 3) + +/* CONNACK return codes */ +#define MG_EV_MQTT_CONNACK_ACCEPTED 0 +#define MG_EV_MQTT_CONNACK_UNACCEPTABLE_VERSION 1 +#define MG_EV_MQTT_CONNACK_IDENTIFIER_REJECTED 2 +#define MG_EV_MQTT_CONNACK_SERVER_UNAVAILABLE 3 +#define MG_EV_MQTT_CONNACK_BAD_AUTH 4 +#define MG_EV_MQTT_CONNACK_NOT_AUTHORIZED 5 + +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + +/* + * Attaches a built-in MQTT event handler to the given connection. + * + * The user-defined event handler will receive following extra events: + * + * - MG_EV_MQTT_CONNACK + * - MG_EV_MQTT_PUBLISH + * - MG_EV_MQTT_PUBACK + * - MG_EV_MQTT_PUBREC + * - MG_EV_MQTT_PUBREL + * - MG_EV_MQTT_PUBCOMP + * - MG_EV_MQTT_SUBACK + */ +void mg_set_protocol_mqtt(struct mg_connection *nc); + +/* Sends an MQTT handshake. */ +void mg_send_mqtt_handshake(struct mg_connection *nc, const char *client_id); + +/* Sends an MQTT handshake with optional parameters. */ +void mg_send_mqtt_handshake_opt(struct mg_connection *nc, const char *client_id, + struct mg_send_mqtt_handshake_opts); + +/* Publishes a message to a given topic. */ +void mg_mqtt_publish(struct mg_connection *nc, const char *topic, + uint16_t message_id, int flags, const void *data, + size_t len); + +/* Subscribes to a bunch of topics. */ +void mg_mqtt_subscribe(struct mg_connection *nc, + const struct mg_mqtt_topic_expression *topics, + size_t topics_len, uint16_t message_id); + +/* Unsubscribes from a bunch of topics. */ +void mg_mqtt_unsubscribe(struct mg_connection *nc, char **topics, + size_t topics_len, uint16_t message_id); + +/* Sends a DISCONNECT command. */ +void mg_mqtt_disconnect(struct mg_connection *nc); + +/* Sends a CONNACK command with a given `return_code`. */ +void mg_mqtt_connack(struct mg_connection *nc, uint8_t return_code); + +/* Sends a PUBACK command with a given `message_id`. */ +void mg_mqtt_puback(struct mg_connection *nc, uint16_t message_id); + +/* Sends a PUBREC command with a given `message_id`. */ +void mg_mqtt_pubrec(struct mg_connection *nc, uint16_t message_id); + +/* Sends a PUBREL command with a given `message_id`. */ +void mg_mqtt_pubrel(struct mg_connection *nc, uint16_t message_id); + +/* Sends a PUBCOMP command with a given `message_id`. */ +void mg_mqtt_pubcomp(struct mg_connection *nc, uint16_t message_id); + +/* + * Sends a SUBACK command with a given `message_id` + * and a sequence of granted QoSs. + */ +void mg_mqtt_suback(struct mg_connection *nc, uint8_t *qoss, size_t qoss_len, + uint16_t message_id); + +/* Sends a UNSUBACK command with a given `message_id`. */ +void mg_mqtt_unsuback(struct mg_connection *nc, uint16_t message_id); + +/* Sends a PINGREQ command. */ +void mg_mqtt_ping(struct mg_connection *nc); + +/* Sends a PINGRESP command. */ +void mg_mqtt_pong(struct mg_connection *nc); + +/* + * Extracts the next topic expression from a SUBSCRIBE command payload. + * + * The topic expression name will point to a string in the payload buffer. + * Returns the pos of the next topic expression or -1 when the list + * of topics is exhausted. + */ +int mg_mqtt_next_subscribe_topic(struct mg_mqtt_message *msg, + struct mg_str *topic, uint8_t *qos, int pos); + +/* + * Matches a topic against a topic expression + * + * Returns 1 if it matches; 0 otherwise. + */ +int mg_mqtt_match_topic_expression(struct mg_str exp, struct mg_str topic); + +/* + * Same as `mg_mqtt_match_topic_expression()`, but takes `exp` as a + * NULL-terminated string. + */ +int mg_mqtt_vmatch_topic_expression(const char *exp, struct mg_str topic); + +#ifdef __cplusplus +} +#endif /* __cplusplus */ + +#endif /* CS_MONGOOSE_SRC_MQTT_H_ */ +#ifdef MG_MODULE_LINES +#line 1 "mongoose/src/mqtt_server.h" +#endif +/* + * Copyright (c) 2014 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. + * + * Alternatively, you can license this software under a commercial + * license, as set out in . + */ + +/* + * === MQTT Server API reference + */ + +#ifndef CS_MONGOOSE_SRC_MQTT_BROKER_H_ +#define CS_MONGOOSE_SRC_MQTT_BROKER_H_ + +#if MG_ENABLE_MQTT_BROKER + +/* Amalgamated: #include "common/queue.h" */ +/* Amalgamated: #include "mongoose/src/mqtt.h" */ + +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + +#define MG_MQTT_MAX_SESSION_SUBSCRIPTIONS 512; + +struct mg_mqtt_broker; + +/* MQTT session (Broker side). */ +struct mg_mqtt_session { + struct mg_mqtt_broker *brk; /* Broker */ + LIST_ENTRY(mg_mqtt_session) link; /* mg_mqtt_broker::sessions linkage */ + struct mg_connection *nc; /* Connection with the client */ + size_t num_subscriptions; /* Size of `subscriptions` array */ + void *user_data; /* User data */ + struct mg_mqtt_topic_expression *subscriptions; +}; + +/* MQTT broker. */ +struct mg_mqtt_broker { + LIST_HEAD(_mg_sesshead, mg_mqtt_session) sessions; /* Session list */ + void *user_data; /* User data */ +}; + +/* Initialises a MQTT broker. */ +void mg_mqtt_broker_init(struct mg_mqtt_broker *brk, void *user_data); + +/* + * Processes a MQTT broker message. + * + * The listening connection expects a pointer to an initialised + * `mg_mqtt_broker` structure in the `user_data` field. + * + * Basic usage: + * + * ```c + * mg_mqtt_broker_init(&brk, NULL); + * + * if ((nc = mg_bind(&mgr, address, mg_mqtt_broker)) == NULL) { + * // fail; + * } + * nc->user_data = &brk; + * ``` + * + * New incoming connections will receive a `mg_mqtt_session` structure + * in the connection `user_data`. The original `user_data` will be stored + * in the `user_data` field of the session structure. This allows the user + * handler to store user data before `mg_mqtt_broker` creates the session. + * + * Since only the MG_EV_ACCEPT message is processed by the listening socket, + * for most events the `user_data` will thus point to a `mg_mqtt_session`. + */ +void mg_mqtt_broker(struct mg_connection *brk, int ev, void *data); + +/* + * Iterates over all MQTT session connections. Example: + * + * ```c + * struct mg_mqtt_session *s; + * for (s = mg_mqtt_next(brk, NULL); s != NULL; s = mg_mqtt_next(brk, s)) { + * // Do something + * } + * ``` + */ +struct mg_mqtt_session *mg_mqtt_next(struct mg_mqtt_broker *brk, + struct mg_mqtt_session *s); + +#ifdef __cplusplus +} +#endif /* __cplusplus */ + +#endif /* MG_ENABLE_MQTT_BROKER */ +#endif /* CS_MONGOOSE_SRC_MQTT_BROKER_H_ */ +#ifdef MG_MODULE_LINES +#line 1 "mongoose/src/dns.h" +#endif +/* + * Copyright (c) 2014 Cesanta Software Limited + * All rights reserved + */ + +/* + * === DNS API reference + */ + +#ifndef CS_MONGOOSE_SRC_DNS_H_ +#define CS_MONGOOSE_SRC_DNS_H_ + +/* Amalgamated: #include "mongoose/src/net.h" */ + +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + +#define MG_DNS_A_RECORD 0x01 /* Lookup IP address */ +#define MG_DNS_CNAME_RECORD 0x05 /* Lookup CNAME */ +#define MG_DNS_PTR_RECORD 0x0c /* Lookup PTR */ +#define MG_DNS_TXT_RECORD 0x10 /* Lookup TXT */ +#define MG_DNS_AAAA_RECORD 0x1c /* Lookup IPv6 address */ +#define MG_DNS_SRV_RECORD 0x21 /* Lookup SRV */ +#define MG_DNS_MX_RECORD 0x0f /* Lookup mail server for domain */ + +#define MG_MAX_DNS_QUESTIONS 32 +#define MG_MAX_DNS_ANSWERS 32 + +#define MG_DNS_MESSAGE 100 /* High-level DNS message event */ + +enum mg_dns_resource_record_kind { + MG_DNS_INVALID_RECORD = 0, + MG_DNS_QUESTION, + MG_DNS_ANSWER +}; + +/* DNS resource record. */ +struct mg_dns_resource_record { + struct mg_str name; /* buffer with compressed name */ + int rtype; + int rclass; + int ttl; + enum mg_dns_resource_record_kind kind; + struct mg_str rdata; /* protocol data (can be a compressed name) */ +}; + +/* DNS message (request and response). */ +struct mg_dns_message { + struct mg_str pkt; /* packet body */ + uint16_t flags; + uint16_t transaction_id; + int num_questions; + int num_answers; + struct mg_dns_resource_record questions[MG_MAX_DNS_QUESTIONS]; + struct mg_dns_resource_record answers[MG_MAX_DNS_ANSWERS]; +}; + +struct mg_dns_resource_record *mg_dns_next_record( + struct mg_dns_message *msg, int query, struct mg_dns_resource_record *prev); + +/* + * Parses the record data from a DNS resource record. + * + * - A: struct in_addr *ina + * - AAAA: struct in6_addr *ina + * - CNAME: char buffer + * + * Returns -1 on error. + * + * TODO(mkm): MX + */ +int mg_dns_parse_record_data(struct mg_dns_message *msg, + struct mg_dns_resource_record *rr, void *data, + size_t data_len); + +/* + * Sends a DNS query to the remote end. + */ +void mg_send_dns_query(struct mg_connection *nc, const char *name, + int query_type); + +/* + * Inserts a DNS header to an IO buffer. + * + * Returns the number of bytes inserted. + */ +int mg_dns_insert_header(struct mbuf *io, size_t pos, + struct mg_dns_message *msg); + +/* + * Appends already encoded questions from an existing message. + * + * This is useful when generating a DNS reply message which includes + * all question records. + * + * Returns the number of appended bytes. + */ +int mg_dns_copy_questions(struct mbuf *io, struct mg_dns_message *msg); + +/* + * Encodes and appends a DNS resource record to an IO buffer. + * + * The record metadata is taken from the `rr` parameter, while the name and data + * are taken from the parameters, encoded in the appropriate format depending on + * record type and stored in the IO buffer. The encoded values might contain + * offsets within the IO buffer. It's thus important that the IO buffer doesn't + * get trimmed while a sequence of records are encoded while preparing a DNS + * reply. + * + * This function doesn't update the `name` and `rdata` pointers in the `rr` + * struct because they might be invalidated as soon as the IO buffer grows + * again. + * + * Returns the number of bytes appended or -1 in case of error. + */ +int mg_dns_encode_record(struct mbuf *io, struct mg_dns_resource_record *rr, + const char *name, size_t nlen, const void *rdata, + size_t rlen); + +/* + * Encodes a DNS name. + */ +int mg_dns_encode_name(struct mbuf *io, const char *name, size_t len); + +/* Low-level: parses a DNS response. */ +int mg_parse_dns(const char *buf, int len, struct mg_dns_message *msg); + +/* + * Uncompresses a DNS compressed name. + * + * The containing DNS message is required because of the compressed encoding + * and reference suffixes present elsewhere in the packet. + * + * If the name is less than `dst_len` characters long, the remainder + * of `dst` is terminated with `\0` characters. Otherwise, `dst` is not + * terminated. + * + * If `dst_len` is 0 `dst` can be NULL. + * Returns the uncompressed name length. + */ +size_t mg_dns_uncompress_name(struct mg_dns_message *msg, struct mg_str *name, + char *dst, int dst_len); + +/* + * Attaches a built-in DNS event handler to the given listening connection. + * + * The DNS event handler parses the incoming UDP packets, treating them as DNS + * requests. If an incoming packet gets successfully parsed by the DNS event + * handler, a user event handler will receive an `MG_DNS_REQUEST` event, with + * `ev_data` pointing to the parsed `struct mg_dns_message`. + * + * See + * [captive_dns_server](https://github.com/cesanta/mongoose/tree/master/examples/captive_dns_server) + * example on how to handle DNS request and send DNS reply. + */ +void mg_set_protocol_dns(struct mg_connection *nc); + +#ifdef __cplusplus +} +#endif /* __cplusplus */ +#endif /* CS_MONGOOSE_SRC_DNS_H_ */ +#ifdef MG_MODULE_LINES +#line 1 "mongoose/src/dns_server.h" +#endif +/* + * Copyright (c) 2014 Cesanta Software Limited + * All rights reserved + */ + +/* + * === DNS server API reference + * + * Disabled by default; enable with `-DMG_ENABLE_DNS_SERVER`. + */ + +#ifndef CS_MONGOOSE_SRC_DNS_SERVER_H_ +#define CS_MONGOOSE_SRC_DNS_SERVER_H_ + +#if MG_ENABLE_DNS_SERVER + +/* Amalgamated: #include "mongoose/src/dns.h" */ + +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + +#define MG_DNS_SERVER_DEFAULT_TTL 3600 + +struct mg_dns_reply { + struct mg_dns_message *msg; + struct mbuf *io; + size_t start; +}; + +/* + * Creates a DNS reply. + * + * The reply will be based on an existing query message `msg`. + * The query body will be appended to the output buffer. + * "reply + recursion allowed" will be added to the message flags and the + * message's num_answers will be set to 0. + * + * Answer records can be appended with `mg_dns_send_reply` or by lower + * level function defined in the DNS API. + * + * In order to send a reply use `mg_dns_send_reply`. + * It's possible to use a connection's send buffer as reply buffer, + * and it will work for both UDP and TCP connections. + * + * Example: + * + * ```c + * reply = mg_dns_create_reply(&nc->send_mbuf, msg); + * for (i = 0; i < msg->num_questions; i++) { + * rr = &msg->questions[i]; + * if (rr->rtype == MG_DNS_A_RECORD) { + * mg_dns_reply_record(&reply, rr, 3600, &dummy_ip_addr, 4); + * } + * } + * mg_dns_send_reply(nc, &reply); + * ``` + */ +struct mg_dns_reply mg_dns_create_reply(struct mbuf *io, + struct mg_dns_message *msg); + +/* + * Appends a DNS reply record to the IO buffer and to the DNS message. + * + * The message's num_answers field will be incremented. It's the caller's duty + * to ensure num_answers is properly initialised. + * + * Returns -1 on error. + */ +int mg_dns_reply_record(struct mg_dns_reply *reply, + struct mg_dns_resource_record *question, + const char *name, int rtype, int ttl, const void *rdata, + size_t rdata_len); + +/* + * Sends a DNS reply through a connection. + * + * The DNS data is stored in an IO buffer pointed by reply structure in `r`. + * This function mutates the content of that buffer in order to ensure that + * the DNS header reflects the size and flags of the message, that might have + * been updated either with `mg_dns_reply_record` or by direct manipulation of + * `r->message`. + * + * Once sent, the IO buffer will be trimmed unless the reply IO buffer + * is the connection's send buffer and the connection is not in UDP mode. + */ +void mg_dns_send_reply(struct mg_connection *nc, struct mg_dns_reply *r); + +#ifdef __cplusplus +} +#endif /* __cplusplus */ + +#endif /* MG_ENABLE_DNS_SERVER */ +#endif /* CS_MONGOOSE_SRC_DNS_SERVER_H_ */ +#ifdef MG_MODULE_LINES +#line 1 "mongoose/src/resolv.h" +#endif +/* + * Copyright (c) 2014 Cesanta Software Limited + * All rights reserved + */ + +/* + * === API reference + */ + +#ifndef CS_MONGOOSE_SRC_RESOLV_H_ +#define CS_MONGOOSE_SRC_RESOLV_H_ + +/* Amalgamated: #include "mongoose/src/dns.h" */ + +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + +enum mg_resolve_err { + MG_RESOLVE_OK = 0, + MG_RESOLVE_NO_ANSWERS = 1, + MG_RESOLVE_EXCEEDED_RETRY_COUNT = 2, + MG_RESOLVE_TIMEOUT = 3 +}; + +typedef void (*mg_resolve_callback_t)(struct mg_dns_message *dns_message, + void *user_data, enum mg_resolve_err); + +/* Options for `mg_resolve_async_opt`. */ +struct mg_resolve_async_opts { + const char *nameserver; + int max_retries; /* defaults to 2 if zero */ + int timeout; /* in seconds; defaults to 5 if zero */ + int accept_literal; /* pseudo-resolve literal ipv4 and ipv6 addrs */ + int only_literal; /* only resolves literal addrs; sync cb invocation */ + struct mg_connection **dns_conn; /* return DNS connection */ +}; + +/* See `mg_resolve_async_opt()` */ +int mg_resolve_async(struct mg_mgr *mgr, const char *name, int query, + mg_resolve_callback_t cb, void *data); + +/* Set default DNS server */ +void mg_set_nameserver(struct mg_mgr *mgr, const char *nameserver); + +/* + * Resolved a DNS name asynchronously. + * + * Upon successful resolution, the user callback will be invoked + * with the full DNS response message and a pointer to the user's + * context `data`. + * + * In case of timeout while performing the resolution the callback + * will receive a NULL `msg`. + * + * The DNS answers can be extracted with `mg_next_record` and + * `mg_dns_parse_record_data`: + * + * [source,c] + * ---- + * struct in_addr ina; + * struct mg_dns_resource_record *rr = mg_next_record(msg, MG_DNS_A_RECORD, + * NULL); + * mg_dns_parse_record_data(msg, rr, &ina, sizeof(ina)); + * ---- + */ +int mg_resolve_async_opt(struct mg_mgr *mgr, const char *name, int query, + mg_resolve_callback_t cb, void *data, + struct mg_resolve_async_opts opts); + +/* + * Resolve a name from `/etc/hosts`. + * + * Returns 0 on success, -1 on failure. + */ +int mg_resolve_from_hosts_file(const char *host, union socket_address *usa); + +#ifdef __cplusplus +} +#endif /* __cplusplus */ +#endif /* CS_MONGOOSE_SRC_RESOLV_H_ */ +#ifdef MG_MODULE_LINES +#line 1 "mongoose/src/coap.h" +#endif +/* + * Copyright (c) 2015 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. + * + * Alternatively, you can license this software under a commercial + * license, as set out in . + */ + +/* + * === CoAP API reference + * + * CoAP message format: + * + * ``` + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+- + * |Ver| T | TKL | Code | Message ID | Token (if any, TKL bytes) ... + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+- + * | Options (if any) ... |1 1 1 1 1 1 1 1| Payload (if any) ... + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+- + * ``` + */ + +#ifndef CS_MONGOOSE_SRC_COAP_H_ +#define CS_MONGOOSE_SRC_COAP_H_ + +#if MG_ENABLE_COAP + +#define MG_COAP_MSG_TYPE_FIELD 0x2 +#define MG_COAP_CODE_CLASS_FIELD 0x4 +#define MG_COAP_CODE_DETAIL_FIELD 0x8 +#define MG_COAP_MSG_ID_FIELD 0x10 +#define MG_COAP_TOKEN_FIELD 0x20 +#define MG_COAP_OPTIOMG_FIELD 0x40 +#define MG_COAP_PAYLOAD_FIELD 0x80 + +#define MG_COAP_ERROR 0x10000 +#define MG_COAP_FORMAT_ERROR (MG_COAP_ERROR | 0x20000) +#define MG_COAP_IGNORE (MG_COAP_ERROR | 0x40000) +#define MG_COAP_NOT_ENOUGH_DATA (MG_COAP_ERROR | 0x80000) +#define MG_COAP_NETWORK_ERROR (MG_COAP_ERROR | 0x100000) + +#define MG_COAP_MSG_CON 0 +#define MG_COAP_MSG_NOC 1 +#define MG_COAP_MSG_ACK 2 +#define MG_COAP_MSG_RST 3 +#define MG_COAP_MSG_MAX 3 + +#define MG_COAP_CODECLASS_REQUEST 0 +#define MG_COAP_CODECLASS_RESP_OK 2 +#define MG_COAP_CODECLASS_CLIENT_ERR 4 +#define MG_COAP_CODECLASS_SRV_ERR 5 + +#define MG_COAP_EVENT_BASE 300 +#define MG_EV_COAP_CON (MG_COAP_EVENT_BASE + MG_COAP_MSG_CON) +#define MG_EV_COAP_NOC (MG_COAP_EVENT_BASE + MG_COAP_MSG_NOC) +#define MG_EV_COAP_ACK (MG_COAP_EVENT_BASE + MG_COAP_MSG_ACK) +#define MG_EV_COAP_RST (MG_COAP_EVENT_BASE + MG_COAP_MSG_RST) + +/* + * CoAP options. + * Use mg_coap_add_option and mg_coap_free_options + * for creation and destruction. + */ +struct mg_coap_option { + struct mg_coap_option *next; + uint32_t number; + struct mg_str value; +}; + +/* CoAP message. See RFC 7252 for details. */ +struct mg_coap_message { + uint32_t flags; + uint8_t msg_type; + uint8_t code_class; + uint8_t code_detail; + uint16_t msg_id; + struct mg_str token; + struct mg_coap_option *options; + struct mg_str payload; + struct mg_coap_option *optiomg_tail; +}; + +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + +/* Sets CoAP protocol handler - triggers CoAP specific events. */ +int mg_set_protocol_coap(struct mg_connection *nc); + +/* + * Adds a new option to mg_coap_message structure. + * Returns pointer to the newly created option. + * Note: options must be freed by using mg_coap_free_options + */ +struct mg_coap_option *mg_coap_add_option(struct mg_coap_message *cm, + uint32_t number, char *value, + size_t len); + +/* + * Frees the memory allocated for options. + * If the cm parameter doesn't contain any option it does nothing. + */ +void mg_coap_free_options(struct mg_coap_message *cm); + +/* + * Composes a CoAP message from `mg_coap_message` + * and sends it into `nc` connection. + * Returns 0 on success. On error, it is a bitmask: + * + * - `#define MG_COAP_ERROR 0x10000` + * - `#define MG_COAP_FORMAT_ERROR (MG_COAP_ERROR | 0x20000)` + * - `#define MG_COAP_IGNORE (MG_COAP_ERROR | 0x40000)` + * - `#define MG_COAP_NOT_ENOUGH_DATA (MG_COAP_ERROR | 0x80000)` + * - `#define MG_COAP_NETWORK_ERROR (MG_COAP_ERROR | 0x100000)` + */ +uint32_t mg_coap_send_message(struct mg_connection *nc, + struct mg_coap_message *cm); + +/* + * Composes CoAP acknowledgement from `mg_coap_message` + * and sends it into `nc` connection. + * Return value: see `mg_coap_send_message()` + */ +uint32_t mg_coap_send_ack(struct mg_connection *nc, uint16_t msg_id); + +/* + * Parses CoAP message and fills mg_coap_message and returns cm->flags. + * This is a helper function. + * + * NOTE: usually CoAP works over UDP, so lack of data means format error. + * But, in theory, it is possible to use CoAP over TCP (according to RFC) + * + * The caller has to check results and treat COAP_NOT_ENOUGH_DATA according to + * underlying protocol: + * + * - in case of UDP COAP_NOT_ENOUGH_DATA means COAP_FORMAT_ERROR, + * - in case of TCP client can try to receive more data + * + * Return value: see `mg_coap_send_message()` + */ +uint32_t mg_coap_parse(struct mbuf *io, struct mg_coap_message *cm); + +/* + * Composes CoAP message from mg_coap_message structure. + * This is a helper function. + * Return value: see `mg_coap_send_message()` + */ +uint32_t mg_coap_compose(struct mg_coap_message *cm, struct mbuf *io); + +#ifdef __cplusplus +} +#endif /* __cplusplus */ + +#endif /* MG_ENABLE_COAP */ + +#endif /* CS_MONGOOSE_SRC_COAP_H_ */ +#ifdef MG_MODULE_LINES +#line 1 "mongoose/src/sntp.h" +#endif +/* + * Copyright (c) 2016 Cesanta Software Limited + * All rights reserved + */ + +#ifndef CS_MONGOOSE_SRC_SNTP_H_ +#define CS_MONGOOSE_SRC_SNTP_H_ + +#if MG_ENABLE_SNTP + +#define MG_SNTP_EVENT_BASE 500 + +/* + * Received reply from time server. Event handler parameter contains + * pointer to mg_sntp_message structure + */ +#define MG_SNTP_REPLY (MG_SNTP_EVENT_BASE + 1) + +/* Received malformed SNTP packet */ +#define MG_SNTP_MALFORMED_REPLY (MG_SNTP_EVENT_BASE + 2) + +/* Failed to get time from server (timeout etc) */ +#define MG_SNTP_FAILED (MG_SNTP_EVENT_BASE + 3) + +struct mg_sntp_message { + /* if server sends this flags, user should not send requests to it */ + int kiss_of_death; + /* usual mg_time */ + double time; +}; + +/* Establishes connection to given sntp server */ +struct mg_connection *mg_sntp_connect(struct mg_mgr *mgr, + MG_CB(mg_event_handler_t event_handler, + void *user_data), + const char *sntp_server_name); + +/* Sends time request to given connection */ +void mg_sntp_send_request(struct mg_connection *c); + +/* + * Helper function + * Establishes connection to time server, tries to send request + * repeats sending SNTP_ATTEMPTS times every SNTP_TIMEOUT sec + * (if needed) + * See sntp_client example + */ +struct mg_connection *mg_sntp_get_time(struct mg_mgr *mgr, + mg_event_handler_t event_handler, + const char *sntp_server_name); + +#endif + +#endif /* CS_MONGOOSE_SRC_SNTP_H_ */ From 8ce34af9f375ed082120b489394ac32c63832c5c Mon Sep 17 00:00:00 2001 From: Sergey Lyubka Date: Tue, 11 Apr 2017 00:53:39 +0100 Subject: [PATCH 046/137] Clean send_mbuf in mg_if_sent_cb, fix hexdump PUBLISHED_FROM=3d222e548a3323b957376666e6702b408843b5a3 --- mongoose.c | 103 +++++++++++++++++++++++++++-------------------------- 1 file changed, 52 insertions(+), 51 deletions(-) diff --git a/mongoose.c b/mongoose.c index 32fe0d70..aa3d0b40 100644 --- a/mongoose.c +++ b/mongoose.c @@ -2042,14 +2042,9 @@ MG_INTERNAL void mg_call(struct mg_connection *nc, #if !defined(NO_LIBC) && MG_ENABLE_HEXDUMP /* LCOV_EXCL_START */ - if (nc->mgr->hexdump_file != NULL && ev != MG_EV_POLL && + if (nc->mgr->hexdump_file != NULL && ev != MG_EV_POLL && ev != MG_EV_RECV && ev != MG_EV_SEND /* handled separately */) { - if (ev == MG_EV_RECV) { - mg_hexdump_connection(nc, nc->mgr->hexdump_file, nc->recv_mbuf.buf, - *(int *) ev_data, ev); - } else { - mg_hexdump_connection(nc, nc->mgr->hexdump_file, NULL, 0, ev); - } + mg_hexdump_connection(nc, nc->mgr->hexdump_file, NULL, 0, ev); } /* LCOV_EXCL_STOP */ #endif @@ -2480,16 +2475,20 @@ void mg_send(struct mg_connection *nc, const void *buf, int len) { } else { nc->iface->vtable->tcp_send(nc, buf, 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_SEND); - } -#endif } void mg_if_sent_cb(struct mg_connection *nc, int 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); } @@ -2497,6 +2496,13 @@ void mg_if_sent_cb(struct mg_connection *nc, int num_sent) { 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)); /* @@ -3134,17 +3140,16 @@ void mg_set_non_blocking_mode(sock_t sock) { #endif } -static int mg_is_error(int n) { +static int mg_is_error(void) { int err = mg_get_errno(); - return (n < 0 && err != EINPROGRESS && err != EWOULDBLOCK + return err != EINPROGRESS && err != EWOULDBLOCK #ifndef WINCE - && err != EAGAIN && err != EINTR + && err != EAGAIN && err != EINTR #endif #ifdef _WIN32 - && WSAGetLastError() != WSAEINTR && - WSAGetLastError() != WSAEWOULDBLOCK + && WSAGetLastError() != WSAEINTR && WSAGetLastError() != WSAEWOULDBLOCK #endif - ); + ; } void mg_socket_if_connect_tcp(struct mg_connection *nc, @@ -3159,7 +3164,7 @@ void mg_socket_if_connect_tcp(struct mg_connection *nc, mg_set_non_blocking_mode(nc->sock); #endif rc = connect(nc->sock, &sa->sa, sizeof(sa->sin)); - nc->err = mg_is_error(rc) ? mg_get_errno() : 0; + nc->err = rc < 0 && mg_is_error() ? mg_get_errno() : 0; DBG(("%p sock %d rc %d errno %d err %d", nc, nc->sock, rc, mg_get_errno(), nc->err)); } @@ -3235,7 +3240,7 @@ 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(-1)) 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); @@ -3320,10 +3325,7 @@ static void mg_write_to_socket(struct mg_connection *nc) { 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))); - if (n > 0) { - mbuf_remove(io, n); - mg_if_sent_cb(nc, n); - } + mg_if_sent_cb(nc, n); return; } @@ -3350,17 +3352,9 @@ static void mg_write_to_socket(struct mg_connection *nc) { { n = (int) MG_SEND_FUNC(nc->sock, io->buf, io->len, 0); DBG(("%p %d bytes -> %d", nc, n, nc->sock)); - if (n < 0 && mg_is_error(n)) { - /* Something went wrong, drop the connection. */ - nc->flags |= MG_F_CLOSE_IMMEDIATELY; - return; - } } - if (n > 0) { - mbuf_remove(io, n); - mg_if_sent_cb(nc, n); - } + mg_if_sent_cb(nc, n); } MG_INTERNAL size_t recv_avail_size(struct mg_connection *conn, size_t max) { @@ -3415,7 +3409,7 @@ static void mg_handle_tcp_read(struct mg_connection *conn) { if (n == 0) { /* Orderly shutdown of the socket, try flushing output. */ conn->flags |= MG_F_SEND_AND_CLOSE; - } else if (mg_is_error(n)) { + } else if (n < 0 && mg_is_error()) { conn->flags |= MG_F_CLOSE_IMMEDIATELY; } } @@ -9549,6 +9543,25 @@ void mg_hexdump_connection(struct mg_connection *nc, const char *path, FILE *fp = NULL; char *hexbuf, src[60], dst[60]; int buf_size = num_bytes * 5 + 100; + const char *tag = NULL; + switch (ev) { + case MG_EV_RECV: + tag = "<-"; + break; + case MG_EV_SEND: + tag = "->"; + break; + case MG_EV_ACCEPT: + tag = "" - : ev == MG_EV_ACCEPT - ? "" : "XX", - dst, num_bytes); + fprintf(fp, "%lu %p %s %s %s %d\n", (unsigned long) mg_time(), (void *) nc, + src, tag, dst, num_bytes); if (num_bytes > 0 && (hexbuf = (char *) MG_MALLOC(buf_size)) != NULL) { mg_hexdump(buf, num_bytes, hexbuf, buf_size); fprintf(fp, "%s", hexbuf); @@ -11991,7 +11998,7 @@ static void mg_get_ntp_ts(const char *ntp, uint64_t *val) { } void mg_sntp_send_request(struct mg_connection *c) { - char buf[48] = {0}; + uint8_t buf[48] = {0}; /* * header - 8 bit: * LI (2 bit) - 3 (not in sync), VN (3 bit) - 4 (version), @@ -13373,7 +13380,6 @@ static void mg_write_to_socket(struct mg_connection *nc) { } if (n > 0) { - mbuf_remove(io, n); mg_if_sent_cb(nc, n); } else if (n < 0 && mg_is_error(n)) { /* Something went wrong, drop the connection. */ @@ -14399,8 +14405,6 @@ static void mg_lwip_send_more(struct mg_connection *nc) { if (num_written < 0) { mg_lwip_post_signal(MG_SIG_CLOSE_CONN, nc); } - mbuf_remove(&nc->send_mbuf, num_written); - mbuf_trim(&nc->send_mbuf); } void mg_lwip_if_tcp_send(struct mg_connection *nc, const void *buf, @@ -14639,7 +14643,7 @@ void mg_ev_mgr_lwip_process_signals(struct mg_mgr *mgr) { break; } case MG_SIG_SENT_CB: { - if (cs->num_sent > 0) mg_if_sent_cb(nc, cs->num_sent); + mg_if_sent_cb(nc, cs->num_sent); cs->num_sent = 0; if (nc->send_mbuf.len == 0 && (nc->flags & MG_F_SEND_AND_CLOSE) && @@ -15268,10 +15272,7 @@ static void mg_handle_send(struct mg_connection *nc) { } } - if (bytes_written != 0) { - mbuf_remove(&nc->send_mbuf, bytes_written); - mg_if_sent_cb(nc, bytes_written); - } + mg_if_sent_cb(nc, bytes_written); } static void mg_handle_recv(struct mg_connection *nc) { From 7f259f2a79d8e1c613e015b867ff19102f103573 Mon Sep 17 00:00:00 2001 From: Deomid Ryabkov Date: Tue, 11 Apr 2017 11:32:19 +0100 Subject: [PATCH 047/137] Add optional digest auth to mOS HTTP server If http.auth_{domain,file} are configured, all HTTP requests require valid digest authorization header. This applies to files served by mg_http_serve as well as synamic endpoints such as /update and /rpc. mongoose-os#229 PUBLISHED_FROM=824d594147cfeb2428b463d24478b207839aa5e2 --- mongoose.c | 620 +++++++++++++++++++++++++++++------------------------ mongoose.h | 183 ++++++++-------- 2 files changed, 430 insertions(+), 373 deletions(-) diff --git a/mongoose.c b/mongoose.c index aa3d0b40..7cc9bb57 100644 --- a/mongoose.c +++ b/mongoose.c @@ -777,7 +777,7 @@ double cs_time(void) { #endif /* CS_COMMON_CS_ENDIAN_H_ */ #ifdef MG_MODULE_LINES -#line 1 "common/md5.c" +#line 1 "common/cs_md5.c" #endif /* * This code implements the MD5 message-digest algorithm. @@ -796,7 +796,7 @@ double cs_time(void) { * will fill a supplied 16-byte array with the digest. */ -/* Amalgamated: #include "common/md5.h" */ +/* Amalgamated: #include "common/cs_md5.h" */ /* Amalgamated: #include "common/str_util.h" */ #if !defined(EXCLUDE_COMMON) @@ -831,7 +831,7 @@ static void byteReverse(unsigned char *buf, unsigned longs) { * Start MD5 accumulation. Set bit count to 0 and buffer to mysterious * initialization constants. */ -void MD5_Init(MD5_CTX *ctx) { +void cs_md5_init(cs_md5_ctx *ctx) { ctx->buf[0] = 0x67452301; ctx->buf[1] = 0xefcdab89; ctx->buf[2] = 0x98badcfe; @@ -841,7 +841,7 @@ void MD5_Init(MD5_CTX *ctx) { ctx->bits[1] = 0; } -static void MD5Transform(uint32_t buf[4], uint32_t const in[16]) { +static void cs_md5_transform(uint32_t buf[4], uint32_t const in[16]) { register uint32_t a, b, c, d; a = buf[0]; @@ -923,7 +923,7 @@ static void MD5Transform(uint32_t buf[4], uint32_t const in[16]) { buf[3] += d; } -void MD5_Update(MD5_CTX *ctx, const unsigned char *buf, size_t len) { +void cs_md5_update(cs_md5_ctx *ctx, const unsigned char *buf, size_t len) { uint32_t t; t = ctx->bits[0]; @@ -942,7 +942,7 @@ void MD5_Update(MD5_CTX *ctx, const unsigned char *buf, size_t len) { } memcpy(p, buf, t); byteReverse(ctx->in, 16); - MD5Transform(ctx->buf, (uint32_t *) ctx->in); + cs_md5_transform(ctx->buf, (uint32_t *) ctx->in); buf += t; len -= t; } @@ -950,7 +950,7 @@ void MD5_Update(MD5_CTX *ctx, const unsigned char *buf, size_t len) { while (len >= 64) { memcpy(ctx->in, buf, 64); byteReverse(ctx->in, 16); - MD5Transform(ctx->buf, (uint32_t *) ctx->in); + cs_md5_transform(ctx->buf, (uint32_t *) ctx->in); buf += 64; len -= 64; } @@ -958,7 +958,7 @@ void MD5_Update(MD5_CTX *ctx, const unsigned char *buf, size_t len) { memcpy(ctx->in, buf, len); } -void MD5_Final(unsigned char digest[16], MD5_CTX *ctx) { +void cs_md5_final(unsigned char digest[16], cs_md5_ctx *ctx) { unsigned count; unsigned char *p; uint32_t *a; @@ -971,7 +971,7 @@ void MD5_Final(unsigned char digest[16], MD5_CTX *ctx) { if (count < 8) { memset(p, 0, count); byteReverse(ctx->in, 16); - MD5Transform(ctx->buf, (uint32_t *) ctx->in); + cs_md5_transform(ctx->buf, (uint32_t *) ctx->in); memset(ctx->in, 0, 56); } else { memset(p, 0, count - 8); @@ -982,234 +982,21 @@ void MD5_Final(unsigned char digest[16], MD5_CTX *ctx) { a[14] = ctx->bits[0]; a[15] = ctx->bits[1]; - MD5Transform(ctx->buf, (uint32_t *) ctx->in); + cs_md5_transform(ctx->buf, (uint32_t *) ctx->in); byteReverse((unsigned char *) ctx->buf, 4); memcpy(digest, ctx->buf, 16); memset((char *) ctx, 0, sizeof(*ctx)); } -char *cs_md5(char buf[33], ...) { - unsigned char hash[16]; - const unsigned char *p; - va_list ap; - MD5_CTX ctx; - - MD5_Init(&ctx); - - va_start(ap, buf); - while ((p = va_arg(ap, const unsigned char *) ) != NULL) { - size_t len = va_arg(ap, size_t); - MD5_Update(&ctx, p, len); - } - va_end(ap); - - MD5_Final(hash, &ctx); - cs_to_hex(buf, hash, sizeof(hash)); - - return buf; -} - #endif /* CS_DISABLE_MD5 */ #endif /* EXCLUDE_COMMON */ #ifdef MG_MODULE_LINES -#line 1 "common/mbuf.c" -#endif -/* - * Copyright (c) 2014 Cesanta Software Limited - * All rights reserved - */ - -#ifndef EXCLUDE_COMMON - -#include -#include -/* Amalgamated: #include "common/mbuf.h" */ - -#ifndef MBUF_REALLOC -#define MBUF_REALLOC realloc -#endif - -#ifndef MBUF_FREE -#define MBUF_FREE free -#endif - -void mbuf_init(struct mbuf *mbuf, size_t initial_size) WEAK; -void mbuf_init(struct mbuf *mbuf, size_t initial_size) { - mbuf->len = mbuf->size = 0; - mbuf->buf = NULL; - mbuf_resize(mbuf, initial_size); -} - -void mbuf_free(struct mbuf *mbuf) WEAK; -void mbuf_free(struct mbuf *mbuf) { - if (mbuf->buf != NULL) { - MBUF_FREE(mbuf->buf); - mbuf_init(mbuf, 0); - } -} - -void mbuf_resize(struct mbuf *a, size_t new_size) WEAK; -void mbuf_resize(struct mbuf *a, size_t new_size) { - if (new_size > a->size || (new_size < a->size && new_size >= a->len)) { - char *buf = (char *) MBUF_REALLOC(a->buf, new_size); - /* - * In case realloc fails, there's not much we can do, except keep things as - * they are. Note that NULL is a valid return value from realloc when - * size == 0, but that is covered too. - */ - if (buf == NULL && new_size != 0) return; - a->buf = buf; - a->size = new_size; - } -} - -void mbuf_trim(struct mbuf *mbuf) WEAK; -void mbuf_trim(struct mbuf *mbuf) { - mbuf_resize(mbuf, mbuf->len); -} - -size_t mbuf_insert(struct mbuf *a, size_t off, const void *buf, size_t) WEAK; -size_t mbuf_insert(struct mbuf *a, size_t off, const void *buf, size_t len) { - char *p = NULL; - - assert(a != NULL); - assert(a->len <= a->size); - assert(off <= a->len); - - /* check overflow */ - if (~(size_t) 0 - (size_t) a->buf < len) return 0; - - if (a->len + len <= a->size) { - memmove(a->buf + off + len, a->buf + off, a->len - off); - if (buf != NULL) { - memcpy(a->buf + off, buf, 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) { - a->buf = p; - 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; - } else { - len = 0; - } - } - - return len; -} - -size_t mbuf_append(struct mbuf *a, const void *buf, size_t len) WEAK; -size_t mbuf_append(struct mbuf *a, const void *buf, size_t len) { - return mbuf_insert(a, a->len, buf, len); -} - -void mbuf_remove(struct mbuf *mb, size_t n) WEAK; -void mbuf_remove(struct mbuf *mb, size_t n) { - if (n > 0 && n <= mb->len) { - memmove(mb->buf, mb->buf + n, mb->len - n); - mb->len -= n; - } -} - -#endif /* EXCLUDE_COMMON */ -#ifdef MG_MODULE_LINES -#line 1 "common/mg_str.c" -#endif -/* - * Copyright (c) 2014-2016 Cesanta Software Limited - * All rights reserved - */ - -/* Amalgamated: #include "common/mg_mem.h" */ -/* Amalgamated: #include "common/mg_str.h" */ - -#include -#include - -int mg_ncasecmp(const char *s1, const char *s2, size_t len) WEAK; - -struct mg_str mg_mk_str(const char *s) WEAK; -struct mg_str mg_mk_str(const char *s) { - struct mg_str ret = {s, 0}; - if (s != NULL) ret.len = strlen(s); - return ret; -} - -struct mg_str mg_mk_str_n(const char *s, size_t len) WEAK; -struct mg_str mg_mk_str_n(const char *s, size_t len) { - struct mg_str ret = {s, len}; - return ret; -} - -int mg_vcmp(const struct mg_str *str1, const char *str2) WEAK; -int mg_vcmp(const struct mg_str *str1, const char *str2) { - size_t n2 = strlen(str2), n1 = str1->len; - int r = strncmp(str1->p, str2, (n1 < n2) ? n1 : n2); - if (r == 0) { - return n1 - n2; - } - return r; -} - -int mg_vcasecmp(const struct mg_str *str1, const char *str2) WEAK; -int mg_vcasecmp(const struct mg_str *str1, const char *str2) { - size_t n2 = strlen(str2), n1 = str1->len; - int r = mg_ncasecmp(str1->p, str2, (n1 < n2) ? n1 : n2); - if (r == 0) { - return n1 - n2; - } - return r; -} - -struct mg_str mg_strdup(const struct mg_str s) WEAK; -struct mg_str mg_strdup(const struct mg_str s) { - struct mg_str r = {NULL, 0}; - if (s.len > 0 && s.p != NULL) { - r.p = (char *) MG_MALLOC(s.len); - if (r.p != NULL) { - memcpy((char *) r.p, s.p, s.len); - r.len = s.len; - } - } - return r; -} - -int mg_strcmp(const struct mg_str str1, const struct mg_str str2) WEAK; -int mg_strcmp(const struct mg_str str1, const struct mg_str str2) { - size_t i = 0; - while (i < str1.len && i < str2.len) { - if (str1.p[i] < str2.p[i]) return -1; - if (str1.p[i] > str2.p[i]) return 1; - i++; - } - if (i < str1.len) return 1; - if (i < str2.len) return -1; - return 0; -} - -int mg_strncmp(const struct mg_str, const struct mg_str, size_t n) WEAK; -int mg_strncmp(const struct mg_str str1, const struct mg_str str2, size_t n) { - struct mg_str s1 = str1; - struct mg_str s2 = str2; - - if (s1.len > n) { - s1.len = n; - } - if (s2.len > n) { - s2.len = n; - } - return mg_strcmp(s1, s2); -} -#ifdef MG_MODULE_LINES -#line 1 "common/sha1.c" +#line 1 "common/cs_sha1.c" #endif /* Copyright(c) By Steve Reid */ /* 100% Public Domain */ -/* Amalgamated: #include "common/sha1.h" */ +/* Amalgamated: #include "common/cs_sha1.h" */ #if !CS_DISABLE_SHA1 && !defined(EXCLUDE_COMMON) @@ -1460,6 +1247,198 @@ void cs_hmac_sha1(const unsigned char *key, size_t keylen, #endif /* EXCLUDE_COMMON */ #ifdef MG_MODULE_LINES +#line 1 "common/mbuf.c" +#endif +/* + * Copyright (c) 2014 Cesanta Software Limited + * All rights reserved + */ + +#ifndef EXCLUDE_COMMON + +#include +#include +/* Amalgamated: #include "common/mbuf.h" */ + +#ifndef MBUF_REALLOC +#define MBUF_REALLOC realloc +#endif + +#ifndef MBUF_FREE +#define MBUF_FREE free +#endif + +void mbuf_init(struct mbuf *mbuf, size_t initial_size) WEAK; +void mbuf_init(struct mbuf *mbuf, size_t initial_size) { + mbuf->len = mbuf->size = 0; + mbuf->buf = NULL; + mbuf_resize(mbuf, initial_size); +} + +void mbuf_free(struct mbuf *mbuf) WEAK; +void mbuf_free(struct mbuf *mbuf) { + if (mbuf->buf != NULL) { + MBUF_FREE(mbuf->buf); + mbuf_init(mbuf, 0); + } +} + +void mbuf_resize(struct mbuf *a, size_t new_size) WEAK; +void mbuf_resize(struct mbuf *a, size_t new_size) { + if (new_size > a->size || (new_size < a->size && new_size >= a->len)) { + char *buf = (char *) MBUF_REALLOC(a->buf, new_size); + /* + * In case realloc fails, there's not much we can do, except keep things as + * they are. Note that NULL is a valid return value from realloc when + * size == 0, but that is covered too. + */ + if (buf == NULL && new_size != 0) return; + a->buf = buf; + a->size = new_size; + } +} + +void mbuf_trim(struct mbuf *mbuf) WEAK; +void mbuf_trim(struct mbuf *mbuf) { + mbuf_resize(mbuf, mbuf->len); +} + +size_t mbuf_insert(struct mbuf *a, size_t off, const void *buf, size_t) WEAK; +size_t mbuf_insert(struct mbuf *a, size_t off, const void *buf, size_t len) { + char *p = NULL; + + assert(a != NULL); + assert(a->len <= a->size); + assert(off <= a->len); + + /* check overflow */ + if (~(size_t) 0 - (size_t) a->buf < len) return 0; + + if (a->len + len <= a->size) { + memmove(a->buf + off + len, a->buf + off, a->len - off); + if (buf != NULL) { + memcpy(a->buf + off, buf, 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) { + a->buf = p; + 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; + } else { + len = 0; + } + } + + return len; +} + +size_t mbuf_append(struct mbuf *a, const void *buf, size_t len) WEAK; +size_t mbuf_append(struct mbuf *a, const void *buf, size_t len) { + return mbuf_insert(a, a->len, buf, len); +} + +void mbuf_remove(struct mbuf *mb, size_t n) WEAK; +void mbuf_remove(struct mbuf *mb, size_t n) { + if (n > 0 && n <= mb->len) { + memmove(mb->buf, mb->buf + n, mb->len - n); + mb->len -= n; + } +} + +#endif /* EXCLUDE_COMMON */ +#ifdef MG_MODULE_LINES +#line 1 "common/mg_str.c" +#endif +/* + * Copyright (c) 2014-2016 Cesanta Software Limited + * All rights reserved + */ + +/* Amalgamated: #include "common/mg_mem.h" */ +/* Amalgamated: #include "common/mg_str.h" */ + +#include +#include + +int mg_ncasecmp(const char *s1, const char *s2, size_t len) WEAK; + +struct mg_str mg_mk_str(const char *s) WEAK; +struct mg_str mg_mk_str(const char *s) { + struct mg_str ret = {s, 0}; + if (s != NULL) ret.len = strlen(s); + return ret; +} + +struct mg_str mg_mk_str_n(const char *s, size_t len) WEAK; +struct mg_str mg_mk_str_n(const char *s, size_t len) { + struct mg_str ret = {s, len}; + return ret; +} + +int mg_vcmp(const struct mg_str *str1, const char *str2) WEAK; +int mg_vcmp(const struct mg_str *str1, const char *str2) { + size_t n2 = strlen(str2), n1 = str1->len; + int r = strncmp(str1->p, str2, (n1 < n2) ? n1 : n2); + if (r == 0) { + return n1 - n2; + } + return r; +} + +int mg_vcasecmp(const struct mg_str *str1, const char *str2) WEAK; +int mg_vcasecmp(const struct mg_str *str1, const char *str2) { + size_t n2 = strlen(str2), n1 = str1->len; + int r = mg_ncasecmp(str1->p, str2, (n1 < n2) ? n1 : n2); + if (r == 0) { + return n1 - n2; + } + return r; +} + +struct mg_str mg_strdup(const struct mg_str s) WEAK; +struct mg_str mg_strdup(const struct mg_str s) { + struct mg_str r = {NULL, 0}; + if (s.len > 0 && s.p != NULL) { + r.p = (char *) MG_MALLOC(s.len); + if (r.p != NULL) { + memcpy((char *) r.p, s.p, s.len); + r.len = s.len; + } + } + return r; +} + +int mg_strcmp(const struct mg_str str1, const struct mg_str str2) WEAK; +int mg_strcmp(const struct mg_str str1, const struct mg_str str2) { + size_t i = 0; + while (i < str1.len && i < str2.len) { + if (str1.p[i] < str2.p[i]) return -1; + if (str1.p[i] > str2.p[i]) return 1; + i++; + } + if (i < str1.len) return 1; + if (i < str2.len) return -1; + return 0; +} + +int mg_strncmp(const struct mg_str, const struct mg_str, size_t n) WEAK; +int mg_strncmp(const struct mg_str str1, const struct mg_str str2, size_t n) { + struct mg_str s1 = str1; + struct mg_str s2 = str2; + + if (s1.len > n) { + s1.len = n; + } + if (s2.len > n) { + s2.len = n; + } + return mg_strcmp(s1, s2); +} +#ifdef MG_MODULE_LINES #line 1 "common/str_util.c" #endif /* @@ -5032,7 +5011,6 @@ int mg_normalize_uri_path(const struct mg_str *in, struct mg_str *out) { #if MG_ENABLE_HTTP /* Amalgamated: #include "common/md5.h" */ -/* Amalgamated: #include "common/sha1.h" */ /* Amalgamated: #include "mongoose/src/internal.h" */ /* Amalgamated: #include "mongoose/src/util.h" */ @@ -5060,8 +5038,10 @@ struct mg_http_proto_data_chuncked { struct mg_http_endpoint { struct mg_http_endpoint *next; - const char *name; - size_t name_len; + struct mg_str uri_pattern; /* owned */ + char *auth_domain; /* owned */ + char *auth_file; /* owned */ + mg_event_handler_t handler; #if MG_ENABLE_CALLBACK_USERDATA void *user_data; @@ -5151,7 +5131,9 @@ static void mg_http_free_proto_data_endpoints(struct mg_http_endpoint **ep) { while (current != NULL) { struct mg_http_endpoint *tmp = current->next; - MG_FREE((void *) current->name); + MG_FREE((void *) current->uri_pattern.p); + MG_FREE((void *) current->auth_domain); + MG_FREE((void *) current->auth_file); MG_FREE(current); current = tmp; } @@ -5583,8 +5565,7 @@ struct mg_http_endpoint *mg_http_get_endpoint_handler(struct mg_connection *nc, ep = pd->endpoints; while (ep != NULL) { - const struct mg_str name_s = {ep->name, ep->name_len}; - if ((matched = mg_match_prefix_n(name_s, *uri_path)) != -1) { + if ((matched = mg_match_prefix_n(ep->uri_pattern, *uri_path)) != -1) { if (matched > matched_max) { /* Looking for the longest suitable handler */ ret = ep; @@ -5598,25 +5579,6 @@ struct mg_http_endpoint *mg_http_get_endpoint_handler(struct mg_connection *nc, return ret; } -static void mg_http_call_endpoint_handler(struct mg_connection *nc, int ev, - struct http_message *hm) { - struct mg_http_proto_data *pd = mg_http_get_proto_data(nc); - void *user_data = nc->user_data; - - if (ev == MG_EV_HTTP_REQUEST) { - struct mg_http_endpoint *ep = - mg_http_get_endpoint_handler(nc->listener, &hm->uri); - if (ep != NULL) { - pd->endpoint_handler = ep->handler; -#if MG_ENABLE_CALLBACK_USERDATA - user_data = ep->user_data; -#endif - } - } - mg_call(nc, pd->endpoint_handler ? pd->endpoint_handler : nc->handler, - user_data, ev, hm); -} - #if MG_ENABLE_HTTP_STREAMING_MULTIPART static void mg_http_multipart_continue(struct mg_connection *nc); @@ -5625,6 +5587,9 @@ static void mg_http_multipart_begin(struct mg_connection *nc, #endif +static void mg_http_call_endpoint_handler(struct mg_connection *nc, int ev, + struct http_message *hm); + /* * lx106 compiler has a bug (TODO(mkm) report and insert tracking bug here) * If a big structure is declared in a big function, lx106 gcc will make it @@ -6691,6 +6656,42 @@ static int mg_is_file_hidden(const char *path, } #if !MG_DISABLE_HTTP_DIGEST_AUTH + +#ifndef MG_EXT_MD5 +void mg_hash_md5_v(size_t num_msgs, const uint8_t *msgs[], + const size_t *msg_lens, uint8_t *digest) { + size_t i; + cs_md5_ctx md5_ctx; + cs_md5_init(&md5_ctx); + for (i = 0; i < num_msgs; i++) { + cs_md5_update(&md5_ctx, msgs[i], msg_lens[i]); + } + cs_md5_final(digest, &md5_ctx); +} +#else +extern void mg_hash_md5_v(size_t num_msgs, const uint8_t *msgs[], + const size_t *msg_lens, uint8_t *digest); +#endif + +void cs_md5(char buf[33], ...) { + unsigned char hash[16]; + const uint8_t *msgs[20], *p; + size_t msg_lens[20]; + size_t num_msgs = 0; + va_list ap; + + va_start(ap, buf); + while ((p = va_arg(ap, const unsigned char *) ) != NULL) { + msgs[num_msgs] = p; + msg_lens[num_msgs] = va_arg(ap, size_t); + num_msgs++; + } + va_end(ap); + + mg_hash_md5_v(num_msgs, msgs, msg_lens, hash); + cs_to_hex(buf, hash, sizeof(hash)); +} + static void mg_mkmd5resp(const char *method, size_t method_len, const char *uri, size_t uri_len, const char *ha1, size_t ha1_len, const char *nonce, size_t nonce_len, const char *nc, @@ -6699,7 +6700,6 @@ static void mg_mkmd5resp(const char *method, size_t method_len, const char *uri, static const char colon[] = ":"; static const size_t one = 1; char ha2[33]; - cs_md5(ha2, method, method_len, colon, one, uri, uri_len, NULL); cs_md5(resp, ha1, ha1_len, colon, one, nonce, nonce_len, colon, one, nc, nc_len, colon, one, cnonce, cnonce_len, colon, one, qop, qop_len, @@ -6744,7 +6744,7 @@ int mg_http_check_digest_auth(struct http_message *hm, const char *auth_domain, FILE *fp) { struct mg_str *hdr; char buf[128], f_user[sizeof(buf)], f_ha1[sizeof(buf)], f_domain[sizeof(buf)]; - char user[50], cnonce[33], response[40], uri[200], qop[20], nc[20], nonce[30]; + char user[50], cnonce[64], response[40], uri[200], qop[20], nc[20], nonce[30]; char expected_response[33]; /* Parse "Authorization:" header, fail fast on parse error */ @@ -6777,6 +6777,8 @@ int mg_http_check_digest_auth(struct http_message *hm, const char *auth_domain, hm->uri.len + (hm->query_string.len ? hm->query_string.len + 1 : 0), f_ha1, strlen(f_ha1), nonce, strlen(nonce), nc, strlen(nc), cnonce, strlen(cnonce), qop, strlen(qop), expected_response); + LOG(LL_DEBUG, + ("%s %s %s %s", user, f_domain, response, expected_response)); return mg_casecmp(response, expected_response) == 0; } } @@ -6785,10 +6787,10 @@ int mg_http_check_digest_auth(struct http_message *hm, const char *auth_domain, return 0; } -static int mg_is_authorized(struct http_message *hm, const char *path, - int is_directory, const char *domain, - const char *passwords_file, - int is_global_pass_file) { +static int mg_http_is_authorized(struct http_message *hm, struct mg_str path, + int is_directory, const char *domain, + const char *passwords_file, + int is_global_pass_file) { char buf[MG_MAX_PATH]; const char *p; FILE *fp; @@ -6798,12 +6800,13 @@ static int mg_is_authorized(struct http_message *hm, const char *path, if (is_global_pass_file) { fp = mg_fopen(passwords_file, "r"); } else if (is_directory) { - snprintf(buf, sizeof(buf), "%s%c%s", path, DIRSEP, passwords_file); + snprintf(buf, sizeof(buf), "%.*s%c%s", (int) path.len, path.p, DIRSEP, + passwords_file); fp = mg_fopen(buf, "r"); } else { - p = strrchr(path, DIRSEP); - if (p == NULL) p = path; - snprintf(buf, sizeof(buf), "%.*s%c%s", (int) (p - path), path, DIRSEP, + p = strrchr(path.p, DIRSEP); + if (p == NULL) p = path.p; + snprintf(buf, sizeof(buf), "%.*s%c%s", (int) (p - path.p), path.p, DIRSEP, passwords_file); fp = mg_fopen(buf, "r"); } @@ -6814,15 +6817,16 @@ static int mg_is_authorized(struct http_message *hm, const char *path, } } - LOG(LL_DEBUG, ("%s '%s' %d %d", path, passwords_file ? passwords_file : "", - is_global_pass_file, authorized)); + LOG(LL_DEBUG, + ("%.*s %s %d %d", (int) path.len, path.p, + passwords_file ? passwords_file : "", is_global_pass_file, authorized)); return authorized; } #else -static int mg_is_authorized(struct http_message *hm, const char *path, - int is_directory, const char *domain, - const char *passwords_file, - int is_global_pass_file) { +static int mg_http_is_authorized(struct http_message *hm, + const struct mg_str path, int is_directory, + const char *domain, const char *passwords_file, + int is_global_pass_file) { (void) hm; (void) path; (void) is_directory; @@ -7169,7 +7173,7 @@ static int mg_http_handle_forwarding(struct mg_connection *nc, return 0; } -#endif +#endif /* MG_ENABLE_FILESYSTEM */ MG_INTERNAL int mg_uri_to_local_path(struct http_message *hm, const struct mg_serve_http_opts *opts, @@ -7453,10 +7457,12 @@ MG_INTERNAL void mg_send_http_file(struct mg_connection *nc, char *path, if (is_dav && opts->dav_document_root == NULL) { mg_http_send_error(nc, 501, NULL); - } else if (!mg_is_authorized(hm, path, is_directory, opts->auth_domain, - opts->global_auth_file, 1) || - !mg_is_authorized(hm, path, is_directory, opts->auth_domain, - opts->per_directory_auth_file, 0)) { + } else if (!mg_http_is_authorized(hm, mg_mk_str(path), is_directory, + opts->auth_domain, opts->global_auth_file, + 1) || + !mg_http_is_authorized(hm, mg_mk_str(path), is_directory, + opts->auth_domain, + opts->per_directory_auth_file, 0)) { mg_http_send_digest_auth_request(nc, opts->auth_domain); } else if (is_cgi) { #if MG_ENABLE_HTTP_CGI @@ -7472,11 +7478,11 @@ MG_INTERNAL void mg_send_http_file(struct mg_connection *nc, char *path, } else if (!mg_vcmp(&hm->method, "PROPFIND")) { mg_handle_propfind(nc, path, &st, hm, opts); #if !MG_DISABLE_DAV_AUTH - } else if (is_dav && - (opts->dav_auth_file == NULL || - (strcmp(opts->dav_auth_file, "-") != 0 && - !mg_is_authorized(hm, path, is_directory, opts->auth_domain, - opts->dav_auth_file, 1)))) { + } else if (is_dav && (opts->dav_auth_file == NULL || + (strcmp(opts->dav_auth_file, "-") != 0 && + !mg_http_is_authorized(hm, mg_mk_str(path), + is_directory, opts->auth_domain, + opts->dav_auth_file, 1)))) { mg_http_send_digest_auth_request(nc, opts->auth_domain); #endif } else if (!mg_vcmp(&hm->method, "MKCOL")) { @@ -7910,9 +7916,10 @@ size_t mg_parse_multipart(const char *buf, size_t buf_len, char *var_name, return 0; } -void mg_register_http_endpoint(struct mg_connection *nc, const char *uri_path, - MG_CB(mg_event_handler_t handler, - void *user_data)) { +void mg_register_http_endpoint_opt(struct mg_connection *nc, + const char *uri_path, + mg_event_handler_t handler, + struct mg_http_endpoint_opts opts) { struct mg_http_proto_data *pd = NULL; struct mg_http_endpoint *new_ep = NULL; @@ -7921,16 +7928,57 @@ void mg_register_http_endpoint(struct mg_connection *nc, const char *uri_path, if (new_ep == NULL) return; pd = mg_http_get_proto_data(nc); - new_ep->name = strdup(uri_path); - new_ep->name_len = strlen(new_ep->name); + new_ep->uri_pattern = mg_strdup(mg_mk_str(uri_path)); + if (opts.auth_domain != NULL && opts.auth_file != NULL) { + new_ep->auth_domain = strdup(opts.auth_domain); + new_ep->auth_file = strdup(opts.auth_file); + } new_ep->handler = handler; #if MG_ENABLE_CALLBACK_USERDATA - new_ep->user_data = user_data; + new_ep->user_data = opts.user_data; #endif new_ep->next = pd->endpoints; pd->endpoints = new_ep; } +static void mg_http_call_endpoint_handler(struct mg_connection *nc, int ev, + struct http_message *hm) { + struct mg_http_proto_data *pd = mg_http_get_proto_data(nc); + void *user_data = nc->user_data; + + if (ev == MG_EV_HTTP_REQUEST) { + struct mg_http_endpoint *ep = + mg_http_get_endpoint_handler(nc->listener, &hm->uri); + if (ep != NULL) { +#if MG_ENABLE_FILESYSTEM && !MG_DISABLE_HTTP_DIGEST_AUTH + if (!mg_http_is_authorized(hm, hm->uri, 0 /* is_directory */, + ep->auth_domain, ep->auth_file, + 1 /* is_global_pass_file */)) { + mg_http_send_digest_auth_request(nc, ep->auth_domain); + return; + } +#endif + pd->endpoint_handler = ep->handler; +#if MG_ENABLE_CALLBACK_USERDATA + user_data = ep->user_data; +#endif + } + } + mg_call(nc, pd->endpoint_handler ? pd->endpoint_handler : nc->handler, + user_data, ev, hm); +} + +void mg_register_http_endpoint(struct mg_connection *nc, const char *uri_path, + MG_CB(mg_event_handler_t handler, + void *user_data)) { + struct mg_http_endpoint_opts opts; + memset(&opts, 0, sizeof(opts)); +#if MG_ENABLE_CALLBACK_USERDATA + opts.user_data = user_data; +#endif + mg_register_http_endpoint_opt(nc, uri_path, handler, opts); +} + #endif /* MG_ENABLE_HTTP */ #ifdef MG_MODULE_LINES #line 1 "mongoose/src/http_cgi.c" @@ -8919,6 +8967,8 @@ MG_INTERNAL void mg_handle_put(struct mg_connection *nc, const char *path, #if MG_ENABLE_HTTP && MG_ENABLE_HTTP_WEBSOCKET +/* Amalgamated: #include "common/sha1.h" */ + #ifndef MG_WEBSOCKET_PING_INTERVAL_SECONDS #define MG_WEBSOCKET_PING_INTERVAL_SECONDS 5 #endif @@ -9187,8 +9237,8 @@ MG_INTERNAL void mg_ws_handler(struct mg_connection *nc, int ev, } #ifndef MG_EXT_SHA1 -static void mg_hash_sha1_v(size_t num_msgs, const uint8_t *msgs[], - const size_t *msg_lens, uint8_t *digest) { +void mg_hash_sha1_v(size_t num_msgs, const uint8_t *msgs[], + const size_t *msg_lens, uint8_t *digest) { size_t i; cs_sha1_ctx sha_ctx; cs_sha1_init(&sha_ctx); @@ -9650,7 +9700,7 @@ int mg_match_prefix_n(const struct mg_str pattern, const struct mg_str str) { return j == str.len ? (int) j : -1; } else if (pattern.p[i] == '*') { i++; - if (pattern.p[i] == '*') { + if (i < pattern.len && pattern.p[i] == '*') { i++; len = str.len - j; } else { diff --git a/mongoose.h b/mongoose.h index 6dbe7659..f6e1743e 100644 --- a/mongoose.h +++ b/mongoose.h @@ -1629,6 +1629,84 @@ void mg_lwip_set_keepalive_params(struct mg_connection *nc, int idle, #endif /* CS_COMMON_PLATFORMS_LWIP_MG_LWIP_H_ */ #ifdef MG_MODULE_LINES +#line 1 "common/cs_md5.h" +#endif +/* + * Copyright (c) 2014 Cesanta Software Limited + * All rights reserved + */ + +#ifndef CS_COMMON_MD5_H_ +#define CS_COMMON_MD5_H_ + +/* Amalgamated: #include "common/platform.h" */ + +#ifndef CS_DISABLE_MD5 +#define CS_DISABLE_MD5 0 +#endif + +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + +typedef struct { + uint32_t buf[4]; + uint32_t bits[2]; + unsigned char in[64]; +} cs_md5_ctx; + +void cs_md5_init(cs_md5_ctx *c); +void cs_md5_update(cs_md5_ctx *c, const unsigned char *data, size_t len); +void cs_md5_final(unsigned char *md, cs_md5_ctx *c); + +#ifdef __cplusplus +} +#endif /* __cplusplus */ + +#endif /* CS_COMMON_MD5_H_ */ +#ifdef MG_MODULE_LINES +#line 1 "common/cs_sha1.h" +#endif +/* + * Copyright (c) 2014 Cesanta Software Limited + * All rights reserved + */ + +#ifndef CS_COMMON_SHA1_H_ +#define CS_COMMON_SHA1_H_ + +#ifndef CS_DISABLE_SHA1 +#define CS_DISABLE_SHA1 0 +#endif + +#if !CS_DISABLE_SHA1 + +/* Amalgamated: #include "common/platform.h" */ + +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + +typedef struct { + uint32_t state[5]; + uint32_t count[2]; + unsigned char buffer[64]; +} cs_sha1_ctx; + +void cs_sha1_init(cs_sha1_ctx *); +void cs_sha1_update(cs_sha1_ctx *, const unsigned char *data, uint32_t len); +void cs_sha1_final(unsigned char digest[20], cs_sha1_ctx *); +void cs_hmac_sha1(const unsigned char *key, size_t key_len, + const unsigned char *text, size_t text_len, + unsigned char out[20]); +#ifdef __cplusplus +} +#endif /* __cplusplus */ + +#endif /* CS_DISABLE_SHA1 */ + +#endif /* CS_COMMON_SHA1_H_ */ +#ifdef MG_MODULE_LINES #line 1 "common/cs_time.h" #endif /* @@ -1793,94 +1871,6 @@ void mbuf_trim(struct mbuf *); #endif /* CS_COMMON_MBUF_H_ */ #ifdef MG_MODULE_LINES -#line 1 "common/sha1.h" -#endif -/* - * Copyright (c) 2014 Cesanta Software Limited - * All rights reserved - */ - -#ifndef CS_COMMON_SHA1_H_ -#define CS_COMMON_SHA1_H_ - -#ifndef CS_DISABLE_SHA1 -#define CS_DISABLE_SHA1 0 -#endif - -#if !CS_DISABLE_SHA1 - -/* Amalgamated: #include "common/platform.h" */ - -#ifdef __cplusplus -extern "C" { -#endif /* __cplusplus */ - -typedef struct { - uint32_t state[5]; - uint32_t count[2]; - unsigned char buffer[64]; -} cs_sha1_ctx; - -void cs_sha1_init(cs_sha1_ctx *); -void cs_sha1_update(cs_sha1_ctx *, const unsigned char *data, uint32_t len); -void cs_sha1_final(unsigned char digest[20], cs_sha1_ctx *); -void cs_hmac_sha1(const unsigned char *key, size_t key_len, - const unsigned char *text, size_t text_len, - unsigned char out[20]); -#ifdef __cplusplus -} -#endif /* __cplusplus */ - -#endif /* CS_DISABLE_SHA1 */ - -#endif /* CS_COMMON_SHA1_H_ */ -#ifdef MG_MODULE_LINES -#line 1 "common/md5.h" -#endif -/* - * Copyright (c) 2014 Cesanta Software Limited - * All rights reserved - */ - -#ifndef CS_COMMON_MD5_H_ -#define CS_COMMON_MD5_H_ - -/* Amalgamated: #include "common/platform.h" */ - -#ifndef CS_DISABLE_MD5 -#define CS_DISABLE_MD5 0 -#endif - -#ifdef __cplusplus -extern "C" { -#endif /* __cplusplus */ - -typedef struct MD5Context { - uint32_t buf[4]; - uint32_t bits[2]; - unsigned char in[64]; -} MD5_CTX; - -void MD5_Init(MD5_CTX *c); -void MD5_Update(MD5_CTX *c, const unsigned char *data, size_t len); -void MD5_Final(unsigned char *md, MD5_CTX *c); - -/* - * Return stringified MD5 hash for NULL terminated list of pointer/length pairs. - * A length should be specified as size_t variable. - * Example: - * - * char buf[33]; - * cs_md5(buf, "foo", (size_t) 3, "bar", (size_t) 3, NULL); - */ -char *cs_md5(char buf[33], ...); - -#ifdef __cplusplus -} -#endif /* __cplusplus */ - -#endif /* CS_COMMON_MD5_H_ */ -#ifdef MG_MODULE_LINES #line 1 "common/base64.h" #endif /* @@ -4394,6 +4384,11 @@ void mg_printf_websocket_frame(struct mg_connection *nc, int op_and_flags, int mg_url_decode(const char *src, int src_len, char *dst, int dst_len, int is_form_url_encoded); +extern void mg_hash_md5_v(size_t num_msgs, const uint8_t *msgs[], + const size_t *msg_lens, uint8_t *digest); +extern void mg_hash_sha1_v(size_t num_msgs, const uint8_t *msgs[], + const size_t *msg_lens, uint8_t *digest); + #ifdef __cplusplus } #endif /* __cplusplus */ @@ -4805,6 +4800,18 @@ void mg_register_http_endpoint(struct mg_connection *nc, const char *uri_path, MG_CB(mg_event_handler_t handler, void *user_data)); +struct mg_http_endpoint_opts { + void *user_data; + /* Authorization domain (realm) */ + const char *auth_domain; + const char *auth_file; +}; + +void mg_register_http_endpoint_opt(struct mg_connection *nc, + const char *uri_path, + mg_event_handler_t handler, + struct mg_http_endpoint_opts opts); + /* * Authenticates a HTTP request against an opened password file. * Returns 1 if authenticated, 0 otherwise. From a07fb2be510e71ec8a51d2ba8ebf753dc6d64e8f Mon Sep 17 00:00:00 2001 From: Deomid Ryabkov Date: Tue, 11 Apr 2017 16:40:46 +0100 Subject: [PATCH 048/137] Log DNS failures in mOS To aid disagnosing cases like https://forum.cesanta.com/index.php?p=/discussion/397/retries-connecting-to-aws-broker PUBLISHED_FROM=98680b594dbed42234fc53050c9df292feb32f35 --- mongoose.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/mongoose.c b/mongoose.c index 7cc9bb57..8c8a6349 100644 --- a/mongoose.c +++ b/mongoose.c @@ -11001,6 +11001,11 @@ static void mg_resolve_async_eh(struct mg_connection *nc, int ev, case MG_EV_CLOSE: /* If we got here with request still not done, fire an error callback. */ if (req != NULL) { + char addr[32]; + mg_sock_addr_to_str(&nc->sa, addr, sizeof(addr), MG_SOCK_STRINGIFY_IP); +#ifdef MG_LOG_DNS_FAILURES + LOG(LL_ERROR, ("Failed to resolve '%s', server %s", req->name, addr)); +#endif req->callback(NULL, req->data, req->err); nc->user_data = NULL; MG_FREE(req); From b2e2ad9a459522611620f33899a337d8d2fbf3a5 Mon Sep 17 00:00:00 2001 From: Deomid Ryabkov Date: Wed, 12 Apr 2017 16:43:11 +0100 Subject: [PATCH 049/137] Fix hexdump on ESP8266, deliver MG_EV_SEND [...] [...] after handing data off to LWIP, do not wait for ACK. We don't do it in net_if_socket, don't do it here either. Also prevents multiple send attempt on the same send_mbuf data. PUBLISHED_FROM=4e5a677ebda84af1514f34299e53ce856a537883 --- mongoose.c | 132 +++++++++++++++++++++++------------------------------ 1 file changed, 58 insertions(+), 74 deletions(-) diff --git a/mongoose.c b/mongoose.c index 8c8a6349..1521e747 100644 --- a/mongoose.c +++ b/mongoose.c @@ -2020,12 +2020,10 @@ MG_INTERNAL void mg_call(struct mg_connection *nc, } #if !defined(NO_LIBC) && MG_ENABLE_HEXDUMP - /* LCOV_EXCL_START */ if (nc->mgr->hexdump_file != NULL && ev != MG_EV_POLL && ev != MG_EV_RECV && ev != MG_EV_SEND /* handled separately */) { mg_hexdump_connection(nc, nc->mgr->hexdump_file, NULL, 0, ev); } -/* LCOV_EXCL_STOP */ #endif if (ev_handler != NULL) { unsigned long flags_before = nc->flags; @@ -9591,8 +9589,7 @@ void mg_hexdumpf(FILE *fp, const void *buf, int len) { void mg_hexdump_connection(struct mg_connection *nc, const char *path, const void *buf, int num_bytes, int ev) { FILE *fp = NULL; - char *hexbuf, src[60], dst[60]; - int buf_size = num_bytes * 5 + 100; + char src[60], dst[60]; const char *tag = NULL; switch (ev) { case MG_EV_RECV: @@ -9630,13 +9627,11 @@ void mg_hexdump_connection(struct mg_connection *nc, const char *path, MG_SOCK_STRINGIFY_PORT | MG_SOCK_STRINGIFY_REMOTE); fprintf(fp, "%lu %p %s %s %s %d\n", (unsigned long) mg_time(), (void *) nc, - src, tag, dst, num_bytes); - if (num_bytes > 0 && (hexbuf = (char *) MG_MALLOC(buf_size)) != NULL) { - mg_hexdump(buf, num_bytes, hexbuf, buf_size); - fprintf(fp, "%s", hexbuf); - MG_FREE(hexbuf); + src, tag, dst, (int) num_bytes); + if (num_bytes > 0) { + mg_hexdumpf(fp, buf, num_bytes); } - if (fp != stdin && fp != stdout) fclose(fp); + if (fp != stdout && fp != stderr) fclose(fp); } #endif @@ -13983,10 +13978,9 @@ struct mg_lwip_conn_state { enum mg_sig_type { MG_SIG_CONNECT_RESULT = 1, MG_SIG_RECV = 2, - MG_SIG_SENT_CB = 3, - MG_SIG_CLOSE_CONN = 4, - MG_SIG_TOMBSTONE = 5, - MG_SIG_ACCEPT = 6, + MG_SIG_CLOSE_CONN = 3, + MG_SIG_TOMBSTONE = 4, + MG_SIG_ACCEPT = 5, }; void mg_lwip_post_signal(enum mg_sig_type sig, struct mg_connection *nc); @@ -14206,14 +14200,10 @@ static err_t mg_lwip_tcp_sent_cb(void *arg, struct tcp_pcb *tpcb, u16_t num_sent) { struct mg_connection *nc = (struct mg_connection *) arg; DBG(("%p %p %u", nc, tpcb, num_sent)); - if (nc == NULL) { - tcp_abort(tpcb); - return ERR_ABRT; + if ((nc->flags & MG_F_SEND_AND_CLOSE) && !(nc->flags & MG_F_WANT_WRITE) && + nc->send_mbuf.len == 0 && tpcb->unacked == 0) { + mg_lwip_post_signal(MG_SIG_CLOSE_CONN, nc); } - struct mg_lwip_conn_state *cs = (struct mg_lwip_conn_state *) nc->sock; - cs->num_sent += num_sent; - - mg_lwip_post_signal(MG_SIG_SENT_CB, nc); return ERR_OK; } @@ -14436,28 +14426,59 @@ int mg_lwip_tcp_write(struct mg_connection *nc, const void *data, len = MIN(len, (TCP_MSS - tpcb->unsent->len)); } #endif - err_t err = tcp_write(tpcb, data, len, TCP_WRITE_FLAG_COPY); - DBG(("%p tcp_write %u = %d", tpcb, len, err)); - if (err != ERR_OK) { + cs->err = tcp_write(tpcb, data, len, TCP_WRITE_FLAG_COPY); + DBG(("%p tcp_write %u = %d", tpcb, len, cs->err)); + if (cs->err != ERR_OK) { /* * We ignore ERR_MEM because memory will be freed up when the data is sent * and we'll retry. */ - return (err == ERR_MEM ? 0 : -1); + return (cs->err == ERR_MEM ? 0 : -1); } return len; } -static void mg_lwip_send_more(struct mg_connection *nc) { +static int mg_lwip_udp_send(struct mg_connection *nc, const void *data, + uint16_t len) { 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 (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; } - int num_written = 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_written)); - if (num_written == 0) return; - if (num_written < 0) { + struct udp_pcb *upcb = cs->pcb.udp; + struct pbuf *p = pbuf_alloc(PBUF_TRANSPORT, len, PBUF_RAM); + ip_addr_t *ip = (ip_addr_t *) &nc->sa.sin.sin_addr.s_addr; + u16_t port = ntohs(nc->sa.sin.sin_port); + if (p == NULL) { + DBG(("OOM")); + return 0; + } + memcpy(p->payload, data, len); + cs->err = udp_sendto(upcb, p, (ip_addr_t *) ip, port); + DBG(("%p udp_sendto = %d", nc, cs->err)); + pbuf_free(p); + return (cs->err == ERR_OK ? len : -1); +} + +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)); + } + 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); } } @@ -14470,34 +14491,8 @@ void mg_lwip_if_tcp_send(struct mg_connection *nc, const void *buf, void mg_lwip_if_udp_send(struct mg_connection *nc, const void *buf, size_t len) { - struct mg_lwip_conn_state *cs = (struct mg_lwip_conn_state *) nc->sock; - if (nc->sock == INVALID_SOCKET || 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; - } - struct udp_pcb *upcb = cs->pcb.udp; - struct pbuf *p = pbuf_alloc(PBUF_TRANSPORT, len, PBUF_RAM); - ip_addr_t *ip = (ip_addr_t *) &nc->sa.sin.sin_addr.s_addr; - u16_t port = ntohs(nc->sa.sin.sin_port); - if (p == NULL) { - DBG(("OOM")); - return; - } - memcpy(p->payload, buf, len); - cs->err = udp_sendto(upcb, p, (ip_addr_t *) ip, port); - DBG(("%p udp_sendto = %d", nc, cs->err)); - pbuf_free(p); - if (cs->err != ERR_OK) { - mg_lwip_post_signal(MG_SIG_CLOSE_CONN, nc); - } else { - cs->num_sent += len; - mg_lwip_post_signal(MG_SIG_SENT_CB, nc); - } + mbuf_append(&nc->send_mbuf, buf, len); + mg_lwip_mgr_schedule_poll(nc->mgr); } void mg_lwip_if_recved(struct mg_connection *nc, size_t len) { @@ -14697,17 +14692,6 @@ void mg_ev_mgr_lwip_process_signals(struct mg_mgr *mgr) { } break; } - case MG_SIG_SENT_CB: { - mg_if_sent_cb(nc, cs->num_sent); - cs->num_sent = 0; - - if (nc->send_mbuf.len == 0 && (nc->flags & MG_F_SEND_AND_CLOSE) && - !(nc->flags & MG_F_WANT_WRITE)) { - mg_close_conn(nc); - } - - break; - } case MG_SIG_TOMBSTONE: { break; } @@ -14791,8 +14775,8 @@ time_t mg_lwip_if_poll(struct mg_iface *iface, int timeout_ms) { } else #endif /* MG_ENABLE_SSL */ { - if (!(nc->flags & (MG_F_CONNECTING | MG_F_UDP))) { - if (nc->send_mbuf.len > 0) mg_lwip_send_more(nc); + if (nc->send_mbuf.len > 0 && !(nc->flags & MG_F_CONNECTING)) { + mg_lwip_send_more(nc); } } if (nc->sock != INVALID_SOCKET && From f9596cc1db51e76e563cd6811af8b2e1cfd32d99 Mon Sep 17 00:00:00 2001 From: Deomid Ryabkov Date: Wed, 12 Apr 2017 17:47:57 +0100 Subject: [PATCH 050/137] Perform endpoint auth check on multipart requests https://github.com/cesanta/mongoose-os/issues/229#issuecomment-293613426 PUBLISHED_FROM=1c34db7ab2598eca1db0266cc6cdd31c32a16fff --- mongoose.c | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) diff --git a/mongoose.c b/mongoose.c index 1521e747..316de629 100644 --- a/mongoose.c +++ b/mongoose.c @@ -5824,7 +5824,6 @@ static void mg_http_multipart_begin(struct mg_connection *nc, struct mg_http_proto_data *pd = mg_http_get_proto_data(nc); struct mg_str *ct; struct mbuf *io = &nc->recv_mbuf; - void *user_data = nc->user_data; char boundary[100]; int boundary_len; @@ -5871,13 +5870,9 @@ static void mg_http_multipart_begin(struct mg_connection *nc, ep = mg_http_get_endpoint_handler(nc->listener, &hm->uri); if (ep != NULL) { pd->endpoint_handler = ep->handler; -#if MG_ENABLE_CALLBACK_USERDATA - user_data = ep->user_data; -#endif } - mg_call(nc, pd->endpoint_handler, user_data, MG_EV_HTTP_MULTIPART_REQUEST, - hm); + mg_http_call_endpoint_handler(nc, MG_EV_HTTP_MULTIPART_REQUEST, hm); mbuf_remove(io, req_len); } @@ -7944,7 +7939,11 @@ static void mg_http_call_endpoint_handler(struct mg_connection *nc, int ev, struct mg_http_proto_data *pd = mg_http_get_proto_data(nc); void *user_data = nc->user_data; - if (ev == MG_EV_HTTP_REQUEST) { + if (ev == MG_EV_HTTP_REQUEST +#if MG_ENABLE_HTTP_STREAMING_MULTIPART + || ev == MG_EV_HTTP_MULTIPART_REQUEST +#endif + ) { struct mg_http_endpoint *ep = mg_http_get_endpoint_handler(nc->listener, &hm->uri); if (ep != NULL) { From 8354319e72c264850bf10a7798f6fcd6a85bfe53 Mon Sep 17 00:00:00 2001 From: Ruslan Valiullin Date: Fri, 14 Apr 2017 17:42:10 +0500 Subject: [PATCH 051/137] websocket_chat added MG_EV_HTTP_REQUEST PUBLISHED_FROM=6f5e1b4a97ada21025f892d3348808bffb469dfa --- examples/websocket_chat/Makefile | 2 +- examples/websocket_chat/websocket_chat.c | 7 +++++++ 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/examples/websocket_chat/Makefile b/examples/websocket_chat/Makefile index b6244834..2fbb6947 100644 --- a/examples/websocket_chat/Makefile +++ b/examples/websocket_chat/Makefile @@ -1,3 +1,3 @@ PROG = websocket_chat -MODULE_CFLAGS = -DMG_ENABLE_FILESYSTEM=0 +MODULE_CFLAGS = -DMG_ENABLE_FILESYSTEM=1 include ../examples.mk diff --git a/examples/websocket_chat/websocket_chat.c b/examples/websocket_chat/websocket_chat.c index 3d2ad611..265ea079 100644 --- a/examples/websocket_chat/websocket_chat.c +++ b/examples/websocket_chat/websocket_chat.c @@ -7,6 +7,7 @@ static sig_atomic_t s_signal_received = 0; static const char *s_http_port = "8000"; +static struct mg_serve_http_opts s_http_server_opts; static void signal_handler(int sig_num) { signal(sig_num, signal_handler); // Reinstantiate signal handler @@ -46,6 +47,10 @@ static void ev_handler(struct mg_connection *nc, int ev, void *ev_data) { broadcast(nc, d); break; } + case MG_EV_HTTP_REQUEST: { + mg_serve_http(nc, (struct http_message *) ev_data, s_http_server_opts); + break; + } case MG_EV_CLOSE: { /* Disconnect. Tell everybody. */ if (is_websocket(nc)) { @@ -69,6 +74,8 @@ int main(void) { nc = mg_bind(&mgr, s_http_port, ev_handler); mg_set_protocol_http_websocket(nc); + s_http_server_opts.document_root = "."; // Serve current directory + s_http_server_opts.enable_directory_listing = "yes"; printf("Started on port %s\n", s_http_port); while (s_signal_received == 0) { From 69266555138ceddd8ad5ba5fa8e308c67422c727 Mon Sep 17 00:00:00 2001 From: Ruslan Valiullin Date: Sat, 15 Apr 2017 07:31:37 +0100 Subject: [PATCH 052/137] add to cgi doc note about zombies PUBLISHED_FROM=fb1796f11a595befd160bd5ab1088b6e39f16757 --- docs/http/cgi.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/docs/http/cgi.md b/docs/http/cgi.md index 8e2309db..c667fec4 100644 --- a/docs/http/cgi.md +++ b/docs/http/cgi.md @@ -29,3 +29,7 @@ Example: ```c opts.cgi_interpreter = "C:\\ruby\\ruby.exe"; ``` +NOTE: In the CGI handler we don't use explicitly a system call waitpid() for +reaping zombie processes. Instead, we set the SIGCHLD handler to SIG_IGN. +It will cause zombie processes to be reaped automatically. +CAUTION: not all OSes (e.g. QNX) reap zombies if SIGCHLD is ignored. \ No newline at end of file From 57e32b87c7d273c881fb4cff679215978899ee0a Mon Sep 17 00:00:00 2001 From: Deomid Ryabkov Date: Mon, 17 Apr 2017 08:13:20 +0100 Subject: [PATCH 053/137] Fix MQTT will_message length calculation PUBLISHED_FROM=d2400f6ef4837411586fb27db0b1fa03d94283c6 --- mongoose.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mongoose.c b/mongoose.c index 316de629..7840a264 100644 --- a/mongoose.c +++ b/mongoose.c @@ -10011,7 +10011,7 @@ void mg_send_mqtt_handshake_opt(struct mg_connection *nc, const char *client_id, rem_len += 2 + hlen; hlen = strlen(opts.will_message); - nlen = htons((uint16_t) nlen); + nlen = htons((uint16_t) hlen); mg_send(nc, &nlen, 2); mg_send(nc, opts.will_message, hlen); rem_len += 2 + hlen; From 1cee8a16b9669b64cd19905850556eaf281a54e8 Mon Sep 17 00:00:00 2001 From: Deomid Ryabkov Date: Tue, 18 Apr 2017 13:26:46 +0100 Subject: [PATCH 054/137] Fix mg_socket_if_get_conn_addr for UDP sockets Remote address is not associated with an outgoing UDP socket. Instead, it is stored in mg_connection.sa PUBLISHED_FROM=16f82ee8a69b995d684ec96b8db6b5591cd400db --- mongoose.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/mongoose.c b/mongoose.c index 7840a264..7c40cb9c 100644 --- a/mongoose.c +++ b/mongoose.c @@ -3792,6 +3792,10 @@ void mg_sock_to_str(sock_t sock, char *buf, size_t len, int flags) { void mg_socket_if_get_conn_addr(struct mg_connection *nc, int remote, union socket_address *sa) { + if ((nc->flags & MG_F_UDP) && remote) { + memcpy(sa, &nc->sa, sizeof(*sa)); + return; + } mg_sock_get_addr(nc->sock, remote, sa); } From 84907d5bc4a940133d4a45971e48662d448e5394 Mon Sep 17 00:00:00 2001 From: Deomid Ryabkov Date: Tue, 18 Apr 2017 15:20:46 +0100 Subject: [PATCH 055/137] Ignore tcp sent cb when there's no asscociated nc TCP ACK may arrive after the we've corresponding mg_connection has already been closed. Fixes cesanta/mongoose-os#235 PUBLISHED_FROM=8164b86131ef08c1b2a6a08630920d600b3f91ac --- mongoose.c | 1 + 1 file changed, 1 insertion(+) diff --git a/mongoose.c b/mongoose.c index 7c40cb9c..928f1107 100644 --- a/mongoose.c +++ b/mongoose.c @@ -14203,6 +14203,7 @@ static err_t mg_lwip_tcp_sent_cb(void *arg, struct tcp_pcb *tpcb, u16_t num_sent) { struct mg_connection *nc = (struct mg_connection *) arg; DBG(("%p %p %u", nc, tpcb, num_sent)); + if (nc == NULL) return ERR_OK; if ((nc->flags & MG_F_SEND_AND_CLOSE) && !(nc->flags & MG_F_WANT_WRITE) && nc->send_mbuf.len == 0 && tpcb->unacked == 0) { mg_lwip_post_signal(MG_SIG_CLOSE_CONN, nc); From f868fc861b68bfdd59cc193b893966061c8aa5a3 Mon Sep 17 00:00:00 2001 From: Deomid Ryabkov Date: Tue, 18 Apr 2017 23:27:32 +0100 Subject: [PATCH 056/137] Enable hosts and resolv.conf lookups on UNIX only Not relevant for other platforms PUBLISHED_FROM=65b8959ee677555e2fb330c84d443e0a93d9fd1c --- mongoose.c | 8 ++++---- mongoose.h | 8 ++++++++ 2 files changed, 12 insertions(+), 4 deletions(-) diff --git a/mongoose.c b/mongoose.c index 928f1107..3ad2d9e4 100644 --- a/mongoose.c +++ b/mongoose.c @@ -10872,11 +10872,11 @@ static int mg_get_ip_address_of_nameserver(char *name, size_t name_len) { } RegCloseKey(hKey); } -#elif MG_ENABLE_FILESYSTEM +#elif MG_ENABLE_FILESYSTEM && defined(MG_RESOLV_CONF_FILE_NAME) FILE *fp; char line[512]; - if ((fp = mg_fopen("/etc/resolv.conf", "r")) == NULL) { + if ((fp = mg_fopen(MG_RESOLV_CONF_FILE_NAME, "r")) == NULL) { ret = -1; } else { /* Try to figure out what nameserver to use */ @@ -10898,7 +10898,7 @@ static int mg_get_ip_address_of_nameserver(char *name, size_t name_len) { } int mg_resolve_from_hosts_file(const char *name, union socket_address *usa) { -#if MG_ENABLE_FILESYSTEM +#if MG_ENABLE_FILESYSTEM && defined(MG_HOSTS_FILE_NAME) /* TODO(mkm) cache /etc/hosts */ FILE *fp; char line[1024]; @@ -10907,7 +10907,7 @@ int mg_resolve_from_hosts_file(const char *name, union socket_address *usa) { unsigned int a, b, c, d; int len = 0; - if ((fp = mg_fopen("/etc/hosts", "r")) == NULL) { + if ((fp = mg_fopen(MG_HOSTS_FILE_NAME, "r")) == NULL) { return -1; } diff --git a/mongoose.h b/mongoose.h index f6e1743e..1f2e52ff 100644 --- a/mongoose.h +++ b/mongoose.h @@ -460,6 +460,14 @@ typedef struct stat cs_stat_t; #define MG_NET_IF MG_NET_IF_SOCKET #endif +#ifndef MG_HOSTS_FILE_NAME +#define MG_HOSTS_FILE_NAME "/etc/hosts" +#endif + +#ifndef MG_RESOLV_CONF_FILE_NAME +#define MG_RESOLV_CONF_FILE_NAME "/etc/resolv.conf" +#endif + #endif /* CS_PLATFORM == CS_P_UNIX */ #endif /* CS_COMMON_PLATFORMS_PLATFORM_UNIX_H_ */ #ifdef MG_MODULE_LINES From cd9c7dcbec9059ab02b5b87893fbbe1e1ffe3b6b Mon Sep 17 00:00:00 2001 From: Sergey Lyubka Date: Wed, 19 Apr 2017 13:37:49 +0100 Subject: [PATCH 057/137] Correct negative AAAA answer with NSEC RR PUBLISHED_FROM=c7e3132d55e603f159019e3f0290e01b189e75e0 --- mongoose.h | 2 ++ 1 file changed, 2 insertions(+) diff --git a/mongoose.h b/mongoose.h index 1f2e52ff..dab5c709 100644 --- a/mongoose.h +++ b/mongoose.h @@ -5362,6 +5362,8 @@ extern "C" { #define MG_DNS_AAAA_RECORD 0x1c /* Lookup IPv6 address */ #define MG_DNS_SRV_RECORD 0x21 /* Lookup SRV */ #define MG_DNS_MX_RECORD 0x0f /* Lookup mail server for domain */ +#define MG_DNS_ANY_RECORD 0xff +#define MG_DNS_NSEC_RECORD 0x2f #define MG_MAX_DNS_QUESTIONS 32 #define MG_MAX_DNS_ANSWERS 32 From 49bbfaf130fa71ea886fba45908a4b488c854fb4 Mon Sep 17 00:00:00 2001 From: Deomid Ryabkov Date: Fri, 21 Apr 2017 22:16:57 +0300 Subject: [PATCH 058/137] Fix mg_lwip_if_get_conn_addr when there's no pcb Connection may not (yet) have a TCP or UDP PCB associated with it. mg_lwip_if_get_conn_addr should not crash in this case. PUBLISHED_FROM=fd0ed683b18b3f549135c9d79eeadfc7348ab05a --- mongoose.c | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/mongoose.c b/mongoose.c index 3ad2d9e4..43f30130 100644 --- a/mongoose.c +++ b/mongoose.c @@ -14562,22 +14562,21 @@ void mg_lwip_if_destroy_conn(struct mg_connection *nc) { void mg_lwip_if_get_conn_addr(struct mg_connection *nc, int remote, union socket_address *sa) { memset(sa, 0, sizeof(*sa)); - if (nc->sock == INVALID_SOCKET) return; + if (nc == NULL || nc->sock == INVALID_SOCKET) return; struct mg_lwip_conn_state *cs = (struct mg_lwip_conn_state *) nc->sock; if (nc->flags & MG_F_UDP) { struct udp_pcb *upcb = cs->pcb.udp; if (remote) { memcpy(sa, &nc->sa, sizeof(*sa)); - } else { + } else if (upcb != NULL) { sa->sin.sin_port = htons(upcb->local_port); SET_ADDR(sa, &upcb->local_ip); } } else { struct tcp_pcb *tpcb = cs->pcb.tcp; if (remote) { - sa->sin.sin_port = htons(tpcb->remote_port); - SET_ADDR(sa, &tpcb->remote_ip); - } else { + memcpy(sa, &nc->sa, sizeof(*sa)); + } else if (tpcb != NULL) { sa->sin.sin_port = htons(tpcb->local_port); SET_ADDR(sa, &tpcb->local_ip); } From 83fe5a17f3c71710bdf546061387b031ac718a3e Mon Sep 17 00:00:00 2001 From: Deomid Ryabkov Date: Mon, 24 Apr 2017 15:43:19 +0100 Subject: [PATCH 059/137] Make mg_connect_{http,ws} use mg_parse_uri Remove the specialized URI parser, clean up code a bit. Fix parsing of URIs with IPv6 hosts (http://[2001:2:3::4]:567/) PUBLISHED_FROM=968ad97585d928123106ce3828920ee073113f83 --- docs/c-api/http.h/intro.md | 1 + docs/c-api/http.h/mg_send_websocket_framev.md | 3 +- .../http.h/mg_send_websocket_handshake3v.md | 17 ++ docs/c-api/http.h/mg_url_decode.md | 3 +- docs/c-api/uri.h/mg_parse_uri.md | 2 +- docs/c-api/util.h/mg_basic_auth_header.md | 3 +- mongoose.c | 275 +++++++----------- mongoose.h | 24 +- 8 files changed, 154 insertions(+), 174 deletions(-) create mode 100644 docs/c-api/http.h/mg_send_websocket_handshake3v.md diff --git a/docs/c-api/http.h/intro.md b/docs/c-api/http.h/intro.md index 8ef19dd1..8459b601 100644 --- a/docs/c-api/http.h/intro.md +++ b/docs/c-api/http.h/intro.md @@ -11,6 +11,7 @@ items: - { name: mg_send_websocket_handshake.md } - { name: mg_send_websocket_handshake2.md } - { name: mg_send_websocket_handshake3.md } + - { name: mg_send_websocket_handshake3v.md } - { name: mg_set_protocol_http_websocket.md } - { name: mg_url_decode.md } - { name: struct_http_message.md } diff --git a/docs/c-api/http.h/mg_send_websocket_framev.md b/docs/c-api/http.h/mg_send_websocket_framev.md index 005a7916..06e09460 100644 --- a/docs/c-api/http.h/mg_send_websocket_framev.md +++ b/docs/c-api/http.h/mg_send_websocket_framev.md @@ -9,5 +9,6 @@ signature: | Sends multiple websocket frames. -Like `mg_send_websocket_frame()`, but composes a frame from multiple buffers. +Like `mg_send_websocket_frame()`, but composes a frame from multiple +*buffers. diff --git a/docs/c-api/http.h/mg_send_websocket_handshake3v.md b/docs/c-api/http.h/mg_send_websocket_handshake3v.md new file mode 100644 index 00000000..acf8c1e6 --- /dev/null +++ b/docs/c-api/http.h/mg_send_websocket_handshake3v.md @@ -0,0 +1,17 @@ +--- +title: "mg_send_websocket_handshake3v()" +decl_name: "mg_send_websocket_handshake3v" +symbol_kind: "func" +signature: | + void mg_send_websocket_handshake3v(struct mg_connection *nc, + const struct mg_str path, + const struct mg_str host, + const struct mg_str protocol, + const struct mg_str extra_headers, + const struct mg_str user, + const struct mg_str pass); +--- + +Same as mg_send_websocket_handshake3 but with strings not necessarily +NUL-temrinated + diff --git a/docs/c-api/http.h/mg_url_decode.md b/docs/c-api/http.h/mg_url_decode.md index 2343adfa..454acd03 100644 --- a/docs/c-api/http.h/mg_url_decode.md +++ b/docs/c-api/http.h/mg_url_decode.md @@ -13,6 +13,7 @@ Source string is specified by (`src`, `src_len`), and destination is (`dst`, `dst_len`). If `is_form_url_encoded` is non-zero, then `+` character is decoded as a blank space character. This function guarantees to NUL-terminate the destination. If destination is too small, -then the source string is partially decoded and `-1` is returned. Otherwise, +then the source string is partially decoded and `-1` is returned. +*Otherwise, a length of the decoded string is returned, not counting final NUL. diff --git a/docs/c-api/uri.h/mg_parse_uri.md b/docs/c-api/uri.h/mg_parse_uri.md index 48cb6d94..2d330f18 100644 --- a/docs/c-api/uri.h/mg_parse_uri.md +++ b/docs/c-api/uri.h/mg_parse_uri.md @@ -3,7 +3,7 @@ title: "mg_parse_uri()" decl_name: "mg_parse_uri" symbol_kind: "func" signature: | - int mg_parse_uri(struct mg_str uri, struct mg_str *scheme, + int mg_parse_uri(const struct mg_str uri, struct mg_str *scheme, struct mg_str *user_info, struct mg_str *host, unsigned int *port, struct mg_str *path, struct mg_str *query, struct mg_str *fragment); diff --git a/docs/c-api/util.h/mg_basic_auth_header.md b/docs/c-api/util.h/mg_basic_auth_header.md index d8b582a5..724ec053 100644 --- a/docs/c-api/util.h/mg_basic_auth_header.md +++ b/docs/c-api/util.h/mg_basic_auth_header.md @@ -3,7 +3,8 @@ title: "mg_basic_auth_header()" decl_name: "mg_basic_auth_header" symbol_kind: "func" signature: | - void mg_basic_auth_header(const char *user, const char *pass, struct mbuf *buf); + void mg_basic_auth_header(const struct mg_str user, const struct mg_str pass, + struct mbuf *buf); --- Generate a Basic Auth header and appends it to buf. diff --git a/mongoose.c b/mongoose.c index 43f30130..b116409a 100644 --- a/mongoose.c +++ b/mongoose.c @@ -97,11 +97,6 @@ MG_INTERNAL size_t mg_handle_chunked(struct mg_connection *nc, struct http_message *hm, char *buf, size_t blen); -MG_INTERNAL int mg_http_common_url_parse(const char *url, const char *schema, - const char *schema_tls, int *use_ssl, - char **user, char **pass, char **addr, - int *port_i, const char **path); - #if MG_ENABLE_FILESYSTEM MG_INTERNAL int mg_uri_to_local_path(struct http_message *hm, const struct mg_serve_http_opts *opts, @@ -153,11 +148,6 @@ MG_INTERNAL int mg_get_errno(void); MG_INTERNAL void mg_close_conn(struct mg_connection *conn); -MG_INTERNAL int mg_http_common_url_parse(const char *url, const char *schema, - const char *schema_tls, int *use_ssl, - char **user, char **pass, char **addr, - int *port_i, const char **path); - #if MG_ENABLE_SNTP MG_INTERNAL int mg_sntp_parse_reply(const char *buf, int len, struct mg_sntp_message *msg); @@ -4853,7 +4843,7 @@ static void parse_uri_component(const char **p, const char *end, char sep, if (*p < end) (*p)++; } -int mg_parse_uri(struct mg_str uri, struct mg_str *scheme, +int mg_parse_uri(const struct mg_str uri, struct mg_str *scheme, struct mg_str *user_info, struct mg_str *host, unsigned int *port, struct mg_str *path, struct mg_str *query, struct mg_str *fragment) { @@ -4877,8 +4867,13 @@ int mg_parse_uri(struct mg_str uri, struct mg_str *scheme, * expecting on of: * - `scheme://xxxx` * - `xxxx:port` + * - `[a:b:c]:port` * - `xxxx/path` */ + if (*p == '[') { + state = P_HOST; + break; + } for (; p < end; p++) { if (*p == ':') { state = P_SCHEME_OR_PORT; @@ -4898,7 +4893,7 @@ int mg_parse_uri(struct mg_str uri, struct mg_str *scheme, rscheme.p = uri.p; rscheme.len = p - uri.p; state = P_USER_INFO; - p += 2; /* point to last separator char */ + p += 3; } else { rhost.p = uri.p; rhost.len = p - uri.p; @@ -4906,27 +4901,35 @@ int mg_parse_uri(struct mg_str uri, struct mg_str *scheme, } break; case P_USER_INFO: - p++; ruser_info.p = p; for (; p < end; p++) { - if (*p == '@') { - state = P_HOST; - break; - } else if (*p == '/') { + if (*p == '@' || *p == '[') { break; } } - if (p == end || *p == '/') { + if (p == end || *p == '/' || *p == '[') { /* backtrack and parse as host */ - state = P_HOST; p = ruser_info.p; } ruser_info.len = p - ruser_info.p; + state = P_HOST; break; case P_HOST: if (*p == '@') p++; rhost.p = p; - for (; p < end; p++) { + if (*p == '[') { + int found = 0; + for (; !found && p < end; p++) { + found = (*p == ']'); + } + if (!found) return -1; + } else { + for (; p < end; p++) { + if (*p == ':' || *p == '/') break; + } + } + rhost.len = p - rhost.p; + if (p < end) { if (*p == ':') { state = P_PORT; break; @@ -4935,7 +4938,6 @@ int mg_parse_uri(struct mg_str uri, struct mg_str *scheme, break; } } - rhost.len = p - rhost.p; break; case P_PORT: p++; @@ -5095,7 +5097,8 @@ static void mg_http_conn_destructor(void *proto_data); struct mg_connection *mg_connect_http_base( struct mg_mgr *mgr, MG_CB(mg_event_handler_t ev_handler, void *user_data), struct mg_connect_opts opts, const char *schema, const char *schema_ssl, - const char *url, const char **path, char **user, char **pass, char **addr); + const char *url, struct mg_str *path, struct mg_str *user_info, + struct mg_str *host); static struct mg_http_proto_data *mg_http_get_proto_data( struct mg_connection *c) { @@ -7089,20 +7092,19 @@ void mg_http_reverse_proxy(struct mg_connection *nc, struct mg_str upstream) { struct mg_connection *be; char burl[256], *purl = burl; - char *addr = NULL; - const char *path = NULL; int i; const char *error; struct mg_connect_opts opts; + struct mg_str path = MG_NULL_STR, user_info = MG_NULL_STR, host = MG_NULL_STR; memset(&opts, 0, sizeof(opts)); opts.error_string = &error; mg_asprintf(&purl, sizeof(burl), "%.*s%.*s", (int) upstream.len, upstream.p, (int) (hm->uri.len - mount.len), hm->uri.p + mount.len); - be = mg_connect_http_base(nc->mgr, MG_CB(mg_reverse_proxy_handler, NULL), - opts, "http://", "https://", purl, &path, - NULL /* user */, NULL /* pass */, &addr); + be = + mg_connect_http_base(nc->mgr, MG_CB(mg_reverse_proxy_handler, NULL), opts, + "http", "https", purl, &path, &user_info, &host); LOG(LL_DEBUG, ("Proxying %.*s to %s (rule: %.*s)", (int) hm->uri.len, hm->uri.p, purl, (int) mount.len, mount.p)); @@ -7117,10 +7119,10 @@ void mg_http_reverse_proxy(struct mg_connection *nc, mg_http_get_proto_data(nc)->reverse_proxy_data.linked_conn = be; /* send request upstream */ - mg_printf(be, "%.*s %s HTTP/1.1\r\n", (int) hm->method.len, hm->method.p, - path); + mg_printf(be, "%.*s %.*s HTTP/1.1\r\n", (int) hm->method.len, hm->method.p, + (int) path.len, path.p); - mg_printf(be, "Host: %s\r\n", addr); + mg_printf(be, "Host: %.*s\r\n", (int) host.len, host.p); for (i = 0; i < MG_MAX_HTTP_HEADERS && hm->header_names[i].len > 0; i++) { struct mg_str hn = hm->header_names[i]; struct mg_str hv = hm->header_values[i]; @@ -7704,103 +7706,39 @@ void mg_file_upload_handler(struct mg_connection *nc, int ev, void *ev_data, #endif /* MG_ENABLE_HTTP_STREAMING_MULTIPART */ #endif /* MG_ENABLE_FILESYSTEM */ -/* returns 0 on success, -1 on error */ -MG_INTERNAL int mg_http_common_url_parse(const char *url, const char *schema, - const char *schema_tls, int *use_ssl, - char **user, char **pass, char **addr, - int *port_i, const char **path) { - int addr_len = 0; - int auth_sep_pos = -1; - int user_sep_pos = -1; - int port_pos = -1; - (void) user; - (void) pass; - - if (strncmp(url, schema, strlen(schema)) == 0) { - url += strlen(schema); - } else if (strncmp(url, schema_tls, strlen(schema_tls)) == 0) { - url += strlen(schema_tls); - *use_ssl = 1; -#if !MG_ENABLE_SSL - return -1; /* SSL is not enabled, cannot do HTTPS URLs */ -#endif - } - - while (*url != '\0') { - *addr = (char *) MG_REALLOC(*addr, addr_len + 6 /* space for port too. */); - if (*addr == NULL) { - DBG(("OOM")); - return -1; - } - if (*url == '/') { - break; - } - if (*url == '@') { - auth_sep_pos = addr_len; - user_sep_pos = port_pos; - port_pos = -1; - } - if (*url == ':') port_pos = addr_len; - (*addr)[addr_len++] = *url; - (*addr)[addr_len] = '\0'; - url++; - } - - if (addr_len == 0) goto cleanup; - if (port_pos < 0) { - *port_i = addr_len; - addr_len += sprintf(*addr + addr_len, ":%d", *use_ssl ? 443 : 80); - } else { - *port_i = -1; - } - - if (*path == NULL) *path = url; - - if (**path == '\0') *path = "/"; - - if (user != NULL && pass != NULL) { - if (auth_sep_pos == -1) { - *user = NULL; - *pass = NULL; - } else { - /* user is from 0 to user_sep_pos */ - *user = (char *) MG_MALLOC(user_sep_pos + 1); - memcpy(*user, *addr, user_sep_pos); - (*user)[user_sep_pos] = '\0'; - /* pass is from user_sep_pos + 1 to auth_sep_pos */ - *pass = (char *) MG_MALLOC(auth_sep_pos - user_sep_pos - 1 + 1); - memcpy(*pass, *addr + user_sep_pos + 1, auth_sep_pos - user_sep_pos - 1); - (*pass)[auth_sep_pos - user_sep_pos - 1] = '\0'; - - /* move address proper to the front */ - memmove(*addr, *addr + auth_sep_pos + 1, addr_len - auth_sep_pos); - } - } - - DBG(("%s %s", *addr, *path)); - - return 0; - -cleanup: - MG_FREE(*addr); - return -1; -} - struct mg_connection *mg_connect_http_base( struct mg_mgr *mgr, MG_CB(mg_event_handler_t ev_handler, void *user_data), struct mg_connect_opts opts, const char *schema, const char *schema_ssl, - const char *url, const char **path, char **user, char **pass, char **addr) { + const char *url, struct mg_str *path, struct mg_str *user_info, + struct mg_str *host) { struct mg_connection *nc = NULL; - int port_i = -1; + unsigned int port_i = 0; int use_ssl = 0; + struct mg_str scheme, query, fragment; + char conn_addr_buf[2]; + char *conn_addr = conn_addr_buf; - if (mg_http_common_url_parse(url, schema, schema_ssl, &use_ssl, user, pass, - addr, &port_i, path) < 0) { + if (mg_parse_uri(mg_mk_str(url), &scheme, user_info, host, &port_i, path, + &query, &fragment) != 0) { MG_SET_PTRPTR(opts.error_string, "cannot parse url"); - return NULL; + goto out; } - LOG(LL_DEBUG, ("%s use_ssl? %d", url, use_ssl)); + if (mg_vcmp(&scheme, schema) == 0) { + use_ssl = 0; + if (port_i == 0) port_i = 80; + } else if (mg_vcmp(&scheme, schema_ssl) == 0) { + use_ssl = 1; + if (port_i == 0) port_i = 443; + } else { + goto out; + } + + mg_asprintf(&conn_addr, sizeof(conn_addr_buf), "tcp://%.*s:%u", + (int) host->len, host->p, port_i); + if (conn_addr == NULL) goto out; + + LOG(LL_DEBUG, ("%s use_ssl? %d %s", url, use_ssl, conn_addr)); if (use_ssl) { #if MG_ENABLE_SSL /* @@ -7813,20 +7751,17 @@ struct mg_connection *mg_connect_http_base( } #else MG_SET_PTRPTR(opts.error_string, "ssl is disabled"); - if (user != NULL) MG_FREE(*user); - if (pass != NULL) MG_FREE(*pass); - MG_FREE(*addr); - return NULL; + goto out; #endif } - if ((nc = mg_connect_opt(mgr, *addr, MG_CB(ev_handler, user_data), opts)) != - NULL) { + if ((nc = mg_connect_opt(mgr, conn_addr, MG_CB(ev_handler, user_data), + opts)) != NULL) { mg_set_protocol_http_websocket(nc); - /* If the port was addred by us, restore the original host. */ - if (port_i >= 0) (*addr)[port_i] = '\0'; } +out: + if (conn_addr != NULL && conn_addr != conn_addr_buf) MG_FREE(conn_addr); return nc; } @@ -7834,35 +7769,33 @@ struct mg_connection *mg_connect_http_opt( struct mg_mgr *mgr, MG_CB(mg_event_handler_t ev_handler, void *user_data), struct mg_connect_opts opts, const char *url, const char *extra_headers, const char *post_data) { - char *user = NULL, *pass = NULL, *addr = NULL; - const char *path = NULL; + struct mg_str user = MG_NULL_STR, null_str = MG_NULL_STR; + struct mg_str host = MG_NULL_STR, path = MG_NULL_STR; struct mbuf auth; struct mg_connection *nc = - mg_connect_http_base(mgr, MG_CB(ev_handler, user_data), opts, "http://", - "https://", url, &path, &user, &pass, &addr); + mg_connect_http_base(mgr, MG_CB(ev_handler, user_data), opts, "http", + "https", url, &path, &user, &host); if (nc == NULL) { return NULL; } mbuf_init(&auth, 0); - if (user != NULL) { - mg_basic_auth_header(user, pass, &auth); + if (user.len > 0) { + mg_basic_auth_header(user, null_str, &auth); } if (post_data == NULL) post_data = ""; if (extra_headers == NULL) extra_headers = ""; + if (path.len == 0) path = mg_mk_str("/"); - mg_printf(nc, "%s %s HTTP/1.1\r\nHost: %s\r\nContent-Length: %" SIZE_T_FMT + mg_printf(nc, "%s %.*s HTTP/1.1\r\nHost: %.*s\r\nContent-Length: %" SIZE_T_FMT "\r\n%.*s%s\r\n%s", - post_data[0] == '\0' ? "GET" : "POST", path, addr, - strlen(post_data), (int) auth.len, + (post_data[0] == '\0' ? "GET" : "POST"), (int) path.len, path.p, + (int) host.len, host.p, strlen(post_data), (int) auth.len, (auth.buf == NULL ? "" : auth.buf), extra_headers, post_data); mbuf_free(&auth); - MG_FREE(user); - MG_FREE(pass); - MG_FREE(addr); return nc; } @@ -8974,8 +8907,6 @@ MG_INTERNAL void mg_handle_put(struct mg_connection *nc, const char *path, #define MG_WEBSOCKET_PING_INTERVAL_SECONDS 5 #endif -#define MG_WS_NO_HOST_HEADER_MAGIC ((char *) 0x1) - static int mg_is_ws_fragment(unsigned char flags) { return (flags & 0x80) == 0 || (flags & 0x0f) == 0; } @@ -9283,6 +9214,18 @@ void mg_send_websocket_handshake3(struct mg_connection *nc, const char *path, const char *host, const char *protocol, const char *extra_headers, const char *user, const char *pass) { + mg_send_websocket_handshake3v(nc, mg_mk_str(path), mg_mk_str(host), + mg_mk_str(protocol), mg_mk_str(extra_headers), + mg_mk_str(user), mg_mk_str(pass)); +} + +void mg_send_websocket_handshake3v(struct mg_connection *nc, + const struct mg_str path, + const struct mg_str host, + const struct mg_str protocol, + const struct mg_str extra_headers, + const struct mg_str user, + const struct mg_str pass) { struct mbuf auth; char key[25]; uint32_t nonce[4]; @@ -9293,7 +9236,7 @@ void mg_send_websocket_handshake3(struct mg_connection *nc, const char *path, mg_base64_encode((unsigned char *) &nonce, sizeof(nonce), key); mbuf_init(&auth, 0); - if (user != NULL) { + if (user.len > 0) { mg_basic_auth_header(user, pass, &auth); } @@ -9304,23 +9247,25 @@ void mg_send_websocket_handshake3(struct mg_connection *nc, const char *path, * because it handles NULL specially (and incorrectly). */ mg_printf(nc, - "GET %s HTTP/1.1\r\n" + "GET %.*s HTTP/1.1\r\n" "Upgrade: websocket\r\n" "Connection: Upgrade\r\n" "%.*s" "Sec-WebSocket-Version: 13\r\n" "Sec-WebSocket-Key: %s\r\n", - path, (int) auth.len, (auth.buf == NULL ? "" : auth.buf), key); + (int) path.len, path.p, (int) auth.len, + (auth.buf == NULL ? "" : auth.buf), key); /* TODO(mkm): take default hostname from http proto data if host == NULL */ - if (host != MG_WS_NO_HOST_HEADER_MAGIC) { - mg_printf(nc, "Host: %s\r\n", host); + if (host.len > 0) { + mg_printf(nc, "Host: %.*s\r\n", (int) host.len, host.p); } - if (protocol != NULL) { - mg_printf(nc, "Sec-WebSocket-Protocol: %s\r\n", protocol); + if (protocol.len > 0) { + mg_printf(nc, "Sec-WebSocket-Protocol: %.*s\r\n", (int) protocol.len, + protocol.p); } - if (extra_headers != NULL) { - mg_printf(nc, "%s", extra_headers); + if (extra_headers.len > 0) { + mg_printf(nc, "%.*s", (int) extra_headers.len, extra_headers.p); } mg_printf(nc, "\r\n"); @@ -9329,28 +9274,26 @@ void mg_send_websocket_handshake3(struct mg_connection *nc, const char *path, void mg_send_websocket_handshake(struct mg_connection *nc, const char *path, const char *extra_headers) { - mg_send_websocket_handshake2(nc, path, MG_WS_NO_HOST_HEADER_MAGIC, NULL, - extra_headers); + struct mg_str null_str = MG_NULL_STR; + mg_send_websocket_handshake3v( + nc, mg_mk_str(path), null_str /* host */, null_str /* protocol */, + mg_mk_str(extra_headers), null_str /* user */, null_str /* pass */); } struct mg_connection *mg_connect_ws_opt( struct mg_mgr *mgr, MG_CB(mg_event_handler_t ev_handler, void *user_data), struct mg_connect_opts opts, const char *url, const char *protocol, const char *extra_headers) { - char *user = NULL, *pass = NULL, *addr = NULL; - const char *path = NULL; + struct mg_str null_str = MG_NULL_STR; + struct mg_str host = MG_NULL_STR, path = MG_NULL_STR, user_info = MG_NULL_STR; struct mg_connection *nc = - mg_connect_http_base(mgr, MG_CB(ev_handler, user_data), opts, "ws://", - "wss://", url, &path, &user, &pass, &addr); - + mg_connect_http_base(mgr, MG_CB(ev_handler, user_data), opts, "ws", "wss", + url, &path, &user_info, &host); if (nc != NULL) { - mg_send_websocket_handshake3(nc, path, addr, protocol, extra_headers, user, - pass); + mg_send_websocket_handshake3v(nc, path, host, mg_mk_str(protocol), + mg_mk_str(extra_headers), user_info, + null_str); } - - MG_FREE(addr); - MG_FREE(user); - MG_FREE(pass); return nc; } @@ -9749,7 +9692,7 @@ void mg_mbuf_append_base64(struct mbuf *mbuf, const void *data, size_t len) { cs_base64_finish(&ctx); } -void mg_basic_auth_header(const char *user, const char *pass, +void mg_basic_auth_header(const struct mg_str user, const struct mg_str pass, struct mbuf *buf) { const char *header_prefix = "Authorization: Basic "; const char *header_suffix = "\r\n"; @@ -9759,10 +9702,10 @@ void mg_basic_auth_header(const char *user, const char *pass, mbuf_append(buf, header_prefix, strlen(header_prefix)); - cs_base64_update(&ctx, user, strlen(user)); - if (pass != NULL) { + cs_base64_update(&ctx, user.p, user.len); + if (pass.len > 0) { cs_base64_update(&ctx, ":", 1); - cs_base64_update(&ctx, pass, strlen(pass)); + cs_base64_update(&ctx, pass.p, pass.len); } cs_base64_finish(&ctx); mbuf_append(buf, header_suffix, strlen(header_suffix)); diff --git a/mongoose.h b/mongoose.h index dab5c709..622923e3 100644 --- a/mongoose.h +++ b/mongoose.h @@ -1774,6 +1774,8 @@ struct mg_str mg_mk_str_n(const char *s, size_t len); /* Macro for initializing mg_str. */ #define MG_MK_STR(str_literal) \ { str_literal, sizeof(str_literal) - 1 } +#define MG_NULL_STR \ + { NULL, 0 } /* * Cross-platform version of `strcmp()` where where first string is @@ -3828,7 +3830,7 @@ extern "C" { * * Returns 0 on success, -1 on error. */ -int mg_parse_uri(struct mg_str uri, struct mg_str *scheme, +int mg_parse_uri(const struct mg_str uri, struct mg_str *scheme, struct mg_str *user_info, struct mg_str *host, unsigned int *port, struct mg_str *path, struct mg_str *query, struct mg_str *fragment); @@ -4056,7 +4058,8 @@ void mg_mbuf_append_base64(struct mbuf *mbuf, const void *data, size_t len); * If pass is NULL, then user is expected to contain the credentials pair * already encoded as `user:pass`. */ -void mg_basic_auth_header(const char *user, const char *pass, struct mbuf *buf); +void mg_basic_auth_header(const struct mg_str user, const struct mg_str pass, + struct mbuf *buf); #ifdef __cplusplus } @@ -4280,6 +4283,17 @@ void mg_send_websocket_handshake3(struct mg_connection *nc, const char *path, const char *host, const char *protocol, const char *extra_headers, const char *user, const char *pass); + +/* Same as mg_send_websocket_handshake3 but with strings not necessarily + * NUL-temrinated */ +void mg_send_websocket_handshake3v(struct mg_connection *nc, + const struct mg_str path, + const struct mg_str host, + const struct mg_str protocol, + const struct mg_str extra_headers, + const struct mg_str user, + const struct mg_str pass); + /* * Helper function that creates an outbound WebSocket connection. * @@ -4341,7 +4355,8 @@ void mg_send_websocket_frame(struct mg_connection *nc, int op_and_flags, /* * Sends multiple websocket frames. * - * Like `mg_send_websocket_frame()`, but composes a frame from multiple buffers. + * Like `mg_send_websocket_frame()`, but composes a frame from multiple + *buffers. */ void mg_send_websocket_framev(struct mg_connection *nc, int op_and_flags, const struct mg_str *strings, int num_strings); @@ -4386,7 +4401,8 @@ void mg_printf_websocket_frame(struct mg_connection *nc, int op_and_flags, * (`dst`, `dst_len`). If `is_form_url_encoded` is non-zero, then * `+` character is decoded as a blank space character. This function * guarantees to NUL-terminate the destination. If destination is too small, - * then the source string is partially decoded and `-1` is returned. Otherwise, + * then the source string is partially decoded and `-1` is returned. + *Otherwise, * a length of the decoded string is returned, not counting final NUL. */ int mg_url_decode(const char *src, int src_len, char *dst, int dst_len, From a35e5bd966031f0a76e264fdb387283c2cf46094 Mon Sep 17 00:00:00 2001 From: Deomid Ryabkov Date: Tue, 25 Apr 2017 13:18:43 +0300 Subject: [PATCH 060/137] A function to make a NUL-terminated copy of mg_str PUBLISHED_FROM=c1310b7d62f3ad6e2f24fea9f5229588c56b0bbe --- mongoose.c | 22 +++++++++++++++++----- mongoose.h | 8 ++++++++ 2 files changed, 25 insertions(+), 5 deletions(-) diff --git a/mongoose.c b/mongoose.c index b116409a..ce07eed3 100644 --- a/mongoose.c +++ b/mongoose.c @@ -1389,19 +1389,31 @@ int mg_vcasecmp(const struct mg_str *str1, const char *str2) { return r; } -struct mg_str mg_strdup(const struct mg_str s) WEAK; -struct mg_str mg_strdup(const struct mg_str s) { +static struct mg_str mg_strdup_common(const struct mg_str s, + int nul_terminate) { struct mg_str r = {NULL, 0}; if (s.len > 0 && s.p != NULL) { - r.p = (char *) MG_MALLOC(s.len); - if (r.p != NULL) { - memcpy((char *) r.p, s.p, s.len); + char *sc = (char *) MG_MALLOC(s.len + (nul_terminate ? 1 : 0)); + if (sc != NULL) { + memcpy(sc, s.p, s.len); + if (nul_terminate) sc[s.len] = '\0'; + r.p = sc; r.len = s.len; } } return r; } +struct mg_str mg_strdup(const struct mg_str s) WEAK; +struct mg_str mg_strdup(const struct mg_str s) { + return mg_strdup_common(s, 1 /* NUL-terminate */); +} + +struct mg_str mg_strdup_nul(const struct mg_str s) WEAK; +struct mg_str mg_strdup_nul(const struct mg_str s) { + return mg_strdup_common(s, 0 /* NUL-terminate */); +} + int mg_strcmp(const struct mg_str str1, const struct mg_str str2) WEAK; int mg_strcmp(const struct mg_str str1, const struct mg_str str2) { size_t i = 0; diff --git a/mongoose.h b/mongoose.h index 622923e3..76911e1c 100644 --- a/mongoose.h +++ b/mongoose.h @@ -1789,7 +1789,15 @@ int mg_vcmp(const struct mg_str *str2, const char *str1); */ int mg_vcasecmp(const struct mg_str *str2, const char *str1); +/* Creates a copy of s (heap-allocated). */ struct mg_str mg_strdup(const struct mg_str s); + +/* + * Creates a copy of s (heap-allocated). + * Resulting string is NUL-terminated (but NUL is not included in len). + */ +struct mg_str mg_strdup_nul(const struct mg_str s); + int mg_strcmp(const struct mg_str str1, const struct mg_str str2); int mg_strncmp(const struct mg_str str1, const struct mg_str str2, size_t n); From 2e65ce8272d85ae4325cbf3476e0ab0d90dd95a0 Mon Sep 17 00:00:00 2001 From: Deomid Ryabkov Date: Wed, 26 Apr 2017 17:34:03 +0300 Subject: [PATCH 061/137] Fix mg_parse_uri for URIs with fragment but no qs PUBLISHED_FROM=8fb53581e8979c28026f9c2bcacb89de740c18cf --- mongoose.c | 25 +++++++++++++++---------- 1 file changed, 15 insertions(+), 10 deletions(-) diff --git a/mongoose.c b/mongoose.c index ce07eed3..e0e370a9 100644 --- a/mongoose.c +++ b/mongoose.c @@ -4839,17 +4839,20 @@ int mg_ssl_if_mbed_random(void *ctx, unsigned char *buf, size_t len) { /* Amalgamated: #include "mongoose/src/uri.h" */ /* - * scan string until `sep`, keeping track of component boundaries in `res`. + * scan string until encountering one of `seps`, keeping track of component + * boundaries in `res`. * * `p` will point to the char after the separator or it will be `end`. */ -static void parse_uri_component(const char **p, const char *end, char sep, - struct mg_str *res) { +static void parse_uri_component(const char **p, const char *end, + const char *seps, struct mg_str *res) { + const char *q; res->p = *p; for (; *p < end; (*p)++) { - if (**p == sep) { - break; + for (q = seps; *q != '\0'; q++) { + if (**p == *q) break; } + if (*q != '\0') break; } res->len = (*p) - res->p; if (*p < end) (*p)++; @@ -4964,9 +4967,11 @@ int mg_parse_uri(const struct mg_str uri, struct mg_str *scheme, break; case P_REST: /* `p` points to separator. `path` includes the separator */ - parse_uri_component(&p, end, '?', &rpath); - parse_uri_component(&p, end, '#', &rquery); - parse_uri_component(&p, end, '\0', &rfragment); + parse_uri_component(&p, end, "?#", &rpath); + if (p < end && *(p - 1) == '?') { + parse_uri_component(&p, end, "#", &rquery); + } + parse_uri_component(&p, end, "", &rfragment); break; } } @@ -4997,7 +5002,7 @@ int mg_normalize_uri_path(const struct mg_str *in, struct mg_str *out) { while (s < se) { const char *next = s; struct mg_str component; - parse_uri_component(&next, se, '/', &component); + parse_uri_component(&next, se, "/", &component); if (mg_vcmp(&component, ".") == 0) { /* Yum. */ } else if (mg_vcmp(&component, "..") == 0) { @@ -7282,7 +7287,7 @@ MG_INTERNAL int mg_uri_to_local_path(struct http_message *hm, } } if (u >= cp_end) break; - parse_uri_component((const char **) &next, cp_end, '/', &component); + parse_uri_component((const char **) &next, cp_end, "/", &component); if (component.len > 0) { int len; memmove(p + 1, component.p, component.len); From 692f436b3d53d96fede6fa06193559a6c03cd9b6 Mon Sep 17 00:00:00 2001 From: Deomid Ryabkov Date: Thu, 27 Apr 2017 13:38:27 +0300 Subject: [PATCH 062/137] Make mg_connect_ws accept http:// URLs As well as URLs without prefix PUBLISHED_FROM=ee298f6575603c8b384888633fe16413695ba70d --- mongoose.c | 30 ++++++++++++++++-------------- 1 file changed, 16 insertions(+), 14 deletions(-) diff --git a/mongoose.c b/mongoose.c index e0e370a9..6aabb5c0 100644 --- a/mongoose.c +++ b/mongoose.c @@ -5113,9 +5113,9 @@ struct mg_http_proto_data { static void mg_http_conn_destructor(void *proto_data); struct mg_connection *mg_connect_http_base( struct mg_mgr *mgr, MG_CB(mg_event_handler_t ev_handler, void *user_data), - struct mg_connect_opts opts, const char *schema, const char *schema_ssl, - const char *url, struct mg_str *path, struct mg_str *user_info, - struct mg_str *host); + struct mg_connect_opts opts, const char *scheme1, const char *scheme2, + const char *scheme_ssl1, const char *scheme_ssl2, const char *url, + struct mg_str *path, struct mg_str *user_info, struct mg_str *host); static struct mg_http_proto_data *mg_http_get_proto_data( struct mg_connection *c) { @@ -7119,9 +7119,9 @@ void mg_http_reverse_proxy(struct mg_connection *nc, mg_asprintf(&purl, sizeof(burl), "%.*s%.*s", (int) upstream.len, upstream.p, (int) (hm->uri.len - mount.len), hm->uri.p + mount.len); - be = - mg_connect_http_base(nc->mgr, MG_CB(mg_reverse_proxy_handler, NULL), opts, - "http", "https", purl, &path, &user_info, &host); + be = mg_connect_http_base(nc->mgr, MG_CB(mg_reverse_proxy_handler, NULL), + opts, "http", NULL, "https", NULL, purl, &path, + &user_info, &host); LOG(LL_DEBUG, ("Proxying %.*s to %s (rule: %.*s)", (int) hm->uri.len, hm->uri.p, purl, (int) mount.len, mount.p)); @@ -7725,9 +7725,9 @@ void mg_file_upload_handler(struct mg_connection *nc, int ev, void *ev_data, struct mg_connection *mg_connect_http_base( struct mg_mgr *mgr, MG_CB(mg_event_handler_t ev_handler, void *user_data), - struct mg_connect_opts opts, const char *schema, const char *schema_ssl, - const char *url, struct mg_str *path, struct mg_str *user_info, - struct mg_str *host) { + struct mg_connect_opts opts, const char *scheme1, const char *scheme2, + const char *scheme_ssl1, const char *scheme_ssl2, const char *url, + struct mg_str *path, struct mg_str *user_info, struct mg_str *host) { struct mg_connection *nc = NULL; unsigned int port_i = 0; int use_ssl = 0; @@ -7741,10 +7741,12 @@ struct mg_connection *mg_connect_http_base( goto out; } - if (mg_vcmp(&scheme, schema) == 0) { + if (scheme.len == 0 || mg_vcmp(&scheme, scheme1) == 0 || + (scheme2 != NULL && mg_vcmp(&scheme, scheme2) == 0)) { use_ssl = 0; if (port_i == 0) port_i = 80; - } else if (mg_vcmp(&scheme, schema_ssl) == 0) { + } else if (mg_vcmp(&scheme, scheme_ssl1) == 0 || + (scheme2 != NULL && mg_vcmp(&scheme, scheme_ssl2) == 0)) { use_ssl = 1; if (port_i == 0) port_i = 443; } else { @@ -7791,7 +7793,7 @@ struct mg_connection *mg_connect_http_opt( struct mbuf auth; struct mg_connection *nc = mg_connect_http_base(mgr, MG_CB(ev_handler, user_data), opts, "http", - "https", url, &path, &user, &host); + NULL, "https", NULL, url, &path, &user, &host); if (nc == NULL) { return NULL; @@ -9304,8 +9306,8 @@ struct mg_connection *mg_connect_ws_opt( struct mg_str null_str = MG_NULL_STR; struct mg_str host = MG_NULL_STR, path = MG_NULL_STR, user_info = MG_NULL_STR; struct mg_connection *nc = - mg_connect_http_base(mgr, MG_CB(ev_handler, user_data), opts, "ws", "wss", - url, &path, &user_info, &host); + mg_connect_http_base(mgr, MG_CB(ev_handler, user_data), opts, "http", + "ws", "https", "wss", url, &path, &user_info, &host); if (nc != NULL) { mg_send_websocket_handshake3v(nc, path, host, mg_mk_str(protocol), mg_mk_str(extra_headers), user_info, From 189cd8c5f641369c29fd44d385490f0e43940a5d Mon Sep 17 00:00:00 2001 From: Deomid Ryabkov Date: Thu, 27 Apr 2017 14:35:40 +0100 Subject: [PATCH 063/137] Add mg_assemble_uri PUBLISHED_FROM=533e134a48e0fca55509c3eb16b0a6b64c1188e8 --- docs/c-api/uri.h/intro.md | 1 + docs/c-api/uri.h/mg_assemble_uri.md | 20 +++++++++ mongoose.c | 70 +++++++++++++++++++++++++++++ mongoose.h | 15 +++++++ 4 files changed, 106 insertions(+) create mode 100644 docs/c-api/uri.h/mg_assemble_uri.md diff --git a/docs/c-api/uri.h/intro.md b/docs/c-api/uri.h/intro.md index 154aea63..f266b27e 100644 --- a/docs/c-api/uri.h/intro.md +++ b/docs/c-api/uri.h/intro.md @@ -3,6 +3,7 @@ title: "URI" symbol_kind: "intro" decl_name: "uri.h" items: + - { name: mg_assemble_uri.md } - { name: mg_parse_uri.md } --- diff --git a/docs/c-api/uri.h/mg_assemble_uri.md b/docs/c-api/uri.h/mg_assemble_uri.md new file mode 100644 index 00000000..20065148 --- /dev/null +++ b/docs/c-api/uri.h/mg_assemble_uri.md @@ -0,0 +1,20 @@ +--- +title: "mg_assemble_uri()" +decl_name: "mg_assemble_uri" +symbol_kind: "func" +signature: | + int mg_assemble_uri(const struct mg_str *scheme, const struct mg_str *user_info, + const struct mg_str *host, unsigned int port, + const struct mg_str *path, const struct mg_str *query, + const struct mg_str *fragment, int normalize_path, + struct mg_str *uri); +--- + +Assemble URI from parts. Any of the inputs can be NULL or zero-length mg_str. + +If normalize_path is true, path is normalized by resolving relative refs. + +Result is a heap-allocated string (uri->p must be free()d after use). + +Returns 0 on success, -1 on error. + diff --git a/mongoose.c b/mongoose.c index 6aabb5c0..568da31c 100644 --- a/mongoose.c +++ b/mongoose.c @@ -5021,6 +5021,76 @@ int mg_normalize_uri_path(const struct mg_str *in, struct mg_str *out) { out->len = d - cp; return 1; } + +int mg_assemble_uri(const struct mg_str *scheme, const struct mg_str *user_info, + const struct mg_str *host, unsigned int port, + const struct mg_str *path, const struct mg_str *query, + const struct mg_str *fragment, int normalize_path, + struct mg_str *uri) { + int result = -1; + struct mbuf out; + mbuf_init(&out, 0); + + if (scheme != NULL && scheme->len > 0) { + mbuf_append(&out, scheme->p, scheme->len); + mbuf_append(&out, "://", 3); + } + + if (user_info != NULL && user_info->len > 0) { + mbuf_append(&out, user_info->p, user_info->len); + mbuf_append(&out, "@", 1); + } + + if (host != NULL && host->len > 0) { + mbuf_append(&out, host->p, host->len); + } + + if (port != 0) { + char port_str[20]; + int port_str_len = sprintf(port_str, ":%u", port); + mbuf_append(&out, port_str, port_str_len); + } + + if (path != NULL && path->len > 0) { + if (normalize_path) { + struct mg_str npath = mg_strdup(*path); + if (npath.len != path->len) goto out; + if (!mg_normalize_uri_path(path, &npath)) { + free((void *) npath.p); + goto out; + } + mbuf_append(&out, npath.p, npath.len); + free((void *) npath.p); + } else { + mbuf_append(&out, path->p, path->len); + } + } else if (normalize_path) { + mbuf_append(&out, "/", 1); + } + + if (query != NULL && query->len > 0) { + mbuf_append(&out, "?", 1); + mbuf_append(&out, query->p, query->len); + } + + if (fragment != NULL && fragment->len > 0) { + mbuf_append(&out, "#", 1); + mbuf_append(&out, fragment->p, fragment->len); + } + + result = 0; + +out: + if (result == 0) { + uri->p = out.buf; + uri->len = out.len; + } else { + mbuf_free(&out); + uri->p = NULL; + uri->len = 0; + } + return result; +} #ifdef MG_MODULE_LINES #line 1 "mongoose/src/http.c" #endif diff --git a/mongoose.h b/mongoose.h index 76911e1c..766fc1ff 100644 --- a/mongoose.h +++ b/mongoose.h @@ -3843,6 +3843,21 @@ int mg_parse_uri(const struct mg_str uri, struct mg_str *scheme, unsigned int *port, struct mg_str *path, struct mg_str *query, struct mg_str *fragment); +/* + * Assemble URI from parts. Any of the inputs can be NULL or zero-length mg_str. + * + * If normalize_path is true, path is normalized by resolving relative refs. + * + * Result is a heap-allocated string (uri->p must be free()d after use). + * + * Returns 0 on success, -1 on error. + */ +int mg_assemble_uri(const struct mg_str *scheme, const struct mg_str *user_info, + const struct mg_str *host, unsigned int port, + const struct mg_str *path, const struct mg_str *query, + const struct mg_str *fragment, int normalize_path, + struct mg_str *uri); + int mg_normalize_uri_path(const struct mg_str *in, struct mg_str *out); #ifdef __cplusplus From 663e928d65e8cefd0f2597d0cdb9143be9731489 Mon Sep 17 00:00:00 2001 From: Deomid Ryabkov Date: Thu, 27 Apr 2017 17:27:34 +0300 Subject: [PATCH 064/137] Fix mg_strdup_nul PUBLISHED_FROM=25bc4d20016bcb71c4e2e4b7be8d2d0566fdfa2e --- mongoose.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/mongoose.c b/mongoose.c index 568da31c..95fd8e5f 100644 --- a/mongoose.c +++ b/mongoose.c @@ -1406,12 +1406,12 @@ static struct mg_str mg_strdup_common(const struct mg_str s, struct mg_str mg_strdup(const struct mg_str s) WEAK; struct mg_str mg_strdup(const struct mg_str s) { - return mg_strdup_common(s, 1 /* NUL-terminate */); + return mg_strdup_common(s, 0 /* NUL-terminate */); } struct mg_str mg_strdup_nul(const struct mg_str s) WEAK; struct mg_str mg_strdup_nul(const struct mg_str s) { - return mg_strdup_common(s, 0 /* NUL-terminate */); + return mg_strdup_common(s, 1 /* NUL-terminate */); } int mg_strcmp(const struct mg_str str1, const struct mg_str str2) WEAK; From ac857d18db62cd267254e50476add79b84119fee Mon Sep 17 00:00:00 2001 From: Ruslan Valiullin Date: Tue, 2 May 2017 16:45:34 +0100 Subject: [PATCH 065/137] Add mg multithreaded example PUBLISHED_FROM=8a3424ba6260b0351d7c06270dc141d804ae7f77 --- examples/multithreaded/Makefile | 3 + examples/multithreaded/multithreaded.c | 124 +++++++++++++++++++++++++ 2 files changed, 127 insertions(+) create mode 100644 examples/multithreaded/Makefile create mode 100644 examples/multithreaded/multithreaded.c diff --git a/examples/multithreaded/Makefile b/examples/multithreaded/Makefile new file mode 100644 index 00000000..c41017da --- /dev/null +++ b/examples/multithreaded/Makefile @@ -0,0 +1,3 @@ +PROG = multithreaded +MODULE_CFLAGS=-DMG_ENABLE_THREADS +include ../examples.mk diff --git a/examples/multithreaded/multithreaded.c b/examples/multithreaded/multithreaded.c new file mode 100644 index 00000000..a3053c81 --- /dev/null +++ b/examples/multithreaded/multithreaded.c @@ -0,0 +1,124 @@ +/* + * Copyright (c) 2014-2017 Cesanta Software Limited + * All rights reserved + */ + +#include "mongoose.h" + +static sig_atomic_t s_received_signal = 0; +static const char *s_http_port = "8000"; +static const int s_num_worker_threads = 5; +static unsigned long s_next_id = 0; + +static void signal_handler(int sig_num) { + signal(sig_num, signal_handler); + s_received_signal = sig_num; +} +static struct mg_serve_http_opts s_http_server_opts; +static sock_t sock[2]; + +// This info is passed to the worker thread +struct work_request { + unsigned long conn_id; // needed to identify the connection where to send the reply + // optionally, more data that could be required by worker +}; + +// This info is passed by the worker thread to mg_broadcast +struct work_result { + unsigned long conn_id; + int sleep_time; +}; + +static void on_work_complete(struct mg_connection *nc, int ev, void *ev_data) { + (void) ev; + char s[32]; + struct mg_connection *c; + for (c = mg_next(nc->mgr, NULL); c != NULL; c = mg_next(nc->mgr, c)) { + if (c->user_data != NULL) { + struct work_result *res = (struct work_result *)ev_data; + if ((unsigned long)c->user_data == res->conn_id) { + sprintf(s, "conn_id:%lu sleep:%d", res->conn_id, res->sleep_time); + mg_send_head(c, 200, strlen(s), "Content-Type: text/plain"); + mg_printf(c, "%s", s); + } + } + } +} + +void *worker_thread_proc(void *param) { + struct mg_mgr *mgr = (struct mg_mgr *) param; + struct work_request req = {0}; + + while (s_received_signal == 0) { + if (read(sock[1], &req, sizeof(req)) < 0) + perror("Reading worker sock"); + int r = rand() % 10; + sleep(r); + struct work_result res = {req.conn_id, r}; + mg_broadcast(mgr, on_work_complete, (void *)&res, sizeof(res)); + } + return NULL; +} + +static void ev_handler(struct mg_connection *nc, int ev, void *ev_data) { + (void) nc; + (void) ev_data; + + switch (ev) { + case MG_EV_ACCEPT: + nc->user_data = (void *)++s_next_id; + break; + case MG_EV_HTTP_REQUEST: { + struct work_request req = {(unsigned long)nc->user_data}; + + if (write(sock[0], &req, sizeof(req)) < 0) + perror("Writing worker sock"); + break; + } + case MG_EV_CLOSE: { + if (nc->user_data) nc->user_data = NULL; + } + } +} + +int main(void) { + struct mg_mgr mgr; + struct mg_connection *nc; + int i; + + if (mg_socketpair(sock, SOCK_STREAM) == 0) { + perror("Opening socket pair"); + exit(1); + } + + signal(SIGTERM, signal_handler); + signal(SIGINT, signal_handler); + + mg_mgr_init(&mgr, NULL); + + nc = mg_bind(&mgr, s_http_port, ev_handler); + if (nc == NULL) { + printf("Failed to create listener\n"); + return 1; + } + + mg_set_protocol_http_websocket(nc); + s_http_server_opts.document_root = "."; // Serve current directory + s_http_server_opts.enable_directory_listing = "no"; + + for (i = 0; i < s_num_worker_threads; i++) { + mg_start_thread(worker_thread_proc, &mgr); + } + + printf("Started on port %s\n", s_http_port); + while (s_received_signal == 0) { + mg_mgr_poll(&mgr, 200); + } + + mg_mgr_free(&mgr); + + closesocket(sock[0]); + closesocket(sock[1]); + + return 0; +} From ddef0654939ee7f0b7eda454f5447351592b512f Mon Sep 17 00:00:00 2001 From: Deomid Ryabkov Date: Tue, 2 May 2017 21:49:07 +0100 Subject: [PATCH 066/137] Enable SNTP on CC3200 PUBLISHED_FROM=cea0fc4db21f5b68fd3e779334989fef84a1637a --- mongoose.c | 29 ++++++++++++++++------------- mongoose.h | 1 + 2 files changed, 17 insertions(+), 13 deletions(-) diff --git a/mongoose.c b/mongoose.c index 95fd8e5f..a0e2637d 100644 --- a/mongoose.c +++ b/mongoose.c @@ -12388,21 +12388,24 @@ time_t HOSTtime() { #endif /* __TI_COMPILER_VERSION__ */ #ifndef __TI_COMPILER_VERSION__ -int _gettimeofday_r(struct _reent *r, struct timeval *tp, void *tzp) { +int _gettimeofday_r(struct _reent *r, struct timeval *tp, void *tz) { #else -int gettimeofday(struct timeval *tp, void *tzp) { +int gettimeofday(struct timeval *tp, void *tz) { #endif - unsigned long long r1 = 0, r2; - /* Achieve two consecutive reads of the same value. */ - do { - r2 = r1; - r1 = PRCMSlowClkCtrFastGet(); - } while (r1 != r2); - /* This is a 32768 Hz counter. */ - tp->tv_sec = (r1 >> 15); - /* 1/32768-th of a second is 30.517578125 microseconds, approx. 31, - * but we round down so it doesn't overflow at 32767 */ - tp->tv_usec = (r1 & 0x7FFF) * 30; + unsigned long sec; + unsigned short msec; + MAP_PRCMRTCGet(&sec, &msec); + tp->tv_sec = sec; + tp->tv_usec = ((unsigned long) msec) * 1000; + return 0; +} + +#ifndef __TI_COMPILER_VERSION__ +int settimeofday(const struct timeval *tv, const struct timezone *tz) { +#else +int settimeofday(const struct timeval *tv, const void *tz) { +#endif + MAP_PRCMRTCSet(tv->tv_sec, tv->tv_usec / 1000); return 0; } diff --git a/mongoose.h b/mongoose.h index 766fc1ff..b9247747 100644 --- a/mongoose.h +++ b/mongoose.h @@ -676,6 +676,7 @@ extern "C" { 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, ...); From 0ea3cdd228f727f79301a196e69f3241b105d082 Mon Sep 17 00:00:00 2001 From: Deomid Ryabkov Date: Wed, 3 May 2017 00:08:11 +0300 Subject: [PATCH 067/137] Implement sending stdout and stderr to MQTT topics Configured via `debug.std{out,err}_topic` PUBLISHED_FROM=66c581c38c5039aa9ecc406f8aac0b7e3c6541fc --- examples/CC3200/cs_dbg.h | 12 ++++---- mongoose.c | 60 +++++++++++++++++++++++----------------- 2 files changed, 41 insertions(+), 31 deletions(-) diff --git a/examples/CC3200/cs_dbg.h b/examples/CC3200/cs_dbg.h index 8e86f92d..e987c427 100644 --- a/examples/CC3200/cs_dbg.h +++ b/examples/CC3200/cs_dbg.h @@ -40,22 +40,22 @@ void cs_log_set_level(enum cs_log_level level); void cs_log_set_file(FILE *file); -extern enum cs_log_level cs_log_level; +extern enum cs_log_level cs_log_threshold; void cs_log_print_prefix(const char *func); void cs_log_printf(const char *fmt, ...); #define LOG(l, x) \ - if (cs_log_level >= l) { \ + if (cs_log_threshold >= l) { \ cs_log_print_prefix(__func__); \ cs_log_printf x; \ } #ifndef CS_NDEBUG -#define DBG(x) \ - if (cs_log_level >= LL_VERBOSE_DEBUG) { \ - cs_log_print_prefix(__func__); \ - cs_log_printf x; \ +#define DBG(x) \ + if (cs_log_threshold >= LL_VERBOSE_DEBUG) { \ + cs_log_print_prefix(__func__); \ + cs_log_printf x; \ } #else /* NDEBUG */ diff --git a/mongoose.c b/mongoose.c index a0e2637d..dd7ba4ee 100644 --- a/mongoose.c +++ b/mongoose.c @@ -228,26 +228,26 @@ void cs_log_set_level(enum cs_log_level level); #if CS_ENABLE_STDIO void cs_log_set_file(FILE *file); -extern enum cs_log_level cs_log_level; -void cs_log_print_prefix(const char *func); +extern enum cs_log_level cs_log_threshold; +void cs_log_print_prefix(enum cs_log_level level, const char *func); void cs_log_printf(const char *fmt, ...); -#define LOG(l, x) \ - do { \ - if (cs_log_level >= l) { \ - cs_log_print_prefix(__func__); \ - cs_log_printf x; \ - } \ +#define LOG(l, x) \ + do { \ + if (cs_log_threshold >= l) { \ + cs_log_print_prefix(l, __func__); \ + cs_log_printf x; \ + } \ } while (0) #ifndef CS_NDEBUG -#define DBG(x) \ - do { \ - if (cs_log_level >= LL_VERBOSE_DEBUG) { \ - cs_log_print_prefix(__func__); \ - cs_log_printf x; \ - } \ +#define DBG(x) \ + do { \ + if (cs_log_threshold >= LL_VERBOSE_DEBUG) { \ + cs_log_print_prefix(LL_VERBOSE_DEBUG, __func__); \ + cs_log_printf x; \ + } \ } while (0) #else /* NDEBUG */ @@ -284,7 +284,7 @@ void cs_log_printf(const char *fmt, ...); /* Amalgamated: #include "common/cs_time.h" */ -enum cs_log_level cs_log_level WEAK = +enum cs_log_level cs_log_threshold WEAK = #if CS_ENABLE_DEBUG LL_VERBOSE_DEBUG; #else @@ -299,12 +299,15 @@ FILE *cs_log_file WEAK = NULL; double cs_log_ts WEAK; #endif -void cs_log_print_prefix(const char *func) WEAK; -void cs_log_print_prefix(const char *func) { +enum cs_log_level cs_log_cur_msg_level WEAK = LL_NONE; + +void cs_log_print_prefix(enum cs_log_level level, const char *func) WEAK; +void cs_log_print_prefix(enum cs_log_level level, const char *func) { char prefix[21]; strncpy(prefix, func, 20); prefix[20] = '\0'; if (cs_log_file == NULL) cs_log_file = stderr; + cs_log_cur_msg_level = level; fprintf(cs_log_file, "%-20s ", prefix); #if CS_LOG_ENABLE_TS_DIFF { @@ -323,6 +326,7 @@ void cs_log_printf(const char *fmt, ...) { va_end(ap); fputc('\n', cs_log_file); fflush(cs_log_file); + cs_log_cur_msg_level = LL_NONE; } void cs_log_set_file(FILE *file) WEAK; @@ -334,7 +338,7 @@ void cs_log_set_file(FILE *file) { void cs_log_set_level(enum cs_log_level level) WEAK; void cs_log_set_level(enum cs_log_level level) { - cs_log_level = level; + cs_log_threshold = level; #if CS_LOG_ENABLE_TS_DIFF && CS_ENABLE_STDIO cs_log_ts = cs_time(); #endif @@ -12797,7 +12801,7 @@ void fs_slfs_set_new_file_size(const char *name, size_t size) { #define SPIFFS_FD_BASE 10 #define SLFS_FD_BASE 100 -#ifndef MG_UART_CHAR_PUT +#if !defined(MG_UART_CHAR_PUT) && !defined(MG_UART_WRITE) #if CS_PLATFORM == CS_P_CC3200 #include #include @@ -12806,7 +12810,7 @@ void fs_slfs_set_new_file_size(const char *name, size_t size) { #include #define MG_UART_CHAR_PUT(fd, c) MAP_UARTCharPut(UARTA0_BASE, c); #else -#define MG_UART_CHAR_PUT(fd, c) +#define MG_UART_WRITE(fd, buf, len) #endif /* CS_PLATFORM == CS_P_CC3200 */ #endif /* !MG_UART_CHAR_PUT */ @@ -13035,7 +13039,6 @@ int write(int fd, const char *buf, unsigned count) { ssize_t _write(int fd, const void *buf, size_t count) { #endif int r = -1; - size_t i = 0; switch (fd_type(fd)) { case FD_INVALID: r = set_errno(EBADF); @@ -13045,11 +13048,18 @@ ssize_t _write(int fd, const void *buf, size_t count) { r = set_errno(EACCES); break; } - for (i = 0; i < count; i++) { - const char c = ((const char *) buf)[i]; - if (c == '\n') MG_UART_CHAR_PUT(fd, '\r'); - MG_UART_CHAR_PUT(fd, c); +#ifdef MG_UART_WRITE + MG_UART_WRITE(fd, buf, count); +#elif defined(MG_UART_CHAR_PUT) + { + size_t i; + for (i = 0; i < count; i++) { + const char c = ((const char *) buf)[i]; + if (c == '\n') MG_UART_CHAR_PUT(fd, '\r'); + MG_UART_CHAR_PUT(fd, c); + } } +#endif r = count; break; } From d7a633bfa3b0f6bd481d9c259e8e3179ca8079a5 Mon Sep 17 00:00:00 2001 From: Deomid Ryabkov Date: Wed, 3 May 2017 13:39:37 +0100 Subject: [PATCH 068/137] Fix timers when polling loop gets delayed Past due timers should be brought forward to restore interval. PUBLISHED_FROM=dbe1b8b98804cf8de81e1dbe814222422363278f --- mongoose.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/mongoose.c b/mongoose.c index dd7ba4ee..25c33930 100644 --- a/mongoose.c +++ b/mongoose.c @@ -14850,7 +14850,7 @@ time_t mg_lwip_if_poll(struct mg_iface *iface, int timeout_ms) { uint32_t mg_lwip_get_poll_delay_ms(struct mg_mgr *mgr) { struct mg_connection *nc; - double now = mg_time(); + double now; double min_timer = 0; int num_timers = 0; mg_ev_mgr_lwip_process_signals(mgr); @@ -14876,7 +14876,10 @@ uint32_t mg_lwip_get_poll_delay_ms(struct mg_mgr *mgr) { } } uint32_t timeout_ms = ~0; + now = mg_time(); if (num_timers > 0) { + /* If we have a timer that is past due, do a poll ASAP. */ + if (min_timer < now) return 0; double timer_timeout_ms = (min_timer - now) * 1000 + 1 /* rounding */; if (timer_timeout_ms < timeout_ms) { timeout_ms = timer_timeout_ms; From c90cffa68861d1eeff814fe873ecf2ae3c5a019d Mon Sep 17 00:00:00 2001 From: Sergey Lyubka Date: Fri, 5 May 2017 10:46:01 +0100 Subject: [PATCH 069/137] Fix docker invocation PUBLISHED_FROM=064b5e508017b0115239fc880f21ca08b9422a25 --- examples/ESP8266_RTOS/build.sh | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/examples/ESP8266_RTOS/build.sh b/examples/ESP8266_RTOS/build.sh index 749d1f15..a7d1e0ec 100755 --- a/examples/ESP8266_RTOS/build.sh +++ b/examples/ESP8266_RTOS/build.sh @@ -1,7 +1,8 @@ #!/bin/bash +REPO=$(cd ../.. && pwd) docker run \ - --rm -i -v $(realpath ${PWD}/../..):/src \ + --rm -i -v $REPO:/src \ --entrypoint=/bin/bash $(cat sdk.version) -l -c -x ' export SDK_PATH=/opt/Espressif/ESP8266_RTOS_SDK; export BIN_PATH=./bin; From a0527a7f0e2456d652237098cf362dcdcf5769a0 Mon Sep 17 00:00:00 2001 From: Sergey Lyubka Date: Fri, 5 May 2017 11:15:20 +0100 Subject: [PATCH 070/137] Fix esp8266 rtos example build PUBLISHED_FROM=80055394237617605c57a07ac29c43d5197cbf5c --- examples/ESP8266_RTOS/user/mongoose.h | 5895 +------------------------ 1 file changed, 1 insertion(+), 5894 deletions(-) mode change 100644 => 120000 examples/ESP8266_RTOS/user/mongoose.h diff --git a/examples/ESP8266_RTOS/user/mongoose.h b/examples/ESP8266_RTOS/user/mongoose.h deleted file mode 100644 index 4fb82737..00000000 --- a/examples/ESP8266_RTOS/user/mongoose.h +++ /dev/null @@ -1,5894 +0,0 @@ -#ifdef MG_MODULE_LINES -#line 1 "mongoose/src/common.h" -#endif -/* - * Copyright (c) 2004-2013 Sergey Lyubka - * Copyright (c) 2013-2015 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. - * - * Alternatively, you can license this software under a commercial - * license, as set out in . - */ - -#ifndef CS_MONGOOSE_SRC_COMMON_H_ -#define CS_MONGOOSE_SRC_COMMON_H_ - -#define MG_VERSION "6.7" - -/* Local tweaks, applied before any of Mongoose's own headers. */ -#ifdef MG_LOCALS -#include -#endif - -#endif /* CS_MONGOOSE_SRC_COMMON_H_ */ -#ifdef MG_MODULE_LINES -#line 1 "common/platform.h" -#endif -#ifndef CS_COMMON_PLATFORM_H_ -#define CS_COMMON_PLATFORM_H_ - -/* - * For the "custom" platform, includes and dependencies can be - * provided through mg_locals.h. - */ -#define CS_P_CUSTOM 0 -#define CS_P_UNIX 1 -#define CS_P_WINDOWS 2 -#define CS_P_ESP32 15 -#define CS_P_ESP8266 3 -#define CS_P_CC3200 4 -#define CS_P_MSP432 5 -#define CS_P_CC3100 6 -#define CS_P_TM4C129 14 -#define CS_P_MBED 7 -#define CS_P_WINCE 8 -#define CS_P_NXP_LPC 13 -#define CS_P_NXP_KINETIS 9 -#define CS_P_NRF51 12 -#define CS_P_NRF52 10 -#define CS_P_PIC32 11 -#define CS_P_STM32 16 -/* Next id: 17 */ - -/* If not specified explicitly, we guess platform by defines. */ -#ifndef CS_PLATFORM - -#if defined(TARGET_IS_MSP432P4XX) || defined(__MSP432P401R__) -#define CS_PLATFORM CS_P_MSP432 -#elif defined(cc3200) -#define CS_PLATFORM CS_P_CC3200 -#elif defined(__unix__) || defined(__APPLE__) -#define CS_PLATFORM CS_P_UNIX -#elif defined(WINCE) -#define CS_PLATFORM CS_P_WINCE -#elif defined(_WIN32) -#define CS_PLATFORM CS_P_WINDOWS -#elif defined(__MBED__) -#define CS_PLATFORM CS_P_MBED -#elif defined(__USE_LPCOPEN) -#define CS_PLATFORM CS_P_NXP_LPC -#elif defined(FRDM_K64F) || defined(FREEDOM) -#define CS_PLATFORM CS_P_NXP_KINETIS -#elif defined(PIC32) -#define CS_PLATFORM CS_P_PIC32 -#elif defined(ESP_PLATFORM) -#define CS_PLATFORM CS_P_ESP32 -#elif defined(ICACHE_FLASH) -#define CS_PLATFORM CS_P_ESP8266 -#elif defined(TARGET_IS_TM4C129_RA0) || defined(TARGET_IS_TM4C129_RA1) || \ - defined(TARGET_IS_TM4C129_RA2) -#define CS_PLATFORM CS_P_TM4C129 -#elif defined(STM32) -#define CS_PLATFORM CS_P_STM32 -#endif - -#ifndef CS_PLATFORM -#error "CS_PLATFORM is not specified and we couldn't guess it." -#endif - -#endif /* !defined(CS_PLATFORM) */ - -#define MG_NET_IF_SOCKET 1 -#define MG_NET_IF_SIMPLELINK 2 -#define MG_NET_IF_LWIP_LOW_LEVEL 3 -#define MG_NET_IF_PIC32 4 - -#define MG_SSL_IF_OPENSSL 1 -#define MG_SSL_IF_MBEDTLS 2 -#define MG_SSL_IF_SIMPLELINK 3 - -/* Amalgamated: #include "common/platforms/platform_unix.h" */ -/* Amalgamated: #include "common/platforms/platform_windows.h" */ -/* Amalgamated: #include "common/platforms/platform_esp32.h" */ -/* Amalgamated: #include "common/platforms/platform_esp8266.h" */ -/* Amalgamated: #include "common/platforms/platform_cc3200.h" */ -/* Amalgamated: #include "common/platforms/platform_cc3100.h" */ -/* Amalgamated: #include "common/platforms/platform_mbed.h" */ -/* Amalgamated: #include "common/platforms/platform_nrf51.h" */ -/* Amalgamated: #include "common/platforms/platform_nrf52.h" */ -/* Amalgamated: #include "common/platforms/platform_wince.h" */ -/* Amalgamated: #include "common/platforms/platform_nxp_lpc.h" */ -/* Amalgamated: #include "common/platforms/platform_nxp_kinetis.h" */ -/* Amalgamated: #include "common/platforms/platform_pic32.h" */ -/* Amalgamated: #include "common/platforms/platform_stm32.h" */ - -/* Common stuff */ - -#if !defined(WEAK) -#if (defined(__GNUC__) || defined(__TI_COMPILER_VERSION__)) && !defined(_WIN32) -#define WEAK __attribute__((weak)) -#else -#define WEAK -#endif -#endif - -#ifdef __GNUC__ -#define NORETURN __attribute__((noreturn)) -#define NOINLINE __attribute__((noinline)) -#define WARN_UNUSED_RESULT __attribute__((warn_unused_result)) -#define NOINSTR __attribute__((no_instrument_function)) -#define DO_NOT_WARN_UNUSED __attribute__((unused)) -#else -#define NORETURN -#define NOINLINE -#define WARN_UNUSED_RESULT -#define NOINSTR -#define DO_NOT_WARN_UNUSED -#endif /* __GNUC__ */ - -#ifndef ARRAY_SIZE -#define ARRAY_SIZE(array) (sizeof(array) / sizeof(array[0])) -#endif - -#endif /* CS_COMMON_PLATFORM_H_ */ -#ifdef MG_MODULE_LINES -#line 1 "common/platforms/platform_windows.h" -#endif -#ifndef CS_COMMON_PLATFORMS_PLATFORM_WINDOWS_H_ -#define CS_COMMON_PLATFORMS_PLATFORM_WINDOWS_H_ -#if CS_PLATFORM == CS_P_WINDOWS - -/* - * MSVC++ 14.0 _MSC_VER == 1900 (Visual Studio 2015) - * MSVC++ 12.0 _MSC_VER == 1800 (Visual Studio 2013) - * MSVC++ 11.0 _MSC_VER == 1700 (Visual Studio 2012) - * MSVC++ 10.0 _MSC_VER == 1600 (Visual Studio 2010) - * MSVC++ 9.0 _MSC_VER == 1500 (Visual Studio 2008) - * MSVC++ 8.0 _MSC_VER == 1400 (Visual Studio 2005) - * MSVC++ 7.1 _MSC_VER == 1310 (Visual Studio 2003) - * MSVC++ 7.0 _MSC_VER == 1300 - * MSVC++ 6.0 _MSC_VER == 1200 - * MSVC++ 5.0 _MSC_VER == 1100 - */ -#ifdef _MSC_VER -#pragma warning(disable : 4127) /* FD_SET() emits warning, disable it */ -#pragma warning(disable : 4204) /* missing c99 support */ -#endif - -#ifndef _WINSOCK_DEPRECATED_NO_WARNINGS -#define _WINSOCK_DEPRECATED_NO_WARNINGS 1 -#endif - -#ifndef _CRT_SECURE_NO_WARNINGS -#define _CRT_SECURE_NO_WARNINGS -#endif - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#ifdef _MSC_VER -#pragma comment(lib, "ws2_32.lib") /* Linking with winsock library */ -#endif - -#include -#include -#include -#include - -#if defined(_MSC_VER) && _MSC_VER >= 1800 -#define strdup _strdup -#endif - -#ifndef EINPROGRESS -#define EINPROGRESS WSAEINPROGRESS -#endif -#ifndef EWOULDBLOCK -#define EWOULDBLOCK WSAEWOULDBLOCK -#endif -#ifndef __func__ -#define STRX(x) #x -#define STR(x) STRX(x) -#define __func__ __FILE__ ":" STR(__LINE__) -#endif -#define snprintf _snprintf -#define vsnprintf _vsnprintf -#define sleep(x) Sleep((x) *1000) -#define to64(x) _atoi64(x) -#if !defined(__MINGW32__) && !defined(__MINGW64__) -#define popen(x, y) _popen((x), (y)) -#define pclose(x) _pclose(x) -#define fileno _fileno -#endif -#define rmdir _rmdir -#if defined(_MSC_VER) && _MSC_VER >= 1400 -#define fseeko(x, y, z) _fseeki64((x), (y), (z)) -#else -#define fseeko(x, y, z) fseek((x), (y), (z)) -#endif -#if defined(_MSC_VER) && _MSC_VER <= 1200 -typedef unsigned long uintptr_t; -typedef long intptr_t; -#endif -typedef int socklen_t; -#if _MSC_VER >= 1700 -#include -#else -typedef signed char int8_t; -typedef unsigned char uint8_t; -typedef int int32_t; -typedef unsigned int uint32_t; -typedef short int16_t; -typedef unsigned short uint16_t; -typedef __int64 int64_t; -typedef unsigned __int64 uint64_t; -#endif -typedef SOCKET sock_t; -typedef uint32_t in_addr_t; -#ifndef UINT16_MAX -#define UINT16_MAX 65535 -#endif -#ifndef UINT32_MAX -#define UINT32_MAX 4294967295 -#endif -#ifndef pid_t -#define pid_t HANDLE -#endif -#define INT64_FMT "I64d" -#define INT64_X_FMT "I64x" -#define SIZE_T_FMT "Iu" -typedef struct _stati64 cs_stat_t; -#ifndef S_ISDIR -#define S_ISDIR(x) (((x) &_S_IFMT) == _S_IFDIR) -#endif -#ifndef S_ISREG -#define S_ISREG(x) (((x) &_S_IFMT) == _S_IFREG) -#endif -#define DIRSEP '\\' -#define CS_DEFINE_DIRENT - -#ifndef va_copy -#ifdef __va_copy -#define va_copy __va_copy -#else -#define va_copy(x, y) (x) = (y) -#endif -#endif - -#ifndef MG_MAX_HTTP_REQUEST_SIZE -#define MG_MAX_HTTP_REQUEST_SIZE 8192 -#endif - -#ifndef MG_MAX_HTTP_SEND_MBUF -#define MG_MAX_HTTP_SEND_MBUF 4096 -#endif - -#ifndef MG_MAX_HTTP_HEADERS -#define MG_MAX_HTTP_HEADERS 40 -#endif - -#ifndef CS_ENABLE_STDIO -#define CS_ENABLE_STDIO 1 -#endif - -#ifndef MG_ENABLE_BROADCAST -#define MG_ENABLE_BROADCAST 1 -#endif - -#ifndef MG_ENABLE_DIRECTORY_LISTING -#define MG_ENABLE_DIRECTORY_LISTING 1 -#endif - -#ifndef MG_ENABLE_FILESYSTEM -#define MG_ENABLE_FILESYSTEM 1 -#endif - -#ifndef MG_ENABLE_HTTP_CGI -#define MG_ENABLE_HTTP_CGI MG_ENABLE_FILESYSTEM -#endif - -#ifndef MG_NET_IF -#define MG_NET_IF MG_NET_IF_SOCKET -#endif - -#endif /* CS_PLATFORM == CS_P_WINDOWS */ -#endif /* CS_COMMON_PLATFORMS_PLATFORM_WINDOWS_H_ */ -#ifdef MG_MODULE_LINES -#line 1 "common/platforms/platform_unix.h" -#endif -#ifndef CS_COMMON_PLATFORMS_PLATFORM_UNIX_H_ -#define CS_COMMON_PLATFORMS_PLATFORM_UNIX_H_ -#if CS_PLATFORM == CS_P_UNIX - -#ifndef _XOPEN_SOURCE -#define _XOPEN_SOURCE 600 -#endif - -/* wants this for C++ */ -#ifndef __STDC_FORMAT_MACROS -#define __STDC_FORMAT_MACROS -#endif - -/* C++ wants that for INT64_MAX */ -#ifndef __STDC_LIMIT_MACROS -#define __STDC_LIMIT_MACROS -#endif - -/* Enable fseeko() and ftello() functions */ -#ifndef _LARGEFILE_SOURCE -#define _LARGEFILE_SOURCE -#endif - -/* Enable 64-bit file offsets */ -#ifndef _FILE_OFFSET_BITS -#define _FILE_OFFSET_BITS 64 -#endif - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#ifdef __APPLE__ -#include -#ifndef BYTE_ORDER -#define LITTLE_ENDIAN __DARWIN_LITTLE_ENDIAN -#define BIG_ENDIAN __DARWIN_BIG_ENDIAN -#define PDP_ENDIAN __DARWIN_PDP_ENDIAN -#define BYTE_ORDER __DARWIN_BYTE_ORDER -#endif -#endif - -/* - * osx correctly avoids defining strtoll when compiling in strict ansi mode. - * c++ 11 standard defines strtoll as well. - * We require strtoll, and if your embedded pre-c99 compiler lacks one, please - * implement a shim. - */ -#if !(defined(__cplusplus) && __cplusplus >= 201103L) && \ - !(defined(__DARWIN_C_LEVEL) && __DARWIN_C_LEVEL >= 200809L) -long long strtoll(const char *, char **, int); -#endif - -typedef int sock_t; -#define INVALID_SOCKET (-1) -#define SIZE_T_FMT "zu" -typedef struct stat cs_stat_t; -#define DIRSEP '/' -#define to64(x) strtoll(x, NULL, 10) -#define INT64_FMT PRId64 -#define INT64_X_FMT PRIx64 - -#ifndef __cdecl -#define __cdecl -#endif - -#ifndef va_copy -#ifdef __va_copy -#define va_copy __va_copy -#else -#define va_copy(x, y) (x) = (y) -#endif -#endif - -#define closesocket(x) close(x) - -#ifndef MG_MAX_HTTP_REQUEST_SIZE -#define MG_MAX_HTTP_REQUEST_SIZE 8192 -#endif - -#ifndef MG_MAX_HTTP_SEND_MBUF -#define MG_MAX_HTTP_SEND_MBUF 4096 -#endif - -#ifndef MG_MAX_HTTP_HEADERS -#define MG_MAX_HTTP_HEADERS 40 -#endif - -#ifndef CS_ENABLE_STDIO -#define CS_ENABLE_STDIO 1 -#endif - -#ifndef MG_ENABLE_BROADCAST -#define MG_ENABLE_BROADCAST 1 -#endif - -#ifndef MG_ENABLE_DIRECTORY_LISTING -#define MG_ENABLE_DIRECTORY_LISTING 1 -#endif - -#ifndef MG_ENABLE_FILESYSTEM -#define MG_ENABLE_FILESYSTEM 1 -#endif - -#ifndef MG_ENABLE_HTTP_CGI -#define MG_ENABLE_HTTP_CGI MG_ENABLE_FILESYSTEM -#endif - -#ifndef MG_NET_IF -#define MG_NET_IF MG_NET_IF_SOCKET -#endif - -#endif /* CS_PLATFORM == CS_P_UNIX */ -#endif /* CS_COMMON_PLATFORMS_PLATFORM_UNIX_H_ */ -#ifdef MG_MODULE_LINES -#line 1 "common/platforms/platform_esp32.h" -#endif -/* - * Copyright (c) 2014-2016 Cesanta Software Limited - * All rights reserved - */ - -#ifndef CS_COMMON_PLATFORMS_PLATFORM_ESP32_H_ -#define CS_COMMON_PLATFORMS_PLATFORM_ESP32_H_ -#if CS_PLATFORM == CS_P_ESP32 - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#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 _FILE_OFFSET_BITS 32 - -#define MG_LWIP 1 - -#ifndef MG_NET_IF -#define MG_NET_IF MG_NET_IF_SOCKET -#endif - -#ifndef CS_ENABLE_STDIO -#define CS_ENABLE_STDIO 1 -#endif - -#endif /* CS_PLATFORM == CS_P_ESP32 */ -#endif /* CS_COMMON_PLATFORMS_PLATFORM_ESP32_H_ */ -#ifdef MG_MODULE_LINES -#line 1 "common/platforms/platform_esp8266.h" -#endif -/* - * Copyright (c) 2014-2016 Cesanta Software Limited - * All rights reserved - */ - -#ifndef CS_COMMON_PLATFORMS_PLATFORM_ESP8266_H_ -#define CS_COMMON_PLATFORMS_PLATFORM_ESP8266_H_ -#if CS_PLATFORM == CS_P_ESP8266 - -#include -#include -#include -#include -#include -#include -#include -#include - -#define SIZE_T_FMT "u" -typedef struct stat cs_stat_t; -#define DIRSEP '/' -#define CS_DEFINE_DIRENT - -#define to64(x) strtoll(x, NULL, 10) -#define INT64_FMT PRId64 -#define INT64_X_FMT PRIx64 -#define __cdecl -#define _FILE_OFFSET_BITS 32 - -#ifndef RTOS_SDK -#define fileno(x) -1 -#endif - -#define MG_LWIP 1 - -/* struct timeval is defined in sys/time.h. */ -#define LWIP_TIMEVAL_PRIVATE 0 - -#ifndef MG_NET_IF -#include -#if LWIP_SOCKET /* RTOS SDK has LWIP sockets */ -#define MG_NET_IF MG_NET_IF_SOCKET -#else -#define MG_NET_IF MG_NET_IF_LWIP_LOW_LEVEL -#endif -#endif - -#ifndef CS_ENABLE_STDIO -#define CS_ENABLE_STDIO 1 -#endif - -#endif /* CS_PLATFORM == CS_P_ESP8266 */ -#endif /* CS_COMMON_PLATFORMS_PLATFORM_ESP8266_H_ */ -#ifdef MG_MODULE_LINES -#line 1 "common/platforms/platform_cc3100.h" -#endif -/* - * Copyright (c) 2014-2016 Cesanta Software Limited - * All rights reserved - */ - -#ifndef CS_COMMON_PLATFORMS_PLATFORM_CC3100_H_ -#define CS_COMMON_PLATFORMS_PLATFORM_CC3100_H_ -#if CS_PLATFORM == CS_P_CC3100 - -#include -#include -#include -#include -#include -#include -#include - -#define MG_NET_IF MG_NET_IF_SIMPLELINK -#define MG_SSL_IF MG_SSL_IF_SIMPLELINK - -/* - * CC3100 SDK and STM32 SDK include headers w/out path, just like - * #include "simplelink.h". As result, we have to add all required directories - * into Makefile IPATH and do the same thing (include w/out path) - */ - -#include -#include -#undef timeval - -typedef int sock_t; -#define INVALID_SOCKET (-1) - -#define to64(x) strtoll(x, NULL, 10) -#define INT64_FMT PRId64 -#define INT64_X_FMT PRIx64 -#define SIZE_T_FMT "u" - -#define SOMAXCONN 8 - -const char *inet_ntop(int af, const void *src, char *dst, socklen_t size); -char *inet_ntoa(struct in_addr in); -int inet_pton(int af, const char *src, void *dst); - -#endif /* CS_PLATFORM == CS_P_CC3100 */ -#endif /* CS_COMMON_PLATFORMS_PLATFORM_CC3100_H_ */ -#ifdef MG_MODULE_LINES -#line 1 "common/platforms/platform_cc3200.h" -#endif -/* - * Copyright (c) 2014-2016 Cesanta Software Limited - * All rights reserved - */ - -#ifndef CS_COMMON_PLATFORMS_PLATFORM_CC3200_H_ -#define CS_COMMON_PLATFORMS_PLATFORM_CC3200_H_ -#if CS_PLATFORM == CS_P_CC3200 - -#include -#include -#include -#include -#include -#include -#include - -#ifndef __TI_COMPILER_VERSION__ -#include -#include -#endif - -#define MG_NET_IF MG_NET_IF_SIMPLELINK -#define MG_SSL_IF MG_SSL_IF_SIMPLELINK - -/* Only SPIFFS supports directories, SLFS does not. */ -#if defined(CC3200_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 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); -#define stat(a, b) _stat(a, b) - -#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) - -/* As of 5.2.7, TI compiler does not support va_copy() yet. */ -#define va_copy(apc, ap) ((apc) = (ap)) - -#endif /* __TI_COMPILER_VERSION__ */ - -#ifdef CC3200_FS_SLFS -#define MG_FS_SLFS -#endif - -#if (defined(CC3200_FS_SPIFFS) || defined(CC3200_FS_SLFS)) && \ - !defined(MG_ENABLE_FILESYSTEM) -#define MG_ENABLE_FILESYSTEM 1 -#define CS_DEFINE_DIRENT -#endif - -#ifndef CS_ENABLE_STDIO -#define CS_ENABLE_STDIO 1 -#endif - -#ifdef __cplusplus -} -#endif - -#endif /* CS_PLATFORM == CS_P_CC3200 */ -#endif /* CS_COMMON_PLATFORMS_PLATFORM_CC3200_H_ */ -#ifdef MG_MODULE_LINES -#line 1 "common/platforms/platform_msp432.h" -#endif -/* - * Copyright (c) 2014-2016 Cesanta Software Limited - * All rights reserved - */ - -#ifndef CS_COMMON_PLATFORMS_PLATFORM_MSP432_H_ -#define CS_COMMON_PLATFORMS_PLATFORM_MSP432_H_ -#if CS_PLATFORM == CS_P_MSP432 - -#include -#include -#include -#include -#include -#include -#include - -#ifndef __TI_COMPILER_VERSION__ -#include -#include -#endif - -#define MG_NET_IF MG_NET_IF_SIMPLELINK -#define MG_SSL_IF MG_SSL_IF_SIMPLELINK - -/* 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); -#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); -#define stat(a, b) _stat(a, b) - -#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) - -/* As of 5.2.7, TI compiler does not support va_copy() yet. */ -#define va_copy(apc, ap) ((apc) = (ap)) - -#endif /* __TI_COMPILER_VERSION__ */ - -#ifndef CS_ENABLE_STDIO -#define CS_ENABLE_STDIO 1 -#endif - -#if (defined(CC3200_FS_SPIFFS) || defined(CC3200_FS_SLFS)) && \ - !defined(MG_ENABLE_FILESYSTEM) -#define MG_ENABLE_FILESYSTEM 1 -#endif - -#ifdef __cplusplus -} -#endif - -#endif /* CS_PLATFORM == CS_P_MSP432 */ -#endif /* CS_COMMON_PLATFORMS_PLATFORM_MSP432_H_ */ -#ifdef MG_MODULE_LINES -#line 1 "common/platforms/platform_tm4c129.h" -#endif -/* - * Copyright (c) 2014-2016 Cesanta Software Limited - * All rights reserved - */ - -#ifndef CS_COMMON_PLATFORMS_PLATFORM_TM4C129_H_ -#define CS_COMMON_PLATFORMS_PLATFORM_TM4C129_H_ -#if CS_PLATFORM == CS_P_TM4C129 - -#include -#include -#include -#include -#include -#include -#include - -#ifndef __TI_COMPILER_VERSION__ -#include -#include -#endif - -#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 - -#ifndef MG_NET_IF -#include -#if LWIP_SOCKET -#define MG_NET_IF MG_NET_IF_SOCKET -#else -#define MG_NET_IF MG_NET_IF_LWIP_LOW_LEVEL -#endif -#define MG_LWIP 1 -#elif MG_NET_IF == MG_NET_IF_SIMPLELINK -#include "common/platforms/simplelink/cs_simplelink.h" -#endif - -#ifndef CS_ENABLE_STDIO -#define CS_ENABLE_STDIO 1 -#endif - -#ifdef __TI_COMPILER_VERSION__ -/* As of 5.2.8, TI compiler does not support va_copy() yet. */ -#define va_copy(apc, ap) ((apc) = (ap)) -#endif /* __TI_COMPILER_VERSION__ */ - -#ifdef __cplusplus -} -#endif - -#endif /* CS_PLATFORM == CS_P_TM4C129 */ -#endif /* CS_COMMON_PLATFORMS_PLATFORM_TM4C129_H_ */ -#ifdef MG_MODULE_LINES -#line 1 "common/platforms/platform_mbed.h" -#endif -/* - * Copyright (c) 2014-2016 Cesanta Software Limited - * All rights reserved - */ - -#ifndef CS_COMMON_PLATFORMS_PLATFORM_MBED_H_ -#define CS_COMMON_PLATFORMS_PLATFORM_MBED_H_ -#if CS_PLATFORM == CS_P_MBED - -/* - * mbed.h contains C++ code (e.g. templates), thus, it should be processed - * only if included directly to startup file (ex: main.cpp) - */ -#ifdef __cplusplus -/* Amalgamated: #include "mbed.h" */ -#endif /* __cplusplus */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -typedef struct stat cs_stat_t; -#define DIRSEP '/' - -#ifndef CS_ENABLE_STDIO -#define CS_ENABLE_STDIO 1 -#endif - -/* - * mbed can be compiled with the ARM compiler which - * just doesn't come with a gettimeofday shim - * because it's a BSD API and ARM targets embedded - * non-unix platforms. - */ -#if defined(__ARMCC_VERSION) || defined(__ICCARM__) -#define _TIMEVAL_DEFINED -#define gettimeofday _gettimeofday - -/* copied from GCC on ARM; for some reason useconds are signed */ -typedef long suseconds_t; /* microseconds (signed) */ -struct timeval { - time_t tv_sec; /* seconds */ - suseconds_t tv_usec; /* and microseconds */ -}; - -#endif - -#if MG_NET_IF == MG_NET_IF_SIMPLELINK - -#define MG_SIMPLELINK_NO_OSI 1 - -#include - -typedef int sock_t; -#define INVALID_SOCKET (-1) - -#define to64(x) strtoll(x, NULL, 10) -#define INT64_FMT PRId64 -#define INT64_X_FMT PRIx64 -#define SIZE_T_FMT "u" - -#define SOMAXCONN 8 - -const char *inet_ntop(int af, const void *src, char *dst, socklen_t size); -char *inet_ntoa(struct in_addr in); -int inet_pton(int af, const char *src, void *dst); -int inet_aton(const char *cp, struct in_addr *inp); -in_addr_t inet_addr(const char *cp); - -#endif /* MG_NET_IF == MG_NET_IF_SIMPLELINK */ - -#endif /* CS_PLATFORM == CS_P_MBED */ -#endif /* CS_COMMON_PLATFORMS_PLATFORM_MBED_H_ */ -#ifdef MG_MODULE_LINES -#line 1 "common/platforms/platform_nrf51.h" -#endif -/* - * Copyright (c) 2014-2016 Cesanta Software Limited - * All rights reserved - */ -#ifndef CS_COMMON_PLATFORMS_PLATFORM_NRF51_H_ -#define CS_COMMON_PLATFORMS_PLATFORM_NRF51_H_ -#if CS_PLATFORM == CS_P_NRF51 - -#include -#include -#include -#include -#include -#include - -#define to64(x) strtoll(x, NULL, 10) - -#define MG_NET_IF MG_NET_IF_LWIP_LOW_LEVEL -#define MG_LWIP 1 -#define MG_ENABLE_IPV6 1 - -/* - * For ARM C Compiler, make lwip to export `struct timeval`; for other - * compilers, suppress it. - */ -#if !defined(__ARMCC_VERSION) -#define LWIP_TIMEVAL_PRIVATE 0 -#else -struct timeval; -int gettimeofday(struct timeval *tp, void *tzp); -#endif - -#define INT64_FMT PRId64 -#define SIZE_T_FMT "u" - -/* - * ARM C Compiler doesn't have strdup, so we provide it - */ -#define CS_ENABLE_STRDUP defined(__ARMCC_VERSION) - -#endif /* CS_PLATFORM == CS_P_NRF51 */ -#endif /* CS_COMMON_PLATFORMS_PLATFORM_NRF51_H_ */ -#ifdef MG_MODULE_LINES -#line 1 "common/platforms/platform_nrf52.h" -#endif -/* - * Copyright (c) 2014-2016 Cesanta Software Limited - * All rights reserved - */ -#ifndef CS_COMMON_PLATFORMS_PLATFORM_NRF52_H_ -#define CS_COMMON_PLATFORMS_PLATFORM_NRF52_H_ -#if CS_PLATFORM == CS_P_NRF52 - -#include -#include -#include -#include -#include -#include -#include - -#define to64(x) strtoll(x, NULL, 10) - -#define MG_NET_IF MG_NET_IF_LWIP_LOW_LEVEL -#define MG_LWIP 1 -#define MG_ENABLE_IPV6 1 - -#if !defined(ENOSPC) -#define ENOSPC 28 /* No space left on device */ -#endif - -/* - * For ARM C Compiler, make lwip to export `struct timeval`; for other - * compilers, suppress it. - */ -#if !defined(__ARMCC_VERSION) -#define LWIP_TIMEVAL_PRIVATE 0 -#endif - -#define INT64_FMT PRId64 -#define SIZE_T_FMT "u" - -/* - * ARM C Compiler doesn't have strdup, so we provide it - */ -#define CS_ENABLE_STRDUP defined(__ARMCC_VERSION) - -#endif /* CS_PLATFORM == CS_P_NRF52 */ -#endif /* CS_COMMON_PLATFORMS_PLATFORM_NRF52_H_ */ -#ifdef MG_MODULE_LINES -#line 1 "common/platforms/simplelink/cs_simplelink.h" -#endif -/* - * Copyright (c) 2014-2016 Cesanta Software Limited - * All rights reserved - */ - -#ifndef CS_COMMON_PLATFORMS_SIMPLELINK_CS_SIMPLELINK_H_ -#define CS_COMMON_PLATFORMS_SIMPLELINK_CS_SIMPLELINK_H_ - -/* If simplelink.h is already included, all bets are off. */ -#if defined(MG_NET_IF) && MG_NET_IF == MG_NET_IF_SIMPLELINK && \ - !defined(__SIMPLELINK_H__) - -#include - -#ifndef __TI_COMPILER_VERSION__ -#undef __CONCAT -#undef FD_CLR -#undef FD_ISSET -#undef FD_SET -#undef FD_SETSIZE -#undef FD_ZERO -#undef fd_set -#endif - -/* We want to disable SL_INC_STD_BSD_API_NAMING, so we include user.h ourselves - * and undef it. */ -#define PROVISIONING_API_H_ -#include -#undef PROVISIONING_API_H_ -#undef SL_INC_STD_BSD_API_NAMING - -#include -#include - -/* Now define only the subset of the BSD API that we use. - * Notably, close(), read() and write() are not defined. */ -#define AF_INET SL_AF_INET - -#define socklen_t SlSocklen_t -#define sockaddr SlSockAddr_t -#define sockaddr_in SlSockAddrIn_t -#define in_addr SlInAddr_t - -#define SOCK_STREAM SL_SOCK_STREAM -#define SOCK_DGRAM SL_SOCK_DGRAM - -#define htonl sl_Htonl -#define ntohl sl_Ntohl -#define htons sl_Htons -#define ntohs sl_Ntohs - -#ifndef EACCES -#define EACCES SL_EACCES -#endif -#ifndef EAFNOSUPPORT -#define EAFNOSUPPORT SL_EAFNOSUPPORT -#endif -#ifndef EAGAIN -#define EAGAIN SL_EAGAIN -#endif -#ifndef EBADF -#define EBADF SL_EBADF -#endif -#ifndef EINVAL -#define EINVAL SL_EINVAL -#endif -#ifndef ENOMEM -#define ENOMEM SL_ENOMEM -#endif -#ifndef EWOULDBLOCK -#define EWOULDBLOCK SL_EWOULDBLOCK -#endif - -#define SOMAXCONN 8 - -#ifdef __cplusplus -extern "C" { -#endif - -const char *inet_ntop(int af, const void *src, char *dst, socklen_t size); -char *inet_ntoa(struct in_addr in); -int inet_pton(int af, const char *src, void *dst); - -struct mg_mgr; -struct mg_connection; - -typedef void (*mg_init_cb)(struct mg_mgr *mgr); -bool mg_start_task(int priority, int stack_size, mg_init_cb mg_init); - -void mg_run_in_task(void (*cb)(struct mg_mgr *mgr, void *arg), void *cb_arg); - -int sl_fs_init(void); - -void sl_restart_cb(struct mg_mgr *mgr); - -int sl_set_ssl_opts(struct mg_connection *nc); - -#ifdef __cplusplus -} -#endif - -#endif /* MG_NET_IF == MG_NET_IF_SIMPLELINK && !defined(__SIMPLELINK_H__) */ - -#endif /* CS_COMMON_PLATFORMS_SIMPLELINK_CS_SIMPLELINK_H_ */ -#ifdef MG_MODULE_LINES -#line 1 "common/platforms/platform_wince.h" -#endif -#ifndef CS_COMMON_PLATFORMS_PLATFORM_WINCE_H_ -#define CS_COMMON_PLATFORMS_PLATFORM_WINCE_H_ - -#if CS_PLATFORM == CS_P_WINCE - -/* - * MSVC++ 14.0 _MSC_VER == 1900 (Visual Studio 2015) - * MSVC++ 12.0 _MSC_VER == 1800 (Visual Studio 2013) - * MSVC++ 11.0 _MSC_VER == 1700 (Visual Studio 2012) - * MSVC++ 10.0 _MSC_VER == 1600 (Visual Studio 2010) - * MSVC++ 9.0 _MSC_VER == 1500 (Visual Studio 2008) - * MSVC++ 8.0 _MSC_VER == 1400 (Visual Studio 2005) - * MSVC++ 7.1 _MSC_VER == 1310 (Visual Studio 2003) - * MSVC++ 7.0 _MSC_VER == 1300 - * MSVC++ 6.0 _MSC_VER == 1200 - * MSVC++ 5.0 _MSC_VER == 1100 - */ -#pragma warning(disable : 4127) /* FD_SET() emits warning, disable it */ -#pragma warning(disable : 4204) /* missing c99 support */ - -#ifndef _WINSOCK_DEPRECATED_NO_WARNINGS -#define _WINSOCK_DEPRECATED_NO_WARNINGS 1 -#endif - -#ifndef _CRT_SECURE_NO_WARNINGS -#define _CRT_SECURE_NO_WARNINGS -#endif - -#include -#include -#include -#include -#include -#include - -#pragma comment(lib, "ws2.lib") /* Linking with WinCE winsock library */ - -#include -#include -#include - -#define strdup _strdup - -#ifndef EINPROGRESS -#define EINPROGRESS WSAEINPROGRESS -#endif - -#ifndef EWOULDBLOCK -#define EWOULDBLOCK WSAEWOULDBLOCK -#endif - -#ifndef EAGAIN -#define EAGAIN EWOULDBLOCK -#endif - -#ifndef __func__ -#define STRX(x) #x -#define STR(x) STRX(x) -#define __func__ __FILE__ ":" STR(__LINE__) -#endif - -#define snprintf _snprintf -#define fileno _fileno -#define vsnprintf _vsnprintf -#define sleep(x) Sleep((x) *1000) -#define to64(x) _atoi64(x) -#define rmdir _rmdir - -#if defined(_MSC_VER) && _MSC_VER >= 1400 -#define fseeko(x, y, z) _fseeki64((x), (y), (z)) -#else -#define fseeko(x, y, z) fseek((x), (y), (z)) -#endif - -typedef int socklen_t; - -#if _MSC_VER >= 1700 -#include -#else -typedef signed char int8_t; -typedef unsigned char uint8_t; -typedef int int32_t; -typedef unsigned int uint32_t; -typedef short int16_t; -typedef unsigned short uint16_t; -typedef __int64 int64_t; -typedef unsigned __int64 uint64_t; -#endif - -typedef SOCKET sock_t; -typedef uint32_t in_addr_t; - -#ifndef UINT16_MAX -#define UINT16_MAX 65535 -#endif - -#ifndef UINT32_MAX -#define UINT32_MAX 4294967295 -#endif - -#ifndef pid_t -#define pid_t HANDLE -#endif - -#define INT64_FMT "I64d" -#define INT64_X_FMT "I64x" -/* TODO(alashkin): check if this is correct */ -#define SIZE_T_FMT "u" - -#define DIRSEP '\\' -#define CS_DEFINE_DIRENT - -#ifndef va_copy -#ifdef __va_copy -#define va_copy __va_copy -#else -#define va_copy(x, y) (x) = (y) -#endif -#endif - -#ifndef MG_MAX_HTTP_REQUEST_SIZE -#define MG_MAX_HTTP_REQUEST_SIZE 8192 -#endif - -#ifndef MG_MAX_HTTP_SEND_MBUF -#define MG_MAX_HTTP_SEND_MBUF 4096 -#endif - -#ifndef MG_MAX_HTTP_HEADERS -#define MG_MAX_HTTP_HEADERS 40 -#endif - -#ifndef CS_ENABLE_STDIO -#define CS_ENABLE_STDIO 1 -#endif - -#define abort() DebugBreak(); - -#ifndef BUFSIZ -#define BUFSIZ 4096 -#endif -/* - * Explicitly disabling MG_ENABLE_THREADS for WinCE - * because they are enabled for _WIN32 by default - */ -#ifndef MG_ENABLE_THREADS -#define MG_ENABLE_THREADS 0 -#endif - -#ifndef MG_ENABLE_FILESYSTEM -#define MG_ENABLE_FILESYSTEM 1 -#endif - -#ifndef MG_NET_IF -#define MG_NET_IF MG_NET_IF_SOCKET -#endif - -typedef struct _stati64 { - uint32_t st_mtime; - uint32_t st_size; - uint32_t st_mode; -} cs_stat_t; - -/* - * WinCE 6.0 has a lot of useful definitions in ATL (not windows.h) headers - * use #ifdefs to avoid conflicts - */ - -#ifndef ENOENT -#define ENOENT ERROR_PATH_NOT_FOUND -#endif - -#ifndef EACCES -#define EACCES ERROR_ACCESS_DENIED -#endif - -#ifndef ENOMEM -#define ENOMEM ERROR_NOT_ENOUGH_MEMORY -#endif - -#ifndef _UINTPTR_T_DEFINED -typedef unsigned int *uintptr_t; -#endif - -#define _S_IFREG 2 -#define _S_IFDIR 4 - -#ifndef S_ISDIR -#define S_ISDIR(x) (((x) &_S_IFDIR) != 0) -#endif - -#ifndef S_ISREG -#define S_ISREG(x) (((x) &_S_IFREG) != 0) -#endif - -int open(const char *filename, int oflag, int pmode); -int _wstati64(const wchar_t *path, cs_stat_t *st); -const char *strerror(); - -#endif /* CS_PLATFORM == CS_P_WINCE */ -#endif /* CS_COMMON_PLATFORMS_PLATFORM_WINCE_H_ */ -#ifdef MG_MODULE_LINES -#line 1 "common/platforms/platform_nxp_lpc.h" -#endif -/* - * Copyright (c) 2014-2016 Cesanta Software Limited - * All rights reserved - */ - -#ifndef CS_COMMON_PLATFORMS_PLATFORM_NXP_LPC_H_ -#define CS_COMMON_PLATFORMS_PLATFORM_NXP_LPC_H_ - -#if CS_PLATFORM == CS_P_NXP_LPC - -#include -#include -#include - -#define SIZE_T_FMT "u" -typedef struct stat cs_stat_t; -#define INT64_FMT "lld" -#define INT64_X_FMT "llx" -#define __cdecl - -#define MG_LWIP 1 - -#define MG_NET_IF MG_NET_IF_LWIP_LOW_LEVEL - -/* - * LPCXpress comes with 3 C library implementations: Newlib, NewlibNano and - *Redlib. - * See https://community.nxp.com/message/630860 for more details. - * - * Redlib is the default and lacks certain things, so we provide them. - */ -#ifdef __REDLIB_INTERFACE_VERSION__ - -/* Let LWIP define timeval for us. */ -#define LWIP_TIMEVAL_PRIVATE 1 - -#define va_copy(d, s) __builtin_va_copy(d, s) - -#define CS_ENABLE_TO64 1 -#define to64(x) cs_to64(x) - -#define CS_ENABLE_STRDUP 1 - -#else - -#include -#define LWIP_TIMEVAL_PRIVATE 0 -#define to64(x) strtoll(x, NULL, 10) - -#endif - -#endif /* CS_PLATFORM == CS_P_NXP_LPC */ -#endif /* CS_COMMON_PLATFORMS_PLATFORM_NXP_LPC_H_ */ -#ifdef MG_MODULE_LINES -#line 1 "common/platforms/platform_nxp_kinetis.h" -#endif -/* - * Copyright (c) 2014-2016 Cesanta Software Limited - * All rights reserved - */ - -#ifndef CS_COMMON_PLATFORMS_PLATFORM_NXP_KINETIS_H_ -#define CS_COMMON_PLATFORMS_PLATFORM_NXP_KINETIS_H_ - -#if CS_PLATFORM == CS_P_NXP_KINETIS - -#include -#include -#include -#include - -#define SIZE_T_FMT "u" -typedef struct stat cs_stat_t; -#define to64(x) strtoll(x, NULL, 10) -#define INT64_FMT "lld" -#define INT64_X_FMT "llx" -#define __cdecl - -#define MG_LWIP 1 - -#define MG_NET_IF MG_NET_IF_LWIP_LOW_LEVEL - -/* struct timeval is defined in sys/time.h. */ -#define LWIP_TIMEVAL_PRIVATE 0 - -#endif /* CS_PLATFORM == CS_P_NXP_KINETIS */ -#endif /* CS_COMMON_PLATFORMS_PLATFORM_NXP_KINETIS_H_ */ -#ifdef MG_MODULE_LINES -#line 1 "common/platforms/platform_pic32.h" -#endif -/* - * Copyright (c) 2014-2016 Cesanta Software Limited - * All rights reserved - */ - -#ifndef CS_COMMON_PLATFORMS_PLATFORM_PIC32_H_ -#define CS_COMMON_PLATFORMS_PLATFORM_PIC32_H_ - -#if CS_PLATFORM == CS_P_PIC32 - -#define MG_NET_IF MG_NET_IF_PIC32 - -#include -#include -#include -#include - -#include -#include - -#include - -typedef TCP_SOCKET sock_t; -#define to64(x) strtoll(x, NULL, 10) - -#define SIZE_T_FMT "lu" -#define INT64_FMT "lld" - -#ifndef CS_ENABLE_STDIO -#define CS_ENABLE_STDIO 1 -#endif - -char *inet_ntoa(struct in_addr in); - -#endif /* CS_PLATFORM == CS_P_PIC32 */ - -#endif /* CS_COMMON_PLATFORMS_PLATFORM_PIC32_H_ */ -#ifdef MG_MODULE_LINES -#line 1 "common/platforms/platform_stm32.h" -#endif -/* - * Copyright (c) 2014-2016 Cesanta Software Limited - * All rights reserved - */ - -#ifndef CS_COMMON_PLATFORMS_PLATFORM_STM32_H_ -#define CS_COMMON_PLATFORMS_PLATFORM_STM32_H_ -#if CS_PLATFORM == CS_P_STM32 - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#define to64(x) strtoll(x, NULL, 10) -#define INT64_FMT PRId64 -#define SIZE_T_FMT "u" -typedef struct stat cs_stat_t; -#define DIRSEP '/' - -#ifndef CS_ENABLE_STDIO -#define CS_ENABLE_STDIO 1 -#endif - -#ifndef MG_ENABLE_FILESYSTEM -#define MG_ENABLE_FILESYSTEM 1 -#endif - -#define CS_DEFINE_DIRENT - -#endif /* CS_PLATFORM == CS_P_STM32 */ -#endif /* CS_COMMON_PLATFORMS_PLATFORM_STM32_H_ */ -#ifdef MG_MODULE_LINES -#line 1 "common/platforms/lwip/mg_lwip.h" -#endif -/* - * Copyright (c) 2014-2016 Cesanta Software Limited - * All rights reserved - */ - -#ifndef CS_COMMON_PLATFORMS_LWIP_MG_LWIP_H_ -#define CS_COMMON_PLATFORMS_LWIP_MG_LWIP_H_ - -#ifndef MG_LWIP -#define MG_LWIP 0 -#endif - -#if MG_LWIP - -/* - * When compiling for nRF5x chips with arm-none-eabi-gcc, it has BYTE_ORDER - * already defined, so in order to avoid warnings in lwip, we have to undefine - * it. - * - * TODO: Check if in the future versions of nRF5 SDK that changes. - * Current version of nRF51 SDK: 0.8.0 - * nRF5 SDK: 0.9.0 - */ -#if CS_PLATFORM == CS_P_NRF51 || CS_PLATFORM == CS_P_NRF52 -#undef BYTE_ORDER -#endif - -#include -#include -#include -#include -#include -#include - -#ifndef LWIP_PROVIDE_ERRNO -#include -#endif - -#if LWIP_SOCKET -#include -#else -/* We really need the definitions from sockets.h. */ -#undef LWIP_SOCKET -#define LWIP_SOCKET 1 -#include -#undef LWIP_SOCKET -#define LWIP_SOCKET 0 -#endif - -#define INVALID_SOCKET (-1) -#define SOMAXCONN 10 -typedef int sock_t; - -#if MG_NET_IF == MG_NET_IF_LWIP_LOW_LEVEL -struct mg_mgr; -struct mg_connection; -uint32_t mg_lwip_get_poll_delay_ms(struct mg_mgr *mgr); -void mg_lwip_set_keepalive_params(struct mg_connection *nc, int idle, - int interval, int count); -#endif - -/* For older version of LWIP */ -#ifndef ipX_2_ip -#define ipX_2_ip(x) (x) -#endif - -#endif /* MG_LWIP */ - -#endif /* CS_COMMON_PLATFORMS_LWIP_MG_LWIP_H_ */ -#ifdef MG_MODULE_LINES -#line 1 "common/cs_time.h" -#endif -/* - * Copyright (c) 2014-2016 Cesanta Software Limited - * All rights reserved - */ - -#ifndef CS_COMMON_CS_TIME_H_ -#define CS_COMMON_CS_TIME_H_ - -/* Amalgamated: #include "common/platform.h" */ - -#ifdef __cplusplus -extern "C" { -#endif /* __cplusplus */ - -/* Sub-second granularity time(). */ -double cs_time(void); - -#ifdef __cplusplus -} -#endif /* __cplusplus */ - -#endif /* CS_COMMON_CS_TIME_H_ */ -#ifdef MG_MODULE_LINES -#line 1 "common/mg_str.h" -#endif -/* - * Copyright (c) 2014-2016 Cesanta Software Limited - * All rights reserved - */ - -#ifndef CS_COMMON_MG_STR_H_ -#define CS_COMMON_MG_STR_H_ - -#include - -/* Amalgamated: #include "common/platform.h" */ - -#ifdef __cplusplus -extern "C" { -#endif /* __cplusplus */ - -/* Describes chunk of memory */ -struct mg_str { - const char *p; /* Memory chunk pointer */ - size_t len; /* Memory chunk length */ -}; - -/* - * Helper functions for creating mg_str struct from plain C string. - * `NULL` is allowed and becomes `{NULL, 0}`. - */ -struct mg_str mg_mk_str(const char *s); -struct mg_str mg_mk_str_n(const char *s, size_t len); - -/* Macro for initializing mg_str. */ -#define MG_MK_STR(str_literal) \ - { str_literal, sizeof(str_literal) - 1 } - -/* - * Cross-platform version of `strcmp()` where where first string is - * specified by `struct mg_str`. - */ -int mg_vcmp(const struct mg_str *str2, const char *str1); - -/* - * Cross-platform version of `strncasecmp()` where first string is - * specified by `struct mg_str`. - */ -int mg_vcasecmp(const struct mg_str *str2, const char *str1); - -struct mg_str mg_strdup(const struct mg_str s); -int mg_strcmp(const struct mg_str str1, const struct mg_str str2); -int mg_strncmp(const struct mg_str str1, const struct mg_str str2, size_t n); - -#ifdef __cplusplus -} -#endif /* __cplusplus */ - -#endif /* CS_COMMON_MG_STR_H_ */ -#ifdef MG_MODULE_LINES -#line 1 "common/mbuf.h" -#endif -/* - * Copyright (c) 2015 Cesanta Software Limited - * All rights reserved - */ - -/* - * === Memory Buffers - * - * Mbufs are mutable/growing memory buffers, like C++ strings. - * Mbuf can append data to the end of a buffer or insert data into arbitrary - * position in the middle of a buffer. The buffer grows automatically when - * needed. - */ - -#ifndef CS_COMMON_MBUF_H_ -#define CS_COMMON_MBUF_H_ - -#include -/* Amalgamated: #include "common/platform.h" */ - -#if defined(__cplusplus) -extern "C" { -#endif - -#ifndef MBUF_SIZE_MULTIPLIER -#define MBUF_SIZE_MULTIPLIER 1.5 -#endif - -/* Memory buffer descriptor */ -struct mbuf { - char *buf; /* Buffer pointer */ - size_t len; /* Data length. Data is located between offset 0 and len. */ - size_t size; /* Buffer size allocated by realloc(1). Must be >= len */ -}; - -/* - * Initialises an Mbuf. - * `initial_capacity` specifies the initial capacity of the mbuf. - */ -void mbuf_init(struct mbuf *, size_t initial_capacity); - -/* Frees the space allocated for the mbuffer and resets the mbuf structure. */ -void mbuf_free(struct mbuf *); - -/* - * Appends data to the Mbuf. - * - * Returns the number of bytes appended or 0 if out of memory. - */ -size_t mbuf_append(struct mbuf *, const void *data, size_t data_size); - -/* - * Inserts data at a specified offset in the Mbuf. - * - * Existing data will be shifted forwards and the buffer will - * be grown if necessary. - * Returns the number of bytes inserted. - */ -size_t mbuf_insert(struct mbuf *, size_t, const void *, size_t); - -/* Removes `data_size` bytes from the beginning of the buffer. */ -void mbuf_remove(struct mbuf *, size_t data_size); - -/* - * Resizes an Mbuf. - * - * If `new_size` is smaller than buffer's `len`, the - * resize is not performed. - */ -void mbuf_resize(struct mbuf *, size_t new_size); - -/* Shrinks an Mbuf by resizing its `size` to `len`. */ -void mbuf_trim(struct mbuf *); - -#if defined(__cplusplus) -} -#endif /* __cplusplus */ - -#endif /* CS_COMMON_MBUF_H_ */ -#ifdef MG_MODULE_LINES -#line 1 "common/sha1.h" -#endif -/* - * Copyright (c) 2014 Cesanta Software Limited - * All rights reserved - */ - -#ifndef CS_COMMON_SHA1_H_ -#define CS_COMMON_SHA1_H_ - -#ifndef CS_DISABLE_SHA1 -#define CS_DISABLE_SHA1 0 -#endif - -#if !CS_DISABLE_SHA1 - -/* Amalgamated: #include "common/platform.h" */ - -#ifdef __cplusplus -extern "C" { -#endif /* __cplusplus */ - -typedef struct { - uint32_t state[5]; - uint32_t count[2]; - unsigned char buffer[64]; -} cs_sha1_ctx; - -void cs_sha1_init(cs_sha1_ctx *); -void cs_sha1_update(cs_sha1_ctx *, const unsigned char *data, uint32_t len); -void cs_sha1_final(unsigned char digest[20], cs_sha1_ctx *); -void cs_hmac_sha1(const unsigned char *key, size_t key_len, - const unsigned char *text, size_t text_len, - unsigned char out[20]); -#ifdef __cplusplus -} -#endif /* __cplusplus */ - -#endif /* CS_DISABLE_SHA1 */ - -#endif /* CS_COMMON_SHA1_H_ */ -#ifdef MG_MODULE_LINES -#line 1 "common/md5.h" -#endif -/* - * Copyright (c) 2014 Cesanta Software Limited - * All rights reserved - */ - -#ifndef CS_COMMON_MD5_H_ -#define CS_COMMON_MD5_H_ - -/* Amalgamated: #include "common/platform.h" */ - -#ifndef CS_DISABLE_MD5 -#define CS_DISABLE_MD5 0 -#endif - -#ifdef __cplusplus -extern "C" { -#endif /* __cplusplus */ - -typedef struct MD5Context { - uint32_t buf[4]; - uint32_t bits[2]; - unsigned char in[64]; -} MD5_CTX; - -void MD5_Init(MD5_CTX *c); -void MD5_Update(MD5_CTX *c, const unsigned char *data, size_t len); -void MD5_Final(unsigned char *md, MD5_CTX *c); - -/* - * Return stringified MD5 hash for NULL terminated list of pointer/length pairs. - * A length should be specified as size_t variable. - * Example: - * - * char buf[33]; - * cs_md5(buf, "foo", (size_t) 3, "bar", (size_t) 3, NULL); - */ -char *cs_md5(char buf[33], ...); - -#ifdef __cplusplus -} -#endif /* __cplusplus */ - -#endif /* CS_COMMON_MD5_H_ */ -#ifdef MG_MODULE_LINES -#line 1 "common/base64.h" -#endif -/* - * Copyright (c) 2014 Cesanta Software Limited - * All rights reserved - */ - -#ifndef CS_COMMON_BASE64_H_ -#define CS_COMMON_BASE64_H_ - -#ifndef DISABLE_BASE64 -#define DISABLE_BASE64 0 -#endif - -#if !DISABLE_BASE64 - -#include - -#ifdef __cplusplus -extern "C" { -#endif - -typedef void (*cs_base64_putc_t)(char, void *); - -struct cs_base64_ctx { - /* cannot call it putc because it's a macro on some environments */ - cs_base64_putc_t b64_putc; - unsigned char chunk[3]; - int chunk_size; - void *user_data; -}; - -void cs_base64_init(struct cs_base64_ctx *ctx, cs_base64_putc_t putc, - void *user_data); -void cs_base64_update(struct cs_base64_ctx *ctx, const char *str, size_t len); -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); -int cs_base64_decode(const unsigned char *s, int len, char *dst, int *dec_len); - -#ifdef __cplusplus -} -#endif - -#endif /* DISABLE_BASE64 */ - -#endif /* CS_COMMON_BASE64_H_ */ -#ifdef MG_MODULE_LINES -#line 1 "common/str_util.h" -#endif -/* - * Copyright (c) 2015 Cesanta Software Limited - * All rights reserved - */ - -#ifndef CS_COMMON_STR_UTIL_H_ -#define CS_COMMON_STR_UTIL_H_ - -#include -#include - -/* Amalgamated: #include "common/platform.h" */ - -#ifndef CS_ENABLE_STRDUP -#define CS_ENABLE_STRDUP 0 -#endif - -#ifndef CS_ENABLE_TO64 -#define CS_ENABLE_TO64 0 -#endif - -/* - * Expands to a string representation of its argument: e.g. - * `CS_STRINGIFY_LIT(5) expands to "5"` - */ -#define CS_STRINGIFY_LIT(x) #x - -/* - * Expands to a string representation of its argument, which is allowed - * to be a macro: e.g. - * - * #define FOO 123 - * CS_STRINGIFY_MACRO(FOO) - * - * expands to 123. - */ -#define CS_STRINGIFY_MACRO(x) CS_STRINGIFY_LIT(x) - -#ifdef __cplusplus -extern "C" { -#endif - -size_t c_strnlen(const char *s, size_t maxlen); -int c_snprintf(char *buf, size_t buf_size, const char *format, ...); -int c_vsnprintf(char *buf, size_t buf_size, const char *format, va_list ap); -/* - * Find the first occurrence of find in s, where the search is limited to the - * first slen characters of s. - */ -const char *c_strnstr(const char *s, const char *find, size_t slen); - -/* - * Stringify binary data. Output buffer size must be 2 * size_of_input + 1 - * because each byte of input takes 2 bytes in string representation - * plus 1 byte for the terminating \0 character. - */ -void cs_to_hex(char *to, const unsigned char *p, size_t len); - -/* - * Convert stringified binary data back to binary. - * Does the reverse of `cs_to_hex()`. - */ -void cs_from_hex(char *to, const char *p, size_t len); - -#if CS_ENABLE_STRDUP -char *strdup(const char *src); -#endif - -#if CS_ENABLE_TO64 -#include -/* - * Simple string -> int64 conversion routine. - */ -int64_t cs_to64(const char *s); -#endif - -/* - * Cross-platform version of `strncasecmp()`. - */ -int mg_ncasecmp(const char *s1, const char *s2, size_t len); - -/* - * Cross-platform version of `strcasecmp()`. - */ -int mg_casecmp(const char *s1, const char *s2); - -/* - * Prints message to the buffer. If the buffer is large enough to hold the - * message, it returns buffer. If buffer is to small, it allocates a large - * enough buffer on heap and returns allocated buffer. - * This is a supposed use case: - * - * char buf[5], *p = buf; - * mg_avprintf(&p, sizeof(buf), "%s", "hi there"); - * use_p_somehow(p); - * if (p != buf) { - * free(p); - * } - * - * 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, ...); - -/* Same as mg_asprintf, but takes varargs list. */ -int mg_avprintf(char **buf, size_t size, const char *fmt, va_list ap); - -#ifdef __cplusplus -} -#endif - -#endif /* CS_COMMON_STR_UTIL_H_ */ -#ifdef MG_MODULE_LINES -#line 1 "common/queue.h" -#endif -/* clang-format off */ -/*- - * Copyright (c) 1991, 1993 - * The Regents of the University of California. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 4. Neither the name of the University nor the names of its contributors - * may be used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - * - * @(#)queue.h 8.5 (Berkeley) 8/20/94 - * $FreeBSD$ - */ - -#ifndef _SYS_QUEUE_H_ -#define _SYS_QUEUE_H_ - -/* - * This file defines four types of data structures: singly-linked lists, - * singly-linked tail queues, lists and tail queues. - * - * A singly-linked list is headed by a single forward pointer. The elements - * are singly linked for minimum space and pointer manipulation overhead at - * the expense of O(n) removal for arbitrary elements. New elements can be - * added to the list after an existing element or at the head of the list. - * Elements being removed from the head of the list should use the explicit - * macro for this purpose for optimum efficiency. A singly-linked list may - * only be traversed in the forward direction. Singly-linked lists are ideal - * for applications with large datasets and few or no removals or for - * implementing a LIFO queue. - * - * A singly-linked tail queue is headed by a pair of pointers, one to the - * head of the list and the other to the tail of the list. The elements are - * singly linked for minimum space and pointer manipulation overhead at the - * expense of O(n) removal for arbitrary elements. New elements can be added - * to the list after an existing element, at the head of the list, or at the - * end of the list. Elements being removed from the head of the tail queue - * should use the explicit macro for this purpose for optimum efficiency. - * A singly-linked tail queue may only be traversed in the forward direction. - * Singly-linked tail queues are ideal for applications with large datasets - * and few or no removals or for implementing a FIFO queue. - * - * A list is headed by a single forward pointer (or an array of forward - * pointers for a hash table header). The elements are doubly linked - * so that an arbitrary element can be removed without a need to - * traverse the list. New elements can be added to the list before - * or after an existing element or at the head of the list. A list - * may be traversed in either direction. - * - * A tail queue is headed by a pair of pointers, one to the head of the - * list and the other to the tail of the list. The elements are doubly - * linked so that an arbitrary element can be removed without a need to - * traverse the list. New elements can be added to the list before or - * after an existing element, at the head of the list, or at the end of - * the list. A tail queue may be traversed in either direction. - * - * For details on the use of these macros, see the queue(3) manual page. - * - * - * SLIST LIST STAILQ TAILQ - * _HEAD + + + + - * _CLASS_HEAD + + + + - * _HEAD_INITIALIZER + + + + - * _ENTRY + + + + - * _CLASS_ENTRY + + + + - * _INIT + + + + - * _EMPTY + + + + - * _FIRST + + + + - * _NEXT + + + + - * _PREV - + - + - * _LAST - - + + - * _FOREACH + + + + - * _FOREACH_FROM + + + + - * _FOREACH_SAFE + + + + - * _FOREACH_FROM_SAFE + + + + - * _FOREACH_REVERSE - - - + - * _FOREACH_REVERSE_FROM - - - + - * _FOREACH_REVERSE_SAFE - - - + - * _FOREACH_REVERSE_FROM_SAFE - - - + - * _INSERT_HEAD + + + + - * _INSERT_BEFORE - + - + - * _INSERT_AFTER + + + + - * _INSERT_TAIL - - + + - * _CONCAT - - + + - * _REMOVE_AFTER + - + - - * _REMOVE_HEAD + - + - - * _REMOVE + + + + - * _SWAP + + + + - * - */ -#ifdef QUEUE_MACRO_DEBUG -/* Store the last 2 places the queue element or head was altered */ -struct qm_trace { - unsigned long lastline; - unsigned long prevline; - const char *lastfile; - const char *prevfile; -}; - -#define TRACEBUF struct qm_trace trace; -#define TRACEBUF_INITIALIZER { __LINE__, 0, __FILE__, NULL } , -#define TRASHIT(x) do {(x) = (void *)-1;} while (0) -#define QMD_SAVELINK(name, link) void **name = (void *)&(link) - -#define QMD_TRACE_HEAD(head) do { \ - (head)->trace.prevline = (head)->trace.lastline; \ - (head)->trace.prevfile = (head)->trace.lastfile; \ - (head)->trace.lastline = __LINE__; \ - (head)->trace.lastfile = __FILE__; \ -} while (0) - -#define QMD_TRACE_ELEM(elem) do { \ - (elem)->trace.prevline = (elem)->trace.lastline; \ - (elem)->trace.prevfile = (elem)->trace.lastfile; \ - (elem)->trace.lastline = __LINE__; \ - (elem)->trace.lastfile = __FILE__; \ -} while (0) - -#else -#define QMD_TRACE_ELEM(elem) -#define QMD_TRACE_HEAD(head) -#define QMD_SAVELINK(name, link) -#define TRACEBUF -#define TRACEBUF_INITIALIZER -#define TRASHIT(x) -#endif /* QUEUE_MACRO_DEBUG */ - -#ifdef __cplusplus -/* - * In C++ there can be structure lists and class lists: - */ -#define QUEUE_TYPEOF(type) type -#else -#define QUEUE_TYPEOF(type) struct type -#endif - -/* - * Singly-linked List declarations. - */ -#define SLIST_HEAD(name, type) \ -struct name { \ - struct type *slh_first; /* first element */ \ -} - -#define SLIST_CLASS_HEAD(name, type) \ -struct name { \ - class type *slh_first; /* first element */ \ -} - -#define SLIST_HEAD_INITIALIZER(head) \ - { NULL } - -#define SLIST_ENTRY(type) \ -struct { \ - struct type *sle_next; /* next element */ \ -} - -#define SLIST_CLASS_ENTRY(type) \ -struct { \ - class type *sle_next; /* next element */ \ -} - -/* - * Singly-linked List functions. - */ -#define SLIST_EMPTY(head) ((head)->slh_first == NULL) - -#define SLIST_FIRST(head) ((head)->slh_first) - -#define SLIST_FOREACH(var, head, field) \ - for ((var) = SLIST_FIRST((head)); \ - (var); \ - (var) = SLIST_NEXT((var), field)) - -#define SLIST_FOREACH_FROM(var, head, field) \ - for ((var) = ((var) ? (var) : SLIST_FIRST((head))); \ - (var); \ - (var) = SLIST_NEXT((var), field)) - -#define SLIST_FOREACH_SAFE(var, head, field, tvar) \ - for ((var) = SLIST_FIRST((head)); \ - (var) && ((tvar) = SLIST_NEXT((var), field), 1); \ - (var) = (tvar)) - -#define SLIST_FOREACH_FROM_SAFE(var, head, field, tvar) \ - for ((var) = ((var) ? (var) : SLIST_FIRST((head))); \ - (var) && ((tvar) = SLIST_NEXT((var), field), 1); \ - (var) = (tvar)) - -#define SLIST_FOREACH_PREVPTR(var, varp, head, field) \ - for ((varp) = &SLIST_FIRST((head)); \ - ((var) = *(varp)) != NULL; \ - (varp) = &SLIST_NEXT((var), field)) - -#define SLIST_INIT(head) do { \ - SLIST_FIRST((head)) = NULL; \ -} while (0) - -#define SLIST_INSERT_AFTER(slistelm, elm, field) do { \ - SLIST_NEXT((elm), field) = SLIST_NEXT((slistelm), field); \ - SLIST_NEXT((slistelm), field) = (elm); \ -} while (0) - -#define SLIST_INSERT_HEAD(head, elm, field) do { \ - SLIST_NEXT((elm), field) = SLIST_FIRST((head)); \ - SLIST_FIRST((head)) = (elm); \ -} while (0) - -#define SLIST_NEXT(elm, field) ((elm)->field.sle_next) - -#define SLIST_REMOVE(head, elm, type, field) do { \ - QMD_SAVELINK(oldnext, (elm)->field.sle_next); \ - if (SLIST_FIRST((head)) == (elm)) { \ - SLIST_REMOVE_HEAD((head), field); \ - } \ - else { \ - QUEUE_TYPEOF(type) *curelm = SLIST_FIRST(head); \ - while (SLIST_NEXT(curelm, field) != (elm)) \ - curelm = SLIST_NEXT(curelm, field); \ - SLIST_REMOVE_AFTER(curelm, field); \ - } \ - TRASHIT(*oldnext); \ -} while (0) - -#define SLIST_REMOVE_AFTER(elm, field) do { \ - SLIST_NEXT(elm, field) = \ - SLIST_NEXT(SLIST_NEXT(elm, field), field); \ -} while (0) - -#define SLIST_REMOVE_HEAD(head, field) do { \ - SLIST_FIRST((head)) = SLIST_NEXT(SLIST_FIRST((head)), field); \ -} while (0) - -#define SLIST_SWAP(head1, head2, type) do { \ - QUEUE_TYPEOF(type) *swap_first = SLIST_FIRST(head1); \ - SLIST_FIRST(head1) = SLIST_FIRST(head2); \ - SLIST_FIRST(head2) = swap_first; \ -} while (0) - -/* - * Singly-linked Tail queue declarations. - */ -#define STAILQ_HEAD(name, type) \ -struct name { \ - struct type *stqh_first;/* first element */ \ - struct type **stqh_last;/* addr of last next element */ \ -} - -#define STAILQ_CLASS_HEAD(name, type) \ -struct name { \ - class type *stqh_first; /* first element */ \ - class type **stqh_last; /* addr of last next element */ \ -} - -#define STAILQ_HEAD_INITIALIZER(head) \ - { NULL, &(head).stqh_first } - -#define STAILQ_ENTRY(type) \ -struct { \ - struct type *stqe_next; /* next element */ \ -} - -#define STAILQ_CLASS_ENTRY(type) \ -struct { \ - class type *stqe_next; /* next element */ \ -} - -/* - * Singly-linked Tail queue functions. - */ -#define STAILQ_CONCAT(head1, head2) do { \ - if (!STAILQ_EMPTY((head2))) { \ - *(head1)->stqh_last = (head2)->stqh_first; \ - (head1)->stqh_last = (head2)->stqh_last; \ - STAILQ_INIT((head2)); \ - } \ -} while (0) - -#define STAILQ_EMPTY(head) ((head)->stqh_first == NULL) - -#define STAILQ_FIRST(head) ((head)->stqh_first) - -#define STAILQ_FOREACH(var, head, field) \ - for((var) = STAILQ_FIRST((head)); \ - (var); \ - (var) = STAILQ_NEXT((var), field)) - -#define STAILQ_FOREACH_FROM(var, head, field) \ - for ((var) = ((var) ? (var) : STAILQ_FIRST((head))); \ - (var); \ - (var) = STAILQ_NEXT((var), field)) - -#define STAILQ_FOREACH_SAFE(var, head, field, tvar) \ - for ((var) = STAILQ_FIRST((head)); \ - (var) && ((tvar) = STAILQ_NEXT((var), field), 1); \ - (var) = (tvar)) - -#define STAILQ_FOREACH_FROM_SAFE(var, head, field, tvar) \ - for ((var) = ((var) ? (var) : STAILQ_FIRST((head))); \ - (var) && ((tvar) = STAILQ_NEXT((var), field), 1); \ - (var) = (tvar)) - -#define STAILQ_INIT(head) do { \ - STAILQ_FIRST((head)) = NULL; \ - (head)->stqh_last = &STAILQ_FIRST((head)); \ -} while (0) - -#define STAILQ_INSERT_AFTER(head, tqelm, elm, field) do { \ - if ((STAILQ_NEXT((elm), field) = STAILQ_NEXT((tqelm), field)) == NULL)\ - (head)->stqh_last = &STAILQ_NEXT((elm), field); \ - STAILQ_NEXT((tqelm), field) = (elm); \ -} while (0) - -#define STAILQ_INSERT_HEAD(head, elm, field) do { \ - if ((STAILQ_NEXT((elm), field) = STAILQ_FIRST((head))) == NULL) \ - (head)->stqh_last = &STAILQ_NEXT((elm), field); \ - STAILQ_FIRST((head)) = (elm); \ -} while (0) - -#define STAILQ_INSERT_TAIL(head, elm, field) do { \ - STAILQ_NEXT((elm), field) = NULL; \ - *(head)->stqh_last = (elm); \ - (head)->stqh_last = &STAILQ_NEXT((elm), field); \ -} while (0) - -#define STAILQ_LAST(head, type, field) \ - (STAILQ_EMPTY((head)) ? NULL : \ - __containerof((head)->stqh_last, \ - QUEUE_TYPEOF(type), field.stqe_next)) - -#define STAILQ_NEXT(elm, field) ((elm)->field.stqe_next) - -#define STAILQ_REMOVE(head, elm, type, field) do { \ - QMD_SAVELINK(oldnext, (elm)->field.stqe_next); \ - if (STAILQ_FIRST((head)) == (elm)) { \ - STAILQ_REMOVE_HEAD((head), field); \ - } \ - else { \ - QUEUE_TYPEOF(type) *curelm = STAILQ_FIRST(head); \ - while (STAILQ_NEXT(curelm, field) != (elm)) \ - curelm = STAILQ_NEXT(curelm, field); \ - STAILQ_REMOVE_AFTER(head, curelm, field); \ - } \ - TRASHIT(*oldnext); \ -} while (0) - -#define STAILQ_REMOVE_AFTER(head, elm, field) do { \ - if ((STAILQ_NEXT(elm, field) = \ - STAILQ_NEXT(STAILQ_NEXT(elm, field), field)) == NULL) \ - (head)->stqh_last = &STAILQ_NEXT((elm), field); \ -} while (0) - -#define STAILQ_REMOVE_HEAD(head, field) do { \ - if ((STAILQ_FIRST((head)) = \ - STAILQ_NEXT(STAILQ_FIRST((head)), field)) == NULL) \ - (head)->stqh_last = &STAILQ_FIRST((head)); \ -} while (0) - -#define STAILQ_SWAP(head1, head2, type) do { \ - QUEUE_TYPEOF(type) *swap_first = STAILQ_FIRST(head1); \ - QUEUE_TYPEOF(type) **swap_last = (head1)->stqh_last; \ - STAILQ_FIRST(head1) = STAILQ_FIRST(head2); \ - (head1)->stqh_last = (head2)->stqh_last; \ - STAILQ_FIRST(head2) = swap_first; \ - (head2)->stqh_last = swap_last; \ - if (STAILQ_EMPTY(head1)) \ - (head1)->stqh_last = &STAILQ_FIRST(head1); \ - if (STAILQ_EMPTY(head2)) \ - (head2)->stqh_last = &STAILQ_FIRST(head2); \ -} while (0) - - -/* - * List declarations. - */ -#define LIST_HEAD(name, type) \ -struct name { \ - struct type *lh_first; /* first element */ \ -} - -#define LIST_CLASS_HEAD(name, type) \ -struct name { \ - class type *lh_first; /* first element */ \ -} - -#define LIST_HEAD_INITIALIZER(head) \ - { NULL } - -#define LIST_ENTRY(type) \ -struct { \ - struct type *le_next; /* next element */ \ - struct type **le_prev; /* address of previous next element */ \ -} - -#define LIST_CLASS_ENTRY(type) \ -struct { \ - class type *le_next; /* next element */ \ - class type **le_prev; /* address of previous next element */ \ -} - -/* - * List functions. - */ - -#if (defined(_KERNEL) && defined(INVARIANTS)) -#define QMD_LIST_CHECK_HEAD(head, field) do { \ - if (LIST_FIRST((head)) != NULL && \ - LIST_FIRST((head))->field.le_prev != \ - &LIST_FIRST((head))) \ - panic("Bad list head %p first->prev != head", (head)); \ -} while (0) - -#define QMD_LIST_CHECK_NEXT(elm, field) do { \ - if (LIST_NEXT((elm), field) != NULL && \ - LIST_NEXT((elm), field)->field.le_prev != \ - &((elm)->field.le_next)) \ - panic("Bad link elm %p next->prev != elm", (elm)); \ -} while (0) - -#define QMD_LIST_CHECK_PREV(elm, field) do { \ - if (*(elm)->field.le_prev != (elm)) \ - panic("Bad link elm %p prev->next != elm", (elm)); \ -} while (0) -#else -#define QMD_LIST_CHECK_HEAD(head, field) -#define QMD_LIST_CHECK_NEXT(elm, field) -#define QMD_LIST_CHECK_PREV(elm, field) -#endif /* (_KERNEL && INVARIANTS) */ - -#define LIST_EMPTY(head) ((head)->lh_first == NULL) - -#define LIST_FIRST(head) ((head)->lh_first) - -#define LIST_FOREACH(var, head, field) \ - for ((var) = LIST_FIRST((head)); \ - (var); \ - (var) = LIST_NEXT((var), field)) - -#define LIST_FOREACH_FROM(var, head, field) \ - for ((var) = ((var) ? (var) : LIST_FIRST((head))); \ - (var); \ - (var) = LIST_NEXT((var), field)) - -#define LIST_FOREACH_SAFE(var, head, field, tvar) \ - for ((var) = LIST_FIRST((head)); \ - (var) && ((tvar) = LIST_NEXT((var), field), 1); \ - (var) = (tvar)) - -#define LIST_FOREACH_FROM_SAFE(var, head, field, tvar) \ - for ((var) = ((var) ? (var) : LIST_FIRST((head))); \ - (var) && ((tvar) = LIST_NEXT((var), field), 1); \ - (var) = (tvar)) - -#define LIST_INIT(head) do { \ - LIST_FIRST((head)) = NULL; \ -} while (0) - -#define LIST_INSERT_AFTER(listelm, elm, field) do { \ - QMD_LIST_CHECK_NEXT(listelm, field); \ - if ((LIST_NEXT((elm), field) = LIST_NEXT((listelm), field)) != NULL)\ - LIST_NEXT((listelm), field)->field.le_prev = \ - &LIST_NEXT((elm), field); \ - LIST_NEXT((listelm), field) = (elm); \ - (elm)->field.le_prev = &LIST_NEXT((listelm), field); \ -} while (0) - -#define LIST_INSERT_BEFORE(listelm, elm, field) do { \ - QMD_LIST_CHECK_PREV(listelm, field); \ - (elm)->field.le_prev = (listelm)->field.le_prev; \ - LIST_NEXT((elm), field) = (listelm); \ - *(listelm)->field.le_prev = (elm); \ - (listelm)->field.le_prev = &LIST_NEXT((elm), field); \ -} while (0) - -#define LIST_INSERT_HEAD(head, elm, field) do { \ - QMD_LIST_CHECK_HEAD((head), field); \ - if ((LIST_NEXT((elm), field) = LIST_FIRST((head))) != NULL) \ - LIST_FIRST((head))->field.le_prev = &LIST_NEXT((elm), field);\ - LIST_FIRST((head)) = (elm); \ - (elm)->field.le_prev = &LIST_FIRST((head)); \ -} while (0) - -#define LIST_NEXT(elm, field) ((elm)->field.le_next) - -#define LIST_PREV(elm, head, type, field) \ - ((elm)->field.le_prev == &LIST_FIRST((head)) ? NULL : \ - __containerof((elm)->field.le_prev, \ - QUEUE_TYPEOF(type), field.le_next)) - -#define LIST_REMOVE(elm, field) do { \ - QMD_SAVELINK(oldnext, (elm)->field.le_next); \ - QMD_SAVELINK(oldprev, (elm)->field.le_prev); \ - QMD_LIST_CHECK_NEXT(elm, field); \ - QMD_LIST_CHECK_PREV(elm, field); \ - if (LIST_NEXT((elm), field) != NULL) \ - LIST_NEXT((elm), field)->field.le_prev = \ - (elm)->field.le_prev; \ - *(elm)->field.le_prev = LIST_NEXT((elm), field); \ - TRASHIT(*oldnext); \ - TRASHIT(*oldprev); \ -} while (0) - -#define LIST_SWAP(head1, head2, type, field) do { \ - QUEUE_TYPEOF(type) *swap_tmp = LIST_FIRST(head1); \ - LIST_FIRST((head1)) = LIST_FIRST((head2)); \ - LIST_FIRST((head2)) = swap_tmp; \ - if ((swap_tmp = LIST_FIRST((head1))) != NULL) \ - swap_tmp->field.le_prev = &LIST_FIRST((head1)); \ - if ((swap_tmp = LIST_FIRST((head2))) != NULL) \ - swap_tmp->field.le_prev = &LIST_FIRST((head2)); \ -} while (0) - -/* - * Tail queue declarations. - */ -#define TAILQ_HEAD(name, type) \ -struct name { \ - struct type *tqh_first; /* first element */ \ - struct type **tqh_last; /* addr of last next element */ \ - TRACEBUF \ -} - -#define TAILQ_CLASS_HEAD(name, type) \ -struct name { \ - class type *tqh_first; /* first element */ \ - class type **tqh_last; /* addr of last next element */ \ - TRACEBUF \ -} - -#define TAILQ_HEAD_INITIALIZER(head) \ - { NULL, &(head).tqh_first, TRACEBUF_INITIALIZER } - -#define TAILQ_ENTRY(type) \ -struct { \ - struct type *tqe_next; /* next element */ \ - struct type **tqe_prev; /* address of previous next element */ \ - TRACEBUF \ -} - -#define TAILQ_CLASS_ENTRY(type) \ -struct { \ - class type *tqe_next; /* next element */ \ - class type **tqe_prev; /* address of previous next element */ \ - TRACEBUF \ -} - -/* - * Tail queue functions. - */ -#if (defined(_KERNEL) && defined(INVARIANTS)) -#define QMD_TAILQ_CHECK_HEAD(head, field) do { \ - if (!TAILQ_EMPTY(head) && \ - TAILQ_FIRST((head))->field.tqe_prev != \ - &TAILQ_FIRST((head))) \ - panic("Bad tailq head %p first->prev != head", (head)); \ -} while (0) - -#define QMD_TAILQ_CHECK_TAIL(head, field) do { \ - if (*(head)->tqh_last != NULL) \ - panic("Bad tailq NEXT(%p->tqh_last) != NULL", (head)); \ -} while (0) - -#define QMD_TAILQ_CHECK_NEXT(elm, field) do { \ - if (TAILQ_NEXT((elm), field) != NULL && \ - TAILQ_NEXT((elm), field)->field.tqe_prev != \ - &((elm)->field.tqe_next)) \ - panic("Bad link elm %p next->prev != elm", (elm)); \ -} while (0) - -#define QMD_TAILQ_CHECK_PREV(elm, field) do { \ - if (*(elm)->field.tqe_prev != (elm)) \ - panic("Bad link elm %p prev->next != elm", (elm)); \ -} while (0) -#else -#define QMD_TAILQ_CHECK_HEAD(head, field) -#define QMD_TAILQ_CHECK_TAIL(head, headname) -#define QMD_TAILQ_CHECK_NEXT(elm, field) -#define QMD_TAILQ_CHECK_PREV(elm, field) -#endif /* (_KERNEL && INVARIANTS) */ - -#define TAILQ_CONCAT(head1, head2, field) do { \ - if (!TAILQ_EMPTY(head2)) { \ - *(head1)->tqh_last = (head2)->tqh_first; \ - (head2)->tqh_first->field.tqe_prev = (head1)->tqh_last; \ - (head1)->tqh_last = (head2)->tqh_last; \ - TAILQ_INIT((head2)); \ - QMD_TRACE_HEAD(head1); \ - QMD_TRACE_HEAD(head2); \ - } \ -} while (0) - -#define TAILQ_EMPTY(head) ((head)->tqh_first == NULL) - -#define TAILQ_FIRST(head) ((head)->tqh_first) - -#define TAILQ_FOREACH(var, head, field) \ - for ((var) = TAILQ_FIRST((head)); \ - (var); \ - (var) = TAILQ_NEXT((var), field)) - -#define TAILQ_FOREACH_FROM(var, head, field) \ - for ((var) = ((var) ? (var) : TAILQ_FIRST((head))); \ - (var); \ - (var) = TAILQ_NEXT((var), field)) - -#define TAILQ_FOREACH_SAFE(var, head, field, tvar) \ - for ((var) = TAILQ_FIRST((head)); \ - (var) && ((tvar) = TAILQ_NEXT((var), field), 1); \ - (var) = (tvar)) - -#define TAILQ_FOREACH_FROM_SAFE(var, head, field, tvar) \ - for ((var) = ((var) ? (var) : TAILQ_FIRST((head))); \ - (var) && ((tvar) = TAILQ_NEXT((var), field), 1); \ - (var) = (tvar)) - -#define TAILQ_FOREACH_REVERSE(var, head, headname, field) \ - for ((var) = TAILQ_LAST((head), headname); \ - (var); \ - (var) = TAILQ_PREV((var), headname, field)) - -#define TAILQ_FOREACH_REVERSE_FROM(var, head, headname, field) \ - for ((var) = ((var) ? (var) : TAILQ_LAST((head), headname)); \ - (var); \ - (var) = TAILQ_PREV((var), headname, field)) - -#define TAILQ_FOREACH_REVERSE_SAFE(var, head, headname, field, tvar) \ - for ((var) = TAILQ_LAST((head), headname); \ - (var) && ((tvar) = TAILQ_PREV((var), headname, field), 1); \ - (var) = (tvar)) - -#define TAILQ_FOREACH_REVERSE_FROM_SAFE(var, head, headname, field, tvar) \ - for ((var) = ((var) ? (var) : TAILQ_LAST((head), headname)); \ - (var) && ((tvar) = TAILQ_PREV((var), headname, field), 1); \ - (var) = (tvar)) - -#define TAILQ_INIT(head) do { \ - TAILQ_FIRST((head)) = NULL; \ - (head)->tqh_last = &TAILQ_FIRST((head)); \ - QMD_TRACE_HEAD(head); \ -} while (0) - -#define TAILQ_INSERT_AFTER(head, listelm, elm, field) do { \ - QMD_TAILQ_CHECK_NEXT(listelm, field); \ - if ((TAILQ_NEXT((elm), field) = TAILQ_NEXT((listelm), field)) != NULL)\ - TAILQ_NEXT((elm), field)->field.tqe_prev = \ - &TAILQ_NEXT((elm), field); \ - else { \ - (head)->tqh_last = &TAILQ_NEXT((elm), field); \ - QMD_TRACE_HEAD(head); \ - } \ - TAILQ_NEXT((listelm), field) = (elm); \ - (elm)->field.tqe_prev = &TAILQ_NEXT((listelm), field); \ - QMD_TRACE_ELEM(&(elm)->field); \ - QMD_TRACE_ELEM(&(listelm)->field); \ -} while (0) - -#define TAILQ_INSERT_BEFORE(listelm, elm, field) do { \ - QMD_TAILQ_CHECK_PREV(listelm, field); \ - (elm)->field.tqe_prev = (listelm)->field.tqe_prev; \ - TAILQ_NEXT((elm), field) = (listelm); \ - *(listelm)->field.tqe_prev = (elm); \ - (listelm)->field.tqe_prev = &TAILQ_NEXT((elm), field); \ - QMD_TRACE_ELEM(&(elm)->field); \ - QMD_TRACE_ELEM(&(listelm)->field); \ -} while (0) - -#define TAILQ_INSERT_HEAD(head, elm, field) do { \ - QMD_TAILQ_CHECK_HEAD(head, field); \ - if ((TAILQ_NEXT((elm), field) = TAILQ_FIRST((head))) != NULL) \ - TAILQ_FIRST((head))->field.tqe_prev = \ - &TAILQ_NEXT((elm), field); \ - else \ - (head)->tqh_last = &TAILQ_NEXT((elm), field); \ - TAILQ_FIRST((head)) = (elm); \ - (elm)->field.tqe_prev = &TAILQ_FIRST((head)); \ - QMD_TRACE_HEAD(head); \ - QMD_TRACE_ELEM(&(elm)->field); \ -} while (0) - -#define TAILQ_INSERT_TAIL(head, elm, field) do { \ - QMD_TAILQ_CHECK_TAIL(head, field); \ - TAILQ_NEXT((elm), field) = NULL; \ - (elm)->field.tqe_prev = (head)->tqh_last; \ - *(head)->tqh_last = (elm); \ - (head)->tqh_last = &TAILQ_NEXT((elm), field); \ - QMD_TRACE_HEAD(head); \ - QMD_TRACE_ELEM(&(elm)->field); \ -} while (0) - -#define TAILQ_LAST(head, headname) \ - (*(((struct headname *)((head)->tqh_last))->tqh_last)) - -#define TAILQ_NEXT(elm, field) ((elm)->field.tqe_next) - -#define TAILQ_PREV(elm, headname, field) \ - (*(((struct headname *)((elm)->field.tqe_prev))->tqh_last)) - -#define TAILQ_REMOVE(head, elm, field) do { \ - QMD_SAVELINK(oldnext, (elm)->field.tqe_next); \ - QMD_SAVELINK(oldprev, (elm)->field.tqe_prev); \ - QMD_TAILQ_CHECK_NEXT(elm, field); \ - QMD_TAILQ_CHECK_PREV(elm, field); \ - if ((TAILQ_NEXT((elm), field)) != NULL) \ - TAILQ_NEXT((elm), field)->field.tqe_prev = \ - (elm)->field.tqe_prev; \ - else { \ - (head)->tqh_last = (elm)->field.tqe_prev; \ - QMD_TRACE_HEAD(head); \ - } \ - *(elm)->field.tqe_prev = TAILQ_NEXT((elm), field); \ - TRASHIT(*oldnext); \ - TRASHIT(*oldprev); \ - QMD_TRACE_ELEM(&(elm)->field); \ -} while (0) - -#define TAILQ_SWAP(head1, head2, type, field) do { \ - QUEUE_TYPEOF(type) *swap_first = (head1)->tqh_first; \ - QUEUE_TYPEOF(type) **swap_last = (head1)->tqh_last; \ - (head1)->tqh_first = (head2)->tqh_first; \ - (head1)->tqh_last = (head2)->tqh_last; \ - (head2)->tqh_first = swap_first; \ - (head2)->tqh_last = swap_last; \ - if ((swap_first = (head1)->tqh_first) != NULL) \ - swap_first->field.tqe_prev = &(head1)->tqh_first; \ - else \ - (head1)->tqh_last = &(head1)->tqh_first; \ - if ((swap_first = (head2)->tqh_first) != NULL) \ - swap_first->field.tqe_prev = &(head2)->tqh_first; \ - else \ - (head2)->tqh_last = &(head2)->tqh_first; \ -} while (0) - -#endif /* !_SYS_QUEUE_H_ */ -#ifdef MG_MODULE_LINES -#line 1 "mongoose/src/features.h" -#endif -/* - * Copyright (c) 2014-2016 Cesanta Software Limited - * All rights reserved - */ - -#ifndef CS_MONGOOSE_SRC_FEATURES_H_ -#define CS_MONGOOSE_SRC_FEATURES_H_ - -#ifndef MG_DISABLE_HTTP_DIGEST_AUTH -#define MG_DISABLE_HTTP_DIGEST_AUTH 0 -#endif - -#ifndef MG_DISABLE_HTTP_KEEP_ALIVE -#define MG_DISABLE_HTTP_KEEP_ALIVE 0 -#endif - -#ifndef MG_DISABLE_PFS -#define MG_DISABLE_PFS 0 -#endif - -#ifndef MG_DISABLE_WS_RANDOM_MASK -#define MG_DISABLE_WS_RANDOM_MASK 0 -#endif - -#ifndef MG_ENABLE_ASYNC_RESOLVER -#define MG_ENABLE_ASYNC_RESOLVER 1 -#endif - -#ifndef MG_ENABLE_BROADCAST -#define MG_ENABLE_BROADCAST 0 -#endif - -#ifndef MG_ENABLE_COAP -#define MG_ENABLE_COAP 0 -#endif - -#ifndef MG_ENABLE_DEBUG -#define MG_ENABLE_DEBUG 0 -#endif - -#ifndef MG_ENABLE_DIRECTORY_LISTING -#define MG_ENABLE_DIRECTORY_LISTING 0 -#endif - -#ifndef MG_ENABLE_DNS -#define MG_ENABLE_DNS 1 -#endif - -#ifndef MG_ENABLE_DNS_SERVER -#define MG_ENABLE_DNS_SERVER 0 -#endif - -#ifndef MG_ENABLE_FAKE_DAVLOCK -#define MG_ENABLE_FAKE_DAVLOCK 0 -#endif - -#ifndef MG_ENABLE_FILESYSTEM -#define MG_ENABLE_FILESYSTEM 0 -#endif - -#ifndef MG_ENABLE_GETADDRINFO -#define MG_ENABLE_GETADDRINFO 0 -#endif - -#ifndef MG_ENABLE_HEXDUMP -#define MG_ENABLE_HEXDUMP CS_ENABLE_STDIO -#endif - -#ifndef MG_ENABLE_HTTP -#define MG_ENABLE_HTTP 1 -#endif - -#ifndef MG_ENABLE_HTTP_CGI -#define MG_ENABLE_HTTP_CGI 0 -#endif - -#ifndef MG_ENABLE_HTTP_SSI -#define MG_ENABLE_HTTP_SSI MG_ENABLE_FILESYSTEM -#endif - -#ifndef MG_ENABLE_HTTP_SSI_EXEC -#define MG_ENABLE_HTTP_SSI_EXEC 0 -#endif - -#ifndef MG_ENABLE_HTTP_STREAMING_MULTIPART -#define MG_ENABLE_HTTP_STREAMING_MULTIPART 0 -#endif - -#ifndef MG_ENABLE_HTTP_WEBDAV -#define MG_ENABLE_HTTP_WEBDAV 0 -#endif - -#ifndef MG_ENABLE_HTTP_WEBSOCKET -#define MG_ENABLE_HTTP_WEBSOCKET MG_ENABLE_HTTP -#endif - -#ifndef MG_ENABLE_IPV6 -#define MG_ENABLE_IPV6 0 -#endif - -#ifndef MG_ENABLE_JAVASCRIPT -#define MG_ENABLE_JAVASCRIPT 0 -#endif - -#ifndef MG_ENABLE_MQTT -#define MG_ENABLE_MQTT 1 -#endif - -#ifndef MG_ENABLE_MQTT_BROKER -#define MG_ENABLE_MQTT_BROKER 0 -#endif - -#ifndef MG_ENABLE_SSL -#define MG_ENABLE_SSL 0 -#endif - -#ifndef MG_ENABLE_SYNC_RESOLVER -#define MG_ENABLE_SYNC_RESOLVER 0 -#endif - -#ifndef MG_ENABLE_STDIO -#define MG_ENABLE_STDIO CS_ENABLE_STDIO -#endif - -#ifndef MG_NET_IF -#define MG_NET_IF MG_NET_IF_SOCKET -#endif - -#ifndef MG_SSL_IF -#define MG_SSL_IF MG_SSL_IF_OPENSSL -#endif - -#ifndef MG_ENABLE_THREADS /* ifdef-ok */ -#ifdef _WIN32 -#define MG_ENABLE_THREADS 1 -#else -#define MG_ENABLE_THREADS 0 -#endif -#endif - -#if MG_ENABLE_DEBUG && !defined(CS_ENABLE_DEBUG) -#define CS_ENABLE_DEBUG 1 -#endif - -/* MQTT broker requires MQTT */ -#if MG_ENABLE_MQTT_BROKER && !MG_ENABLE_MQTT -#undef MG_ENABLE_MQTT -#define MG_ENABLE_MQTT 1 -#endif - -#ifndef MG_ENABLE_HTTP_URL_REWRITES -#define MG_ENABLE_HTTP_URL_REWRITES \ - (CS_PLATFORM == CS_P_WINDOWS || CS_PLATFORM == CS_P_UNIX) -#endif - -#ifndef MG_ENABLE_TUN -#define MG_ENABLE_TUN MG_ENABLE_HTTP_WEBSOCKET -#endif - -#ifndef MG_ENABLE_SNTP -#define MG_ENABLE_SNTP 0 -#endif - -#ifndef MG_ENABLE_EXTRA_ERRORS_DESC -#define MG_ENABLE_EXTRA_ERRORS_DESC 0 -#endif - -#ifndef MG_ENABLE_CALLBACK_USERDATA -#define MG_ENABLE_CALLBACK_USERDATA 0 -#endif - -#if MG_ENABLE_CALLBACK_USERDATA -#define MG_UD_ARG(ud) , ud -#define MG_CB(cb, ud) cb, ud -#else -#define MG_UD_ARG(ud) -#define MG_CB(cb, ud) cb -#endif - -#endif /* CS_MONGOOSE_SRC_FEATURES_H_ */ -#ifdef MG_MODULE_LINES -#line 1 "mongoose/src/net_if.h" -#endif -/* - * Copyright (c) 2014-2016 Cesanta Software Limited - * All rights reserved - */ - -#ifndef CS_MONGOOSE_SRC_NET_IF_H_ -#define CS_MONGOOSE_SRC_NET_IF_H_ - -/* Amalgamated: #include "common/platform.h" */ - -/* - * Internal async networking core interface. - * Consists of calls made by the core, which should not block, - * and callbacks back into the core ("..._cb"). - * Callbacks may (will) cause methods to be invoked from within, - * but methods are not allowed to invoke callbacks inline. - * - * Implementation must ensure that only one callback is invoked at any time. - */ - -#ifdef __cplusplus -extern "C" { -#endif /* __cplusplus */ - -#define MG_MAIN_IFACE 0 - -struct mg_mgr; -struct mg_connection; -union socket_address; - -struct mg_iface_vtable; - -struct mg_iface { - struct mg_mgr *mgr; - void *data; /* Implementation-specific data */ - const struct mg_iface_vtable *vtable; -}; - -struct mg_iface_vtable { - void (*init)(struct mg_iface *iface); - void (*free)(struct mg_iface *iface); - void (*add_conn)(struct mg_connection *nc); - void (*remove_conn)(struct mg_connection *nc); - time_t (*poll)(struct mg_iface *iface, int timeout_ms); - - /* Set up a listening TCP socket on a given address. rv = 0 -> ok. */ - int (*listen_tcp)(struct mg_connection *nc, union socket_address *sa); - /* Request that a "listening" UDP socket be created. */ - int (*listen_udp)(struct mg_connection *nc, union socket_address *sa); - - /* Request that a TCP connection is made to the specified address. */ - void (*connect_tcp)(struct mg_connection *nc, const union socket_address *sa); - /* Open a UDP socket. Doesn't actually connect anything. */ - 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); - - void (*recved)(struct mg_connection *nc, size_t len); - - /* Perform interface-related connection initialization. Return 1 on ok. */ - int (*create_conn)(struct mg_connection *nc); - /* Perform interface-related cleanup on connection before destruction. */ - void (*destroy_conn)(struct mg_connection *nc); - - /* Associate a socket to a connection. */ - void (*sock_set)(struct mg_connection *nc, sock_t sock); - - /* Put connection's address into *sa, local (remote = 0) or remote. */ - void (*get_conn_addr)(struct mg_connection *nc, int remote, - union socket_address *sa); -}; - -extern const struct mg_iface_vtable *mg_ifaces[]; -extern int mg_num_ifaces; - -/* Creates a new interface instance. */ -struct mg_iface *mg_if_create_iface(const struct mg_iface_vtable *vtable, - struct mg_mgr *mgr); - -/* - * Find an interface with a given implementation. The search is started from - * interface `from`, exclusive. Returns NULL if none is found. - */ -struct mg_iface *mg_find_iface(struct mg_mgr *mgr, - const struct mg_iface_vtable *vtable, - struct mg_iface *from); -/* - * Deliver a new TCP connection. Returns NULL in case on error (unable to - * create connection, in which case interface state should be discarded. - * This is phase 1 of the two-phase process - MG_EV_ACCEPT will be delivered - * when mg_if_accept_tcp_cb is invoked. - */ -struct mg_connection *mg_if_accept_new_conn(struct mg_connection *lc); -void mg_if_accept_tcp_cb(struct mg_connection *nc, union socket_address *sa, - size_t sa_len); - -/* 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. - */ -void mg_if_recv_tcp_cb(struct mg_connection *nc, void *buf, int len, int own); -/* - * 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); - -/* 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); - -#ifdef __cplusplus -} -#endif /* __cplusplus */ - -#endif /* CS_MONGOOSE_SRC_NET_IF_H_ */ -#ifdef MG_MODULE_LINES -#line 1 "mongoose/src/ssl_if.h" -#endif -/* - * Copyright (c) 2014-2016 Cesanta Software Limited - * All rights reserved - */ - -#ifndef CS_MONGOOSE_SRC_SSL_IF_H_ -#define CS_MONGOOSE_SRC_SSL_IF_H_ - -#if MG_ENABLE_SSL - -#ifdef __cplusplus -extern "C" { -#endif /* __cplusplus */ - -struct mg_ssl_if_ctx; -struct mg_connection; - -void mg_ssl_if_init(); - -enum mg_ssl_if_result { - MG_SSL_OK = 0, - MG_SSL_WANT_READ = -1, - MG_SSL_WANT_WRITE = -2, - MG_SSL_ERROR = -3, -}; - -struct mg_ssl_if_conn_params { - const char *cert; - const char *key; - const char *ca_cert; - const char *server_name; - const char *cipher_suites; - const char *psk_identity; - const char *psk_key; -}; - -enum mg_ssl_if_result mg_ssl_if_conn_init( - struct mg_connection *nc, const struct mg_ssl_if_conn_params *params, - const char **err_msg); -enum mg_ssl_if_result mg_ssl_if_conn_accept(struct mg_connection *nc, - struct mg_connection *lc); -void mg_ssl_if_conn_close_notify(struct mg_connection *nc); -void mg_ssl_if_conn_free(struct mg_connection *nc); - -enum mg_ssl_if_result mg_ssl_if_handshake(struct mg_connection *nc); -int mg_ssl_if_read(struct mg_connection *nc, void *buf, size_t buf_size); -int mg_ssl_if_write(struct mg_connection *nc, const void *data, size_t len); - -#ifdef __cplusplus -} -#endif /* __cplusplus */ - -#endif /* MG_ENABLE_SSL */ - -#endif /* CS_MONGOOSE_SRC_SSL_IF_H_ */ -#ifdef MG_MODULE_LINES -#line 1 "mongoose/src/net.h" -#endif -/* - * Copyright (c) 2014 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. - * - * Alternatively, you can license this software under a commercial - * license, as set out in . - */ - -/* - * === Core API: TCP/UDP/SSL - * - * NOTE: Mongoose manager is single threaded. It does not protect - * its data structures by mutexes, therefore all functions that are dealing - * with a particular event manager should be called from the same thread, - * with exception of the `mg_broadcast()` function. It is fine to have different - * event managers handled by different threads. - */ - -#ifndef CS_MONGOOSE_SRC_NET_H_ -#define CS_MONGOOSE_SRC_NET_H_ - -#if MG_ENABLE_JAVASCRIPT -#define EXCLUDE_COMMON -#include -#endif - -/* Amalgamated: #include "mongoose/src/common.h" */ -/* Amalgamated: #include "mongoose/src/net_if.h" */ -/* Amalgamated: #include "common/mbuf.h" */ - -#ifndef MG_VPRINTF_BUFFER_SIZE -#define MG_VPRINTF_BUFFER_SIZE 100 -#endif - -#ifdef MG_USE_READ_WRITE -#define MG_RECV_FUNC(s, b, l, f) read(s, b, l) -#define MG_SEND_FUNC(s, b, l, f) write(s, b, l) -#else -#define MG_RECV_FUNC(s, b, l, f) recv(s, b, l, f) -#define MG_SEND_FUNC(s, b, l, f) send(s, b, l, f) -#endif - -#ifdef __cplusplus -extern "C" { -#endif /* __cplusplus */ - -union socket_address { - struct sockaddr sa; - struct sockaddr_in sin; -#if MG_ENABLE_IPV6 - struct sockaddr_in6 sin6; -#else - struct sockaddr sin6; -#endif -}; - -struct mg_connection; - -/* - * Callback function (event handler) prototype. Must be defined by the user. - * Mongoose calls the event handler, passing the events defined below. - */ -typedef void (*mg_event_handler_t)(struct mg_connection *nc, int ev, - void *ev_data MG_UD_ARG(void *user_data)); - -/* Events. Meaning of event parameter (evp) is given in the comment. */ -#define MG_EV_POLL 0 /* Sent to each connection on each mg_mgr_poll() call */ -#define MG_EV_ACCEPT 1 /* New connection accepted. union socket_address * */ -#define MG_EV_CONNECT 2 /* connect() succeeded or failed. int * */ -#define MG_EV_RECV 3 /* Data has been received. int *num_bytes */ -#define MG_EV_SEND 4 /* Data has been written to a socket. int *num_bytes */ -#define MG_EV_CLOSE 5 /* Connection is closed. NULL */ -#define MG_EV_TIMER 6 /* now >= conn->ev_timer_time. double * */ - -/* - * Mongoose event manager. - */ -struct mg_mgr { - struct mg_connection *active_connections; -#if MG_ENABLE_HEXDUMP - const char *hexdump_file; /* Debug hexdump file path */ -#endif -#if MG_ENABLE_BROADCAST - sock_t ctl[2]; /* Socketpair for mg_broadcast() */ -#endif - void *user_data; /* User data */ - int num_ifaces; - struct mg_iface **ifaces; /* network interfaces */ -#if MG_ENABLE_JAVASCRIPT - struct v7 *v7; -#endif - const char *nameserver; /* DNS server to use */ -}; - -/* - * Mongoose connection. - */ -struct mg_connection { - struct mg_connection *next, *prev; /* mg_mgr::active_connections linkage */ - struct mg_connection *listener; /* Set only for accept()-ed connections */ - struct mg_mgr *mgr; /* Pointer to containing manager */ - - sock_t sock; /* Socket to the remote peer */ - int err; - union socket_address sa; /* Remote peer address */ - size_t recv_mbuf_limit; /* Max size of recv buffer */ - struct mbuf recv_mbuf; /* Received data */ - struct mbuf send_mbuf; /* Data scheduled for sending */ - time_t last_io_time; /* Timestamp of the last socket IO */ - double ev_timer_time; /* Timestamp of the future MG_EV_TIMER */ -#if MG_ENABLE_SSL - void *ssl_if_data; /* SSL library data. */ -#endif - mg_event_handler_t proto_handler; /* Protocol-specific event handler */ - void *proto_data; /* Protocol-specific data */ - void (*proto_data_destructor)(void *proto_data); - mg_event_handler_t handler; /* Event handler function */ - void *user_data; /* User-specific data */ - union { - void *v; - /* - * the C standard is fussy about fitting function pointers into - * void pointers, since some archs might have fat pointers for functions. - */ - mg_event_handler_t f; - } priv_1; - void *priv_2; - void *mgr_data; /* Implementation-specific event manager's data. */ - struct mg_iface *iface; - unsigned long flags; -/* Flags set by Mongoose */ -#define MG_F_LISTENING (1 << 0) /* This connection is listening */ -#define MG_F_UDP (1 << 1) /* This connection is UDP */ -#define MG_F_RESOLVING (1 << 2) /* Waiting for async resolver */ -#define MG_F_CONNECTING (1 << 3) /* connect() call in progress */ -#define MG_F_SSL (1 << 4) /* SSL is enabled on the connection */ -#define MG_F_SSL_HANDSHAKE_DONE (1 << 5) /* SSL hanshake has completed */ -#define MG_F_WANT_READ (1 << 6) /* SSL specific */ -#define MG_F_WANT_WRITE (1 << 7) /* SSL specific */ -#define MG_F_IS_WEBSOCKET (1 << 8) /* Websocket specific */ - -/* Flags that are settable by user */ -#define MG_F_SEND_AND_CLOSE (1 << 10) /* Push remaining data and close */ -#define MG_F_CLOSE_IMMEDIATELY (1 << 11) /* Disconnect */ -#define MG_F_WEBSOCKET_NO_DEFRAG (1 << 12) /* Websocket specific */ -#define MG_F_DELETE_CHUNK (1 << 13) /* HTTP specific */ -#define MG_F_ENABLE_BROADCAST (1 << 14) /* Allow broadcast address usage */ -#define MG_F_TUN_DO_NOT_RECONNECT (1 << 15) /* Don't reconnect tunnel */ - -#define MG_F_USER_1 (1 << 20) /* Flags left for application */ -#define MG_F_USER_2 (1 << 21) -#define MG_F_USER_3 (1 << 22) -#define MG_F_USER_4 (1 << 23) -#define MG_F_USER_5 (1 << 24) -#define MG_F_USER_6 (1 << 25) -}; - -/* - * Initialise Mongoose manager. Side effect: ignores SIGPIPE signal. - * `mgr->user_data` field will be initialised with a `user_data` parameter. - * That is an arbitrary pointer, where the user code can associate some data - * with the particular Mongoose manager. For example, a C++ wrapper class - * could be written in which case `user_data` can hold a pointer to the - * class instance. - */ -void mg_mgr_init(struct mg_mgr *mgr, void *user_data); - -/* - * Optional parameters to `mg_mgr_init_opt()`. - * - * If `main_iface` is not NULL, it will be used as the main interface in the - * default interface set. The pointer will be free'd by `mg_mgr_free`. - * Otherwise, the main interface will be autodetected based on the current - * platform. - * - * If `num_ifaces` is 0 and `ifaces` is NULL, the default interface set will be - * used. - * This is an advanced option, as it requires you to construct a full interface - * set, including special networking interfaces required by some optional - * features such as TCP tunneling. Memory backing `ifaces` and each of the - * `num_ifaces` pointers it contains will be reclaimed by `mg_mgr_free`. - */ -struct mg_mgr_init_opts { - const struct mg_iface_vtable *main_iface; - int num_ifaces; - const struct mg_iface_vtable **ifaces; - const char *nameserver; -}; - -/* - * Like `mg_mgr_init` but with more options. - * - * Notably, this allows you to create a manger and choose - * dynamically which networking interface implementation to use. - */ -void mg_mgr_init_opt(struct mg_mgr *mgr, void *user_data, - struct mg_mgr_init_opts opts); - -/* - * De-initialises Mongoose manager. - * - * Closes and deallocates all active connections. - */ -void mg_mgr_free(struct mg_mgr *); - -/* - * This function performs the actual IO and must be called in a loop - * (an event loop). It returns the current timestamp. - * `milli` is the maximum number of milliseconds to sleep. - * `mg_mgr_poll()` checks all connections for IO readiness. If at least one - * of the connections is IO-ready, `mg_mgr_poll()` triggers the respective - * event handlers and returns. - */ -time_t mg_mgr_poll(struct mg_mgr *, int milli); - -#if MG_ENABLE_BROADCAST -/* - * Passes a message of a given length to all connections. - * - * Must be called from a thread that does NOT call `mg_mgr_poll()`. - * Note that `mg_broadcast()` is the only function - * that can be, and must be, called from a different (non-IO) thread. - * - * `func` callback function will be called by the IO thread for each - * connection. When called, the event will be `MG_EV_POLL`, and a message will - * be passed as the `ev_data` pointer. Maximum message size is capped - * by `MG_CTL_MSG_MESSAGE_SIZE` which is set to 8192 bytes. - */ -void mg_broadcast(struct mg_mgr *mgr, mg_event_handler_t cb, void *data, - size_t len); -#endif - -/* - * Iterates over all active connections. - * - * Returns the next connection from the list - * of active connections or `NULL` if there are no more connections. Below - * is the iteration idiom: - * - * ```c - * for (c = mg_next(srv, NULL); c != NULL; c = mg_next(srv, c)) { - * // Do something with connection `c` - * } - * ``` - */ -struct mg_connection *mg_next(struct mg_mgr *mgr, struct mg_connection *c); - -/* - * Optional parameters to `mg_add_sock_opt()`. - * - * `flags` is an initial `struct mg_connection::flags` bitmask to set, - * see `MG_F_*` flags definitions. - */ -struct mg_add_sock_opts { - void *user_data; /* Initial value for connection's user_data */ - unsigned int flags; /* Initial connection flags */ - const char **error_string; /* Placeholder for the error string */ - struct mg_iface *iface; /* Interface instance */ -}; - -/* - * Creates a connection, associates it with the given socket and event handler - * and adds it to the manager. - * - * For more options see the `mg_add_sock_opt` variant. - */ -struct mg_connection *mg_add_sock(struct mg_mgr *mgr, sock_t sock, - MG_CB(mg_event_handler_t handler, - void *user_data)); - -/* - * Creates a connection, associates it with the given socket and event handler - * and adds to the manager. - * - * See the `mg_add_sock_opts` structure for a description of the options. - */ -struct mg_connection *mg_add_sock_opt(struct mg_mgr *mgr, sock_t sock, - MG_CB(mg_event_handler_t handler, - void *user_data), - struct mg_add_sock_opts opts); - -/* - * Optional parameters to `mg_bind_opt()`. - * - * `flags` is an initial `struct mg_connection::flags` bitmask to set, - * see `MG_F_*` flags definitions. - */ -struct mg_bind_opts { - void *user_data; /* Initial value for connection's user_data */ - unsigned int flags; /* Extra connection flags */ - const char **error_string; /* Placeholder for the error string */ - struct mg_iface *iface; /* Interface instance */ -#if MG_ENABLE_SSL - /* - * SSL settings. - * - * Server certificate to present to clients or client certificate to - * present to tunnel dispatcher (for tunneled connections). - */ - const char *ssl_cert; - /* Private key corresponding to the certificate. If ssl_cert is set but - * ssl_key is not, ssl_cert is used. */ - const char *ssl_key; - /* CA bundle used to verify client certificates or tunnel dispatchers. */ - const char *ssl_ca_cert; - /* Colon-delimited list of acceptable cipher suites. - * Names depend on the library used, for example: - * - * ECDH-ECDSA-AES128-GCM-SHA256:DHE-RSA-AES128-SHA256 (OpenSSL) - * TLS-ECDH-ECDSA-WITH-AES-128-GCM-SHA256:TLS-DHE-RSA-WITH-AES-128-GCM-SHA256 - * (mbedTLS) - * - * For OpenSSL the list can be obtained by running "openssl ciphers". - * For mbedTLS, names can be found in library/ssl_ciphersuites.c - * If NULL, a reasonable default is used. - */ - const char *ssl_cipher_suites; -#endif -}; - -/* - * Creates a listening connection. - * - * See `mg_bind_opt` for full documentation. - */ -struct mg_connection *mg_bind(struct mg_mgr *mgr, const char *address, - MG_CB(mg_event_handler_t handler, - void *user_data)); -/* - * Creates a listening connection. - * - * The `address` parameter specifies which address to bind to. It's format is - * the same as for the `mg_connect()` call, where `HOST` part is optional. - * `address` can be just a port number, e.g. `:8000`. To bind to a specific - * interface, an IP address can be specified, e.g. `1.2.3.4:8000`. By default, - * a TCP connection is created. To create UDP connection, prepend `udp://` - * prefix, e.g. `udp://:8000`. To summarize, `address` parameter has following - * format: `[PROTO://][IP_ADDRESS]:PORT`, where `PROTO` could be `tcp` or - * `udp`. - * - * See the `mg_bind_opts` structure for a description of the optional - * parameters. - * - * Returns a new listening connection or `NULL` on error. - * NOTE: The connection remains owned by the manager, do not free(). - */ -struct mg_connection *mg_bind_opt(struct mg_mgr *mgr, const char *address, - MG_CB(mg_event_handler_t handler, - void *user_data), - struct mg_bind_opts opts); - -/* Optional parameters to `mg_connect_opt()` */ -struct mg_connect_opts { - void *user_data; /* Initial value for connection's user_data */ - unsigned int flags; /* Extra connection flags */ - const char **error_string; /* Placeholder for the error string */ - struct mg_iface *iface; /* Interface instance */ - const char *nameserver; /* DNS server to use, NULL for default */ -#if MG_ENABLE_SSL - /* - * SSL settings. - * Client certificate to present to the server. - */ - const char *ssl_cert; - /* - * Private key corresponding to the certificate. - * If ssl_cert is set but ssl_key is not, ssl_cert is used. - */ - const char *ssl_key; - /* - * Verify server certificate using this CA bundle. If set to "*", then SSL - * is enabled but no cert verification is performed. - */ - const char *ssl_ca_cert; - /* Colon-delimited list of acceptable cipher suites. - * Names depend on the library used, for example: - * - * ECDH-ECDSA-AES128-GCM-SHA256:DHE-RSA-AES128-SHA256 (OpenSSL) - * TLS-ECDH-ECDSA-WITH-AES-128-GCM-SHA256:TLS-DHE-RSA-WITH-AES-128-GCM-SHA256 - * (mbedTLS) - * - * For OpenSSL the list can be obtained by running "openssl ciphers". - * For mbedTLS, names can be found in library/ssl_ciphersuites.c - * If NULL, a reasonable default is used. - */ - const char *ssl_cipher_suites; - /* - * Server name verification. If ssl_ca_cert is set and the certificate has - * passed verification, its subject will be verified against this string. - * By default (if ssl_server_name is NULL) hostname part of the address will - * be used. Wildcard matching is supported. A special value of "*" disables - * name verification. - */ - const char *ssl_server_name; - /* - * PSK identity and key. Identity is a NUL-terminated string and key is a hex - * string. Key must be either 16 or 32 bytes (32 or 64 hex digits) for AES-128 - * or AES-256 respectively. - * Note: Default list of cipher suites does not include PSK suites, if you - * want to use PSK you will need to set ssl_cipher_suites as well. - */ - const char *ssl_psk_identity; - const char *ssl_psk_key; -#endif -}; - -/* - * Connects to a remote host. - * - * See `mg_connect_opt()` for full documentation. - */ -struct mg_connection *mg_connect(struct mg_mgr *mgr, const char *address, - MG_CB(mg_event_handler_t handler, - void *user_data)); - -/* - * Connects to a remote host. - * - * The `address` format is `[PROTO://]HOST:PORT`. `PROTO` could be `tcp` or - * `udp`. `HOST` could be an IP address, - * IPv6 address (if Mongoose is compiled with `-DMG_ENABLE_IPV6`) or a host - * name. If `HOST` is a name, Mongoose will resolve it asynchronously. Examples - * of valid addresses: `google.com:80`, `udp://1.2.3.4:53`, `10.0.0.1:443`, - * `[::1]:80` - * - * See the `mg_connect_opts` structure for a description of the optional - * parameters. - * - * Returns a new outbound connection or `NULL` on error. - * - * NOTE: The connection remains owned by the manager, do not free(). - * - * NOTE: To enable IPv6 addresses `-DMG_ENABLE_IPV6` should be specified - * in the compilation flags. - * - * NOTE: The new connection will receive `MG_EV_CONNECT` as its first event - * which will report the connect success status. - * If the asynchronous resolution fails or the `connect()` syscall fails for - * whatever reason (e.g. with `ECONNREFUSED` or `ENETUNREACH`), then - * `MG_EV_CONNECT` event will report failure. Code example below: - * - * ```c - * static void ev_handler(struct mg_connection *nc, int ev, void *ev_data) { - * int connect_status; - * - * switch (ev) { - * case MG_EV_CONNECT: - * connect_status = * (int *) ev_data; - * if (connect_status == 0) { - * // Success - * } else { - * // Error - * printf("connect() error: %s\n", strerror(connect_status)); - * } - * break; - * ... - * } - * } - * - * ... - * mg_connect(mgr, "my_site.com:80", ev_handler); - * ``` - */ -struct mg_connection *mg_connect_opt(struct mg_mgr *mgr, const char *address, - MG_CB(mg_event_handler_t handler, - void *user_data), - struct mg_connect_opts opts); - -#if MG_ENABLE_SSL && MG_NET_IF != MG_NET_IF_SIMPLELINK -/* - * Note: This function is deprecated. Please, use SSL options in - * mg_connect_opt. - * - * Enables SSL for a given connection. - * `cert` is a server certificate file name for a listening connection - * or a client certificate file name for an outgoing connection. - * The certificate files must be in PEM format. The server certificate file - * must contain a certificate, concatenated with a private key, optionally - * concatenated with DH parameters. - * `ca_cert` is a CA certificate or NULL if peer verification is not - * required. - * Return: NULL on success or error message on error. - */ -const char *mg_set_ssl(struct mg_connection *nc, const char *cert, - const char *ca_cert); -#endif - -/* - * Sends data to the connection. - * - * Note that sending functions do not actually push data to the socket. - * They just append data to the output buffer. MG_EV_SEND will be delivered when - * the data has actually been pushed out. - */ -void mg_send(struct mg_connection *, const void *buf, int len); - -/* Enables format string warnings for mg_printf */ -#if defined(__GNUC__) -__attribute__((format(printf, 2, 3))) -#endif -/* don't separate from mg_printf declaration */ - -/* - * Sends `printf`-style formatted data to the connection. - * - * See `mg_send` for more details on send semantics. - */ -int mg_printf(struct mg_connection *, const char *fmt, ...); - -/* Same as `mg_printf()`, but takes `va_list ap` as an argument. */ -int mg_vprintf(struct mg_connection *, const char *fmt, va_list ap); - -/* - * Creates a socket pair. - * `sock_type` can be either `SOCK_STREAM` or `SOCK_DGRAM`. - * Returns 0 on failure and 1 on success. - */ -int mg_socketpair(sock_t[2], int sock_type); - -#if MG_ENABLE_SYNC_RESOLVER -/* - * Convert domain name into IP address. - * - * This is a utility function. If compilation flags have - * `-DMG_ENABLE_GETADDRINFO`, then `getaddrinfo()` call is used for name - * resolution. Otherwise, `gethostbyname()` is used. - * - * CAUTION: this function can block. - * Return 1 on success, 0 on failure. - */ -int mg_resolve(const char *domain_name, char *ip_addr_buf, size_t buf_len); -#endif - -/* - * Verify given IP address against the ACL. - * - * `remote_ip` - an IPv4 address to check, in host byte order - * `acl` - a comma separated list of IP subnets: `x.x.x.x/x` or `x.x.x.x`. - * Each subnet is - * prepended by either a - or a + sign. A plus sign means allow, where a - * minus sign means deny. If a subnet mask is omitted, such as `-1.2.3.4`, - * it means that only that single IP address is denied. - * Subnet masks may vary from 0 to 32, inclusive. The default setting - * is to allow all access. On each request the full list is traversed, - * and the last match wins. Example: - * - * `-0.0.0.0/0,+192.168/16` - deny all accesses, only allow 192.168/16 subnet - * - * To learn more about subnet masks, see this - * link:https://en.wikipedia.org/wiki/Subnetwork[Wikipedia page on Subnetwork]. - * - * Returns -1 if ACL is malformed, 0 if address is disallowed, 1 if allowed. - */ -int mg_check_ip_acl(const char *acl, uint32_t remote_ip); - -#if MG_ENABLE_JAVASCRIPT -/* - * Enables server-side JavaScript scripting. - * Requires a `-DMG_ENABLE_JAVASCRIPT` compilation flag and V7 engine sources. - * V7 instance must not be destroyed during manager's lifetime. - * Returns a V7 error. - */ -enum v7_err mg_enable_javascript(struct mg_mgr *m, struct v7 *v7, - const char *init_js_file_name); -#endif - -/* - * Schedules an MG_EV_TIMER event to be delivered at `timestamp` time. - * `timestamp` is UNIX time (the number of seconds since Epoch). It is - * `double` instead of `time_t` to allow for sub-second precision. - * Returns the old timer value. - * - * Example: set the connect timeout to 1.5 seconds: - * - * ``` - * c = mg_connect(&mgr, "cesanta.com", ev_handler); - * mg_set_timer(c, mg_time() + 1.5); - * ... - * - * void ev_handler(struct mg_connection *c, int ev, void *ev_data) { - * switch (ev) { - * case MG_EV_CONNECT: - * mg_set_timer(c, 0); // Clear connect timer - * break; - * case MG_EV_TIMER: - * log("Connect timeout"); - * c->flags |= MG_F_CLOSE_IMMEDIATELY; - * break; - * ``` - */ -double mg_set_timer(struct mg_connection *c, double timestamp); - -/* - * A sub-second precision version of time(). - */ -double mg_time(void); - -#ifdef __cplusplus -} -#endif /* __cplusplus */ - -#endif /* CS_MONGOOSE_SRC_NET_H_ */ -#ifdef MG_MODULE_LINES -#line 1 "mongoose/src/uri.h" -#endif -/* - * Copyright (c) 2014 Cesanta Software Limited - * All rights reserved - */ - -/* - * === URI - */ - -#ifndef CS_MONGOOSE_SRC_URI_H_ -#define CS_MONGOOSE_SRC_URI_H_ - -/* Amalgamated: #include "mongoose/src/net.h" */ - -#ifdef __cplusplus -extern "C" { -#endif /* __cplusplus */ - -/* - * Parses an URI and fills string chunks with locations of the respective - * uri components within the input uri string. NULL pointers will be - * ignored. - * - * General syntax: - * - * [scheme://[user_info@]]host[:port][/path][?query][#fragment] - * - * Example: - * - * foo.com:80 - * tcp://foo.com:1234 - * http://foo.com:80/bar?baz=1 - * https://user:pw@foo.com:443/blah - * - * `path` will include the leading slash. `query` won't include the leading `?`. - * `host` can contain embedded colons if surrounded by square brackets in order - * to support IPv6 literal addresses. - * - * - * Returns 0 on success, -1 on error. - */ -int mg_parse_uri(struct mg_str uri, struct mg_str *scheme, - struct mg_str *user_info, struct mg_str *host, - unsigned int *port, struct mg_str *path, struct mg_str *query, - struct mg_str *fragment); - -int mg_normalize_uri_path(const struct mg_str *in, struct mg_str *out); - -#ifdef __cplusplus -} -#endif /* __cplusplus */ -#endif /* CS_MONGOOSE_SRC_URI_H_ */ -#ifdef MG_MODULE_LINES -#line 1 "mongoose/src/util.h" -#endif -/* - * Copyright (c) 2014 Cesanta Software Limited - * All rights reserved - */ - -/* - * === Utility API - */ - -#ifndef CS_MONGOOSE_SRC_UTIL_H_ -#define CS_MONGOOSE_SRC_UTIL_H_ - -#include - -/* Amalgamated: #include "mongoose/src/common.h" */ -/* Amalgamated: #include "mongoose/src/net_if.h" */ - -#ifdef __cplusplus -extern "C" { -#endif /* __cplusplus */ - -#ifndef MAX_PATH_SIZE -#define MAX_PATH_SIZE 500 -#endif - -/* - * Fetches substring from input string `s`, `end` into `v`. - * Skips initial delimiter characters. Records first non-delimiter character - * at the beginning of substring `v`. Then scans the rest of the string - * until a delimiter character or end-of-string is found. - * `delimiters` is a 0-terminated string containing delimiter characters. - * Either one of `delimiters` or `end_string` terminates the search. - * Returns an `s` pointer, advanced forward where parsing has stopped. - */ -const char *mg_skip(const char *s, const char *end_string, - const char *delimiters, struct mg_str *v); - -/* - * Decodes base64-encoded string `s`, `len` into the destination `dst`. - * The destination has to have enough space to hold the decoded buffer. - * Decoding stops either when all strings have been decoded or invalid an - * character appeared. - * Destination is '\0'-terminated. - * Returns the number of decoded characters. On success, that should be equal - * to `len`. On error (invalid character) the return value is smaller then - * `len`. - */ -int mg_base64_decode(const unsigned char *s, int len, char *dst); - -/* - * Base64-encode chunk of memory `src`, `src_len` into the destination `dst`. - * Destination has to have enough space to hold encoded buffer. - * Destination is '\0'-terminated. - */ -void mg_base64_encode(const unsigned char *src, int src_len, char *dst); - -#if MG_ENABLE_FILESYSTEM -/* - * Performs a 64-bit `stat()` call against a given file. - * - * `path` should be UTF8 encoded. - * - * Return value is the same as for `stat()` syscall. - */ -int mg_stat(const char *path, cs_stat_t *st); - -/* - * Opens the given file and returns a file stream. - * - * `path` and `mode` should be UTF8 encoded. - * - * Return value is the same as for the `fopen()` call. - */ -FILE *mg_fopen(const char *path, const char *mode); - -/* - * Opens the given file and returns a file stream. - * - * `path` should be UTF8 encoded. - * - * Return value is the same as for the `open()` syscall. - */ -int mg_open(const char *path, int flag, int mode); - -/* - * Reads data from the given file stream. - * - * Return value is a number of bytes readen. - */ -size_t mg_fread(void *ptr, size_t size, size_t count, FILE *f); - -/* - * Writes data to the given file stream. - * - * Return value is a number of bytes wtitten. - */ -size_t mg_fwrite(const void *ptr, size_t size, size_t count, FILE *f); - -#endif /* MG_ENABLE_FILESYSTEM */ - -#if MG_ENABLE_THREADS -/* - * Starts a new detached thread. - * Arguments and semantics are the same as pthead's `pthread_create()`. - * `thread_func` is a thread function, `thread_func_param` is a parameter - * that is passed to the thread function. - */ -void *mg_start_thread(void *(*thread_func)(void *), void *thread_func_param); -#endif - -void mg_set_close_on_exec(sock_t); - -#define MG_SOCK_STRINGIFY_IP 1 -#define MG_SOCK_STRINGIFY_PORT 2 -#define MG_SOCK_STRINGIFY_REMOTE 4 -/* - * Converts a connection's local or remote address into string. - * - * The `flags` parameter is a bit mask that controls the behaviour, - * see `MG_SOCK_STRINGIFY_*` definitions. - * - * - MG_SOCK_STRINGIFY_IP - print IP address - * - MG_SOCK_STRINGIFY_PORT - print port number - * - MG_SOCK_STRINGIFY_REMOTE - print remote peer's IP/port, not local address - * - * If both port number and IP address are printed, they are separated by `:`. - * If compiled with `-DMG_ENABLE_IPV6`, IPv6 addresses are supported. - */ -void mg_conn_addr_to_str(struct mg_connection *nc, char *buf, size_t len, - int flags); -#if MG_NET_IF == MG_NET_IF_SOCKET -/* Legacy interface. */ -void mg_sock_to_str(sock_t sock, char *buf, size_t len, int flags); -#endif - -/* - * Convert the socket's address into string. - * - * `flags` is MG_SOCK_STRINGIFY_IP and/or MG_SOCK_STRINGIFY_PORT. - */ -void mg_sock_addr_to_str(const union socket_address *sa, char *buf, size_t len, - int flags); - -#if MG_ENABLE_HEXDUMP -/* - * Generates a human-readable hexdump of memory chunk. - * - * Takes a memory buffer `buf` of length `len` and creates a hex dump of that - * buffer in `dst`. The generated output is a-la hexdump(1). - * Returns the length of generated string, excluding terminating `\0`. If - * returned length is bigger than `dst_len`, the overflow bytes are discarded. - */ -int mg_hexdump(const void *buf, int len, char *dst, int dst_len); - -/* Same as mg_hexdump, but with output going to file instead of a buffer. */ -void mg_hexdumpf(FILE *fp, const void *buf, int len); - -/* - * Generates human-readable hexdump of the data sent or received by the - * connection. `path` is a file name where hexdump should be written. - * `num_bytes` is a number of bytes sent/received. `ev` is one of the `MG_*` - * events sent to an event handler. This function is supposed to be called from - * the event handler. - */ -void mg_hexdump_connection(struct mg_connection *nc, const char *path, - const void *buf, int num_bytes, int ev); -#endif - -/* - * Returns true if target platform is big endian. - */ -int mg_is_big_endian(void); - -/* - * A helper function for traversing a comma separated list of values. - * It returns a list pointer shifted to the next value or NULL if the end - * of the list found. - * The value is stored in a val vector. If the value has a form "x=y", then - * eq_val vector is initialised to point to the "y" part, and val vector length - * is adjusted to point only to "x". - * If the list is just a comma separated list of entries, like "aa,bb,cc" then - * `eq_val` will contain zero-length string. - * - * The purpose of this function is to parse comma separated string without - * any copying/memory allocation. - */ -const char *mg_next_comma_list_entry(const char *list, struct mg_str *val, - struct mg_str *eq_val); - -/* - * Matches 0-terminated string (mg_match_prefix) or string with given length - * mg_match_prefix_n against a glob pattern. - * - * Match is case-insensitive. Returns number of bytes matched, or -1 if no - * match. - */ -int mg_match_prefix(const char *pattern, int pattern_len, const char *str); -int mg_match_prefix_n(const struct mg_str pattern, const struct mg_str str); - -/* - * Use with cs_base64_init/update/finish in order to write out base64 in chunks. - */ -void mg_mbuf_append_base64_putc(char ch, void *user_data); - -/* - * Encode `len` bytes starting at `data` as base64 and append them to an mbuf. - */ -void mg_mbuf_append_base64(struct mbuf *mbuf, const void *data, size_t len); - -/* - * Generate a Basic Auth header and appends it to buf. - * If pass is NULL, then user is expected to contain the credentials pair - * already encoded as `user:pass`. - */ -void mg_basic_auth_header(const char *user, const char *pass, struct mbuf *buf); - -#ifdef __cplusplus -} -#endif /* __cplusplus */ -#endif /* CS_MONGOOSE_SRC_UTIL_H_ */ -#ifdef MG_MODULE_LINES -#line 1 "mongoose/src/http.h" -#endif -/* - * Copyright (c) 2014 Cesanta Software Limited - * All rights reserved - */ - -/* - * === Common API reference - */ - -#ifndef CS_MONGOOSE_SRC_HTTP_H_ -#define CS_MONGOOSE_SRC_HTTP_H_ - -#if MG_ENABLE_HTTP - -/* Amalgamated: #include "mongoose/src/net.h" */ -/* Amalgamated: #include "common/mg_str.h" */ - -#ifdef __cplusplus -extern "C" { -#endif /* __cplusplus */ - -#ifndef MG_MAX_HTTP_HEADERS -#define MG_MAX_HTTP_HEADERS 20 -#endif - -#ifndef MG_MAX_HTTP_REQUEST_SIZE -#define MG_MAX_HTTP_REQUEST_SIZE 1024 -#endif - -#ifndef MG_MAX_PATH -#ifdef PATH_MAX -#define MG_MAX_PATH PATH_MAX -#else -#define MG_MAX_PATH 256 -#endif -#endif - -#ifndef MG_MAX_HTTP_SEND_MBUF -#define MG_MAX_HTTP_SEND_MBUF 1024 -#endif - -#ifndef MG_CGI_ENVIRONMENT_SIZE -#define MG_CGI_ENVIRONMENT_SIZE 8192 -#endif - -/* HTTP message */ -struct http_message { - struct mg_str message; /* Whole message: request line + headers + body */ - - /* HTTP Request line (or HTTP response line) */ - struct mg_str method; /* "GET" */ - struct mg_str uri; /* "/my_file.html" */ - struct mg_str proto; /* "HTTP/1.1" -- for both request and response */ - - /* For responses, code and response status message are set */ - int resp_code; - struct mg_str resp_status_msg; - - /* - * Query-string part of the URI. For example, for HTTP request - * GET /foo/bar?param1=val1¶m2=val2 - * | uri | query_string | - * - * Note that question mark character doesn't belong neither to the uri, - * nor to the query_string - */ - struct mg_str query_string; - - /* Headers */ - struct mg_str header_names[MG_MAX_HTTP_HEADERS]; - struct mg_str header_values[MG_MAX_HTTP_HEADERS]; - - /* Message body */ - struct mg_str body; /* Zero-length for requests with no body */ -}; - -#if MG_ENABLE_HTTP_WEBSOCKET -/* WebSocket message */ -struct websocket_message { - unsigned char *data; - size_t size; - unsigned char flags; -}; -#endif - -/* HTTP multipart part */ -struct mg_http_multipart_part { - const char *file_name; - const char *var_name; - struct mg_str data; - int status; /* <0 on error */ - void *user_data; -}; - -/* SSI call context */ -struct mg_ssi_call_ctx { - struct http_message *req; /* The request being processed. */ - struct mg_str file; /* Filesystem path of the file being processed. */ - struct mg_str arg; /* The argument passed to the tag: . */ -}; - -/* HTTP and websocket events. void *ev_data is described in a comment. */ -#define MG_EV_HTTP_REQUEST 100 /* struct http_message * */ -#define MG_EV_HTTP_REPLY 101 /* struct http_message * */ -#define MG_EV_HTTP_CHUNK 102 /* struct http_message * */ -#define MG_EV_SSI_CALL 105 /* char * */ -#define MG_EV_SSI_CALL_CTX 106 /* struct mg_ssi_call_ctx * */ - -#if MG_ENABLE_HTTP_WEBSOCKET -#define MG_EV_WEBSOCKET_HANDSHAKE_REQUEST 111 /* struct http_message * */ -#define MG_EV_WEBSOCKET_HANDSHAKE_DONE 112 /* NULL */ -#define MG_EV_WEBSOCKET_FRAME 113 /* struct websocket_message * */ -#define MG_EV_WEBSOCKET_CONTROL_FRAME 114 /* struct websocket_message * */ -#endif - -#if MG_ENABLE_HTTP_STREAMING_MULTIPART -#define MG_EV_HTTP_MULTIPART_REQUEST 121 /* struct http_message */ -#define MG_EV_HTTP_PART_BEGIN 122 /* struct mg_http_multipart_part */ -#define MG_EV_HTTP_PART_DATA 123 /* struct mg_http_multipart_part */ -#define MG_EV_HTTP_PART_END 124 /* struct mg_http_multipart_part */ -/* struct mg_http_multipart_part */ -#define MG_EV_HTTP_MULTIPART_REQUEST_END 125 -#endif - -/* - * Attaches a built-in HTTP event handler to the given connection. - * The user-defined event handler will receive following extra events: - * - * - MG_EV_HTTP_REQUEST: HTTP request has arrived. Parsed HTTP request - * is passed as - * `struct http_message` through the handler's `void *ev_data` pointer. - * - MG_EV_HTTP_REPLY: The HTTP reply has arrived. The parsed HTTP reply is - * passed as `struct http_message` through the handler's `void *ev_data` - * pointer. - * - MG_EV_HTTP_CHUNK: The HTTP chunked-encoding chunk has arrived. - * The parsed HTTP reply is passed as `struct http_message` through the - * handler's `void *ev_data` pointer. `http_message::body` would contain - * incomplete, reassembled HTTP body. - * It will grow with every new chunk that arrives, and it can - * potentially consume a lot of memory. An event handler may process - * the body as chunks are coming, and signal Mongoose to delete processed - * body by setting `MG_F_DELETE_CHUNK` in `mg_connection::flags`. When - * the last zero chunk is received, - * Mongoose sends `MG_EV_HTTP_REPLY` event with - * full reassembled body (if handler did not signal to delete chunks) or - * with empty body (if handler did signal to delete chunks). - * - MG_EV_WEBSOCKET_HANDSHAKE_REQUEST: server has received the WebSocket - * handshake request. `ev_data` contains parsed HTTP request. - * - MG_EV_WEBSOCKET_HANDSHAKE_DONE: server has completed the WebSocket - * handshake. `ev_data` is `NULL`. - * - MG_EV_WEBSOCKET_FRAME: new WebSocket frame has arrived. `ev_data` is - * `struct websocket_message *` - * - * When compiled with MG_ENABLE_HTTP_STREAMING_MULTIPART, Mongoose parses - * multipart requests and splits them into separate events: - * - MG_EV_HTTP_MULTIPART_REQUEST: Start of the request. - * This event is sent before body is parsed. After this, the user - * should expect a sequence of PART_BEGIN/DATA/END requests. - * This is also the last time when headers and other request fields are - * accessible. - * - MG_EV_HTTP_PART_BEGIN: Start of a part of a multipart message. - * Argument: mg_http_multipart_part with var_name and file_name set - * (if present). No data is passed in this message. - * - MG_EV_HTTP_PART_DATA: new portion of data from the multipart message. - * Argument: mg_http_multipart_part. var_name and file_name are preserved, - * data is available in mg_http_multipart_part.data. - * - MG_EV_HTTP_PART_END: End of the current part. var_name, file_name are - * the same, no data in the message. If status is 0, then the part is - * properly terminated with a boundary, status < 0 means that connection - * was terminated. - * - MG_EV_HTTP_MULTIPART_REQUEST_END: End of the multipart request. - * Argument: mg_http_multipart_part, var_name and file_name are NULL, - * status = 0 means request was properly closed, < 0 means connection - * was terminated (note: in this case both PART_END and REQUEST_END are - * delivered). - */ -void mg_set_protocol_http_websocket(struct mg_connection *nc); - -#if MG_ENABLE_HTTP_WEBSOCKET -/* - * Send websocket handshake to the server. - * - * `nc` must be a valid connection, connected to a server. `uri` is an URI - * to fetch, extra_headers` is extra HTTP headers to send or `NULL`. - * - * This function is intended to be used by websocket client. - * - * Note that the Host header is mandatory in HTTP/1.1 and must be - * included in `extra_headers`. `mg_send_websocket_handshake2` offers - * a better API for that. - * - * Deprecated in favour of `mg_send_websocket_handshake2` - */ -void mg_send_websocket_handshake(struct mg_connection *nc, const char *uri, - const char *extra_headers); - -/* - * Send websocket handshake to the server. - * - * `nc` must be a valid connection, connected to a server. `uri` is an URI - * to fetch, `host` goes into the `Host` header, `protocol` goes into the - * `Sec-WebSocket-Proto` header (NULL to omit), extra_headers` is extra HTTP - * headers to send or `NULL`. - * - * This function is intended to be used by websocket client. - */ -void mg_send_websocket_handshake2(struct mg_connection *nc, const char *path, - const char *host, const char *protocol, - const char *extra_headers); - -/* Like mg_send_websocket_handshake2 but also passes basic auth header */ -void mg_send_websocket_handshake3(struct mg_connection *nc, const char *path, - const char *host, const char *protocol, - const char *extra_headers, const char *user, - const char *pass); -/* - * Helper function that creates an outbound WebSocket connection. - * - * `url` is a URL to connect to. It must be properly URL-encoded, e.g. have - * no spaces, etc. By default, `mg_connect_ws()` sends Connection and - * Host headers. `extra_headers` is an extra HTTP header to send, e.g. - * `"User-Agent: my-app\r\n"`. - * If `protocol` is not NULL, then a `Sec-WebSocket-Protocol` header is sent. - * - * Examples: - * - * ```c - * nc1 = mg_connect_ws(mgr, ev_handler_1, "ws://echo.websocket.org", NULL, - * NULL); - * nc2 = mg_connect_ws(mgr, ev_handler_1, "wss://echo.websocket.org", NULL, - * NULL); - * nc3 = mg_connect_ws(mgr, ev_handler_1, "ws://api.cesanta.com", - * "clubby.cesanta.com", NULL); - * ``` - */ -struct mg_connection *mg_connect_ws(struct mg_mgr *mgr, - MG_CB(mg_event_handler_t event_handler, - void *user_data), - const char *url, const char *protocol, - const char *extra_headers); - -/* - * Helper function that creates an outbound WebSocket connection - * - * Mostly identical to `mg_connect_ws`, but allows to provide extra parameters - * (for example, SSL parameters) - */ -struct mg_connection *mg_connect_ws_opt( - struct mg_mgr *mgr, MG_CB(mg_event_handler_t ev_handler, void *user_data), - struct mg_connect_opts opts, const char *url, const char *protocol, - const char *extra_headers); - -/* - * Send WebSocket frame to the remote end. - * - * `op_and_flags` specifies the frame's type. It's one of: - * - * - WEBSOCKET_OP_CONTINUE - * - WEBSOCKET_OP_TEXT - * - WEBSOCKET_OP_BINARY - * - WEBSOCKET_OP_CLOSE - * - WEBSOCKET_OP_PING - * - WEBSOCKET_OP_PONG - * - * Orred with one of the flags: - * - * - WEBSOCKET_DONT_FIN: Don't set the FIN flag on the frame to be sent. - * - * `data` and `data_len` contain frame data. - */ -void mg_send_websocket_frame(struct mg_connection *nc, int op_and_flags, - const void *data, size_t data_len); - -/* - * Sends multiple websocket frames. - * - * Like `mg_send_websocket_frame()`, but composes a frame from multiple buffers. - */ -void mg_send_websocket_framev(struct mg_connection *nc, int op_and_flags, - const struct mg_str *strings, int num_strings); - -/* - * Sends WebSocket frame to the remote end. - * - * Like `mg_send_websocket_frame()`, but allows to create formatted messages - * with `printf()`-like semantics. - */ -void mg_printf_websocket_frame(struct mg_connection *nc, int op_and_flags, - const char *fmt, ...); - -/* Websocket opcodes, from http://tools.ietf.org/html/rfc6455 */ -#define WEBSOCKET_OP_CONTINUE 0 -#define WEBSOCKET_OP_TEXT 1 -#define WEBSOCKET_OP_BINARY 2 -#define WEBSOCKET_OP_CLOSE 8 -#define WEBSOCKET_OP_PING 9 -#define WEBSOCKET_OP_PONG 10 - -/* - * If set causes the FIN flag to not be set on outbound - * frames. This enables sending multiple fragments of a single - * logical message. - * - * The WebSocket protocol mandates that if the FIN flag of a data - * frame is not set, the next frame must be a WEBSOCKET_OP_CONTINUE. - * The last frame must have the FIN bit set. - * - * Note that mongoose will automatically defragment incoming messages, - * so this flag is used only on outbound messages. - */ -#define WEBSOCKET_DONT_FIN 0x100 - -#endif /* MG_ENABLE_HTTP_WEBSOCKET */ - -/* - * Decodes a URL-encoded string. - * - * Source string is specified by (`src`, `src_len`), and destination is - * (`dst`, `dst_len`). If `is_form_url_encoded` is non-zero, then - * `+` character is decoded as a blank space character. This function - * guarantees to NUL-terminate the destination. If destination is too small, - * then the source string is partially decoded and `-1` is returned. Otherwise, - * a length of the decoded string is returned, not counting final NUL. - */ -int mg_url_decode(const char *src, int src_len, char *dst, int dst_len, - int is_form_url_encoded); - -#ifdef __cplusplus -} -#endif /* __cplusplus */ - -#endif /* MG_ENABLE_HTTP */ - -#endif /* CS_MONGOOSE_SRC_HTTP_H_ */ -#ifdef MG_MODULE_LINES -#line 1 "mongoose/src/http_server.h" -#endif -/* - * === Server API reference - */ - -#ifndef CS_MONGOOSE_SRC_HTTP_SERVER_H_ -#define CS_MONGOOSE_SRC_HTTP_SERVER_H_ - -#if MG_ENABLE_HTTP - -#ifdef __cplusplus -extern "C" { -#endif /* __cplusplus */ - -/* - * Parses a HTTP message. - * - * `is_req` should be set to 1 if parsing a request, 0 if reply. - * - * Returns the number of bytes parsed. If HTTP message is - * incomplete `0` is returned. On parse error, a negative number is returned. - */ -int mg_parse_http(const char *s, int n, struct http_message *hm, int is_req); - -/* - * Searches and returns the header `name` in parsed HTTP message `hm`. - * If header is not found, NULL is returned. Example: - * - * struct mg_str *host_hdr = mg_get_http_header(hm, "Host"); - */ -struct mg_str *mg_get_http_header(struct http_message *hm, const char *name); - -/* - * Parses the HTTP header `hdr`. Finds variable `var_name` and stores its value - * in the buffer `buf`, `buf_size`. Returns 0 if variable not found, non-zero - * otherwise. - * - * This function is supposed to parse cookies, authentication headers, etc. - * Example (error handling omitted): - * - * char user[20]; - * struct mg_str *hdr = mg_get_http_header(hm, "Authorization"); - * mg_http_parse_header(hdr, "username", user, sizeof(user)); - * - * Returns the length of the variable's value. If buffer is not large enough, - * or variable not found, 0 is returned. - */ -int mg_http_parse_header(struct mg_str *hdr, const char *var_name, char *buf, - size_t buf_size); - -/* - * Gets and parses the Authorization: Basic header - * Returns -1 if no Authorization header is found, or if - * mg_parse_http_basic_auth - * fails parsing the resulting header. - */ -int mg_get_http_basic_auth(struct http_message *hm, char *user, size_t user_len, - char *pass, size_t pass_len); - -/* - * Parses the Authorization: Basic header - * Returns -1 iif the authorization type is not "Basic" or any other error such - * as incorrectly encoded base64 user password pair. - */ -int mg_parse_http_basic_auth(struct mg_str *hdr, char *user, size_t user_len, - char *pass, size_t pass_len); - -/* - * Parses the buffer `buf`, `buf_len` that contains multipart form data chunks. - * Stores the chunk name in a `var_name`, `var_name_len` buffer. - * If a chunk is an uploaded file, then `file_name`, `file_name_len` is - * filled with an uploaded file name. `chunk`, `chunk_len` - * points to the chunk data. - * - * Return: number of bytes to skip to the next chunk or 0 if there are - * no more chunks. - * - * Usage example: - * - * ```c - * static void ev_handler(struct mg_connection *nc, int ev, void *ev_data) { - * switch(ev) { - * case MG_EV_HTTP_REQUEST: { - * struct http_message *hm = (struct http_message *) ev_data; - * char var_name[100], file_name[100]; - * const char *chunk; - * size_t chunk_len, n1, n2; - * - * n1 = n2 = 0; - * while ((n2 = mg_parse_multipart(hm->body.p + n1, - * hm->body.len - n1, - * var_name, sizeof(var_name), - * file_name, sizeof(file_name), - * &chunk, &chunk_len)) > 0) { - * printf("var: %s, file_name: %s, size: %d, chunk: [%.*s]\n", - * var_name, file_name, (int) chunk_len, - * (int) chunk_len, chunk); - * n1 += n2; - * } - * } - * break; - * ``` - */ -size_t mg_parse_multipart(const char *buf, size_t buf_len, char *var_name, - size_t var_name_len, char *file_name, - size_t file_name_len, const char **chunk, - size_t *chunk_len); - -/* - * Fetches a HTTP form variable. - * - * Fetches a variable `name` from a `buf` into a buffer specified by `dst`, - * `dst_len`. The destination is always zero-terminated. Returns the length of - * a fetched variable. If not found, 0 is returned. `buf` must be valid - * url-encoded buffer. If destination is too small or an error occured, - * negative number is returned. - */ -int mg_get_http_var(const struct mg_str *buf, const char *name, char *dst, - size_t dst_len); - -#if MG_ENABLE_FILESYSTEM -/* - * This structure defines how `mg_serve_http()` works. - * Best practice is to set only required settings, and leave the rest as NULL. - */ -struct mg_serve_http_opts { - /* Path to web root directory */ - const char *document_root; - - /* List of index files. Default is "" */ - const char *index_files; - - /* - * Leave as NULL to disable authentication. - * To enable directory protection with authentication, set this to ".htpasswd" - * Then, creating ".htpasswd" file in any directory automatically protects - * it with digest authentication. - * Use `mongoose` web server binary, or `htdigest` Apache utility to - * create/manipulate passwords file. - * Make sure `auth_domain` is set to a valid domain name. - */ - const char *per_directory_auth_file; - - /* Authorization domain (domain name of this web server) */ - const char *auth_domain; - - /* - * Leave as NULL to disable authentication. - * Normally, only selected directories in the document root are protected. - * If absolutely every access to the web server needs to be authenticated, - * regardless of the URI, set this option to the path to the passwords file. - * Format of that file is the same as ".htpasswd" file. Make sure that file - * is located outside document root to prevent people fetching it. - */ - const char *global_auth_file; - - /* Set to "no" to disable directory listing. Enabled by default. */ - const char *enable_directory_listing; - - /* - * SSI files pattern. If not set, "**.shtml$|**.shtm$" is used. - * - * All files that match ssi_pattern are treated as SSI. - * - * Server Side Includes (SSI) is a simple interpreted server-side scripting - * language which is most commonly used to include the contents of a file - * into a web page. It can be useful when it is desirable to include a common - * piece of code throughout a website, for example, headers and footers. - * - * In order for a webpage to recognize an SSI-enabled HTML file, the - * filename should end with a special extension, by default the extension - * should be either .shtml or .shtm - * - * Unknown SSI directives are silently ignored by Mongoose. Currently, - * the following SSI directives are supported: - * <!--#include FILE_TO_INCLUDE --> - * <!--#exec "COMMAND_TO_EXECUTE" --> - * <!--#call COMMAND --> - * - * Note that <!--#include ...> directive supports three path - *specifications: - * - * <!--#include virtual="path" --> Path is relative to web server root - * <!--#include abspath="path" --> Path is absolute or relative to the - * web server working dir - * <!--#include file="path" -->, Path is relative to current document - * <!--#include "path" --> - * - * The include directive may be used to include the contents of a file or - * the result of running a CGI script. - * - * The exec directive is used to execute - * a command on a server, and show command's output. Example: - * - * <!--#exec "ls -l" --> - * - * The call directive is a way to invoke a C handler from the HTML page. - * On each occurence of <!--#call COMMAND OPTIONAL_PARAMS> directive, - * Mongoose calls a registered event handler with MG_EV_SSI_CALL event, - * and event parameter will point to the COMMAND OPTIONAL_PARAMS string. - * An event handler can output any text, for example by calling - * `mg_printf()`. This is a flexible way of generating a web page on - * server side by calling a C event handler. Example: - * - * <!--#call foo --> ... <!--#call bar --> - * - * In the event handler: - * case MG_EV_SSI_CALL: { - * const char *param = (const char *) ev_data; - * if (strcmp(param, "foo") == 0) { - * mg_printf(c, "hello from foo"); - * } else if (strcmp(param, "bar") == 0) { - * mg_printf(c, "hello from bar"); - * } - * break; - * } - */ - const char *ssi_pattern; - - /* IP ACL. By default, NULL, meaning all IPs are allowed to connect */ - const char *ip_acl; - -#if MG_ENABLE_HTTP_URL_REWRITES - /* URL rewrites. - * - * Comma-separated list of `uri_pattern=url_file_or_directory_path` rewrites. - * When HTTP request is received, Mongoose constructs a file name from the - * requested URI by combining `document_root` and the URI. However, if the - * rewrite option is used and `uri_pattern` matches requested URI, then - * `document_root` is ignored. Instead, `url_file_or_directory_path` is used, - * which should be a full path name or a path relative to the web server's - * current working directory. It can also be an URI (http:// or https://) - * in which case mongoose will behave as a reverse proxy for that destination. - * - * Note that `uri_pattern`, as all Mongoose patterns, is a prefix pattern. - * - * If uri_pattern starts with `@` symbol, then Mongoose compares it with the - * HOST header of the request. If they are equal, Mongoose sets document root - * to `file_or_directory_path`, implementing virtual hosts support. - * Example: `@foo.com=/document/root/for/foo.com` - * - * If `uri_pattern` starts with `%` symbol, then Mongoose compares it with - * the listening port. If they match, then Mongoose issues a 301 redirect. - * For example, to redirect all HTTP requests to the - * HTTPS port, do `%80=https://my.site.com`. Note that the request URI is - * automatically appended to the redirect location. - */ - const char *url_rewrites; -#endif - - /* DAV document root. If NULL, DAV requests are going to fail. */ - const char *dav_document_root; - - /* - * DAV passwords file. If NULL, DAV requests are going to fail. - * If passwords file is set to "-", then DAV auth is disabled. - */ - const char *dav_auth_file; - - /* Glob pattern for the files to hide. */ - const char *hidden_file_pattern; - - /* Set to non-NULL to enable CGI, e.g. **.cgi$|**.php$" */ - const char *cgi_file_pattern; - - /* If not NULL, ignore CGI script hashbang and use this interpreter */ - const char *cgi_interpreter; - - /* - * Comma-separated list of Content-Type overrides for path suffixes, e.g. - * ".txt=text/plain; charset=utf-8,.c=text/plain" - */ - const char *custom_mime_types; - - /* - * Extra HTTP headers to add to each server response. - * Example: to enable CORS, set this to "Access-Control-Allow-Origin: *". - */ - const char *extra_headers; -}; - -/* - * Serves given HTTP request according to the `options`. - * - * Example code snippet: - * - * ```c - * static void ev_handler(struct mg_connection *nc, int ev, void *ev_data) { - * struct http_message *hm = (struct http_message *) ev_data; - * struct mg_serve_http_opts opts = { .document_root = "/var/www" }; // C99 - * - * switch (ev) { - * case MG_EV_HTTP_REQUEST: - * mg_serve_http(nc, hm, opts); - * break; - * default: - * break; - * } - * } - * ``` - */ -void mg_serve_http(struct mg_connection *nc, struct http_message *hm, - struct mg_serve_http_opts opts); - -/* - * Serves a specific file with a given MIME type and optional extra headers. - * - * Example code snippet: - * - * ```c - * static void ev_handler(struct mg_connection *nc, int ev, void *ev_data) { - * switch (ev) { - * case MG_EV_HTTP_REQUEST: { - * struct http_message *hm = (struct http_message *) ev_data; - * mg_http_serve_file(nc, hm, "file.txt", - * mg_mk_str("text/plain"), mg_mk_str("")); - * break; - * } - * ... - * } - * } - * ``` - */ -void mg_http_serve_file(struct mg_connection *nc, struct http_message *hm, - const char *path, const struct mg_str mime_type, - const struct mg_str extra_headers); - -#if MG_ENABLE_HTTP_STREAMING_MULTIPART - -/* Callback prototype for `mg_file_upload_handler()`. */ -typedef struct mg_str (*mg_fu_fname_fn)(struct mg_connection *nc, - struct mg_str fname); - -/* - * File upload handler. - * This handler can be used to implement file uploads with minimum code. - * This handler will process MG_EV_HTTP_PART_* events and store file data into - * a local file. - * `local_name_fn` will be invoked with whatever name was provided by the client - * and will expect the name of the local file to open. A return value of NULL - * will abort file upload (client will get a "403 Forbidden" response). If - * non-null, the returned string must be heap-allocated and will be freed by - * the caller. - * Exception: it is ok to return the same string verbatim. - * - * Example: - * - * ```c - * struct mg_str upload_fname(struct mg_connection *nc, struct mg_str fname) { - * // Just return the same filename. Do not actually do this except in test! - * // fname is user-controlled and needs to be sanitized. - * return fname; - * } - * void ev_handler(struct mg_connection *nc, int ev, void *ev_data) { - * switch (ev) { - * ... - * case MG_EV_HTTP_PART_BEGIN: - * case MG_EV_HTTP_PART_DATA: - * case MG_EV_HTTP_PART_END: - * mg_file_upload_handler(nc, ev, ev_data, upload_fname); - * break; - * } - * } - * ``` - */ -void mg_file_upload_handler(struct mg_connection *nc, int ev, void *ev_data, - mg_fu_fname_fn local_name_fn - MG_UD_ARG(void *user_data)); -#endif /* MG_ENABLE_HTTP_STREAMING_MULTIPART */ -#endif /* MG_ENABLE_FILESYSTEM */ - -/* - * Registers a callback for a specified http endpoint - * Note: if callback is registered it is called instead of the - * callback provided in mg_bind - * - * Example code snippet: - * - * ```c - * static void handle_hello1(struct mg_connection *nc, int ev, void *ev_data) { - * (void) ev; (void) ev_data; - * mg_printf(nc, "HTTP/1.0 200 OK\r\n\r\n[I am Hello1]"); - * nc->flags |= MG_F_SEND_AND_CLOSE; - * } - * - * static void handle_hello2(struct mg_connection *nc, int ev, void *ev_data) { - * (void) ev; (void) ev_data; - * mg_printf(nc, "HTTP/1.0 200 OK\r\n\r\n[I am Hello2]"); - * nc->flags |= MG_F_SEND_AND_CLOSE; - * } - * - * void init() { - * nc = mg_bind(&mgr, local_addr, cb1); - * mg_register_http_endpoint(nc, "/hello1", handle_hello1); - * mg_register_http_endpoint(nc, "/hello1/hello2", handle_hello2); - * } - * ``` - */ -void mg_register_http_endpoint(struct mg_connection *nc, const char *uri_path, - MG_CB(mg_event_handler_t handler, - void *user_data)); - -/* - * Authenticates a HTTP request against an opened password file. - * Returns 1 if authenticated, 0 otherwise. - */ -int mg_http_check_digest_auth(struct http_message *hm, const char *auth_domain, - FILE *fp); - -/* - * Sends buffer `buf` of size `len` to the client using chunked HTTP encoding. - * This function sends the buffer size as hex number + newline first, then - * the buffer itself, then the newline. For example, - * `mg_send_http_chunk(nc, "foo", 3)` will append the `3\r\nfoo\r\n` string - * to the `nc->send_mbuf` output IO buffer. - * - * NOTE: The HTTP header "Transfer-Encoding: chunked" should be sent prior to - * using this function. - * - * NOTE: do not forget to send an empty chunk at the end of the response, - * to tell the client that everything was sent. Example: - * - * ``` - * mg_printf_http_chunk(nc, "%s", "my response!"); - * mg_send_http_chunk(nc, "", 0); // Tell the client we're finished - * ``` - */ -void mg_send_http_chunk(struct mg_connection *nc, const char *buf, size_t len); - -/* - * Sends a printf-formatted HTTP chunk. - * Functionality is similar to `mg_send_http_chunk()`. - */ -void mg_printf_http_chunk(struct mg_connection *nc, const char *fmt, ...); - -/* - * Sends the response status line. - * If `extra_headers` is not NULL, then `extra_headers` are also sent - * after the response line. `extra_headers` must NOT end end with new line. - * Example: - * - * mg_send_response_line(nc, 200, "Access-Control-Allow-Origin: *"); - * - * Will result in: - * - * HTTP/1.1 200 OK\r\n - * Access-Control-Allow-Origin: *\r\n - */ -void mg_send_response_line(struct mg_connection *nc, int status_code, - const char *extra_headers); - -/* - * Sends an error response. If reason is NULL, the message will be inferred - * from the error code (if supported). - */ -void mg_http_send_error(struct mg_connection *nc, int code, const char *reason); - -/* - * Sends a redirect response. - * `status_code` should be either 301 or 302 and `location` point to the - * new location. - * If `extra_headers` is not empty, then `extra_headers` are also sent - * after the response line. `extra_headers` must NOT end end with new line. - * - * Example: - * - * mg_http_send_redirect(nc, 302, mg_mk_str("/login"), mg_mk_str(NULL)); - */ -void mg_http_send_redirect(struct mg_connection *nc, int status_code, - const struct mg_str location, - const struct mg_str extra_headers); - -/* - * Sends the response line and headers. - * This function sends the response line with the `status_code`, and - * automatically - * sends one header: either "Content-Length" or "Transfer-Encoding". - * If `content_length` is negative, then "Transfer-Encoding: chunked" header - * is sent, otherwise, "Content-Length" header is sent. - * - * NOTE: If `Transfer-Encoding` is `chunked`, then message body must be sent - * using `mg_send_http_chunk()` or `mg_printf_http_chunk()` functions. - * Otherwise, `mg_send()` or `mg_printf()` must be used. - * Extra headers could be set through `extra_headers`. Note `extra_headers` - * must NOT be terminated by a new line. - */ -void mg_send_head(struct mg_connection *n, int status_code, - int64_t content_length, const char *extra_headers); - -/* - * Sends a printf-formatted HTTP chunk, escaping HTML tags. - */ -void mg_printf_html_escape(struct mg_connection *nc, const char *fmt, ...); - -#if MG_ENABLE_HTTP_URL_REWRITES -/* - * Proxies a given request to a given upstream http server. The path prefix - * in `mount` will be stripped of the path requested to the upstream server, - * e.g. if mount is /api and upstream is http://localhost:8001/foo - * then an incoming request to /api/bar will cause a request to - * http://localhost:8001/foo/bar - * - * EXPERIMENTAL API. Please use http_serve_http + url_rewrites if a static - * mapping is good enough. - */ -void mg_http_reverse_proxy(struct mg_connection *nc, - const struct http_message *hm, struct mg_str mount, - struct mg_str upstream); -#endif - -#ifdef __cplusplus -} -#endif /* __cplusplus */ - -#endif /* MG_ENABLE_HTTP */ - -#endif /* CS_MONGOOSE_SRC_HTTP_SERVER_H_ */ -#ifdef MG_MODULE_LINES -#line 1 "mongoose/src/http_client.h" -#endif -/* - * === Client API reference - */ - -#ifndef CS_MONGOOSE_SRC_HTTP_CLIENT_H_ -#define CS_MONGOOSE_SRC_HTTP_CLIENT_H_ - -#ifdef __cplusplus -extern "C" { -#endif /* __cplusplus */ - -/* - * Helper function that creates an outbound HTTP connection. - * - * `url` is the URL to fetch. It must be properly URL-encoded, e.g. have - * no spaces, etc. By default, `mg_connect_http()` sends the Connection and - * Host headers. `extra_headers` is an extra HTTP header to send, e.g. - * `"User-Agent: my-app\r\n"`. - * If `post_data` is NULL, then a GET request is created. Otherwise, a POST - * request is created with the specified POST data. Note that if the data being - * posted is a form submission, the `Content-Type` header should be set - * accordingly (see example below). - * - * Examples: - * - * ```c - * nc1 = mg_connect_http(mgr, ev_handler_1, "http://www.google.com", NULL, - * NULL); - * nc2 = mg_connect_http(mgr, ev_handler_1, "https://github.com", NULL, NULL); - * nc3 = mg_connect_http( - * mgr, ev_handler_1, "my_server:8000/form_submit/", - * "Content-Type: application/x-www-form-urlencoded\r\n", - * "var_1=value_1&var_2=value_2"); - * ``` - */ -struct mg_connection *mg_connect_http( - struct mg_mgr *mgr, - MG_CB(mg_event_handler_t event_handler, void *user_data), const char *url, - const char *extra_headers, const char *post_data); - -/* - * Helper function that creates an outbound HTTP connection. - * - * Mostly identical to mg_connect_http, but allows you to provide extra - *parameters - * (for example, SSL parameters) - */ -struct mg_connection *mg_connect_http_opt( - struct mg_mgr *mgr, MG_CB(mg_event_handler_t ev_handler, void *user_data), - struct mg_connect_opts opts, const char *url, const char *extra_headers, - const char *post_data); - -/* Creates digest authentication header for a client request. */ -int mg_http_create_digest_auth_header(char *buf, size_t buf_len, - const char *method, const char *uri, - const char *auth_domain, const char *user, - const char *passwd); - -#ifdef __cplusplus -} -#endif /* __cplusplus */ -#endif /* CS_MONGOOSE_SRC_HTTP_CLIENT_H_ */ -#ifdef MG_MODULE_LINES -#line 1 "mongoose/src/mqtt.h" -#endif -/* - * Copyright (c) 2014 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. - * - * Alternatively, you can license this software under a commercial - * license, as set out in . - */ - -/* - * === MQTT API reference - */ - -#ifndef CS_MONGOOSE_SRC_MQTT_H_ -#define CS_MONGOOSE_SRC_MQTT_H_ - -/* Amalgamated: #include "mongoose/src/net.h" */ - -struct mg_mqtt_message { - int cmd; - int qos; - struct mg_str topic; - struct mg_str payload; - - uint8_t connack_ret_code; /* connack */ - uint16_t message_id; /* puback */ - - /* connect */ - uint8_t protocol_version; - uint8_t connect_flags; - uint16_t keep_alive_timer; - struct mg_str protocol_name; - struct mg_str client_id; - struct mg_str will_topic; - struct mg_str will_message; - struct mg_str user_name; - struct mg_str password; -}; - -struct mg_mqtt_topic_expression { - const char *topic; - uint8_t qos; -}; - -struct mg_send_mqtt_handshake_opts { - unsigned char flags; /* connection flags */ - uint16_t keep_alive; - const char *will_topic; - const char *will_message; - const char *user_name; - const char *password; -}; - -/* mg_mqtt_proto_data should be in header to allow external access to it */ -struct mg_mqtt_proto_data { - uint16_t keep_alive; -}; - -/* Message types */ -#define MG_MQTT_CMD_CONNECT 1 -#define MG_MQTT_CMD_CONNACK 2 -#define MG_MQTT_CMD_PUBLISH 3 -#define MG_MQTT_CMD_PUBACK 4 -#define MG_MQTT_CMD_PUBREC 5 -#define MG_MQTT_CMD_PUBREL 6 -#define MG_MQTT_CMD_PUBCOMP 7 -#define MG_MQTT_CMD_SUBSCRIBE 8 -#define MG_MQTT_CMD_SUBACK 9 -#define MG_MQTT_CMD_UNSUBSCRIBE 10 -#define MG_MQTT_CMD_UNSUBACK 11 -#define MG_MQTT_CMD_PINGREQ 12 -#define MG_MQTT_CMD_PINGRESP 13 -#define MG_MQTT_CMD_DISCONNECT 14 - -/* MQTT event types */ -#define MG_MQTT_EVENT_BASE 200 -#define MG_EV_MQTT_CONNECT (MG_MQTT_EVENT_BASE + MG_MQTT_CMD_CONNECT) -#define MG_EV_MQTT_CONNACK (MG_MQTT_EVENT_BASE + MG_MQTT_CMD_CONNACK) -#define MG_EV_MQTT_PUBLISH (MG_MQTT_EVENT_BASE + MG_MQTT_CMD_PUBLISH) -#define MG_EV_MQTT_PUBACK (MG_MQTT_EVENT_BASE + MG_MQTT_CMD_PUBACK) -#define MG_EV_MQTT_PUBREC (MG_MQTT_EVENT_BASE + MG_MQTT_CMD_PUBREC) -#define MG_EV_MQTT_PUBREL (MG_MQTT_EVENT_BASE + MG_MQTT_CMD_PUBREL) -#define MG_EV_MQTT_PUBCOMP (MG_MQTT_EVENT_BASE + MG_MQTT_CMD_PUBCOMP) -#define MG_EV_MQTT_SUBSCRIBE (MG_MQTT_EVENT_BASE + MG_MQTT_CMD_SUBSCRIBE) -#define MG_EV_MQTT_SUBACK (MG_MQTT_EVENT_BASE + MG_MQTT_CMD_SUBACK) -#define MG_EV_MQTT_UNSUBSCRIBE (MG_MQTT_EVENT_BASE + MG_MQTT_CMD_UNSUBSCRIBE) -#define MG_EV_MQTT_UNSUBACK (MG_MQTT_EVENT_BASE + MG_MQTT_CMD_UNSUBACK) -#define MG_EV_MQTT_PINGREQ (MG_MQTT_EVENT_BASE + MG_MQTT_CMD_PINGREQ) -#define MG_EV_MQTT_PINGRESP (MG_MQTT_EVENT_BASE + MG_MQTT_CMD_PINGRESP) -#define MG_EV_MQTT_DISCONNECT (MG_MQTT_EVENT_BASE + MG_MQTT_CMD_DISCONNECT) - -/* Message flags */ -#define MG_MQTT_RETAIN 0x1 -#define MG_MQTT_DUP 0x4 -#define MG_MQTT_QOS(qos) ((qos) << 1) -#define MG_MQTT_GET_QOS(flags) (((flags) &0x6) >> 1) -#define MG_MQTT_SET_QOS(flags, qos) (flags) = ((flags) & ~0x6) | ((qos) << 1) - -/* Connection flags */ -#define MG_MQTT_CLEAN_SESSION 0x02 -#define MG_MQTT_HAS_WILL 0x04 -#define MG_MQTT_WILL_RETAIN 0x20 -#define MG_MQTT_HAS_PASSWORD 0x40 -#define MG_MQTT_HAS_USER_NAME 0x80 -#define MG_MQTT_GET_WILL_QOS(flags) (((flags) &0x18) >> 3) -#define MG_MQTT_SET_WILL_QOS(flags, qos) \ - (flags) = ((flags) & ~0x18) | ((qos) << 3) - -/* CONNACK return codes */ -#define MG_EV_MQTT_CONNACK_ACCEPTED 0 -#define MG_EV_MQTT_CONNACK_UNACCEPTABLE_VERSION 1 -#define MG_EV_MQTT_CONNACK_IDENTIFIER_REJECTED 2 -#define MG_EV_MQTT_CONNACK_SERVER_UNAVAILABLE 3 -#define MG_EV_MQTT_CONNACK_BAD_AUTH 4 -#define MG_EV_MQTT_CONNACK_NOT_AUTHORIZED 5 - -#ifdef __cplusplus -extern "C" { -#endif /* __cplusplus */ - -/* - * Attaches a built-in MQTT event handler to the given connection. - * - * The user-defined event handler will receive following extra events: - * - * - MG_EV_MQTT_CONNACK - * - MG_EV_MQTT_PUBLISH - * - MG_EV_MQTT_PUBACK - * - MG_EV_MQTT_PUBREC - * - MG_EV_MQTT_PUBREL - * - MG_EV_MQTT_PUBCOMP - * - MG_EV_MQTT_SUBACK - */ -void mg_set_protocol_mqtt(struct mg_connection *nc); - -/* Sends an MQTT handshake. */ -void mg_send_mqtt_handshake(struct mg_connection *nc, const char *client_id); - -/* Sends an MQTT handshake with optional parameters. */ -void mg_send_mqtt_handshake_opt(struct mg_connection *nc, const char *client_id, - struct mg_send_mqtt_handshake_opts); - -/* Publishes a message to a given topic. */ -void mg_mqtt_publish(struct mg_connection *nc, const char *topic, - uint16_t message_id, int flags, const void *data, - size_t len); - -/* Subscribes to a bunch of topics. */ -void mg_mqtt_subscribe(struct mg_connection *nc, - const struct mg_mqtt_topic_expression *topics, - size_t topics_len, uint16_t message_id); - -/* Unsubscribes from a bunch of topics. */ -void mg_mqtt_unsubscribe(struct mg_connection *nc, char **topics, - size_t topics_len, uint16_t message_id); - -/* Sends a DISCONNECT command. */ -void mg_mqtt_disconnect(struct mg_connection *nc); - -/* Sends a CONNACK command with a given `return_code`. */ -void mg_mqtt_connack(struct mg_connection *nc, uint8_t return_code); - -/* Sends a PUBACK command with a given `message_id`. */ -void mg_mqtt_puback(struct mg_connection *nc, uint16_t message_id); - -/* Sends a PUBREC command with a given `message_id`. */ -void mg_mqtt_pubrec(struct mg_connection *nc, uint16_t message_id); - -/* Sends a PUBREL command with a given `message_id`. */ -void mg_mqtt_pubrel(struct mg_connection *nc, uint16_t message_id); - -/* Sends a PUBCOMP command with a given `message_id`. */ -void mg_mqtt_pubcomp(struct mg_connection *nc, uint16_t message_id); - -/* - * Sends a SUBACK command with a given `message_id` - * and a sequence of granted QoSs. - */ -void mg_mqtt_suback(struct mg_connection *nc, uint8_t *qoss, size_t qoss_len, - uint16_t message_id); - -/* Sends a UNSUBACK command with a given `message_id`. */ -void mg_mqtt_unsuback(struct mg_connection *nc, uint16_t message_id); - -/* Sends a PINGREQ command. */ -void mg_mqtt_ping(struct mg_connection *nc); - -/* Sends a PINGRESP command. */ -void mg_mqtt_pong(struct mg_connection *nc); - -/* - * Extracts the next topic expression from a SUBSCRIBE command payload. - * - * The topic expression name will point to a string in the payload buffer. - * Returns the pos of the next topic expression or -1 when the list - * of topics is exhausted. - */ -int mg_mqtt_next_subscribe_topic(struct mg_mqtt_message *msg, - struct mg_str *topic, uint8_t *qos, int pos); - -/* - * Matches a topic against a topic expression - * - * Returns 1 if it matches; 0 otherwise. - */ -int mg_mqtt_match_topic_expression(struct mg_str exp, struct mg_str topic); - -/* - * Same as `mg_mqtt_match_topic_expression()`, but takes `exp` as a - * NULL-terminated string. - */ -int mg_mqtt_vmatch_topic_expression(const char *exp, struct mg_str topic); - -#ifdef __cplusplus -} -#endif /* __cplusplus */ - -#endif /* CS_MONGOOSE_SRC_MQTT_H_ */ -#ifdef MG_MODULE_LINES -#line 1 "mongoose/src/mqtt_server.h" -#endif -/* - * Copyright (c) 2014 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. - * - * Alternatively, you can license this software under a commercial - * license, as set out in . - */ - -/* - * === MQTT Server API reference - */ - -#ifndef CS_MONGOOSE_SRC_MQTT_BROKER_H_ -#define CS_MONGOOSE_SRC_MQTT_BROKER_H_ - -#if MG_ENABLE_MQTT_BROKER - -/* Amalgamated: #include "common/queue.h" */ -/* Amalgamated: #include "mongoose/src/mqtt.h" */ - -#ifdef __cplusplus -extern "C" { -#endif /* __cplusplus */ - -#define MG_MQTT_MAX_SESSION_SUBSCRIPTIONS 512; - -struct mg_mqtt_broker; - -/* MQTT session (Broker side). */ -struct mg_mqtt_session { - struct mg_mqtt_broker *brk; /* Broker */ - LIST_ENTRY(mg_mqtt_session) link; /* mg_mqtt_broker::sessions linkage */ - struct mg_connection *nc; /* Connection with the client */ - size_t num_subscriptions; /* Size of `subscriptions` array */ - void *user_data; /* User data */ - struct mg_mqtt_topic_expression *subscriptions; -}; - -/* MQTT broker. */ -struct mg_mqtt_broker { - LIST_HEAD(_mg_sesshead, mg_mqtt_session) sessions; /* Session list */ - void *user_data; /* User data */ -}; - -/* Initialises a MQTT broker. */ -void mg_mqtt_broker_init(struct mg_mqtt_broker *brk, void *user_data); - -/* - * Processes a MQTT broker message. - * - * The listening connection expects a pointer to an initialised - * `mg_mqtt_broker` structure in the `user_data` field. - * - * Basic usage: - * - * ```c - * mg_mqtt_broker_init(&brk, NULL); - * - * if ((nc = mg_bind(&mgr, address, mg_mqtt_broker)) == NULL) { - * // fail; - * } - * nc->user_data = &brk; - * ``` - * - * New incoming connections will receive a `mg_mqtt_session` structure - * in the connection `user_data`. The original `user_data` will be stored - * in the `user_data` field of the session structure. This allows the user - * handler to store user data before `mg_mqtt_broker` creates the session. - * - * Since only the MG_EV_ACCEPT message is processed by the listening socket, - * for most events the `user_data` will thus point to a `mg_mqtt_session`. - */ -void mg_mqtt_broker(struct mg_connection *brk, int ev, void *data); - -/* - * Iterates over all MQTT session connections. Example: - * - * ```c - * struct mg_mqtt_session *s; - * for (s = mg_mqtt_next(brk, NULL); s != NULL; s = mg_mqtt_next(brk, s)) { - * // Do something - * } - * ``` - */ -struct mg_mqtt_session *mg_mqtt_next(struct mg_mqtt_broker *brk, - struct mg_mqtt_session *s); - -#ifdef __cplusplus -} -#endif /* __cplusplus */ - -#endif /* MG_ENABLE_MQTT_BROKER */ -#endif /* CS_MONGOOSE_SRC_MQTT_BROKER_H_ */ -#ifdef MG_MODULE_LINES -#line 1 "mongoose/src/dns.h" -#endif -/* - * Copyright (c) 2014 Cesanta Software Limited - * All rights reserved - */ - -/* - * === DNS API reference - */ - -#ifndef CS_MONGOOSE_SRC_DNS_H_ -#define CS_MONGOOSE_SRC_DNS_H_ - -/* Amalgamated: #include "mongoose/src/net.h" */ - -#ifdef __cplusplus -extern "C" { -#endif /* __cplusplus */ - -#define MG_DNS_A_RECORD 0x01 /* Lookup IP address */ -#define MG_DNS_CNAME_RECORD 0x05 /* Lookup CNAME */ -#define MG_DNS_PTR_RECORD 0x0c /* Lookup PTR */ -#define MG_DNS_TXT_RECORD 0x10 /* Lookup TXT */ -#define MG_DNS_AAAA_RECORD 0x1c /* Lookup IPv6 address */ -#define MG_DNS_SRV_RECORD 0x21 /* Lookup SRV */ -#define MG_DNS_MX_RECORD 0x0f /* Lookup mail server for domain */ - -#define MG_MAX_DNS_QUESTIONS 32 -#define MG_MAX_DNS_ANSWERS 32 - -#define MG_DNS_MESSAGE 100 /* High-level DNS message event */ - -enum mg_dns_resource_record_kind { - MG_DNS_INVALID_RECORD = 0, - MG_DNS_QUESTION, - MG_DNS_ANSWER -}; - -/* DNS resource record. */ -struct mg_dns_resource_record { - struct mg_str name; /* buffer with compressed name */ - int rtype; - int rclass; - int ttl; - enum mg_dns_resource_record_kind kind; - struct mg_str rdata; /* protocol data (can be a compressed name) */ -}; - -/* DNS message (request and response). */ -struct mg_dns_message { - struct mg_str pkt; /* packet body */ - uint16_t flags; - uint16_t transaction_id; - int num_questions; - int num_answers; - struct mg_dns_resource_record questions[MG_MAX_DNS_QUESTIONS]; - struct mg_dns_resource_record answers[MG_MAX_DNS_ANSWERS]; -}; - -struct mg_dns_resource_record *mg_dns_next_record( - struct mg_dns_message *msg, int query, struct mg_dns_resource_record *prev); - -/* - * Parses the record data from a DNS resource record. - * - * - A: struct in_addr *ina - * - AAAA: struct in6_addr *ina - * - CNAME: char buffer - * - * Returns -1 on error. - * - * TODO(mkm): MX - */ -int mg_dns_parse_record_data(struct mg_dns_message *msg, - struct mg_dns_resource_record *rr, void *data, - size_t data_len); - -/* - * Sends a DNS query to the remote end. - */ -void mg_send_dns_query(struct mg_connection *nc, const char *name, - int query_type); - -/* - * Inserts a DNS header to an IO buffer. - * - * Returns the number of bytes inserted. - */ -int mg_dns_insert_header(struct mbuf *io, size_t pos, - struct mg_dns_message *msg); - -/* - * Appends already encoded questions from an existing message. - * - * This is useful when generating a DNS reply message which includes - * all question records. - * - * Returns the number of appended bytes. - */ -int mg_dns_copy_questions(struct mbuf *io, struct mg_dns_message *msg); - -/* - * Encodes and appends a DNS resource record to an IO buffer. - * - * The record metadata is taken from the `rr` parameter, while the name and data - * are taken from the parameters, encoded in the appropriate format depending on - * record type and stored in the IO buffer. The encoded values might contain - * offsets within the IO buffer. It's thus important that the IO buffer doesn't - * get trimmed while a sequence of records are encoded while preparing a DNS - * reply. - * - * This function doesn't update the `name` and `rdata` pointers in the `rr` - * struct because they might be invalidated as soon as the IO buffer grows - * again. - * - * Returns the number of bytes appended or -1 in case of error. - */ -int mg_dns_encode_record(struct mbuf *io, struct mg_dns_resource_record *rr, - const char *name, size_t nlen, const void *rdata, - size_t rlen); - -/* - * Encodes a DNS name. - */ -int mg_dns_encode_name(struct mbuf *io, const char *name, size_t len); - -/* Low-level: parses a DNS response. */ -int mg_parse_dns(const char *buf, int len, struct mg_dns_message *msg); - -/* - * Uncompresses a DNS compressed name. - * - * The containing DNS message is required because of the compressed encoding - * and reference suffixes present elsewhere in the packet. - * - * If the name is less than `dst_len` characters long, the remainder - * of `dst` is terminated with `\0` characters. Otherwise, `dst` is not - * terminated. - * - * If `dst_len` is 0 `dst` can be NULL. - * Returns the uncompressed name length. - */ -size_t mg_dns_uncompress_name(struct mg_dns_message *msg, struct mg_str *name, - char *dst, int dst_len); - -/* - * Attaches a built-in DNS event handler to the given listening connection. - * - * The DNS event handler parses the incoming UDP packets, treating them as DNS - * requests. If an incoming packet gets successfully parsed by the DNS event - * handler, a user event handler will receive an `MG_DNS_REQUEST` event, with - * `ev_data` pointing to the parsed `struct mg_dns_message`. - * - * See - * [captive_dns_server](https://github.com/cesanta/mongoose/tree/master/examples/captive_dns_server) - * example on how to handle DNS request and send DNS reply. - */ -void mg_set_protocol_dns(struct mg_connection *nc); - -#ifdef __cplusplus -} -#endif /* __cplusplus */ -#endif /* CS_MONGOOSE_SRC_DNS_H_ */ -#ifdef MG_MODULE_LINES -#line 1 "mongoose/src/dns_server.h" -#endif -/* - * Copyright (c) 2014 Cesanta Software Limited - * All rights reserved - */ - -/* - * === DNS server API reference - * - * Disabled by default; enable with `-DMG_ENABLE_DNS_SERVER`. - */ - -#ifndef CS_MONGOOSE_SRC_DNS_SERVER_H_ -#define CS_MONGOOSE_SRC_DNS_SERVER_H_ - -#if MG_ENABLE_DNS_SERVER - -/* Amalgamated: #include "mongoose/src/dns.h" */ - -#ifdef __cplusplus -extern "C" { -#endif /* __cplusplus */ - -#define MG_DNS_SERVER_DEFAULT_TTL 3600 - -struct mg_dns_reply { - struct mg_dns_message *msg; - struct mbuf *io; - size_t start; -}; - -/* - * Creates a DNS reply. - * - * The reply will be based on an existing query message `msg`. - * The query body will be appended to the output buffer. - * "reply + recursion allowed" will be added to the message flags and the - * message's num_answers will be set to 0. - * - * Answer records can be appended with `mg_dns_send_reply` or by lower - * level function defined in the DNS API. - * - * In order to send a reply use `mg_dns_send_reply`. - * It's possible to use a connection's send buffer as reply buffer, - * and it will work for both UDP and TCP connections. - * - * Example: - * - * ```c - * reply = mg_dns_create_reply(&nc->send_mbuf, msg); - * for (i = 0; i < msg->num_questions; i++) { - * rr = &msg->questions[i]; - * if (rr->rtype == MG_DNS_A_RECORD) { - * mg_dns_reply_record(&reply, rr, 3600, &dummy_ip_addr, 4); - * } - * } - * mg_dns_send_reply(nc, &reply); - * ``` - */ -struct mg_dns_reply mg_dns_create_reply(struct mbuf *io, - struct mg_dns_message *msg); - -/* - * Appends a DNS reply record to the IO buffer and to the DNS message. - * - * The message's num_answers field will be incremented. It's the caller's duty - * to ensure num_answers is properly initialised. - * - * Returns -1 on error. - */ -int mg_dns_reply_record(struct mg_dns_reply *reply, - struct mg_dns_resource_record *question, - const char *name, int rtype, int ttl, const void *rdata, - size_t rdata_len); - -/* - * Sends a DNS reply through a connection. - * - * The DNS data is stored in an IO buffer pointed by reply structure in `r`. - * This function mutates the content of that buffer in order to ensure that - * the DNS header reflects the size and flags of the message, that might have - * been updated either with `mg_dns_reply_record` or by direct manipulation of - * `r->message`. - * - * Once sent, the IO buffer will be trimmed unless the reply IO buffer - * is the connection's send buffer and the connection is not in UDP mode. - */ -void mg_dns_send_reply(struct mg_connection *nc, struct mg_dns_reply *r); - -#ifdef __cplusplus -} -#endif /* __cplusplus */ - -#endif /* MG_ENABLE_DNS_SERVER */ -#endif /* CS_MONGOOSE_SRC_DNS_SERVER_H_ */ -#ifdef MG_MODULE_LINES -#line 1 "mongoose/src/resolv.h" -#endif -/* - * Copyright (c) 2014 Cesanta Software Limited - * All rights reserved - */ - -/* - * === API reference - */ - -#ifndef CS_MONGOOSE_SRC_RESOLV_H_ -#define CS_MONGOOSE_SRC_RESOLV_H_ - -/* Amalgamated: #include "mongoose/src/dns.h" */ - -#ifdef __cplusplus -extern "C" { -#endif /* __cplusplus */ - -enum mg_resolve_err { - MG_RESOLVE_OK = 0, - MG_RESOLVE_NO_ANSWERS = 1, - MG_RESOLVE_EXCEEDED_RETRY_COUNT = 2, - MG_RESOLVE_TIMEOUT = 3 -}; - -typedef void (*mg_resolve_callback_t)(struct mg_dns_message *dns_message, - void *user_data, enum mg_resolve_err); - -/* Options for `mg_resolve_async_opt`. */ -struct mg_resolve_async_opts { - const char *nameserver; - int max_retries; /* defaults to 2 if zero */ - int timeout; /* in seconds; defaults to 5 if zero */ - int accept_literal; /* pseudo-resolve literal ipv4 and ipv6 addrs */ - int only_literal; /* only resolves literal addrs; sync cb invocation */ - struct mg_connection **dns_conn; /* return DNS connection */ -}; - -/* See `mg_resolve_async_opt()` */ -int mg_resolve_async(struct mg_mgr *mgr, const char *name, int query, - mg_resolve_callback_t cb, void *data); - -/* Set default DNS server */ -void mg_set_nameserver(struct mg_mgr *mgr, const char *nameserver); - -/* - * Resolved a DNS name asynchronously. - * - * Upon successful resolution, the user callback will be invoked - * with the full DNS response message and a pointer to the user's - * context `data`. - * - * In case of timeout while performing the resolution the callback - * will receive a NULL `msg`. - * - * The DNS answers can be extracted with `mg_next_record` and - * `mg_dns_parse_record_data`: - * - * [source,c] - * ---- - * struct in_addr ina; - * struct mg_dns_resource_record *rr = mg_next_record(msg, MG_DNS_A_RECORD, - * NULL); - * mg_dns_parse_record_data(msg, rr, &ina, sizeof(ina)); - * ---- - */ -int mg_resolve_async_opt(struct mg_mgr *mgr, const char *name, int query, - mg_resolve_callback_t cb, void *data, - struct mg_resolve_async_opts opts); - -/* - * Resolve a name from `/etc/hosts`. - * - * Returns 0 on success, -1 on failure. - */ -int mg_resolve_from_hosts_file(const char *host, union socket_address *usa); - -#ifdef __cplusplus -} -#endif /* __cplusplus */ -#endif /* CS_MONGOOSE_SRC_RESOLV_H_ */ -#ifdef MG_MODULE_LINES -#line 1 "mongoose/src/coap.h" -#endif -/* - * Copyright (c) 2015 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. - * - * Alternatively, you can license this software under a commercial - * license, as set out in . - */ - -/* - * === CoAP API reference - * - * CoAP message format: - * - * ``` - * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+- - * |Ver| T | TKL | Code | Message ID | Token (if any, TKL bytes) ... - * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+- - * | Options (if any) ... |1 1 1 1 1 1 1 1| Payload (if any) ... - * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+- - * ``` - */ - -#ifndef CS_MONGOOSE_SRC_COAP_H_ -#define CS_MONGOOSE_SRC_COAP_H_ - -#if MG_ENABLE_COAP - -#define MG_COAP_MSG_TYPE_FIELD 0x2 -#define MG_COAP_CODE_CLASS_FIELD 0x4 -#define MG_COAP_CODE_DETAIL_FIELD 0x8 -#define MG_COAP_MSG_ID_FIELD 0x10 -#define MG_COAP_TOKEN_FIELD 0x20 -#define MG_COAP_OPTIOMG_FIELD 0x40 -#define MG_COAP_PAYLOAD_FIELD 0x80 - -#define MG_COAP_ERROR 0x10000 -#define MG_COAP_FORMAT_ERROR (MG_COAP_ERROR | 0x20000) -#define MG_COAP_IGNORE (MG_COAP_ERROR | 0x40000) -#define MG_COAP_NOT_ENOUGH_DATA (MG_COAP_ERROR | 0x80000) -#define MG_COAP_NETWORK_ERROR (MG_COAP_ERROR | 0x100000) - -#define MG_COAP_MSG_CON 0 -#define MG_COAP_MSG_NOC 1 -#define MG_COAP_MSG_ACK 2 -#define MG_COAP_MSG_RST 3 -#define MG_COAP_MSG_MAX 3 - -#define MG_COAP_CODECLASS_REQUEST 0 -#define MG_COAP_CODECLASS_RESP_OK 2 -#define MG_COAP_CODECLASS_CLIENT_ERR 4 -#define MG_COAP_CODECLASS_SRV_ERR 5 - -#define MG_COAP_EVENT_BASE 300 -#define MG_EV_COAP_CON (MG_COAP_EVENT_BASE + MG_COAP_MSG_CON) -#define MG_EV_COAP_NOC (MG_COAP_EVENT_BASE + MG_COAP_MSG_NOC) -#define MG_EV_COAP_ACK (MG_COAP_EVENT_BASE + MG_COAP_MSG_ACK) -#define MG_EV_COAP_RST (MG_COAP_EVENT_BASE + MG_COAP_MSG_RST) - -/* - * CoAP options. - * Use mg_coap_add_option and mg_coap_free_options - * for creation and destruction. - */ -struct mg_coap_option { - struct mg_coap_option *next; - uint32_t number; - struct mg_str value; -}; - -/* CoAP message. See RFC 7252 for details. */ -struct mg_coap_message { - uint32_t flags; - uint8_t msg_type; - uint8_t code_class; - uint8_t code_detail; - uint16_t msg_id; - struct mg_str token; - struct mg_coap_option *options; - struct mg_str payload; - struct mg_coap_option *optiomg_tail; -}; - -#ifdef __cplusplus -extern "C" { -#endif /* __cplusplus */ - -/* Sets CoAP protocol handler - triggers CoAP specific events. */ -int mg_set_protocol_coap(struct mg_connection *nc); - -/* - * Adds a new option to mg_coap_message structure. - * Returns pointer to the newly created option. - * Note: options must be freed by using mg_coap_free_options - */ -struct mg_coap_option *mg_coap_add_option(struct mg_coap_message *cm, - uint32_t number, char *value, - size_t len); - -/* - * Frees the memory allocated for options. - * If the cm parameter doesn't contain any option it does nothing. - */ -void mg_coap_free_options(struct mg_coap_message *cm); - -/* - * Composes a CoAP message from `mg_coap_message` - * and sends it into `nc` connection. - * Returns 0 on success. On error, it is a bitmask: - * - * - `#define MG_COAP_ERROR 0x10000` - * - `#define MG_COAP_FORMAT_ERROR (MG_COAP_ERROR | 0x20000)` - * - `#define MG_COAP_IGNORE (MG_COAP_ERROR | 0x40000)` - * - `#define MG_COAP_NOT_ENOUGH_DATA (MG_COAP_ERROR | 0x80000)` - * - `#define MG_COAP_NETWORK_ERROR (MG_COAP_ERROR | 0x100000)` - */ -uint32_t mg_coap_send_message(struct mg_connection *nc, - struct mg_coap_message *cm); - -/* - * Composes CoAP acknowledgement from `mg_coap_message` - * and sends it into `nc` connection. - * Return value: see `mg_coap_send_message()` - */ -uint32_t mg_coap_send_ack(struct mg_connection *nc, uint16_t msg_id); - -/* - * Parses CoAP message and fills mg_coap_message and returns cm->flags. - * This is a helper function. - * - * NOTE: usually CoAP works over UDP, so lack of data means format error. - * But, in theory, it is possible to use CoAP over TCP (according to RFC) - * - * The caller has to check results and treat COAP_NOT_ENOUGH_DATA according to - * underlying protocol: - * - * - in case of UDP COAP_NOT_ENOUGH_DATA means COAP_FORMAT_ERROR, - * - in case of TCP client can try to receive more data - * - * Return value: see `mg_coap_send_message()` - */ -uint32_t mg_coap_parse(struct mbuf *io, struct mg_coap_message *cm); - -/* - * Composes CoAP message from mg_coap_message structure. - * This is a helper function. - * Return value: see `mg_coap_send_message()` - */ -uint32_t mg_coap_compose(struct mg_coap_message *cm, struct mbuf *io); - -#ifdef __cplusplus -} -#endif /* __cplusplus */ - -#endif /* MG_ENABLE_COAP */ - -#endif /* CS_MONGOOSE_SRC_COAP_H_ */ -#ifdef MG_MODULE_LINES -#line 1 "mongoose/src/sntp.h" -#endif -/* - * Copyright (c) 2016 Cesanta Software Limited - * All rights reserved - */ - -#ifndef CS_MONGOOSE_SRC_SNTP_H_ -#define CS_MONGOOSE_SRC_SNTP_H_ - -#if MG_ENABLE_SNTP - -#define MG_SNTP_EVENT_BASE 500 - -/* - * Received reply from time server. Event handler parameter contains - * pointer to mg_sntp_message structure - */ -#define MG_SNTP_REPLY (MG_SNTP_EVENT_BASE + 1) - -/* Received malformed SNTP packet */ -#define MG_SNTP_MALFORMED_REPLY (MG_SNTP_EVENT_BASE + 2) - -/* Failed to get time from server (timeout etc) */ -#define MG_SNTP_FAILED (MG_SNTP_EVENT_BASE + 3) - -struct mg_sntp_message { - /* if server sends this flags, user should not send requests to it */ - int kiss_of_death; - /* usual mg_time */ - double time; -}; - -/* Establishes connection to given sntp server */ -struct mg_connection *mg_sntp_connect(struct mg_mgr *mgr, - MG_CB(mg_event_handler_t event_handler, - void *user_data), - const char *sntp_server_name); - -/* Sends time request to given connection */ -void mg_sntp_send_request(struct mg_connection *c); - -/* - * Helper function - * Establishes connection to time server, tries to send request - * repeats sending SNTP_ATTEMPTS times every SNTP_TIMEOUT sec - * (if needed) - * See sntp_client example - */ -struct mg_connection *mg_sntp_get_time(struct mg_mgr *mgr, - mg_event_handler_t event_handler, - const char *sntp_server_name); - -#endif - -#endif /* CS_MONGOOSE_SRC_SNTP_H_ */ diff --git a/examples/ESP8266_RTOS/user/mongoose.h b/examples/ESP8266_RTOS/user/mongoose.h new file mode 120000 index 00000000..ee4ac823 --- /dev/null +++ b/examples/ESP8266_RTOS/user/mongoose.h @@ -0,0 +1 @@ +../../../mongoose.h \ No newline at end of file From cfe77a3d5854853f3345c0e14e7bc126860d118f Mon Sep 17 00:00:00 2001 From: Sergey Lyubka Date: Sat, 6 May 2017 12:16:34 +0100 Subject: [PATCH 071/137] Move struct http_message::body Rationale: this is the optimisation to make JS FFI-ed API work nicer. We don't have strucuture introspection now, and do not generate offsets automatially. Thus, using a stable well-known location of the parsed message body is better, in case of number of HTTP headers macro changes. PUBLISHED_FROM=55bf25ac77060a9c81dfecd6601f037562530801 --- docs/c-api/http.h/struct_http_message.md | 4 +--- mongoose.h | 4 +--- 2 files changed, 2 insertions(+), 6 deletions(-) diff --git a/docs/c-api/http.h/struct_http_message.md b/docs/c-api/http.h/struct_http_message.md index 60eae685..9380496d 100644 --- a/docs/c-api/http.h/struct_http_message.md +++ b/docs/c-api/http.h/struct_http_message.md @@ -5,6 +5,7 @@ symbol_kind: "struct" signature: | struct http_message { struct mg_str message; /* Whole message: request line + headers + body */ + struct mg_str body; /* Message body. 0-length for requests with no body */ /* HTTP Request line (or HTTP response line) */ struct mg_str method; /* "GET" */ @@ -28,9 +29,6 @@ signature: | /* Headers */ struct mg_str header_names[MG_MAX_HTTP_HEADERS]; struct mg_str header_values[MG_MAX_HTTP_HEADERS]; - - /* Message body */ - struct mg_str body; /* Zero-length for requests with no body */ }; --- diff --git a/mongoose.h b/mongoose.h index b9247747..a8e30c3f 100644 --- a/mongoose.h +++ b/mongoose.h @@ -4140,6 +4140,7 @@ extern "C" { /* HTTP message */ struct http_message { struct mg_str message; /* Whole message: request line + headers + body */ + struct mg_str body; /* Message body. 0-length for requests with no body */ /* HTTP Request line (or HTTP response line) */ struct mg_str method; /* "GET" */ @@ -4163,9 +4164,6 @@ struct http_message { /* Headers */ struct mg_str header_names[MG_MAX_HTTP_HEADERS]; struct mg_str header_values[MG_MAX_HTTP_HEADERS]; - - /* Message body */ - struct mg_str body; /* Zero-length for requests with no body */ }; #if MG_ENABLE_HTTP_WEBSOCKET From 6f140202ade8a3735f8bdc15f45f7af0aa0caf76 Mon Sep 17 00:00:00 2001 From: Deomid Ryabkov Date: Tue, 9 May 2017 19:07:00 +0300 Subject: [PATCH 072/137] Fix LWIP net_if when RTOS is used; use for ESP32 All calls to core LWIP APIs should go through the tcpip thread. PUBLISHED_FROM=ebe8c7f043394a75a46810f2b6626582c63b9e68 --- mongoose.c | 204 ++++++++++++++++++++++++++++++++++++++++++----------- 1 file changed, 163 insertions(+), 41 deletions(-) diff --git a/mongoose.c b/mongoose.c index 25c33930..1ce98d01 100644 --- a/mongoose.c +++ b/mongoose.c @@ -14051,15 +14051,31 @@ void mg_lwip_mgr_schedule_poll(struct mg_mgr *mgr); /* Amalgamated: #include "common/mg_mem.h" */ +#include #include #include -#if CS_PLATFORM != CS_P_STM32 +#include +#if LWIP_VERSION >= 0x01050000 +#include /* For tcp_seg */ +#else #include #endif #include /* Amalgamated: #include "common/cs_dbg.h" */ +/* + * Newest versions of LWIP have ip_2_ip4, older have ipX_2_ip, + * even older have nothing. + */ +#ifndef ip_2_ip4 +#ifdef ipX_2_ip +#define ip_2_ip4(addr) ipX_2_ip(addr) +#else +#define ip_2_ip4(addr) (addr) +#endif +#endif + /* * Depending on whether Mongoose is compiled with ipv6 support, use right * lwip functions @@ -14077,16 +14093,12 @@ void mg_lwip_mgr_schedule_poll(struct mg_mgr *mgr); #define TCP_BIND tcp_bind #define UDP_BIND udp_bind #define IPADDR_NTOA ipaddr_ntoa -#define SET_ADDR(dst, src) (dst)->sin.sin_addr.s_addr = GET_IPV4(src) +#define SET_ADDR(dst, src) (dst)->sin.sin_addr.s_addr = ip_2_ip4(src)->addr #endif -/* - * If lwip is compiled with ipv6 support, then API changes even for ipv4 - */ -#if !defined(LWIP_IPV6) || !LWIP_IPV6 -#define GET_IPV4(ipX_addr) ((ipX_addr)->addr) -#else -#define GET_IPV4(ipX_addr) ((ipX_addr)->ip4.addr) +#if NO_SYS +#define tcpip_callback(fn, arg) (fn)(arg) +typedef void (*tcpip_callback_fn)(void *arg); #endif void mg_lwip_ssl_do_hs(struct mg_connection *nc); @@ -14256,8 +14268,17 @@ static err_t mg_lwip_tcp_sent_cb(void *arg, struct tcp_pcb *tpcb, return ERR_OK; } -void mg_lwip_if_connect_tcp(struct mg_connection *nc, - const union socket_address *sa) { +struct mg_lwip_if_connect_tcp_ctx { + struct mg_connection *nc; + const union socket_address *sa; +}; + +static void mg_lwip_if_connect_tcp_tcpip(void *arg) { + struct mg_lwip_if_connect_tcp_ctx *ctx = + (struct mg_lwip_if_connect_tcp_ctx *) arg; + struct mg_connection *nc = ctx->nc; + const union socket_address *sa = ctx->sa; + struct mg_lwip_conn_state *cs = (struct mg_lwip_conn_state *) nc->sock; struct tcp_pcb *tpcb = TCP_NEW(); cs->pcb.tcp = tpcb; @@ -14281,12 +14302,17 @@ void mg_lwip_if_connect_tcp(struct mg_connection *nc, } } +void mg_lwip_if_connect_tcp(struct mg_connection *nc, + const union socket_address *sa) { + struct mg_lwip_if_connect_tcp_ctx ctx = {.nc = nc, .sa = sa}; + tcpip_callback(mg_lwip_if_connect_tcp_tcpip, &ctx); +} + /* * Lwip included in the SDKs for nRF5x chips has different type for the * callback of `udp_recv()` */ -#if CS_PLATFORM == CS_P_NRF51 || CS_PLATFORM == CS_P_NRF52 || \ - CS_PLATFORM == CS_P_STM32 +#if LWIP_VERSION >= 0x01050000 static void mg_lwip_udp_recv_cb(void *arg, struct udp_pcb *pcb, struct pbuf *p, const ip_addr_t *addr, u16_t port) #else @@ -14304,7 +14330,11 @@ static void mg_lwip_udp_recv_cb(void *arg, struct udp_pcb *pcb, struct pbuf *p, return; } union socket_address *sa = (union socket_address *) sap->payload; +#if LWIP_VERSION >= 0x01050000 + sa->sin.sin_addr.s_addr = ip_2_ip4(addr)->addr; +#else sa->sin.sin_addr.s_addr = addr->addr; +#endif sa->sin.sin_port = htons(port); /* Logic in the recv handler requires that there be exactly one data pbuf. */ p = pbuf_coalesce(p, PBUF_RAW); @@ -14353,7 +14383,8 @@ static void mg_lwip_handle_recv_udp(struct mg_connection *nc) { } } -void mg_lwip_if_connect_udp(struct mg_connection *nc) { +static void mg_lwip_if_connect_udp_tcpip(void *arg) { + struct mg_connection *nc = (struct mg_connection *) arg; struct mg_lwip_conn_state *cs = (struct mg_lwip_conn_state *) nc->sock; struct udp_pcb *upcb = udp_new(); cs->err = UDP_BIND(upcb, IP_ADDR_ANY, 0 /* any port */); @@ -14367,6 +14398,10 @@ void mg_lwip_if_connect_udp(struct mg_connection *nc) { mg_lwip_post_signal(MG_SIG_CONNECT_RESULT, nc); } +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); @@ -14374,13 +14409,17 @@ void mg_lwip_accept_conn(struct mg_connection *nc, struct tcp_pcb *tpcb) { mg_if_accept_tcp_cb(nc, &sa, sizeof(sa.sin)); } +static void tcp_close_tcpip(void *arg) { + tcp_close((struct tcp_pcb *) arg); +} + void mg_lwip_handle_accept(struct mg_connection *nc) { struct mg_lwip_conn_state *cs = (struct mg_lwip_conn_state *) nc->sock; #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")); - tcp_close(cs->pcb.tcp); + tcpip_callback(tcp_close_tcpip, cs->pcb.tcp); } } else #endif @@ -14415,7 +14454,16 @@ static err_t mg_lwip_accept_cb(void *arg, struct tcp_pcb *newtpcb, err_t err) { return ERR_OK; } -int mg_lwip_if_listen_tcp(struct mg_connection *nc, union socket_address *sa) { +struct mg_lwip_if_listen_ctx { + struct mg_connection *nc; + union socket_address *sa; + int ret; +}; + +static void mg_lwip_if_listen_tcp_tcpip(void *arg) { + struct mg_lwip_if_listen_ctx *ctx = (struct mg_lwip_if_listen_ctx *) arg; + struct mg_connection *nc = ctx->nc; + union socket_address *sa = ctx->sa; struct mg_lwip_conn_state *cs = (struct mg_lwip_conn_state *) nc->sock; struct tcp_pcb *tpcb = TCP_NEW(); ip_addr_t *ip = (ip_addr_t *) &sa->sin.sin_addr.s_addr; @@ -14424,16 +14472,26 @@ int mg_lwip_if_listen_tcp(struct mg_connection *nc, union socket_address *sa) { DBG(("%p tcp_bind(%s:%u) = %d", nc, IPADDR_NTOA(ip), port, cs->err)); if (cs->err != ERR_OK) { tcp_close(tpcb); - return -1; + ctx->ret = -1; + return; } tcp_arg(tpcb, nc); tpcb = tcp_listen(tpcb); cs->pcb.tcp = tpcb; tcp_accept(tpcb, mg_lwip_accept_cb); - return 0; + ctx->ret = 0; } -int mg_lwip_if_listen_udp(struct mg_connection *nc, union socket_address *sa) { +int mg_lwip_if_listen_tcp(struct mg_connection *nc, union socket_address *sa) { + struct mg_lwip_if_listen_ctx ctx = {.nc = nc, .sa = sa}; + tcpip_callback(mg_lwip_if_listen_tcp_tcpip, &ctx); + return ctx.ret; +} + +static void mg_lwip_if_listen_udp_tcpip(void *arg) { + struct mg_lwip_if_listen_ctx *ctx = (struct mg_lwip_if_listen_ctx *) arg; + struct mg_connection *nc = ctx->nc; + union socket_address *sa = ctx->sa; struct mg_lwip_conn_state *cs = (struct mg_lwip_conn_state *) nc->sock; struct udp_pcb *upcb = udp_new(); ip_addr_t *ip = (ip_addr_t *) &sa->sin.sin_addr.s_addr; @@ -14442,24 +14500,43 @@ int mg_lwip_if_listen_udp(struct mg_connection *nc, union socket_address *sa) { DBG(("%p udb_bind(%s:%u) = %d", nc, IPADDR_NTOA(ip), port, cs->err)); if (cs->err != ERR_OK) { udp_remove(upcb); - return -1; + ctx->ret = -1; + } else { + udp_recv(upcb, mg_lwip_udp_recv_cb, nc); + cs->pcb.udp = upcb; + ctx->ret = 0; } - udp_recv(upcb, mg_lwip_udp_recv_cb, nc); - cs->pcb.udp = upcb; - return 0; } -int mg_lwip_tcp_write(struct mg_connection *nc, const void *data, - uint16_t len) { +int mg_lwip_if_listen_udp(struct mg_connection *nc, union socket_address *sa) { + struct mg_lwip_if_listen_ctx ctx = {.nc = nc, .sa = sa}; + tcpip_callback(mg_lwip_if_listen_udp_tcpip, &ctx); + return ctx.ret; +} + +struct mg_lwip_tcp_write_ctx { + struct mg_connection *nc; + const void *data; + uint16_t len; + int ret; +}; + +static void tcp_output_tcpip(void *arg) { + tcp_output((struct tcp_pcb *) arg); +} + +static void mg_lwip_tcp_write_tcpip(void *arg) { + struct mg_lwip_tcp_write_ctx *ctx = (struct mg_lwip_tcp_write_ctx *) arg; + struct mg_connection *nc = ctx->nc; struct mg_lwip_conn_state *cs = (struct mg_lwip_conn_state *) nc->sock; struct tcp_pcb *tpcb = cs->pcb.tcp; - if (tpcb == NULL) return -1; - len = MIN(tpcb->mss, MIN(len, tpcb->snd_buf)); + uint16_t len = MIN(tpcb->mss, MIN(ctx->len, tpcb->snd_buf)); if (len == 0) { DBG(("%p no buf avail %u %u %u %p %p", tpcb, tpcb->acked, tpcb->snd_buf, tpcb->snd_queuelen, tpcb->unsent, tpcb->unacked)); - tcp_output(tpcb); - return 0; + tcpip_callback(tcp_output_tcpip, tpcb); + ctx->ret = 0; + return; } /* * On ESP8266 we only allow one TCP segment in flight at any given time. @@ -14469,22 +14546,49 @@ int mg_lwip_tcp_write(struct mg_connection *nc, const void *data, */ #if CS_PLATFORM == CS_P_ESP8266 if (tpcb->unacked != NULL) { - return 0; + ctx->ret = 0; + return; } if (tpcb->unsent != NULL) { len = MIN(len, (TCP_MSS - tpcb->unsent->len)); } #endif - cs->err = tcp_write(tpcb, data, len, TCP_WRITE_FLAG_COPY); + cs->err = tcp_write(tpcb, ctx->data, len, TCP_WRITE_FLAG_COPY); DBG(("%p tcp_write %u = %d", tpcb, len, cs->err)); if (cs->err != ERR_OK) { /* * We ignore ERR_MEM because memory will be freed up when the data is sent * and we'll retry. */ - return (cs->err == ERR_MEM ? 0 : -1); + ctx->ret = (cs->err == ERR_MEM ? 0 : -1); + return; } - return len; + 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}; + struct mg_lwip_conn_state *cs = (struct mg_lwip_conn_state *) nc->sock; + struct tcp_pcb *tpcb = cs->pcb.tcp; + if (tpcb == NULL) { + return -1; + } + tcpip_callback(mg_lwip_tcp_write_tcpip, &ctx); + return ctx.ret; +} + +struct udp_sendto_ctx { + struct udp_pcb *upcb; + struct pbuf *p; + ip_addr_t *ip; + uint16_t port; + int ret; +}; + +static void udp_sendto_tcpip(void *arg) { + struct udp_sendto_ctx *ctx = (struct udp_sendto_ctx *) 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, @@ -14508,7 +14612,9 @@ static int mg_lwip_udp_send(struct mg_connection *nc, const void *data, return 0; } memcpy(p->payload, data, len); - cs->err = udp_sendto(upcb, p, (ip_addr_t *) ip, port); + struct udp_sendto_ctx ctx = {.upcb = upcb, .p = p, .ip = ip, .port = port}; + tcpip_callback(udp_sendto_tcpip, &ctx); + cs->err = ctx.ret; DBG(("%p udp_sendto = %d", nc, cs->err)); pbuf_free(p); return (cs->err == ERR_OK ? len : -1); @@ -14544,6 +14650,16 @@ void mg_lwip_if_udp_send(struct mg_connection *nc, const void *buf, mg_lwip_mgr_schedule_poll(nc->mgr); } +struct tcp_recved_ctx { + struct tcp_pcb *tpcb; + size_t len; +}; + +void tcp_recved_tcpip(void *arg) { + struct tcp_recved_ctx *ctx = (struct tcp_recved_ctx *) 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; struct mg_lwip_conn_state *cs = (struct mg_lwip_conn_state *) nc->sock; @@ -14552,14 +14668,16 @@ void mg_lwip_if_recved(struct mg_connection *nc, size_t len) { return; } DBG(("%p %p %u", nc, cs->pcb.tcp, len)); -/* Currently SSL acknowledges data immediately. - * TODO(rojer): Find a way to propagate mg_lwip_if_recved. */ + struct tcp_recved_ctx ctx = {.tpcb = cs->pcb.tcp, .len = len}; #if MG_ENABLE_SSL if (!(nc->flags & MG_F_SSL)) { - tcp_recved(cs->pcb.tcp, len); + tcpip_callback(tcp_recved_tcpip, &ctx); + } else { + /* Currently SSL acknowledges data immediately. + * TODO(rojer): Find a way to propagate mg_lwip_if_recved. */ } #else - tcp_recved(cs->pcb.tcp, len); + tcpip_callback(tcp_recved_tcpip, &ctx); #endif mbuf_trim(&nc->recv_mbuf); } @@ -14573,6 +14691,10 @@ int mg_lwip_if_create_conn(struct mg_connection *nc) { return 1; } +static void udp_remove_tcpip(void *arg) { + udp_remove((struct udp_pcb *) arg); +} + void mg_lwip_if_destroy_conn(struct mg_connection *nc) { if (nc->sock == INVALID_SOCKET) return; struct mg_lwip_conn_state *cs = (struct mg_lwip_conn_state *) nc->sock; @@ -14582,7 +14704,7 @@ void mg_lwip_if_destroy_conn(struct mg_connection *nc) { tcp_arg(tpcb, NULL); DBG(("%p tcp_close %p", nc, tpcb)); tcp_arg(tpcb, NULL); - tcp_close(tpcb); + tcpip_callback(tcp_close_tcpip, tpcb); } while (cs->rx_chain != NULL) { struct pbuf *seg = cs->rx_chain; @@ -14596,7 +14718,7 @@ void mg_lwip_if_destroy_conn(struct mg_connection *nc) { struct udp_pcb *upcb = cs->pcb.udp; if (upcb != NULL) { DBG(("%p udp_remove %p", nc, upcb)); - udp_remove(upcb); + tcpip_callback(udp_remove_tcpip, upcb); } memset(cs, 0, sizeof(*cs)); MG_FREE(cs); @@ -14830,7 +14952,7 @@ time_t mg_lwip_if_poll(struct mg_iface *iface, int timeout_ms) { if (nc->sock != INVALID_SOCKET && !(nc->flags & (MG_F_UDP | MG_F_LISTENING)) && cs->pcb.tcp != NULL && cs->pcb.tcp->unsent != NULL) { - tcp_output(cs->pcb.tcp); + tcpip_callback(tcp_output_tcpip, cs->pcb.tcp); } if (nc->ev_timer_time > 0) { if (num_timers == 0 || nc->ev_timer_time < min_timer) { From acfc66cd60f5bfa7dc4d37194d72855c201e5710 Mon Sep 17 00:00:00 2001 From: Deomid Ryabkov Date: Thu, 11 May 2017 10:49:36 +0100 Subject: [PATCH 073/137] Correctly report bytes sent via SSL This prevented hexdump from showing data sent over SSL when using LWIP net_if PUBLISHED_FROM=aa520a27bdd21294484c52bf33c8580f3b4bad65 --- mongoose.c | 1 + 1 file changed, 1 insertion(+) diff --git a/mongoose.c b/mongoose.c index 1ce98d01..b95f70d5 100644 --- a/mongoose.c +++ b/mongoose.c @@ -15099,6 +15099,7 @@ void mg_lwip_ssl_send(struct mg_connection *nc) { int ret = mg_ssl_if_write(nc, nc->send_mbuf.buf, len); DBG(("%p SSL_write %u = %d, %d", nc, len, ret)); if (ret > 0) { + mg_if_sent_cb(nc, ret); mbuf_remove(&nc->send_mbuf, ret); mbuf_trim(&nc->send_mbuf); cs->last_ssl_write_size = 0; From 06670d340196c56f8305ed9588eb50632b980e50 Mon Sep 17 00:00:00 2001 From: Deomid Ryabkov Date: Fri, 19 May 2017 17:03:26 +0100 Subject: [PATCH 074/137] Fix double-removal of send_mbuf data with SSL on Other minor fixes. Also decrease idle poll interval to 100 ms, as a workaround for some cases of incorrect next poll delay computation. Added HW tests for SSL fetches. Fixes cesanta/mongoose-os#262 PUBLISHED_FROM=4d19f845768b4b3b990d25959d4211972368d7fc --- mongoose.c | 61 ++++++++++++++++++++++++++++++++---------------------- 1 file changed, 36 insertions(+), 25 deletions(-) diff --git a/mongoose.c b/mongoose.c index b95f70d5..aaadc2ba 100644 --- a/mongoose.c +++ b/mongoose.c @@ -2461,6 +2461,7 @@ void mg_send(struct mg_connection *nc, const void *buf, int len) { } 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; @@ -5507,21 +5508,26 @@ static void mg_http_transfer_file_data(struct mg_connection *nc) { if (pd->file.type == DATA_FILE) { struct mbuf *io = &nc->send_mbuf; - if (io->len < sizeof(buf)) { - to_read = sizeof(buf) - io->len; + if (io->len >= MG_MAX_HTTP_SEND_MBUF) { + to_read = 0; + } else { + to_read = MG_MAX_HTTP_SEND_MBUF - io->len; } - - if (left > 0 && to_read > left) { + if (to_read > left) { to_read = left; } - - if (to_read == 0) { - /* Rate limiting. send_mbuf is too full, wait until it's drained. */ - } else if (pd->file.sent < pd->file.cl && - (n = mg_fread(buf, 1, to_read, pd->file.fp)) > 0) { - mg_send(nc, buf, n); - pd->file.sent += n; + if (to_read > 0) { + n = mg_fread(buf, 1, to_read, pd->file.fp); + if (n > 0) { + mg_send(nc, buf, n); + pd->file.sent += n; + DBG(("%p sent %d (total %d)", nc, (int) n, (int) pd->file.sent)); + } } else { + /* Rate-limited */ + } + if (pd->file.sent >= pd->file.cl) { + LOG(LL_DEBUG, ("%p done, %d bytes", nc, (int) pd->file.sent)); if (!pd->file.keepalive) nc->flags |= MG_F_SEND_AND_CLOSE; mg_http_free_proto_data_file(&pd->file); } @@ -14056,7 +14062,7 @@ void mg_lwip_mgr_schedule_poll(struct mg_mgr *mgr); #include #include #if LWIP_VERSION >= 0x01050000 -#include /* For tcp_seg */ +#include /* For tcp_seg */ #else #include #endif @@ -14259,10 +14265,10 @@ static void mg_lwip_handle_recv_tcp(struct mg_connection *nc) { static err_t mg_lwip_tcp_sent_cb(void *arg, struct tcp_pcb *tpcb, u16_t num_sent) { struct mg_connection *nc = (struct mg_connection *) arg; - DBG(("%p %p %u", nc, tpcb, num_sent)); + DBG(("%p %p %u %u %u", nc, tpcb, num_sent, tpcb->unsent, tpcb->unacked)); if (nc == NULL) return ERR_OK; if ((nc->flags & MG_F_SEND_AND_CLOSE) && !(nc->flags & MG_F_WANT_WRITE) && - nc->send_mbuf.len == 0 && tpcb->unacked == 0) { + nc->send_mbuf.len == 0 && tpcb->unsent == 0 && tpcb->unacked == 0) { mg_lwip_post_signal(MG_SIG_CLOSE_CONN, nc); } return ERR_OK; @@ -14530,7 +14536,8 @@ static void mg_lwip_tcp_write_tcpip(void *arg) { struct mg_connection *nc = ctx->nc; struct mg_lwip_conn_state *cs = (struct mg_lwip_conn_state *) nc->sock; struct tcp_pcb *tpcb = cs->pcb.tcp; - uint16_t len = MIN(tpcb->mss, MIN(ctx->len, tpcb->snd_buf)); + size_t len = MIN(tpcb->mss, MIN(ctx->len, tpcb->snd_buf)); + size_t unsent, unacked; if (len == 0) { DBG(("%p no buf avail %u %u %u %p %p", tpcb, tpcb->acked, tpcb->snd_buf, tpcb->snd_queuelen, tpcb->unsent, tpcb->unacked)); @@ -14538,6 +14545,8 @@ static void mg_lwip_tcp_write_tcpip(void *arg) { ctx->ret = 0; return; } + unsent = (tpcb->unsent != NULL ? tpcb->unsent->len : 0); + unacked = (tpcb->unacked != NULL ? tpcb->unacked->len : 0); /* * On ESP8266 we only allow one TCP segment in flight at any given time. * This may increase latency and reduce efficiency of tcp windowing, @@ -14545,16 +14554,16 @@ static void mg_lwip_tcp_write_tcpip(void *arg) { * reduce footprint. */ #if CS_PLATFORM == CS_P_ESP8266 - if (tpcb->unacked != NULL) { + if (unacked > 0) { ctx->ret = 0; return; } - if (tpcb->unsent != NULL) { - len = MIN(len, (TCP_MSS - tpcb->unsent->len)); - } + len = MIN(len, (TCP_MSS - unsent)); #endif cs->err = tcp_write(tpcb, ctx->data, len, TCP_WRITE_FLAG_COPY); - DBG(("%p tcp_write %u = %d", tpcb, len, cs->err)); + unsent = (tpcb->unsent != NULL ? tpcb->unsent->len : 0); + unacked = (tpcb->unacked != NULL ? tpcb->unacked->len : 0); + DBG(("%p tcp_write %u = %d, %u %u", tpcb, len, cs->err, unsent, unacked)); if (cs->err != ERR_OK) { /* * We ignore ERR_MEM because memory will be freed up when the data is sent @@ -14984,7 +14993,11 @@ uint32_t mg_lwip_get_poll_delay_ms(struct mg_mgr *mgr) { } num_timers++; } - if (nc->send_mbuf.len > 0) { + 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) { @@ -15097,11 +15110,9 @@ void mg_lwip_ssl_send(struct mg_connection *nc) { 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, %d", nc, len, ret)); + DBG(("%p SSL_write %u = %d", nc, len, ret)); if (ret > 0) { mg_if_sent_cb(nc, ret); - mbuf_remove(&nc->send_mbuf, ret); - mbuf_trim(&nc->send_mbuf); cs->last_ssl_write_size = 0; } else if (ret < 0) { /* This is tricky. We must remember the exact data we were sending to retry @@ -15186,8 +15197,8 @@ 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); - LOG(LL_DEBUG, ("%p %d -> %d", nc, len, ret)); if (ret == 0) ret = MBEDTLS_ERR_SSL_WANT_WRITE; + LOG(LL_DEBUG, ("%p %d -> %d", nc, len, ret)); return ret; } From cf0a969a65b9a3772d01a63d32de404a0e9c5202 Mon Sep 17 00:00:00 2001 From: Deomid Ryabkov Date: Thu, 25 May 2017 18:05:18 +0100 Subject: [PATCH 075/137] ESP8266 and ESP32 build image updates ESP32: 2.0-r6 ESP8266: 2.0.0-1.5.0-r5 This brings updated mbedTLS with support for on-disk CA chains: https://github.com/cesanta/mbedtls/compare/esp32_2.0-r5...esp32_2.0-r6 ESP8266 gets bigger rollup (ESP32 got those changes earlier, seems ok): https://github.com/cesanta/mbedtls/compare/esp8266...esp8266_2.0.0-1.5.0-r5 Saves ~1.5K RAM for now, but will allow adding more roots to ca.pem without wasting RAM. Refactored docker build for ESP8266 in the same way as was done earlier for ESP32. PUBLISHED_FROM=db8eb0f91875d02266a8baaf1141c0d65eb59674 --- mongoose.c | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/mongoose.c b/mongoose.c index aaadc2ba..dc8170d6 100644 --- a/mongoose.c +++ b/mongoose.c @@ -4602,6 +4602,12 @@ static void mg_ssl_if_mbed_free_certs_and_keys(struct mg_ssl_if_ctx *ctx) { } if (ctx->ca_cert != NULL) { mbedtls_ssl_conf_ca_chain(ctx->conf, NULL, NULL); +#ifdef MBEDTLS_X509_CA_CHAIN_ON_DISK + if (ctx->ca_cert->ca_chain_file != NULL) { + MG_FREE((void *) ctx->ca_cert->ca_chain_file); + ctx->ca_cert->ca_chain_file = NULL; + } +#endif mbedtls_x509_crt_free(ctx->ca_cert); MG_FREE(ctx->ca_cert); ctx->ca_cert = NULL; @@ -4687,9 +4693,16 @@ static enum mg_ssl_if_result mg_use_ca_cert(struct mg_ssl_if_ctx *ctx, } ctx->ca_cert = (mbedtls_x509_crt *) MG_CALLOC(1, sizeof(*ctx->ca_cert)); mbedtls_x509_crt_init(ctx->ca_cert); +#ifdef MBEDTLS_X509_CA_CHAIN_ON_DISK + ca_cert = strdup(ca_cert); + if (mbedtls_x509_crt_set_ca_chain_file(ctx->ca_cert, ca_cert) != 0) { + return MG_SSL_ERROR; + } +#else if (mbedtls_x509_crt_parse_file(ctx->ca_cert, ca_cert) != 0) { return MG_SSL_ERROR; } +#endif mbedtls_ssl_conf_ca_chain(ctx->conf, ctx->ca_cert, NULL); mbedtls_ssl_conf_authmode(ctx->conf, MBEDTLS_SSL_VERIFY_REQUIRED); return MG_SSL_OK; From c8416cc17d3fc79bdcae59f418375a60330adaca Mon Sep 17 00:00:00 2001 From: Deomid Ryabkov Date: Fri, 26 May 2017 15:38:20 +0100 Subject: [PATCH 076/137] NULL out name server field properly Fixes https://github.com/cesanta/mongoose-os/issues/260 PUBLISHED_FROM=e95076915d52edb2298e3ea386281c277e42c89a --- mongoose.c | 1 + 1 file changed, 1 insertion(+) diff --git a/mongoose.c b/mongoose.c index dc8170d6..c22c9dc5 100644 --- a/mongoose.c +++ b/mongoose.c @@ -11129,6 +11129,7 @@ int mg_resolve_async_opt(struct mg_mgr *mgr, const char *name, int query, void mg_set_nameserver(struct mg_mgr *mgr, const char *nameserver) { MG_FREE((char *) mgr->nameserver); + mgr->nameserver = NULL; if (nameserver != NULL) { mgr->nameserver = strdup(nameserver); } From f78ee9d42e0f841b95db64de62da2df72e1c48f4 Mon Sep 17 00:00:00 2001 From: Dmitry Frank Date: Thu, 25 May 2017 17:53:49 +0300 Subject: [PATCH 077/137] Don't ignore non-merge commits when publishing Merge commits are not explicitly ignored either: they're just naturally ignored as empty commits. PUBLISHED_FROM=2c814104eedd76ee90813488277ecaaf2baf6315 --- mongoose.c | 14 -------------- 1 file changed, 14 deletions(-) diff --git a/mongoose.c b/mongoose.c index c22c9dc5..aaadc2ba 100644 --- a/mongoose.c +++ b/mongoose.c @@ -4602,12 +4602,6 @@ static void mg_ssl_if_mbed_free_certs_and_keys(struct mg_ssl_if_ctx *ctx) { } if (ctx->ca_cert != NULL) { mbedtls_ssl_conf_ca_chain(ctx->conf, NULL, NULL); -#ifdef MBEDTLS_X509_CA_CHAIN_ON_DISK - if (ctx->ca_cert->ca_chain_file != NULL) { - MG_FREE((void *) ctx->ca_cert->ca_chain_file); - ctx->ca_cert->ca_chain_file = NULL; - } -#endif mbedtls_x509_crt_free(ctx->ca_cert); MG_FREE(ctx->ca_cert); ctx->ca_cert = NULL; @@ -4693,16 +4687,9 @@ static enum mg_ssl_if_result mg_use_ca_cert(struct mg_ssl_if_ctx *ctx, } ctx->ca_cert = (mbedtls_x509_crt *) MG_CALLOC(1, sizeof(*ctx->ca_cert)); mbedtls_x509_crt_init(ctx->ca_cert); -#ifdef MBEDTLS_X509_CA_CHAIN_ON_DISK - ca_cert = strdup(ca_cert); - if (mbedtls_x509_crt_set_ca_chain_file(ctx->ca_cert, ca_cert) != 0) { - return MG_SSL_ERROR; - } -#else if (mbedtls_x509_crt_parse_file(ctx->ca_cert, ca_cert) != 0) { return MG_SSL_ERROR; } -#endif mbedtls_ssl_conf_ca_chain(ctx->conf, ctx->ca_cert, NULL); mbedtls_ssl_conf_authmode(ctx->conf, MBEDTLS_SSL_VERIFY_REQUIRED); return MG_SSL_OK; @@ -11129,7 +11116,6 @@ int mg_resolve_async_opt(struct mg_mgr *mgr, const char *name, int query, void mg_set_nameserver(struct mg_mgr *mgr, const char *nameserver) { MG_FREE((char *) mgr->nameserver); - mgr->nameserver = NULL; if (nameserver != NULL) { mgr->nameserver = strdup(nameserver); } From c5452fc2ec620c9b26ba22ff3c283b20ba9e1de1 Mon Sep 17 00:00:00 2001 From: Deomid Ryabkov Date: Sun, 28 May 2017 14:16:37 +0100 Subject: [PATCH 078/137] Don't ignore non-merge commits when publishing Merge commits are not explicitly ignored either: they're just naturally ignored as empty commits. PUBLISHED_FROM=12871fd4c9b1e9de4e57e13d810bffd98ddba299 --- mongoose.c | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/mongoose.c b/mongoose.c index aaadc2ba..c22c9dc5 100644 --- a/mongoose.c +++ b/mongoose.c @@ -4602,6 +4602,12 @@ static void mg_ssl_if_mbed_free_certs_and_keys(struct mg_ssl_if_ctx *ctx) { } if (ctx->ca_cert != NULL) { mbedtls_ssl_conf_ca_chain(ctx->conf, NULL, NULL); +#ifdef MBEDTLS_X509_CA_CHAIN_ON_DISK + if (ctx->ca_cert->ca_chain_file != NULL) { + MG_FREE((void *) ctx->ca_cert->ca_chain_file); + ctx->ca_cert->ca_chain_file = NULL; + } +#endif mbedtls_x509_crt_free(ctx->ca_cert); MG_FREE(ctx->ca_cert); ctx->ca_cert = NULL; @@ -4687,9 +4693,16 @@ static enum mg_ssl_if_result mg_use_ca_cert(struct mg_ssl_if_ctx *ctx, } ctx->ca_cert = (mbedtls_x509_crt *) MG_CALLOC(1, sizeof(*ctx->ca_cert)); mbedtls_x509_crt_init(ctx->ca_cert); +#ifdef MBEDTLS_X509_CA_CHAIN_ON_DISK + ca_cert = strdup(ca_cert); + if (mbedtls_x509_crt_set_ca_chain_file(ctx->ca_cert, ca_cert) != 0) { + return MG_SSL_ERROR; + } +#else if (mbedtls_x509_crt_parse_file(ctx->ca_cert, ca_cert) != 0) { return MG_SSL_ERROR; } +#endif mbedtls_ssl_conf_ca_chain(ctx->conf, ctx->ca_cert, NULL); mbedtls_ssl_conf_authmode(ctx->conf, MBEDTLS_SSL_VERIFY_REQUIRED); return MG_SSL_OK; @@ -11116,6 +11129,7 @@ int mg_resolve_async_opt(struct mg_mgr *mgr, const char *name, int query, void mg_set_nameserver(struct mg_mgr *mgr, const char *nameserver) { MG_FREE((char *) mgr->nameserver); + mgr->nameserver = NULL; if (nameserver != NULL) { mgr->nameserver = strdup(nameserver); } From e4309d472b0679405e2da8ef3600c1b8d69ea95b Mon Sep 17 00:00:00 2001 From: Deomid Ryabkov Date: Tue, 30 May 2017 11:50:07 +0100 Subject: [PATCH 079/137] Annotate cs_log_printf with format attribute This adds compile-time checks for format strings. Fix issues exposed by this. PUBLISHED_FROM=b9f820d8ad44fce9186dfdad4fe109fafa5371ce --- examples/CC3200/Makefile.build | 2 +- mongoose.c | 40 +++++++++++++++++++--------------- 2 files changed, 24 insertions(+), 18 deletions(-) diff --git a/examples/CC3200/Makefile.build b/examples/CC3200/Makefile.build index 7d567d0f..083cb885 100644 --- a/examples/CC3200/Makefile.build +++ b/examples/CC3200/Makefile.build @@ -22,7 +22,7 @@ IPATH = . ../.. $(REPO_PATH) VPATH = ../.. -MONGOOSE_FEATURES = -DMG_ENABLE_SSL -DMG_ENABLE_HTTP_STREAMING_MULTIPART +MONGOOSE_FEATURES = -DMG_ENABLE_SSL -DMG_ENABLE_HTTP_STREAMING_MULTIPART -DMG_MODULE_LINES SDK_FLAGS = -DUSE_FREERTOS -DSL_PLATFORM_MULTI_THREADED # -DTARGET_IS_CC3200 would reduce code size by using functions in ROM diff --git a/mongoose.c b/mongoose.c index c22c9dc5..1424e929 100644 --- a/mongoose.c +++ b/mongoose.c @@ -230,7 +230,11 @@ void cs_log_set_level(enum cs_log_level level); void cs_log_set_file(FILE *file); extern enum cs_log_level cs_log_threshold; void cs_log_print_prefix(enum cs_log_level level, const char *func); -void cs_log_printf(const char *fmt, ...); +void cs_log_printf(const char *fmt, ...) +#ifdef __GNUC__ + __attribute__((format(printf, 1, 2))) +#endif + ; #define LOG(l, x) \ do { \ @@ -2918,7 +2922,7 @@ int mg_check_ip_acl(const char *acl, uint32_t remote_ip) { } } - DBG(("%08x %c", remote_ip, allowed)); + DBG(("%08x %c", (unsigned int) remote_ip, allowed)); return allowed == '+'; } @@ -2936,7 +2940,7 @@ double mg_set_timer(struct mg_connection *c, double timestamp) { * connections, so not processed yet. It has a DNS resolver connection * linked to it. Set up a timer for the DNS connection. */ - DBG(("%p %p %d -> %lu", c, c->priv_2, c->flags & MG_F_RESOLVING, + 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; @@ -3883,7 +3887,7 @@ void mg_tun_if_tcp_send(struct mg_connection *nc, const void *buf, size_t len) { #if MG_ENABLE_HEXDUMP char hex[512]; mg_hexdump(buf, len, hex, sizeof(hex)); - LOG(LL_DEBUG, ("sending to stream %zu:\n%s", stream_id, hex)); + LOG(LL_DEBUG, ("sending to stream 0x%x:\n%s", (unsigned int) stream_id, hex)); #endif mg_tun_send_frame(client->disp, stream_id, MG_TUN_DATA_FRAME, 0, msg); @@ -3914,7 +3918,7 @@ void mg_tun_if_destroy_conn(struct mg_connection *nc) { uint32_t stream_id = (uint32_t)(uintptr_t) nc->mgr_data; struct mg_str msg = {NULL, 0}; - LOG(LL_DEBUG, ("closing %zu:", stream_id)); + LOG(LL_DEBUG, ("closing 0x%x:", (unsigned int) stream_id)); mg_tun_send_frame(client->disp, stream_id, MG_TUN_DATA_FRAME, MG_TUN_F_END_STREAM, msg); } @@ -3970,13 +3974,14 @@ struct mg_connection *mg_tun_if_find_conn(struct mg_tun_client *client, if (stream_id > client->last_stream_id) { /* create a new connection */ - LOG(LL_DEBUG, ("new stream 0x%lx, accepting", stream_id)); + LOG(LL_DEBUG, ("new stream 0x%x, accepting", (unsigned int) stream_id)); nc = mg_if_accept_new_conn(client->listener); nc->mgr_data = (void *) (uintptr_t) stream_id; client->last_stream_id = stream_id; } else { - LOG(LL_DEBUG, ("Ignoring stream 0x%lx (last_stream_id 0x%lx)", stream_id, - client->last_stream_id)); + LOG(LL_DEBUG, + ("Ignoring stream 0x%x (last_stream_id 0x%x)", (unsigned int) stream_id, + (unsigned int) client->last_stream_id)); } return nc; @@ -9897,7 +9902,7 @@ MG_INTERNAL int parse_mqtt(struct mbuf *io, struct mg_mqtt_message *mm) { LOG(LL_DEBUG, ("%d %2x %d proto [%.*s] client_id [%.*s] will_topic [%.*s] " "will_msg [%.*s] user_name [%.*s] password [%.*s]", - len, (int) mm->connect_flags, (int) mm->keep_alive_timer, + (int) len, (int) mm->connect_flags, (int) mm->keep_alive_timer, (int) mm->protocol_name.len, mm->protocol_name.p, (int) mm->client_id.len, mm->client_id.p, (int) mm->will_topic.len, mm->will_topic.p, (int) mm->will_message.len, mm->will_message.p, @@ -11771,9 +11776,10 @@ static void mg_tun_init_client(struct mg_tun_client *client, struct mg_mgr *mgr, } void mg_tun_log_frame(struct mg_tun_frame *frame) { - LOG(LL_DEBUG, ("Got TUN frame: type=0x%x, flags=0x%x stream_id=0x%lx, " - "len=%zu", - frame->type, frame->flags, frame->stream_id, frame->body.len)); + LOG(LL_DEBUG, ("Got TUN frame: type=0x%x, flags=0x%x stream_id=0x%x, " + "len=%d", + frame->type, frame->flags, (unsigned int) frame->stream_id, + (int) frame->body.len)); #if MG_ENABLE_HEXDUMP { char hex[512]; @@ -11836,7 +11842,7 @@ static void mg_tun_client_handler(struct mg_connection *nc, int ev, struct mg_tun_frame frame; if (mg_tun_parse_frame(wm->data, wm->size, &frame) == -1) { - LOG(LL_ERROR, ("Got invalid tun frame dropping", wm->size)); + LOG(LL_ERROR, ("Got invalid tun frame dropping")); break; } @@ -14279,10 +14285,10 @@ static void mg_lwip_handle_recv_tcp(struct mg_connection *nc) { static err_t mg_lwip_tcp_sent_cb(void *arg, struct tcp_pcb *tpcb, u16_t num_sent) { struct mg_connection *nc = (struct mg_connection *) arg; - DBG(("%p %p %u %u %u", nc, tpcb, num_sent, tpcb->unsent, tpcb->unacked)); + DBG(("%p %p %u %p %p", nc, tpcb, num_sent, tpcb->unsent, tpcb->unacked)); if (nc == NULL) return ERR_OK; if ((nc->flags & MG_F_SEND_AND_CLOSE) && !(nc->flags & MG_F_WANT_WRITE) && - nc->send_mbuf.len == 0 && tpcb->unsent == 0 && tpcb->unacked == 0) { + nc->send_mbuf.len == 0 && tpcb->unsent == NULL && tpcb->unacked == NULL) { mg_lwip_post_signal(MG_SIG_CLOSE_CONN, nc); } return ERR_OK; @@ -14897,7 +14903,7 @@ 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")); + LOG(LL_INFO, ("%p Mongoose init", iface)); iface->data = MG_CALLOC(1, sizeof(struct mg_ev_mgr_lwip_data)); } @@ -15076,7 +15082,7 @@ void mg_lwip_ssl_do_hs(struct mg_connection *nc) { enum mg_ssl_if_result res; if (nc->flags & MG_F_CLOSE_IMMEDIATELY) return; res = mg_ssl_if_handshake(nc); - DBG(("%p %d %d %d", nc, nc->flags, server_side, res)); + 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; From 023b55f2e53ae07018921bbbc1ff1bd8a0e482d8 Mon Sep 17 00:00:00 2001 From: Deomid Ryabkov Date: Sun, 4 Jun 2017 15:10:52 +0100 Subject: [PATCH 080/137] MQTT client keep alive fixes - Move keep alive management up to the Mongoose library - Only outgoing control messgaes should reset keepalive timer - Add unit test https://forum.mongoose-os.com/discussion/1155/mqtt-keep-alive-compliance-issue PUBLISHED_FROM=f86e30744ded53a6f7f96afec066b4ff3b4372c0 --- docs/c-api/mqtt.h/struct_mg_mqtt_proto_data.md | 1 + mongoose.c | 17 +++++++++++++++-- mongoose.h | 1 + 3 files changed, 17 insertions(+), 2 deletions(-) diff --git a/docs/c-api/mqtt.h/struct_mg_mqtt_proto_data.md b/docs/c-api/mqtt.h/struct_mg_mqtt_proto_data.md index 8ae54fcf..f095589d 100644 --- a/docs/c-api/mqtt.h/struct_mg_mqtt_proto_data.md +++ b/docs/c-api/mqtt.h/struct_mg_mqtt_proto_data.md @@ -5,6 +5,7 @@ symbol_kind: "struct" signature: | struct mg_mqtt_proto_data { uint16_t keep_alive; + double last_control_time; }; --- diff --git a/mongoose.c b/mongoose.c index 1424e929..f69d0010 100644 --- a/mongoose.c +++ b/mongoose.c @@ -2079,7 +2079,7 @@ void mg_if_poll(struct mg_connection *nc, time_t now) { } } -static void mg_destroy_conn(struct mg_connection *conn, int destroy_if) { +void mg_destroy_conn(struct mg_connection *conn, int 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); @@ -9957,7 +9957,7 @@ static void mqtt_handler(struct mg_connection *nc, int ev, nc->handler(nc, ev, ev_data MG_UD_ARG(user_data)); switch (ev) { - case MG_EV_RECV: + case MG_EV_RECV: { /* There can be multiple messages in the buffer, process them all. */ while (1) { int len = parse_mqtt(io, &mm); @@ -9966,6 +9966,17 @@ static void mqtt_handler(struct mg_connection *nc, int ev, mbuf_remove(io, len); } break; + } + case MG_EV_POLL: { + struct mg_mqtt_proto_data *pd = + (struct mg_mqtt_proto_data *) nc->proto_data; + double now = mg_time(); + if (pd->keep_alive > 0 && pd->last_control_time > 0 && + (now - pd->last_control_time) > pd->keep_alive) { + LOG(LL_DEBUG, ("Send PINGREQ")); + mg_mqtt_ping(nc); + } + } } } @@ -10007,6 +10018,7 @@ void mg_set_protocol_mqtt(struct mg_connection *nc) { static void mg_mqtt_prepend_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; @@ -10026,6 +10038,7 @@ static void mg_mqtt_prepend_header(struct mg_connection *nc, uint8_t cmd, } while (len > 0); mbuf_insert(&nc->send_mbuf, off, buf, vlen - buf); + pd->last_control_time = mg_time(); } void mg_send_mqtt_handshake(struct mg_connection *nc, const char *client_id) { diff --git a/mongoose.h b/mongoose.h index a8e30c3f..209614cb 100644 --- a/mongoose.h +++ b/mongoose.h @@ -5105,6 +5105,7 @@ struct mg_send_mqtt_handshake_opts { /* mg_mqtt_proto_data should be in header to allow external access to it */ struct mg_mqtt_proto_data { uint16_t keep_alive; + double last_control_time; }; /* Message types */ From a2192ae4839d9a6981cc47de1e3621bec2261865 Mon Sep 17 00:00:00 2001 From: ruslanvaliullin Date: Wed, 7 Jun 2017 21:34:44 +0300 Subject: [PATCH 081/137] Add mbuf_append result check PUBLISHED_FROM=967a7ff3684e548ddbfe92365f7718a99e14d098 --- mongoose.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mongoose.c b/mongoose.c index f69d0010..9dbc4943 100644 --- a/mongoose.c +++ b/mongoose.c @@ -11618,7 +11618,7 @@ uint32_t mg_coap_compose(struct mg_coap_message *cm, struct mbuf *io) { /* saving previous lenght to handle non-empty mbuf */ prev_io_len = io->len; - mbuf_append(io, NULL, packet_size); + if (mbuf_append(io, NULL, packet_size) == 0) return MG_COAP_ERROR; ptr = io->buf + prev_io_len; /* From 3a3b433849b2088aaceeac6d258b3ade029ff9e3 Mon Sep 17 00:00:00 2001 From: Dmitry Frank Date: Fri, 9 Jun 2017 14:16:14 +0100 Subject: [PATCH 082/137] Don't ignore userdata in mg_bind PUBLISHED_FROM=0ffcd770535efa66ff1b6f9201f2caf832bd5055 --- mongoose.c | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/mongoose.c b/mongoose.c index 9dbc4943..18467af7 100644 --- a/mongoose.c +++ b/mongoose.c @@ -2783,6 +2783,10 @@ struct mg_connection *mg_bind_opt(struct mg_mgr *mgr, const char *address, struct mg_add_sock_opts add_sock_opts; char host[MG_MAX_HOST_LEN]; +#if MG_ENABLE_CALLBACK_USERDATA + opts.user_data = user_data; +#endif + MG_COPY_COMMON_CONNECTION_OPTIONS(&add_sock_opts, &opts); #if MG_ENABLE_TUN @@ -2846,9 +2850,6 @@ struct mg_connection *mg_bind_opt(struct mg_mgr *mgr, const char *address, } mg_add_conn(nc->mgr, nc); -#if MG_ENABLE_CALLBACK_USERDATA - (void) user_data; -#endif return nc; } From 5baeba53d7e5f83c4a690565bc9c02e6fafb491d Mon Sep 17 00:00:00 2001 From: Sergey Lyubka Date: Thu, 8 Jun 2017 09:08:44 +0100 Subject: [PATCH 083/137] Reorg docs PUBLISHED_FROM=657a53762ada0ab3fe715a15939eb510a637e37f --- mongoose.c | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/mongoose.c b/mongoose.c index 18467af7..9dbc4943 100644 --- a/mongoose.c +++ b/mongoose.c @@ -2783,10 +2783,6 @@ struct mg_connection *mg_bind_opt(struct mg_mgr *mgr, const char *address, struct mg_add_sock_opts add_sock_opts; char host[MG_MAX_HOST_LEN]; -#if MG_ENABLE_CALLBACK_USERDATA - opts.user_data = user_data; -#endif - MG_COPY_COMMON_CONNECTION_OPTIONS(&add_sock_opts, &opts); #if MG_ENABLE_TUN @@ -2850,6 +2846,9 @@ struct mg_connection *mg_bind_opt(struct mg_mgr *mgr, const char *address, } mg_add_conn(nc->mgr, nc); +#if MG_ENABLE_CALLBACK_USERDATA + (void) user_data; +#endif return nc; } From cd48bcfd7da3ecaa1a4a537e6903c24ed3688e4a Mon Sep 17 00:00:00 2001 From: Dmitry Frank Date: Fri, 9 Jun 2017 14:16:14 +0100 Subject: [PATCH 084/137] Don't ignore userdata in mg_bind PUBLISHED_FROM=0ffcd770535efa66ff1b6f9201f2caf832bd5055 --- mongoose.c | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/mongoose.c b/mongoose.c index 9dbc4943..18467af7 100644 --- a/mongoose.c +++ b/mongoose.c @@ -2783,6 +2783,10 @@ struct mg_connection *mg_bind_opt(struct mg_mgr *mgr, const char *address, struct mg_add_sock_opts add_sock_opts; char host[MG_MAX_HOST_LEN]; +#if MG_ENABLE_CALLBACK_USERDATA + opts.user_data = user_data; +#endif + MG_COPY_COMMON_CONNECTION_OPTIONS(&add_sock_opts, &opts); #if MG_ENABLE_TUN @@ -2846,9 +2850,6 @@ struct mg_connection *mg_bind_opt(struct mg_mgr *mgr, const char *address, } mg_add_conn(nc->mgr, nc); -#if MG_ENABLE_CALLBACK_USERDATA - (void) user_data; -#endif return nc; } From 27094896b19b46d1eed0bc5346d4b0dc3c2e3cd6 Mon Sep 17 00:00:00 2001 From: Deomid Ryabkov Date: Tue, 13 Jun 2017 16:22:43 +0100 Subject: [PATCH 085/137] mOS filesystem refactoring: introduce VFS With different filesystem implementations and storage drivers, like grown-ups have :) This is not currently used to add any new functionality, we still have only one FS and driver on ESP8266 and ESP32; CC3200 has two: SPIFFS and SLFS. This will be used soon to implement filesystems on additional SPI flash chips and SD cards. PUBLISHED_FROM=293960fef82952c505e9b1925aac7724c7308362 --- mongoose.c | 86 +++++++++++++++++++++++++++++++----------------------- mongoose.h | 4 ++- 2 files changed, 52 insertions(+), 38 deletions(-) diff --git a/mongoose.c b/mongoose.c index 18467af7..988d9487 100644 --- a/mongoose.c +++ b/mongoose.c @@ -12593,8 +12593,8 @@ void fs_slfs_set_new_file_size(const char *name, size_t size); /* Amalgamated: #include "common/mg_mem.h" */ /* From sl_fs.c */ -extern int set_errno(int e); -static const char *drop_dir(const char *fname, bool *is_slfs); +int set_errno(int e); +const char *drop_dir(const char *fname, bool *is_slfs); /* * With SLFS, you have to pre-declare max file size. Yes. Really. @@ -12657,6 +12657,7 @@ int fs_slfs_open(const char *pathname, int flags, mode_t mode) { _u32 am = 0; fi->size = (size_t) -1; int rw = (flags & 3); + size_t new_size = FS_SLFS_MAX_FILE_SIZE; if (rw == O_RDONLY) { SlFsFileInfo_t sl_fi; _i32 r = sl_FsGetInfo((const _u8 *) pathname, 0, &sl_fi); @@ -12671,25 +12672,24 @@ int fs_slfs_open(const char *pathname, int flags, mode_t mode) { return set_errno(ENOTSUP); } if (flags & O_CREAT) { - size_t i, size = FS_SLFS_MAX_FILE_SIZE; + size_t i; for (i = 0; i < MAX_OPEN_SLFS_FILES; i++) { if (s_sl_file_size_hints[i].name != NULL && strcmp(s_sl_file_size_hints[i].name, pathname) == 0) { - size = s_sl_file_size_hints[i].size; + new_size = s_sl_file_size_hints[i].size; MG_FREE(s_sl_file_size_hints[i].name); s_sl_file_size_hints[i].name = NULL; break; } } - DBG(("creating %s with max size %d", pathname, (int) size)); - am = FS_MODE_OPEN_CREATE(size, 0); + am = FS_MODE_OPEN_CREATE(new_size, 0); } else { am = FS_MODE_OPEN_WRITE; } } _i32 r = sl_FsOpen((_u8 *) pathname, am, NULL, &fi->fh); - DBG(("sl_FsOpen(%s, 0x%x) = %d, %d", pathname, (int) am, (int) r, - (int) fi->fh)); + LOG(LL_DEBUG, ("sl_FsOpen(%s, 0x%x) sz %u = %d, %d", pathname, (int) am, + (unsigned int) new_size, (int) r, (int) fi->fh)); if (r == SL_FS_OK) { fi->pos = 0; r = fd; @@ -12704,7 +12704,7 @@ int fs_slfs_close(int fd) { struct sl_fd_info *fi = &s_sl_fds[fd]; if (fi->fh <= 0) return set_errno(EBADF); _i32 r = sl_FsClose(fi->fh, NULL, NULL, 0); - DBG(("sl_FsClose(%d) = %d", (int) fi->fh, (int) r)); + LOG(LL_DEBUG, ("sl_FsClose(%d) = %d", (int) fi->fh, (int) r)); s_sl_fds[fd].fh = -1; return set_errno(sl_fs_to_errno(r)); } @@ -12817,6 +12817,32 @@ void fs_slfs_set_new_file_size(const char *name, size_t size) { #if MG_NET_IF == MG_NET_IF_SIMPLELINK && \ (defined(MG_FS_SLFS) || defined(MG_FS_SPIFFS)) +int set_errno(int e) { + errno = e; + return (e == 0 ? 0 : -1); +} + +const char *drop_dir(const char *fname, bool *is_slfs) { + if (is_slfs != NULL) { + *is_slfs = (strncmp(fname, "SL:", 3) == 0); + if (*is_slfs) fname += 3; + } + /* Drop "./", if any */ + if (fname[0] == '.' && fname[1] == '/') { + fname += 2; + } + /* + * Drop / if it is the only one in the path. + * This allows use of /pretend/directories but serves /file.txt as normal. + */ + if (fname[0] == '/' && strchr(fname + 1, '/') == NULL) { + fname++; + } + return fname; +} + +#if !defined(MG_FS_NO_VFS) + #include #include #include @@ -12854,30 +12880,6 @@ void fs_slfs_set_new_file_size(const char *name, size_t size) { #endif /* CS_PLATFORM == CS_P_CC3200 */ #endif /* !MG_UART_CHAR_PUT */ -int set_errno(int e) { - errno = e; - return (e == 0 ? 0 : -1); -} - -static const char *drop_dir(const char *fname, bool *is_slfs) { - if (is_slfs != NULL) { - *is_slfs = (strncmp(fname, "SL:", 3) == 0); - if (*is_slfs) fname += 3; - } - /* Drop "./", if any */ - if (fname[0] == '.' && fname[1] == '/') { - fname += 2; - } - /* - * Drop / if it is the only one in the path. - * This allows use of /pretend/directories but serves /file.txt as normal. - */ - if (fname[0] == '/' && strchr(fname + 1, '/') == NULL) { - fname++; - } - return fname; -} - enum fd_type { FD_INVALID, FD_SYS, @@ -13215,6 +13217,7 @@ int sl_fs_init(void) { return ret; } +#endif /* !defined(MG_FS_NO_VFS) */ #endif /* MG_NET_IF == MG_NET_IF_SIMPLELINK && (defined(MG_FS_SLFS) || \ defined(MG_FS_SPIFFS)) */ #ifdef MG_MODULE_LINES @@ -13833,6 +13836,13 @@ const struct mg_iface_vtable mg_default_iface_vtable = MG_SL_IFACE_VTABLE; /* Amalgamated: #include "common/mg_mem.h" */ +#ifndef MG_SSL_IF_SIMPLELINK_SLFS_PREFIX +#define MG_SSL_IF_SIMPLELINK_SLFS_PREFIX "SL:" +#endif + +#define MG_SSL_IF_SIMPLELINK_SLFS_PREFIX_LEN \ + (sizeof(MG_SSL_IF_SIMPLELINK_SLFS_PREFIX) - 1) + struct mg_ssl_if_ctx { char *ssl_cert; char *ssl_key; @@ -13897,7 +13907,8 @@ bool pem_to_der(const char *pem_file, const char *der_file) { pf = fopen(pem_file, "r"); if (pf == NULL) goto clean; remove(der_file); - fs_slfs_set_new_file_size(der_file + 3, 2048); + fs_slfs_set_new_file_size(der_file + MG_SSL_IF_SIMPLELINK_SLFS_PREFIX_LEN, + 2048); df = fopen(der_file, "w"); if (df == NULL) goto clean; while (1) { @@ -13939,8 +13950,8 @@ static char *sl_pem2der(const char *pem_file) { } char *der_file = NULL; /* DER file must be located on SLFS, add prefix. */ - int l = mg_asprintf(&der_file, 0, "SL:%.*s.der", (int) (pem_ext - pem_file), - pem_file); + int l = mg_asprintf(&der_file, 0, MG_SSL_IF_SIMPLELINK_SLFS_PREFIX "%.*s.der", + (int) (pem_ext - pem_file), pem_file); if (der_file == NULL) return NULL; bool result = false; cs_stat_t st; @@ -13953,7 +13964,8 @@ static char *sl_pem2der(const char *pem_file) { } if (result) { /* Strip the SL: prefix we added since NWP does not expect it. */ - memmove(der_file, der_file + 3, l - 2 /* including \0 */); + memmove(der_file, der_file + MG_SSL_IF_SIMPLELINK_SLFS_PREFIX_LEN, + l - 2 /* including \0 */); } else { MG_FREE(der_file); der_file = NULL; diff --git a/mongoose.h b/mongoose.h index 209614cb..19727dba 100644 --- a/mongoose.h +++ b/mongoose.h @@ -538,7 +538,9 @@ typedef struct stat cs_stat_t; #define SIZE_T_FMT "u" typedef struct stat cs_stat_t; #define DIRSEP '/' +#if !defined(MGOS_VFS_DEFINE_DIRENT) #define CS_DEFINE_DIRENT +#endif #define to64(x) strtoll(x, NULL, 10) #define INT64_FMT PRId64 @@ -700,7 +702,7 @@ struct stat { }; int _stat(const char *pathname, struct stat *st); -#define stat(a, b) _stat(a, b) +int stat(const char *pathname, struct stat *st); #define __S_IFMT 0170000 From 474e065a3069e8b8280d5638b3459c699aee69dc Mon Sep 17 00:00:00 2001 From: Deomid Ryabkov Date: Tue, 20 Jun 2017 18:50:09 +0100 Subject: [PATCH 086/137] MAX_PATH_SIZE -> MG_MAX_PATH PUBLISHED_FROM=32bda9e86a11cad3b908d211a1f7bc9d27312874 --- mongoose.c | 32 ++++++++++++++++---------------- mongoose.h | 16 ++++++---------- 2 files changed, 22 insertions(+), 26 deletions(-) diff --git a/mongoose.c b/mongoose.c index 988d9487..7cafda28 100644 --- a/mongoose.c +++ b/mongoose.c @@ -6991,7 +6991,7 @@ static void mg_escape(const char *src, char *dst, size_t dst_len) { static void mg_print_dir_entry(struct mg_connection *nc, const char *file_name, cs_stat_t *stp) { - char size[64], mod[64], href[MAX_PATH_SIZE * 3], path[MAX_PATH_SIZE]; + char size[64], mod[64], href[MG_MAX_PATH * 3], path[MG_MAX_PATH]; int64_t fsize = stp->st_size; int is_dir = S_ISDIR(stp->st_mode); const char *slash = is_dir ? "/" : ""; @@ -7027,7 +7027,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[MAX_PATH_SIZE]; + char path[MG_MAX_PATH]; cs_stat_t st; struct dirent *dp; DIR *dirp; @@ -8136,7 +8136,7 @@ static void mg_spawn_stdio_thread(sock_t sock, HANDLE hPipe, } static void mg_abs_path(const char *utf8_path, char *abs_path, size_t len) { - wchar_t buf[MAX_PATH_SIZE], buf2[MAX_PATH_SIZE]; + wchar_t buf[MG_MAX_PATH], buf2[MG_MAX_PATH]; to_wchar(utf8_path, buf, ARRAY_SIZE(buf)); GetFullPathNameW(buf, ARRAY_SIZE(buf2), buf2, NULL); WideCharToMultiByte(CP_UTF8, 0, buf2, wcslen(buf2) + 1, abs_path, len, 0, 0); @@ -8148,9 +8148,9 @@ static int mg_start_process(const char *interp, const char *cmd, STARTUPINFOW si; PROCESS_INFORMATION pi; HANDLE a[2], b[2], me = GetCurrentProcess(); - wchar_t wcmd[MAX_PATH_SIZE], full_dir[MAX_PATH_SIZE]; - char buf[MAX_PATH_SIZE], buf2[MAX_PATH_SIZE], buf5[MAX_PATH_SIZE], - buf4[MAX_PATH_SIZE], cmdline[MAX_PATH_SIZE]; + wchar_t wcmd[MG_MAX_PATH], full_dir[MG_MAX_PATH]; + char buf[MG_MAX_PATH], buf2[MG_MAX_PATH], buf5[MG_MAX_PATH], + buf4[MG_MAX_PATH], cmdline[MG_MAX_PATH]; DWORD flags = DUPLICATE_CLOSE_SOURCE | DUPLICATE_SAME_ACCESS; FILE *fp; @@ -8476,7 +8476,7 @@ MG_INTERNAL void mg_handle_cgi(struct mg_connection *nc, const char *prog, const struct http_message *hm, const struct mg_serve_http_opts *opts) { struct mg_cgi_env_block blk; - char dir[MAX_PATH_SIZE]; + char dir[MG_MAX_PATH]; const char *p; sock_t fds[2]; @@ -8567,7 +8567,7 @@ static void mg_send_file_data(struct mg_connection *nc, FILE *fp) { static void mg_do_ssi_include(struct mg_connection *nc, struct http_message *hm, const char *ssi, char *tag, int include_level, const struct mg_serve_http_opts *opts) { - char file_name[BUFSIZ], path[MAX_PATH_SIZE], *p; + char file_name[MG_MAX_PATH], path[MG_MAX_PATH], *p; FILE *fp; /* @@ -8783,7 +8783,7 @@ static int mg_mkdir(const char *path, uint32_t mode) { static void mg_print_props(struct mg_connection *nc, const char *name, cs_stat_t *stp) { - char mtime[64], buf[MAX_PATH_SIZE * 3]; + char mtime[64], buf[MG_MAX_PATH * 3]; time_t t = stp->st_mtime; /* store in local variable for NDK compile */ mg_gmt_time_string(mtime, sizeof(mtime), &t); mg_url_encode(name, strlen(name), buf, sizeof(buf)); @@ -8821,7 +8821,7 @@ MG_INTERNAL void mg_handle_propfind(struct mg_connection *nc, const char *path, strcmp(opts->enable_directory_listing, "yes") != 0) { mg_printf(nc, "%s", "HTTP/1.1 403 Directory Listing Denied\r\n\r\n"); } else { - char uri[MAX_PATH_SIZE]; + char uri[MG_MAX_PATH]; mg_send(nc, header, sizeof(header) - 1); snprintf(uri, sizeof(uri), "%.*s", (int) hm->uri.len, hm->uri.p); mg_print_props(nc, uri, stp); @@ -8888,7 +8888,7 @@ MG_INTERNAL void mg_handle_mkcol(struct mg_connection *nc, const char *path, static int mg_remove_directory(const struct mg_serve_http_opts *opts, const char *dir) { - char path[MAX_PATH_SIZE]; + char path[MG_MAX_PATH]; struct dirent *dp; cs_stat_t st; DIR *dirp; @@ -8923,7 +8923,7 @@ MG_INTERNAL void mg_handle_move(struct mg_connection *c, const char *p = (char *) memchr(dest->p, '/', dest->len); if (p != NULL && p[1] == '/' && (p = (char *) memchr(p + 2, '/', dest->p + dest->len - p)) != NULL) { - char buf[MAX_PATH_SIZE]; + char buf[MG_MAX_PATH]; snprintf(buf, sizeof(buf), "%s%.*s", opts->dav_document_root, (int) (dest->p + dest->len - p), p); if (rename(path, buf) == 0) { @@ -8960,7 +8960,7 @@ static int mg_create_itermediate_directories(const char *path) { /* Create intermediate directories if they do not exist */ for (s = path + 1; *s != '\0'; s++) { if (*s == '/') { - char buf[MAX_PATH_SIZE]; + char buf[MG_MAX_PATH]; cs_stat_t st; snprintf(buf, sizeof(buf), "%.*s", (int) (s - path), path); buf[sizeof(buf) - 1] = '\0'; @@ -9457,7 +9457,7 @@ static int lowercase(const char *s) { #if MG_ENABLE_FILESYSTEM && !defined(MG_USER_FILE_FUNCTIONS) int mg_stat(const char *path, cs_stat_t *st) { #ifdef _WIN32 - wchar_t wpath[MAX_PATH_SIZE]; + wchar_t wpath[MG_MAX_PATH]; to_wchar(path, wpath, ARRAY_SIZE(wpath)); DBG(("[%ls] -> %d", wpath, _wstati64(wpath, st))); return _wstati64(wpath, st); @@ -9468,7 +9468,7 @@ int mg_stat(const char *path, cs_stat_t *st) { FILE *mg_fopen(const char *path, const char *mode) { #ifdef _WIN32 - wchar_t wpath[MAX_PATH_SIZE], wmode[10]; + wchar_t wpath[MG_MAX_PATH], wmode[10]; to_wchar(path, wpath, ARRAY_SIZE(wpath)); to_wchar(mode, wmode, ARRAY_SIZE(wmode)); return _wfopen(wpath, wmode); @@ -9479,7 +9479,7 @@ FILE *mg_fopen(const char *path, const char *mode) { int mg_open(const char *path, int flag, int mode) { /* LCOV_EXCL_LINE */ #if defined(_WIN32) && !defined(WINCE) - wchar_t wpath[MAX_PATH_SIZE]; + wchar_t wpath[MG_MAX_PATH]; to_wchar(path, wpath, ARRAY_SIZE(wpath)); return _wopen(wpath, flag, mode); #else diff --git a/mongoose.h b/mongoose.h index 19727dba..bed63633 100644 --- a/mongoose.h +++ b/mongoose.h @@ -3891,8 +3891,12 @@ int mg_normalize_uri_path(const struct mg_str *in, struct mg_str *out); extern "C" { #endif /* __cplusplus */ -#ifndef MAX_PATH_SIZE -#define MAX_PATH_SIZE 500 +#ifndef MG_MAX_PATH +#ifdef PATH_MAX +#define MG_MAX_PATH PATH_MAX +#else +#define MG_MAX_PATH 256 +#endif #endif /* @@ -4123,14 +4127,6 @@ extern "C" { #define MG_MAX_HTTP_REQUEST_SIZE 1024 #endif -#ifndef MG_MAX_PATH -#ifdef PATH_MAX -#define MG_MAX_PATH PATH_MAX -#else -#define MG_MAX_PATH 256 -#endif -#endif - #ifndef MG_MAX_HTTP_SEND_MBUF #define MG_MAX_HTTP_SEND_MBUF 1024 #endif From 104106b9cff5692a49849f405ec095427403a81a Mon Sep 17 00:00:00 2001 From: Deomid Ryabkov Date: Tue, 20 Jun 2017 19:25:43 +0100 Subject: [PATCH 087/137] Invoke tcp_accepted() on the listening pcb As required by the LWIP API PUBLISHED_FROM=7bfc6d816aa69f8fdd7592ade48b2d52e2d4991a --- mongoose.c | 21 +++++++++++++++++---- 1 file changed, 17 insertions(+), 4 deletions(-) diff --git a/mongoose.c b/mongoose.c index 7cafda28..7de66e91 100644 --- a/mongoose.c +++ b/mongoose.c @@ -14481,15 +14481,27 @@ void mg_lwip_handle_accept(struct mg_connection *nc) { } static err_t mg_lwip_accept_cb(void *arg, struct tcp_pcb *newtpcb, err_t err) { - struct mg_connection *lc = (struct mg_connection *) arg; - DBG(("%p conn %p from %s:%u", lc, newtpcb, + struct mg_connection *lc = (struct mg_connection *) arg, *nc; + struct mg_lwip_conn_state *lcs, *cs; + struct tcp_pcb_listen *lpcb; + LOG(LL_INFO, + ("%p conn %p from %s:%u", lc, newtpcb, IPADDR_NTOA(ipX_2_ip(&newtpcb->remote_ip)), newtpcb->remote_port)); - struct mg_connection *nc = mg_if_accept_new_conn(lc); + if (lc == NULL) { + tcp_abort(newtpcb); + return ERR_ABRT; + } + lcs = (struct mg_lwip_conn_state *) lc->sock; + lpcb = (struct tcp_pcb_listen *) lcs->pcb.tcp; +#if TCP_LISTEN_BACKLOG + tcp_accepted(lpcb); +#endif + nc = mg_if_accept_new_conn(lc); if (nc == NULL) { tcp_abort(newtpcb); return ERR_ABRT; } - struct mg_lwip_conn_state *cs = (struct mg_lwip_conn_state *) nc->sock; + cs = (struct mg_lwip_conn_state *) nc->sock; cs->lc = lc; cs->pcb.tcp = newtpcb; /* We need to set up callbacks before returning because data may start @@ -14503,6 +14515,7 @@ static err_t mg_lwip_accept_cb(void *arg, struct tcp_pcb *newtpcb, err_t err) { #endif mg_lwip_post_signal(MG_SIG_ACCEPT, nc); (void) err; + (void) lpcb; return ERR_OK; } From 02707364f00d95f507f2bf9683372700f0d71e9e Mon Sep 17 00:00:00 2001 From: Deomid Ryabkov Date: Tue, 20 Jun 2017 19:54:01 +0100 Subject: [PATCH 088/137] Lower conn accept message verbosity to DEBUG Raised in previous commit by mistake PUBLISHED_FROM=31a73fb610c34ed0c85d081bfa11a8067f216696 --- mongoose.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mongoose.c b/mongoose.c index 7de66e91..7f7f099c 100644 --- a/mongoose.c +++ b/mongoose.c @@ -14484,7 +14484,7 @@ static err_t mg_lwip_accept_cb(void *arg, struct tcp_pcb *newtpcb, err_t err) { struct mg_connection *lc = (struct mg_connection *) arg, *nc; struct mg_lwip_conn_state *lcs, *cs; struct tcp_pcb_listen *lpcb; - LOG(LL_INFO, + LOG(LL_DEBUG, ("%p conn %p from %s:%u", lc, newtpcb, IPADDR_NTOA(ipX_2_ip(&newtpcb->remote_ip)), newtpcb->remote_port)); if (lc == NULL) { From f374ac5f9a1eb814e1bc2413aeda66be2162f363 Mon Sep 17 00:00:00 2001 From: Deomid Ryabkov Date: Tue, 20 Jun 2017 20:49:50 +0100 Subject: [PATCH 089/137] Do not close already closed connection PUBLISHED_FROM=9e345f2319141f20b89e28a2d29adba21ea213e1 --- mongoose.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mongoose.c b/mongoose.c index 7f7f099c..3015c29f 100644 --- a/mongoose.c +++ b/mongoose.c @@ -14230,7 +14230,7 @@ static err_t mg_lwip_tcp_recv_cb(void *arg, struct tcp_pcb *tpcb, struct mg_connection *nc = (struct mg_connection *) arg; DBG(("%p %p %u %d", nc, tpcb, (p != NULL ? p->tot_len : 0), err)); if (p == NULL) { - if (nc != NULL) { + if (nc != NULL && !(nc->flags & MG_F_CLOSE_IMMEDIATELY)) { mg_lwip_post_signal(MG_SIG_CLOSE_CONN, nc); } else { /* Tombstoned connection, do nothing. */ From fb3a5a7d905978b5b1ce26ad3100294ee669dda1 Mon Sep 17 00:00:00 2001 From: Deomid Ryabkov Date: Wed, 21 Jun 2017 15:17:22 +0100 Subject: [PATCH 090/137] Disable cert verification when ssl_ca_cert is '*' PUBLISHED_FROM=578706e48a2c1fbbf5e9aaab3eba743e7d13fa61 --- mongoose.c | 1 + 1 file changed, 1 insertion(+) diff --git a/mongoose.c b/mongoose.c index 3015c29f..ca80bd4b 100644 --- a/mongoose.c +++ b/mongoose.c @@ -4695,6 +4695,7 @@ void mg_ssl_if_conn_free(struct mg_connection *nc) { static enum mg_ssl_if_result mg_use_ca_cert(struct mg_ssl_if_ctx *ctx, const char *ca_cert) { if (ca_cert == NULL || strcmp(ca_cert, "*") == 0) { + mbedtls_ssl_conf_authmode(ctx->conf, MBEDTLS_SSL_VERIFY_NONE); return MG_SSL_OK; } ctx->ca_cert = (mbedtls_x509_crt *) MG_CALLOC(1, sizeof(*ctx->ca_cert)); From 8d76733fadc280e6e22779d49cdd57e07f39f060 Mon Sep 17 00:00:00 2001 From: Sergey Lyubka Date: Mon, 26 Jun 2017 21:34:16 +0100 Subject: [PATCH 091/137] Make mg_conn_addr_to_str return len Also amend api_net.js to use returned length. PUBLISHED_FROM=38e15f9587edf28049c5b9e5f126b4db159910e8 --- docs/c-api/util.h/mg_conn_addr_to_str.md | 7 ++++--- docs/c-api/util.h/mg_sock_addr_to_str.md | 4 ++-- mongoose.c | 15 ++++++++------- mongoose.h | 9 +++++---- 4 files changed, 19 insertions(+), 16 deletions(-) diff --git a/docs/c-api/util.h/mg_conn_addr_to_str.md b/docs/c-api/util.h/mg_conn_addr_to_str.md index e623734f..b7603fb2 100644 --- a/docs/c-api/util.h/mg_conn_addr_to_str.md +++ b/docs/c-api/util.h/mg_conn_addr_to_str.md @@ -3,8 +3,8 @@ title: "mg_conn_addr_to_str()" decl_name: "mg_conn_addr_to_str" symbol_kind: "func" signature: | - void mg_conn_addr_to_str(struct mg_connection *nc, char *buf, size_t len, - int flags); + int mg_conn_addr_to_str(struct mg_connection *c, char *buf, size_t len, + int flags); --- Converts a connection's local or remote address into string. @@ -17,5 +17,6 @@ see `MG_SOCK_STRINGIFY_*` definitions. - MG_SOCK_STRINGIFY_REMOTE - print remote peer's IP/port, not local address If both port number and IP address are printed, they are separated by `:`. -If compiled with `-DMG_ENABLE_IPV6`, IPv6 addresses are supported. +If compiled with `-DMG_ENABLE_IPV6`, IPv6 addresses are supported. +Return length of the stringified address. diff --git a/docs/c-api/util.h/mg_sock_addr_to_str.md b/docs/c-api/util.h/mg_sock_addr_to_str.md index 3502e135..b5cb6fdd 100644 --- a/docs/c-api/util.h/mg_sock_addr_to_str.md +++ b/docs/c-api/util.h/mg_sock_addr_to_str.md @@ -3,8 +3,8 @@ title: "mg_sock_addr_to_str()" decl_name: "mg_sock_addr_to_str" symbol_kind: "func" signature: | - void mg_sock_addr_to_str(const union socket_address *sa, char *buf, size_t len, - int flags); + int mg_sock_addr_to_str(const union socket_address *sa, char *buf, size_t len, + int flags); --- Convert the socket's address into string. diff --git a/mongoose.c b/mongoose.c index ca80bd4b..677ce124 100644 --- a/mongoose.c +++ b/mongoose.c @@ -9541,10 +9541,10 @@ void mg_set_close_on_exec(sock_t sock) { #endif } -void mg_sock_addr_to_str(const union socket_address *sa, char *buf, size_t len, - int flags) { +int mg_sock_addr_to_str(const union socket_address *sa, char *buf, size_t len, + int flags) { int is_v6; - if (buf == NULL || len <= 0) return; + if (buf == NULL || len <= 0) return 0; memset(buf, 0, len); #if MG_ENABLE_IPV6 is_v6 = sa->sa.sa_family == AF_INET6; @@ -9594,18 +9594,19 @@ void mg_sock_addr_to_str(const union socket_address *sa, char *buf, size_t len, } } - return; + return strlen(buf); cleanup: *buf = '\0'; + return 0; } -void mg_conn_addr_to_str(struct mg_connection *nc, char *buf, size_t len, - int flags) { +int mg_conn_addr_to_str(struct mg_connection *nc, char *buf, size_t len, + int flags) { union socket_address sa; memset(&sa, 0, sizeof(sa)); mg_if_get_conn_addr(nc, flags & MG_SOCK_STRINGIFY_REMOTE, &sa); - mg_sock_addr_to_str(&sa, buf, len, flags); + return mg_sock_addr_to_str(&sa, buf, len, flags); } #if MG_ENABLE_HEXDUMP diff --git a/mongoose.h b/mongoose.h index bed63633..64a9250b 100644 --- a/mongoose.h +++ b/mongoose.h @@ -4001,9 +4001,10 @@ void mg_set_close_on_exec(sock_t); * * If both port number and IP address are printed, they are separated by `:`. * If compiled with `-DMG_ENABLE_IPV6`, IPv6 addresses are supported. + * Return length of the stringified address. */ -void mg_conn_addr_to_str(struct mg_connection *nc, char *buf, size_t len, - int flags); +int mg_conn_addr_to_str(struct mg_connection *c, char *buf, size_t len, + int flags); #if MG_NET_IF == MG_NET_IF_SOCKET /* Legacy interface. */ void mg_sock_to_str(sock_t sock, char *buf, size_t len, int flags); @@ -4014,8 +4015,8 @@ void mg_sock_to_str(sock_t sock, char *buf, size_t len, int flags); * * `flags` is MG_SOCK_STRINGIFY_IP and/or MG_SOCK_STRINGIFY_PORT. */ -void mg_sock_addr_to_str(const union socket_address *sa, char *buf, size_t len, - int flags); +int mg_sock_addr_to_str(const union socket_address *sa, char *buf, size_t len, + int flags); #if MG_ENABLE_HEXDUMP /* From ff078882d5066472c8df0d52629e4714c2416023 Mon Sep 17 00:00:00 2001 From: Dmitry Frank Date: Tue, 27 Jun 2017 16:06:21 +0100 Subject: [PATCH 092/137] Don't define fileno stub in C++ PUBLISHED_FROM=98fb6c78d20a98dfba07ba6671bd51a394bbc4ca --- mongoose.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mongoose.h b/mongoose.h index 64a9250b..1067ed3b 100644 --- a/mongoose.h +++ b/mongoose.h @@ -548,7 +548,7 @@ typedef struct stat cs_stat_t; #define __cdecl #define _FILE_OFFSET_BITS 32 -#ifndef RTOS_SDK +#if !defined(RTOS_SDK) && !defined(__cplusplus) #define fileno(x) -1 #endif From 244e5f67d35dc81167a1d2b7ecbd4b2a243bcedf Mon Sep 17 00:00:00 2001 From: Sergey Lyubka Date: Wed, 28 Jun 2017 19:18:42 +0100 Subject: [PATCH 093/137] Commonize pattern matching functions PUBLISHED_FROM=e69e298a51dbe0f9c47184169ecad06eef0676fc --- docs/c-api/util.h/intro.md | 2 - docs/c-api/util.h/mg_match_prefix.md | 14 -- docs/c-api/util.h/mg_next_comma_list_entry.md | 21 -- mongoose.c | 179 +++++++++--------- mongoose.h | 53 +++--- 5 files changed, 119 insertions(+), 150 deletions(-) delete mode 100644 docs/c-api/util.h/mg_match_prefix.md delete mode 100644 docs/c-api/util.h/mg_next_comma_list_entry.md diff --git a/docs/c-api/util.h/intro.md b/docs/c-api/util.h/intro.md index 4a390e48..d04619a1 100644 --- a/docs/c-api/util.h/intro.md +++ b/docs/c-api/util.h/intro.md @@ -14,10 +14,8 @@ items: - { name: mg_hexdump_connection.md } - { name: mg_hexdumpf.md } - { name: mg_is_big_endian.md } - - { name: mg_match_prefix.md } - { name: mg_mbuf_append_base64.md } - { name: mg_mbuf_append_base64_putc.md } - - { name: mg_next_comma_list_entry.md } - { name: mg_open.md } - { name: mg_skip.md } - { name: mg_sock_addr_to_str.md } diff --git a/docs/c-api/util.h/mg_match_prefix.md b/docs/c-api/util.h/mg_match_prefix.md deleted file mode 100644 index 15ddc9ef..00000000 --- a/docs/c-api/util.h/mg_match_prefix.md +++ /dev/null @@ -1,14 +0,0 @@ ---- -title: "mg_match_prefix()" -decl_name: "mg_match_prefix" -symbol_kind: "func" -signature: | - int mg_match_prefix(const char *pattern, int pattern_len, const char *str); ---- - -Matches 0-terminated string (mg_match_prefix) or string with given length -mg_match_prefix_n against a glob pattern. - -Match is case-insensitive. Returns number of bytes matched, or -1 if no -match. - diff --git a/docs/c-api/util.h/mg_next_comma_list_entry.md b/docs/c-api/util.h/mg_next_comma_list_entry.md deleted file mode 100644 index a9610393..00000000 --- a/docs/c-api/util.h/mg_next_comma_list_entry.md +++ /dev/null @@ -1,21 +0,0 @@ ---- -title: "mg_next_comma_list_entry()" -decl_name: "mg_next_comma_list_entry" -symbol_kind: "func" -signature: | - const char *mg_next_comma_list_entry(const char *list, struct mg_str *val, - struct mg_str *eq_val); ---- - -A helper function for traversing a comma separated list of values. -It returns a list pointer shifted to the next value or NULL if the end -of the list found. -The value is stored in a val vector. If the value has a form "x=y", then -eq_val vector is initialised to point to the "y" part, and val vector length -is adjusted to point only to "x". -If the list is just a comma separated list of entries, like "aa,bb,cc" then -`eq_val` will contain zero-length string. - -The purpose of this function is to parse comma separated string without -any copying/memory allocation. - diff --git a/mongoose.c b/mongoose.c index 677ce124..8379c6eb 100644 --- a/mongoose.c +++ b/mongoose.c @@ -1858,6 +1858,98 @@ int mg_avprintf(char **buf, size_t size, const char *fmt, va_list ap) { return len; } +const char *mg_next_comma_list_entry(const char *, struct mg_str *, + struct mg_str *) WEAK; +const char *mg_next_comma_list_entry(const char *list, struct mg_str *val, + struct mg_str *eq_val) { + if (list == NULL || *list == '\0') { + /* End of the list */ + list = NULL; + } else { + val->p = list; + if ((list = strchr(val->p, ',')) != NULL) { + /* Comma found. Store length and shift the list ptr */ + val->len = list - val->p; + list++; + } else { + /* This value is the last one */ + list = val->p + strlen(val->p); + val->len = list - val->p; + } + + if (eq_val != NULL) { + /* Value has form "x=y", adjust pointers and lengths */ + /* so that val points to "x", and eq_val points to "y". */ + eq_val->len = 0; + eq_val->p = (const char *) memchr(val->p, '=', val->len); + if (eq_val->p != NULL) { + eq_val->p++; /* Skip over '=' character */ + eq_val->len = val->p + val->len - eq_val->p; + val->len = (eq_val->p - val->p) - 1; + } + } + } + + return list; +} + +int mg_match_prefix_n(const struct mg_str, const struct mg_str) WEAK; +int mg_match_prefix_n(const struct mg_str pattern, const struct mg_str str) { + const char *or_str; + size_t len, i = 0, j = 0; + int res; + + if ((or_str = (const char *) memchr(pattern.p, '|', pattern.len)) != NULL || + (or_str = (const char *) memchr(pattern.p, ',', pattern.len)) != NULL) { + struct mg_str pstr = {pattern.p, (size_t)(or_str - pattern.p)}; + res = mg_match_prefix_n(pstr, str); + if (res > 0) return res; + pstr.p = or_str + 1; + pstr.len = (pattern.p + pattern.len) - (or_str + 1); + return mg_match_prefix_n(pstr, str); + } + + for (; i < pattern.len; i++, j++) { + if (pattern.p[i] == '?' && j != str.len) { + continue; + } else if (pattern.p[i] == '$') { + return j == str.len ? (int) j : -1; + } else if (pattern.p[i] == '*') { + i++; + if (i < pattern.len && pattern.p[i] == '*') { + i++; + len = str.len - j; + } else { + len = 0; + while (j + len != str.len && str.p[j + len] != '/') { + len++; + } + } + if (i == pattern.len) { + return j + len; + } + do { + const struct mg_str pstr = {pattern.p + i, pattern.len - i}; + const struct mg_str sstr = {str.p + j + len, str.len - j - len}; + res = mg_match_prefix_n(pstr, sstr); + } while (res == -1 && len-- > 0); + return res == -1 ? -1 : (int) (j + res + len); + } else if (str_util_lowercase(&pattern.p[i]) != + str_util_lowercase(&str.p[j])) { + return -1; + } + } + return j; +} + +int mg_match_prefix(const char *, int, const char *) WEAK; +int mg_match_prefix(const char *pattern, int pattern_len, const char *str) { + const struct mg_str pstr = {pattern, (size_t) pattern_len}; + struct mg_str s = {str, 0}; + if (str != NULL) s.len = strlen(str); + return mg_match_prefix_n(pstr, s); +} + #endif /* EXCLUDE_COMMON */ #ifdef MG_MODULE_LINES #line 1 "mongoose/src/tun.h" @@ -9451,10 +9543,6 @@ const char *mg_skip(const char *s, const char *end, const char *delims, return s; } -static int lowercase(const char *s) { - return tolower(*(const unsigned char *) s); -} - #if MG_ENABLE_FILESYSTEM && !defined(MG_USER_FILE_FUNCTIONS) int mg_stat(const char *path, cs_stat_t *st) { #ifdef _WIN32 @@ -9707,89 +9795,6 @@ int mg_is_big_endian(void) { return ((char *) &n)[0] == 0; } -const char *mg_next_comma_list_entry(const char *list, struct mg_str *val, - struct mg_str *eq_val) { - if (list == NULL || *list == '\0') { - /* End of the list */ - list = NULL; - } else { - val->p = list; - if ((list = strchr(val->p, ',')) != NULL) { - /* Comma found. Store length and shift the list ptr */ - val->len = list - val->p; - list++; - } else { - /* This value is the last one */ - list = val->p + strlen(val->p); - val->len = list - val->p; - } - - if (eq_val != NULL) { - /* Value has form "x=y", adjust pointers and lengths */ - /* so that val points to "x", and eq_val points to "y". */ - eq_val->len = 0; - eq_val->p = (const char *) memchr(val->p, '=', val->len); - if (eq_val->p != NULL) { - eq_val->p++; /* Skip over '=' character */ - eq_val->len = val->p + val->len - eq_val->p; - val->len = (eq_val->p - val->p) - 1; - } - } - } - - return list; -} - -int mg_match_prefix_n(const struct mg_str pattern, const struct mg_str str) { - const char *or_str; - size_t len, i = 0, j = 0; - int res; - - if ((or_str = (const char *) memchr(pattern.p, '|', pattern.len)) != NULL) { - struct mg_str pstr = {pattern.p, (size_t)(or_str - pattern.p)}; - res = mg_match_prefix_n(pstr, str); - if (res > 0) return res; - pstr.p = or_str + 1; - pstr.len = (pattern.p + pattern.len) - (or_str + 1); - return mg_match_prefix_n(pstr, str); - } - - for (; i < pattern.len; i++, j++) { - if (pattern.p[i] == '?' && j != str.len) { - continue; - } else if (pattern.p[i] == '$') { - return j == str.len ? (int) j : -1; - } else if (pattern.p[i] == '*') { - i++; - if (i < pattern.len && pattern.p[i] == '*') { - i++; - len = str.len - j; - } else { - len = 0; - while (j + len != str.len && str.p[j + len] != '/') { - len++; - } - } - if (i == pattern.len) { - return j + len; - } - do { - const struct mg_str pstr = {pattern.p + i, pattern.len - i}; - const struct mg_str sstr = {str.p + j + len, str.len - j - len}; - res = mg_match_prefix_n(pstr, sstr); - } while (res == -1 && len-- > 0); - return res == -1 ? -1 : (int) (j + res + len); - } else if (lowercase(&pattern.p[i]) != lowercase(&str.p[j])) { - return -1; - } - } - return j; -} - -int mg_match_prefix(const char *pattern, int pattern_len, const char *str) { - const struct mg_str pstr = {pattern, (size_t) pattern_len}; - return mg_match_prefix_n(pstr, mg_mk_str(str)); -} DO_NOT_WARN_UNUSED MG_INTERNAL int mg_get_errno(void) { #ifndef WINCE diff --git a/mongoose.h b/mongoose.h index 1067ed3b..76bab928 100644 --- a/mongoose.h +++ b/mongoose.h @@ -1955,6 +1955,7 @@ int cs_base64_decode(const unsigned char *s, int len, char *dst, int *dec_len); #include /* Amalgamated: #include "common/platform.h" */ +/* Amalgamated: #include "common/mg_str.h" */ #ifndef CS_ENABLE_STRDUP #define CS_ENABLE_STRDUP 0 @@ -2049,6 +2050,32 @@ int mg_asprintf(char **buf, size_t size, const char *fmt, ...); /* Same as mg_asprintf, but takes varargs list. */ int mg_avprintf(char **buf, size_t size, const char *fmt, va_list ap); +/* + * A helper function for traversing a comma separated list of values. + * It returns a list pointer shifted to the next value or NULL if the end + * of the list found. + * The value is stored in a val vector. If the value has a form "x=y", then + * eq_val vector is initialised to point to the "y" part, and val vector length + * is adjusted to point only to "x". + * If the list is just a comma separated list of entries, like "aa,bb,cc" then + * `eq_val` will contain zero-length string. + * + * The purpose of this function is to parse comma separated string without + * any copying/memory allocation. + */ +const char *mg_next_comma_list_entry(const char *list, struct mg_str *val, + struct mg_str *eq_val); + +/* + * Matches 0-terminated string (mg_match_prefix) or string with given length + * mg_match_prefix_n against a glob pattern. + * + * Match is case-insensitive. Returns number of bytes matched, or -1 if no + * match. + */ +int mg_match_prefix(const char *pattern, int pattern_len, const char *str); +int mg_match_prefix_n(const struct mg_str pattern, const struct mg_str str); + #ifdef __cplusplus } #endif @@ -4048,32 +4075,6 @@ void mg_hexdump_connection(struct mg_connection *nc, const char *path, */ int mg_is_big_endian(void); -/* - * A helper function for traversing a comma separated list of values. - * It returns a list pointer shifted to the next value or NULL if the end - * of the list found. - * The value is stored in a val vector. If the value has a form "x=y", then - * eq_val vector is initialised to point to the "y" part, and val vector length - * is adjusted to point only to "x". - * If the list is just a comma separated list of entries, like "aa,bb,cc" then - * `eq_val` will contain zero-length string. - * - * The purpose of this function is to parse comma separated string without - * any copying/memory allocation. - */ -const char *mg_next_comma_list_entry(const char *list, struct mg_str *val, - struct mg_str *eq_val); - -/* - * Matches 0-terminated string (mg_match_prefix) or string with given length - * mg_match_prefix_n against a glob pattern. - * - * Match is case-insensitive. Returns number of bytes matched, or -1 if no - * match. - */ -int mg_match_prefix(const char *pattern, int pattern_len, const char *str); -int mg_match_prefix_n(const struct mg_str pattern, const struct mg_str str); - /* * Use with cs_base64_init/update/finish in order to write out base64 in chunks. */ From cae0a1cbc0b4efcf340368ce17d02a023deb9273 Mon Sep 17 00:00:00 2001 From: Deomid Ryabkov Date: Wed, 28 Jun 2017 20:06:18 +0100 Subject: [PATCH 094/137] Fix mongoose amalgamation PUBLISHED_FROM=16ae777c949caf87e7dce428d62fa8878a30d318 --- mongoose.c | 1 - 1 file changed, 1 deletion(-) diff --git a/mongoose.c b/mongoose.c index 8379c6eb..10d3924d 100644 --- a/mongoose.c +++ b/mongoose.c @@ -9795,7 +9795,6 @@ int mg_is_big_endian(void) { return ((char *) &n)[0] == 0; } - DO_NOT_WARN_UNUSED MG_INTERNAL int mg_get_errno(void) { #ifndef WINCE return errno; From a7a2e3deb11659341c99e9b68d49d7c23d2f67b4 Mon Sep 17 00:00:00 2001 From: Sergey Lyubka Date: Thu, 29 Jun 2017 15:21:03 +0100 Subject: [PATCH 095/137] Introduce log filter PUBLISHED_FROM=b8f538f87e034452032284d45b78090338e87f72 --- mongoose.c | 58 ++++++++++++++++++++++++++++++++++++++---------------- 1 file changed, 41 insertions(+), 17 deletions(-) diff --git a/mongoose.c b/mongoose.c index 10d3924d..66563fcf 100644 --- a/mongoose.c +++ b/mongoose.c @@ -223,36 +223,34 @@ enum cs_log_level { _LL_MAX = 5, }; +/* Set log level. */ void cs_log_set_level(enum cs_log_level level); +/* Set log filter. NULL (a default) logs everything. */ +void cs_log_set_filter(char *source_file_name); + +int cs_log_print_prefix(enum cs_log_level level, const char *func, + const char *filename); + +extern enum cs_log_level cs_log_threshold; + #if CS_ENABLE_STDIO void cs_log_set_file(FILE *file); -extern enum cs_log_level cs_log_threshold; -void cs_log_print_prefix(enum cs_log_level level, const char *func); void cs_log_printf(const char *fmt, ...) #ifdef __GNUC__ __attribute__((format(printf, 1, 2))) #endif ; -#define LOG(l, x) \ - do { \ - if (cs_log_threshold >= l) { \ - cs_log_print_prefix(l, __func__); \ - cs_log_printf x; \ - } \ +#define LOG(l, x) \ + do { \ + if (cs_log_print_prefix(l, __func__, __FILE__)) cs_log_printf x; \ } while (0) #ifndef CS_NDEBUG -#define DBG(x) \ - do { \ - if (cs_log_threshold >= LL_VERBOSE_DEBUG) { \ - cs_log_print_prefix(LL_VERBOSE_DEBUG, __func__); \ - cs_log_printf x; \ - } \ - } while (0) +#define DBG(x) LOG(LL_VERBOSE_DEBUG, x) #else /* NDEBUG */ @@ -287,6 +285,7 @@ void cs_log_printf(const char *fmt, ...) #include /* Amalgamated: #include "common/cs_time.h" */ +/* Amalgamated: #include "common/str_util.h" */ enum cs_log_level cs_log_threshold WEAK = #if CS_ENABLE_DEBUG @@ -295,6 +294,9 @@ enum cs_log_level cs_log_threshold WEAK = LL_ERROR; #endif +static char *s_filter_pattern = NULL; +static size_t s_filter_pattern_len; + #if CS_ENABLE_STDIO FILE *cs_log_file WEAK = NULL; @@ -305,9 +307,30 @@ double cs_log_ts WEAK; enum cs_log_level cs_log_cur_msg_level WEAK = LL_NONE; -void cs_log_print_prefix(enum cs_log_level level, const char *func) WEAK; -void cs_log_print_prefix(enum cs_log_level level, const char *func) { +void cs_log_set_filter(char *str) WEAK; +void cs_log_set_filter(char *str) { + free(s_filter_pattern); + if (str != NULL) { + s_filter_pattern = strdup(str); + s_filter_pattern_len = strlen(str); + } else { + s_filter_pattern = NULL; + s_filter_pattern_len = 0; + } +}; + +int cs_log_print_prefix(enum cs_log_level, const char *, const char *) WEAK; +int cs_log_print_prefix(enum cs_log_level level, const char *func, + const char *filename) { char prefix[21]; + + if (level > cs_log_threshold) return 0; + if (s_filter_pattern != NULL && + mg_match_prefix(s_filter_pattern, s_filter_pattern_len, func) < 0 && + mg_match_prefix(s_filter_pattern, s_filter_pattern_len, filename) < 0) { + return 0; + } + strncpy(prefix, func, 20); prefix[20] = '\0'; if (cs_log_file == NULL) cs_log_file = stderr; @@ -320,6 +343,7 @@ void cs_log_print_prefix(enum cs_log_level level, const char *func) { cs_log_ts = now; } #endif + return 1; } void cs_log_printf(const char *fmt, ...) WEAK; From ae611a6e553dfe8e9cc814f71a42181bc6af1194 Mon Sep 17 00:00:00 2001 From: Sergey Lyubka Date: Sat, 1 Jul 2017 09:47:33 +0100 Subject: [PATCH 096/137] Clean up v7 from mongoose PUBLISHED_FROM=efa9cc3aaf0c5ae8841e029370f882b615cebf1b --- docs/c-api/net.h/intro.md | 1 - docs/c-api/net.h/mg_enable_javascript.md | 14 ----- docs/c-api/net.h/struct_mg_mgr.md | 3 - mongoose.c | 79 +----------------------- mongoose.h | 23 ------- 5 files changed, 2 insertions(+), 118 deletions(-) delete mode 100644 docs/c-api/net.h/mg_enable_javascript.md diff --git a/docs/c-api/net.h/intro.md b/docs/c-api/net.h/intro.md index fc0bb22f..1534ceb0 100644 --- a/docs/c-api/net.h/intro.md +++ b/docs/c-api/net.h/intro.md @@ -11,7 +11,6 @@ items: - { name: mg_check_ip_acl.md } - { name: mg_connect.md } - { name: mg_connect_opt.md } - - { name: mg_enable_javascript.md } - { name: mg_mgr_free.md } - { name: mg_mgr_init.md } - { name: mg_mgr_init_opt.md } diff --git a/docs/c-api/net.h/mg_enable_javascript.md b/docs/c-api/net.h/mg_enable_javascript.md deleted file mode 100644 index 763151e0..00000000 --- a/docs/c-api/net.h/mg_enable_javascript.md +++ /dev/null @@ -1,14 +0,0 @@ ---- -title: "mg_enable_javascript()" -decl_name: "mg_enable_javascript" -symbol_kind: "func" -signature: | - enum v7_err mg_enable_javascript(struct mg_mgr *m, struct v7 *v7, - const char *init_js_file_name); ---- - -Enables server-side JavaScript scripting. -Requires a `-DMG_ENABLE_JAVASCRIPT` compilation flag and V7 engine sources. -V7 instance must not be destroyed during manager's lifetime. -Returns a V7 error. - diff --git a/docs/c-api/net.h/struct_mg_mgr.md b/docs/c-api/net.h/struct_mg_mgr.md index 63d94633..8e43a1e6 100644 --- a/docs/c-api/net.h/struct_mg_mgr.md +++ b/docs/c-api/net.h/struct_mg_mgr.md @@ -14,9 +14,6 @@ signature: | void *user_data; /* User data */ int num_ifaces; struct mg_iface **ifaces; /* network interfaces */ - #if MG_ENABLE_JAVASCRIPT - struct v7 *v7; - #endif const char *nameserver; /* DNS server to use */ }; --- diff --git a/mongoose.c b/mongoose.c index 66563fcf..ec4303fb 100644 --- a/mongoose.c +++ b/mongoose.c @@ -317,7 +317,7 @@ void cs_log_set_filter(char *str) { s_filter_pattern = NULL; s_filter_pattern_len = 0; } -}; +} int cs_log_print_prefix(enum cs_log_level, const char *, const char *) WEAK; int cs_log_print_prefix(enum cs_log_level level, const char *func, @@ -2281,32 +2281,6 @@ void mg_mgr_init_opt(struct mg_mgr *m, void *user_data, DBG(("init mgr=%p", m)); } -#if MG_ENABLE_JAVASCRIPT -static enum v7_err mg_send_js(struct v7 *v7, v7_val_t *res) { - v7_val_t arg0 = v7_arg(v7, 0); - v7_val_t arg1 = v7_arg(v7, 1); - struct mg_connection *c = (struct mg_connection *) v7_get_ptr(v7, arg0); - size_t len = 0; - - if (v7_is_string(arg1)) { - const char *data = v7_get_string(v7, &arg1, &len); - mg_send(c, data, len); - } - - *res = v7_mk_number(v7, len); - - return V7_OK; -} - -enum v7_err mg_enable_javascript(struct mg_mgr *m, struct v7 *v7, - const char *init_file_name) { - v7_val_t v; - m->v7 = v7; - v7_set_method(v7, v7_get_global(v7), "mg_send", mg_send_js); - return v7_exec_file(v7, init_file_name, &v); -} -#endif - void mg_mgr_free(struct mg_mgr *m) { struct mg_connection *conn, *tmp_conn; @@ -5995,57 +5969,8 @@ void mg_http_handler(struct mg_connection *nc, int ev, MG_SOCK_STRINGIFY_IP | MG_SOCK_STRINGIFY_PORT); DBG(("%p %s %.*s %.*s", nc, addr, (int) hm->method.len, hm->method.p, (int) hm->uri.len, hm->uri.p)); - -/* Whole HTTP message is fully buffered, call event handler */ - -#if MG_ENABLE_JAVASCRIPT - v7_val_t v1, v2, headers, req, args, res; - struct v7 *v7 = nc->mgr->v7; - const char *ev_name = trigger_ev == MG_EV_HTTP_REPLY ? "onsnd" : "onrcv"; - int i, js_callback_handled_request = 0; - - if (v7 != NULL) { - /* Lookup JS callback */ - v1 = v7_get(v7, v7_get_global(v7), "Http", ~0); - v2 = v7_get(v7, v1, ev_name, ~0); - - /* Create callback params. TODO(lsm): own/disown those */ - args = v7_mk_array(v7); - req = v7_mk_object(v7); - headers = v7_mk_object(v7); - - /* Populate request object */ - v7_set(v7, req, "method", ~0, - v7_mk_string(v7, hm->method.p, hm->method.len, 1)); - v7_set(v7, req, "uri", ~0, v7_mk_string(v7, hm->uri.p, hm->uri.len, 1)); - v7_set(v7, req, "body", ~0, - v7_mk_string(v7, hm->body.p, hm->body.len, 1)); - v7_set(v7, req, "headers", ~0, headers); - for (i = 0; hm->header_names[i].len > 0; i++) { - const struct mg_str *name = &hm->header_names[i]; - const struct mg_str *value = &hm->header_values[i]; - v7_set(v7, headers, name->p, name->len, - v7_mk_string(v7, value->p, value->len, 1)); - } - - /* Invoke callback. TODO(lsm): report errors */ - v7_array_push(v7, args, v7_mk_foreign(v7, nc)); - v7_array_push(v7, args, req); - if (v7_apply(v7, v2, V7_UNDEFINED, args, &res) == V7_OK && - v7_is_truthy(v7, res)) { - js_callback_handled_request++; - } - } - - /* If JS callback returns true, stop request processing */ - if (js_callback_handled_request) { - nc->flags |= MG_F_SEND_AND_CLOSE; - } else { - mg_http_call_endpoint_handler(nc, trigger_ev, hm); - } -#else + /* Whole HTTP message is fully buffered, call event handler */ mg_http_call_endpoint_handler(nc, trigger_ev, hm); -#endif mbuf_remove(io, hm->message.len); } } diff --git a/mongoose.h b/mongoose.h index 76bab928..23ef0f16 100644 --- a/mongoose.h +++ b/mongoose.h @@ -2939,10 +2939,6 @@ struct { \ #define MG_ENABLE_IPV6 0 #endif -#ifndef MG_ENABLE_JAVASCRIPT -#define MG_ENABLE_JAVASCRIPT 0 -#endif - #ifndef MG_ENABLE_MQTT #define MG_ENABLE_MQTT 1 #endif @@ -3243,11 +3239,6 @@ int mg_ssl_if_write(struct mg_connection *nc, const void *data, size_t len); #ifndef CS_MONGOOSE_SRC_NET_H_ #define CS_MONGOOSE_SRC_NET_H_ -#if MG_ENABLE_JAVASCRIPT -#define EXCLUDE_COMMON -#include -#endif - /* Amalgamated: #include "mongoose/src/common.h" */ /* Amalgamated: #include "mongoose/src/net_if.h" */ /* Amalgamated: #include "common/mbuf.h" */ @@ -3310,9 +3301,6 @@ struct mg_mgr { void *user_data; /* User data */ int num_ifaces; struct mg_iface **ifaces; /* network interfaces */ -#if MG_ENABLE_JAVASCRIPT - struct v7 *v7; -#endif const char *nameserver; /* DNS server to use */ }; @@ -3777,17 +3765,6 @@ int mg_resolve(const char *domain_name, char *ip_addr_buf, size_t buf_len); */ int mg_check_ip_acl(const char *acl, uint32_t remote_ip); -#if MG_ENABLE_JAVASCRIPT -/* - * Enables server-side JavaScript scripting. - * Requires a `-DMG_ENABLE_JAVASCRIPT` compilation flag and V7 engine sources. - * V7 instance must not be destroyed during manager's lifetime. - * Returns a V7 error. - */ -enum v7_err mg_enable_javascript(struct mg_mgr *m, struct v7 *v7, - const char *init_js_file_name); -#endif - /* * Schedules an MG_EV_TIMER event to be delivered at `timestamp` time. * `timestamp` is UNIX time (the number of seconds since Epoch). It is From 3e59e1c465b39bebbb596df38be451307906109b Mon Sep 17 00:00:00 2001 From: Dmitry Frank Date: Sun, 2 Jul 2017 20:59:19 +0100 Subject: [PATCH 097/137] Fix formatting PUBLISHED_FROM=1803e726eee7bb64496d70389655083eb70257ab --- docs/c-api/net.h/struct_mg_mgr.md | 2 +- mongoose.h | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/c-api/net.h/struct_mg_mgr.md b/docs/c-api/net.h/struct_mg_mgr.md index 8e43a1e6..d33727c3 100644 --- a/docs/c-api/net.h/struct_mg_mgr.md +++ b/docs/c-api/net.h/struct_mg_mgr.md @@ -14,7 +14,7 @@ signature: | void *user_data; /* User data */ int num_ifaces; struct mg_iface **ifaces; /* network interfaces */ - const char *nameserver; /* DNS server to use */ + const char *nameserver; /* DNS server to use */ }; --- diff --git a/mongoose.h b/mongoose.h index 23ef0f16..acf01c79 100644 --- a/mongoose.h +++ b/mongoose.h @@ -3301,7 +3301,7 @@ struct mg_mgr { void *user_data; /* User data */ int num_ifaces; struct mg_iface **ifaces; /* network interfaces */ - const char *nameserver; /* DNS server to use */ + const char *nameserver; /* DNS server to use */ }; /* From 5a0b6fc35abd21031ad749a1180a6f63cd70b52a Mon Sep 17 00:00:00 2001 From: Deomid Ryabkov Date: Mon, 3 Jul 2017 11:54:17 +0100 Subject: [PATCH 098/137] Use SSL_CTX_{get,set}_app_data to store context h/t @hendrikw01 Fixes https://github.com/cesanta/mongoose/issues/826 Closes https://github.com/cesanta/mongoose/pull/831 PUBLISHED_FROM=d5e1285bee9bcbb85d581ee62972a2fde7d9c0db --- mongoose.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/mongoose.c b/mongoose.c index ec4303fb..7e4cbeb1 100644 --- a/mongoose.c +++ b/mongoose.c @@ -4407,7 +4407,7 @@ static unsigned int mg_ssl_if_ossl_psk_cb(SSL *ssl, const char *hint, unsigned char *psk, unsigned int max_psk_len) { struct mg_ssl_if_ctx *ctx = - (struct mg_ssl_if_ctx *) ssl->ctx->msg_callback_arg; + (struct mg_ssl_if_ctx *) SSL_CTX_get_app_data(SSL_get_SSL_CTX(ssl)); size_t key_len = ctx->psk.len - ctx->identity_len - 1; DBG(("hint: '%s'", (hint ? hint : ""))); if (ctx->identity_len + 1 > max_identity_len) { @@ -4456,8 +4456,7 @@ static enum mg_ssl_if_result mg_ssl_if_ossl_set_psk(struct mg_ssl_if_ctx *ctx, mbuf_append(&ctx->psk, identity, ctx->identity_len + 1); mbuf_append(&ctx->psk, key, key_len); SSL_CTX_set_psk_client_callback(ctx->ssl_ctx, mg_ssl_if_ossl_psk_cb); - /* Hack: there is no field for us to keep this, so we use msg_callback_arg */ - ctx->ssl_ctx->msg_callback_arg = ctx; + SSL_CTX_set_app_data(ctx->ssl_ctx, ctx); return MG_SSL_OK; } #else From cfd28a4f7a7e5017feadddf9c66afeeaf7698322 Mon Sep 17 00:00:00 2001 From: Deomid Ryabkov Date: Mon, 3 Jul 2017 17:55:24 +0300 Subject: [PATCH 099/137] Add mg_strchr Write unit tests for some mg_str functions. PUBLISHED_FROM=1fc7e1d5d5ef259d4023f295aec8651caa3e7e86 --- mongoose.c | 9 +++++++++ mongoose.h | 5 +++++ 2 files changed, 14 insertions(+) diff --git a/mongoose.c b/mongoose.c index 7e4cbeb1..986e424f 100644 --- a/mongoose.c +++ b/mongoose.c @@ -1446,6 +1446,15 @@ struct mg_str mg_strdup_nul(const struct mg_str s) { return mg_strdup_common(s, 1 /* NUL-terminate */); } +const char *mg_strchr(const struct mg_str s, int c) WEAK; +const char *mg_strchr(const struct mg_str s, int c) { + size_t i; + for (i = 0; i < s.len; i++) { + if (s.p[i] == c) return &s.p[i]; + } + return NULL; +} + int mg_strcmp(const struct mg_str str1, const struct mg_str str2) WEAK; int mg_strcmp(const struct mg_str str1, const struct mg_str str2) { size_t i = 0; diff --git a/mongoose.h b/mongoose.h index acf01c79..4292276d 100644 --- a/mongoose.h +++ b/mongoose.h @@ -1801,6 +1801,11 @@ struct mg_str mg_strdup(const struct mg_str s); */ struct mg_str mg_strdup_nul(const struct mg_str s); +/* + * Locates character in a string. + */ +const char *mg_strchr(const struct mg_str s, int c); + int mg_strcmp(const struct mg_str str1, const struct mg_str str2); int mg_strncmp(const struct mg_str str1, const struct mg_str str2, size_t n); From 4d0cc95ff47299908613a538bb09c99174c6f51b Mon Sep 17 00:00:00 2001 From: Sergey Lyubka Date: Tue, 4 Jul 2017 19:49:52 +0100 Subject: [PATCH 100/137] Add JS net api test PUBLISHED_FROM=f2821b104f8f2fc196ce4064b7c9f35ea152368d --- mongoose.c | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/mongoose.c b/mongoose.c index 986e424f..b9f7b23b 100644 --- a/mongoose.c +++ b/mongoose.c @@ -14636,17 +14636,20 @@ static int mg_lwip_udp_send(struct mg_connection *nc, const void *data, } struct udp_pcb *upcb = cs->pcb.udp; struct pbuf *p = pbuf_alloc(PBUF_TRANSPORT, len, PBUF_RAM); - ip_addr_t *ip = (ip_addr_t *) &nc->sa.sin.sin_addr.s_addr; +#if defined(LWIP_IPV4) && LWIP_IPV4 && defined(LWIP_IPV6) && LWIP_IPV6 + ip_addr_t ip = { .u_addr.ip4.addr = nc->sa.sin.sin_addr.s_addr, .type = 0 }; +#else + 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; } memcpy(p->payload, data, len); - struct udp_sendto_ctx ctx = {.upcb = upcb, .p = p, .ip = ip, .port = port}; + struct udp_sendto_ctx ctx = {.upcb = upcb, .p = p, .ip = &ip, .port = port}; tcpip_callback(udp_sendto_tcpip, &ctx); cs->err = ctx.ret; - DBG(("%p udp_sendto = %d", nc, cs->err)); pbuf_free(p); return (cs->err == ERR_OK ? len : -1); } From 41558bbf643dc9efb9ff241894fc84cea2e5e781 Mon Sep 17 00:00:00 2001 From: Dmitry Frank Date: Tue, 4 Jul 2017 22:31:26 +0300 Subject: [PATCH 101/137] Fix formatting PUBLISHED_FROM=4d4d49136e13ba8035d452a4f64fcaf48f15bdb3 --- mongoose.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/mongoose.c b/mongoose.c index b9f7b23b..78024e36 100644 --- a/mongoose.c +++ b/mongoose.c @@ -14637,9 +14637,9 @@ static int mg_lwip_udp_send(struct mg_connection *nc, const void *data, 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 - ip_addr_t ip = { .u_addr.ip4.addr = nc->sa.sin.sin_addr.s_addr, .type = 0 }; + ip_addr_t ip = {.u_addr.ip4.addr = nc->sa.sin.sin_addr.s_addr, .type = 0}; #else - ip_addr_t ip = { .addr = nc->sa.sin.sin_addr.s_addr }; + 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) { From 2a2bc33a8945c7a14436062247a52ca7d0c91fe5 Mon Sep 17 00:00:00 2001 From: Deomid Ryabkov Date: Wed, 5 Jul 2017 17:14:34 +0100 Subject: [PATCH 102/137] Add mg_strstr PUBLISHED_FROM=4306e870e2cab854febb6becc198ca2247e2e002 --- mongoose.c | 14 ++++++++++++++ mongoose.h | 2 ++ 2 files changed, 16 insertions(+) diff --git a/mongoose.c b/mongoose.c index 78024e36..4a8aea4f 100644 --- a/mongoose.c +++ b/mongoose.c @@ -1481,6 +1481,20 @@ int mg_strncmp(const struct mg_str str1, const struct mg_str str2, size_t n) { } return mg_strcmp(s1, s2); } + +const char *mg_strstr(const struct mg_str haystack, + const struct mg_str needle) WEAK; +const char *mg_strstr(const struct mg_str haystack, + const struct mg_str needle) { + size_t i; + if (needle.len > haystack.len) return NULL; + for (i = 0; i <= haystack.len - needle.len; i++) { + if (memcmp(haystack.p + i, needle.p, needle.len) == 0) { + return haystack.p + i; + } + } + return NULL; +} #ifdef MG_MODULE_LINES #line 1 "common/str_util.c" #endif diff --git a/mongoose.h b/mongoose.h index 4292276d..514b904e 100644 --- a/mongoose.h +++ b/mongoose.h @@ -1809,6 +1809,8 @@ const char *mg_strchr(const struct mg_str s, int c); int mg_strcmp(const struct mg_str str1, const struct mg_str str2); 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); + #ifdef __cplusplus } #endif /* __cplusplus */ From 4c37e4927480fdf8f0ff024a98314387711d5203 Mon Sep 17 00:00:00 2001 From: Deomid Ryabkov Date: Wed, 5 Jul 2017 17:53:29 +0100 Subject: [PATCH 103/137] Disable insecure and deprectaed SSL protocols Also allow disabling conmpression and forcing server cipher list. PUBLISHED_FROM=5539deec9c2382ba34597872dd7f3a5abc0cc311 --- mongoose.c | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/mongoose.c b/mongoose.c index 4a8aea4f..e6edab39 100644 --- a/mongoose.c +++ b/mongoose.c @@ -4198,6 +4198,21 @@ enum mg_ssl_if_result mg_ssl_if_conn_init( return MG_SSL_ERROR; } +#ifndef KR_VERSION + /* Disable deprecated protocols. */ + SSL_CTX_set_options(ctx->ssl_ctx, SSL_OP_NO_SSLv2); + SSL_CTX_set_options(ctx->ssl_ctx, SSL_OP_NO_SSLv3); + SSL_CTX_set_options(ctx->ssl_ctx, SSL_OP_NO_TLSv1); +#ifdef MG_SSL_OPENSSL_NO_COMPRESSION + SSL_CTX_set_options(ctx->ssl_ctx, SSL_OP_NO_COMPRESSION); +#endif +#ifdef MG_SSL_OPENSSL_CIPHER_SERVER_PREFERENCE + SSL_CTX_set_options(ctx->ssl_ctx, SSL_OP_CIPHER_SERVER_PREFERENCE); +#endif +#else +/* Krypton only supports TLSv1.2 anyway. */ +#endif + if (params->cert != NULL && mg_use_cert(ctx->ssl_ctx, params->cert, params->key, err_msg) != MG_SSL_OK) { From 0bb14abbddf13634eac91257af437ff6ce2cd280 Mon Sep 17 00:00:00 2001 From: Sergey Lyubka Date: Fri, 14 Jul 2017 13:47:42 +0300 Subject: [PATCH 104/137] Nitpick for MQTT example PUBLISHED_FROM=a0dd26c00b41363f1cc58c28f530fbdf272ed146 --- examples/mqtt_broker/Makefile | 2 +- examples/mqtt_broker/mqtt_broker.c | 21 +++++++++++++++------ examples/mqtt_client/mqtt_client.c | 5 +---- 3 files changed, 17 insertions(+), 11 deletions(-) diff --git a/examples/mqtt_broker/Makefile b/examples/mqtt_broker/Makefile index f0c17a0e..86f0b09b 100644 --- a/examples/mqtt_broker/Makefile +++ b/examples/mqtt_broker/Makefile @@ -1,4 +1,4 @@ PROG = mqtt_broker MODULE_CFLAGS = -DMG_ENABLE_MQTT_BROKER -DMG_ENABLE_HTTP=0 -SSL_LIB=openssl +#SSL_LIB=openssl include ../examples.mk diff --git a/examples/mqtt_broker/mqtt_broker.c b/examples/mqtt_broker/mqtt_broker.c index 4c02f9b6..4cc5185b 100644 --- a/examples/mqtt_broker/mqtt_broker.c +++ b/examples/mqtt_broker/mqtt_broker.c @@ -17,22 +17,31 @@ #include "../../mongoose.h" +static const char *s_listening_address = "0.0.0.0:1883"; + +static void ev_handler(struct mg_connection *c, int ev, void *ev_data) { + if (ev != MG_EV_POLL) printf("USER HANDLER GOT EVENT %d\n", ev); + /* Do your custom event processing here */ + mg_mqtt_broker(c, ev, ev_data); +} + int main(void) { struct mg_mgr mgr; - const char *address = "0.0.0.0:1883"; - struct mg_connection *nc; + struct mg_connection *c; struct mg_mqtt_broker brk; mg_mgr_init(&mgr, NULL); mg_mqtt_broker_init(&brk, NULL); - if ((nc = mg_bind(&mgr, address, mg_mqtt_broker)) == NULL) { - fprintf(stderr, "mg_bind(%s) failed\n", address); + if ((c = mg_bind(&mgr, s_listening_address, ev_handler)) == NULL) { + fprintf(stderr, "mg_bind(%s) failed\n", s_listening_address); exit(EXIT_FAILURE); } - nc->user_data = &brk; + mg_mqtt_broker_init(&brk, NULL); + c->user_data = &brk; + mg_set_protocol_mqtt(c); - printf("MQTT broker started on %s\n", address); + printf("MQTT broker started on %s\n", s_listening_address); /* * TODO: Add a HTTP status page that shows current sessions diff --git a/examples/mqtt_client/mqtt_client.c b/examples/mqtt_client/mqtt_client.c index da0282bb..20090efe 100644 --- a/examples/mqtt_client/mqtt_client.c +++ b/examples/mqtt_client/mqtt_client.c @@ -27,10 +27,7 @@ static void ev_handler(struct mg_connection *nc, int ev, void *p) { struct mg_mqtt_message *msg = (struct mg_mqtt_message *) p; (void) nc; -#if 0 - if (ev != MG_EV_POLL) - printf("USER HANDLER GOT %d\n", ev); -#endif + if (ev != MG_EV_POLL) printf("USER HANDLER GOT EVENT %d\n", ev); switch (ev) { case MG_EV_CONNECT: { From a0ece4e96990b9f096c3bc80083b6a1ed65989ea Mon Sep 17 00:00:00 2001 From: Sergey Lyubka Date: Mon, 17 Jul 2017 13:10:24 +0100 Subject: [PATCH 105/137] Fix links for MWS readme PUBLISHED_FROM=c6c31d47eedcfe09b675e3f56d967da5b22809f6 --- README.md | 22 +++++++++------------- 1 file changed, 9 insertions(+), 13 deletions(-) diff --git a/README.md b/README.md index 0967275f..acc01972 100644 --- a/README.md +++ b/README.md @@ -8,7 +8,7 @@ used by vast number of open source and commercial products - it even runs on the International Space station! Mongoose makes embedded network programming fast, robust, and easy. -- [Download Mongoose Source Code here](https://www.cesanta.com) +- [Download Mongoose Source Code here](https://www.cesanta.com/download.html) Looking for a complete IoT firmware solution? @@ -17,9 +17,9 @@ Check out [Mongoose OS](https://mongoose-os.com) - open source embedded operatin # Support - [Study mongoose example code](https://github.com/cesanta/mongoose/tree/master/examples) - [Read User Guide and API reference](https://docs.cesanta.com/mongoose) -- [Support Forum - ask your technical questions here] (http://forum.cesanta.com/index.php?p=/categories/mongoose) -- [Commercial licensing and support available] (https://www.cesanta.com/services-support) -- [Check our latest releases] (https://github.com/cesanta/mongoose/releases) +- [Support Forum - ask your technical questions here](https://forum.mongoose-os.com/categories/mongoose) +- [Commercial licensing and support available](https://www.cesanta.com/licensing.html) +- [Check our latest releases](https://github.com/cesanta/mongoose/releases) # Features @@ -47,7 +47,7 @@ Check out [Mongoose OS](https://mongoose-os.com) - open source embedded operatin Mongoose is released under Commercial and [GNU GPL v.2](http://www.gnu.org/licenses/old-licenses/gpl-2.0.html) open source licenses. -Commercial Projects: [Contact us for commercial license.] (https://www.cesanta.com/contact) +Commercial Projects: [Contact us for commercial license.](https://www.cesanta.com/contact.html) # Dashboard Example @@ -55,18 +55,14 @@ Mongoose is often used to implement device dashboards and real-time data exchange over Websocket. Here is a dashboard example that illustrates the functionality: -![](http://www.cesanta.com/hubfs/www.cesanta.com/diagrams/dash_mongoose_diagram.png) +![](http://www.cesanta.com/images/dashboard.png) -[Developing a new product? Contact us today to discuss how Mongoose can help. -](https://www.cesanta.com/contact) +[Developing a new product? Contact us today to discuss how Mongoose can help.](https://www.cesanta.com/contact.html) # Contributions -To submit contributions, sign -[Cesanta CLA](https://docs.cesanta.com/contributors_la.shtml) +To submit contributions, sign [Cesanta CLA](https://cesanta.com/cla.html) and send GitHub pull request. You retain the copyright on your contributions. # Looking for a pre-compiled Mongoose web server Windows or Mac binary? -- [Download pre-compiled Mongoose web server binary.](https://www.cesanta.com/products/binary) - -[![Analytics](https://ga-beacon.appspot.com/UA-42732794-5/project-page)](https://github.com/cesanta/mongoose) +- [Download pre-compiled Mongoose web server binary.](https://www.cesanta.com/binary.html) From f1ae1837521b6721ef2b8edfaf7841eb8f5d0577 Mon Sep 17 00:00:00 2001 From: Sergey Lyubka Date: Mon, 17 Jul 2017 15:11:55 +0100 Subject: [PATCH 106/137] Fix https://github.com/cesanta/mongoose/pull/829 PUBLISHED_FROM=6e56c250fe62010e25b6ed489c0d608163ba629c --- docs/http/cgi.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/http/cgi.md b/docs/http/cgi.md index c667fec4..86b0a4f3 100644 --- a/docs/http/cgi.md +++ b/docs/http/cgi.md @@ -16,7 +16,7 @@ CGI file must be executable. Mongoose honours the shebang line - see http://en.wikipedia.org/wiki/Shebang_(Unix). For example, if both PHP and Perl CGIs are used, then -``#!/path/to/php-cgi.exe` and ``#!/path/to/perl.exe` must be the first lines +`#!/path/to/php-cgi.exe` and `#!/path/to/perl.exe` must be the first lines of the respective CGI scripts. It is possible to hardcode the path to the CGI interpreter for all From 944a6b761cf7e552a6f3add5635567035453068c Mon Sep 17 00:00:00 2001 From: Sergey Lyubka Date: Mon, 17 Jul 2017 15:14:38 +0100 Subject: [PATCH 107/137] Fix https://github.com/cesanta/mongoose/pull/824 PUBLISHED_FROM=ed2c39b9e00a7374af7fed5af0c9acd6c330334a --- docs/http/ssl.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/http/ssl.md b/docs/http/ssl.md index 9908f190..c317e57a 100644 --- a/docs/http/ssl.md +++ b/docs/http/ssl.md @@ -30,4 +30,4 @@ int main(void) { } ``` -For the full example, please see the [Simplest HTTPS server example](https://github.com/cesanta/dev/tree/master/mongoose/examples/simplest_web_server_ssl). +For the full example, please see the [Simplest HTTPS server example](https://github.com/cesanta/mongoose/tree/master/examples/simplest_web_server_ssl). From fea648496cf134a1aedddd81ee35bbc05e39853a Mon Sep 17 00:00:00 2001 From: Sergey Lyubka Date: Thu, 20 Jul 2017 09:59:18 +0200 Subject: [PATCH 108/137] Fix https://github.com/cesanta/mongoose-os/issues/318 PUBLISHED_FROM=2fc7b59b2edd0f473acd22067439471778acef8e --- mongoose.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/mongoose.c b/mongoose.c index e6edab39..3dfe789a 100644 --- a/mongoose.c +++ b/mongoose.c @@ -7919,6 +7919,9 @@ struct mg_connection *mg_connect_http_base( goto out; } + /* If query is present, do not strip it. Pass to the caller. */ + if (query.len > 0) path->len += query.len + 1; + if (scheme.len == 0 || mg_vcmp(&scheme, scheme1) == 0 || (scheme2 != NULL && mg_vcmp(&scheme, scheme2) == 0)) { use_ssl = 0; From 0fba87c755a4dd23bfa5e538480db9d0e955793b Mon Sep 17 00:00:00 2001 From: Deomid Ryabkov Date: Fri, 21 Jul 2017 14:02:06 +0200 Subject: [PATCH 109/137] Make mg_url_encode public Change the API to heap-allocate the string and get rid of a bunch of fat stack buffers. PUBLISHED_FROM=c793dc64a9a044a9769d92ea16859f5d704a2181 --- docs/c-api/util.h/intro.md | 1 + docs/c-api/util.h/mg_url_encode.md | 13 +++++++ mongoose.c | 59 ++++++++++++++++-------------- mongoose.h | 8 ++++ 4 files changed, 53 insertions(+), 28 deletions(-) create mode 100644 docs/c-api/util.h/mg_url_encode.md diff --git a/docs/c-api/util.h/intro.md b/docs/c-api/util.h/intro.md index d04619a1..73c4f792 100644 --- a/docs/c-api/util.h/intro.md +++ b/docs/c-api/util.h/intro.md @@ -22,6 +22,7 @@ items: - { name: mg_sock_to_str.md } - { name: mg_start_thread.md } - { name: mg_stat.md } + - { name: mg_url_encode.md } --- diff --git a/docs/c-api/util.h/mg_url_encode.md b/docs/c-api/util.h/mg_url_encode.md new file mode 100644 index 00000000..105ce947 --- /dev/null +++ b/docs/c-api/util.h/mg_url_encode.md @@ -0,0 +1,13 @@ +--- +title: "mg_url_encode()" +decl_name: "mg_url_encode" +symbol_kind: "func" +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. + diff --git a/mongoose.c b/mongoose.c index 3dfe789a..f3210df8 100644 --- a/mongoose.c +++ b/mongoose.c @@ -7033,28 +7033,6 @@ static int mg_http_is_authorized(struct http_message *hm, #endif #if MG_ENABLE_DIRECTORY_LISTING -static size_t mg_url_encode(const char *src, size_t s_len, char *dst, - size_t dst_len) { - static const char *dont_escape = "._-$,;~()/"; - static const char *hex = "0123456789abcdef"; - size_t i = 0, j = 0; - - for (i = j = 0; dst_len > 0 && i < s_len && j + 2 < dst_len - 1; i++, j++) { - if (isalnum(*(const unsigned char *) (src + i)) || - strchr(dont_escape, *(const unsigned char *) (src + i)) != NULL) { - dst[j] = src[i]; - } else if (j + 3 < dst_len) { - dst[j] = '%'; - dst[j + 1] = hex[(*(const unsigned char *) (src + i)) >> 4]; - dst[j + 2] = hex[(*(const unsigned char *) (src + i)) & 0xf]; - j += 2; - } - } - - dst[j] = '\0'; - return j; -} - static void mg_escape(const char *src, char *dst, size_t dst_len) { size_t n = 0; while (*src != '\0' && n + 5 < dst_len) { @@ -7070,10 +7048,11 @@ static void mg_escape(const char *src, char *dst, size_t dst_len) { static void mg_print_dir_entry(struct mg_connection *nc, const char *file_name, cs_stat_t *stp) { - char size[64], mod[64], href[MG_MAX_PATH * 3], path[MG_MAX_PATH]; + char size[64], mod[64], path[MG_MAX_PATH]; int64_t fsize = stp->st_size; int is_dir = S_ISDIR(stp->st_mode); const char *slash = is_dir ? "/" : ""; + struct mg_str href; if (is_dir) { snprintf(size, sizeof(size), "%s", "[DIRECTORY]"); @@ -7094,12 +7073,13 @@ static void mg_print_dir_entry(struct mg_connection *nc, const char *file_name, } strftime(mod, sizeof(mod), "%d-%b-%Y %H:%M", localtime(&stp->st_mtime)); mg_escape(file_name, path, sizeof(path)); - mg_url_encode(file_name, strlen(file_name), href, sizeof(href)); + href = mg_url_encode(mg_mk_str(file_name)); mg_printf_http_chunk(nc, "%s%s" "%s%s\n", - href, slash, path, slash, mod, is_dir ? -1 : fsize, + href.p, slash, path, slash, mod, is_dir ? -1 : fsize, size); + free((void *) href.p); } static void mg_scan_directory(struct mg_connection *nc, const char *dir, @@ -8865,10 +8845,10 @@ static int mg_mkdir(const char *path, uint32_t mode) { static void mg_print_props(struct mg_connection *nc, const char *name, cs_stat_t *stp) { - char mtime[64], buf[MG_MAX_PATH * 3]; + char mtime[64]; time_t t = stp->st_mtime; /* store in local variable for NDK compile */ + struct mg_str name_esc = mg_url_encode(mg_mk_str(name)); mg_gmt_time_string(mtime, sizeof(mtime), &t); - mg_url_encode(name, strlen(name), buf, sizeof(buf)); mg_printf(nc, "" "%s" @@ -8882,8 +8862,9 @@ static void mg_print_props(struct mg_connection *nc, const char *name, "HTTP/1.1 200 OK" "" "\n", - buf, S_ISDIR(stp->st_mode) ? "" : "", + name_esc.p, S_ISDIR(stp->st_mode) ? "" : "", (int64_t) stp->st_size, mtime); + free((void *) name_esc.p); } MG_INTERNAL void mg_handle_propfind(struct mg_connection *nc, const char *path, @@ -9823,6 +9804,28 @@ void mg_basic_auth_header(const struct mg_str user, const struct mg_str pass, cs_base64_finish(&ctx); 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"; + 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) { + mbuf_append(&mb, &c, 1); + } else { + mbuf_append(&mb, "%", 1); + mbuf_append(&mb, &hex[c >> 4], 1); + mbuf_append(&mb, &hex[c & 15], 1); + } + } + mbuf_append(&mb, "", 1); + mbuf_trim(&mb); + return mg_mk_str_n(mb.buf, mb.len - 1); +} #ifdef MG_MODULE_LINES #line 1 "mongoose/src/mqtt.c" #endif diff --git a/mongoose.h b/mongoose.h index 514b904e..66fbe857 100644 --- a/mongoose.h +++ b/mongoose.h @@ -4077,6 +4077,14 @@ void mg_mbuf_append_base64(struct mbuf *mbuf, const void *data, size_t len); void mg_basic_auth_header(const struct mg_str user, const struct mg_str pass, struct mbuf *buf); +/* + * 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. + */ +struct mg_str mg_url_encode(const struct mg_str src); + #ifdef __cplusplus } #endif /* __cplusplus */ From 8bbb44f90c0d2c2cb67d342ccc029bcc41cc6adf Mon Sep 17 00:00:00 2001 From: Sergey Lyubka Date: Fri, 21 Jul 2017 14:27:47 +0100 Subject: [PATCH 110/137] Always send MG_EV_HTTP_CHUNK PUBLISHED_FROM=33957356e1510b73b37768496c74a6bf12630215 --- mongoose.c | 29 ++++++++++++++++++++++++----- 1 file changed, 24 insertions(+), 5 deletions(-) diff --git a/mongoose.c b/mongoose.c index f3210df8..472a114d 100644 --- a/mongoose.c +++ b/mongoose.c @@ -5330,6 +5330,7 @@ struct mg_http_proto_data { struct mg_http_endpoint *endpoints; mg_event_handler_t endpoint_handler; struct mg_reverse_proxy_data reverse_proxy_data; + size_t rcvd; /* How many bytes we have received. */ }; static void mg_http_conn_destructor(void *proto_data); @@ -5839,6 +5840,16 @@ static void mg_http_multipart_begin(struct mg_connection *nc, static void mg_http_call_endpoint_handler(struct mg_connection *nc, int ev, struct http_message *hm); +static void deliver_chunk(struct mg_connection *c, struct http_message *hm, + int req_len) { + /* Incomplete message received. Send MG_EV_HTTP_CHUNK event */ + hm->body.len = c->recv_mbuf.len - req_len; + c->flags &= ~MG_F_DELETE_CHUNK; + mg_call(c, c->handler, c->user_data, MG_EV_HTTP_CHUNK, hm); + /* Delete processed data if user set MG_F_DELETE_CHUNK flag */ + if (c->flags & MG_F_DELETE_CHUNK) c->recv_mbuf.len = req_len; +} + /* * lx106 compiler has a bug (TODO(mkm) report and insert tracking bug here) * If a big structure is declared in a big function, lx106 gcc will make it @@ -5861,8 +5872,7 @@ static void mg_http_handler2(struct mg_connection *nc, int ev, #else /* !__XTENSA__ */ void mg_http_handler(struct mg_connection *nc, int ev, void *ev_data MG_UD_ARG(void *user_data)) { - struct http_message shm; - struct http_message *hm = &shm; + struct http_message shm, *hm = &shm; #endif /* __XTENSA__ */ struct mg_http_proto_data *pd = mg_http_get_proto_data(nc); struct mbuf *io = &nc->recv_mbuf; @@ -5898,7 +5908,8 @@ void mg_http_handler(struct mg_connection *nc, int ev, nc->user_data, MG_EV_HTTP_MULTIPART_REQUEST_END, &mp); } else #endif - if (io->len > 0 && mg_parse_http(io->buf, io->len, hm, is_req) > 0) { + if (io->len > 0 && + (req_len = mg_parse_http(io->buf, io->len, hm, is_req)) > 0) { /* * For HTTP messages without Content-Length, always send HTTP message * before MG_EV_CLOSE message. @@ -5906,8 +5917,10 @@ void mg_http_handler(struct mg_connection *nc, int ev, int ev2 = is_req ? MG_EV_HTTP_REQUEST : MG_EV_HTTP_REPLY; hm->message.len = io->len; hm->body.len = io->buf + io->len - hm->body.p; + deliver_chunk(nc, hm, req_len); mg_http_call_endpoint_handler(nc, ev2, hm); } + pd->rcvd = 0; } #if MG_ENABLE_FILESYSTEM @@ -5920,6 +5933,7 @@ void mg_http_handler(struct mg_connection *nc, int ev, if (ev == MG_EV_RECV) { struct mg_str *s; + pd->rcvd += *(int *) ev_data; #if MG_ENABLE_HTTP_STREAMING_MULTIPART if (pd->mp_stream.boundary != NULL) { @@ -5999,19 +6013,24 @@ void mg_http_handler(struct mg_connection *nc, int ev, } } #endif /* MG_ENABLE_HTTP_WEBSOCKET */ - else if (hm->message.len <= io->len) { + else if (hm->message.len > pd->rcvd) { + /* Not yet received all HTTP body, deliver MG_EV_HTTP_CHUNK */ + deliver_chunk(nc, hm, req_len); + } else { + /* We did receive all HTTP body. */ int trigger_ev = nc->listener ? MG_EV_HTTP_REQUEST : MG_EV_HTTP_REPLY; char addr[32]; mg_sock_addr_to_str(&nc->sa, addr, sizeof(addr), MG_SOCK_STRINGIFY_IP | MG_SOCK_STRINGIFY_PORT); DBG(("%p %s %.*s %.*s", nc, addr, (int) hm->method.len, hm->method.p, (int) hm->uri.len, hm->uri.p)); + deliver_chunk(nc, hm, req_len); /* 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; } } - (void) pd; } static size_t mg_get_line_len(const char *buf, size_t buf_len) { From 448b44094a04264162197086e765defee8afae1e Mon Sep 17 00:00:00 2001 From: Deomid Ryabkov Date: Thu, 27 Jul 2017 13:09:33 +0200 Subject: [PATCH 111/137] Add automated check for extern "C" Fix headers that didn't have it PUBLISHED_FROM=ce8140783d4b661f16278a4a5adc957b21965473 --- mongoose.c | 16 +++++++++++++++ mongoose.h | 58 ++++++++++++++++++++++++++++-------------------------- 2 files changed, 46 insertions(+), 28 deletions(-) diff --git a/mongoose.c b/mongoose.c index 472a114d..75ee3ac7 100644 --- a/mongoose.c +++ b/mongoose.c @@ -165,6 +165,10 @@ MG_INTERNAL int mg_sntp_parse_reply(const char *buf, int len, #ifndef CS_COMMON_MG_MEM_H_ #define CS_COMMON_MG_MEM_H_ +#ifdef __cplusplus +extern "C" { +#endif + #ifndef MG_MALLOC #define MG_MALLOC malloc #endif @@ -181,6 +185,10 @@ MG_INTERNAL int mg_sntp_parse_reply(const char *buf, int len, #define MG_FREE free #endif +#ifdef __cplusplus +} +#endif + #endif /* CS_COMMON_MG_MEM_H_ */ #ifdef MG_MODULE_LINES #line 1 "common/cs_dbg.h" @@ -782,6 +790,10 @@ double cs_time(void) { #ifndef CS_COMMON_CS_ENDIAN_H_ #define CS_COMMON_CS_ENDIAN_H_ +#ifdef __cplusplus +extern "C" { +#endif + /* * clang with std=-c99 uses __LITTLE_ENDIAN, by default * while for ex, RTOS gcc - LITTLE_ENDIAN, by default @@ -797,6 +809,10 @@ double cs_time(void) { #endif /* BIG_ENDIAN */ #endif /* BYTE_ORDER */ +#ifdef __cplusplus +} +#endif + #endif /* CS_COMMON_CS_ENDIAN_H_ */ #ifdef MG_MODULE_LINES #line 1 "common/cs_md5.c" diff --git a/mongoose.h b/mongoose.h index 66fbe857..819dd80b 100644 --- a/mongoose.h +++ b/mongoose.h @@ -560,9 +560,9 @@ typedef struct stat cs_stat_t; #ifndef MG_NET_IF #include #if LWIP_SOCKET /* RTOS SDK has LWIP sockets */ -# define MG_NET_IF MG_NET_IF_SOCKET +#define MG_NET_IF MG_NET_IF_SOCKET #else -# define MG_NET_IF MG_NET_IF_LWIP_LOW_LEVEL +#define MG_NET_IF MG_NET_IF_LWIP_LOW_LEVEL #endif #endif @@ -603,7 +603,7 @@ typedef struct stat cs_stat_t; #include #include -#undef timeval +#undef timeval typedef int sock_t; #define INVALID_SOCKET (-1) @@ -840,7 +840,8 @@ int _stat(const char *pathname, struct stat *st); #define CS_ENABLE_STDIO 1 #endif -#if (defined(CC3200_FS_SPIFFS) || defined(CC3200_FS_SLFS)) && !defined(MG_ENABLE_FILESYSTEM) +#if (defined(CC3200_FS_SPIFFS) || defined(CC3200_FS_SLFS)) && \ + !defined(MG_ENABLE_FILESYSTEM) #define MG_ENABLE_FILESYSTEM 1 #endif @@ -884,15 +885,15 @@ typedef struct stat cs_stat_t; #define __cdecl #ifndef MG_NET_IF -# include -# if LWIP_SOCKET -# define MG_NET_IF MG_NET_IF_SOCKET -# else -# define MG_NET_IF MG_NET_IF_LWIP_LOW_LEVEL -# endif -# define MG_LWIP 1 +#include +#if LWIP_SOCKET +#define MG_NET_IF MG_NET_IF_SOCKET +#else +#define MG_NET_IF MG_NET_IF_LWIP_LOW_LEVEL +#endif +#define MG_LWIP 1 #elif MG_NET_IF == MG_NET_IF_SIMPLELINK -# include "common/platforms/simplelink/cs_simplelink.h" +/* Amalgamated: #include "common/platforms/simplelink/cs_simplelink.h" */ #endif #ifndef CS_ENABLE_STDIO @@ -1014,16 +1015,16 @@ in_addr_t inet_addr(const char *cp); #define to64(x) strtoll(x, NULL, 10) -#define MG_NET_IF MG_NET_IF_LWIP_LOW_LEVEL -#define MG_LWIP 1 -#define MG_ENABLE_IPV6 1 +#define MG_NET_IF MG_NET_IF_LWIP_LOW_LEVEL +#define MG_LWIP 1 +#define MG_ENABLE_IPV6 1 /* * For ARM C Compiler, make lwip to export `struct timeval`; for other * compilers, suppress it. */ #if !defined(__ARMCC_VERSION) -# define LWIP_TIMEVAL_PRIVATE 0 +#define LWIP_TIMEVAL_PRIVATE 0 #else struct timeval; int gettimeofday(struct timeval *tp, void *tzp); @@ -1060,12 +1061,12 @@ int gettimeofday(struct timeval *tp, void *tzp); #define to64(x) strtoll(x, NULL, 10) -#define MG_NET_IF MG_NET_IF_LWIP_LOW_LEVEL -#define MG_LWIP 1 -#define MG_ENABLE_IPV6 1 +#define MG_NET_IF MG_NET_IF_LWIP_LOW_LEVEL +#define MG_LWIP 1 +#define MG_ENABLE_IPV6 1 #if !defined(ENOSPC) -# define ENOSPC 28 /* No space left on device */ +#define ENOSPC 28 /* No space left on device */ #endif /* @@ -1073,7 +1074,7 @@ int gettimeofday(struct timeval *tp, void *tzp); * compilers, suppress it. */ #if !defined(__ARMCC_VERSION) -# define LWIP_TIMEVAL_PRIVATE 0 +#define LWIP_TIMEVAL_PRIVATE 0 #endif #define INT64_FMT PRId64 @@ -1377,18 +1378,18 @@ typedef struct _stati64 { #endif #ifndef _UINTPTR_T_DEFINED -typedef unsigned int* uintptr_t; +typedef unsigned int *uintptr_t; #endif #define _S_IFREG 2 #define _S_IFDIR 4 #ifndef S_ISDIR -#define S_ISDIR(x) (((x) & _S_IFDIR) != 0) +#define S_ISDIR(x) (((x) &_S_IFDIR) != 0) #endif #ifndef S_ISREG -#define S_ISREG(x) (((x) & _S_IFREG) != 0) +#define S_ISREG(x) (((x) &_S_IFREG) != 0) #endif int open(const char *filename, int oflag, int pmode); @@ -1425,7 +1426,8 @@ typedef struct stat cs_stat_t; #define MG_NET_IF MG_NET_IF_LWIP_LOW_LEVEL /* - * LPCXpress comes with 3 C library implementations: Newlib, NewlibNano and Redlib. + * LPCXpress comes with 3 C library implementations: Newlib, NewlibNano and + *Redlib. * See https://community.nxp.com/message/630860 for more details. * * Redlib is the default and lacks certain things, so we provide them. @@ -1521,7 +1523,7 @@ typedef TCP_SOCKET sock_t; #define CS_ENABLE_STDIO 1 #endif -char* inet_ntoa(struct in_addr in); +char *inet_ntoa(struct in_addr in); #endif /* CS_PLATFORM == CS_P_PIC32 */ @@ -1759,7 +1761,7 @@ double cs_time(void); #ifdef __cplusplus extern "C" { -#endif /* __cplusplus */ +#endif /* Describes chunk of memory */ struct mg_str { @@ -1813,7 +1815,7 @@ const char *mg_strstr(const struct mg_str haystack, const struct mg_str needle); #ifdef __cplusplus } -#endif /* __cplusplus */ +#endif #endif /* CS_COMMON_MG_STR_H_ */ #ifdef MG_MODULE_LINES From 66b23b11b0f6e7ed060300ad091f19ba6d0ab4d6 Mon Sep 17 00:00:00 2001 From: ruslanvaliullin Date: Wed, 16 Aug 2017 22:24:07 +0500 Subject: [PATCH 112/137] Fix Nmap reset on ESP8266 PUBLISHED_FROM=7b9c85e7708721f2c6d0e2fc8ad5c32c61b48854 --- mongoose.c | 1 + 1 file changed, 1 insertion(+) diff --git a/mongoose.c b/mongoose.c index 75ee3ac7..5c5900e5 100644 --- a/mongoose.c +++ b/mongoose.c @@ -14500,6 +14500,7 @@ 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) { From 7f20c41dd5ada1c79c449eb5be269badb4462623 Mon Sep 17 00:00:00 2001 From: ruslanvaliullin Date: Thu, 17 Aug 2017 15:07:45 +0100 Subject: [PATCH 113/137] Implement rmdir & sleep func instead macros PUBLISHED_FROM=62c73e5fb4f70e2b5b8824ce092012508640b173 --- mongoose.c | 20 ++++++++++++++++++++ mongoose.h | 5 +++-- 2 files changed, 23 insertions(+), 2 deletions(-) diff --git a/mongoose.c b/mongoose.c index 5c5900e5..4903ecb3 100644 --- a/mongoose.c +++ b/mongoose.c @@ -15726,3 +15726,23 @@ const struct mg_iface_vtable mg_default_iface_vtable = MG_PIC32_IFACE_VTABLE; #endif #endif /* MG_ENABLE_NET_IF_PIC32 */ +#ifdef MG_MODULE_LINES +#line 1 "common/platforms/windows/windows_direct.c" +#endif +/* + * Copyright (c) 2017 Cesanta Software Limited + * All rights reserved + */ + +#ifdef _WIN32 + +int rmdir(const char *dirname) { + return _rmdir(dirname); +} + +unsigned int sleep(unsigned int seconds) { + Sleep(seconds * 1000); + return 0; +} + +#endif /* _WIN32 */ diff --git a/mongoose.h b/mongoose.h index 819dd80b..d21f3c54 100644 --- a/mongoose.h +++ b/mongoose.h @@ -223,14 +223,12 @@ #endif #define snprintf _snprintf #define vsnprintf _vsnprintf -#define sleep(x) Sleep((x) *1000) #define to64(x) _atoi64(x) #if !defined(__MINGW32__) && !defined(__MINGW64__) #define popen(x, y) _popen((x), (y)) #define pclose(x) _pclose(x) #define fileno _fileno #endif -#define rmdir _rmdir #if defined(_MSC_VER) && _MSC_VER >= 1400 #define fseeko(x, y, z) _fseeki64((x), (y), (z)) #else @@ -321,6 +319,9 @@ typedef struct _stati64 cs_stat_t; #define MG_NET_IF MG_NET_IF_SOCKET #endif +int rmdir(const char *dirname); +unsigned int sleep(unsigned int seconds); + #endif /* CS_PLATFORM == CS_P_WINDOWS */ #endif /* CS_COMMON_PLATFORMS_PLATFORM_WINDOWS_H_ */ #ifdef MG_MODULE_LINES From 7632a5e4afa41d8fc876d50da2a87349dc917fcb Mon Sep 17 00:00:00 2001 From: ruslanvaliullin Date: Thu, 17 Aug 2017 20:20:34 +0500 Subject: [PATCH 114/137] Fix ignoring DhcpNameServer PUBLISHED_FROM=73d6767e4aaa7249eeb5d76f9e7160be041292ca --- mongoose.c | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) diff --git a/mongoose.c b/mongoose.c index 4903ecb3..e82be2c8 100644 --- a/mongoose.c +++ b/mongoose.c @@ -10952,10 +10952,12 @@ static int mg_get_ip_address_of_nameserver(char *name, size_t name_len) { break; } if (RegOpenKeyExW(hKey, subkey, 0, KEY_READ, &hSub) == ERROR_SUCCESS && - (RegQueryValueExW(hSub, L"NameServer", 0, &type, (void *) value, - &len) == ERROR_SUCCESS || - RegQueryValueExW(hSub, L"DhcpNameServer", 0, &type, (void *) value, - &len) == ERROR_SUCCESS)) { + ((RegQueryValueExW(hSub, L"NameServer", 0, &type, (void *) value, + &len) == ERROR_SUCCESS && + value[0] != '\0') || + (RegQueryValueExW(hSub, L"DhcpNameServer", 0, &type, (void *) value, + &len) == ERROR_SUCCESS && + value[0] != '\0'))) { /* * See https://github.com/cesanta/mongoose/issues/176 * The value taken from the registry can be empty, a single @@ -10964,9 +10966,6 @@ static int mg_get_ip_address_of_nameserver(char *name, size_t name_len) { * If it's multiple IP addresses, take the first one. */ wchar_t *comma = wcschr(value, ','); - if (value[0] == '\0') { - continue; - } if (comma != NULL) { *comma = '\0'; } From 6517af3deaa54b6478b393bc6dd09ed2fae8531a Mon Sep 17 00:00:00 2001 From: Deomid Ryabkov Date: Mon, 21 Aug 2017 08:47:37 +0100 Subject: [PATCH 115/137] CC3220 blinky Ignore all the mess, this is just the beginning... PUBLISHED_FROM=41ab3c5af0b1d07204619dd4d8dc2e84b6a54f32 --- mongoose.h | 20 +++++++++++++++----- 1 file changed, 15 insertions(+), 5 deletions(-) diff --git a/mongoose.h b/mongoose.h index d21f3c54..d23c7016 100644 --- a/mongoose.h +++ b/mongoose.h @@ -46,9 +46,10 @@ #define CS_P_WINDOWS 2 #define CS_P_ESP32 15 #define CS_P_ESP8266 3 -#define CS_P_CC3200 4 -#define CS_P_MSP432 5 #define CS_P_CC3100 6 +#define CS_P_CC3200 4 +#define CS_P_CC3220 17 +#define CS_P_MSP432 5 #define CS_P_TM4C129 14 #define CS_P_MBED 7 #define CS_P_WINCE 8 @@ -58,7 +59,7 @@ #define CS_P_NRF52 10 #define CS_P_PIC32 11 #define CS_P_STM32 16 -/* Next id: 17 */ +/* Next id: 18 */ /* If not specified explicitly, we guess platform by defines. */ #ifndef CS_PLATFORM @@ -111,8 +112,9 @@ /* Amalgamated: #include "common/platforms/platform_windows.h" */ /* Amalgamated: #include "common/platforms/platform_esp32.h" */ /* Amalgamated: #include "common/platforms/platform_esp8266.h" */ -/* Amalgamated: #include "common/platforms/platform_cc3200.h" */ /* Amalgamated: #include "common/platforms/platform_cc3100.h" */ +/* Amalgamated: #include "common/platforms/platform_cc3200.h" */ +/* Amalgamated: #include "common/platforms/platform_cc3220.h" */ /* Amalgamated: #include "common/platforms/platform_mbed.h" */ /* Amalgamated: #include "common/platforms/platform_nrf51.h" */ /* Amalgamated: #include "common/platforms/platform_nrf52.h" */ @@ -719,8 +721,10 @@ int stat(const char *pathname, struct stat *st); #define S_ISDIR(mode) __S_ISTYPE((mode), __S_IFDIR) #define S_ISREG(mode) __S_ISTYPE((mode), __S_IFREG) -/* As of 5.2.7, TI compiler does not support va_copy() yet. */ +/* 5.x series compilers don't have va_copy, 16.x do. */ +#if __TI_COMPILER_VERSION__ < 16000000 #define va_copy(apc, ap) ((apc) = (ap)) +#endif #endif /* __TI_COMPILER_VERSION__ */ @@ -1115,6 +1119,11 @@ int gettimeofday(struct timeval *tp, void *tzp); #undef fd_set #endif +#if CS_PLATFORM == CS_P_CC3220 +#include +#include +#include +#else /* We want to disable SL_INC_STD_BSD_API_NAMING, so we include user.h ourselves * and undef it. */ #define PROVISIONING_API_H_ @@ -1124,6 +1133,7 @@ int gettimeofday(struct timeval *tp, void *tzp); #include #include +#endif /* CS_PLATFORM == CS_P_CC3220 */ /* Now define only the subset of the BSD API that we use. * Notably, close(), read() and write() are not defined. */ From 7d5479985dfa533446255e3558009542c58ff7f3 Mon Sep 17 00:00:00 2001 From: Deomid Ryabkov Date: Mon, 21 Aug 2017 15:07:24 +0100 Subject: [PATCH 116/137] Enable LWIP net_if locking on ESP32 (doh!) https://forum.mongoose-os.com/discussion/comment/4620/#Comment_4620 PUBLISHED_FROM=679dd48e078615ef4f57d1879957b734f549ef2e --- mongoose.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mongoose.c b/mongoose.c index e82be2c8..d199e3b2 100644 --- a/mongoose.c +++ b/mongoose.c @@ -14195,7 +14195,7 @@ void mg_lwip_if_add_conn(struct mg_connection *nc); void mg_lwip_if_remove_conn(struct mg_connection *nc); time_t mg_lwip_if_poll(struct mg_iface *iface, int timeout_ms); -#ifdef RTOS_SDK +#if defined(RTOS_SDK) || defined(ESP_PLATFORM) extern void mgos_lock(); extern void mgos_unlock(); #else From d4b55c4ceb3eb24f96218a45852ec7d0e1c38aee Mon Sep 17 00:00:00 2001 From: Dmitry Frank Date: Tue, 22 Aug 2017 22:47:43 +0300 Subject: [PATCH 117/137] Separate digest auth from HTTP headers parsing PUBLISHED_FROM=f97569ae2f31ab94ce4875eae4d0a198f719c388 --- docs/c-api/http_server.h/intro.md | 1 + .../http_server.h/mg_check_digest_auth.md | 17 +++++++ mongoose.c | 47 +++++++++++++------ mongoose.h | 12 +++++ 4 files changed, 62 insertions(+), 15 deletions(-) create mode 100644 docs/c-api/http_server.h/mg_check_digest_auth.md diff --git a/docs/c-api/http_server.h/intro.md b/docs/c-api/http_server.h/intro.md index 98402e96..0fc609db 100644 --- a/docs/c-api/http_server.h/intro.md +++ b/docs/c-api/http_server.h/intro.md @@ -3,6 +3,7 @@ title: "Server API reference" symbol_kind: "intro" decl_name: "http_server.h" items: + - { name: mg_check_digest_auth.md } - { name: mg_file_upload_handler.md } - { name: mg_get_http_basic_auth.md } - { name: mg_get_http_header.md } diff --git a/docs/c-api/http_server.h/mg_check_digest_auth.md b/docs/c-api/http_server.h/mg_check_digest_auth.md new file mode 100644 index 00000000..189f0c4a --- /dev/null +++ b/docs/c-api/http_server.h/mg_check_digest_auth.md @@ -0,0 +1,17 @@ +--- +title: "mg_check_digest_auth()" +decl_name: "mg_check_digest_auth" +symbol_kind: "func" +signature: | + int mg_check_digest_auth(struct mg_str method, struct mg_str uri, + struct mg_str username, struct mg_str cnonce, + struct mg_str response, struct mg_str qop, + struct mg_str nc, struct mg_str nonce, + struct mg_str auth_domain, FILE *fp); +--- + +Authenticates given response params against an opened password file. +Returns 1 if authenticated, 0 otherwise. + +It's used by mg_http_check_digest_auth(). + diff --git a/mongoose.c b/mongoose.c index d199e3b2..a765594a 100644 --- a/mongoose.c +++ b/mongoose.c @@ -6973,14 +6973,13 @@ static int mg_check_nonce(const char *nonce) { int mg_http_check_digest_auth(struct http_message *hm, const char *auth_domain, FILE *fp) { struct mg_str *hdr; - char buf[128], f_user[sizeof(buf)], f_ha1[sizeof(buf)], f_domain[sizeof(buf)]; - char user[50], cnonce[64], response[40], uri[200], qop[20], nc[20], nonce[30]; - char expected_response[33]; + char username[50], cnonce[64], response[40], uri[200], qop[20], nc[20], + nonce[30]; /* Parse "Authorization:" header, fail fast on parse error */ if (hm == NULL || fp == NULL || (hdr = mg_get_http_header(hm, "Authorization")) == NULL || - mg_http_parse_header(hdr, "username", user, sizeof(user)) == 0 || + mg_http_parse_header(hdr, "username", username, sizeof(username)) == 0 || mg_http_parse_header(hdr, "cnonce", cnonce, sizeof(cnonce)) == 0 || mg_http_parse_header(hdr, "response", response, sizeof(response)) == 0 || mg_http_parse_header(hdr, "uri", uri, sizeof(uri)) == 0 || @@ -6991,6 +6990,26 @@ int mg_http_check_digest_auth(struct http_message *hm, const char *auth_domain, return 0; } + /* NOTE(lsm): due to a bug in MSIE, we do not compare URIs */ + + return mg_check_digest_auth( + hm->method, + mg_mk_str_n( + hm->uri.p, + hm->uri.len + (hm->query_string.len ? hm->query_string.len + 1 : 0)), + mg_mk_str(username), mg_mk_str(cnonce), mg_mk_str(response), + mg_mk_str(qop), mg_mk_str(nc), mg_mk_str(nonce), mg_mk_str(auth_domain), + fp); +} + +int mg_check_digest_auth(struct mg_str method, struct mg_str uri, + struct mg_str username, struct mg_str cnonce, + struct mg_str response, struct mg_str qop, + struct mg_str nc, struct mg_str nonce, + struct mg_str auth_domain, FILE *fp) { + char buf[128], f_user[sizeof(buf)], f_ha1[sizeof(buf)], f_domain[sizeof(buf)]; + char expected_response[33]; + /* * Read passwords file line by line. If should have htdigest format, * i.e. each line should be a colon-separated sequence: @@ -6998,18 +7017,16 @@ int mg_http_check_digest_auth(struct http_message *hm, const char *auth_domain, */ while (fgets(buf, sizeof(buf), fp) != NULL) { if (sscanf(buf, "%[^:]:%[^:]:%s", f_user, f_domain, f_ha1) == 3 && - strcmp(user, f_user) == 0 && - /* NOTE(lsm): due to a bug in MSIE, we do not compare URIs */ - strcmp(auth_domain, f_domain) == 0) { - /* User and domain matched, check the password */ - mg_mkmd5resp( - hm->method.p, hm->method.len, hm->uri.p, - hm->uri.len + (hm->query_string.len ? hm->query_string.len + 1 : 0), - f_ha1, strlen(f_ha1), nonce, strlen(nonce), nc, strlen(nc), cnonce, - strlen(cnonce), qop, strlen(qop), expected_response); + mg_vcmp(&username, f_user) == 0 && + mg_vcmp(&auth_domain, f_domain) == 0) { + /* Username and domain matched, check the password */ + mg_mkmd5resp(method.p, method.len, uri.p, uri.len, f_ha1, strlen(f_ha1), + nonce.p, nonce.len, nc.p, nc.len, cnonce.p, cnonce.len, + qop.p, qop.len, expected_response); LOG(LL_DEBUG, - ("%s %s %s %s", user, f_domain, response, expected_response)); - return mg_casecmp(response, expected_response) == 0; + ("%.*s %s %.*s %s", (int) username.len, username.p, f_domain, + (int) response.len, response.p, expected_response)); + return mg_ncasecmp(response.p, expected_response, response.len) == 0; } } diff --git a/mongoose.h b/mongoose.h index d23c7016..a9414274 100644 --- a/mongoose.h +++ b/mongoose.h @@ -4870,6 +4870,18 @@ void mg_register_http_endpoint_opt(struct mg_connection *nc, int mg_http_check_digest_auth(struct http_message *hm, const char *auth_domain, FILE *fp); +/* + * Authenticates given response params against an opened password file. + * Returns 1 if authenticated, 0 otherwise. + * + * It's used by mg_http_check_digest_auth(). + */ +int mg_check_digest_auth(struct mg_str method, struct mg_str uri, + struct mg_str username, struct mg_str cnonce, + struct mg_str response, struct mg_str qop, + struct mg_str nc, struct mg_str nonce, + struct mg_str auth_domain, FILE *fp); + /* * Sends buffer `buf` of size `len` to the client using chunked HTTP encoding. * This function sends the buffer size as hex number + newline first, then From 09e4254718300644ccc90c28aa0a32975d49237b Mon Sep 17 00:00:00 2001 From: Our CI Bot Date: Thu, 24 Aug 2017 11:29:02 +0100 Subject: [PATCH 118/137] Add mqtt_over_websocket_server example Fixed bug in websocket handshake: now adding Sec-WebSocket-Protocol header in handshake response. PUBLISHED_FROM=e4a71ff9dc4aeec63db40cb7f356dc5b25c1215a --- examples/mqtt_over_websocket_server/Makefile | 4 + .../mqtt_over_websocket_server.c | 124 ++++++++++++++++++ mongoose.c | 40 ++++-- mongoose.h | 1 + 4 files changed, 156 insertions(+), 13 deletions(-) create mode 100644 examples/mqtt_over_websocket_server/Makefile create mode 100644 examples/mqtt_over_websocket_server/mqtt_over_websocket_server.c diff --git a/examples/mqtt_over_websocket_server/Makefile b/examples/mqtt_over_websocket_server/Makefile new file mode 100644 index 00000000..7f6be7c6 --- /dev/null +++ b/examples/mqtt_over_websocket_server/Makefile @@ -0,0 +1,4 @@ +PROG = mqtt_over_websocket_server +MODULE_CFLAGS = -DMG_ENABLE_MQTT_BROKER=1 +#SSL_LIB=mbedtls +include ../examples.mk diff --git a/examples/mqtt_over_websocket_server/mqtt_over_websocket_server.c b/examples/mqtt_over_websocket_server/mqtt_over_websocket_server.c new file mode 100644 index 00000000..885921ce --- /dev/null +++ b/examples/mqtt_over_websocket_server/mqtt_over_websocket_server.c @@ -0,0 +1,124 @@ +/* + * Copyright (c) 2014 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. + * + * Alternatively, you can license this software under a commercial + * license, as set out in . + */ + +#include "mongoose.h" + +static const char *s_mqtt_address = "0.0.0.0:1883"; +static const char *s_http_address = "0.0.0.0:8080"; + +static void unproxy(struct mg_connection *c) { + struct mg_connection *pc = (struct mg_connection *) c->user_data; + if (pc != NULL) { + pc->flags |= MG_F_CLOSE_IMMEDIATELY; + pc->user_data = NULL; + c->user_data = NULL; + } + printf("Closing connection %p\n", c); +} + +static void proxy_handler(struct mg_connection *c, int ev, void *ev_data) { + if (ev == MG_EV_POLL) return; + printf("%p %s EVENT %d %p\n", c, __func__, ev, ev_data); + switch (ev) { + case MG_EV_CLOSE: { + unproxy(c); + break; + } + case MG_EV_RECV: { + struct mg_connection *pc = (struct mg_connection *) c->user_data; + if (pc != NULL) { + mg_send_websocket_frame(pc, WEBSOCKET_OP_BINARY, c->recv_mbuf.buf, + c->recv_mbuf.len); + mbuf_remove(&c->recv_mbuf, c->recv_mbuf.len); + } + break; + } + } +} + +static void http_handler(struct mg_connection *c, int ev, void *ev_data) { + struct mg_connection *pc = (struct mg_connection *) c->user_data; + if (ev == MG_EV_POLL) return; + printf("%p %s EVENT %d %p\n", c, __func__, ev, ev_data); + /* Do your custom event processing here */ + switch (ev) { + case MG_EV_WEBSOCKET_HANDSHAKE_DONE: { + pc = mg_connect(c->mgr, s_mqtt_address, proxy_handler); + pc->user_data = c; + c->user_data = pc; + printf("Created proxy connection %p\n", pc); + break; + } + case MG_EV_WEBSOCKET_FRAME: { + struct websocket_message *wm = (struct websocket_message *) ev_data; + if (pc != NULL) { + printf("Forwarding %d bytes\n", (int) wm->size); + mg_send(pc, wm->data, wm->size); + } + break; + } + case MG_EV_CLOSE: { + unproxy(c); + break; + } + } +} + +static void mqtt_handler(struct mg_connection *c, int ev, void *ev_data) { + if (ev == MG_EV_POLL) return; + printf("%p %s EVENT %d %p\n", c, __func__, ev, ev_data); + /* Do your custom event processing here */ + switch (ev) { + case MG_EV_CLOSE: + printf("Closing MQTT connection %p\n", c); + break; + } + mg_mqtt_broker(c, ev, ev_data); +} + +static void start_mqtt_server(struct mg_mgr *mgr, const char *addr) { + struct mg_connection *c; + static struct mg_mqtt_broker brk; // static is important - must not perish + if ((c = mg_bind(mgr, addr, mqtt_handler)) == NULL) { + fprintf(stderr, "Cannot start MQTT server on port [%s]\n", addr); + exit(EXIT_FAILURE); + } + mg_mqtt_broker_init(&brk, NULL); + c->user_data = &brk; + mg_set_protocol_mqtt(c); + printf("MQTT server started on %s\n", addr); +} + +static void start_http_server(struct mg_mgr *mgr, const char *addr) { + struct mg_connection *c; + if ((c = mg_bind(mgr, addr, http_handler)) == NULL) { + fprintf(stderr, "Cannot start HTTP server on port [%s]\n", addr); + exit(EXIT_FAILURE); + } + mg_set_protocol_http_websocket(c); + printf("HTTP server started on %s\n", addr); +} + +int main(void) { + struct mg_mgr mgr; + mg_mgr_init(&mgr, NULL); + start_http_server(&mgr, s_http_address); + start_mqtt_server(&mgr, s_mqtt_address); + for (;;) { + mg_mgr_poll(&mgr, 1000); + } +} diff --git a/mongoose.c b/mongoose.c index a765594a..eac8391d 100644 --- a/mongoose.c +++ b/mongoose.c @@ -34,9 +34,9 @@ #define MG_DISABLE_PFS #endif -/* Amalgamated: #include "mongoose/src/net.h" */ -/* Amalgamated: #include "mongoose/src/http.h" */ /* Amalgamated: #include "common/cs_dbg.h" */ +/* Amalgamated: #include "mongoose/src/http.h" */ +/* Amalgamated: #include "mongoose/src/net.h" */ #define MG_CTL_MSG_MESSAGE_SIZE 8192 @@ -140,7 +140,8 @@ MG_INTERNAL void mg_handle_put(struct mg_connection *nc, const char *path, MG_INTERNAL void mg_ws_handler(struct mg_connection *nc, int ev, void *ev_data MG_UD_ARG(void *user_data)); MG_INTERNAL void mg_ws_handshake(struct mg_connection *nc, - const struct mg_str *key); + const struct mg_str *key, + struct http_message *); #endif #endif /* MG_ENABLE_HTTP */ @@ -6021,7 +6022,7 @@ void mg_http_handler(struct mg_connection *nc, int ev, hm); if (!(nc->flags & (MG_F_CLOSE_IMMEDIATELY | MG_F_SEND_AND_CLOSE))) { if (nc->send_mbuf.len == 0) { - mg_ws_handshake(nc, vec); + mg_ws_handshake(nc, vec, hm); } mg_call(nc, nc->handler, nc->user_data, MG_EV_WEBSOCKET_HANDSHAKE_DONE, NULL); @@ -9164,8 +9165,9 @@ static int mg_deliver_websocket_data(struct mg_connection *nc) { unsigned char *p = (unsigned char *) nc->recv_mbuf.buf, *buf = p, *e = p + buf_len; unsigned *sizep = (unsigned *) &p[1]; /* Size ptr for defragmented frames */ - int ok, reass = buf_len > 0 && mg_is_ws_fragment(p[0]) && - !(nc->flags & MG_F_WEBSOCKET_NO_DEFRAG); + int ok; + int reass = buf_len > 0 && mg_is_ws_fragment(p[0]) && + !(nc->flags & MG_F_WEBSOCKET_NO_DEFRAG); /* If that's a continuation frame that must be reassembled, handle it */ if (reass && !mg_is_ws_first_fragment(p[0]) && @@ -9418,21 +9420,28 @@ extern void mg_hash_sha1_v(size_t num_msgs, const uint8_t *msgs[], #endif MG_INTERNAL void mg_ws_handshake(struct mg_connection *nc, - const struct mg_str *key) { + const struct mg_str *key, + struct http_message *hm) { static const char *magic = "258EAFA5-E914-47DA-95CA-C5AB0DC85B11"; const uint8_t *msgs[2] = {(const uint8_t *) key->p, (const uint8_t *) magic}; const size_t msg_lens[2] = {key->len, 36}; unsigned char sha[20]; char b64_sha[30]; + struct mg_str *s; mg_hash_sha1_v(2, msgs, msg_lens, sha); mg_base64_encode(sha, sizeof(sha), b64_sha); - mg_printf(nc, "%s%s%s", + mg_printf(nc, "%s", "HTTP/1.1 101 Switching Protocols\r\n" "Upgrade: websocket\r\n" - "Connection: Upgrade\r\n" - "Sec-WebSocket-Accept: ", - b64_sha, "\r\n\r\n"); + "Connection: Upgrade\r\n"); + + s = mg_get_http_header(hm, "Sec-WebSocket-Protocol"); + if (s != NULL) { + mg_printf(nc, "Sec-WebSocket-Protocol: %.*s\r\n", (int) s->len, s->p); + } + mg_printf(nc, "Sec-WebSocket-Accept: %s%s", b64_sha, "\r\n\r\n"); + DBG(("%p %.*s %s", nc, (int) key->len, key->p, b64_sha)); } @@ -9996,7 +10005,8 @@ MG_INTERNAL int parse_mqtt(struct mbuf *io, struct mg_mqtt_message *mm) { break; } - return end - io->buf; + mm->len = end - io->buf; + return mm->len; } static void mqtt_handler(struct mg_connection *nc, int ev, @@ -10008,6 +10018,9 @@ static void mqtt_handler(struct mg_connection *nc, int ev, nc->handler(nc, ev, ev_data MG_UD_ARG(user_data)); switch (ev) { + case MG_EV_ACCEPT: + if (nc->proto_data == NULL) mg_set_protocol_mqtt(nc); + break; case MG_EV_RECV: { /* There can be multiple messages in the buffer, process them all. */ while (1) { @@ -10027,6 +10040,7 @@ static void mqtt_handler(struct mg_connection *nc, int ev, LOG(LL_DEBUG, ("Send PINGREQ")); mg_mqtt_ping(nc); } + break; } } } @@ -10438,7 +10452,7 @@ void mg_mqtt_broker(struct mg_connection *nc, int ev, void *data) { switch (ev) { case MG_EV_ACCEPT: - mg_set_protocol_mqtt(nc); + if (nc->proto_data == NULL) mg_set_protocol_mqtt(nc); nc->user_data = NULL; /* Clear up the inherited pointer to broker */ break; case MG_EV_MQTT_CONNECT: diff --git a/mongoose.h b/mongoose.h index a9414274..a7689ba6 100644 --- a/mongoose.h +++ b/mongoose.h @@ -5087,6 +5087,7 @@ int mg_http_create_digest_auth_header(char *buf, size_t buf_len, struct mg_mqtt_message { int cmd; int qos; + int len; /* message length in the IO buffer */ struct mg_str topic; struct mg_str payload; From 38e984a0085832e6c402275b7cb92314c48e4d2a Mon Sep 17 00:00:00 2001 From: Deomid Ryabkov Date: Sat, 26 Aug 2017 18:02:08 +0100 Subject: [PATCH 119/137] CC3220 first steps Achievement unlocked: CC3220 port prints a boot banner. Then locks up. Included in this PR is refactoring to pull out common parts to be shared with CC3200. PUBLISHED_FROM=5fb9d9a00bb9ce7f63dde20bc1876076b76d5257 --- mongoose.c | 42 ++++++++++++++++++++++++------------------ mongoose.h | 27 +++++++++++++++++++++++---- 2 files changed, 47 insertions(+), 22 deletions(-) diff --git a/mongoose.c b/mongoose.c index eac8391d..1b54cf81 100644 --- a/mongoose.c +++ b/mongoose.c @@ -13302,7 +13302,7 @@ const char *inet_ntop(int af, const void *src, char *dst, socklen_t size) { int res; struct in_addr *in = (struct in_addr *) src; if (af != AF_INET) { - errno = EAFNOSUPPORT; + errno = ENOTSUP; return NULL; } res = snprintf(dst, size, "%lu.%lu.%lu.%lu", SL_IPV4_BYTE(in->s_addr, 0), @@ -13320,7 +13320,7 @@ int inet_pton(int af, const char *src, void *dst) { uint32_t a0, a1, a2, a3; uint8_t *db = (uint8_t *) dst; if (af != AF_INET) { - errno = EAFNOSUPPORT; + errno = ENOTSUP; return 0; } if (sscanf(src, "%lu.%lu.%lu.%lu", &a0, &a1, &a2, &a3) != 4) { @@ -13442,12 +13442,16 @@ int sl_set_ssl_opts(struct mg_connection *nc); void mg_set_non_blocking_mode(sock_t sock) { SlSockNonblocking_t opt; +#if SL_MAJOR_VERSION_NUM < 2 opt.NonblockingEnabled = 1; +#else + opt.NonBlockingEnabled = 1; +#endif sl_SetSockOpt(sock, SL_SOL_SOCKET, SL_SO_NONBLOCKING, &opt, sizeof(opt)); } static int mg_is_error(int n) { - return (n < 0 && n != SL_EALREADY && n != SL_EAGAIN); + return (n < 0 && n != SL_ERROR_BSD_EALREADY && n != SL_ERROR_BSD_EAGAIN); } void mg_sl_if_connect_tcp(struct mg_connection *nc, @@ -13648,7 +13652,7 @@ void mg_mgr_handle_conn(struct mg_connection *nc, int fd_flags, double now) { fd_flags, nc->flags, (int) nc->recv_mbuf.len, (int) nc->send_mbuf.len)); if (nc->flags & MG_F_CONNECTING) { - if (nc->flags & MG_F_UDP || nc->err != SL_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 @@ -13657,9 +13661,9 @@ void mg_mgr_handle_conn(struct mg_connection *nc, int fd_flags, double now) { if (fd_flags & _MG_F_FD_CAN_WRITE) { nc->err = sl_Connect(nc->sock, &nc->sa.sa, sizeof(nc->sa.sin)); DBG(("%p conn res=%d", nc, nc->err)); - if (nc->err == SL_ESECSNOVERIFY || + if (nc->err == SL_ERROR_BSD_ESECSNOVERIFY || /* TODO(rojer): Provide API to set the date for verification. */ - nc->err == SL_ESECDATEERROR) { + nc->err == SL_ERROR_BSD_ESECDATEERROR) { nc->err = 0; } if (nc->flags & MG_F_SSL && nc->err == 0) { @@ -13733,9 +13737,9 @@ time_t mg_sl_if_poll(struct mg_iface *iface, int timeout_ms) { sock_t max_fd = INVALID_SOCKET; int num_fds, num_ev = 0, num_timers = 0; - SL_FD_ZERO(&read_set); - SL_FD_ZERO(&write_set); - SL_FD_ZERO(&err_set); + SL_SOCKET_FD_ZERO(&read_set); + SL_SOCKET_FD_ZERO(&write_set); + SL_SOCKET_FD_ZERO(&err_set); /* * Note: it is ok to have connections with sock == INVALID_SOCKET in the list, @@ -13751,14 +13755,14 @@ time_t mg_sl_if_poll(struct mg_iface *iface, int timeout_ms) { if (!(nc->flags & MG_F_WANT_WRITE) && nc->recv_mbuf.len < nc->recv_mbuf_limit && (!(nc->flags & MG_F_UDP) || nc->listener == NULL)) { - SL_FD_SET(nc->sock, &read_set); + SL_SOCKET_FD_SET(nc->sock, &read_set); if (max_fd == INVALID_SOCKET || nc->sock > max_fd) max_fd = nc->sock; } if (((nc->flags & MG_F_CONNECTING) && !(nc->flags & MG_F_WANT_READ)) || (nc->send_mbuf.len > 0 && !(nc->flags & MG_F_CONNECTING))) { - SL_FD_SET(nc->sock, &write_set); - SL_FD_SET(nc->sock, &err_set); + SL_SOCKET_FD_SET(nc->sock, &write_set); + SL_SOCKET_FD_SET(nc->sock, &err_set); if (max_fd == INVALID_SOCKET || nc->sock > max_fd) max_fd = nc->sock; } } @@ -13799,12 +13803,13 @@ time_t mg_sl_if_poll(struct mg_iface *iface, int timeout_ms) { if (nc->sock != INVALID_SOCKET) { if (num_ev > 0) { fd_flags = - (SL_FD_ISSET(nc->sock, &read_set) && + (SL_SOCKET_FD_ISSET(nc->sock, &read_set) && (!(nc->flags & MG_F_UDP) || nc->listener == NULL) ? _MG_F_FD_CAN_READ : 0) | - (SL_FD_ISSET(nc->sock, &write_set) ? _MG_F_FD_CAN_WRITE : 0) | - (SL_FD_ISSET(nc->sock, &err_set) ? _MG_F_FD_ERROR : 0); + (SL_SOCKET_FD_ISSET(nc->sock, &write_set) ? _MG_F_FD_CAN_WRITE + : 0) | + (SL_SOCKET_FD_ISSET(nc->sock, &err_set) ? _MG_F_FD_ERROR : 0); } /* SimpleLink does not report UDP sockets as writable. */ if (nc->flags & MG_F_UDP && nc->send_mbuf.len > 0) { @@ -14087,13 +14092,14 @@ int sl_set_ssl_opts(struct mg_connection *nc) { } if (ctx->ssl_server_name != NULL) { err = sl_SetSockOpt(nc->sock, SL_SOL_SOCKET, - SO_SECURE_DOMAIN_NAME_VERIFICATION, + 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_ENOPROTOOPT. There isn't much we can do about it, + * 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_ENOPROTOOPT) return err; + if (err != 0 && err != SL_ERROR_BSD_ENOPROTOOPT) return err; } } return 0; diff --git a/mongoose.h b/mongoose.h index a7689ba6..daae6ec0 100644 --- a/mongoose.h +++ b/mongoose.h @@ -66,8 +66,10 @@ #if defined(TARGET_IS_MSP432P4XX) || defined(__MSP432P401R__) #define CS_PLATFORM CS_P_MSP432 -#elif defined(cc3200) +#elif defined(cc3200) || defined(TARGET_IS_CC3200) #define CS_PLATFORM CS_P_CC3200 +#elif defined(cc3220) || defined(TARGET_IS_CC3220) +#define CS_PLATFORM CS_P_CC3220 #elif defined(__unix__) || defined(__APPLE__) #define CS_PLATFORM CS_P_UNIX #elif defined(WINCE) @@ -1103,9 +1105,10 @@ int gettimeofday(struct timeval *tp, void *tzp); #ifndef CS_COMMON_PLATFORMS_SIMPLELINK_CS_SIMPLELINK_H_ #define CS_COMMON_PLATFORMS_SIMPLELINK_CS_SIMPLELINK_H_ +#if defined(MG_NET_IF) && MG_NET_IF == MG_NET_IF_SIMPLELINK + /* If simplelink.h is already included, all bets are off. */ -#if defined(MG_NET_IF) && MG_NET_IF == MG_NET_IF_SIMPLELINK && \ - !defined(__SIMPLELINK_H__) +#if !defined(__SIMPLELINK_H__) #include @@ -1122,6 +1125,7 @@ int gettimeofday(struct timeval *tp, void *tzp); #if CS_PLATFORM == CS_P_CC3220 #include #include +#include #include #else /* We want to disable SL_INC_STD_BSD_API_NAMING, so we include user.h ourselves @@ -1202,7 +1206,22 @@ int sl_set_ssl_opts(struct mg_connection *nc); } #endif -#endif /* MG_NET_IF == MG_NET_IF_SIMPLELINK && !defined(__SIMPLELINK_H__) */ +#endif /* !defined(__SIMPLELINK_H__) */ + +/* COmpatibility with older versions of SimpleLink */ +#if SL_MAJOR_VERSION_NUM < 2 +#define SL_ERROR_BSD_EAGAIN SL_EAGAIN +#define SL_ERROR_BSD_EALREADY SL_EALREADY +#define SL_ERROR_BSD_ENOPROTOOPT SL_ENOPROTOOPT +#define SL_ERROR_BSD_ESECDATEERROR SL_ESECDATEERROR +#define SL_ERROR_BSD_ESECSNOVERIFY SL_ESECSNOVERIFY +#define SL_SOCKET_FD_ZERO SL_FD_ZERO +#define SL_SOCKET_FD_SET SL_FD_SET +#define SL_SOCKET_FD_ISSET SL_FD_ISSET +#define SL_SO_SECURE_DOMAIN_NAME_VERIFICATION SO_SECURE_DOMAIN_NAME_VERIFICATION +#endif + +#endif /* MG_NET_IF == MG_NET_IF_SIMPLELINK */ #endif /* CS_COMMON_PLATFORMS_SIMPLELINK_CS_SIMPLELINK_H_ */ #ifdef MG_MODULE_LINES From 6fe9cae62abb6a5fca55914b0f8f187c9f556645 Mon Sep 17 00:00:00 2001 From: Dmitry Frank Date: Sun, 27 Aug 2017 13:43:17 +0100 Subject: [PATCH 120/137] Add mg_next_comma_list_entry_n() And mgos_conf_check_access_n() PUBLISHED_FROM=c7de937b4f5463ca463d604183a4ee831617bd6d --- mongoose.c | 27 +++++++++++++++++++-------- mongoose.h | 2 ++ 2 files changed, 21 insertions(+), 8 deletions(-) diff --git a/mongoose.c b/mongoose.c index 1b54cf81..510fee0e 100644 --- a/mongoose.c +++ b/mongoose.c @@ -1926,19 +1926,30 @@ const char *mg_next_comma_list_entry(const char *, struct mg_str *, struct mg_str *) WEAK; const char *mg_next_comma_list_entry(const char *list, struct mg_str *val, struct mg_str *eq_val) { - if (list == NULL || *list == '\0') { + struct mg_str ret = mg_next_comma_list_entry_n(mg_mk_str(list), val, eq_val); + return ret.p; +} + +struct mg_str mg_next_comma_list_entry_n(struct mg_str list, struct mg_str *val, + struct mg_str *eq_val) WEAK; +struct mg_str mg_next_comma_list_entry_n(struct mg_str list, struct mg_str *val, + struct mg_str *eq_val) { + if (list.len == 0) { /* End of the list */ - list = NULL; + list = mg_mk_str(NULL); } else { - val->p = list; - if ((list = strchr(val->p, ',')) != NULL) { + const char *chr = NULL; + *val = list; + + if ((chr = mg_strchr(*val, ',')) != NULL) { /* Comma found. Store length and shift the list ptr */ - val->len = list - val->p; - list++; + val->len = chr - val->p; + chr++; + list.len -= (chr - list.p); + list.p = chr; } else { /* This value is the last one */ - list = val->p + strlen(val->p); - val->len = list - val->p; + list = mg_mk_str_n(list.p + list.len, 0); } if (eq_val != NULL) { diff --git a/mongoose.h b/mongoose.h index daae6ec0..5e431391 100644 --- a/mongoose.h +++ b/mongoose.h @@ -2104,6 +2104,8 @@ int mg_avprintf(char **buf, size_t size, const char *fmt, va_list ap); */ const char *mg_next_comma_list_entry(const char *list, struct mg_str *val, struct mg_str *eq_val); +struct mg_str mg_next_comma_list_entry_n(struct mg_str list, struct mg_str *val, + struct mg_str *eq_val); /* * Matches 0-terminated string (mg_match_prefix) or string with given length From 0a93e301c9fdd139dcc37e8325017684de55f3b1 Mon Sep 17 00:00:00 2001 From: Deomid Ryabkov Date: Wed, 30 Aug 2017 00:44:29 +0300 Subject: [PATCH 121/137] CC3220: Exception handling, NWP init Also make CC3200 use newer ARM compiler, generates slightly smaller code. PUBLISHED_FROM=a0be49d7ea864a95886f7110887a59f6f11802d7 --- examples/CC3200/Makefile.build | 8 ++++---- examples/CC3200/main.c | 13 +++++++++++++ examples/CC3200/sdk.version | 2 +- mongoose.c | 22 ---------------------- mongoose.h | 9 ++++++++- 5 files changed, 26 insertions(+), 28 deletions(-) diff --git a/examples/CC3200/Makefile.build b/examples/CC3200/Makefile.build index 083cb885..6e16c3ce 100644 --- a/examples/CC3200/Makefile.build +++ b/examples/CC3200/Makefile.build @@ -58,11 +58,11 @@ $(FW_DIR): $(FW_ZIP): $(FW_ELF) $(FW_BIN) $(SLFS_FILES) @echo " Code size: $(shell ls -l $(FW_BIN) | awk '{print $$5}')" @echo " GEN $(FW_MANIFEST)" - @fw_meta gen_build_info \ + @fw_meta.py gen_build_info \ --json_output=$(BUILD_INFO_JSON) @cp -v $(SLFS_FILES) out/ @cp $(CC3200_SP_FILE)* $(FW_DIR) - @fw_meta create_manifest \ + @fw_meta.py create_manifest \ --name=$(PROG) --platform=$(PLATFORM) \ --build_info=$(BUILD_INFO_JSON) \ --output=$(FW_MANIFEST) \ @@ -72,14 +72,14 @@ $(FW_ZIP): $(FW_ELF) $(FW_BIN) $(SLFS_FILES) /sys/mcuimg.bin:type=app,src=$(notdir $(FW_BIN)) \ $(foreach f,$(SLFS_FILES), $(notdir $(f)):type=slfile,src=$(notdir $(f))) @echo " ZIP $@" - @fw_meta create_fw \ + @fw_meta.py create_fw \ --manifest=$(FW_MANIFEST) \ --src_dir=$(FW_DIR) \ --output=$@ FREERTOS_SRCS = timers.c list.c queue.c tasks.c port.c heap_3.c osi_freertos.c DRIVER_SRCS = cpu.c gpio.c gpio_if.c i2c.c i2c_if.c interrupt.c pin.c prcm.c spi.c uart.c udma.c utils.c -SL_SRCS = socket.c wlan.c driver.c device.c netapp.c netcfg.c network_common.c cc_pal.c fs.c +SL_SRCS = socket.c wlan.c driver.c device.c netapp.c netcfg.c network_common.c timer.c cc_pal.c fs.c SDK_SRCS = startup_gcc.c $(FREERTOS_SRCS) $(DRIVER_SRCS) $(SL_SRCS) IPATH += $(SDK_PATH) $(SDK_PATH)/inc $(SDK_PATH)/driverlib \ $(SDK_PATH)/example/common $(SDK_PATH)/oslib \ diff --git a/examples/CC3200/main.c b/examples/CC3200/main.c index 24eea055..dbda74ae 100644 --- a/examples/CC3200/main.c +++ b/examples/CC3200/main.c @@ -294,3 +294,16 @@ void SimpleLinkGeneralEventHandler(SlDeviceEvent_t *e) { LOG(LL_ERROR, ("status %d sender %d", e->EventData.deviceEvent.status, e->EventData.deviceEvent.sender)); } + +#ifndef __TI_COMPILER_VERSION__ +int _gettimeofday_r(struct _reent *r, struct timeval *tp, void *tz) { +#else +int gettimeofday(struct timeval *tp, void *tz) { +#endif + unsigned long sec; + unsigned short msec; + MAP_PRCMRTCGet(&sec, &msec); + tp->tv_sec = sec; + tp->tv_usec = ((unsigned long) msec) * 1000; + return 0; +} diff --git a/examples/CC3200/sdk.version b/examples/CC3200/sdk.version index 8f4f18a3..f8bd0dae 100644 --- a/examples/CC3200/sdk.version +++ b/examples/CC3200/sdk.version @@ -1 +1 @@ -docker.cesanta.com/cc3200-build:1.2.0-r8 +docker.cesanta.com/cc3200-build:1.3.0-r2 diff --git a/mongoose.c b/mongoose.c index 510fee0e..d83a2e47 100644 --- a/mongoose.c +++ b/mongoose.c @@ -12505,28 +12505,6 @@ time_t HOSTtime() { #endif /* __TI_COMPILER_VERSION__ */ -#ifndef __TI_COMPILER_VERSION__ -int _gettimeofday_r(struct _reent *r, struct timeval *tp, void *tz) { -#else -int gettimeofday(struct timeval *tp, void *tz) { -#endif - unsigned long sec; - unsigned short msec; - MAP_PRCMRTCGet(&sec, &msec); - tp->tv_sec = sec; - tp->tv_usec = ((unsigned long) msec) * 1000; - return 0; -} - -#ifndef __TI_COMPILER_VERSION__ -int settimeofday(const struct timeval *tv, const struct timezone *tz) { -#else -int settimeofday(const struct timeval *tv, const void *tz) { -#endif - MAP_PRCMRTCSet(tv->tv_sec, tv->tv_usec / 1000); - return 0; -} - void fprint_str(FILE *fp, const char *str) { while (*str != '\0') { if (*str == '\n') MAP_UARTCharPut(CONSOLE_UART, '\r'); diff --git a/mongoose.h b/mongoose.h index 5e431391..8757a6d7 100644 --- a/mongoose.h +++ b/mongoose.h @@ -1208,7 +1208,7 @@ int sl_set_ssl_opts(struct mg_connection *nc); #endif /* !defined(__SIMPLELINK_H__) */ -/* COmpatibility with older versions of SimpleLink */ +/* Compatibility with older versions of SimpleLink */ #if SL_MAJOR_VERSION_NUM < 2 #define SL_ERROR_BSD_EAGAIN SL_EAGAIN #define SL_ERROR_BSD_EALREADY SL_EALREADY @@ -1219,6 +1219,13 @@ int sl_set_ssl_opts(struct mg_connection *nc); #define SL_SOCKET_FD_SET SL_FD_SET #define SL_SOCKET_FD_ISSET SL_FD_ISSET #define SL_SO_SECURE_DOMAIN_NAME_VERIFICATION SO_SECURE_DOMAIN_NAME_VERIFICATION + +#define SlDeviceVersion_t SlVersionFull +#define sl_DeviceGet sl_DevGet +#define SL_DEVICE_GENERAL SL_DEVICE_GENERAL_CONFIGURATION +#define SL_DEV_GET_LEN_TYPE _u8 +#else +#define SL_DEV_GET_LEN_TYPE _u16 #endif #endif /* MG_NET_IF == MG_NET_IF_SIMPLELINK */ From f62018451f7868544aee63ff67599ef92a0e8dda Mon Sep 17 00:00:00 2001 From: Deomid Ryabkov Date: Wed, 30 Aug 2017 09:42:24 +0100 Subject: [PATCH 122/137] Fix subscription parsing in MQTT broker Also, do not accept PUBLISH and SUBSCRIBE before a sucessful CONNECT. PUBLISHED_FROM=b5096cdc2ec5da1358244c428efbbb2e20be1a05 --- mongoose.c | 30 +++++++++++++++++++++++------- 1 file changed, 23 insertions(+), 7 deletions(-) diff --git a/mongoose.c b/mongoose.c index d83a2e47..2c81f5df 100644 --- a/mongoose.c +++ b/mongoose.c @@ -10234,15 +10234,16 @@ void mg_mqtt_subscribe(struct mg_connection *nc, int mg_mqtt_next_subscribe_topic(struct mg_mqtt_message *msg, struct mg_str *topic, uint8_t *qos, int pos) { unsigned char *buf = (unsigned char *) msg->payload.p + pos; + int new_pos; - if ((size_t) pos >= msg->payload.len) { - return -1; - } + if ((size_t) pos >= msg->payload.len) return -1; topic->len = buf[0] << 8 | buf[1]; topic->p = (char *) buf + 2; *qos = buf[2 + topic->len]; - return pos + 2 + topic->len + 1; + new_pos = pos + 2 + topic->len + 1; + if ((size_t) new_pos > msg->payload.len) return -1; + return new_pos; } void mg_mqtt_unsubscribe(struct mg_connection *nc, char **topics, @@ -10467,13 +10468,28 @@ void mg_mqtt_broker(struct mg_connection *nc, int ev, void *data) { nc->user_data = NULL; /* Clear up the inherited pointer to broker */ break; case MG_EV_MQTT_CONNECT: - mg_mqtt_broker_handle_connect(brk, nc); + if (nc->user_data == NULL) { + mg_mqtt_broker_handle_connect(brk, nc); + } else { + /* Repeated CONNECT */ + nc->flags |= MG_F_CLOSE_IMMEDIATELY; + } break; case MG_EV_MQTT_SUBSCRIBE: - mg_mqtt_broker_handle_subscribe(nc, msg); + if (nc->user_data != NULL) { + mg_mqtt_broker_handle_subscribe(nc, msg); + } else { + /* Subscribe before CONNECT */ + nc->flags |= MG_F_CLOSE_IMMEDIATELY; + } break; case MG_EV_MQTT_PUBLISH: - mg_mqtt_broker_handle_publish(brk, msg); + if (nc->user_data != NULL) { + mg_mqtt_broker_handle_publish(brk, msg); + } else { + /* Publish before CONNECT */ + nc->flags |= MG_F_CLOSE_IMMEDIATELY; + } break; case MG_EV_CLOSE: if (nc->listener && nc->user_data != NULL) { From d5a9000d466511c36cc3b4e6d49e322d6dbfdc52 Mon Sep 17 00:00:00 2001 From: Deomid Ryabkov Date: Wed, 30 Aug 2017 13:38:51 +0100 Subject: [PATCH 123/137] Harden MQTT parser some more PUBLISHED_FROM=5e7fcc7bf145aa8e1045e8d627b1c0731bb4341b --- mongoose.c | 33 +++++++++++++++++++++++++++------ 1 file changed, 27 insertions(+), 6 deletions(-) diff --git a/mongoose.c b/mongoose.c index 2c81f5df..974a9d7c 100644 --- a/mongoose.c +++ b/mongoose.c @@ -9956,19 +9956,31 @@ MG_INTERNAL int parse_mqtt(struct mbuf *io, struct mg_mqtt_message *mm) { switch (cmd) { case MG_MQTT_CMD_CONNECT: { p = scanto(p, &mm->protocol_name); + if (p > end - 4) return -2; mm->protocol_version = *(uint8_t *) p++; mm->connect_flags = *(uint8_t *) p++; mm->keep_alive_timer = getu16(p); p += 2; - if (p < end) p = scanto(p, &mm->client_id); - if (p < end && (mm->connect_flags & MG_MQTT_HAS_WILL)) + if (p >= end) return -2; + p = scanto(p, &mm->client_id); + if (p > end) return -2; + if (mm->connect_flags & MG_MQTT_HAS_WILL) { + if (p >= end) return -2; p = scanto(p, &mm->will_topic); - if (p < end && (mm->connect_flags & MG_MQTT_HAS_WILL)) + } + if (mm->connect_flags & MG_MQTT_HAS_WILL) { + if (p >= end) return -2; p = scanto(p, &mm->will_message); - if (p < end && (mm->connect_flags & MG_MQTT_HAS_USER_NAME)) + } + if (mm->connect_flags & MG_MQTT_HAS_USER_NAME) { + if (p >= end) return -2; p = scanto(p, &mm->user_name); - if (p < end && (mm->connect_flags & MG_MQTT_HAS_PASSWORD)) + } + if (mm->connect_flags & MG_MQTT_HAS_PASSWORD) { + if (p >= end) return -2; p = scanto(p, &mm->password); + } + if (p != end) return -2; LOG(LL_DEBUG, ("%d %2x %d proto [%.*s] client_id [%.*s] will_topic [%.*s] " @@ -9982,6 +9994,7 @@ MG_INTERNAL int parse_mqtt(struct mbuf *io, struct mg_mqtt_message *mm) { break; } case MG_MQTT_CMD_CONNACK: + if (end - p < 2) return -2; mm->connack_ret_code = p[1]; break; case MG_MQTT_CMD_PUBACK: @@ -9993,7 +10006,9 @@ MG_INTERNAL int parse_mqtt(struct mbuf *io, struct mg_mqtt_message *mm) { break; case MG_MQTT_CMD_PUBLISH: { p = scanto(p, &mm->topic); + if (p > end) return -2; if (mm->qos > 0) { + if (end - p < 2) return -2; mm->message_id = getu16(p); p += 2; } @@ -10002,6 +10017,7 @@ MG_INTERNAL int parse_mqtt(struct mbuf *io, struct mg_mqtt_message *mm) { break; } case MG_MQTT_CMD_SUBSCRIBE: + if (end - p < 2) return -2; mm->message_id = getu16(p); p += 2; /* @@ -10036,7 +10052,12 @@ static void mqtt_handler(struct mg_connection *nc, int ev, /* There can be multiple messages in the buffer, process them all. */ while (1) { int len = parse_mqtt(io, &mm); - if (len == -1) break; /* not fully buffered */ + if (len < 0) { + if (len == -1) break; /* not fully buffered */ + /* Protocol error. */ + nc->flags |= MG_F_CLOSE_IMMEDIATELY; + break; + } nc->handler(nc, MG_MQTT_EVENT_BASE + mm.cmd, &mm MG_UD_ARG(user_data)); mbuf_remove(io, len); } From c7bea65ae7e05d4a810163d4c7dae7615dea59bf Mon Sep 17 00:00:00 2001 From: Deomid Ryabkov Date: Wed, 30 Aug 2017 17:44:36 +0100 Subject: [PATCH 124/137] CC3220 FS support For now, we only support SPIFFS-in-a-box, same as CC3200. On CC3200SF it should be possible to have SPIFFS on built-in flash, but that is left for later. PUBLISHED_FROM=dee337c8cd8ed288c22abe9960eef81e6e90cc4a --- mongoose.c | 48 +++++++++++++++++++++++++++++------------------- mongoose.h | 31 +++++++++++++++++++++++++++++-- 2 files changed, 58 insertions(+), 21 deletions(-) diff --git a/mongoose.c b/mongoose.c index 974a9d7c..5b80e724 100644 --- a/mongoose.c +++ b/mongoose.c @@ -12675,12 +12675,22 @@ void fs_slfs_set_new_file_size(const char *name, size_t size); #if CS_PLATFORM == CS_P_CC3200 #include #endif -#include -#include /* Amalgamated: #include "common/cs_dbg.h" */ /* Amalgamated: #include "common/mg_mem.h" */ +#if SL_MAJOR_VERSION_NUM < 2 +int slfs_open(const unsigned char *fname, uint32_t flags) { + _i32 fh; + _i32 r = sl_FsOpen(fname, flags, NULL /* token */, &fh); + return (r < 0 ? r : fh); +} +#else /* SL_MAJOR_VERSION_NUM >= 2 */ +int slfs_open(const unsigned char *fname, uint32_t flags) { + return sl_FsOpen(fname, flags, NULL /* token */); +} +#endif + /* From sl_fs.c */ int set_errno(int e); const char *drop_dir(const char *fname, bool *is_slfs); @@ -12712,18 +12722,18 @@ static int sl_fs_to_errno(_i32 r) { switch (r) { case SL_FS_OK: return 0; - case SL_FS_FILE_NAME_EXIST: + case SL_ERROR_FS_FILE_NAME_EXIST: return EEXIST; - case SL_FS_WRONG_FILE_NAME: + case SL_ERROR_FS_WRONG_FILE_NAME: return EINVAL; - case SL_FS_ERR_NO_AVAILABLE_NV_INDEX: - case SL_FS_ERR_NO_AVAILABLE_BLOCKS: + case SL_ERROR_FS_NO_AVAILABLE_NV_INDEX: + case SL_ERROR_FS_NOT_ENOUGH_STORAGE_SPACE: return ENOSPC; - case SL_FS_ERR_FAILED_TO_ALLOCATE_MEM: + case SL_ERROR_FS_FAILED_TO_ALLOCATE_MEM: return ENOMEM; - case SL_FS_ERR_FILE_NOT_EXISTS: + case SL_ERROR_FS_FILE_NOT_EXISTS: return ENOENT; - case SL_FS_ERR_NOT_SUPPORTED: + case SL_ERROR_FS_NOT_SUPPORTED: return ENOTSUP; } return ENXIO; @@ -12751,9 +12761,9 @@ int fs_slfs_open(const char *pathname, int flags, mode_t mode) { SlFsFileInfo_t sl_fi; _i32 r = sl_FsGetInfo((const _u8 *) pathname, 0, &sl_fi); if (r == SL_FS_OK) { - fi->size = sl_fi.FileLen; + fi->size = SL_FI_FILE_SIZE(sl_fi); } - am = FS_MODE_OPEN_READ; + am = SL_FS_READ; } else { if (!(flags & O_TRUNC) || (flags & O_APPEND)) { // FailFS files cannot be opened for append and will be truncated @@ -12773,18 +12783,18 @@ int fs_slfs_open(const char *pathname, int flags, mode_t mode) { } am = FS_MODE_OPEN_CREATE(new_size, 0); } else { - am = FS_MODE_OPEN_WRITE; + am = SL_FS_WRITE; } } - _i32 r = sl_FsOpen((_u8 *) pathname, am, NULL, &fi->fh); - LOG(LL_DEBUG, ("sl_FsOpen(%s, 0x%x) sz %u = %d, %d", pathname, (int) am, - (unsigned int) new_size, (int) r, (int) fi->fh)); - if (r == SL_FS_OK) { + fi->fh = slfs_open((_u8 *) pathname, am); + LOG(LL_DEBUG, ("sl_FsOpen(%s, 0x%x) sz %u = %d", pathname, (int) am, + (unsigned int) new_size, (int) fi->fh)); + int r; + if (fi->fh >= 0) { fi->pos = 0; r = fd; } else { - fi->fh = -1; - r = set_errno(sl_fs_to_errno(r)); + r = set_errno(sl_fs_to_errno(fi->fh)); } return r; } @@ -12838,7 +12848,7 @@ int fs_slfs_stat(const char *pathname, struct stat *s) { if (r == SL_FS_OK) { s->st_mode = S_IFREG | 0666; s->st_nlink = 1; - s->st_size = sl_fi.FileLen; + s->st_size = SL_FI_FILE_SIZE(sl_fi); return 0; } return set_errno(sl_fs_to_errno(r)); diff --git a/mongoose.h b/mongoose.h index 8757a6d7..d62fc888 100644 --- a/mongoose.h +++ b/mongoose.h @@ -1210,23 +1210,50 @@ int sl_set_ssl_opts(struct mg_connection *nc); /* Compatibility with older versions of SimpleLink */ #if SL_MAJOR_VERSION_NUM < 2 + #define SL_ERROR_BSD_EAGAIN SL_EAGAIN #define SL_ERROR_BSD_EALREADY SL_EALREADY #define SL_ERROR_BSD_ENOPROTOOPT SL_ENOPROTOOPT #define SL_ERROR_BSD_ESECDATEERROR SL_ESECDATEERROR #define SL_ERROR_BSD_ESECSNOVERIFY SL_ESECSNOVERIFY +#define SL_ERROR_FS_FAILED_TO_ALLOCATE_MEM SL_FS_ERR_FAILED_TO_ALLOCATE_MEM +#define SL_ERROR_FS_FILE_HAS_NOT_BEEN_CLOSE_CORRECTLY \ + SL_FS_FILE_HAS_NOT_BEEN_CLOSE_CORRECTLY +#define SL_ERROR_FS_FILE_NAME_EXIST SL_FS_FILE_NAME_EXIST +#define SL_ERROR_FS_FILE_NOT_EXISTS SL_FS_ERR_FILE_NOT_EXISTS +#define SL_ERROR_FS_NO_AVAILABLE_NV_INDEX SL_FS_ERR_NO_AVAILABLE_NV_INDEX +#define SL_ERROR_FS_NOT_ENOUGH_STORAGE_SPACE SL_FS_ERR_NO_AVAILABLE_BLOCKS +#define SL_ERROR_FS_NOT_SUPPORTED SL_FS_ERR_NOT_SUPPORTED +#define SL_ERROR_FS_WRONG_FILE_NAME SL_FS_WRONG_FILE_NAME +#define SL_ERROR_FS_INVALID_HANDLE SL_FS_ERR_INVALID_HANDLE #define SL_SOCKET_FD_ZERO SL_FD_ZERO #define SL_SOCKET_FD_SET SL_FD_SET #define SL_SOCKET_FD_ISSET SL_FD_ISSET #define SL_SO_SECURE_DOMAIN_NAME_VERIFICATION SO_SECURE_DOMAIN_NAME_VERIFICATION +#define SL_FS_READ FS_MODE_OPEN_READ +#define SL_FS_WRITE FS_MODE_OPEN_WRITE + +#define SL_FI_FILE_SIZE(fi) ((fi).FileLen) +#define SL_FI_FILE_MAX_SIZE(fi) ((fi).AllocatedLen) + #define SlDeviceVersion_t SlVersionFull #define sl_DeviceGet sl_DevGet #define SL_DEVICE_GENERAL SL_DEVICE_GENERAL_CONFIGURATION #define SL_DEV_GET_LEN_TYPE _u8 -#else + +#else /* SL_MAJOR_VERSION_NUM >= 2 */ + +#define FS_MODE_OPEN_CREATE(max_size, flag) \ + (SL_FS_CREATE | SL_FS_CREATE_MAX_SIZE(max_size)) +#define SL_FI_FILE_SIZE(fi) ((fi).Len) +#define SL_FI_FILE_MAX_SIZE(fi) ((fi).MaxSize) + #define SL_DEV_GET_LEN_TYPE _u16 -#endif + +#endif /* SL_MAJOR_VERSION_NUM < 2 */ + +int slfs_open(const unsigned char *fname, uint32_t flags); #endif /* MG_NET_IF == MG_NET_IF_SIMPLELINK */ From 202300952ceab6d166990ba47dae880bedfad59d Mon Sep 17 00:00:00 2001 From: Deomid Ryabkov Date: Wed, 30 Aug 2017 18:38:24 +0100 Subject: [PATCH 125/137] CC3220: GPIO, sys_config and mgos_init support ``` Using port /dev/ttyACM0 [Aug 30 19:33:02.105] [Aug 30 19:33:02.114] cc32xx_init c_no_libs 1.0 (20170830-163205/mos8@6587ffd6+) [Aug 30 19:33:02.123] cc32xx_init Mongoose OS 2017083016 (20170830-163205/mos8@6587ffd6+) [Aug 30 19:33:02.130] cc32xx_init RAM: 253588 total, 240044 free [Aug 30 19:33:04.430] cc32xx_start_nwp NWP v3.4.0.0 started, host driver v2.0.1.19 [Aug 30 19:33:04.437] mgos_vfs_dev_open slfs_container ({"prefix": "spiffs.img.0"}) -> 20005a64 [Aug 30 19:33:04.450] cc32xx_vfs_dev_slfs_ 20005a64 spiffs.img.0.0 262144 0xfffffffffffffffe [Aug 30 19:33:04.457] mgos_vfs_mount Mount SPIFFS @ / (dev 20005a64, opts ) -> 20005a74 [Aug 30 19:33:06.102] mgos_vfs_mount /: size 233681, used: 4016, free: 229665 [Aug 30 19:33:06.108] mgos_vfs_mount Mount SLFS @ /slfs (dev 0, opts ) -> 20005ed4 [Aug 30 19:33:06.114] mgos_vfs_mount /slfs: size 0, used: 0, free: 0 [Aug 30 19:33:06.718] mgos_sys_config_init MAC: 04A316459442 [Aug 30 19:33:06.720] mgos_sys_config_init WDT: 30 seconds [Aug 30 19:33:06.724] Hello, world! [Aug 30 19:33:06.728] mgos_init Init done, RAM: 253588 total, 236544 free, 235864 min free ``` PUBLISHED_FROM=7e83c9ddcc642bd324a40e125d6636ece824fb18 --- mongoose.h | 1 + 1 file changed, 1 insertion(+) diff --git a/mongoose.h b/mongoose.h index d62fc888..667835ed 100644 --- a/mongoose.h +++ b/mongoose.h @@ -1226,6 +1226,7 @@ int sl_set_ssl_opts(struct mg_connection *nc); #define SL_ERROR_FS_NOT_SUPPORTED SL_FS_ERR_NOT_SUPPORTED #define SL_ERROR_FS_WRONG_FILE_NAME SL_FS_WRONG_FILE_NAME #define SL_ERROR_FS_INVALID_HANDLE SL_FS_ERR_INVALID_HANDLE +#define SL_NETCFG_MAC_ADDRESS_GET SL_MAC_ADDRESS_GET #define SL_SOCKET_FD_ZERO SL_FD_ZERO #define SL_SOCKET_FD_SET SL_FD_SET #define SL_SOCKET_FD_ISSET SL_FD_ISSET From eb5645241c85028d019ee154900215e79b22e2a9 Mon Sep 17 00:00:00 2001 From: Deomid Ryabkov Date: Thu, 31 Aug 2017 18:23:11 +0300 Subject: [PATCH 126/137] CC3220: WiFi, basic networking support PUBLISHED_FROM=db89a45a536f0234d6d5cf740354c0dbeeff1f26 --- mongoose.h | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/mongoose.h b/mongoose.h index 667835ed..9e6f3a3f 100644 --- a/mongoose.h +++ b/mongoose.h @@ -1241,7 +1241,8 @@ int sl_set_ssl_opts(struct mg_connection *nc); #define SlDeviceVersion_t SlVersionFull #define sl_DeviceGet sl_DevGet #define SL_DEVICE_GENERAL SL_DEVICE_GENERAL_CONFIGURATION -#define SL_DEV_GET_LEN_TYPE _u8 +#define SL_LEN_TYPE _u8 +#define SL_OPT_TYPE _u8 #else /* SL_MAJOR_VERSION_NUM >= 2 */ @@ -1250,7 +1251,8 @@ int sl_set_ssl_opts(struct mg_connection *nc); #define SL_FI_FILE_SIZE(fi) ((fi).Len) #define SL_FI_FILE_MAX_SIZE(fi) ((fi).MaxSize) -#define SL_DEV_GET_LEN_TYPE _u16 +#define SL_LEN_TYPE _u16 +#define SL_OPT_TYPE _u16 #endif /* SL_MAJOR_VERSION_NUM < 2 */ From 177e05deb28b8eaa5ce5d65b2bbfb8d88cc6b4f1 Mon Sep 17 00:00:00 2001 From: Deomid Ryabkov Date: Fri, 1 Sep 2017 00:35:11 +0300 Subject: [PATCH 127/137] CC3220: AWS connection works PUBLISHED_FROM=5831462c5be0b79afff32130a1f45784f32bc524 --- mongoose.c | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/mongoose.c b/mongoose.c index 5b80e724..402cd6ff 100644 --- a/mongoose.c +++ b/mongoose.c @@ -13699,7 +13699,15 @@ void mg_mgr_handle_conn(struct mg_connection *nc, int fd_flags, double now) { DBG(("%p conn res=%d", nc, nc->err)); if (nc->err == SL_ERROR_BSD_ESECSNOVERIFY || /* TODO(rojer): Provide API to set the date for verification. */ - nc->err == SL_ERROR_BSD_ESECDATEERROR) { + nc->err == SL_ERROR_BSD_ESECDATEERROR +#if SL_MAJOR_VERSION_NUM >= 2 + /* Per SWRU455, this error does not mean verification failed, + * it only means that the cert used is not present in the trusted + * root CA catalog. Which is perfectly fine. */ + || + nc->err == SL_ERROR_BSD_ESECUNKNOWNROOTCA +#endif + ) { nc->err = 0; } if (nc->flags & MG_F_SSL && nc->err == 0) { From abf89d32d9434f3b3eed74dc2b61f2434ea51fcb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=9D=D0=B0=D1=88=D0=B5=20=D0=B2=D0=B0=D0=BC=20=D1=81=20?= =?UTF-8?q?=D0=BA=D0=B8=D1=81=D1=82=D0=BE=D1=87=D0=BA=D0=BE=D0=B9?= Date: Fri, 1 Sep 2017 09:26:14 +0100 Subject: [PATCH 128/137] Make C ws client work with Go PUBLISHED_FROM=263553121b992ec0f66b0275b4e10f4176281812 --- mongoose.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/mongoose.c b/mongoose.c index 402cd6ff..b1278dfe 100644 --- a/mongoose.c +++ b/mongoose.c @@ -8036,7 +8036,7 @@ struct mg_connection *mg_connect_http_opt( mg_printf(nc, "%s %.*s HTTP/1.1\r\nHost: %.*s\r\nContent-Length: %" SIZE_T_FMT "\r\n%.*s%s\r\n%s", (post_data[0] == '\0' ? "GET" : "POST"), (int) path.len, path.p, - (int) host.len, host.p, strlen(post_data), (int) auth.len, + (int) (path.p - host.p), host.p, strlen(post_data), (int) auth.len, (auth.buf == NULL ? "" : auth.buf), extra_headers, post_data); mbuf_free(&auth); @@ -9511,7 +9511,8 @@ void mg_send_websocket_handshake3v(struct mg_connection *nc, /* TODO(mkm): take default hostname from http proto data if host == NULL */ if (host.len > 0) { - mg_printf(nc, "Host: %.*s\r\n", (int) host.len, host.p); + int host_len = (int) (path.p - host.p); /* Account for possible :PORT */ + mg_printf(nc, "Host: %.*s\r\n", host_len, host.p); } if (protocol.len > 0) { mg_printf(nc, "Sec-WebSocket-Protocol: %.*s\r\n", (int) protocol.len, From 77e44c7c0e0538d7c85d7870dc3ffad0c4508ae4 Mon Sep 17 00:00:00 2001 From: Deomid Ryabkov Date: Wed, 6 Sep 2017 14:37:33 +0300 Subject: [PATCH 129/137] Harden MQTT variable length parsing PUBLISHED_FROM=e16ee57bc30277e5b5684e53da78e69baaf9f779 --- mongoose.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/mongoose.c b/mongoose.c index b1278dfe..dbe21386 100644 --- a/mongoose.c +++ b/mongoose.c @@ -9943,11 +9943,12 @@ MG_INTERNAL int parse_mqtt(struct mbuf *io, struct mg_mqtt_message *mm) { lc = *((const unsigned char *) p++); len += (lc & 0x7f) << 7 * len_len; len_len++; - if (!(lc & 0x80) || (len_len > sizeof(len))) break; + if (!(lc & 0x80)) break; + if (len_len > 4) return -2; } end = p + len; - if (lc & 0x80 || end > io->buf + io->len) { + if (lc & 0x80 || len > (io->len - (p - io->buf))) { return -1; } From 97d733e129b9f9c624472bc423c21affebd8aca0 Mon Sep 17 00:00:00 2001 From: Deomid Ryabkov Date: Wed, 6 Sep 2017 13:49:35 +0100 Subject: [PATCH 130/137] Fix MQTT broker SUBSCRIBE request parsing Add checks on the number of subscribe requests per packet and overall per-session subscription limit. PUBLISHED_FROM=faaf5c50af31a0694c9308a664f2e418dbb0eb18 --- mongoose.c | 24 ++++++++++++++++++------ mongoose.h | 4 +++- 2 files changed, 21 insertions(+), 7 deletions(-) diff --git a/mongoose.c b/mongoose.c index dbe21386..8de1a665 100644 --- a/mongoose.c +++ b/mongoose.c @@ -10424,8 +10424,8 @@ static void mg_mqtt_broker_handle_connect(struct mg_mqtt_broker *brk, static void mg_mqtt_broker_handle_subscribe(struct mg_connection *nc, struct mg_mqtt_message *msg) { struct mg_mqtt_session *ss = (struct mg_mqtt_session *) nc->user_data; - uint8_t qoss[512]; - size_t qoss_len = 0; + uint8_t qoss[MG_MQTT_MAX_SESSION_SUBSCRIPTIONS]; + size_t num_subs = 0; struct mg_str topic; uint8_t qos; int pos; @@ -10433,11 +10433,23 @@ static void mg_mqtt_broker_handle_subscribe(struct mg_connection *nc, for (pos = 0; (pos = mg_mqtt_next_subscribe_topic(msg, &topic, &qos, pos)) != -1;) { - qoss[qoss_len++] = qos; + if (num_subs >= sizeof(MG_MQTT_MAX_SESSION_SUBSCRIPTIONS) || + (ss->num_subscriptions + num_subs >= + MG_MQTT_MAX_SESSION_SUBSCRIPTIONS)) { + nc->flags |= MG_F_CLOSE_IMMEDIATELY; + return; + } + qoss[num_subs++] = qos; } - ss->subscriptions = (struct mg_mqtt_topic_expression *) MG_REALLOC( - ss->subscriptions, sizeof(*ss->subscriptions) * qoss_len); + te = (struct mg_mqtt_topic_expression *) MG_REALLOC( + ss->subscriptions, + sizeof(*ss->subscriptions) * (ss->num_subscriptions + num_subs)); + if (te == NULL) { + nc->flags |= MG_F_CLOSE_IMMEDIATELY; + return; + } + ss->subscriptions = te; for (pos = 0; (pos = mg_mqtt_next_subscribe_topic(msg, &topic, &qos, pos)) != -1; ss->num_subscriptions++) { @@ -10447,7 +10459,7 @@ static void mg_mqtt_broker_handle_subscribe(struct mg_connection *nc, strncpy((char *) te->topic, topic.p, topic.len + 1); } - mg_mqtt_suback(nc, qoss, qoss_len, msg->message_id); + mg_mqtt_suback(nc, qoss, num_subs, msg->message_id); } static void mg_mqtt_broker_handle_publish(struct mg_mqtt_broker *brk, diff --git a/mongoose.h b/mongoose.h index 9e6f3a3f..78482c2e 100644 --- a/mongoose.h +++ b/mongoose.h @@ -5380,7 +5380,9 @@ int mg_mqtt_vmatch_topic_expression(const char *exp, struct mg_str topic); extern "C" { #endif /* __cplusplus */ -#define MG_MQTT_MAX_SESSION_SUBSCRIPTIONS 512; +#ifndef MG_MQTT_MAX_SESSION_SUBSCRIPTIONS +#define MG_MQTT_MAX_SESSION_SUBSCRIPTIONS 512 +#endif struct mg_mqtt_broker; From f857f6394f80d1846f13721cf6f761d25d41cc58 Mon Sep 17 00:00:00 2001 From: Deomid Ryabkov Date: Wed, 6 Sep 2017 18:22:34 +0300 Subject: [PATCH 131/137] Access QoS field after validating topic length PUBLISHED_FROM=6f2d9849d75ca1ec2b6dade11ccad8d0c5d4b3bd --- mongoose.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mongoose.c b/mongoose.c index 8de1a665..5e8193a4 100644 --- a/mongoose.c +++ b/mongoose.c @@ -10263,9 +10263,9 @@ int mg_mqtt_next_subscribe_topic(struct mg_mqtt_message *msg, topic->len = buf[0] << 8 | buf[1]; topic->p = (char *) buf + 2; - *qos = buf[2 + topic->len]; new_pos = pos + 2 + topic->len + 1; if ((size_t) new_pos > msg->payload.len) return -1; + *qos = buf[2 + topic->len]; return new_pos; } From c8af7cdd2740ecf89e927c1a26437e4c29d5ae6e Mon Sep 17 00:00:00 2001 From: Deomid Ryabkov Date: Wed, 6 Sep 2017 18:25:27 +0100 Subject: [PATCH 132/137] Check for int overflow when parsing WS frames PUBLISHED_FROM=b7325b38e881455df703b0b628c41931565ccb33 --- mongoose.c | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/mongoose.c b/mongoose.c index 5e8193a4..c573e7aa 100644 --- a/mongoose.c +++ b/mongoose.c @@ -9204,7 +9204,13 @@ static int mg_deliver_websocket_data(struct mg_connection *nc) { } frame_len = header_len + data_len; - ok = frame_len > 0 && frame_len <= buf_len; + ok = (frame_len > 0 && frame_len <= buf_len); + + /* Check for overflow */ + if (frame_len < header_len || frame_len < data_len) { + ok = 0; + nc->flags |= MG_F_CLOSE_IMMEDIATELY; + } if (ok) { struct websocket_message wsm; From 2fa18b47db9ef17f1d1b3742c06bb25c0384bb54 Mon Sep 17 00:00:00 2001 From: Deomid Ryabkov Date: Wed, 6 Sep 2017 20:54:38 +0300 Subject: [PATCH 133/137] Fix DNS name uncompression PUBLISHED_FROM=07e820f539fa5feca2ad1cf81faca8404b773a65 --- mongoose.c | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/mongoose.c b/mongoose.c index c573e7aa..b3959e1a 100644 --- a/mongoose.c +++ b/mongoose.c @@ -10835,7 +10835,7 @@ int mg_parse_dns(const char *buf, int len, struct mg_dns_message *msg) { size_t mg_dns_uncompress_name(struct mg_dns_message *msg, struct mg_str *name, char *dst, int dst_len) { - int chunk_len; + int chunk_len, num_ptrs = 0; char *old_dst = dst; const unsigned char *data = (unsigned char *) name->p; const unsigned char *end = (unsigned char *) msg->pkt.p + msg->pkt.len; @@ -10850,14 +10850,21 @@ size_t mg_dns_uncompress_name(struct mg_dns_message *msg, struct mg_str *name, return 0; } - if (chunk_len & 0xc0) { + if ((chunk_len & 0xc0) == 0xc0) { uint16_t off = (data[-1] & (~0xc0)) << 8 | data[0]; if (off >= msg->pkt.len) { return 0; } + /* Basic circular loop avoidance: allow up to 16 pointer hops. */ + if (++num_ptrs > 15) { + return 0; + } data = (unsigned char *) msg->pkt.p + off; continue; } + if (chunk_len > 63) { + return 0; + } if (chunk_len > leeway) { chunk_len = leeway; } From 2b2816cfe43c74056f8bba6da008e3252febb5fd Mon Sep 17 00:00:00 2001 From: Deomid Ryabkov Date: Wed, 6 Sep 2017 21:55:14 +0300 Subject: [PATCH 134/137] Store reassembled WS frame length in proto_data PUBLISHED_FROM=7bbe7dd20dca8435c786dca30200a4973ae0827d --- mongoose.c | 41 +++++++++++++++++++++++++++-------------- 1 file changed, 27 insertions(+), 14 deletions(-) diff --git a/mongoose.c b/mongoose.c index b3959e1a..bfe18678 100644 --- a/mongoose.c +++ b/mongoose.c @@ -5344,6 +5344,10 @@ struct mg_reverse_proxy_data { struct mg_connection *linked_conn; }; +struct mg_ws_proto_data { + size_t reass_len; /* Defragmented size of the frame so far. */ +}; + struct mg_http_proto_data { #if MG_ENABLE_FILESYSTEM struct mg_http_proto_data_file file; @@ -5353,6 +5357,9 @@ struct mg_http_proto_data { #endif #if MG_ENABLE_HTTP_STREAMING_MULTIPART struct mg_http_multipart_stream mp_stream; +#endif +#if MG_ENABLE_HTTP_WEBSOCKET + struct mg_ws_proto_data ws_data; #endif struct mg_http_proto_data_chuncked chunk; struct mg_http_endpoint *endpoints; @@ -9169,27 +9176,32 @@ static void mg_handle_incoming_websocket_frame(struct mg_connection *nc, } } +static struct mg_ws_proto_data *mg_ws_get_proto_data(struct mg_connection *nc) { + struct mg_http_proto_data *htd = mg_http_get_proto_data(nc); + return (htd != NULL ? &htd->ws_data : NULL); +}; + static int mg_deliver_websocket_data(struct mg_connection *nc) { /* Using unsigned char *, cause of integer arithmetic below */ uint64_t i, data_len = 0, frame_len = 0, buf_len = nc->recv_mbuf.len, len, mask_len = 0, header_len = 0; unsigned char *p = (unsigned char *) nc->recv_mbuf.buf, *buf = p, *e = p + buf_len; - unsigned *sizep = (unsigned *) &p[1]; /* Size ptr for defragmented frames */ + struct mg_ws_proto_data *wsd = mg_ws_get_proto_data(nc); int ok; int reass = buf_len > 0 && mg_is_ws_fragment(p[0]) && !(nc->flags & MG_F_WEBSOCKET_NO_DEFRAG); /* If that's a continuation frame that must be reassembled, handle it */ - if (reass && !mg_is_ws_first_fragment(p[0]) && - buf_len >= 1 + sizeof(*sizep) && buf_len >= 1 + sizeof(*sizep) + *sizep) { - buf += 1 + sizeof(*sizep) + *sizep; - buf_len -= 1 + sizeof(*sizep) + *sizep; + if (reass && !mg_is_ws_first_fragment(p[0]) && buf_len >= 1 && + buf_len >= 1 + wsd->reass_len) { + buf += 1 + wsd->reass_len; + buf_len -= 1 + wsd->reass_len; } if (buf_len >= 2) { - len = buf[1] & 127; - mask_len = buf[1] & 128 ? 4 : 0; + len = buf[1] & 0x7f; + mask_len = buf[1] & 0x80 ? 4 : 0; if (len < 126 && buf_len >= mask_len) { data_len = len; header_len = 2 + mask_len; @@ -9229,28 +9241,29 @@ static int mg_deliver_websocket_data(struct mg_connection *nc) { if (reass) { /* On first fragmented frame, nullify size */ if (mg_is_ws_first_fragment(wsm.flags)) { - mbuf_resize(&nc->recv_mbuf, nc->recv_mbuf.size + sizeof(*sizep)); p[0] &= ~0x0f; /* Next frames will be treated as continuation */ - buf = p + 1 + sizeof(*sizep); - *sizep = 0; /* TODO(lsm): fix. this can stomp over frame data */ + buf = p + 1; + wsd->reass_len = 0; } /* Append this frame to the reassembled buffer */ memmove(buf, wsm.data, e - wsm.data); - (*sizep) += wsm.size; + wsd->reass_len += wsm.size; nc->recv_mbuf.len -= wsm.data - buf; /* On last fragmented frame - call user handler and remove data */ if (wsm.flags & 0x80) { - wsm.data = p + 1 + sizeof(*sizep); - wsm.size = *sizep; + wsm.data = p + 1; + wsm.size = wsd->reass_len; mg_handle_incoming_websocket_frame(nc, &wsm); - mbuf_remove(&nc->recv_mbuf, 1 + sizeof(*sizep) + *sizep); + mbuf_remove(&nc->recv_mbuf, 1 + wsd->reass_len); + wsd->reass_len = 0; } } else { /* TODO(lsm): properly handle OOB control frames during defragmentation */ mg_handle_incoming_websocket_frame(nc, &wsm); mbuf_remove(&nc->recv_mbuf, (size_t) frame_len); /* Cleanup frame */ + wsd->reass_len = 0; } /* If the frame is not reassembled - client closes and close too */ From 3d6b568c6e7ddb05a76c336069d6e7ed75cc178b Mon Sep 17 00:00:00 2001 From: Deomid Ryabkov Date: Thu, 7 Sep 2017 13:51:08 +0300 Subject: [PATCH 135/137] Prefer ECDHE with CBC over DHE ciphersuites PUBLISHED_FROM=4ddfc25af77247fac7e7d04cc0e56d6f3800f87b --- mongoose.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/mongoose.c b/mongoose.c index bfe18678..d7599397 100644 --- a/mongoose.c +++ b/mongoose.c @@ -4898,7 +4898,9 @@ static enum mg_ssl_if_result mg_use_cert(struct mg_ssl_if_ctx *ctx, static const int mg_s_cipher_list[] = { MBEDTLS_TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256, + MBEDTLS_TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256, MBEDTLS_TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256, + MBEDTLS_TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256, MBEDTLS_TLS_DHE_RSA_WITH_AES_128_GCM_SHA256, MBEDTLS_TLS_DHE_RSA_WITH_AES_128_CBC_SHA256, MBEDTLS_TLS_ECDH_ECDSA_WITH_AES_128_GCM_SHA256, From 0aaba7a461341916f61929e0a8ea871055d8dd73 Mon Sep 17 00:00:00 2001 From: Dmitry Frank Date: Tue, 12 Sep 2017 19:08:43 +0300 Subject: [PATCH 136/137] Add cs_timegm Which is a slightly modified version from https://stackoverflow.com/questions/283166/easy-way-to-convert-a-struct-tm-expressed-in-utc-to-time-t-type PUBLISHED_FROM=b73f920ca42c45473c23337782e815306bdf69f1 --- mongoose.c | 35 +++++++++++++++++++++++++++++++++++ mongoose.h | 8 ++++++++ 2 files changed, 43 insertions(+) diff --git a/mongoose.c b/mongoose.c index d7599397..b3461bf7 100644 --- a/mongoose.c +++ b/mongoose.c @@ -780,6 +780,41 @@ double cs_time(void) { #endif /* _WIN32 */ return now; } + +double cs_timegm(const struct tm *tm) { + /* Month-to-day offset for non-leap-years. */ + static const int month_day[12] = {0, 31, 59, 90, 120, 151, + 181, 212, 243, 273, 304, 334}; + + /* Most of the calculation is easy; leap years are the main difficulty. */ + int month = tm->tm_mon % 12; + int year = tm->tm_year + tm->tm_mon / 12; + int year_for_leap; + int64_t rt; + + if (month < 0) { /* Negative values % 12 are still negative. */ + month += 12; + --year; + } + + /* This is the number of Februaries since 1900. */ + year_for_leap = (month > 1) ? year + 1 : year; + + rt = + tm->tm_sec /* Seconds */ + + + 60 * + (tm->tm_min /* Minute = 60 seconds */ + + + 60 * (tm->tm_hour /* Hour = 60 minutes */ + + + 24 * (month_day[month] + tm->tm_mday - 1 /* Day = 24 hours */ + + 365 * (year - 70) /* Year = 365 days */ + + (year_for_leap - 69) / 4 /* Every 4 years is leap... */ + - (year_for_leap - 1) / 100 /* Except centuries... */ + + (year_for_leap + 299) / 400))); /* Except 400s. */ + return rt < 0 ? -1 : (double) rt; +} #ifdef MG_MODULE_LINES #line 1 "common/cs_endian.h" #endif diff --git a/mongoose.h b/mongoose.h index 78482c2e..2822d9bc 100644 --- a/mongoose.h +++ b/mongoose.h @@ -1797,6 +1797,8 @@ void cs_hmac_sha1(const unsigned char *key, size_t key_len, #ifndef CS_COMMON_CS_TIME_H_ #define CS_COMMON_CS_TIME_H_ +#include + /* Amalgamated: #include "common/platform.h" */ #ifdef __cplusplus @@ -1806,6 +1808,12 @@ extern "C" { /* Sub-second granularity time(). */ double cs_time(void); +/* + * Similar to (non-standard) timegm, converts broken-down time into the number + * of seconds since Unix Epoch. + */ +double cs_timegm(const struct tm *tm); + #ifdef __cplusplus } #endif /* __cplusplus */ From 9d30e892e944bc665725faad34d8a18f2e9bf674 Mon Sep 17 00:00:00 2001 From: Deomid Ryabkov Date: Wed, 13 Sep 2017 12:08:04 +0300 Subject: [PATCH 137/137] Mongoose 6.8 PUBLISHED_FROM=082d0bf5e9b06b850382ce502c7f5b4d68a6a328 --- mongoose.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mongoose.h b/mongoose.h index 2822d9bc..73176345 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.7" +#define MG_VERSION "6.8" /* Local tweaks, applied before any of Mongoose's own headers. */ #ifdef MG_LOCALS