Refactor mg_open_listener()

This commit is contained in:
Sergey Lyubka committed 2022-05-10 13:41:45 +01:00
1 parent 84480f4072
commit 5ac5c93c90
2 files changed
+68 -68

No files matched your search

+34 -34
View File
@@ -3322,7 +3322,7 @@ static void mg_set_non_blocking_mode(SOCKET fd) {
bool mg_open_listener(struct mg_connection *c, const char *url) { bool mg_open_listener(struct mg_connection *c, const char *url) {
SOCKET fd = INVALID_SOCKET; SOCKET fd = INVALID_SOCKET;
int s_err = 0; // Memoized socket error, in case closesocket() overrides it bool success = false;
c->loc.port = mg_htons(mg_url_port(url)); c->loc.port = mg_htons(mg_url_port(url));
if (!mg_aton(mg_url_host(url), &c->loc)) { if (!mg_aton(mg_url_host(url), &c->loc)) {
MG_ERROR(("invalid listening URL: %s", url)); MG_ERROR(("invalid listening URL: %s", url));
@@ -3334,47 +3334,47 @@ bool mg_open_listener(struct mg_connection *c, const char *url) {
int proto = type == SOCK_DGRAM ? IPPROTO_UDP : IPPROTO_TCP; int proto = type == SOCK_DGRAM ? IPPROTO_UDP : IPPROTO_TCP;
(void) on; (void) on;
if ((fd = socket(af, type, proto)) != INVALID_SOCKET && if ((fd = socket(af, type, proto)) == INVALID_SOCKET) {
MG_ERROR(("socket: %s", MG_SOCK_ERRNO));
#if (MG_ARCH != MG_ARCH_WIN32 || !defined(SO_EXCLUSIVEADDRUSE)) && \ #if (MG_ARCH != MG_ARCH_WIN32 || !defined(SO_EXCLUSIVEADDRUSE)) && \
(!defined(LWIP_SOCKET) || (defined(LWIP_SOCKET) && SO_REUSE == 1)) (!defined(LWIP_SOCKET) || (defined(LWIP_SOCKET) && SO_REUSE == 1))
// 1. SO_RESUSEADDR is not enabled on Windows because the semantics of } else if (setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, (char *) &on,
// SO_REUSEADDR on UNIX and Windows is different. On Windows, sizeof(on)) != 0) {
// SO_REUSEADDR allows to bind a socket to a port without error even // 1. SO_RESUSEADDR is not enabled on Windows because the semantics of
// if the port is already open by another program. This is not the // SO_REUSEADDR on UNIX and Windows is different. On Windows,
// behavior SO_REUSEADDR was designed for, and leads to hard-to-track // SO_REUSEADDR allows to bind a socket to a port without error even
// failure scenarios. Therefore, SO_REUSEADDR was disabled on Windows // if the port is already open by another program. This is not the
// unless SO_EXCLUSIVEADDRUSE is supported and set on a socket. // behavior SO_REUSEADDR was designed for, and leads to hard-to-track
// 2. In case of LWIP, SO_REUSEADDR should be explicitly enabled, by // failure scenarios. Therefore, SO_REUSEADDR was disabled on Windows
// defining // unless SO_EXCLUSIVEADDRUSE is supported and set on a socket.
// SO_REUSE (in lwipopts.h), otherwise the code below will compile // 2. In case of LWIP, SO_REUSEADDR should be explicitly enabled, by
// but won't work! (setsockopt will return EINVAL) // defining
!setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, (char *) &on, sizeof(on)) && // SO_REUSE (in lwipopts.h), otherwise the code below will compile
// but won't work! (setsockopt will return EINVAL)
MG_ERROR(("reuseaddr: %s", MG_SOCK_ERRNO));
#endif #endif
#if MG_ARCH == MG_ARCH_WIN32 && defined(SO_EXCLUSIVEADDRUSE) && !defined(WINCE) #if MG_ARCH == MG_ARCH_WIN32 && defined(SO_EXCLUSIVEADDRUSE) && !defined(WINCE)
// "Using SO_REUSEADDR and SO_EXCLUSIVEADDRUSE" } else if (setsockopt(fd, SOL_SOCKET, SO_EXCLUSIVEADDRUSE, (char *) &on,
//! setsockopt(fd, SOL_SOCKET, SO_BROADCAST, (char *) &on, sizeof(on)) sizeof(on)) != 0) {
//! && // "Using SO_REUSEADDR and SO_EXCLUSIVEADDRUSE"
!setsockopt(fd, SOL_SOCKET, SO_EXCLUSIVEADDRUSE, (char *) &on, MG_ERROR(("exclusiveaddruse: %s", MG_SOCK_ERRNO));
sizeof(on)) &&
#endif #endif
bind(fd, &usa.sa, slen) == 0 && } else if (bind(fd, &usa.sa, slen) != 0) {
// NOTE(lsm): FreeRTOS uses backlog value as a connection limit MG_ERROR(("bind: %s", MG_SOCK_ERRNO));
(type == SOCK_DGRAM || listen(fd, MG_SOCK_LISTEN_BACKLOG_SIZE) == 0)) { } else if ((type == SOCK_STREAM &&
listen(fd, MG_SOCK_LISTEN_BACKLOG_SIZE) != 0)) {
// NOTE(lsm): FreeRTOS uses backlog value as a connection limit
// In case port was set to 0, get the real port number // In case port was set to 0, get the real port number
MG_ERROR(("listen: %s", MG_SOCK_ERRNO));
} else {
setlocaddr(fd, &c->loc); setlocaddr(fd, &c->loc);
mg_set_non_blocking_mode(fd); mg_set_non_blocking_mode(fd);
} else if (fd != INVALID_SOCKET) { c->fd = S2PTR(fd);
s_err = MG_SOCK_ERRNO; success = true;
closesocket(fd);
fd = INVALID_SOCKET;
} }
} }
c->fd = S2PTR(fd); if (success == false && fd != INVALID_SOCKET) closesocket(fd);
if (fd == INVALID_SOCKET) { return success;
if (s_err == 0) s_err = MG_SOCK_ERRNO;
MG_ERROR(("failed %s, errno %d (%s)", url, s_err, strerror(s_err)));
}
return fd != INVALID_SOCKET;
} }
static long mg_sock_recv(struct mg_connection *c, void *buf, size_t len) { static long mg_sock_recv(struct mg_connection *c, void *buf, size_t len) {
@@ -3512,8 +3512,8 @@ static void accept_conn(struct mg_mgr *mgr, struct mg_connection *lsn) {
if (fd == INVALID_SOCKET) { if (fd == INVALID_SOCKET) {
#if MG_ARCH == MG_ARCH_AZURERTOS #if MG_ARCH == MG_ARCH_AZURERTOS
// AzureRTOS, in non-block socket mode can mark listening socket readable // AzureRTOS, in non-block socket mode can mark listening socket readable
// even it is not. See comment for 'select' func implementation in nx_bsd.c // even it is not. See comment for 'select' func implementation in
// That's not an error, just should try later // nx_bsd.c That's not an error, just should try later
if (MG_SOCK_ERRNO != EAGAIN) if (MG_SOCK_ERRNO != EAGAIN)
#endif #endif
MG_ERROR(("%lu accept failed, errno %d", lsn->id, MG_SOCK_ERRNO)); MG_ERROR(("%lu accept failed, errno %d", lsn->id, MG_SOCK_ERRNO));
+34 -34
View File
@@ -185,7 +185,7 @@ static void mg_set_non_blocking_mode(SOCKET fd) {
bool mg_open_listener(struct mg_connection *c, const char *url) { bool mg_open_listener(struct mg_connection *c, const char *url) {
SOCKET fd = INVALID_SOCKET; SOCKET fd = INVALID_SOCKET;
int s_err = 0; // Memoized socket error, in case closesocket() overrides it bool success = false;
c->loc.port = mg_htons(mg_url_port(url)); c->loc.port = mg_htons(mg_url_port(url));
if (!mg_aton(mg_url_host(url), &c->loc)) { if (!mg_aton(mg_url_host(url), &c->loc)) {
MG_ERROR(("invalid listening URL: %s", url)); MG_ERROR(("invalid listening URL: %s", url));
@@ -197,47 +197,47 @@ bool mg_open_listener(struct mg_connection *c, const char *url) {
int proto = type == SOCK_DGRAM ? IPPROTO_UDP : IPPROTO_TCP; int proto = type == SOCK_DGRAM ? IPPROTO_UDP : IPPROTO_TCP;
(void) on; (void) on;
if ((fd = socket(af, type, proto)) != INVALID_SOCKET && if ((fd = socket(af, type, proto)) == INVALID_SOCKET) {
MG_ERROR(("socket: %s", MG_SOCK_ERRNO));
#if (MG_ARCH != MG_ARCH_WIN32 || !defined(SO_EXCLUSIVEADDRUSE)) && \ #if (MG_ARCH != MG_ARCH_WIN32 || !defined(SO_EXCLUSIVEADDRUSE)) && \
(!defined(LWIP_SOCKET) || (defined(LWIP_SOCKET) && SO_REUSE == 1)) (!defined(LWIP_SOCKET) || (defined(LWIP_SOCKET) && SO_REUSE == 1))
// 1. SO_RESUSEADDR is not enabled on Windows because the semantics of } else if (setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, (char *) &on,
// SO_REUSEADDR on UNIX and Windows is different. On Windows, sizeof(on)) != 0) {
// SO_REUSEADDR allows to bind a socket to a port without error even // 1. SO_RESUSEADDR is not enabled on Windows because the semantics of
// if the port is already open by another program. This is not the // SO_REUSEADDR on UNIX and Windows is different. On Windows,
// behavior SO_REUSEADDR was designed for, and leads to hard-to-track // SO_REUSEADDR allows to bind a socket to a port without error even
// failure scenarios. Therefore, SO_REUSEADDR was disabled on Windows // if the port is already open by another program. This is not the
// unless SO_EXCLUSIVEADDRUSE is supported and set on a socket. // behavior SO_REUSEADDR was designed for, and leads to hard-to-track
// 2. In case of LWIP, SO_REUSEADDR should be explicitly enabled, by // failure scenarios. Therefore, SO_REUSEADDR was disabled on Windows
// defining // unless SO_EXCLUSIVEADDRUSE is supported and set on a socket.
// SO_REUSE (in lwipopts.h), otherwise the code below will compile // 2. In case of LWIP, SO_REUSEADDR should be explicitly enabled, by
// but won't work! (setsockopt will return EINVAL) // defining
!setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, (char *) &on, sizeof(on)) && // SO_REUSE (in lwipopts.h), otherwise the code below will compile
// but won't work! (setsockopt will return EINVAL)
MG_ERROR(("reuseaddr: %s", MG_SOCK_ERRNO));
#endif #endif
#if MG_ARCH == MG_ARCH_WIN32 && defined(SO_EXCLUSIVEADDRUSE) && !defined(WINCE) #if MG_ARCH == MG_ARCH_WIN32 && defined(SO_EXCLUSIVEADDRUSE) && !defined(WINCE)
// "Using SO_REUSEADDR and SO_EXCLUSIVEADDRUSE" } else if (setsockopt(fd, SOL_SOCKET, SO_EXCLUSIVEADDRUSE, (char *) &on,
//! setsockopt(fd, SOL_SOCKET, SO_BROADCAST, (char *) &on, sizeof(on)) sizeof(on)) != 0) {
//! && // "Using SO_REUSEADDR and SO_EXCLUSIVEADDRUSE"
!setsockopt(fd, SOL_SOCKET, SO_EXCLUSIVEADDRUSE, (char *) &on, MG_ERROR(("exclusiveaddruse: %s", MG_SOCK_ERRNO));
sizeof(on)) &&
#endif #endif
bind(fd, &usa.sa, slen) == 0 && } else if (bind(fd, &usa.sa, slen) != 0) {
// NOTE(lsm): FreeRTOS uses backlog value as a connection limit MG_ERROR(("bind: %s", MG_SOCK_ERRNO));
(type == SOCK_DGRAM || listen(fd, MG_SOCK_LISTEN_BACKLOG_SIZE) == 0)) { } else if ((type == SOCK_STREAM &&
listen(fd, MG_SOCK_LISTEN_BACKLOG_SIZE) != 0)) {
// NOTE(lsm): FreeRTOS uses backlog value as a connection limit
// In case port was set to 0, get the real port number // In case port was set to 0, get the real port number
MG_ERROR(("listen: %s", MG_SOCK_ERRNO));
} else {
setlocaddr(fd, &c->loc); setlocaddr(fd, &c->loc);
mg_set_non_blocking_mode(fd); mg_set_non_blocking_mode(fd);
} else if (fd != INVALID_SOCKET) { c->fd = S2PTR(fd);
s_err = MG_SOCK_ERRNO; success = true;
closesocket(fd);
fd = INVALID_SOCKET;
} }
} }
c->fd = S2PTR(fd); if (success == false && fd != INVALID_SOCKET) closesocket(fd);
if (fd == INVALID_SOCKET) { return success;
if (s_err == 0) s_err = MG_SOCK_ERRNO;
MG_ERROR(("failed %s, errno %d (%s)", url, s_err, strerror(s_err)));
}
return fd != INVALID_SOCKET;
} }
static long mg_sock_recv(struct mg_connection *c, void *buf, size_t len) { static long mg_sock_recv(struct mg_connection *c, void *buf, size_t len) {
@@ -375,8 +375,8 @@ static void accept_conn(struct mg_mgr *mgr, struct mg_connection *lsn) {
if (fd == INVALID_SOCKET) { if (fd == INVALID_SOCKET) {
#if MG_ARCH == MG_ARCH_AZURERTOS #if MG_ARCH == MG_ARCH_AZURERTOS
// AzureRTOS, in non-block socket mode can mark listening socket readable // AzureRTOS, in non-block socket mode can mark listening socket readable
// even it is not. See comment for 'select' func implementation in nx_bsd.c // even it is not. See comment for 'select' func implementation in
// That's not an error, just should try later // nx_bsd.c That's not an error, just should try later
if (MG_SOCK_ERRNO != EAGAIN) if (MG_SOCK_ERRNO != EAGAIN)
#endif #endif
MG_ERROR(("%lu accept failed, errno %d", lsn->id, MG_SOCK_ERRNO)); MG_ERROR(("%lu accept failed, errno %d", lsn->id, MG_SOCK_ERRNO));