mirror of
https://github.com/cesanta/mongoose.git
synced 2026-11-06 15:51:25 +00:00
Add ipv6 server test
This commit is contained in:
1 parent
2e87783246
commit
c3aae185df
6 files changed
+93
-76
No files matched your search
@@ -8,9 +8,9 @@ jobs:
|
|||||||
- name: Install packages
|
- name: Install packages
|
||||||
run: sudo apt-get install libmbedtls-dev
|
run: sudo apt-get install libmbedtls-dev
|
||||||
- name: make
|
- name: make
|
||||||
run: make test test++
|
run: make test test++ IPV6=0
|
||||||
- name: openssl
|
- name: openssl
|
||||||
run: make test SSL=OPENSSL
|
run: make test SSL=OPENSSL IPV6=0
|
||||||
- name: examples
|
- name: examples
|
||||||
run: make ex
|
run: make ex
|
||||||
macos:
|
macos:
|
||||||
@@ -20,9 +20,9 @@ jobs:
|
|||||||
- name: Install packages
|
- name: Install packages
|
||||||
run: HOMEBREW_NO_AUTO_UPDATE=1 brew install jq mbedtls openssl
|
run: HOMEBREW_NO_AUTO_UPDATE=1 brew install jq mbedtls openssl
|
||||||
- name: make
|
- name: make
|
||||||
run: make test++ upload-coverage
|
run: make test++ upload-coverage IPV6=0
|
||||||
- name: openssl
|
- name: openssl
|
||||||
run: make test SSL=OPENSSL
|
run: make test SSL=OPENSSL IPV6=0
|
||||||
- name: exports
|
- name: exports
|
||||||
run: make mg_prefix
|
run: make mg_prefix
|
||||||
windows:
|
windows:
|
||||||
|
|||||||
@@ -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
|
GCC = docker run --rm -v $(CDIR):$(CDIR) -w $(CDIR) mdashnet/cc2
|
||||||
VCFLAGS = /nologo /W3 /O2 /I. $(DEFS) $(TFLAGS)
|
VCFLAGS = /nologo /W3 /O2 /I. $(DEFS) $(TFLAGS)
|
||||||
CLANG ?= clang # /usr/local/opt/llvm\@9/bin/clang
|
CLANG ?= clang # /usr/local/opt/llvm\@9/bin/clang
|
||||||
|
IPV6 ?= 1
|
||||||
ASAN_OPTIONS ?=
|
ASAN_OPTIONS ?=
|
||||||
EXAMPLES := $(wildcard examples/*)
|
EXAMPLES := $(wildcard examples/*)
|
||||||
EXAMPLE_TARGET ?= example
|
EXAMPLE_TARGET ?= example
|
||||||
@@ -51,7 +52,7 @@ fuzz: mongoose.c mongoose.h Makefile test/fuzz.c
|
|||||||
$(DEBUGGER) ./fuzzer
|
$(DEBUGGER) ./fuzzer
|
||||||
|
|
||||||
# make CLANG=/usr/local/opt/llvm\@8/bin/clang ASAN_OPTIONS=detect_leaks=1
|
# 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
|
test: mongoose.c mongoose.h Makefile test/unit_test.c
|
||||||
$(CLANG) mongoose.c test/unit_test.c $(CFLAGS) -coverage $(LDFLAGS) -g -o unit_test
|
$(CLANG) mongoose.c test/unit_test.c $(CFLAGS) -coverage $(LDFLAGS) -g -o unit_test
|
||||||
ASAN_OPTIONS=$(ASAN_OPTIONS) $(DEBUGGER) ./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 cl mongoose.c test/unit_test.c $(VCFLAGS) ws2_32.lib /Fe$@.exe
|
||||||
$(VC2017) wine64 $@.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
|
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) $(CC) mongoose.c test/unit_test.c $(CFLAGS) $(LDFLAGS) -o unit_test_gcc
|
||||||
$(GCC) ./unit_test_gcc
|
$(GCC) ./unit_test_gcc
|
||||||
|
|||||||
+38
-35
@@ -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);
|
struct mg_connection *c = mg_listen(mgr, url, fn, fn_data);
|
||||||
if (c != NULL) c->pfn = http_cb, c->pfn_data = mgr;
|
if (c != NULL) c->pfn = http_cb, c->pfn_data = mgr;
|
||||||
#if MG_ENABLE_HTTP_DEBUG_ENDPOINT
|
#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
|
#endif
|
||||||
return c;
|
return c;
|
||||||
}
|
}
|
||||||
@@ -2581,45 +2581,49 @@ static void mg_set_non_blocking_mode(SOCKET fd) {
|
|||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
SOCKET mg_open_listener(const char *ip, uint16_t port, int is_udp) {
|
SOCKET mg_open_listener(const char *url) {
|
||||||
union usa usa;
|
|
||||||
int on = 1;
|
|
||||||
int proto = is_udp ? IPPROTO_UDP : IPPROTO_TCP;
|
|
||||||
int type = is_udp ? SOCK_DGRAM : SOCK_STREAM;
|
|
||||||
struct mg_addr addr;
|
struct mg_addr addr;
|
||||||
SOCKET fd;
|
SOCKET fd = INVALID_SOCKET;
|
||||||
|
|
||||||
memset(&usa, 0, sizeof(usa));
|
memset(&addr, 0, sizeof(addr));
|
||||||
usa.sin.sin_family = AF_INET;
|
addr.port = mg_htons(mg_url_port(url));
|
||||||
usa.sin.sin_port = mg_htons(port);
|
if (!mg_aton(mg_url_host(url), &addr)) {
|
||||||
mg_aton(mg_url_host(ip), &addr);
|
LOG(LL_ERROR, ("invalid listening URL: %s", url));
|
||||||
*(uint32_t *) &usa.sin.sin_addr = addr.ip;
|
} 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)
|
#if !defined(_WIN32) || !defined(SO_EXCLUSIVEADDRUSE)
|
||||||
// SO_RESUSEADDR is not enabled on Windows because the semantics of
|
// SO_RESUSEADDR is not enabled on Windows because the semantics of
|
||||||
// SO_REUSEADDR on UNIX and Windows is different. On Windows,
|
// SO_REUSEADDR on UNIX and Windows is different. On Windows,
|
||||||
// SO_REUSEADDR allows to bind a socket to a port without error even if
|
// 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
|
// 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
|
// SO_REUSEADDR was designed for, and leads to hard-to-track failure
|
||||||
// scenarios. Therefore, SO_REUSEADDR was disabled on Windows unless
|
// scenarios. Therefore, SO_REUSEADDR was disabled on Windows unless
|
||||||
// SO_EXCLUSIVEADDRUSE is supported and set on a socket.
|
// SO_EXCLUSIVEADDRUSE is supported and set on a socket.
|
||||||
!setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, (void *) &on, sizeof(on)) &&
|
!setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, (void *) &on, sizeof(on)) &&
|
||||||
#endif
|
#endif
|
||||||
#if defined(_WIN32) && defined(SO_EXCLUSIVEADDRUSE) && !defined(WINCE)
|
#if defined(_WIN32) && defined(SO_EXCLUSIVEADDRUSE) && !defined(WINCE)
|
||||||
// "Using SO_REUSEADDR and SO_EXCLUSIVEADDRUSE"
|
// "Using SO_REUSEADDR and SO_EXCLUSIVEADDRUSE"
|
||||||
!setsockopt(fd, SOL_SOCKET, SO_EXCLUSIVEADDRUSE, (void *) &on,
|
!setsockopt(fd, SOL_SOCKET, SO_EXCLUSIVEADDRUSE, (void *) &on,
|
||||||
sizeof(on)) &&
|
sizeof(on)) &&
|
||||||
#endif
|
#endif
|
||||||
bind(fd, &usa.sa, sizeof(usa.sin)) == 0 &&
|
bind(fd, &usa.sa, slen) == 0 &&
|
||||||
// NOTE(lsm): FreeRTOS uses backlog value as a connection limit
|
// NOTE(lsm): FreeRTOS uses backlog value as a connection limit
|
||||||
(type == SOCK_DGRAM || listen(fd, 128) == 0)) {
|
(type == SOCK_DGRAM || listen(fd, 128) == 0)) {
|
||||||
mg_set_non_blocking_mode(fd);
|
mg_set_non_blocking_mode(fd);
|
||||||
} else if (fd >= 0) {
|
} else if (fd >= 0) {
|
||||||
LOG(LL_ERROR,
|
LOG(LL_ERROR, ("Failed to listen on %s, errno %d", url, MG_SOCK_ERRNO));
|
||||||
("Failed to listen on %s:%hu, errno %d", ip, port, MG_SOCK_ERRNO));
|
closesocket(fd);
|
||||||
closesocket(fd);
|
fd = INVALID_SOCKET;
|
||||||
fd = INVALID_SOCKET;
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return fd;
|
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) {
|
mg_event_handler_t fn, void *fn_data) {
|
||||||
struct mg_connection *c = NULL;
|
struct mg_connection *c = NULL;
|
||||||
int is_udp = strncmp(url, "udp:", 4) == 0;
|
int is_udp = strncmp(url, "udp:", 4) == 0;
|
||||||
struct mg_str host = mg_url_host(url);
|
SOCKET fd = mg_open_listener(url);
|
||||||
SOCKET fd = mg_open_listener(host.ptr, mg_url_port(url), is_udp);
|
|
||||||
if (fd == INVALID_SOCKET) {
|
if (fd == INVALID_SOCKET) {
|
||||||
} else if ((c = alloc_conn(mgr, 0, fd)) == NULL) {
|
} else if ((c = alloc_conn(mgr, 0, fd)) == NULL) {
|
||||||
LOG(LL_ERROR, ("OOM %s", url));
|
LOG(LL_ERROR, ("OOM %s", url));
|
||||||
|
|||||||
+1
-1
@@ -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);
|
struct mg_connection *c = mg_listen(mgr, url, fn, fn_data);
|
||||||
if (c != NULL) c->pfn = http_cb, c->pfn_data = mgr;
|
if (c != NULL) c->pfn = http_cb, c->pfn_data = mgr;
|
||||||
#if MG_ENABLE_HTTP_DEBUG_ENDPOINT
|
#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
|
#endif
|
||||||
return c;
|
return c;
|
||||||
}
|
}
|
||||||
+37
-34
@@ -174,45 +174,49 @@ static void mg_set_non_blocking_mode(SOCKET fd) {
|
|||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
SOCKET mg_open_listener(const char *ip, uint16_t port, int is_udp) {
|
SOCKET mg_open_listener(const char *url) {
|
||||||
union usa usa;
|
|
||||||
int on = 1;
|
|
||||||
int proto = is_udp ? IPPROTO_UDP : IPPROTO_TCP;
|
|
||||||
int type = is_udp ? SOCK_DGRAM : SOCK_STREAM;
|
|
||||||
struct mg_addr addr;
|
struct mg_addr addr;
|
||||||
SOCKET fd;
|
SOCKET fd = INVALID_SOCKET;
|
||||||
|
|
||||||
memset(&usa, 0, sizeof(usa));
|
memset(&addr, 0, sizeof(addr));
|
||||||
usa.sin.sin_family = AF_INET;
|
addr.port = mg_htons(mg_url_port(url));
|
||||||
usa.sin.sin_port = mg_htons(port);
|
if (!mg_aton(mg_url_host(url), &addr)) {
|
||||||
mg_aton(mg_url_host(ip), &addr);
|
LOG(LL_ERROR, ("invalid listening URL: %s", url));
|
||||||
*(uint32_t *) &usa.sin.sin_addr = addr.ip;
|
} 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)
|
#if !defined(_WIN32) || !defined(SO_EXCLUSIVEADDRUSE)
|
||||||
// SO_RESUSEADDR is not enabled on Windows because the semantics of
|
// SO_RESUSEADDR is not enabled on Windows because the semantics of
|
||||||
// SO_REUSEADDR on UNIX and Windows is different. On Windows,
|
// SO_REUSEADDR on UNIX and Windows is different. On Windows,
|
||||||
// SO_REUSEADDR allows to bind a socket to a port without error even if
|
// 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
|
// 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
|
// SO_REUSEADDR was designed for, and leads to hard-to-track failure
|
||||||
// scenarios. Therefore, SO_REUSEADDR was disabled on Windows unless
|
// scenarios. Therefore, SO_REUSEADDR was disabled on Windows unless
|
||||||
// SO_EXCLUSIVEADDRUSE is supported and set on a socket.
|
// SO_EXCLUSIVEADDRUSE is supported and set on a socket.
|
||||||
!setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, (void *) &on, sizeof(on)) &&
|
!setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, (void *) &on, sizeof(on)) &&
|
||||||
#endif
|
#endif
|
||||||
#if defined(_WIN32) && defined(SO_EXCLUSIVEADDRUSE) && !defined(WINCE)
|
#if defined(_WIN32) && defined(SO_EXCLUSIVEADDRUSE) && !defined(WINCE)
|
||||||
// "Using SO_REUSEADDR and SO_EXCLUSIVEADDRUSE"
|
// "Using SO_REUSEADDR and SO_EXCLUSIVEADDRUSE"
|
||||||
!setsockopt(fd, SOL_SOCKET, SO_EXCLUSIVEADDRUSE, (void *) &on,
|
!setsockopt(fd, SOL_SOCKET, SO_EXCLUSIVEADDRUSE, (void *) &on,
|
||||||
sizeof(on)) &&
|
sizeof(on)) &&
|
||||||
#endif
|
#endif
|
||||||
bind(fd, &usa.sa, sizeof(usa.sin)) == 0 &&
|
bind(fd, &usa.sa, slen) == 0 &&
|
||||||
// NOTE(lsm): FreeRTOS uses backlog value as a connection limit
|
// NOTE(lsm): FreeRTOS uses backlog value as a connection limit
|
||||||
(type == SOCK_DGRAM || listen(fd, 128) == 0)) {
|
(type == SOCK_DGRAM || listen(fd, 128) == 0)) {
|
||||||
mg_set_non_blocking_mode(fd);
|
mg_set_non_blocking_mode(fd);
|
||||||
} else if (fd >= 0) {
|
} else if (fd >= 0) {
|
||||||
LOG(LL_ERROR,
|
LOG(LL_ERROR, ("Failed to listen on %s, errno %d", url, MG_SOCK_ERRNO));
|
||||||
("Failed to listen on %s:%hu, errno %d", ip, port, MG_SOCK_ERRNO));
|
closesocket(fd);
|
||||||
closesocket(fd);
|
fd = INVALID_SOCKET;
|
||||||
fd = INVALID_SOCKET;
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return fd;
|
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) {
|
mg_event_handler_t fn, void *fn_data) {
|
||||||
struct mg_connection *c = NULL;
|
struct mg_connection *c = NULL;
|
||||||
int is_udp = strncmp(url, "udp:", 4) == 0;
|
int is_udp = strncmp(url, "udp:", 4) == 0;
|
||||||
struct mg_str host = mg_url_host(url);
|
SOCKET fd = mg_open_listener(url);
|
||||||
SOCKET fd = mg_open_listener(host.ptr, mg_url_port(url), is_udp);
|
|
||||||
if (fd == INVALID_SOCKET) {
|
if (fd == INVALID_SOCKET) {
|
||||||
} else if ((c = alloc_conn(mgr, 0, fd)) == NULL) {
|
} else if ((c = alloc_conn(mgr, 0, fd)) == NULL) {
|
||||||
LOG(LL_ERROR, ("OOM %s", url));
|
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, "GET /a.txt HTTP/1.0\n\n") == 200);
|
||||||
ASSERT(fetch(&mgr, buf, url, "HEAD /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);
|
mg_mgr_free(&mgr);
|
||||||
ASSERT(mgr.conns == NULL);
|
ASSERT(mgr.conns == NULL);
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in new issue
Block a user