diff --git a/mongoose.c b/mongoose.c index fa15b329..2c28431e 100644 --- a/mongoose.c +++ b/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)); diff --git a/src/sock.c b/src/sock.c index 28e1590b..7bfd031f 100644 --- a/src/sock.c +++ b/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));