mirror of
https://github.com/cesanta/mongoose.git
synced 2025-08-06 13:37:34 +08:00
Refactor mg_open_listener()
This commit is contained in:
parent
84480f4072
commit
5ac5c93c90
68
mongoose.c
68
mongoose.c
@ -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));
|
||||
|
68
src/sock.c
68
src/sock.c
@ -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));
|
||||
|
Loading…
Reference in New Issue
Block a user