mirror of
https://github.com/cesanta/mongoose.git
synced 2026-10-13 10:15:00 +00:00
+24
-12
@@ -5042,6 +5042,7 @@ static void mkpay(struct pkt *pkt, void *p) {
|
||||
mg_str_n((char *) p, (size_t) (&pkt->pay.buf[pkt->pay.len] - (char *) p));
|
||||
}
|
||||
|
||||
// NOTE(): DOES NOT handle reentries after odd length, use last
|
||||
static uint32_t csumup(uint32_t sum, const void *buf, size_t len) {
|
||||
size_t i;
|
||||
const uint8_t *p = (const uint8_t *) buf;
|
||||
@@ -5192,18 +5193,25 @@ static bool tx_udp(struct mg_tcpip_if *ifp, uint8_t *l2_dst,
|
||||
udp->len = mg_htons((uint16_t) (sizeof(*udp) + len));
|
||||
udp->csum = 0;
|
||||
cs = csumup(0, udp, sizeof(*udp));
|
||||
cs = csumup(cs, buf, len);
|
||||
#if MG_ENABLE_IPV6
|
||||
if (ip_dst->is_ip6) {
|
||||
uint32_t pseudo[2];
|
||||
cs = csumup(cs, &ip6->src, sizeof(ip6->src));
|
||||
cs = csumup(cs, &ip6->dst, sizeof(ip6->dst));
|
||||
pseudo[0] = mg_htonl((uint32_t) (sizeof(*udp) + len));
|
||||
pseudo[1] = mg_htonl(17);
|
||||
cs = csumup(cs, pseudo, 2 * sizeof(uint32_t));
|
||||
} else
|
||||
#endif
|
||||
{
|
||||
uint16_t pseudo[2];
|
||||
cs = csumup(cs, &ip->src, sizeof(ip->src));
|
||||
cs = csumup(cs, &ip->dst, sizeof(ip->dst));
|
||||
pseudo[0] = mg_htons(17);
|
||||
pseudo[1] = udp->len;
|
||||
cs = csumup(cs, pseudo, 2 * sizeof(uint16_t));
|
||||
}
|
||||
cs += (uint32_t) (17 + sizeof(*udp) + len);
|
||||
cs = csumup(cs, buf, len); // possibly odd length must be last
|
||||
udp->csum = csumfin(cs);
|
||||
memmove(udp + 1, buf, len);
|
||||
l2_len = mg_l2_footer(ifp->l2type, l2_len, l2p);
|
||||
@@ -5520,6 +5528,7 @@ static void tx_icmp6(struct mg_tcpip_if *ifp, uint8_t *l2_dst, uint64_t *ip_src,
|
||||
struct ip6 *ip6;
|
||||
struct icmp6 *icmp6;
|
||||
uint32_t cs;
|
||||
uint16_t pseudo[2];
|
||||
ip6 = tx_ip6(ifp, l2_dst, 58, ip_src, ip_dst, sizeof(*icmp6) + len);
|
||||
icmp6 = (struct icmp6 *) (ip6 + 1);
|
||||
memset(icmp6, 0, sizeof(*icmp6)); // Set csum to 0
|
||||
@@ -5528,10 +5537,12 @@ static void tx_icmp6(struct mg_tcpip_if *ifp, uint8_t *l2_dst, uint64_t *ip_src,
|
||||
memcpy(icmp6 + 1, buf, len); // Copy payload
|
||||
icmp6->csum = 0; // RFC-4443 2.3, RFC-8200 8.1
|
||||
cs = csumup(0, icmp6, sizeof(*icmp6));
|
||||
cs = csumup(cs, buf, len);
|
||||
cs = csumup(cs, ip_src, 16);
|
||||
cs = csumup(cs, ip_dst, 16);
|
||||
cs += (uint32_t) (58 + sizeof(*icmp6) + len);
|
||||
pseudo[0] = htons(58);
|
||||
pseudo[1] = htons((uint16_t) (sizeof(*icmp6) + len));
|
||||
cs = csumup(cs, pseudo, 4);
|
||||
cs = csumup(cs, buf, len); // possibly odd length must be last
|
||||
icmp6->csum = csumfin(cs);
|
||||
driver_output(
|
||||
ifp, mg_l2_footer(ifp->l2type, sizeof(*ip6) + sizeof(*icmp6) + len, l2p));
|
||||
@@ -5922,24 +5933,25 @@ static size_t tx_tcp(struct mg_tcpip_if *ifp, uint8_t *l2_dst,
|
||||
{
|
||||
uint32_t cs = 0;
|
||||
uint16_t n = (uint16_t) (sizeof(*tcp) + len);
|
||||
cs = csumup(cs, tcp, n);
|
||||
#if MG_ENABLE_IPV6
|
||||
if (ip_dst->is_ip6) {
|
||||
uint32_t pseudo[2];
|
||||
cs = csumup(cs, &ip6->src, sizeof(ip6->src));
|
||||
cs = csumup(cs, &ip6->dst, sizeof(ip6->dst));
|
||||
cs += (uint32_t) (6 + n);
|
||||
pseudo[0] = mg_htonl((uint32_t) n);
|
||||
pseudo[1] = mg_htonl(6);
|
||||
cs = csumup(cs, pseudo, 2 * sizeof(uint32_t));
|
||||
} else
|
||||
#endif
|
||||
{
|
||||
uint8_t pseudo[4];
|
||||
pseudo[0] = 0;
|
||||
pseudo[1] = ip->proto;
|
||||
pseudo[2] = (uint8_t) (n >> 8);
|
||||
pseudo[3] = (uint8_t) (n & 255);
|
||||
uint16_t pseudo[2];
|
||||
cs = csumup(cs, &ip->src, sizeof(ip->src));
|
||||
cs = csumup(cs, &ip->dst, sizeof(ip->dst));
|
||||
cs = csumup(cs, pseudo, sizeof(pseudo));
|
||||
pseudo[0] = mg_htons(6);
|
||||
pseudo[1] = mg_htons(n);
|
||||
cs = csumup(cs, pseudo, 2 * sizeof(uint16_t));
|
||||
}
|
||||
cs = csumup(cs, tcp, n); // possibly odd length must be last
|
||||
tcp->csum = csumfin(cs);
|
||||
}
|
||||
MG_VERBOSE(("TCP %M -> %M fl %x len %u", mg_print_ip_port, ip_src,
|
||||
|
||||
+24
-12
@@ -216,6 +216,7 @@ static void mkpay(struct pkt *pkt, void *p) {
|
||||
mg_str_n((char *) p, (size_t) (&pkt->pay.buf[pkt->pay.len] - (char *) p));
|
||||
}
|
||||
|
||||
// NOTE(): DOES NOT handle reentries after odd length, use last
|
||||
static uint32_t csumup(uint32_t sum, const void *buf, size_t len) {
|
||||
size_t i;
|
||||
const uint8_t *p = (const uint8_t *) buf;
|
||||
@@ -366,18 +367,25 @@ static bool tx_udp(struct mg_tcpip_if *ifp, uint8_t *l2_dst,
|
||||
udp->len = mg_htons((uint16_t) (sizeof(*udp) + len));
|
||||
udp->csum = 0;
|
||||
cs = csumup(0, udp, sizeof(*udp));
|
||||
cs = csumup(cs, buf, len);
|
||||
#if MG_ENABLE_IPV6
|
||||
if (ip_dst->is_ip6) {
|
||||
uint32_t pseudo[2];
|
||||
cs = csumup(cs, &ip6->src, sizeof(ip6->src));
|
||||
cs = csumup(cs, &ip6->dst, sizeof(ip6->dst));
|
||||
pseudo[0] = mg_htonl((uint32_t) (sizeof(*udp) + len));
|
||||
pseudo[1] = mg_htonl(17);
|
||||
cs = csumup(cs, pseudo, 2 * sizeof(uint32_t));
|
||||
} else
|
||||
#endif
|
||||
{
|
||||
uint16_t pseudo[2];
|
||||
cs = csumup(cs, &ip->src, sizeof(ip->src));
|
||||
cs = csumup(cs, &ip->dst, sizeof(ip->dst));
|
||||
pseudo[0] = mg_htons(17);
|
||||
pseudo[1] = udp->len;
|
||||
cs = csumup(cs, pseudo, 2 * sizeof(uint16_t));
|
||||
}
|
||||
cs += (uint32_t) (17 + sizeof(*udp) + len);
|
||||
cs = csumup(cs, buf, len); // possibly odd length must be last
|
||||
udp->csum = csumfin(cs);
|
||||
memmove(udp + 1, buf, len);
|
||||
l2_len = mg_l2_footer(ifp->l2type, l2_len, l2p);
|
||||
@@ -694,6 +702,7 @@ static void tx_icmp6(struct mg_tcpip_if *ifp, uint8_t *l2_dst, uint64_t *ip_src,
|
||||
struct ip6 *ip6;
|
||||
struct icmp6 *icmp6;
|
||||
uint32_t cs;
|
||||
uint16_t pseudo[2];
|
||||
ip6 = tx_ip6(ifp, l2_dst, 58, ip_src, ip_dst, sizeof(*icmp6) + len);
|
||||
icmp6 = (struct icmp6 *) (ip6 + 1);
|
||||
memset(icmp6, 0, sizeof(*icmp6)); // Set csum to 0
|
||||
@@ -702,10 +711,12 @@ static void tx_icmp6(struct mg_tcpip_if *ifp, uint8_t *l2_dst, uint64_t *ip_src,
|
||||
memcpy(icmp6 + 1, buf, len); // Copy payload
|
||||
icmp6->csum = 0; // RFC-4443 2.3, RFC-8200 8.1
|
||||
cs = csumup(0, icmp6, sizeof(*icmp6));
|
||||
cs = csumup(cs, buf, len);
|
||||
cs = csumup(cs, ip_src, 16);
|
||||
cs = csumup(cs, ip_dst, 16);
|
||||
cs += (uint32_t) (58 + sizeof(*icmp6) + len);
|
||||
pseudo[0] = htons(58);
|
||||
pseudo[1] = htons((uint16_t) (sizeof(*icmp6) + len));
|
||||
cs = csumup(cs, pseudo, 4);
|
||||
cs = csumup(cs, buf, len); // possibly odd length must be last
|
||||
icmp6->csum = csumfin(cs);
|
||||
driver_output(
|
||||
ifp, mg_l2_footer(ifp->l2type, sizeof(*ip6) + sizeof(*icmp6) + len, l2p));
|
||||
@@ -1096,24 +1107,25 @@ static size_t tx_tcp(struct mg_tcpip_if *ifp, uint8_t *l2_dst,
|
||||
{
|
||||
uint32_t cs = 0;
|
||||
uint16_t n = (uint16_t) (sizeof(*tcp) + len);
|
||||
cs = csumup(cs, tcp, n);
|
||||
#if MG_ENABLE_IPV6
|
||||
if (ip_dst->is_ip6) {
|
||||
uint32_t pseudo[2];
|
||||
cs = csumup(cs, &ip6->src, sizeof(ip6->src));
|
||||
cs = csumup(cs, &ip6->dst, sizeof(ip6->dst));
|
||||
cs += (uint32_t) (6 + n);
|
||||
pseudo[0] = mg_htonl((uint32_t) n);
|
||||
pseudo[1] = mg_htonl(6);
|
||||
cs = csumup(cs, pseudo, 2 * sizeof(uint32_t));
|
||||
} else
|
||||
#endif
|
||||
{
|
||||
uint8_t pseudo[4];
|
||||
pseudo[0] = 0;
|
||||
pseudo[1] = ip->proto;
|
||||
pseudo[2] = (uint8_t) (n >> 8);
|
||||
pseudo[3] = (uint8_t) (n & 255);
|
||||
uint16_t pseudo[2];
|
||||
cs = csumup(cs, &ip->src, sizeof(ip->src));
|
||||
cs = csumup(cs, &ip->dst, sizeof(ip->dst));
|
||||
cs = csumup(cs, pseudo, sizeof(pseudo));
|
||||
pseudo[0] = mg_htons(6);
|
||||
pseudo[1] = mg_htons(n);
|
||||
cs = csumup(cs, pseudo, 2 * sizeof(uint16_t));
|
||||
}
|
||||
cs = csumup(cs, tcp, n); // possibly odd length must be last
|
||||
tcp->csum = csumfin(cs);
|
||||
}
|
||||
MG_VERBOSE(("TCP %M -> %M fl %x len %u", mg_print_ip_port, ip_src,
|
||||
|
||||
@@ -91,6 +91,15 @@ mip_tap_test: mip_tap_test.c mongoose.c mongoose.h packed_fs.c Makefile tls_mult
|
||||
$(CC) mip_tap_test.c packed_fs.c $(CFLAGS) $(LDFLAGS) -o $@
|
||||
ASAN_OPTIONS=$(ASAN_OPTIONS) $(RUN) ./$@
|
||||
|
||||
# bridge UDP port <--> TAP interface
|
||||
port_tap_bridge: port_tap_bridge.c
|
||||
cc port_tap_bridge.c -o $@
|
||||
|
||||
# requires port_tap_bridge to be running
|
||||
mip_port_test: mip_port_test.c mongoose.c mongoose.h packed_fs.c Makefile tls_multirec/server
|
||||
$(CC) mip_port_test.c packed_fs.c $(CFLAGS) $(LDFLAGS) -o $@
|
||||
ASAN_OPTIONS=$(ASAN_OPTIONS) $(RUN) ./$@
|
||||
|
||||
mip_vc98: mip_test.c mongoose.c mongoose.h packed_fs.c Makefile
|
||||
$(DOCKER) mdashnet/vc98 wine cl mip_test.c packed_fs.c $(VCFLAGS) $(DEFS) $(TFLAGS) /Fe$@.exe
|
||||
$(DOCKER) -e WINEPREFIX=/tmp/wineprefix mdashnet/vc98 wine $@.exe
|
||||
@@ -183,6 +192,19 @@ s390: CC = $(DOCKER) mdashnet/s390 cc
|
||||
s390: RUN = $(DOCKER) --init mdashnet/s390
|
||||
s390: test
|
||||
|
||||
mip_s390: ASAN=
|
||||
mip_s390: CC = $(DOCKER) mdashnet/s390 cc
|
||||
mip_s390: RUN = $(DOCKER) --init mdashnet/s390
|
||||
mip_s390: mip_test
|
||||
|
||||
mip_port_s390: ASAN=
|
||||
mip_port_s390: IPV6=0
|
||||
# This test requires curl, not present in this image
|
||||
mip_port_s390: CFLAGS += -DNO_HTTPSERVER_TEST
|
||||
mip_port_s390: CC = $(DOCKER) mdashnet/s390 cc
|
||||
mip_port_s390: RUN = $(DOCKER) --init mdashnet/s390
|
||||
mip_port_s390: mip_port_test
|
||||
|
||||
arm: DEFS += -DMG_ENABLE_POSIX_FS=0 -DMG_ENABLE_TCPIP=1 -DMG_ENABLE_TCPIP_DRIVER_INIT=0 -DMG_ARCH=MG_ARCH_ARMGCC -DNO_SLEEP_ABORT
|
||||
arm: mongoose.h $(SRCS)
|
||||
$(DOCKER) mdashnet/armgcc arm-none-eabi-gcc -mcpu=cortex-m3 -mthumb $(SRCS) $(OPTS) $(WARN) $(INCS) $(DEFS) $(TFLAGS) -o unit_test -nostartfiles --specs nosys.specs -e 0
|
||||
|
||||
@@ -0,0 +1,119 @@
|
||||
#define MIPPORTTEST_USING_DHCP 1
|
||||
|
||||
#include <sys/socket.h>
|
||||
#include <sys/ioctl.h>
|
||||
|
||||
#include "mip_x_test.c"
|
||||
|
||||
struct port_driver_data {
|
||||
int sockfd;
|
||||
struct sockaddr_in port_addr;
|
||||
struct sockaddr_in tap_addr;
|
||||
};
|
||||
|
||||
// MIP Socket driver
|
||||
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);
|
||||
usleep(1); // This is to avoid 100% CPU
|
||||
if (received < 0) return 0;
|
||||
return (size_t) received;
|
||||
}
|
||||
|
||||
static size_t sock_tx(const void *buf, size_t len, struct mg_tcpip_if *ifp) {
|
||||
ssize_t res = send(((struct port_driver_data *)ifp->driver_data)->sockfd, buf, len, 0);
|
||||
if (res < 0) {
|
||||
MG_ERROR(("sock_tx failed: %d", errno));
|
||||
return 0;
|
||||
}
|
||||
return (size_t) res;
|
||||
}
|
||||
|
||||
static bool sock_poll(struct mg_tcpip_if *ifp, bool s1) {
|
||||
return s1 && ifp->driver_data ? true : false;
|
||||
}
|
||||
|
||||
|
||||
int main(void) {
|
||||
bool result;
|
||||
const char *debug_level = getenv("V");
|
||||
// Setup interface
|
||||
const uint16_t port = 0xAA55; // UDP port
|
||||
const char *mac = "02:00:01:02:03:78"; // MAC address
|
||||
|
||||
struct port_driver_data pdd;
|
||||
pdd.sockfd = socket(AF_INET, SOCK_DGRAM, 0);
|
||||
pdd.port_addr.sin_family = AF_INET;
|
||||
pdd.port_addr.sin_addr.s_addr = htonl(INADDR_ANY);
|
||||
pdd.port_addr.sin_port = htons(port);
|
||||
if (bind(pdd.sockfd, (struct sockaddr *) &pdd.port_addr, sizeof(pdd.port_addr)) < 0) return EXIT_FAILURE;
|
||||
printf("Opened UDP socket\n");
|
||||
|
||||
pdd.tap_addr.sin_family = AF_INET;
|
||||
pdd.tap_addr.sin_addr.s_addr = htonl(0x7f000001U); // 127.0.0.1
|
||||
pdd.tap_addr.sin_port = htons(0x55AA);
|
||||
if (connect(pdd.sockfd, (struct sockaddr *) &pdd.tap_addr, sizeof(pdd.tap_addr)) < 0) return EXIT_FAILURE;
|
||||
printf("Connected to TAP UDP socket\n");
|
||||
|
||||
usleep(200000); // 200 ms
|
||||
|
||||
if (debug_level == NULL) debug_level = "3";
|
||||
mg_log_set(atoi(debug_level));
|
||||
|
||||
struct mg_mgr mgr; // Event manager
|
||||
mg_mgr_init(&mgr); // Initialise event manager
|
||||
|
||||
// MIP driver
|
||||
struct mg_tcpip_driver driver;
|
||||
memset(&driver, 0, sizeof(driver));
|
||||
|
||||
driver.tx = sock_tx;
|
||||
driver.poll = sock_poll;
|
||||
driver.rx = sock_rx;
|
||||
|
||||
struct mg_tcpip_if mif;
|
||||
memset(&mif, 0, sizeof(mif));
|
||||
|
||||
mif.driver = &driver;
|
||||
mif.driver_data = &pdd;
|
||||
|
||||
#if MIPPORTTEST_USING_DHCP == 1
|
||||
#else
|
||||
mif.ip = mg_htonl(MG_U32(192, 168, 32, 2)); // Triggering a network failure
|
||||
mif.mask = mg_htonl(MG_U32(255, 255, 255, 0));
|
||||
mif.gw = mg_htonl(MG_U32(192, 168, 32, 1));
|
||||
#endif
|
||||
|
||||
sscanf(mac, "%hhx:%hhx:%hhx:%hhx:%hhx:%hhx", &mif.mac[0], &mif.mac[1],
|
||||
&mif.mac[2], &mif.mac[3], &mif.mac[4], &mif.mac[5]);
|
||||
|
||||
mg_tcpip_init(&mgr, &mif);
|
||||
MG_INFO(("Init done, starting main loop"));
|
||||
usleep(200000); // 200 ms
|
||||
|
||||
// Stack initialization, Network configuration (DHCP lease, ...)
|
||||
#if MIPPORTTEST_USING_DHCP == 0
|
||||
MG_INFO(("MIF configuration: Static IP"));
|
||||
ASSERT(mif.ip != 0); // Check we have a satic IP assigned
|
||||
mg_mgr_poll(&mgr, 100); // For initialisation
|
||||
#else
|
||||
MG_INFO(("MIF configuration: DHCP"));
|
||||
ASSERT(!mif.ip); // Check we are set for DHCP
|
||||
int pc = 500; // Timeout on DHCP lease 500 ~ approx 5s (typical delay <1s)
|
||||
while (((pc--) > 0) && !mif.ip) {
|
||||
mg_mgr_poll(&mgr, 100);
|
||||
usleep(10000); // 10 ms
|
||||
}
|
||||
if (!mif.ip) MG_ERROR(("No ip assigned (DHCP lease may have failed).\n"));
|
||||
ASSERT(mif.ip); // We have an IP (lease or static)
|
||||
#endif
|
||||
while (mif.state != MG_TCPIP_STATE_READY) {
|
||||
mg_mgr_poll(&mgr, 100);
|
||||
usleep(10000); // 10 ms
|
||||
}
|
||||
|
||||
// RUN TESTS
|
||||
result = mip_x_test(&mgr);
|
||||
close(pdd.sockfd);
|
||||
if (!result) return EXIT_FAILURE;
|
||||
return EXIT_SUCCESS;
|
||||
}
|
||||
+4
-452
@@ -1,10 +1,5 @@
|
||||
#define MG_ENABLE_TCPIP 1
|
||||
#define MG_ENABLE_TCPIP_DRIVER_INIT 0
|
||||
|
||||
#define MIPTAPTEST_USING_DHCP 1
|
||||
|
||||
#define FETCH_BUF_SIZE (16 * 1024)
|
||||
|
||||
#include <sys/socket.h>
|
||||
#ifndef __OpenBSD__
|
||||
#include <linux/if.h>
|
||||
@@ -16,112 +11,8 @@
|
||||
#endif
|
||||
#include <sys/ioctl.h>
|
||||
|
||||
#include "mongoose.c"
|
||||
#include "mip_x_test.c"
|
||||
|
||||
#include "driver_mock.c"
|
||||
|
||||
#ifdef MQTT_LOCALHOST
|
||||
#define MQTT_URL "mqtt://127.0.0.1:1883"
|
||||
#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"
|
||||
"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\n"
|
||||
"-----END CERTIFICATE-----\n";
|
||||
#elif MG_TLS
|
||||
#ifdef MQTT_LOCALHOST
|
||||
// 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_LOCALHOST
|
||||
#endif
|
||||
|
||||
static char *host_ip;
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
// MIP TUNTAP driver
|
||||
static size_t tap_rx(void *buf, size_t len, struct mg_tcpip_if *ifp) {
|
||||
@@ -144,313 +35,9 @@ static bool tap_poll(struct mg_tcpip_if *ifp, bool s1) {
|
||||
return s1 && ifp->driver_data ? true : false;
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
}
|
||||
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");
|
||||
#if MG_TLS == MG_TLS_BUILTIN
|
||||
// our TLS does not search for the proper CA in a bundle
|
||||
opts.ca = mg_file_read(&mg_fs_posix, "data/e5.crt");
|
||||
#endif
|
||||
}
|
||||
mg_tls_init(c, &opts);
|
||||
#if MG_TLS == MG_TLS_BUILTIN
|
||||
mg_free((void *) opts.ca.buf);
|
||||
#endif
|
||||
}
|
||||
} 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)
|
||||
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 = MG_ENABLE_IPV6;
|
||||
#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;
|
||||
opts.name = mg_url_host(data->url);
|
||||
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_LOCALHOST) && MG_TLS != MG_TLS_BUILTIN
|
||||
if (host_ip == NULL) {
|
||||
printf("\nMQTT_LOCALHOST defined but no HOST_IP provided, skipping MQTTS tests\n");
|
||||
return;
|
||||
}
|
||||
printf("HOST_IP: %s\n", host_ip);
|
||||
#endif
|
||||
#if MG_TLS
|
||||
#if defined(MQTT_LOCALHOST) && MG_TLS != MG_TLS_BUILTIN
|
||||
data.url = mg_mprintf("mqtts://%s:8883", host_ip);
|
||||
#else
|
||||
data.url = strdup(MQTTS_URL);
|
||||
#endif
|
||||
#else
|
||||
#ifdef MQTT_LOCALHOST
|
||||
data.url = mg_mprintf("mqtt://%s:1883", host_ip);
|
||||
#else
|
||||
data.url = strdup(MQTT_URL);
|
||||
#endif
|
||||
#endif
|
||||
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(10000); // 10 ms. Slow down poll loop to ensure packets transit
|
||||
}
|
||||
ASSERT(data.passed);
|
||||
mg_mgr_poll(mgr, 0);
|
||||
free(data.url);
|
||||
}
|
||||
|
||||
#include <pthread.h>
|
||||
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;
|
||||
}
|
||||
|
||||
static void test_http_server(struct mg_mgr *mgr) {
|
||||
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));
|
||||
// opts.ca = mg_str(s_tls_ca);
|
||||
opts.cert = mg_unpacked("/certs/server.crt");
|
||||
opts.key = mg_unpacked("/certs/server.key");
|
||||
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);
|
||||
}
|
||||
|
||||
static void test_tls(struct mg_mgr *mgr) {
|
||||
#if MG_TLS
|
||||
char *url;
|
||||
char buf[FETCH_BUF_SIZE]; // make sure it can hold Makefile
|
||||
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);
|
||||
// - POST a large file, make sure we drain TLS buffers and read all: done at
|
||||
// server test, using curl as POSTing client
|
||||
// - Fire patched server, test multiple TLS records per TCP segment handling
|
||||
url = mg_mprintf("https://%s:8443", host_ip); // for historic reasons
|
||||
ASSERT(system("tls_multirec/server -d tls_multirec &") == 0);
|
||||
sleep(1);
|
||||
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
|
||||
(void) cmpbody("", "");
|
||||
(void) mgr;
|
||||
#endif
|
||||
}
|
||||
|
||||
int main(void) {
|
||||
bool result;
|
||||
const char *debug_level = getenv("V");
|
||||
// Setup interface
|
||||
const char *iface = "tap0"; // Network iface
|
||||
@@ -485,9 +72,6 @@ int main(void) {
|
||||
if (debug_level == NULL) debug_level = "3";
|
||||
mg_log_set(atoi(debug_level));
|
||||
|
||||
host_ip = getenv("HOST_IP");
|
||||
|
||||
// Events
|
||||
struct mg_mgr mgr; // Event manager
|
||||
mg_mgr_init(&mgr); // Initialise event manager
|
||||
|
||||
@@ -540,41 +124,9 @@ int main(void) {
|
||||
usleep(10000); // 10 ms
|
||||
}
|
||||
|
||||
#define DASHBOARD(x) printf("HEALTH_DASHBOARD\t\"%s\": %s,\n", x, s_error ? "false":"true");
|
||||
|
||||
// RUN TESTS
|
||||
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
|
||||
result = mip_x_test(&mgr);
|
||||
close(fd);
|
||||
printf("HEALTH_DASHBOARD\t\"cleanup\": %s\n", s_error ? "false":"true");
|
||||
// last entry with no comma
|
||||
|
||||
#ifdef NO_ABORT
|
||||
if (s_abort != 0) return EXIT_FAILURE;
|
||||
#endif
|
||||
|
||||
printf("SUCCESS. Total tests: %d\n", s_num_tests);
|
||||
if (!result) return EXIT_FAILURE;
|
||||
return EXIT_SUCCESS;
|
||||
}
|
||||
|
||||
+114
-19
@@ -41,10 +41,100 @@ struct ipp {
|
||||
static void test_csum(void) {
|
||||
uint8_t ip[20] = {0x45, 0x00, 0x00, 0x1c, 0x00, 0x00, 0x00, 0x00, 0x28, 0x11,
|
||||
0x94, 0xcf, 0x7f, 0x00, 0x00, 0x01, 0x7f, 0x00, 0x00, 0x01};
|
||||
uint8_t udp_odd[53] = {0xc0, 0xa8, 0x45, 0x58, 0x08, 0x08, 0x08, 0x08, 0x00,
|
||||
0x11, 0x00, 0x29, 0xad, 0x67, 0x00, 0x35, 0x00, 0x29,
|
||||
0xaf, 0xf8, 0x00, 0x01, 0x01, 0x00, 0x00, 0x01, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x74, 0x69, 0x6d,
|
||||
0x65, 0x06, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x03,
|
||||
0x63, 0x6f, 0x6d, 0x00, 0x00, 0x01, 0x00, 0x01};
|
||||
|
||||
ASSERT(ipcsum(ip, 20) == 0);
|
||||
ASSERT(ipcsum(udp_odd, 53) == 0);
|
||||
// UDP and TCP checksum calc funcions use the same basic calls as ipcsum()
|
||||
}
|
||||
|
||||
#if defined(__DCC__)
|
||||
#pragma pack(1)
|
||||
#else
|
||||
#pragma pack(push, 1)
|
||||
#endif
|
||||
|
||||
struct pseudoip {
|
||||
uint32_t src; // Source IP
|
||||
uint32_t dst; // Destination IP
|
||||
uint8_t zero;
|
||||
uint8_t proto; // Upper level protocol
|
||||
uint16_t len; // Datagram length
|
||||
};
|
||||
|
||||
struct pseudoip6 {
|
||||
uint64_t src[2]; // Source IP
|
||||
uint64_t dst[2]; // Destination IP
|
||||
uint32_t plen; // Payload length
|
||||
uint8_t zero[3];
|
||||
uint8_t next; // Upper level protocol
|
||||
};
|
||||
|
||||
#if defined(__DCC__)
|
||||
#pragma pack(0)
|
||||
#else
|
||||
#pragma pack(pop)
|
||||
#endif
|
||||
|
||||
static bool test_udp_csum(void *d, void *u) {
|
||||
struct ip *ip = (struct ip *) d;
|
||||
struct udp *udp = (struct udp *) u;
|
||||
struct pseudoip pseudo, *pip;
|
||||
pseudo.src = ip->src;
|
||||
pseudo.dst = ip->dst;
|
||||
pseudo.zero = 0;
|
||||
pseudo.proto = ip->proto;
|
||||
pseudo.len = udp->len;
|
||||
pip = (struct pseudoip *)((size_t) u - sizeof(*pip));
|
||||
memcpy(pip, &pseudo, sizeof(*pip));
|
||||
return (ipcsum(pip, sizeof(*pip) + mg_ntohs(udp->len)) == 0);
|
||||
}
|
||||
|
||||
static bool test_udp6_csum(void *d, void *u) {
|
||||
struct ip6 *ip = (struct ip6 *) d;
|
||||
struct udp *udp = (struct udp *) u;
|
||||
struct pseudoip6 pseudo, *pip;
|
||||
pseudo.src[0] = ip->src[0], pseudo.src[1] = ip->src[1];
|
||||
pseudo.dst[0] = ip->dst[0], pseudo.dst[1] = ip->dst[1];
|
||||
pseudo.zero[0] = 0, pseudo.zero[1] = 0, pseudo.zero[2] = 0;
|
||||
pseudo.plen = mg_htonl((uint32_t) mg_ntohs(udp->len));
|
||||
pseudo.next = ip->next;
|
||||
pip = (struct pseudoip6 *) ((size_t) u - sizeof(*pip));
|
||||
memcpy(pip, &pseudo, sizeof(*pip));
|
||||
return (ipcsum(pip, sizeof(*pip) + mg_ntohs(udp->len)) == 0);
|
||||
}
|
||||
|
||||
static bool test_tcp_csum(void *d, void *t) {
|
||||
struct ip *ip = (struct ip *) d;
|
||||
struct pseudoip pseudo, *pip;
|
||||
pseudo.src = ip->src;
|
||||
pseudo.dst = ip->dst;
|
||||
pseudo.zero = 0;
|
||||
pseudo.proto = ip->proto;
|
||||
pseudo.len = mg_htons((uint16_t)(mg_ntohs(ip->len) - (ip->ver & 0x0F) * 4));
|
||||
pip = (struct pseudoip *)((size_t) t - sizeof(*pip));
|
||||
memcpy(pip, &pseudo, sizeof(*pip));
|
||||
return (ipcsum(pip, sizeof(*pip) + mg_ntohs(pip->len)) == 0);
|
||||
}
|
||||
|
||||
static bool test_tcp6_csum(void *d, void *t) {
|
||||
struct ip6 *ip = (struct ip6 *) d;
|
||||
struct pseudoip6 pseudo, *pip;
|
||||
pseudo.src[0] = ip->src[0], pseudo.src[1] = ip->src[1];
|
||||
pseudo.dst[0] = ip->dst[0], pseudo.dst[1] = ip->dst[1];
|
||||
pseudo.zero[0] = 0, pseudo.zero[1] = 0, pseudo.zero[2] = 0;
|
||||
pseudo.plen = mg_htonl((uint32_t) mg_ntohs(ip->plen));
|
||||
pseudo.next = ip->next;
|
||||
pip = (struct pseudoip6 *) ((size_t) t - sizeof(*pip));
|
||||
memcpy(pip, &pseudo, sizeof(*pip));
|
||||
return (ipcsum(pip, sizeof(*pip) + mg_ntohl(pip->plen)) == 0);
|
||||
}
|
||||
|
||||
static bool executed = false;
|
||||
|
||||
static void mif_fn(struct mg_tcpip_if *ifp, int ev, void *ev_data) {
|
||||
@@ -78,8 +168,8 @@ static void mif6_fn(struct mg_tcpip_if *ifp, int ev, void *ev_data) {
|
||||
static void test_state6change(void) {
|
||||
struct mg_tcpip_if iface;
|
||||
memset(&iface, 0, sizeof(iface));
|
||||
iface.ip6[0] = (uint64_t) mg_htonl(0x01020304);
|
||||
iface.ip6[1] = (uint64_t) mg_htonl(0x05060708);
|
||||
iface.ip6[0] = mg_htonll(0x01020304);
|
||||
iface.ip6[1] = mg_htonll(0x05060708);
|
||||
iface.state6 = MG_TCPIP_STATE_READY;
|
||||
iface.driver = &mg_tcpip_driver_mock;
|
||||
iface.fn = mif6_fn;
|
||||
@@ -145,7 +235,7 @@ static void test_poll(void) {
|
||||
memset(&mif, 0, sizeof(mif));
|
||||
mif.driver = &mg_tcpip_driver_mock;
|
||||
mg_tcpip_init(&mgr, &mif);
|
||||
mg_http_listen(&mgr, "http://127.0.0.1:12346", ph, &count);
|
||||
mg_http_listen(&mgr, "http://0.0.0.0:12346", ph, &count);
|
||||
for (i = 0; i < 10; i++) mg_mgr_poll(&mgr, 0);
|
||||
ASSERT(count == 10);
|
||||
mg_mgr_free(&mgr);
|
||||
@@ -250,18 +340,18 @@ static void init_tests(struct mg_mgr *mgr, struct eth *e, struct ipp *ipp,
|
||||
mif->driver_data = &s_driver_data;
|
||||
#if MG_ENABLE_IPV6
|
||||
if (ipp->ip6 != NULL) {
|
||||
mif->ip6[0] = 1;
|
||||
mif->ip6[0] = mg_htonll(1ULL << 56);
|
||||
mif->prefix[0] = 1;
|
||||
mif->prefix_len = 64;
|
||||
mif->gw6[0] = 1;
|
||||
mif->gw6[0] = mg_htonll(1ULL << 56);
|
||||
mif->gw6_ready = true;
|
||||
mif->state = MG_TCPIP_STATE_READY; // so DHCP stops
|
||||
mif->state6 = MG_TCPIP_STATE_READY; // so mg_send() works and RS stops
|
||||
} else
|
||||
#endif
|
||||
{
|
||||
mif->ip = 1;
|
||||
mif->gw = 1;
|
||||
mif->ip = mg_htonl(0x1000000);
|
||||
mif->gw = mg_htonl(0x1000000);
|
||||
mif->gw_ready = true;
|
||||
mif->mask = 255; // use router, to avoid firing an ARP request
|
||||
mif->state = MG_TCPIP_STATE_READY; // so mg_send() works and DHCP stops
|
||||
@@ -281,7 +371,7 @@ static void init_tests(struct mg_mgr *mgr, struct eth *e, struct ipp *ipp,
|
||||
ip->ver = 0x60;
|
||||
ip->next = proto;
|
||||
// must be outside of Mongoose network to avoid firing NS requests
|
||||
ip->src[0] = 2;
|
||||
ip->src[0] = mg_htonll(2ULL << 56);
|
||||
ip->dst[0] = mif->ip6[0];
|
||||
} else
|
||||
#endif
|
||||
@@ -291,7 +381,7 @@ static void init_tests(struct mg_mgr *mgr, struct eth *e, struct ipp *ipp,
|
||||
ip->ver = (4 << 4) | 5;
|
||||
ip->proto = proto;
|
||||
// must be outside of Mongoose network to avoid firing ARP requests
|
||||
ip->src = 2;
|
||||
ip->src = mg_htonl(0x2000000);
|
||||
ip->dst = mif->ip;
|
||||
}
|
||||
}
|
||||
@@ -364,10 +454,13 @@ static void test_tcp_basics(bool ipv6) {
|
||||
ASSERT(t->flags == (TH_RST | TH_ACK));
|
||||
ASSERT(t->seq == mg_htonl(0));
|
||||
ASSERT(t->ack == mg_htonl(1235));
|
||||
mg_hexdump(s_driver_data.buf, s_driver_data.len);
|
||||
if (ipv6) {
|
||||
ASSERT(i6->src[0] == 1 && i6->dst[0] == 2);
|
||||
ASSERT(test_tcp6_csum(i6, t));
|
||||
} else {
|
||||
ASSERT(i->src == 1 && i->dst == 2);
|
||||
ASSERT(i->src == mg_htonl(0x1000000) && i->dst == mg_htonl(0x2000000));
|
||||
ASSERT(test_tcp_csum(i, t));
|
||||
}
|
||||
|
||||
// send SYN+ACK, expect RST
|
||||
@@ -421,7 +514,7 @@ static void test_tcp_basics(bool ipv6) {
|
||||
if (ipv6) {
|
||||
ASSERT(i6->src[0] == 1 && i6->dst[0] == 2);
|
||||
} else {
|
||||
ASSERT(i->src == 1 && i->dst == 2);
|
||||
ASSERT(i->src == mg_htonl(0x1000000) && i->dst == mg_htonl(0x2000000));
|
||||
}
|
||||
|
||||
// send SYN+ACK, expect RST
|
||||
@@ -459,7 +552,7 @@ static void test_tcp_basics(bool ipv6) {
|
||||
if (ipv6) {
|
||||
ASSERT(i6->src[0] == 1 && i6->dst[0] == 2);
|
||||
} else {
|
||||
ASSERT(i->src == 1 && i->dst == 2);
|
||||
ASSERT(i->src == mg_htonl(0x1000000) && i->dst == mg_htonl(0x2000000));
|
||||
}
|
||||
|
||||
// segment with seq_no way out of window
|
||||
@@ -678,7 +771,7 @@ static void test_tcp_basics(bool ipv6) {
|
||||
if (ipv6) {
|
||||
ASSERT(i6->src[0] == 1 && i6->dst[0] == 2);
|
||||
} else {
|
||||
ASSERT(i->src == 1 && i->dst == 2);
|
||||
ASSERT(i->src == mg_htonl(0x1000000) && i->dst == mg_htonl(0x2000000));
|
||||
}
|
||||
|
||||
// invalid SYN + ACK to connecting client (after SYN...), send ACK != seq
|
||||
@@ -1068,8 +1161,10 @@ static void test_udp(bool ipv6) {
|
||||
ASSERT(*((char *) (u + 1)) == 'P');
|
||||
if (ipv6) {
|
||||
ASSERT(i6->src[0] == 1 && i6->dst[0] == 2);
|
||||
ASSERT(test_udp6_csum(i6, u));
|
||||
} else {
|
||||
ASSERT(i->src == 1 && i->dst == 2);
|
||||
ASSERT(i->src == mg_htonl(0x1000000) && i->dst == mg_htonl(0x2000000));
|
||||
ASSERT(test_udp_csum(i, u));
|
||||
}
|
||||
|
||||
s_driver_data.len = 0;
|
||||
@@ -1119,7 +1214,7 @@ static void test_icmp_basics(void) {
|
||||
create_icmp_dat(&e, &ipp, 8, 0, 0); // Echo Request
|
||||
mg_mgr_poll(&mgr, 0); // make sure we clean former stuff in buffer
|
||||
while (!received_response(&s_driver_data)) mg_mgr_poll(&mgr, 0);
|
||||
ASSERT(i->src == 1 && i->dst == 2);
|
||||
ASSERT(i->src == mg_htonl(0x1000000) && i->dst == mg_htonl(0x2000000));
|
||||
ASSERT(i->proto == 1);
|
||||
ASSERT(i->len == mg_htons(sizeof(*i) + sizeof(*icmp) + 0));
|
||||
ASSERT(ipcsum(i, sizeof(*i)) == 0); // Bonus, not tested elsewhere
|
||||
@@ -1130,7 +1225,7 @@ static void test_icmp_basics(void) {
|
||||
create_icmp_dat(&e, &ipp, 8, 0, 69); // Echo Request
|
||||
mg_mgr_poll(&mgr, 0); // make sure we clean former stuff in buffer
|
||||
while (!received_response(&s_driver_data)) mg_mgr_poll(&mgr, 0);
|
||||
ASSERT(i->src == 1 && i->dst == 2);
|
||||
ASSERT(i->src == mg_htonl(0x1000000) && i->dst == mg_htonl(0x2000000));
|
||||
ASSERT(i->proto == 1);
|
||||
ASSERT(i->len == mg_htons(sizeof(*i) + sizeof(*icmp) + 69));
|
||||
ASSERT(icmp->type == 0); // Echo Reply
|
||||
@@ -1201,7 +1296,7 @@ static void test_icmp6_basics(void) {
|
||||
create_icmp6_dat(&e, &ipp, 128, 0, NULL, 0); // Echo Request
|
||||
mg_mgr_poll(&mgr, 0); // make sure we clean former stuff in buffer
|
||||
while (!received_response(&s_driver_data)) mg_mgr_poll(&mgr, 0);
|
||||
ASSERT(i->src[0] == 1 && i->src[1] == 0 && i->dst[0] == 2 && i->dst[1] == 0);
|
||||
ASSERT(i->src[0] == mg_htonll(1ULL << 56) && i->src[1] == 0 && i->dst[0] == mg_htonll(2ULL << 56) && i->dst[1] == 0);
|
||||
ASSERT(i->next == 58);
|
||||
ASSERT(i->plen == mg_htons(sizeof(*icmp6) + 0));
|
||||
ASSERT(icmp6->type == 129); // Echo Reply
|
||||
@@ -1211,7 +1306,7 @@ static void test_icmp6_basics(void) {
|
||||
create_icmp6_dat(&e, &ipp, 128, 0, NULL, 69); // Echo Request
|
||||
mg_mgr_poll(&mgr, 0); // make sure we clean former stuff in buffer
|
||||
while (!received_response(&s_driver_data)) mg_mgr_poll(&mgr, 0);
|
||||
ASSERT(i->src[0] == 1 && i->src[1] == 0 && i->dst[0] == 2 && i->dst[1] == 0);
|
||||
ASSERT(i->src[0] == mg_htonll(1ULL << 56) && i->src[1] == 0 && i->dst[0] == mg_htonll(2ULL << 56) && i->dst[1] == 0);
|
||||
ASSERT(i->next == 58);
|
||||
ASSERT(i->plen == mg_htons(sizeof(*icmp6) + 69));
|
||||
ASSERT(icmp6->type == 129); // Echo Reply
|
||||
@@ -1226,7 +1321,7 @@ static void test_icmp6_basics(void) {
|
||||
create_icmp6_dat(&e, &ipp, 135, 0, payload, 28);
|
||||
mg_mgr_poll(&mgr, 0); // make sure we clean former stuff in buffer
|
||||
while (!received_response(&s_driver_data)) mg_mgr_poll(&mgr, 0);
|
||||
ASSERT(i->src[0] == 1 && i->src[1] == 0 && i->dst[0] == 2 && i->dst[1] == 0);
|
||||
ASSERT(i->src[0] == mg_htonll(1ULL << 56) && i->src[1] == 0 && i->dst[0] == mg_htonll(2ULL << 56) && i->dst[1] == 0);
|
||||
ASSERT(i->next == 58);
|
||||
ASSERT(i->plen == mg_htons(sizeof(*icmp6) + 28));
|
||||
ASSERT(icmp6->type == 136); // Neighbor Advertisement
|
||||
|
||||
@@ -0,0 +1,468 @@
|
||||
#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_LOCALHOST
|
||||
#define MQTT_URL "mqtt://127.0.0.1:1883"
|
||||
#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_LOCALHOST
|
||||
// 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_LOCALHOST
|
||||
#endif
|
||||
|
||||
static char *host_ip;
|
||||
|
||||
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");
|
||||
#if MG_TLS == MG_TLS_BUILTIN
|
||||
// our TLS does not search for the proper CA in a bundle
|
||||
opts.ca = mg_file_read(&mg_fs_posix, "data/e5.crt");
|
||||
#endif
|
||||
}
|
||||
mg_tls_init(c, &opts);
|
||||
#if MG_TLS == MG_TLS_BUILTIN
|
||||
mg_free((void *) opts.ca.buf);
|
||||
#endif
|
||||
}
|
||||
} 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)
|
||||
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 = MG_ENABLE_IPV6;
|
||||
#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;
|
||||
opts.name = mg_url_host(data->url);
|
||||
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_LOCALHOST) && MG_TLS != MG_TLS_BUILTIN
|
||||
if (host_ip == NULL) {
|
||||
printf("\nMQTT_LOCALHOST defined but no HOST_IP provided, skipping MQTTS tests\n");
|
||||
return;
|
||||
}
|
||||
printf("HOST_IP: %s\n", host_ip);
|
||||
#endif
|
||||
#if MG_TLS
|
||||
#if defined(MQTT_LOCALHOST) && MG_TLS != MG_TLS_BUILTIN
|
||||
data.url = mg_mprintf("mqtts://%s:8883", host_ip);
|
||||
#else
|
||||
data.url = strdup(MQTTS_URL);
|
||||
#endif
|
||||
#else
|
||||
#ifdef MQTT_LOCALHOST
|
||||
data.url = mg_mprintf("mqtt://%s:1883", host_ip);
|
||||
#else
|
||||
data.url = strdup(MQTT_URL);
|
||||
#endif
|
||||
#endif
|
||||
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(10000); // 10 ms. Slow down poll loop to ensure packets transit
|
||||
}
|
||||
ASSERT(data.passed);
|
||||
mg_mgr_poll(mgr, 0);
|
||||
free(data.url);
|
||||
}
|
||||
|
||||
#ifndef NO_HTTPSERVER_TEST
|
||||
#include <pthread.h>
|
||||
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));
|
||||
// opts.ca = mg_str(s_tls_ca);
|
||||
opts.cert = mg_unpacked("/certs/server.crt");
|
||||
opts.key = mg_unpacked("/certs/server.key");
|
||||
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
|
||||
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);
|
||||
// - POST a large file, make sure we drain TLS buffers and read all: done at
|
||||
// server test, using curl as POSTing client
|
||||
// - Fire patched server, test multiple TLS records per TCP segment handling
|
||||
url = mg_mprintf("https://%s:8443", host_ip); // for historic reasons
|
||||
ASSERT(system("tls_multirec/server -d tls_multirec &") == 0);
|
||||
sleep(1);
|
||||
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
|
||||
(void) cmpbody("", "");
|
||||
(void) mgr;
|
||||
#endif
|
||||
}
|
||||
|
||||
bool mip_x_test(struct mg_mgr *mgr) {
|
||||
|
||||
host_ip = getenv("HOST_IP");
|
||||
|
||||
#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;
|
||||
}
|
||||
@@ -0,0 +1,105 @@
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <time.h>
|
||||
#include <unistd.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/socket.h>
|
||||
#include <netinet/in.h>
|
||||
#include <arpa/inet.h>
|
||||
#include <fcntl.h>
|
||||
#include <sys/ioctl.h>
|
||||
#include <sys/poll.h>
|
||||
|
||||
#ifndef __OpenBSD__
|
||||
#include <linux/if.h>
|
||||
#include <linux/if_tun.h>
|
||||
#else
|
||||
#include <net/if.h>
|
||||
#include <net/if_tun.h>
|
||||
#include <net/if_types.h>
|
||||
#endif
|
||||
|
||||
static int s_signo;
|
||||
void signal_handler(int signo) {
|
||||
s_signo = signo;
|
||||
}
|
||||
|
||||
int main(void) {
|
||||
// Setup interface
|
||||
const char *iface = "tap0"; // Network iface
|
||||
const uint16_t port = 0x55AA; // UDP port
|
||||
#ifndef __OpenBSD__
|
||||
const char *tuntap_device = "/dev/net/tun";
|
||||
#else
|
||||
const char *tuntap_device = "/dev/tap0";
|
||||
#endif
|
||||
int fd = open(tuntap_device, O_RDWR);
|
||||
struct ifreq ifr;
|
||||
memset(&ifr, 0, sizeof(ifr));
|
||||
strncpy(ifr.ifr_name, iface, IFNAMSIZ);
|
||||
#ifndef __OpenBSD__
|
||||
ifr.ifr_flags = IFF_TAP | IFF_NO_PI;
|
||||
if (ioctl(fd, TUNSETIFF, (void *) &ifr) < 0) {
|
||||
#else
|
||||
ifr.ifr_flags = (short) (IFF_UP | IFF_BROADCAST | IFF_MULTICAST);
|
||||
if (ioctl(fd, TUNSIFMODE, (void *) &ifr) < 0) {
|
||||
#endif
|
||||
printf("Failed to setup TAP interface: %s", ifr.ifr_name);
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
printf("Opened TAP interface: %s\n", iface);
|
||||
|
||||
int sockfd;
|
||||
struct sockaddr_in tap_addr, port_addr;
|
||||
|
||||
sockfd = socket(AF_INET, SOCK_DGRAM, 0);
|
||||
tap_addr.sin_family = AF_INET;
|
||||
tap_addr.sin_addr.s_addr = htonl(0x7f000001U); // 127.0.0.1
|
||||
tap_addr.sin_port = htons(port);
|
||||
if (bind(sockfd, (struct sockaddr *) &tap_addr, sizeof(tap_addr)) < 0) return EXIT_FAILURE;
|
||||
printf("Opened UDP socket\n");
|
||||
|
||||
memset(&port_addr, 0, sizeof(port_addr));
|
||||
|
||||
while (s_signo == 0) {
|
||||
struct pollfd pfd[2];
|
||||
int result;
|
||||
do {
|
||||
pfd[0].fd = fd;
|
||||
pfd[0].events = POLLIN | POLLPRI; // will wait for input available (read ready), use POLLOUT for write
|
||||
pfd[1].fd = sockfd;
|
||||
pfd[1].events = POLLIN | POLLPRI; // will wait for input available (read ready), use POLLOUT for write
|
||||
|
||||
// only read ready shown here, for write ready use the 3rd arg, and the 4th for exceptions
|
||||
result = poll(pfd, 2, 1000); // 2 pfd, TIMEOUT in milliseconds
|
||||
switch(result) {
|
||||
case -1: // error
|
||||
break;
|
||||
case 0: // timeout (if a timeout struct was passed to select)
|
||||
break;
|
||||
default: // the number of fd/sockets with data available (see pfd.revents for each one);
|
||||
uint8_t buf[1540];
|
||||
if (pfd[0].revents & (POLLIN | POLLPRI)) {
|
||||
ssize_t nread = read(fd, buf, 1540);
|
||||
// printf("Got at TAP: %d bytes\n", (int) nread);
|
||||
if (port_addr.sin_family != 0) { // something has been written to this struct (we got a conterpart)
|
||||
sendto(sockfd, buf, (size_t) nread, 0, (struct sockaddr *) &port_addr, sizeof(port_addr));
|
||||
// printf("Sent to %s port %d\n", inet_ntoa(port_addr.sin_addr), ntohs(port_addr.sin_port));
|
||||
}
|
||||
}
|
||||
if (pfd[1].revents & (POLLIN | POLLPRI)) {
|
||||
socklen_t len = sizeof(port_addr);
|
||||
ssize_t nread = recvfrom(sockfd, buf, 1540, 0, (struct sockaddr *) &port_addr, &len);
|
||||
// printf("Got at UDP: %d bytes from %s port %d\n", nread, inet_ntoa(port_addr.sin_addr), ntohs(port_addr.sin_port));
|
||||
write(fd, buf, (size_t) nread);
|
||||
// printf("Sent to TAP\n");
|
||||
}
|
||||
break;
|
||||
}
|
||||
} while (result >= 0);
|
||||
printf("looks like we got an error here... should I quit ? Waiting for CTRL-C\n");
|
||||
}
|
||||
close(sockfd);
|
||||
close(fd);
|
||||
}
|
||||
Reference in New Issue
Block a user