From 453d4be4d0e85f429d85f237f12b903b7bd2d400 Mon Sep 17 00:00:00 2001 From: Alex Alashkin Date: Wed, 11 Aug 2021 09:56:46 +0300 Subject: [PATCH] Update FREERTOS + LWIP support --- mongoose.c | 26 +++++++++++++++++--------- mongoose.h | 13 ++++++++++++- src/arch_freertos_lwip.h | 13 ++++++++++++- src/fs_posix.c | 2 +- src/log.c | 1 + src/sock.c | 23 +++++++++++++++-------- 6 files changed, 58 insertions(+), 20 deletions(-) diff --git a/mongoose.c b/mongoose.c index 485d2a25..8b60b340 100644 --- a/mongoose.c +++ b/mongoose.c @@ -529,7 +529,7 @@ static char *posix_realpath(const char *path, char *resolved_path) { #ifdef _WIN32 return _fullpath(resolved_path, path, _MAX_PATH); #elif MG_ARCH == MG_ARCH_ESP32 || MG_ARCH == MG_ARCH_ESP8266 || \ - MG_ARCH == MG_ARCH_FREERTOS_TCP + MG_ARCH == MG_ARCH_FREERTOS_TCP || MG_ARCH == MG_ARCH_FREERTOS_LWIP if (resolved_path == NULL) resolved_path = malloc(strlen(path) + 1); strcpy(resolved_path, path); return resolved_path; @@ -1830,6 +1830,7 @@ bool mg_log_prefix(int level, const char *file, int line, const char *fname) { time_t t = time(NULL); struct tm tmp, *tm = gmtime_r(&t, &tmp); int n, tag; + (void)tmp; strftime(timebuf, sizeof(timebuf), "%Y-%m-%d %H:%M:%S", tm); tag = level == LL_ERROR ? 'E' : level == LL_INFO ? 'I' : ' '; n = snprintf(buf, sizeof(buf), "%s %c %s:%d:%s", timebuf, tag, p, line, @@ -2944,6 +2945,8 @@ static void mg_set_non_blocking_mode(SOCKET fd) { const BaseType_t off = 0; setsockopt(fd, 0, FREERTOS_SO_RCVTIMEO, &off, sizeof(off)); setsockopt(fd, 0, FREERTOS_SO_SNDTIMEO, &off, sizeof(off)); +#elif MG_ARCH == MG_ARCH_FREERTOS_LWIP + lwip_fcntl(fd, F_SETFL, O_NONBLOCK); #else fcntl(fd, F_SETFL, fcntl(fd, F_GETFL, 0) | O_NONBLOCK, FD_CLOEXEC); #endif @@ -2961,16 +2964,21 @@ SOCKET mg_open_listener(const char *url, struct mg_addr *addr) { int on = 1, af = addr->is_ip6 ? AF_INET6 : AF_INET; int type = strncmp(url, "udp:", 4) == 0 ? SOCK_DGRAM : SOCK_STREAM; int proto = type == SOCK_DGRAM ? IPPROTO_UDP : IPPROTO_TCP; + (void)on; 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. +#if (!defined(_WIN32) || !defined(SO_EXCLUSIVEADDRUSE)) \ + && (!defined(LWIP_SOCKET) || (defined(LWIP_SOCKET) && SO_REUSE == 1)) + // 1. 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. + // 2. In case of LWIP, SO_REUSEADDR should be explicitly enabled, by defining + // SO_REUSE (in lwipopts.h), otherwise the code below will compile + // but won't work! (setsockopt will return EINVAL) !setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, (char *) &on, sizeof(on)) && #endif #if defined(_WIN32) && defined(SO_EXCLUSIVEADDRUSE) && !defined(WINCE) diff --git a/mongoose.h b/mongoose.h index ba48ced2..69883995 100644 --- a/mongoose.h +++ b/mongoose.h @@ -192,10 +192,10 @@ extern "C" { #if MG_ARCH == MG_ARCH_FREERTOS_LWIP -#include #include #include #include +#include #if defined(__GNUC__) #include @@ -213,6 +213,17 @@ struct timeval { #include +#if LWIP_SOCKET != 1 +// Sockets support disabled in LWIP by default +#error Set LWIP_SOCKET variable to 1 (in lwipopts.h) +#endif + +#if LWIP_POSIX_SOCKETS_IO_NAMES != 0 +// LWIP_POSIX_SOCKETS_IO_NAMES must be disabled in posix-compatible OS enviroment +// (freertos mimics to one) otherwise names like `read` and `write` conflict +#error LWIP_POSIX_SOCKETS_IO_NAMES must be set to 0 (in lwipopts.h) for FreeRTOS +#endif + #define MG_INT64_FMT "%lld" #define MG_DIRSEP '/' diff --git a/src/arch_freertos_lwip.h b/src/arch_freertos_lwip.h index 4e5ebc38..56213b97 100644 --- a/src/arch_freertos_lwip.h +++ b/src/arch_freertos_lwip.h @@ -2,10 +2,10 @@ #if MG_ARCH == MG_ARCH_FREERTOS_LWIP -#include #include #include #include +#include #if defined(__GNUC__) #include @@ -23,6 +23,17 @@ struct timeval { #include +#if LWIP_SOCKET != 1 +// Sockets support disabled in LWIP by default +#error Set LWIP_SOCKET variable to 1 (in lwipopts.h) +#endif + +#if LWIP_POSIX_SOCKETS_IO_NAMES != 0 +// LWIP_POSIX_SOCKETS_IO_NAMES must be disabled in posix-compatible OS enviroment +// (freertos mimics to one) otherwise names like `read` and `write` conflict +#error LWIP_POSIX_SOCKETS_IO_NAMES must be set to 0 (in lwipopts.h) for FreeRTOS +#endif + #define MG_INT64_FMT "%lld" #define MG_DIRSEP '/' diff --git a/src/fs_posix.c b/src/fs_posix.c index 15e4d2dd..e5c55f09 100644 --- a/src/fs_posix.c +++ b/src/fs_posix.c @@ -5,7 +5,7 @@ static char *posix_realpath(const char *path, char *resolved_path) { #ifdef _WIN32 return _fullpath(resolved_path, path, _MAX_PATH); #elif MG_ARCH == MG_ARCH_ESP32 || MG_ARCH == MG_ARCH_ESP8266 || \ - MG_ARCH == MG_ARCH_FREERTOS_TCP + MG_ARCH == MG_ARCH_FREERTOS_TCP || MG_ARCH == MG_ARCH_FREERTOS_LWIP if (resolved_path == NULL) resolved_path = malloc(strlen(path) + 1); strcpy(resolved_path, path); return resolved_path; diff --git a/src/log.c b/src/log.c index a4c0d721..b2e9e984 100644 --- a/src/log.c +++ b/src/log.c @@ -37,6 +37,7 @@ bool mg_log_prefix(int level, const char *file, int line, const char *fname) { time_t t = time(NULL); struct tm tmp, *tm = gmtime_r(&t, &tmp); int n, tag; + (void)tmp; strftime(timebuf, sizeof(timebuf), "%Y-%m-%d %H:%M:%S", tm); tag = level == LL_ERROR ? 'E' : level == LL_INFO ? 'I' : ' '; n = snprintf(buf, sizeof(buf), "%s %c %s:%d:%s", timebuf, tag, p, line, diff --git a/src/sock.c b/src/sock.c index 05d87594..2b8772f6 100644 --- a/src/sock.c +++ b/src/sock.c @@ -118,6 +118,8 @@ static void mg_set_non_blocking_mode(SOCKET fd) { const BaseType_t off = 0; setsockopt(fd, 0, FREERTOS_SO_RCVTIMEO, &off, sizeof(off)); setsockopt(fd, 0, FREERTOS_SO_SNDTIMEO, &off, sizeof(off)); +#elif MG_ARCH == MG_ARCH_FREERTOS_LWIP + lwip_fcntl(fd, F_SETFL, O_NONBLOCK); #else fcntl(fd, F_SETFL, fcntl(fd, F_GETFL, 0) | O_NONBLOCK, FD_CLOEXEC); #endif @@ -135,16 +137,21 @@ SOCKET mg_open_listener(const char *url, struct mg_addr *addr) { int on = 1, af = addr->is_ip6 ? AF_INET6 : AF_INET; int type = strncmp(url, "udp:", 4) == 0 ? SOCK_DGRAM : SOCK_STREAM; int proto = type == SOCK_DGRAM ? IPPROTO_UDP : IPPROTO_TCP; + (void)on; 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. +#if (!defined(_WIN32) || !defined(SO_EXCLUSIVEADDRUSE)) \ + && (!defined(LWIP_SOCKET) || (defined(LWIP_SOCKET) && SO_REUSE == 1)) + // 1. 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. + // 2. In case of LWIP, SO_REUSEADDR should be explicitly enabled, by defining + // SO_REUSE (in lwipopts.h), otherwise the code below will compile + // but won't work! (setsockopt will return EINVAL) !setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, (char *) &on, sizeof(on)) && #endif #if defined(_WIN32) && defined(SO_EXCLUSIVEADDRUSE) && !defined(WINCE)