mirror of
https://github.com/cesanta/mongoose.git
synced 2026-11-06 15:51:25 +00:00
Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
f59a3f71ed |
No files matched your search
+16
-8
@@ -5,6 +5,9 @@
|
|||||||
|
|
||||||
#include "mip_x_test.c"
|
#include "mip_x_test.c"
|
||||||
|
|
||||||
|
static bool drop_tcp_segment(const void *buf, size_t len,
|
||||||
|
struct mg_tcpip_if *ifp);
|
||||||
|
|
||||||
struct port_driver_data {
|
struct port_driver_data {
|
||||||
int sockfd;
|
int sockfd;
|
||||||
struct sockaddr_in port_addr;
|
struct sockaddr_in port_addr;
|
||||||
@@ -16,6 +19,7 @@ static size_t sock_rx(void *buf, size_t len, struct mg_tcpip_if *ifp) {
|
|||||||
ssize_t received = recv(((struct port_driver_data *)ifp->driver_data)->sockfd, buf, len, 0);
|
ssize_t received = recv(((struct port_driver_data *)ifp->driver_data)->sockfd, buf, len, 0);
|
||||||
usleep(1); // This is to avoid 100% CPU
|
usleep(1); // This is to avoid 100% CPU
|
||||||
if (received < 0) return 0;
|
if (received < 0) return 0;
|
||||||
|
if (drop_tcp_segment(buf, (size_t) received, ifp)) return 0;
|
||||||
return (size_t) received;
|
return (size_t) received;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -37,15 +41,19 @@ static bool is_tcp_segment(const void *buf, size_t len) {
|
|||||||
return (tcp->flags & (TH_SYN | TH_FIN)) == 0;
|
return (tcp->flags & (TH_SYN | TH_FIN)) == 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static size_t sock_tx(const void *buf, size_t len, struct mg_tcpip_if *ifp) {
|
static bool drop_tcp_segment(const void *buf, size_t len,
|
||||||
|
struct mg_tcpip_if *ifp) {
|
||||||
uint32_t random;
|
uint32_t random;
|
||||||
if (ifp->enable_tcp_retransmit && is_tcp_segment(buf, len)) { // introduce a 30% segment loss
|
if (!ifp->enable_tcp_retransmit || !is_tcp_segment(buf, len)) return false;
|
||||||
mg_random(&random, sizeof(random));
|
// Introduce a 30% segment loss
|
||||||
if (random % 10 < 3) {
|
mg_random(&random, sizeof(random));
|
||||||
MG_DEBUG(("dropping TCP segment"));
|
if (random % 10 >= 3) return false;
|
||||||
return len;
|
MG_DEBUG(("dropping TCP segment"));
|
||||||
}
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static size_t sock_tx(const void *buf, size_t len, struct mg_tcpip_if *ifp) {
|
||||||
|
if (drop_tcp_segment(buf, len, ifp)) return len;
|
||||||
ssize_t res = send(((struct port_driver_data *)ifp->driver_data)->sockfd, buf, len, 0);
|
ssize_t res = send(((struct port_driver_data *)ifp->driver_data)->sockfd, buf, len, 0);
|
||||||
if (res < 0) {
|
if (res < 0) {
|
||||||
MG_ERROR(("sock_tx failed: %d", errno));
|
MG_ERROR(("sock_tx failed: %d", errno));
|
||||||
|
|||||||
+15
-8
@@ -13,12 +13,15 @@
|
|||||||
|
|
||||||
#include "mip_x_test.c"
|
#include "mip_x_test.c"
|
||||||
|
|
||||||
|
static bool drop_tcp_segment(const void *buf, size_t len,
|
||||||
|
struct mg_tcpip_if *ifp);
|
||||||
|
|
||||||
// MIP TUNTAP driver
|
// MIP TUNTAP driver
|
||||||
static size_t tap_rx(void *buf, size_t len, struct mg_tcpip_if *ifp) {
|
static size_t tap_rx(void *buf, size_t len, struct mg_tcpip_if *ifp) {
|
||||||
ssize_t received = read(*(int *) ifp->driver_data, buf, len);
|
ssize_t received = read(*(int *) ifp->driver_data, buf, len);
|
||||||
usleep(1); // This is to avoid 100% CPU
|
usleep(1); // This is to avoid 100% CPU
|
||||||
if (received < 0) return 0;
|
if (received < 0) return 0;
|
||||||
|
if (drop_tcp_segment(buf, (size_t) received, ifp)) return 0;
|
||||||
return (size_t) received;
|
return (size_t) received;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -40,15 +43,19 @@ static bool is_tcp_segment(const void *buf, size_t len) {
|
|||||||
return (tcp->flags & (TH_SYN | TH_FIN)) == 0;
|
return (tcp->flags & (TH_SYN | TH_FIN)) == 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static size_t tap_tx(const void *buf, size_t len, struct mg_tcpip_if *ifp) {
|
static bool drop_tcp_segment(const void *buf, size_t len,
|
||||||
|
struct mg_tcpip_if *ifp) {
|
||||||
uint32_t random;
|
uint32_t random;
|
||||||
if (ifp->enable_tcp_retransmit && is_tcp_segment(buf, len)) { // introduce a 30% segment loss
|
if (!ifp->enable_tcp_retransmit || !is_tcp_segment(buf, len)) return false;
|
||||||
mg_random(&random, sizeof(random));
|
// Introduce a 30% segment loss
|
||||||
if (random % 10 < 3) {
|
mg_random(&random, sizeof(random));
|
||||||
MG_DEBUG(("dropping TCP segment"));
|
if (random % 10 >= 3) return false;
|
||||||
return len;
|
MG_DEBUG(("dropping TCP segment"));
|
||||||
}
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static size_t tap_tx(const void *buf, size_t len, struct mg_tcpip_if *ifp) {
|
||||||
|
if (drop_tcp_segment(buf, len, ifp)) return len;
|
||||||
ssize_t res = write(*(int *) ifp->driver_data, buf, len);
|
ssize_t res = write(*(int *) ifp->driver_data, buf, len);
|
||||||
if (res < 0) {
|
if (res < 0) {
|
||||||
MG_ERROR(("tap_tx failed: %d", errno));
|
MG_ERROR(("tap_tx failed: %d", errno));
|
||||||
|
|||||||
+69
-47
@@ -76,6 +76,7 @@ static int s_num_tests = 0;
|
|||||||
static bool s_error = false;
|
static bool s_error = false;
|
||||||
|
|
||||||
#define POLL_LIMIT(n) (mgr->ifp->enable_tcp_retransmit ? (n) * 10 : (n))
|
#define POLL_LIMIT(n) (mgr->ifp->enable_tcp_retransmit ? (n) * 10 : (n))
|
||||||
|
#define RTX_ATTEMPTS(mgr) ((mgr)->ifp->enable_tcp_retransmit ? 3 : 1)
|
||||||
|
|
||||||
#ifdef NO_ABORT
|
#ifdef NO_ABORT
|
||||||
static int s_abort = 0;
|
static int s_abort = 0;
|
||||||
@@ -151,13 +152,15 @@ static void eh1(struct mg_connection *c, int ev, void *ev_data) {
|
|||||||
struct fetch_data {
|
struct fetch_data {
|
||||||
char *buf;
|
char *buf;
|
||||||
const char *url;
|
const char *url;
|
||||||
int code, closed;
|
int code;
|
||||||
|
bool connected, received, closed;
|
||||||
};
|
};
|
||||||
|
|
||||||
static void fcb(struct mg_connection *c, int ev, void *ev_data) {
|
static void fcb(struct mg_connection *c, int ev, void *ev_data) {
|
||||||
struct fetch_data *fd = (struct fetch_data *) c->fn_data;
|
struct fetch_data *fd = (struct fetch_data *) c->fn_data;
|
||||||
if (ev == MG_EV_CONNECT) {
|
if (ev == MG_EV_CONNECT) {
|
||||||
MG_DEBUG(("CONNECT"));
|
MG_DEBUG(("CONNECT"));
|
||||||
|
fd->connected = true;
|
||||||
if (mg_url_is_ssl(fd->url)) {
|
if (mg_url_is_ssl(fd->url)) {
|
||||||
struct mg_tls_opts opts;
|
struct mg_tls_opts opts;
|
||||||
memset(&opts, 0, sizeof(opts)); // read CA from packed_fs
|
memset(&opts, 0, sizeof(opts)); // read CA from packed_fs
|
||||||
@@ -173,6 +176,7 @@ static void fcb(struct mg_connection *c, int ev, void *ev_data) {
|
|||||||
}
|
}
|
||||||
} else if (ev == MG_EV_HTTP_MSG) {
|
} else if (ev == MG_EV_HTTP_MSG) {
|
||||||
struct mg_http_message *hm = (struct mg_http_message *) ev_data;
|
struct mg_http_message *hm = (struct mg_http_message *) ev_data;
|
||||||
|
fd->received = true;
|
||||||
snprintf(fd->buf, FETCH_BUF_SIZE, "%.*s", (int) hm->message.len,
|
snprintf(fd->buf, FETCH_BUF_SIZE, "%.*s", (int) hm->message.len,
|
||||||
hm->message.buf);
|
hm->message.buf);
|
||||||
fd->code = atoi(hm->uri.buf);
|
fd->code = atoi(hm->uri.buf);
|
||||||
@@ -191,32 +195,38 @@ static void fcb(struct mg_connection *c, int ev, void *ev_data) {
|
|||||||
|
|
||||||
static int fetch(struct mg_mgr *mgr, char *buf, const char *url,
|
static int fetch(struct mg_mgr *mgr, char *buf, const char *url,
|
||||||
const char *fmt, ...) {
|
const char *fmt, ...) {
|
||||||
struct fetch_data fd = {buf, url, 0, 0};
|
int i, attempt;
|
||||||
int i;
|
|
||||||
struct mg_connection *c = NULL;
|
struct mg_connection *c = NULL;
|
||||||
va_list ap;
|
va_list ap;
|
||||||
mg_mgr_poll(mgr, 0); // update ifp->now to avoid ARP lookup using an old
|
for (attempt = 0; attempt < RTX_ATTEMPTS(mgr); attempt++) {
|
||||||
// timestamp (from an ancient call in other test)
|
struct fetch_data fd = {buf, url, 0, false, false, false};
|
||||||
mg_mgr_poll(mgr, 0); // (prior idling collects lots of frames)
|
mg_mgr_poll(mgr, 0); // update ifp->now to avoid ARP lookup using an old
|
||||||
c = mg_http_connect(mgr, url, fcb, &fd);
|
// timestamp (from an ancient call in other test)
|
||||||
ASSERT(c != NULL);
|
mg_mgr_poll(mgr, 0); // (prior idling collects lots of frames)
|
||||||
va_start(ap, fmt);
|
c = mg_http_connect(mgr, url, fcb, &fd);
|
||||||
mg_vprintf(c, fmt, &ap);
|
ASSERT(c != NULL);
|
||||||
va_end(ap);
|
va_start(ap, fmt);
|
||||||
buf[0] = '\0';
|
mg_vprintf(c, fmt, &ap);
|
||||||
// - TLS: multiple (small) records: allow enough loops so mg_mgr_poll can
|
va_end(ap);
|
||||||
// process buffered records when no more frames are coming in
|
buf[0] = '\0';
|
||||||
for (i = 0; i < POLL_LIMIT(500) && buf[0] == '\0' && !fd.closed; i++) {
|
// - TLS: multiple (small) records: allow enough loops so mg_mgr_poll can
|
||||||
|
// process buffered records when no more frames are coming in
|
||||||
|
for (i = 0; i < POLL_LIMIT(500) && buf[0] == '\0' && !fd.closed; i++) {
|
||||||
|
mg_mgr_poll(mgr, 0);
|
||||||
|
usleep(5000); // 5 ms. Slow down poll loop to ensure packet transit, but
|
||||||
|
// allow enough loops to get the ARP response, otherwise,
|
||||||
|
// given enough traffic, the timer expires before we get a
|
||||||
|
// chance to see the response
|
||||||
|
}
|
||||||
|
if (!fd.closed) // failed, force closure and conn removal, and loop end
|
||||||
|
((struct connstate *) (c + 1))->is_closing = 1;
|
||||||
mg_mgr_poll(mgr, 0);
|
mg_mgr_poll(mgr, 0);
|
||||||
usleep(5000); // 5 ms. Slow down poll loop to ensure packet transit, but
|
if (!(fd.connected && fd.closed && !fd.received) ||
|
||||||
// allow enough loops to get the ARP response, otherwise,
|
attempt + 1 == RTX_ATTEMPTS(mgr))
|
||||||
// given enough traffic, the timer expires before we get a
|
return fd.code;
|
||||||
// chance to see the response
|
MG_INFO(("HTTP retry %d", attempt + 2));
|
||||||
}
|
}
|
||||||
if (!fd.closed) // failed, force closure and conn removal, and loop end
|
return 0;
|
||||||
((struct connstate *) (c + 1))->is_closing = 1;
|
|
||||||
mg_mgr_poll(mgr, 0);
|
|
||||||
return fd.code;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void test_http_client(struct mg_mgr *mgr) {
|
static void test_http_client(struct mg_mgr *mgr) {
|
||||||
@@ -256,13 +266,14 @@ static char s_topic[16];
|
|||||||
|
|
||||||
struct mqtt_data {
|
struct mqtt_data {
|
||||||
char *url;
|
char *url;
|
||||||
bool passed;
|
bool connected, opened, passed;
|
||||||
};
|
};
|
||||||
|
|
||||||
static void mqtt_fn(struct mg_connection *c, int ev, void *ev_data) {
|
static void mqtt_fn(struct mg_connection *c, int ev, void *ev_data) {
|
||||||
struct mqtt_data *data = (struct mqtt_data *) c->fn_data;
|
struct mqtt_data *data = (struct mqtt_data *) c->fn_data;
|
||||||
if (ev == MG_EV_CONNECT) {
|
if (ev == MG_EV_CONNECT) {
|
||||||
MG_DEBUG(("CONNECT"));
|
MG_DEBUG(("CONNECT"));
|
||||||
|
data->connected = true;
|
||||||
#if MG_TLS
|
#if MG_TLS
|
||||||
struct mg_tls_opts opts;
|
struct mg_tls_opts opts;
|
||||||
memset(&opts, 0, sizeof(opts));
|
memset(&opts, 0, sizeof(opts));
|
||||||
@@ -277,6 +288,7 @@ static void mqtt_fn(struct mg_connection *c, int ev, void *ev_data) {
|
|||||||
#endif
|
#endif
|
||||||
} else if (ev == MG_EV_MQTT_OPEN) {
|
} else if (ev == MG_EV_MQTT_OPEN) {
|
||||||
MG_DEBUG(("MQTT CONNECT"));
|
MG_DEBUG(("MQTT CONNECT"));
|
||||||
|
data->opened = true;
|
||||||
struct mg_mqtt_opts sub_opts;
|
struct mg_mqtt_opts sub_opts;
|
||||||
memset(&sub_opts, 0, sizeof(sub_opts));
|
memset(&sub_opts, 0, sizeof(sub_opts));
|
||||||
sub_opts.topic = mg_str(mg_random_str(s_topic, sizeof(s_topic)));
|
sub_opts.topic = mg_str(mg_random_str(s_topic, sizeof(s_topic)));
|
||||||
@@ -326,12 +338,30 @@ static void mqtt_fn(struct mg_connection *c, int ev, void *ev_data) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static bool mqtt_attempt(struct mg_mgr *mgr, struct mqtt_data *data,
|
||||||
|
struct mg_mqtt_opts *opts) {
|
||||||
|
int i;
|
||||||
|
data->connected = data->opened = data->passed = false;
|
||||||
|
mg_mgr_poll(mgr, 0); // update interface timing (*)
|
||||||
|
mg_mgr_poll(mgr, 0);
|
||||||
|
s_conn = mg_mqtt_connect(mgr, data->url, opts, mqtt_fn, data);
|
||||||
|
ASSERT(s_conn != NULL);
|
||||||
|
for (i = 0; i < POLL_LIMIT(1000) && s_conn != NULL && !s_conn->is_closing;
|
||||||
|
i++) {
|
||||||
|
mg_mgr_poll(mgr, 0);
|
||||||
|
usleep(5000); // 5 ms (*) See fetch() above for reasons
|
||||||
|
}
|
||||||
|
mg_mgr_poll(mgr, 0);
|
||||||
|
return data->connected && !data->opened && s_conn == NULL;
|
||||||
|
}
|
||||||
|
|
||||||
static void test_mqtt_connsubpub(struct mg_mgr *mgr) {
|
static void test_mqtt_connsubpub(struct mg_mgr *mgr) {
|
||||||
struct mqtt_data data;
|
struct mqtt_data data;
|
||||||
struct mg_mqtt_opts opts;
|
struct mg_mqtt_opts opts;
|
||||||
|
bool retry;
|
||||||
|
int attempt;
|
||||||
memset(&opts, 0, sizeof(opts));
|
memset(&opts, 0, sizeof(opts));
|
||||||
opts.clean = true, opts.version = 4;
|
opts.clean = true, opts.version = 4;
|
||||||
data.passed = false;
|
|
||||||
#if defined(MQTT_HOST) && MG_TLS != MG_TLS_BUILTIN
|
#if defined(MQTT_HOST) && MG_TLS != MG_TLS_BUILTIN
|
||||||
if (host_ip == NULL) {
|
if (host_ip == NULL) {
|
||||||
printf("\nMQTT_HOST defined but no HOST_IP provided, skipping MQTT tests\n");
|
printf("\nMQTT_HOST defined but no HOST_IP provided, skipping MQTT tests\n");
|
||||||
@@ -359,15 +389,10 @@ static void test_mqtt_connsubpub(struct mg_mgr *mgr) {
|
|||||||
data.url = strdup(MQTT_URL);
|
data.url = strdup(MQTT_URL);
|
||||||
#endif
|
#endif
|
||||||
#endif // MG_TLS
|
#endif // MG_TLS
|
||||||
mg_mgr_poll(mgr, 0); // update interface timing (*)
|
for (attempt = 0; attempt < RTX_ATTEMPTS(mgr); attempt++) {
|
||||||
mg_mgr_poll(mgr, 0);
|
retry = mqtt_attempt(mgr, &data, &opts);
|
||||||
s_conn = mg_mqtt_connect(mgr, data.url, &opts, mqtt_fn, &data);
|
if (!retry || attempt + 1 == RTX_ATTEMPTS(mgr)) break;
|
||||||
ASSERT(s_conn != NULL);
|
MG_INFO(("MQTT retry %d", attempt + 2));
|
||||||
for (int i = 0;
|
|
||||||
i < POLL_LIMIT(1000) && s_conn != NULL && !s_conn->is_closing;
|
|
||||||
i++) {
|
|
||||||
mg_mgr_poll(mgr, 0);
|
|
||||||
usleep(5000); // 5 ms (*) See fetch() above for reasons
|
|
||||||
}
|
}
|
||||||
ASSERT(data.passed);
|
ASSERT(data.passed);
|
||||||
mg_mgr_poll(mgr, 0);
|
mg_mgr_poll(mgr, 0);
|
||||||
@@ -406,16 +431,10 @@ static void test_mqtt_connsubpub(struct mg_mgr *mgr) {
|
|||||||
//data.url = strdup(MQTT_URL);
|
//data.url = strdup(MQTT_URL);
|
||||||
#endif
|
#endif
|
||||||
#endif // MG_TLS
|
#endif // MG_TLS
|
||||||
data.passed = false;
|
for (attempt = 0; attempt < RTX_ATTEMPTS(mgr); attempt++) {
|
||||||
mg_mgr_poll(mgr, 0); // update interface timing (*)
|
retry = mqtt_attempt(mgr, &data, &opts);
|
||||||
mg_mgr_poll(mgr, 0);
|
if (!retry || attempt + 1 == RTX_ATTEMPTS(mgr)) break;
|
||||||
s_conn = mg_mqtt_connect(mgr, data.url, &opts, mqtt_fn, &data);
|
MG_INFO(("MQTT retry %d", attempt + 2));
|
||||||
ASSERT(s_conn != NULL);
|
|
||||||
for (int i = 0;
|
|
||||||
i < POLL_LIMIT(1000) && s_conn != NULL && !s_conn->is_closing;
|
|
||||||
i++) {
|
|
||||||
mg_mgr_poll(mgr, 0);
|
|
||||||
usleep(5000); // 5 ms (*) See fetch() above for reasons
|
|
||||||
}
|
}
|
||||||
ASSERT(data.passed);
|
ASSERT(data.passed);
|
||||||
mg_mgr_poll(mgr, 0);
|
mg_mgr_poll(mgr, 0);
|
||||||
@@ -445,7 +464,7 @@ static void test_http_server(struct mg_mgr *mgr) {
|
|||||||
struct mg_connection *c;
|
struct mg_connection *c;
|
||||||
char *cmd;
|
char *cmd;
|
||||||
pthread_t thread_id = (pthread_t) 0;
|
pthread_t thread_id = (pthread_t) 0;
|
||||||
int rc;
|
int attempt, rc;
|
||||||
#if MG_TLS
|
#if MG_TLS
|
||||||
struct mg_tls_opts opts;
|
struct mg_tls_opts opts;
|
||||||
memset(&opts, 0, sizeof(opts));
|
memset(&opts, 0, sizeof(opts));
|
||||||
@@ -468,8 +487,11 @@ static void test_http_server(struct mg_mgr *mgr) {
|
|||||||
s_poll_done = false;
|
s_poll_done = false;
|
||||||
pthread_create(&thread_id, NULL, poll_thread,
|
pthread_create(&thread_id, NULL, poll_thread,
|
||||||
mgr); // simpler this way, no concurrency anyway
|
mgr); // simpler this way, no concurrency anyway
|
||||||
MG_DEBUG(("CURL"));
|
for (attempt = 0; attempt < RTX_ATTEMPTS(mgr); attempt++) {
|
||||||
rc = system(cmd); // wait for curl
|
MG_DEBUG(("CURL attempt %d", attempt + 1));
|
||||||
|
rc = system(cmd); // wait for curl
|
||||||
|
if (rc == 0) break;
|
||||||
|
}
|
||||||
MG_DEBUG(("MONGOOSE"));
|
MG_DEBUG(("MONGOOSE"));
|
||||||
s_poll_done = true;
|
s_poll_done = true;
|
||||||
pthread_join(thread_id, NULL); // wait for Mongoose
|
pthread_join(thread_id, NULL); // wait for Mongoose
|
||||||
|
|||||||
Reference in new issue
Block a user