#define MG_ENABLE_TCPIP 1 #define MG_ENABLE_TCPIP_DRIVER_INIT 0 #define FETCH_BUF_SIZE (16 * 1024) #include "mongoose.c" bool mip_x_test(struct mg_mgr *); #ifdef MQTT_HOST // we'll generate MQTT_URL #ifndef MQTT_HOST_NAME #define MQTT_HOST_NAME "localhost" #endif #else #define MQTT_URL "mqtt://broker.hivemq.com:1883" #endif #if MG_TLS == MG_TLS_BUILTIN #define MQTTS_URL "mqtts://mongoose.ws:8883" // test requires TLS 1.3 #define MQTTS_CA mg_str(s_ca_cert) static const char *s_ca_cert = "-----BEGIN CERTIFICATE-----\n" "MIIFazCCA1OgAwIBAgIRAIIQz7DSQONZRGPgu2OCiwAwDQYJKoZIhvcNAQELBQAw\n" "TzELMAkGA1UEBhMCVVMxKTAnBgNVBAoTIEludGVybmV0IFNlY3VyaXR5IFJlc2Vh\n" "cmNoIEdyb3VwMRUwEwYDVQQDEwxJU1JHIFJvb3QgWDEwHhcNMTUwNjA0MTEwNDM4\n" "WhcNMzUwNjA0MTEwNDM4WjBPMQswCQYDVQQGEwJVUzEpMCcGA1UEChMgSW50ZXJu\n" "ZXQgU2VjdXJpdHkgUmVzZWFyY2ggR3JvdXAxFTATBgNVBAMTDElTUkcgUm9vdCBY\n" "MTCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBAK3oJHP0FDfzm54rVygc\n" "h77ct984kIxuPOZXoHj3dcKi/vVqbvYATyjb3miGbESTtrFj/RQSa78f0uoxmyF+\n" "0TM8ukj13Xnfs7j/EvEhmkvBioZxaUpmZmyPfjxwv60pIgbz5MDmgK7iS4+3mX6U\n" "A5/TR5d8mUgjU+g4rk8Kb4Mu0UlXjIB0ttov0DiNewNwIRt18jA8+o+u3dpjq+sW\n" "T8KOEUt+zwvo/7V3LvSye0rgTBIlDHCNAymg4VMk7BPZ7hm/ELNKjD+Jo2FR3qyH\n" "B5T0Y3HsLuJvW5iB4YlcNHlsdu87kGJ55tukmi8mxdAQ4Q7e2RCOFvu396j3x+UC\n" "B5iPNgiV5+I3lg02dZ77DnKxHZu8A/lJBdiB3QW0KtZB6awBdpUKD9jf1b0SHzUv\n" "KBds0pjBqAlkd25HN7rOrFleaJ1/ctaJxQZBKT5ZPt0m9STJEadao0xAH0ahmbWn\n" "OlFuhjuefXKnEgV4We0+UXgVCwOPjdAvBbI+e0ocS3MFEvzG6uBQE3xDk3SzynTn\n" "jh8BCNAw1FtxNrQHusEwMFxIt4I7mKZ9YIqioymCzLq9gwQbooMDQaHWBfEbwrbw\n" "qHyGO0aoSCqI3Haadr8faqU9GY/rOPNk3sgrDQoo//fb4hVC1CLQJ13hef4Y53CI\n" "rU7m2Ys6xt0nUW7/vGT1M0NPAgMBAAGjQjBAMA4GA1UdDwEB/wQEAwIBBjAPBgNV\n" "HRMBAf8EBTADAQH/MB0GA1UdDgQWBBR5tFnme7bl5AFzgAiIyBpY9umbbjANBgkq\n" "hkiG9w0BAQsFAAOCAgEAVR9YqbyyqFDQDLHYGmkgJykIrGF1XIpu+ILlaS/V9lZL\n" "ubhzEFnTIZd+50xx+7LSYK05qAvqFyFWhfFQDlnrzuBZ6brJFe+GnY+EgPbk6ZGQ\n" "3BebYhtF8GaV0nxvwuo77x/Py9auJ/GpsMiu/X1+mvoiBOv/2X/qkSsisRcOj/KK\n" "NFtY2PwByVS5uCbMiogziUwthDyC3+6WVwW6LLv3xLfHTjuCvjHIInNzktHCgKQ5\n" "ORAzI4JMPJ+GslWYHb4phowim57iaztXOoJwTdwJx4nLCgdNbOhdjsnvzqvHu7Ur\n" "TkXWStAmzOVyyghqpZXjFaH3pO3JLF+l+/+sKAIuvtd7u+Nxe5AW0wdeRlN8NwdC\n" "jNPElpzVmbUq4JUagEiuTDkHzsxHpFKVK7q4+63SM1N95R1NbdWhscdCb+ZAJzVc\n" "oyi3B43njTOQ5yOf+1CceWxG1bQVs5ZufpsMljq4Ui0/1lvh+wjChP4kqKOJ2qxq\n" "4RgqsahDYVvTH9w7jXbyLeiNdd8XM2w9U/t7y0Ff/9yi0GE44Za4rF2LN9d11TPA\n" "mRGunUHBcnWEvgJBQl9nJEiU0Zsnvgc/ubhPgXRR4Xq37Z0j4r7g1SgEEzwxA57d\n" "emyPxgcYxn/eR44/KJ4EBs+lVDR3veyJm+kXQ99b21/+jh5Xos1AnX5iItreGCc=\n" "-----END CERTIFICATE-----\n"; #elif MG_TLS #ifdef MQTT_HOST // we'll generate MQTTS_URL #define MQTTS_CA mg_str(s_ca_cert) static const char *s_ca_cert = "-----BEGIN CERTIFICATE-----\n" "MIIBFTCBvAIJAMNTFtpfcq8NMAoGCCqGSM49BAMCMBMxETAPBgNVBAMMCE1vbmdv\n" "b3NlMB4XDTI0MDUwNzE0MzczNloXDTM0MDUwNTE0MzczNlowEzERMA8GA1UEAwwI\n" "TW9uZ29vc2UwWTATBgcqhkjOPQIBBggqhkjOPQMBBwNCAASuP+86T/rOWnGpEVhl\n" "fxYZ+pjMbCmDZ+vdnP0rjoxudwRMRQCv5slRlDK7Lxue761sdvqxWr0Ma6TFGTNg\n" "epsRMAoGCCqGSM49BAMCA0gAMEUCIQCwb2CxuAKm51s81S6BIoy1IcandXSohnqs\n" "us64BAA7QgIgGGtUrpkgFSS0oPBlCUG6YPHFVw42vTfpTC0ySwAS0M4=\n" "-----END CERTIFICATE-----\n"; #else #define MQTTS_URL "mqtts://broker.hivemq.com:8883" #define MQTTS_CA mg_unpacked("/data/ca.pem") #endif // MQTT_HOST #endif static char *host_ip, *host_ip6; static int s_num_tests = 0; static bool s_error = false; #ifdef NO_ABORT static int s_abort = 0; #define ABORT() ++s_abort, s_error = true #else #ifdef NO_SLEEP_ABORT #define ABORT() abort() #else #define ABORT() \ sleep(2); /* 2s, GH print reason */ \ abort(); #endif #endif #define ASSERT(expr) \ do { \ s_num_tests++; \ if (!(expr)) { \ printf("FAILURE %s:%d: %s\n", __FILE__, __LINE__, #expr); \ fflush(stdout); \ ABORT(); \ } \ } while (0) static struct mg_http_message gethm(const char *buf) { struct mg_http_message hm; memset(&hm, 0, sizeof(hm)); mg_http_parse(buf, strlen(buf), &hm); return hm; } static int cmpbody(const char *buf, const char *str) { struct mg_str s = mg_str(str); struct mg_http_message hm = gethm(buf); size_t len = strlen(buf); if (hm.body.len > len) hm.body.len = len - (size_t) (hm.body.buf - buf); return mg_strcmp(hm.body, s); } #ifndef NO_HTTPSERVER_TEST static void eh1(struct mg_connection *c, int ev, void *ev_data) { struct mg_tls_opts *topts = (struct mg_tls_opts *) c->fn_data; if (ev == MG_EV_ACCEPT && topts != NULL) mg_tls_init(c, topts); if (ev == MG_EV_HTTP_MSG) { struct mg_http_message *hm = (struct mg_http_message *) ev_data; MG_DEBUG(("[%.*s %.*s] message len %d", (int) hm->method.len, hm->method.buf, (int) hm->uri.len, hm->uri.buf, (int) hm->message.len)); if (mg_match(hm->uri, mg_str("/foo/*"), NULL)) { mg_http_reply(c, 200, "", "uri: %.*s", hm->uri.len - 5, hm->uri.buf + 5); } else if (mg_match(hm->uri, mg_str("/ws"), NULL)) { mg_ws_upgrade(c, hm, NULL); } else if (mg_match(hm->uri, mg_str("/body"), NULL)) { mg_http_reply(c, 200, "", "%.*s", (int) hm->body.len, hm->body.buf); } else { struct mg_http_serve_opts sopts; memset(&sopts, 0, sizeof(sopts)); sopts.root_dir = "./data"; mg_http_serve_dir(c, hm, &sopts); } } else if (ev == MG_EV_WS_OPEN) { struct mg_http_message *hm = (struct mg_http_message *) ev_data; ASSERT(mg_strcmp(hm->uri, mg_str("/ws")) == 0); mg_ws_send(c, "opened", 6, WEBSOCKET_OP_BINARY); } else if (ev == MG_EV_WS_MSG) { struct mg_ws_message *wm = (struct mg_ws_message *) ev_data; mg_ws_send(c, wm->data.buf, wm->data.len, WEBSOCKET_OP_BINARY); } } #endif struct fetch_data { char *buf; const char *url; int code, closed; }; static void fcb(struct mg_connection *c, int ev, void *ev_data) { struct fetch_data *fd = (struct fetch_data *) c->fn_data; if (ev == MG_EV_CONNECT) { MG_DEBUG(("CONNECT")); if (mg_url_is_ssl(fd->url)) { struct mg_tls_opts opts; memset(&opts, 0, sizeof(opts)); // read CA from packed_fs if (host_ip != NULL && strstr(fd->url, host_ip) != NULL) { MG_DEBUG(("Local connection, using self-signed certificates")); opts.name = mg_str_s("localhost"); opts.ca = mg_unpacked("/certs/ca.crt"); } else { opts.name = mg_url_host(fd->url); opts.ca = mg_unpacked("/data/ca.pem"); } mg_tls_init(c, &opts); } } else if (ev == MG_EV_HTTP_MSG) { struct mg_http_message *hm = (struct mg_http_message *) ev_data; snprintf(fd->buf, FETCH_BUF_SIZE, "%.*s", (int) hm->message.len, hm->message.buf); fd->code = atoi(hm->uri.buf); fd->closed = 1; c->is_closing = 1; MG_DEBUG(("CODE: %d, MSG: %.*s", fd->code, (int) hm->message.len, hm->message.buf)); (void) c; } else if (ev == MG_EV_CLOSE) { MG_DEBUG(("CLOSE")); fd->closed = 1; } else if (ev == MG_EV_READ) { long bytes = *(long *) ev_data; MG_DEBUG(("READ %d: %.*s", (int) bytes, (int) bytes, c->recv.buf)); } } static int fetch(struct mg_mgr *mgr, char *buf, const char *url, const char *fmt, ...) { struct fetch_data fd = {buf, url, 0, 0}; int i; struct mg_connection *c = NULL; va_list ap; mg_mgr_poll(mgr, 0); // update ifp->now to avoid ARP lookup using an old // timestamp (from an ancient call in other test) mg_mgr_poll(mgr, 0); // (prior idling collects lots of frames) c = mg_http_connect(mgr, url, fcb, &fd); ASSERT(c != NULL); va_start(ap, fmt); mg_vprintf(c, fmt, &ap); va_end(ap); buf[0] = '\0'; // - 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 < 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) c->is_closing = 1; mg_mgr_poll(mgr, 0); return fd.code; } static void test_http_client(struct mg_mgr *mgr) { char buf[FETCH_BUF_SIZE]; int rc = 0; const bool ipv6 = #ifdef IPV6_NOROUTING 0; // GitHub does not route IPv6 (as far as I can tell) #else MG_ENABLE_IPV6; #endif #if MG_TLS if (ipv6) { rc = fetch(mgr, buf, "https://ipv6.google.com", "GET / HTTP/1.0\r\nHost: ipv6.google.com\r\n\r\n"); } else { rc = fetch(mgr, buf, "https://cesanta.com", "GET /robots.txt HTTP/1.0\r\nHost: cesanta.com\r\n\r\n"); } ASSERT(rc == 200); // OK #else if (ipv6) { rc = fetch(mgr, buf, "http://ipv6.google.com", "GET / HTTP/1.0\r\nHost: ipv6.google.com\r\n\r\n"); ASSERT(rc == 200); // OK } else { rc = fetch(mgr, buf, "http://cesanta.com", "GET /robots.txt HTTP/1.0\r\nHost: cesanta.com\r\n\r\n"); ASSERT(rc == 301); // OK: Permanently moved (HTTP->HTTPS redirect) } #endif } static struct mg_connection *s_conn; static char s_topic[16]; struct mqtt_data { char *url; bool passed; }; static void mqtt_fn(struct mg_connection *c, int ev, void *ev_data) { struct mqtt_data *data = (struct mqtt_data *) c->fn_data; if (ev == MG_EV_CONNECT) { MG_DEBUG(("CONNECT")); #if MG_TLS struct mg_tls_opts opts; memset(&opts, 0, sizeof(opts)); opts.ca = MQTTS_CA; #if defined(MQTT_HOST) && MG_TLS != MG_TLS_BUILTIN opts.name = mg_str_s(MQTT_HOST_NAME); printf("HOST_NAME: %.*s\n", (int) opts.name.len, opts.name.buf); #else opts.name = mg_url_host(data->url); #endif mg_tls_init(c, &opts); #endif } else if (ev == MG_EV_MQTT_OPEN) { MG_DEBUG(("MQTT CONNECT")); struct mg_mqtt_opts sub_opts; memset(&sub_opts, 0, sizeof(sub_opts)); sub_opts.topic = mg_str(mg_random_str(s_topic, sizeof(s_topic))); sub_opts.qos = 1; mg_mqtt_sub(c, &sub_opts); struct mg_mqtt_opts pub_opts; memset(&pub_opts, 0, sizeof(pub_opts)); pub_opts.topic = sub_opts.topic; pub_opts.message = mg_str("hi"); pub_opts.qos = 1, pub_opts.retain = false; mg_mqtt_pub(c, &pub_opts); } else if (ev == MG_EV_MQTT_MSG) { struct mg_mqtt_message *mm = (struct mg_mqtt_message *) ev_data; MG_DEBUG(("TOPIC: %.*s, MSG: %.*s", (int) mm->topic.len, mm->topic.buf, mm->data.len > 10 ? 10 : (int) mm->data.len, mm->data.buf)); ASSERT(mm->topic.len == strlen(s_topic) && strncmp(mm->topic.buf, s_topic, mm->topic.len) == 0); if (mm->data.len == 2 && strncmp(mm->data.buf, "hi", 2) == 0) { struct mg_mqtt_opts pub_opts; memset(&pub_opts, 0, sizeof(pub_opts)); pub_opts.topic = mm->topic; // send more than 1 record, content is not relevant pub_opts.message = mg_str_n((char *)(size_t) mqtt_fn, 21098); pub_opts.qos = 1, pub_opts.retain = false; mg_mqtt_pub(c, &pub_opts); } else if (mm->data.len == 8 && strncmp(mm->data.buf, "farewell", 8) == 0) { // close on farewell MG_INFO(("%lu CLOSING", c->id)); mg_mqtt_disconnect(c, NULL); data->passed = true; } else if (mm->data.len == 21098) { struct mg_mqtt_opts pub_opts; ASSERT(memcmp((const char *) (size_t) mqtt_fn, mm->data.buf, 21098) == 0); // send farewell after receiving big data memset(&pub_opts, 0, sizeof(pub_opts)); pub_opts.topic = mm->topic; pub_opts.message = mg_str("farewell"); pub_opts.qos = 1, pub_opts.retain = false; mg_mqtt_pub(c, &pub_opts); } } else if (ev == MG_EV_CLOSE) { MG_DEBUG(("CLOSE")); s_conn = NULL; } else if (ev == MG_EV_ERROR) { MG_ERROR(("%lu ERROR %s", c->id, (char *) ev_data)); } } static void test_mqtt_connsubpub(struct mg_mgr *mgr) { struct mqtt_data data; struct mg_mqtt_opts opts; memset(&opts, 0, sizeof(opts)); opts.clean = true, opts.version = 4; data.passed = false; #if defined(MQTT_HOST) && MG_TLS != MG_TLS_BUILTIN if (host_ip == NULL) { printf("\nMQTT_HOST defined but no HOST_IP provided, skipping MQTT tests\n"); return; } printf("HOST_IP: %s\n", host_ip); #endif #if MG_TLS #if MG_TLS != MG_TLS_BUILTIN #if defined(MQTT_HOST) data.url = mg_mprintf("mqtts://%s:8883", host_ip); #else data.url = strdup(MQTTS_URL); #endif #else // MG_TLS != MG_TLS_BUILTIN #if defined(MQTT_HOST) printf("\nAssuming MQTT_HOST is NOT 1.3, ignoring it for MQTTS tests\n"); #endif data.url = strdup(MQTTS_URL); #endif #else // MG_TLS #ifdef MQTT_HOST data.url = mg_mprintf("mqtt://%s:1883", host_ip); #else data.url = strdup(MQTT_URL); #endif #endif // MG_TLS 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 (int i = 0; i < 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); mg_mgr_poll(mgr, 0); free(data.url); #if MG_ENABLE_IPV6 && defined(MQTT_HOST) && MG_TLS != MG_TLS_BUILTIN if (host_ip6 == NULL) { printf("\nMQTT_HOST defined but no HOST_IPV6 provided, skipping MQTT IPV6 tests\n"); return; } printf("HOST_IPV6: %s\n", host_ip6); #if MG_TLS #if MG_TLS != MG_TLS_BUILTIN #if defined(MQTT_HOST) data.url = mg_mprintf("mqtts://[%s]:8883", host_ip6); #else printf("\nMQTT[S] tests over IPv6 require MQTT_HOST, skipping\n"); return; //data.url = strdup(MQTTS_URL); #endif #else // MG_TLS != MG_TLS_BUILTIN #if defined(MQTT_HOST) printf("\nAssuming MQTT_HOST is NOT 1.3, ignoring it for MQTTS tests\n"); printf("\nMQTT[S] tests over IPv6 require MQTT_HOST, skipping\n"); return; #endif printf("\nMQTT[S] tests over IPv6 require MQTT_HOST, skipping\n"); return; //data.url = strdup(MQTTS_URL); #endif #else // MG_TLS #ifdef MQTT_HOST data.url = mg_mprintf("mqtt://[%s]:1883", host_ip6); #else printf("\nMQTT[S] tests over IPv6 require MQTT_HOST, skipping\n"); return; //data.url = strdup(MQTT_URL); #endif #endif // MG_TLS 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 (int i = 0; i < 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); mg_mgr_poll(mgr, 0); free(data.url); #endif } #ifndef NO_HTTPSERVER_TEST #include static void *poll_thread(void *p) { struct mg_mgr *mgr = (struct mg_mgr *) p; int i; for (i = 0; i < 300; i++) { mg_mgr_poll(mgr, 0); usleep(10000); // 10 ms. Slow down poll loop to ensure packet transit } return NULL; } #endif static void test_http_server(struct mg_mgr *mgr) { #ifdef NO_HTTPSERVER_TEST (void) mgr; #else struct mg_connection *c; char *cmd; pthread_t thread_id = (pthread_t) 0; #if MG_TLS struct mg_tls_opts opts; memset(&opts, 0, sizeof(opts)); mg_mem_files = mg_packed_files; // Use generated packed filesystem // opts.ca = mg_str(s_tls_ca); opts.cert = mg_unpacked("/certs/server.crt"); opts.key = mg_unpacked("/certs/server.key"); mg_hexdump(opts.cert.buf, opts.cert.len); mg_hexdump(opts.key.buf, opts.key.len); c = mg_http_listen(mgr, "https://0.0.0.0:12347", eh1, &opts); cmd = mg_mprintf("./mip_curl.sh --insecure https://%M:12347", mg_print_ip4, &mgr->ifp->ip); #else c = mg_http_listen(mgr, "http://0.0.0.0:12347", eh1, NULL); cmd = mg_mprintf("./mip_curl.sh http://%M:12347", mg_print_ip4, &mgr->ifp->ip); #endif ASSERT(c != NULL); ASSERT (mg_send(c, "NADA", 0)); // check mg_send allows len=0 pthread_create(&thread_id, NULL, poll_thread, mgr); // simpler this way, no concurrency anyway MG_DEBUG(("CURL")); ASSERT(system(cmd) == 0); // wait for curl MG_DEBUG(("MONGOOSE")); pthread_join(thread_id, NULL); // wait for Mongoose MG_DEBUG(("DONE")); free(cmd); #endif } static void test_tls(struct mg_mgr *mgr) { #if MG_TLS char *url; char buf[FETCH_BUF_SIZE]; // make sure it can hold Makefile mg_mem_files = mg_packed_files; // Use generated packed filesystem struct mg_str data = mg_unpacked("/Makefile"); if (host_ip == NULL) { printf("\nNo HOST_IP provided, skipping TLS tests\n"); return; } printf("HOST_IP: %s\n", host_ip); printf("NO SIMPLE TLS TEST, no known way to connect to ourselves and no server in HOST_IP\n"); #if MG_TLS == MG_TLS_BUILTIN && defined(__linux__) && \ MG_ENABLE_CHACHA20 // skip for non-CHACHA tests // - Fire patched server, test multiple TLS records per TCP segment handling // skip other TLS stacks to avoid "bad client hello", we are 1.3 only if (access("tls_multirec/server", X_OK) == 0) { url = mg_mprintf("https://%s:8443", host_ip); ASSERT(system("tls_multirec/server -d tls_multirec &") == 0); sleep(1); // fetch() needs to loop enough times in order to process all TLS records; // otherwise it will end with 200 and shorter file contents ASSERT(fetch(mgr, buf, url, "GET /thefile HTTP/1.0\n\n") == 200); ASSERT(cmpbody(buf, data.buf) == 0); // "thefile" links to Makefile ASSERT(system("killall tls_multirec/server") == 0); free(url); } else { printf("SKIPPED TLS MULTIPLE RECORDS TEST, tls_multirec/server NOT PRESENT\n"); } #else printf("SKIPPED TLS MULTIPLE RECORDS TEST, not a known TLS 1.3 stack\n"); (void) cmpbody("", ""); (void) mgr; (void) url; // these three: NO SIMPLE TLS TEST (void) buf; (void) data; #endif #else (void) cmpbody("", ""); (void) mgr; #endif } #if MG_TLS static bool unixms(void) { bool res = false; #if MG_ARCH == MG_ARCH_UNIX struct timeval tv = {0, 0}; gettimeofday(&tv, 0); mg_boot_timestamp_ms = (uint64_t)((int64_t) tv.tv_sec * 1000 + tv.tv_usec / 1000); res = true; #endif return res; } static void sntpcb(struct mg_connection *c, int ev, void *ev_data) { if (ev == MG_EV_SNTP_TIME) *(int64_t *) c->fn_data = *(int64_t *) ev_data; } static bool sntpms(struct mg_mgr *mgr, const char *url) { int64_t ms = 0; int i; mg_sntp_connect(mgr, url, sntpcb, &ms); for (i = 0; i < 50 && ms == 0; i++) { mg_mgr_poll(mgr, 0); usleep(10000); // 10 ms. Slow down poll loop to ensure packet transit } return ms > 0; } static void gettimefortls(struct mg_mgr *mgr) { // NOTE(): historical NTP port blockage issue; expect at least one to be // reachable and work. https://github.com/actions/runner-images/issues/5615 if (sntpms(mgr, "udp://time.apple.com:123") || sntpms(mgr, "udp://time.windows.com:123") || sntpms(mgr, NULL) || unixms()) return; mg_boot_timestamp_ms = (uint64_t) time(NULL) * 1000; } #endif bool mip_x_test(struct mg_mgr *mgr) { host_ip = getenv("HOST_IP"); host_ip6 = getenv("HOST_IPV6"); #if MG_TLS // Feel free to move to other module to support more systems... gettimefortls(mgr); #endif #define DASHBOARD(x) printf("HEALTH_DASHBOARD\t\"%s\": %s,\n", x, s_error ? "false":"true"); usleep(500000); // 500 ms s_error = false; test_http_client(mgr); DASHBOARD("http_client"); usleep(500000); // 500 ms s_error = false; test_http_server(mgr); DASHBOARD("http_server"); usleep(500000); // 500 ms s_error = false; test_tls(mgr); DASHBOARD("tls"); usleep(500000); // 500 ms s_error = false; test_mqtt_connsubpub(mgr); DASHBOARD("mqtt"); // Clear s_error = false; mg_mgr_free(mgr); ASSERT(mgr->conns == NULL); // Deconstruction OK printf("HEALTH_DASHBOARD\t\"cleanup\": %s\n", s_error ? "false":"true"); // last entry with no comma #ifdef NO_ABORT if (s_abort != 0) return false; #endif printf("SUCCESS. Total tests: %d\n", s_num_tests); return true; }