Refactor mg_open_listener()

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

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) {
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));
if (!mg_aton(mg_url_host(url), &c->loc)) {
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;
(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)) && \
(!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)) &&
} else if (setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, (char *) &on,
sizeof(on)) != 0) {
// 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)
MG_ERROR(("reuseaddr: %s", MG_SOCK_ERRNO));
#endif
#if MG_ARCH == MG_ARCH_WIN32 && defined(SO_EXCLUSIVEADDRUSE) && !defined(WINCE)
// "Using SO_REUSEADDR and SO_EXCLUSIVEADDRUSE"
//! setsockopt(fd, SOL_SOCKET, SO_BROADCAST, (char *) &on, sizeof(on))
//! &&
!setsockopt(fd, SOL_SOCKET, SO_EXCLUSIVEADDRUSE, (char *) &on,
sizeof(on)) &&
} else if (setsockopt(fd, SOL_SOCKET, SO_EXCLUSIVEADDRUSE, (char *) &on,
sizeof(on)) != 0) {
// "Using SO_REUSEADDR and SO_EXCLUSIVEADDRUSE"
MG_ERROR(("exclusiveaddruse: %s", MG_SOCK_ERRNO));
#endif
bind(fd, &usa.sa, slen) == 0 &&
// NOTE(lsm): FreeRTOS uses backlog value as a connection limit
(type == SOCK_DGRAM || listen(fd, MG_SOCK_LISTEN_BACKLOG_SIZE) == 0)) {
} else if (bind(fd, &usa.sa, slen) != 0) {
MG_ERROR(("bind: %s", MG_SOCK_ERRNO));
} 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
MG_ERROR(("listen: %s", MG_SOCK_ERRNO));
} else {
setlocaddr(fd, &c->loc);
mg_set_non_blocking_mode(fd);
} else if (fd != INVALID_SOCKET) {
s_err = MG_SOCK_ERRNO;
closesocket(fd);
fd = INVALID_SOCKET;
c->fd = S2PTR(fd);
success = true;
}
}
c->fd = S2PTR(fd);
if (fd == INVALID_SOCKET) {
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;
if (success == false && fd != INVALID_SOCKET) closesocket(fd);
return success;
}
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 MG_ARCH == MG_ARCH_AZURERTOS
// 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
// That's not an error, just should try later
// even it is not. See comment for 'select' func implementation in
// nx_bsd.c That's not an error, just should try later
if (MG_SOCK_ERRNO != EAGAIN)
#endif
MG_ERROR(("%lu accept failed, errno %d", lsn->id, MG_SOCK_ERRNO));

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) {
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));
if (!mg_aton(mg_url_host(url), &c->loc)) {
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;
(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)) && \
(!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)) &&
} else if (setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, (char *) &on,
sizeof(on)) != 0) {
// 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)
MG_ERROR(("reuseaddr: %s", MG_SOCK_ERRNO));
#endif
#if MG_ARCH == MG_ARCH_WIN32 && defined(SO_EXCLUSIVEADDRUSE) && !defined(WINCE)
// "Using SO_REUSEADDR and SO_EXCLUSIVEADDRUSE"
//! setsockopt(fd, SOL_SOCKET, SO_BROADCAST, (char *) &on, sizeof(on))
//! &&
!setsockopt(fd, SOL_SOCKET, SO_EXCLUSIVEADDRUSE, (char *) &on,
sizeof(on)) &&
} else if (setsockopt(fd, SOL_SOCKET, SO_EXCLUSIVEADDRUSE, (char *) &on,
sizeof(on)) != 0) {
// "Using SO_REUSEADDR and SO_EXCLUSIVEADDRUSE"
MG_ERROR(("exclusiveaddruse: %s", MG_SOCK_ERRNO));
#endif
bind(fd, &usa.sa, slen) == 0 &&
// NOTE(lsm): FreeRTOS uses backlog value as a connection limit
(type == SOCK_DGRAM || listen(fd, MG_SOCK_LISTEN_BACKLOG_SIZE) == 0)) {
} else if (bind(fd, &usa.sa, slen) != 0) {
MG_ERROR(("bind: %s", MG_SOCK_ERRNO));
} 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
MG_ERROR(("listen: %s", MG_SOCK_ERRNO));
} else {
setlocaddr(fd, &c->loc);
mg_set_non_blocking_mode(fd);
} else if (fd != INVALID_SOCKET) {
s_err = MG_SOCK_ERRNO;
closesocket(fd);
fd = INVALID_SOCKET;
c->fd = S2PTR(fd);
success = true;
}
}
c->fd = S2PTR(fd);
if (fd == INVALID_SOCKET) {
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;
if (success == false && fd != INVALID_SOCKET) closesocket(fd);
return success;
}
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 MG_ARCH == MG_ARCH_AZURERTOS
// 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
// That's not an error, just should try later
// even it is not. See comment for 'select' func implementation in
// nx_bsd.c That's not an error, just should try later
if (MG_SOCK_ERRNO != EAGAIN)
#endif
MG_ERROR(("%lu accept failed, errno %d", lsn->id, MG_SOCK_ERRNO));