mirror of
https://github.com/cesanta/mongoose.git
synced 2025-01-18 23:53:15 +08:00
Add ipv6 server test
This commit is contained in:
parent
2e87783246
commit
c3aae185df
8
.github/workflows/test.yml
vendored
8
.github/workflows/test.yml
vendored
@ -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:
|
||||
|
6
Makefile
6
Makefile
@ -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
|
||||
|
73
mongoose.c
73
mongoose.c
@ -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));
|
||||
|
@ -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;
|
||||
}
|
||||
|
71
src/sock.c
71
src/sock.c
@ -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));
|
||||
|
@ -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);
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user