diff --git a/docs/c-api/mbuf.h/intro.md b/docs/c-api/mbuf.h/intro.md
index 475c65104b..056369a243 100644
--- a/docs/c-api/mbuf.h/intro.md
+++ b/docs/c-api/mbuf.h/intro.md
@@ -1,5 +1,5 @@
---
-title: "Memory Buffers"
+title: "mbuf.h"
symbol_kind: "intro"
decl_name: "mbuf.h"
items:
diff --git a/docs/c-api/mg_net.h/mg_mgr_free.md b/docs/c-api/mg_net.h/mg_mgr_free.md
index d2df34e4c2..60ad75bdc5 100644
--- a/docs/c-api/mg_net.h/mg_mgr_free.md
+++ b/docs/c-api/mg_net.h/mg_mgr_free.md
@@ -3,7 +3,7 @@ title: "mg_mgr_free()"
decl_name: "mg_mgr_free"
symbol_kind: "func"
signature: |
- void mg_mgr_free(struct mg_mgr *);
+ void mg_mgr_free(struct mg_mgr *mgr);
---
De-initialises Mongoose manager.
diff --git a/docs/c-api/mg_net.h/mg_mgr_poll.md b/docs/c-api/mg_net.h/mg_mgr_poll.md
index b70c31b6db..ef48a19082 100644
--- a/docs/c-api/mg_net.h/mg_mgr_poll.md
+++ b/docs/c-api/mg_net.h/mg_mgr_poll.md
@@ -3,11 +3,11 @@ title: "mg_mgr_poll()"
decl_name: "mg_mgr_poll"
symbol_kind: "func"
signature: |
- time_t mg_mgr_poll(struct mg_mgr *, int milli);
+ int mg_mgr_poll(struct mg_mgr *mgr, int milli);
---
This function performs the actual IO and must be called in a loop
-(an event loop). It returns the current timestamp.
+(an event loop). It returns number of user events generated (except POLLs).
`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
diff --git a/docs/c-api/mg_net.h/struct_mg_mgr.md b/docs/c-api/mg_net.h/struct_mg_mgr.md
index d33727c38d..44efa5fdf2 100644
--- a/docs/c-api/mg_net.h/struct_mg_mgr.md
+++ b/docs/c-api/mg_net.h/struct_mg_mgr.md
@@ -13,6 +13,7 @@ signature: |
#endif
void *user_data; /* User data */
int num_ifaces;
+ int num_calls;
struct mg_iface **ifaces; /* network interfaces */
const char *nameserver; /* DNS server to use */
};
diff --git a/docs/overview/conn-flags.md b/docs/overview/conn-flags.md
index aeb642ab98..b2ed2a74fc 100644
--- a/docs/overview/conn-flags.md
+++ b/docs/overview/conn-flags.md
@@ -7,7 +7,7 @@ flags are meant to be set only by the user event handler to tell Mongoose how to
behave. Below is a list of connection flags that are meant to be set by event
handlers:
-* `MG_F_FINISHED_SENDING_DATA` tells Mongoose that all data has been appended
+* `MG_F_SEND_AND_CLOSE` tells Mongoose that all data has been appended
to the `send_mbuf`. As soon as Mongoose sends it to the socket, the
connection will be closed.
* `MG_F_BUFFER_BUT_DONT_SEND` tells Mongoose to append data to the `send_mbuf`
diff --git a/mongoose.c b/mongoose.c
index d11756499c..3174523a23 100644
--- a/mongoose.c
+++ b/mongoose.c
@@ -2408,6 +2408,7 @@ MG_INTERNAL void mg_call(struct mg_connection *nc,
(nc->flags & _MG_CALLBACK_MODIFIABLE_FLAGS_MASK);
}
}
+ if (ev != MG_EV_POLL) nc->mgr->num_calls++;
if (ev != MG_EV_POLL) {
DBG(("%p after %s flags=0x%lx rmbl=%d smbl=%d", nc,
ev_handler == nc->handler ? "user" : "proto", nc->flags,
@@ -2585,19 +2586,14 @@ void mg_mgr_free(struct mg_mgr *m) {
MG_FREE((char *) m->nameserver);
}
-time_t mg_mgr_poll(struct mg_mgr *m, int timeout_ms) {
- int i;
- time_t now = 0; /* oh GCC, seriously ? */
-
- if (m->num_ifaces == 0) {
- LOG(LL_ERROR, ("cannot poll: no interfaces"));
- return 0;
- }
+int mg_mgr_poll(struct mg_mgr *m, int timeout_ms) {
+ int i, num_calls_before = m->num_calls;
for (i = 0; i < m->num_ifaces; i++) {
- now = m->ifaces[i]->vtable->poll(m->ifaces[i], timeout_ms);
+ m->ifaces[i]->vtable->poll(m->ifaces[i], timeout_ms);
}
- return now;
+
+ return (m->num_calls - num_calls_before);
}
int mg_vprintf(struct mg_connection *nc, const char *fmt, va_list ap) {
@@ -2801,7 +2797,6 @@ MG_INTERNAL void mg_ssl_handshake(struct mg_connection *nc) {
enum mg_ssl_if_result res;
if (nc->flags & MG_F_SSL_HANDSHAKE_DONE) return;
res = mg_ssl_if_handshake(nc);
- LOG(LL_DEBUG, ("%p %d res %d", nc, server_side, res));
if (res == MG_SSL_OK) {
nc->flags |= MG_F_SSL_HANDSHAKE_DONE;
@@ -2932,10 +2927,12 @@ static int mg_recv_tcp(struct mg_connection *nc, char *buf, size_t len) {
mg_hexdump_connection(nc, nc->mgr->hexdump_file, buf, n, MG_EV_RECV);
}
#endif
+ mbuf_trim(&nc->recv_mbuf);
mg_call(nc, NULL, nc->user_data, MG_EV_RECV, &n);
} else if (n < 0) {
nc->flags |= MG_F_CLOSE_IMMEDIATELY;
}
+ mbuf_trim(&nc->recv_mbuf);
return n;
}
@@ -3047,7 +3044,7 @@ void mg_if_can_send_cb(struct mg_connection *nc) {
}
} else
#endif
- {
+ if (len > 0) {
if (nc->flags & MG_F_UDP) {
n = nc->iface->vtable->udp_send(nc, buf, len);
} else {
@@ -3585,6 +3582,162 @@ struct mg_iface *mg_find_iface(struct mg_mgr *mgr,
}
return NULL;
}
+
+double mg_mgr_min_timer(const struct mg_mgr *mgr) {
+ double min_timer = 0;
+ struct mg_connection *nc;
+ for (nc = mgr->active_connections; nc != NULL; nc = nc->next) {
+ if (nc->ev_timer_time <= 0) continue;
+ if (min_timer == 0 || nc->ev_timer_time < min_timer) {
+ min_timer = nc->ev_timer_time;
+ }
+ }
+ return min_timer;
+}
+#ifdef MG_MODULE_LINES
+#line 1 "mongoose/src/mg_net_if_null.c"
+#endif
+/*
+ * Copyright (c) 2018 Cesanta Software Limited
+ * All rights reserved
+ *
+ * This software is dual-licensed: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation. For the terms of this
+ * license, see .
+ *
+ * You are free to use this software under the terms of the GNU General
+ * Public License, but WITHOUT ANY WARRANTY; without even the implied
+ * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ * See the GNU General Public License for more details.
+ *
+ * Alternatively, you can license this software under a commercial
+ * license, as set out in .
+ */
+
+static void mg_null_if_connect_tcp(struct mg_connection *c,
+ const union socket_address *sa) {
+ c->flags |= MG_F_CLOSE_IMMEDIATELY;
+ (void) sa;
+}
+
+static void mg_null_if_connect_udp(struct mg_connection *c) {
+ c->flags |= MG_F_CLOSE_IMMEDIATELY;
+}
+
+static int mg_null_if_listen_tcp(struct mg_connection *c,
+ union socket_address *sa) {
+ (void) c;
+ (void) sa;
+ return -1;
+}
+
+static int mg_null_if_listen_udp(struct mg_connection *c,
+ union socket_address *sa) {
+ (void) c;
+ (void) sa;
+ return -1;
+}
+
+static int mg_null_if_tcp_send(struct mg_connection *c, const void *buf,
+ size_t len) {
+ (void) c;
+ (void) buf;
+ (void) len;
+ return -1;
+}
+
+static int mg_null_if_udp_send(struct mg_connection *c, const void *buf,
+ size_t len) {
+ (void) c;
+ (void) buf;
+ (void) len;
+ return -1;
+}
+
+int mg_null_if_tcp_recv(struct mg_connection *c, void *buf, size_t len) {
+ (void) c;
+ (void) buf;
+ (void) len;
+ return -1;
+}
+
+int mg_null_if_udp_recv(struct mg_connection *c, void *buf, size_t len,
+ union socket_address *sa, size_t *sa_len) {
+ (void) c;
+ (void) buf;
+ (void) len;
+ (void) sa;
+ (void) sa_len;
+ return -1;
+}
+
+static int mg_null_if_create_conn(struct mg_connection *c) {
+ (void) c;
+ return 1;
+}
+
+static void mg_null_if_destroy_conn(struct mg_connection *c) {
+ (void) c;
+}
+
+static void mg_null_if_sock_set(struct mg_connection *c, sock_t sock) {
+ (void) c;
+ (void) sock;
+}
+
+static void mg_null_if_init(struct mg_iface *iface) {
+ (void) iface;
+}
+
+static void mg_null_if_free(struct mg_iface *iface) {
+ (void) iface;
+}
+
+static void mg_null_if_add_conn(struct mg_connection *c) {
+ c->sock = INVALID_SOCKET;
+ c->flags |= MG_F_CLOSE_IMMEDIATELY;
+}
+
+static void mg_null_if_remove_conn(struct mg_connection *c) {
+ (void) c;
+}
+
+static time_t mg_null_if_poll(struct mg_iface *iface, int timeout_ms) {
+ struct mg_mgr *mgr = iface->mgr;
+ struct mg_connection *nc, *tmp;
+ double now = mg_time();
+ /* We basically just run timers and poll. */
+ for (nc = mgr->active_connections; nc != NULL; nc = tmp) {
+ tmp = nc->next;
+ mg_if_poll(nc, now);
+ }
+ (void) timeout_ms;
+ return (time_t) now;
+}
+
+static void mg_null_if_get_conn_addr(struct mg_connection *c, int remote,
+ union socket_address *sa) {
+ (void) c;
+ (void) remote;
+ (void) sa;
+}
+
+#define MG_NULL_IFACE_VTABLE \
+ { \
+ mg_null_if_init, mg_null_if_free, mg_null_if_add_conn, \
+ mg_null_if_remove_conn, mg_null_if_poll, mg_null_if_listen_tcp, \
+ mg_null_if_listen_udp, mg_null_if_connect_tcp, mg_null_if_connect_udp, \
+ mg_null_if_tcp_send, mg_null_if_udp_send, mg_null_if_tcp_recv, \
+ mg_null_if_udp_recv, mg_null_if_create_conn, mg_null_if_destroy_conn, \
+ mg_null_if_sock_set, mg_null_if_get_conn_addr, \
+ }
+
+const struct mg_iface_vtable mg_null_iface_vtable = MG_NULL_IFACE_VTABLE;
+
+#if MG_NET_IF == MG_NET_IF_NULL
+const struct mg_iface_vtable mg_default_iface_vtable = MG_NULL_IFACE_VTABLE;
+#endif /* MG_NET_IF == MG_NET_IF_NULL */
#ifdef MG_MODULE_LINES
#line 1 "mongoose/src/mg_net_if_socket.c"
#endif
@@ -4847,6 +5000,8 @@ static void mg_ssl_mbed_log(void *ctx, int level, const char *file, int line,
}
/* mbedTLS passes strings with \n at the end, strip it. */
LOG(cs_level, ("%p %.*s", ctx, (int) (strlen(str) - 1), str));
+ (void) ctx;
+ (void) str;
(void) file;
(void) line;
(void) cs_level;
@@ -5036,9 +5191,9 @@ 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;
+ if (ctx->conf->ca_chain_file != NULL) {
+ MG_FREE((void *) ctx->conf->ca_chain_file);
+ ctx->conf->ca_chain_file = NULL;
}
#endif
mbedtls_x509_crt_free(ctx->ca_cert);
@@ -5145,15 +5300,13 @@ static enum mg_ssl_if_result mg_use_ca_cert(struct mg_ssl_if_ctx *ctx,
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;
- }
+ mbedtls_ssl_conf_ca_chain_file(ctx->conf, ca_cert, NULL);
#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);
+#endif
mbedtls_ssl_conf_authmode(ctx->conf, MBEDTLS_SSL_VERIFY_REQUIRED);
return MG_SSL_OK;
}
@@ -6155,6 +6308,10 @@ static size_t mg_http_parse_chunk(char *buf, size_t len, char **chunk_data,
n *= 16;
n += (s[i] >= '0' && s[i] <= '9') ? s[i] - '0' : tolower(s[i]) - 'a' + 10;
i++;
+ if (i > 6) {
+ /* Chunk size is unreasonable. */
+ return 0;
+ }
}
/* Skip new line */
@@ -6460,6 +6617,7 @@ void mg_http_handler(struct mg_connection *nc, int ev,
}
} else {
/* We did receive all HTTP body. */
+ int request_done = 1;
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),
@@ -6471,8 +6629,28 @@ void mg_http_handler(struct mg_connection *nc, int ev,
mg_http_call_endpoint_handler(nc, trigger_ev, hm);
mbuf_remove(io, hm->message.len);
pd->rcvd -= hm->message.len;
- if (io->len > 0) {
- goto again;
+#if MG_ENABLE_FILESYSTEM
+ /* We don't have a generic mechanism of communicating that we are done
+ * responding to a request (should probably add one). But if we are
+ * serving
+ * a file, we are definitely not done. */
+ if (pd->file.fp != NULL) request_done = 0;
+#endif
+#if MG_ENABLE_HTTP_CGI
+ /* If this is a CGI request, we are not done either. */
+ if (pd->cgi.cgi_nc != NULL) request_done = 0;
+#endif
+ if (request_done) {
+ /* This request is done but we may receive another on this connection.
+ */
+ mg_http_conn_destructor(pd);
+ nc->proto_data = NULL;
+ if (io->len > 0) {
+ /* We already have data for the next one, restart parsing. */
+ pd = mg_http_get_proto_data(nc);
+ pd->rcvd = io->len;
+ goto again;
+ }
}
}
}
@@ -8328,7 +8506,7 @@ void mg_file_upload_handler(struct mg_connection *nc, int ev, void *ev_data,
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");
+ fus->fp = mg_fopen(fus->lfn, "wb");
if (fus->fp == NULL) {
mg_printf(nc,
"HTTP/1.1 500 Internal Server Error\r\n"
@@ -11812,7 +11990,9 @@ static void mg_resolve_async_eh(struct mg_connection *nc, int ev,
void *user_data = nc->user_data;
#endif
- if (ev != MG_EV_POLL) DBG(("ev=%d user_data=%p", ev, user_data));
+ if (ev != MG_EV_POLL) {
+ DBG(("ev=%d user_data=%p", ev, user_data));
+ }
req = (struct mg_resolve_async_request *) user_data;
@@ -15024,6 +15204,7 @@ static err_t mg_lwip_tcp_recv_cb(void *arg, struct tcp_pcb *tpcb,
}
mg_lwip_recv_common(nc, p);
mgos_unlock();
+ (void) err;
return ERR_OK;
}
@@ -15036,6 +15217,10 @@ static err_t mg_lwip_tcp_sent_cb(void *arg, struct tcp_pcb *tpcb,
nc->send_mbuf.len == 0 && tpcb->unsent == NULL && tpcb->unacked == NULL) {
mg_lwip_post_signal(MG_SIG_CLOSE_CONN, nc);
}
+ if (nc->send_mbuf.len > 0 || (nc->flags & MG_F_WANT_WRITE)) {
+ mg_lwip_mgr_schedule_poll(nc->mgr);
+ }
+ (void) num_sent;
return ERR_OK;
}
@@ -15397,6 +15582,10 @@ static int mg_lwip_if_can_send(struct mg_connection *nc,
can_send = (cs->pcb.udp != NULL);
} else {
can_send = (cs->pcb.tcp != NULL && cs->pcb.tcp->snd_buf > 0);
+/* See comment above. */
+#if CS_PLATFORM == CS_P_ESP8266
+ if (cs->pcb.tcp->unacked != NULL) can_send = 0;
+#endif
}
}
return can_send;
@@ -15716,38 +15905,6 @@ time_t mg_lwip_if_poll(struct mg_iface *iface, int timeout_ms) {
return now;
}
-uint32_t mg_lwip_get_poll_delay_ms(struct mg_mgr *mgr) {
- struct mg_connection *nc;
- double now;
- double min_timer = 0;
- int num_timers = 0;
- mg_ev_mgr_lwip_process_signals(mgr);
- for (nc = mg_next(mgr, NULL); nc != NULL; nc = mg_next(mgr, nc)) {
- struct mg_lwip_conn_state *cs = (struct mg_lwip_conn_state *) nc->sock;
- if (nc->ev_timer_time > 0) {
- if (num_timers == 0 || nc->ev_timer_time < min_timer) {
- min_timer = nc->ev_timer_time;
- }
- num_timers++;
- }
- /* We want and can send data, request a poll immediately. */
- if (nc->sock != INVALID_SOCKET && mg_lwip_if_can_send(nc, cs)) {
- return 0;
- }
- }
- uint32_t timeout_ms = ~0;
- 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;
- }
- }
- return timeout_ms;
-}
-
#endif /* MG_NET_IF == MG_NET_IF_LWIP_LOW_LEVEL */
#ifdef MG_MODULE_LINES
#line 1 "common/platforms/wince/wince_libc.c"
diff --git a/mongoose.h b/mongoose.h
index 2667c75905..8fe13cd60d 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.12"
+#define MG_VERSION "6.13"
/* Local tweaks, applied before any of Mongoose's own headers. */
#ifdef MG_LOCALS
@@ -105,6 +105,7 @@
#define MG_NET_IF_SIMPLELINK 2
#define MG_NET_IF_LWIP_LOW_LEVEL 3
#define MG_NET_IF_PIC32 4
+#define MG_NET_IF_NULL 5
#define MG_SSL_IF_OPENSSL 1
#define MG_SSL_IF_MBEDTLS 2
@@ -1944,7 +1945,7 @@ char *inet_ntoa(struct in_addr in);
#include
#define to64(x) strtoll(x, NULL, 10)
-#define INT64_FMT PRId64
+#define INT64_FMT "lld"
#define SIZE_T_FMT "u"
typedef struct stat cs_stat_t;
#define DIRSEP '/'
@@ -2030,7 +2031,6 @@ 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
@@ -2312,8 +2312,6 @@ struct mg_str mg_strstrip(struct mg_str s);
*/
/*
- * === 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
@@ -3718,6 +3716,12 @@ void mg_if_recv_udp_cb(struct mg_connection *nc, void *buf, int len,
/* Deliver a POLL event to the connection. */
int mg_if_poll(struct mg_connection *nc, double now);
+/*
+ * Return minimal timer value amoung connections in the manager.
+ * Returns 0 if there aren't any timers.
+ */
+double mg_mgr_min_timer(const struct mg_mgr *mgr);
+
#ifdef __cplusplus
}
#endif /* __cplusplus */
@@ -3875,6 +3879,7 @@ struct mg_mgr {
#endif
void *user_data; /* User data */
int num_ifaces;
+ int num_calls;
struct mg_iface **ifaces; /* network interfaces */
const char *nameserver; /* DNS server to use */
};
@@ -3987,17 +3992,17 @@ void mg_mgr_init_opt(struct mg_mgr *mgr, void *user_data,
*
* Closes and deallocates all active connections.
*/
-void mg_mgr_free(struct mg_mgr *);
+void mg_mgr_free(struct mg_mgr *mgr);
/*
* This function performs the actual IO and must be called in a loop
- * (an event loop). It returns the current timestamp.
+ * (an event loop). It returns number of user events generated (except POLLs).
* `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);
+int mg_mgr_poll(struct mg_mgr *mgr, int milli);
#if MG_ENABLE_BROADCAST
/*
diff --git a/src/common/platform.h b/src/common/platform.h
index 1b803c9e6a..af0b4f501b 100644
--- a/src/common/platform.h
+++ b/src/common/platform.h
@@ -69,6 +69,7 @@
#define MG_NET_IF_SIMPLELINK 2
#define MG_NET_IF_LWIP_LOW_LEVEL 3
#define MG_NET_IF_PIC32 4
+#define MG_NET_IF_NULL 5
#define MG_SSL_IF_OPENSSL 1
#define MG_SSL_IF_MBEDTLS 2
diff --git a/src/common/platforms/arm/arm_exc.c b/src/common/platforms/arm/arm_exc.c
index 7f83b3cc4b..606ae5ebbe 100644
--- a/src/common/platforms/arm/arm_exc.c
+++ b/src/common/platforms/arm/arm_exc.c
@@ -27,6 +27,10 @@
#include "mgos_core_dump.h"
#include "mgos_hal.h"
+#ifndef MGOS_ENABLE_CORE_DUMP
+#define MGOS_ENABLE_CORE_DUMP 1
+#endif
+
struct arm_exc_frame {
uint32_t r0;
uint32_t r1;
@@ -53,7 +57,7 @@ struct arm_gdb_reg_file {
uint32_t fpscr;
} __attribute__((packed));
-#if ARM_HAVE_FPU
+#if ARM_HAVE_FPU && !defined(MGOS_BOOT_BUILD)
static void save_s16_s31(uint32_t *dst) {
__asm volatile(
"\
@@ -91,6 +95,7 @@ void arm_exc_handler_bottom(uint8_t isr_no, struct arm_exc_frame *ef,
struct arm_gdb_reg_file *rf) {
char buf[8];
const char *name;
+ (void) ef;
portDISABLE_INTERRUPTS();
switch (isr_no) {
case 0:
@@ -134,16 +139,20 @@ void arm_exc_handler_bottom(uint8_t isr_no, struct arm_exc_frame *ef,
name = "SysTick";
break;
default: {
+#ifndef MGOS_BOOT_BUILD
sprintf(buf, "IRQ%u", isr_no - 16);
+#endif
name = buf;
}
}
mgos_cd_printf("\n\n--- Exception %u (%s) ---\n", isr_no, name);
if (rf != NULL) {
- mgos_cd_printf(" R0: 0x%08lx R1: 0x%08lx R2: 0x%08lx R3: 0x%08lx\n",
- rf->r[0], rf->r[1], rf->r[2], rf->r[3]);
- mgos_cd_printf(" R4: 0x%08lx R5: 0x%08lx R6: 0x%08lx R7: 0x%08lx\n",
- rf->r[4], rf->r[5], rf->r[6], rf->r[7]);
+ mgos_cd_printf(
+ " R%d: 0x%08lx R%d: 0x%08lx R%d: 0x%08lx R%d: 0x%08lx\n", 0,
+ rf->r[0], 1, rf->r[1], 2, rf->r[2], 3, rf->r[3]);
+ mgos_cd_printf(
+ " R%d: 0x%08lx R%d: 0x%08lx R%d: 0x%08lx R%d: 0x%08lx\n", 4,
+ rf->r[4], 5, rf->r[5], 6, rf->r[6], 7, rf->r[7]);
mgos_cd_printf(" R8: 0x%08lx R9: 0x%08lx R10: 0x%08lx R11: 0x%08lx\n",
rf->r[8], rf->r[9], rf->r[10], rf->r[11]);
mgos_cd_printf(" R12: 0x%08lx SP: 0x%08lx LR: 0x%08lx PC: 0x%08lx\n",
@@ -151,7 +160,7 @@ void arm_exc_handler_bottom(uint8_t isr_no, struct arm_exc_frame *ef,
mgos_cd_printf(" PSR: 0x%08lx\n", rf->cpsr);
}
memset(rf->d, 0, sizeof(rf->d));
-#if ARM_HAVE_FPU
+#if ARM_HAVE_FPU && !defined(MGOS_BOOT_BUILD)
rf->fpscr = ef->fpscr;
memcpy((uint8_t *) rf->d, ef->s, sizeof(ef->s));
print_fpu_regs((uint32_t *) rf->d, 0, ARRAY_SIZE(ef->s));
@@ -164,10 +173,12 @@ void arm_exc_handler_bottom(uint8_t isr_no, struct arm_exc_frame *ef,
#else
rf->fpscr = 0;
#endif
+#if MGOS_ENABLE_CORE_DUMP
mgos_cd_emit_header();
mgos_cd_emit_section(MGOS_CORE_DUMP_SECTION_REGS, rf, sizeof(*rf));
mgos_cd_emit_section("SRAM", (void *) SRAM_BASE_ADDR, SRAM_SIZE);
mgos_cd_emit_footer();
+#endif
#ifdef MGOS_HALT_ON_EXCEPTION
mgos_cd_printf("Halting\n");
while (1) {
diff --git a/src/common/platforms/cc3200/gcc.mk b/src/common/platforms/cc3200/gcc.mk
index ec98b75f1d..4f39e78965 100644
--- a/src/common/platforms/cc3200/gcc.mk
+++ b/src/common/platforms/cc3200/gcc.mk
@@ -29,11 +29,11 @@ $(SDK_OBJS): CFLAGS += -include common/platform.h
# cc flags,file
define cc
- $(vecho) "GCC $2 -> $@"
+ $(vecho) "GCC $2"
$(Q) $(CC_WRAPPER) $(CC) -c $1 -o $@ $2
endef
define cxx
- $(vecho) "G++ $2 -> $@"
+ $(vecho) "G++ $2"
$(Q) $(CC_WRAPPER) $(CXX) -c $1 -o $@ $2
endef
diff --git a/src/common/platforms/cc3200/ti.mk b/src/common/platforms/cc3200/ti.mk
index b50407f8e4..cbfc2f1761 100644
--- a/src/common/platforms/cc3200/ti.mk
+++ b/src/common/platforms/cc3200/ti.mk
@@ -17,17 +17,17 @@ CXXFLAGS += $(TI_C_CXX_FLAGS) $(C_CXX_FLAGS)
# cc flags,file
define cc
- $(vecho) "TICC $2 -> $@"
+ $(vecho) "TICC $2"
$(Q) $(CC_WRAPPER) $(CC) -c --preproc_with_compile -ppd=$@.d $1 --output_file=$@ $2
endef
define cxx
- $(vecho) "TICXX $2 -> $@"
+ $(vecho) "TICXX $2"
$(Q) $(CC_WRAPPER) $(CC) -c --preproc_with_compile -ppd=$@.d $1 --output_file=$@ $2
endef
# asm flags,file
define asm
- $(vecho) "TIASM $2 -> $@"
+ $(vecho) "TIASM $2"
$(Q) $(CC_WRAPPER) $(CC) -c $1 --output_file=$@ $2
endef
diff --git a/src/common/platforms/esp8266/esp_crypto.c b/src/common/platforms/esp8266/esp_crypto.c
index 6469cae0f0..ab8e97e2a6 100644
--- a/src/common/platforms/esp8266/esp_crypto.c
+++ b/src/common/platforms/esp8266/esp_crypto.c
@@ -44,80 +44,3 @@ void mg_hash_sha1_v(size_t num_msgs, const uint8_t *msgs[],
const size_t *msg_lens, uint8_t *digest) {
(void) sha1_vector(num_msgs, msgs, msg_lens, digest);
}
-
-#if MG_ENABLE_SSL
-
-#include "mbedtls/aes.h"
-#include "mbedtls/sha256.h"
-
-#define AES_PRIV_NR_POS (4 * 15)
-
-/*
- * Crypto functions in ROM/SDK.
- * They come from wpa_supplicant, you can find them here https://w1.fi/cgit/
- *
- * Note that ROM version of the key setup function is older, does not take the
- * number of bits argument and only supports AES-128. This prototype doesn't
- * suit it, but since the difference is in the last aegument, it doesn't matter.
- */
-
-extern void rijndaelKeySetupDec(void *ctx, const uint8_t *key, int bits);
-extern int rijndaelKeySetupEnc(void *ctx, const uint8_t *key, int bits);
-void aes_encrypt(void *ctx, const uint8_t *plain, uint8_t *crypt);
-void aes_decrypt(void *ctx, const uint8_t *crypt, uint8_t *plain);
-
-/*
- * AES that comes with wpa_supplicant allocates its own AES context in
- * aes_{encrypt,decrypt}_init. Ideally, we'd take that pointer and store it in
- * our mbedtls_aes_context, but then a lot of space would be wasted.
- * We do not call _init and go directly to key setup functions and poke number
- * of rounds into the right place too. This is a bit hacky, but works fine.
- * There is also a difference between older function in ROM and the one coming
- * with SDK which is newer: the older one actually takes two arguments, not 3.
- * But it doesn't matter, extra argument doesn't hurt and this works with both.
- */
-int mbedtls_aes_setkey_enc(mbedtls_aes_context *ctx, const unsigned char *key,
- unsigned int keybits) {
- if (keybits != 128) return MBEDTLS_ERR_AES_INVALID_KEY_LENGTH;
- ((uint32_t *) ctx)[AES_PRIV_NR_POS] = 10;
- rijndaelKeySetupEnc(ctx, key, 128);
- return 0;
-}
-
-int mbedtls_aes_setkey_dec(mbedtls_aes_context *ctx, const unsigned char *key,
- unsigned int keybits) {
- if (keybits != 128) return MBEDTLS_ERR_AES_INVALID_KEY_LENGTH;
- ((uint32_t *) ctx)[AES_PRIV_NR_POS] = 10;
- rijndaelKeySetupDec(ctx, key, 128);
- return 0;
-}
-
-int mbedtls_internal_aes_encrypt(mbedtls_aes_context *ctx,
- const unsigned char input[16],
- unsigned char output[16]) {
- aes_encrypt(ctx, input, output);
- return 0;
-}
-
-int mbedtls_internal_aes_decrypt(mbedtls_aes_context *ctx,
- const unsigned char input[16],
- unsigned char output[16]) {
- aes_decrypt(ctx, input, output);
- return 0;
-}
-
-/* os_get_random uses hardware RNG, so it's cool. */
-int mg_ssl_if_mbed_random(void *ctx, unsigned char *buf, size_t len) {
- os_get_random(buf, len);
- (void) ctx;
- return 0;
-}
-
-/* For CryptoAuthLib host crypto. */
-int atcac_sw_sha2_256(const uint8_t *data, size_t data_size,
- uint8_t digest[32]) {
- mbedtls_sha256(data, data_size, digest, false /* is_224 */);
- return 0;
-}
-
-#endif /* MG_ENABLE_SSL */
diff --git a/src/common/platforms/lwip/mg_lwip.h b/src/common/platforms/lwip/mg_lwip.h
index c0d4081e88..c15e2ee2db 100644
--- a/src/common/platforms/lwip/mg_lwip.h
+++ b/src/common/platforms/lwip/mg_lwip.h
@@ -66,7 +66,6 @@ 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
diff --git a/src/common/platforms/lwip/mg_lwip_ev_mgr.c b/src/common/platforms/lwip/mg_lwip_ev_mgr.c
index 39937fc919..b495464e91 100644
--- a/src/common/platforms/lwip/mg_lwip_ev_mgr.c
+++ b/src/common/platforms/lwip/mg_lwip_ev_mgr.c
@@ -167,36 +167,4 @@ time_t mg_lwip_if_poll(struct mg_iface *iface, int timeout_ms) {
return now;
}
-uint32_t mg_lwip_get_poll_delay_ms(struct mg_mgr *mgr) {
- struct mg_connection *nc;
- double now;
- double min_timer = 0;
- int num_timers = 0;
- mg_ev_mgr_lwip_process_signals(mgr);
- for (nc = mg_next(mgr, NULL); nc != NULL; nc = mg_next(mgr, nc)) {
- struct mg_lwip_conn_state *cs = (struct mg_lwip_conn_state *) nc->sock;
- if (nc->ev_timer_time > 0) {
- if (num_timers == 0 || nc->ev_timer_time < min_timer) {
- min_timer = nc->ev_timer_time;
- }
- num_timers++;
- }
- /* We want and can send data, request a poll immediately. */
- if (nc->sock != INVALID_SOCKET && mg_lwip_if_can_send(nc, cs)) {
- return 0;
- }
- }
- uint32_t timeout_ms = ~0;
- 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;
- }
- }
- return timeout_ms;
-}
-
#endif /* MG_NET_IF == MG_NET_IF_LWIP_LOW_LEVEL */
diff --git a/src/common/platforms/lwip/mg_lwip_net_if.c b/src/common/platforms/lwip/mg_lwip_net_if.c
index c6cbf492b3..d077702915 100644
--- a/src/common/platforms/lwip/mg_lwip_net_if.c
+++ b/src/common/platforms/lwip/mg_lwip_net_if.c
@@ -187,6 +187,7 @@ static err_t mg_lwip_tcp_recv_cb(void *arg, struct tcp_pcb *tpcb,
}
mg_lwip_recv_common(nc, p);
mgos_unlock();
+ (void) err;
return ERR_OK;
}
@@ -199,6 +200,10 @@ static err_t mg_lwip_tcp_sent_cb(void *arg, struct tcp_pcb *tpcb,
nc->send_mbuf.len == 0 && tpcb->unsent == NULL && tpcb->unacked == NULL) {
mg_lwip_post_signal(MG_SIG_CLOSE_CONN, nc);
}
+ if (nc->send_mbuf.len > 0 || (nc->flags & MG_F_WANT_WRITE)) {
+ mg_lwip_mgr_schedule_poll(nc->mgr);
+ }
+ (void) num_sent;
return ERR_OK;
}
@@ -560,6 +565,10 @@ static int mg_lwip_if_can_send(struct mg_connection *nc,
can_send = (cs->pcb.udp != NULL);
} else {
can_send = (cs->pcb.tcp != NULL && cs->pcb.tcp->snd_buf > 0);
+/* See comment above. */
+#if CS_PLATFORM == CS_P_ESP8266
+ if (cs->pcb.tcp->unacked != NULL) can_send = 0;
+#endif
}
}
return can_send;
diff --git a/src/common/platforms/platform_stm32.h b/src/common/platforms/platform_stm32.h
index 6b937569e4..d5b8919238 100644
--- a/src/common/platforms/platform_stm32.h
+++ b/src/common/platforms/platform_stm32.h
@@ -34,7 +34,7 @@
#include
#define to64(x) strtoll(x, NULL, 10)
-#define INT64_FMT PRId64
+#define INT64_FMT "lld"
#define SIZE_T_FMT "u"
typedef struct stat cs_stat_t;
#define DIRSEP '/'
diff --git a/src/mg_common.h b/src/mg_common.h
index adb99e8f1e..69900255aa 100644
--- a/src/mg_common.h
+++ b/src/mg_common.h
@@ -20,7 +20,7 @@
#ifndef CS_MONGOOSE_SRC_COMMON_H_
#define CS_MONGOOSE_SRC_COMMON_H_
-#define MG_VERSION "6.12"
+#define MG_VERSION "6.13"
/* Local tweaks, applied before any of Mongoose's own headers. */
#ifdef MG_LOCALS
diff --git a/src/mg_http.c b/src/mg_http.c
index 257bde4ceb..f8161a4b47 100644
--- a/src/mg_http.c
+++ b/src/mg_http.c
@@ -564,6 +564,10 @@ static size_t mg_http_parse_chunk(char *buf, size_t len, char **chunk_data,
n *= 16;
n += (s[i] >= '0' && s[i] <= '9') ? s[i] - '0' : tolower(s[i]) - 'a' + 10;
i++;
+ if (i > 6) {
+ /* Chunk size is unreasonable. */
+ return 0;
+ }
}
/* Skip new line */
@@ -869,6 +873,7 @@ void mg_http_handler(struct mg_connection *nc, int ev,
}
} else {
/* We did receive all HTTP body. */
+ int request_done = 1;
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),
@@ -880,8 +885,28 @@ void mg_http_handler(struct mg_connection *nc, int ev,
mg_http_call_endpoint_handler(nc, trigger_ev, hm);
mbuf_remove(io, hm->message.len);
pd->rcvd -= hm->message.len;
- if (io->len > 0) {
- goto again;
+#if MG_ENABLE_FILESYSTEM
+ /* We don't have a generic mechanism of communicating that we are done
+ * responding to a request (should probably add one). But if we are
+ * serving
+ * a file, we are definitely not done. */
+ if (pd->file.fp != NULL) request_done = 0;
+#endif
+#if MG_ENABLE_HTTP_CGI
+ /* If this is a CGI request, we are not done either. */
+ if (pd->cgi.cgi_nc != NULL) request_done = 0;
+#endif
+ if (request_done) {
+ /* This request is done but we may receive another on this connection.
+ */
+ mg_http_conn_destructor(pd);
+ nc->proto_data = NULL;
+ if (io->len > 0) {
+ /* We already have data for the next one, restart parsing. */
+ pd = mg_http_get_proto_data(nc);
+ pd->rcvd = io->len;
+ goto again;
+ }
}
}
}
@@ -2737,7 +2762,7 @@ void mg_file_upload_handler(struct mg_connection *nc, int ev, void *ev_data,
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");
+ fus->fp = mg_fopen(fus->lfn, "wb");
if (fus->fp == NULL) {
mg_printf(nc,
"HTTP/1.1 500 Internal Server Error\r\n"
diff --git a/src/mg_modules.mk b/src/mg_modules.mk
index 4bc7602609..b53c53b1bf 100644
--- a/src/mg_modules.mk
+++ b/src/mg_modules.mk
@@ -64,6 +64,7 @@ SOURCES = $(COMMON)/mg_mem.h \
mg_net_if_socket.h \
mg_net_if_socks.h \
mg_net_if.c \
+ mg_net_if_null.c \
mg_net_if_socket.c \
mg_net_if_socks.c \
mg_ssl_if_openssl.c \
diff --git a/src/mg_net.c b/src/mg_net.c
index 5c96140914..97afe9ab56 100644
--- a/src/mg_net.c
+++ b/src/mg_net.c
@@ -99,6 +99,7 @@ MG_INTERNAL void mg_call(struct mg_connection *nc,
(nc->flags & _MG_CALLBACK_MODIFIABLE_FLAGS_MASK);
}
}
+ if (ev != MG_EV_POLL) nc->mgr->num_calls++;
if (ev != MG_EV_POLL) {
DBG(("%p after %s flags=0x%lx rmbl=%d smbl=%d", nc,
ev_handler == nc->handler ? "user" : "proto", nc->flags,
@@ -276,19 +277,14 @@ void mg_mgr_free(struct mg_mgr *m) {
MG_FREE((char *) m->nameserver);
}
-time_t mg_mgr_poll(struct mg_mgr *m, int timeout_ms) {
- int i;
- time_t now = 0; /* oh GCC, seriously ? */
-
- if (m->num_ifaces == 0) {
- LOG(LL_ERROR, ("cannot poll: no interfaces"));
- return 0;
- }
+int mg_mgr_poll(struct mg_mgr *m, int timeout_ms) {
+ int i, num_calls_before = m->num_calls;
for (i = 0; i < m->num_ifaces; i++) {
- now = m->ifaces[i]->vtable->poll(m->ifaces[i], timeout_ms);
+ m->ifaces[i]->vtable->poll(m->ifaces[i], timeout_ms);
}
- return now;
+
+ return (m->num_calls - num_calls_before);
}
int mg_vprintf(struct mg_connection *nc, const char *fmt, va_list ap) {
@@ -492,7 +488,6 @@ MG_INTERNAL void mg_ssl_handshake(struct mg_connection *nc) {
enum mg_ssl_if_result res;
if (nc->flags & MG_F_SSL_HANDSHAKE_DONE) return;
res = mg_ssl_if_handshake(nc);
- LOG(LL_DEBUG, ("%p %d res %d", nc, server_side, res));
if (res == MG_SSL_OK) {
nc->flags |= MG_F_SSL_HANDSHAKE_DONE;
@@ -623,10 +618,12 @@ static int mg_recv_tcp(struct mg_connection *nc, char *buf, size_t len) {
mg_hexdump_connection(nc, nc->mgr->hexdump_file, buf, n, MG_EV_RECV);
}
#endif
+ mbuf_trim(&nc->recv_mbuf);
mg_call(nc, NULL, nc->user_data, MG_EV_RECV, &n);
} else if (n < 0) {
nc->flags |= MG_F_CLOSE_IMMEDIATELY;
}
+ mbuf_trim(&nc->recv_mbuf);
return n;
}
@@ -738,7 +735,7 @@ void mg_if_can_send_cb(struct mg_connection *nc) {
}
} else
#endif
- {
+ if (len > 0) {
if (nc->flags & MG_F_UDP) {
n = nc->iface->vtable->udp_send(nc, buf, len);
} else {
diff --git a/src/mg_net.h b/src/mg_net.h
index 90b42b47af..d854e770a2 100644
--- a/src/mg_net.h
+++ b/src/mg_net.h
@@ -89,6 +89,7 @@ struct mg_mgr {
#endif
void *user_data; /* User data */
int num_ifaces;
+ int num_calls;
struct mg_iface **ifaces; /* network interfaces */
const char *nameserver; /* DNS server to use */
};
@@ -201,17 +202,17 @@ void mg_mgr_init_opt(struct mg_mgr *mgr, void *user_data,
*
* Closes and deallocates all active connections.
*/
-void mg_mgr_free(struct mg_mgr *);
+void mg_mgr_free(struct mg_mgr *mgr);
/*
* This function performs the actual IO and must be called in a loop
- * (an event loop). It returns the current timestamp.
+ * (an event loop). It returns number of user events generated (except POLLs).
* `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);
+int mg_mgr_poll(struct mg_mgr *mgr, int milli);
#if MG_ENABLE_BROADCAST
/*
diff --git a/src/mg_net_if.c b/src/mg_net_if.c
index 2a93dcfd4a..c91feb9960 100644
--- a/src/mg_net_if.c
+++ b/src/mg_net_if.c
@@ -39,3 +39,15 @@ struct mg_iface *mg_find_iface(struct mg_mgr *mgr,
}
return NULL;
}
+
+double mg_mgr_min_timer(const struct mg_mgr *mgr) {
+ double min_timer = 0;
+ struct mg_connection *nc;
+ for (nc = mgr->active_connections; nc != NULL; nc = nc->next) {
+ if (nc->ev_timer_time <= 0) continue;
+ if (min_timer == 0 || nc->ev_timer_time < min_timer) {
+ min_timer = nc->ev_timer_time;
+ }
+ }
+ return min_timer;
+}
diff --git a/src/mg_net_if.h b/src/mg_net_if.h
index cba58fb95f..1239d54a0a 100644
--- a/src/mg_net_if.h
+++ b/src/mg_net_if.h
@@ -118,6 +118,12 @@ void mg_if_recv_udp_cb(struct mg_connection *nc, void *buf, int len,
/* Deliver a POLL event to the connection. */
int mg_if_poll(struct mg_connection *nc, double now);
+/*
+ * Return minimal timer value amoung connections in the manager.
+ * Returns 0 if there aren't any timers.
+ */
+double mg_mgr_min_timer(const struct mg_mgr *mgr);
+
#ifdef __cplusplus
}
#endif /* __cplusplus */
diff --git a/src/mg_net_if_null.c b/src/mg_net_if_null.c
new file mode 100644
index 0000000000..cf8bbaa103
--- /dev/null
+++ b/src/mg_net_if_null.c
@@ -0,0 +1,141 @@
+/*
+ * Copyright (c) 2018 Cesanta Software Limited
+ * All rights reserved
+ *
+ * This software is dual-licensed: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation. For the terms of this
+ * license, see .
+ *
+ * You are free to use this software under the terms of the GNU General
+ * Public License, but WITHOUT ANY WARRANTY; without even the implied
+ * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ * See the GNU General Public License for more details.
+ *
+ * Alternatively, you can license this software under a commercial
+ * license, as set out in .
+ */
+
+static void mg_null_if_connect_tcp(struct mg_connection *c,
+ const union socket_address *sa) {
+ c->flags |= MG_F_CLOSE_IMMEDIATELY;
+ (void) sa;
+}
+
+static void mg_null_if_connect_udp(struct mg_connection *c) {
+ c->flags |= MG_F_CLOSE_IMMEDIATELY;
+}
+
+static int mg_null_if_listen_tcp(struct mg_connection *c,
+ union socket_address *sa) {
+ (void) c;
+ (void) sa;
+ return -1;
+}
+
+static int mg_null_if_listen_udp(struct mg_connection *c,
+ union socket_address *sa) {
+ (void) c;
+ (void) sa;
+ return -1;
+}
+
+static int mg_null_if_tcp_send(struct mg_connection *c, const void *buf,
+ size_t len) {
+ (void) c;
+ (void) buf;
+ (void) len;
+ return -1;
+}
+
+static int mg_null_if_udp_send(struct mg_connection *c, const void *buf,
+ size_t len) {
+ (void) c;
+ (void) buf;
+ (void) len;
+ return -1;
+}
+
+int mg_null_if_tcp_recv(struct mg_connection *c, void *buf, size_t len) {
+ (void) c;
+ (void) buf;
+ (void) len;
+ return -1;
+}
+
+int mg_null_if_udp_recv(struct mg_connection *c, void *buf, size_t len,
+ union socket_address *sa, size_t *sa_len) {
+ (void) c;
+ (void) buf;
+ (void) len;
+ (void) sa;
+ (void) sa_len;
+ return -1;
+}
+
+static int mg_null_if_create_conn(struct mg_connection *c) {
+ (void) c;
+ return 1;
+}
+
+static void mg_null_if_destroy_conn(struct mg_connection *c) {
+ (void) c;
+}
+
+static void mg_null_if_sock_set(struct mg_connection *c, sock_t sock) {
+ (void) c;
+ (void) sock;
+}
+
+static void mg_null_if_init(struct mg_iface *iface) {
+ (void) iface;
+}
+
+static void mg_null_if_free(struct mg_iface *iface) {
+ (void) iface;
+}
+
+static void mg_null_if_add_conn(struct mg_connection *c) {
+ c->sock = INVALID_SOCKET;
+ c->flags |= MG_F_CLOSE_IMMEDIATELY;
+}
+
+static void mg_null_if_remove_conn(struct mg_connection *c) {
+ (void) c;
+}
+
+static time_t mg_null_if_poll(struct mg_iface *iface, int timeout_ms) {
+ struct mg_mgr *mgr = iface->mgr;
+ struct mg_connection *nc, *tmp;
+ double now = mg_time();
+ /* We basically just run timers and poll. */
+ for (nc = mgr->active_connections; nc != NULL; nc = tmp) {
+ tmp = nc->next;
+ mg_if_poll(nc, now);
+ }
+ (void) timeout_ms;
+ return (time_t) now;
+}
+
+static void mg_null_if_get_conn_addr(struct mg_connection *c, int remote,
+ union socket_address *sa) {
+ (void) c;
+ (void) remote;
+ (void) sa;
+}
+
+#define MG_NULL_IFACE_VTABLE \
+ { \
+ mg_null_if_init, mg_null_if_free, mg_null_if_add_conn, \
+ mg_null_if_remove_conn, mg_null_if_poll, mg_null_if_listen_tcp, \
+ mg_null_if_listen_udp, mg_null_if_connect_tcp, mg_null_if_connect_udp, \
+ mg_null_if_tcp_send, mg_null_if_udp_send, mg_null_if_tcp_recv, \
+ mg_null_if_udp_recv, mg_null_if_create_conn, mg_null_if_destroy_conn, \
+ mg_null_if_sock_set, mg_null_if_get_conn_addr, \
+ }
+
+const struct mg_iface_vtable mg_null_iface_vtable = MG_NULL_IFACE_VTABLE;
+
+#if MG_NET_IF == MG_NET_IF_NULL
+const struct mg_iface_vtable mg_default_iface_vtable = MG_NULL_IFACE_VTABLE;
+#endif /* MG_NET_IF == MG_NET_IF_NULL */
diff --git a/src/mg_resolv.c b/src/mg_resolv.c
index b8b73a994a..a67c773870 100644
--- a/src/mg_resolv.c
+++ b/src/mg_resolv.c
@@ -152,7 +152,9 @@ static void mg_resolve_async_eh(struct mg_connection *nc, int ev,
void *user_data = nc->user_data;
#endif
- if (ev != MG_EV_POLL) DBG(("ev=%d user_data=%p", ev, user_data));
+ if (ev != MG_EV_POLL) {
+ DBG(("ev=%d user_data=%p", ev, user_data));
+ }
req = (struct mg_resolve_async_request *) user_data;
diff --git a/src/mg_ssl_if_mbedtls.c b/src/mg_ssl_if_mbedtls.c
index 021addcf48..7640778fff 100644
--- a/src/mg_ssl_if_mbedtls.c
+++ b/src/mg_ssl_if_mbedtls.c
@@ -32,6 +32,8 @@ static void mg_ssl_mbed_log(void *ctx, int level, const char *file, int line,
}
/* mbedTLS passes strings with \n at the end, strip it. */
LOG(cs_level, ("%p %.*s", ctx, (int) (strlen(str) - 1), str));
+ (void) ctx;
+ (void) str;
(void) file;
(void) line;
(void) cs_level;
@@ -221,9 +223,9 @@ 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;
+ if (ctx->conf->ca_chain_file != NULL) {
+ MG_FREE((void *) ctx->conf->ca_chain_file);
+ ctx->conf->ca_chain_file = NULL;
}
#endif
mbedtls_x509_crt_free(ctx->ca_cert);
@@ -330,15 +332,13 @@ static enum mg_ssl_if_result mg_use_ca_cert(struct mg_ssl_if_ctx *ctx,
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;
- }
+ mbedtls_ssl_conf_ca_chain_file(ctx->conf, ca_cert, NULL);
#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);
+#endif
mbedtls_ssl_conf_authmode(ctx->conf, MBEDTLS_SSL_VERIFY_REQUIRED);
return MG_SSL_OK;
}
diff --git a/test/unit_test.c b/test/unit_test.c
index 2cf5aa1ea7..cde8df8afc 100644
--- a/test/unit_test.c
+++ b/test/unit_test.c
@@ -2069,7 +2069,7 @@ static const char *test_http(void) {
nc->user_data = mime2;
/* Run event loop. Use more cycles to let file download complete. */
- poll_until(&mgr, 5, c_str_ne, status, (void *) "");
+ poll_until(&mgr, 15, c_str_ne, status, (void *) "");
mg_mgr_free(&mgr);
/* Check that test buffer has been filled by the callback properly. */