Add ipv6 server test

This commit is contained in:
cpq 2020-12-22 10:16:31 +00:00
parent 2e87783246
commit c3aae185df
6 changed files with 93 additions and 76 deletions

View File

@ -8,9 +8,9 @@ jobs:
- name: Install packages
run: sudo apt-get install libmbedtls-dev
- name: make
run: make test test++
run: make test test++ IPV6=0
- name: openssl
run: make test SSL=OPENSSL
run: make test SSL=OPENSSL IPV6=0
- name: examples
run: make ex
macos:
@ -20,9 +20,9 @@ jobs:
- name: Install packages
run: HOMEBREW_NO_AUTO_UPDATE=1 brew install jq mbedtls openssl
- name: make
run: make test++ upload-coverage
run: make test++ upload-coverage IPV6=0
- name: openssl
run: make test SSL=OPENSSL
run: make test SSL=OPENSSL IPV6=0
- name: exports
run: make mg_prefix
windows:

View File

@ -9,6 +9,7 @@ VC2017 = docker run --rm -e WINEDEBUG=-all -v $(CDIR):$(CDIR) -w $(CDIR) docker.
GCC = docker run --rm -v $(CDIR):$(CDIR) -w $(CDIR) mdashnet/cc2
VCFLAGS = /nologo /W3 /O2 /I. $(DEFS) $(TFLAGS)
CLANG ?= clang # /usr/local/opt/llvm\@9/bin/clang
IPV6 ?= 1
ASAN_OPTIONS ?=
EXAMPLES := $(wildcard examples/*)
EXAMPLE_TARGET ?= example
@ -51,7 +52,7 @@ fuzz: mongoose.c mongoose.h Makefile test/fuzz.c
$(DEBUGGER) ./fuzzer
# make CLANG=/usr/local/opt/llvm\@8/bin/clang ASAN_OPTIONS=detect_leaks=1
test: CFLAGS += -DMG_ENABLE_IPV6=1 -fsanitize=address#,undefined
test: CFLAGS += -DMG_ENABLE_IPV6=$(IPV6) -fsanitize=address#,undefined
test: mongoose.c mongoose.h Makefile test/unit_test.c
$(CLANG) mongoose.c test/unit_test.c $(CFLAGS) -coverage $(LDFLAGS) -g -o unit_test
ASAN_OPTIONS=$(ASAN_OPTIONS) $(DEBUGGER) ./unit_test
@ -76,7 +77,8 @@ vc2017: Makefile mongoose.c mongoose.h test/unit_test.c
$(VC2017) wine64 cl mongoose.c test/unit_test.c $(VCFLAGS) ws2_32.lib /Fe$@.exe
$(VC2017) wine64 $@.exe
linux: CFLAGS += -DMG_ENABLE_IPV6=1 -fsanitize=address,undefined
#linux: CFLAGS += -DMG_ENABLE_IPV6=$(IPV6)
linux: CFLAGS += -fsanitize=address,undefined
linux: Makefile mongoose.c mongoose.h test/unit_test.c
$(GCC) $(CC) mongoose.c test/unit_test.c $(CFLAGS) $(LDFLAGS) -o unit_test_gcc
$(GCC) ./unit_test_gcc

View File

@ -1129,7 +1129,7 @@ struct mg_connection *mg_http_listen(struct mg_mgr *mgr, const char *url,
struct mg_connection *c = mg_listen(mgr, url, fn, fn_data);
if (c != NULL) c->pfn = http_cb, c->pfn_data = mgr;
#if MG_ENABLE_HTTP_DEBUG_ENDPOINT
snprintf(c->label, sizeof(c->label) - 1, "<-LSN");
if (c != NULL) snprintf(c->label, sizeof(c->label) - 1, "<-LSN");
#endif
return c;
}
@ -2581,45 +2581,49 @@ static void mg_set_non_blocking_mode(SOCKET fd) {
#endif
}
SOCKET mg_open_listener(const char *ip, uint16_t port, int is_udp) {
union usa usa;
int on = 1;
int proto = is_udp ? IPPROTO_UDP : IPPROTO_TCP;
int type = is_udp ? SOCK_DGRAM : SOCK_STREAM;
SOCKET mg_open_listener(const char *url) {
struct mg_addr addr;
SOCKET fd;
SOCKET fd = INVALID_SOCKET;
memset(&usa, 0, sizeof(usa));
usa.sin.sin_family = AF_INET;
usa.sin.sin_port = mg_htons(port);
mg_aton(mg_url_host(ip), &addr);
*(uint32_t *) &usa.sin.sin_addr = addr.ip;
memset(&addr, 0, sizeof(addr));
addr.port = mg_htons(mg_url_port(url));
if (!mg_aton(mg_url_host(url), &addr)) {
LOG(LL_ERROR, ("invalid listening URL: %s", url));
} else {
union usa usa = tousa(&addr);
int on = 1, af = AF_INET;
int type = strncmp(url, "udp:", 4) == 0 ? SOCK_DGRAM : SOCK_STREAM;
int proto = type == SOCK_DGRAM ? IPPROTO_UDP : IPPROTO_TCP;
socklen_t slen = sizeof(usa.sin);
#if MG_ENABLE_IPV6
if (addr.is_ip6) af = AF_INET6, slen = sizeof(usa.sin6);
#endif
if ((fd = socket(AF_INET, type, proto)) != INVALID_SOCKET &&
if ((fd = socket(af, type, proto)) != INVALID_SOCKET &&
#if !defined(_WIN32) || !defined(SO_EXCLUSIVEADDRUSE)
// SO_RESUSEADDR is not enabled on Windows because the semantics of
// SO_REUSEADDR on UNIX and Windows is different. On Windows,
// SO_REUSEADDR allows to bind a socket to a port without error even if
// the port is already open by another program. This is not the behavior
// SO_REUSEADDR was designed for, and leads to hard-to-track failure
// scenarios. Therefore, SO_REUSEADDR was disabled on Windows unless
// SO_EXCLUSIVEADDRUSE is supported and set on a socket.
!setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, (void *) &on, sizeof(on)) &&
// SO_RESUSEADDR is not enabled on Windows because the semantics of
// SO_REUSEADDR on UNIX and Windows is different. On Windows,
// SO_REUSEADDR allows to bind a socket to a port without error even if
// the port is already open by another program. This is not the behavior
// SO_REUSEADDR was designed for, and leads to hard-to-track failure
// scenarios. Therefore, SO_REUSEADDR was disabled on Windows unless
// SO_EXCLUSIVEADDRUSE is supported and set on a socket.
!setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, (void *) &on, sizeof(on)) &&
#endif
#if defined(_WIN32) && defined(SO_EXCLUSIVEADDRUSE) && !defined(WINCE)
// "Using SO_REUSEADDR and SO_EXCLUSIVEADDRUSE"
!setsockopt(fd, SOL_SOCKET, SO_EXCLUSIVEADDRUSE, (void *) &on,
sizeof(on)) &&
// "Using SO_REUSEADDR and SO_EXCLUSIVEADDRUSE"
!setsockopt(fd, SOL_SOCKET, SO_EXCLUSIVEADDRUSE, (void *) &on,
sizeof(on)) &&
#endif
bind(fd, &usa.sa, sizeof(usa.sin)) == 0 &&
// NOTE(lsm): FreeRTOS uses backlog value as a connection limit
(type == SOCK_DGRAM || listen(fd, 128) == 0)) {
mg_set_non_blocking_mode(fd);
} else if (fd >= 0) {
LOG(LL_ERROR,
("Failed to listen on %s:%hu, errno %d", ip, port, MG_SOCK_ERRNO));
closesocket(fd);
fd = INVALID_SOCKET;
bind(fd, &usa.sa, slen) == 0 &&
// NOTE(lsm): FreeRTOS uses backlog value as a connection limit
(type == SOCK_DGRAM || listen(fd, 128) == 0)) {
mg_set_non_blocking_mode(fd);
} else if (fd >= 0) {
LOG(LL_ERROR, ("Failed to listen on %s, errno %d", url, MG_SOCK_ERRNO));
closesocket(fd);
fd = INVALID_SOCKET;
}
}
return fd;
@ -2836,8 +2840,7 @@ struct mg_connection *mg_listen(struct mg_mgr *mgr, const char *url,
mg_event_handler_t fn, void *fn_data) {
struct mg_connection *c = NULL;
int is_udp = strncmp(url, "udp:", 4) == 0;
struct mg_str host = mg_url_host(url);
SOCKET fd = mg_open_listener(host.ptr, mg_url_port(url), is_udp);
SOCKET fd = mg_open_listener(url);
if (fd == INVALID_SOCKET) {
} else if ((c = alloc_conn(mgr, 0, fd)) == NULL) {
LOG(LL_ERROR, ("OOM %s", url));

View File

@ -730,7 +730,7 @@ struct mg_connection *mg_http_listen(struct mg_mgr *mgr, const char *url,
struct mg_connection *c = mg_listen(mgr, url, fn, fn_data);
if (c != NULL) c->pfn = http_cb, c->pfn_data = mgr;
#if MG_ENABLE_HTTP_DEBUG_ENDPOINT
snprintf(c->label, sizeof(c->label) - 1, "<-LSN");
if (c != NULL) snprintf(c->label, sizeof(c->label) - 1, "<-LSN");
#endif
return c;
}

View File

@ -174,45 +174,49 @@ static void mg_set_non_blocking_mode(SOCKET fd) {
#endif
}
SOCKET mg_open_listener(const char *ip, uint16_t port, int is_udp) {
union usa usa;
int on = 1;
int proto = is_udp ? IPPROTO_UDP : IPPROTO_TCP;
int type = is_udp ? SOCK_DGRAM : SOCK_STREAM;
SOCKET mg_open_listener(const char *url) {
struct mg_addr addr;
SOCKET fd;
SOCKET fd = INVALID_SOCKET;
memset(&usa, 0, sizeof(usa));
usa.sin.sin_family = AF_INET;
usa.sin.sin_port = mg_htons(port);
mg_aton(mg_url_host(ip), &addr);
*(uint32_t *) &usa.sin.sin_addr = addr.ip;
memset(&addr, 0, sizeof(addr));
addr.port = mg_htons(mg_url_port(url));
if (!mg_aton(mg_url_host(url), &addr)) {
LOG(LL_ERROR, ("invalid listening URL: %s", url));
} else {
union usa usa = tousa(&addr);
int on = 1, af = AF_INET;
int type = strncmp(url, "udp:", 4) == 0 ? SOCK_DGRAM : SOCK_STREAM;
int proto = type == SOCK_DGRAM ? IPPROTO_UDP : IPPROTO_TCP;
socklen_t slen = sizeof(usa.sin);
#if MG_ENABLE_IPV6
if (addr.is_ip6) af = AF_INET6, slen = sizeof(usa.sin6);
#endif
if ((fd = socket(AF_INET, type, proto)) != INVALID_SOCKET &&
if ((fd = socket(af, type, proto)) != INVALID_SOCKET &&
#if !defined(_WIN32) || !defined(SO_EXCLUSIVEADDRUSE)
// SO_RESUSEADDR is not enabled on Windows because the semantics of
// SO_REUSEADDR on UNIX and Windows is different. On Windows,
// SO_REUSEADDR allows to bind a socket to a port without error even if
// the port is already open by another program. This is not the behavior
// SO_REUSEADDR was designed for, and leads to hard-to-track failure
// scenarios. Therefore, SO_REUSEADDR was disabled on Windows unless
// SO_EXCLUSIVEADDRUSE is supported and set on a socket.
!setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, (void *) &on, sizeof(on)) &&
// SO_RESUSEADDR is not enabled on Windows because the semantics of
// SO_REUSEADDR on UNIX and Windows is different. On Windows,
// SO_REUSEADDR allows to bind a socket to a port without error even if
// the port is already open by another program. This is not the behavior
// SO_REUSEADDR was designed for, and leads to hard-to-track failure
// scenarios. Therefore, SO_REUSEADDR was disabled on Windows unless
// SO_EXCLUSIVEADDRUSE is supported and set on a socket.
!setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, (void *) &on, sizeof(on)) &&
#endif
#if defined(_WIN32) && defined(SO_EXCLUSIVEADDRUSE) && !defined(WINCE)
// "Using SO_REUSEADDR and SO_EXCLUSIVEADDRUSE"
!setsockopt(fd, SOL_SOCKET, SO_EXCLUSIVEADDRUSE, (void *) &on,
sizeof(on)) &&
// "Using SO_REUSEADDR and SO_EXCLUSIVEADDRUSE"
!setsockopt(fd, SOL_SOCKET, SO_EXCLUSIVEADDRUSE, (void *) &on,
sizeof(on)) &&
#endif
bind(fd, &usa.sa, sizeof(usa.sin)) == 0 &&
// NOTE(lsm): FreeRTOS uses backlog value as a connection limit
(type == SOCK_DGRAM || listen(fd, 128) == 0)) {
mg_set_non_blocking_mode(fd);
} else if (fd >= 0) {
LOG(LL_ERROR,
("Failed to listen on %s:%hu, errno %d", ip, port, MG_SOCK_ERRNO));
closesocket(fd);
fd = INVALID_SOCKET;
bind(fd, &usa.sa, slen) == 0 &&
// NOTE(lsm): FreeRTOS uses backlog value as a connection limit
(type == SOCK_DGRAM || listen(fd, 128) == 0)) {
mg_set_non_blocking_mode(fd);
} else if (fd >= 0) {
LOG(LL_ERROR, ("Failed to listen on %s, errno %d", url, MG_SOCK_ERRNO));
closesocket(fd);
fd = INVALID_SOCKET;
}
}
return fd;
@ -429,8 +433,7 @@ struct mg_connection *mg_listen(struct mg_mgr *mgr, const char *url,
mg_event_handler_t fn, void *fn_data) {
struct mg_connection *c = NULL;
int is_udp = strncmp(url, "udp:", 4) == 0;
struct mg_str host = mg_url_host(url);
SOCKET fd = mg_open_listener(host.ptr, mg_url_port(url), is_udp);
SOCKET fd = mg_open_listener(url);
if (fd == INVALID_SOCKET) {
} else if ((c = alloc_conn(mgr, 0, fd)) == NULL) {
LOG(LL_ERROR, ("OOM %s", url));

View File

@ -564,6 +564,15 @@ static void test_http_server(void) {
ASSERT(fetch(&mgr, buf, url, "GET /a.txt HTTP/1.0\n\n") == 200);
ASSERT(fetch(&mgr, buf, url, "HEAD /a.txt HTTP/1.0\n\n") == 200);
#if MG_ENABLE_IPV6
{
const char *url6 = "http://[::1]:12346";
ASSERT(mg_http_listen(&mgr, url6, eh1, NULL) != NULL);
ASSERT(fetch(&mgr, buf, url6, "GET /a.txt HTTP/1.0\n\n") == 200);
ASSERT(cmpbody(buf, "hello\n") == 0);
}
#endif
mg_mgr_free(&mgr);
ASSERT(mgr.conns == NULL);
}