Skip to content

Commit 11f32f0

Browse files
author
robert
committed
Fixed mdns bind issue on windows
1 parent 041ec6e commit 11f32f0

File tree

3 files changed

+58
-32
lines changed

3 files changed

+58
-32
lines changed

mongoose.c

Lines changed: 29 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -461,8 +461,13 @@ static void mdns_cb(struct mg_connection *c, int ev, void *ev_data) {
461461

462462
void mg_multicast_add(struct mg_connection *c, char *ip);
463463
struct mg_connection *mg_mdns_listen(struct mg_mgr *mgr, char *name) {
464+
#if MG_ARCH == MG_ARCH_WIN32
465+
const char *mcast_url = "udp://0.0.0.0:5353";
466+
#else
467+
const char *mcast_url = "udp://224.0.0.251:5353";
468+
#endif
464469
struct mg_connection *c =
465-
mg_listen(mgr, "udp://224.0.0.251:5353", mdns_cb, name);
470+
mg_listen(mgr, mcast_url, mdns_cb, name);
466471
if (c != NULL) mg_multicast_add(c, (char *)"224.0.0.251");
467472
return c;
468473
}
@@ -8418,27 +8423,35 @@ bool mg_open_listener(struct mg_connection *c, const char *url) {
84188423
int rc, on = 1, af = c->loc.is_ip6 ? AF_INET6 : AF_INET;
84198424
int type = strncmp(url, "udp:", 4) == 0 ? SOCK_DGRAM : SOCK_STREAM;
84208425
int proto = type == SOCK_DGRAM ? IPPROTO_UDP : IPPROTO_TCP;
8426+
int sockopt = -1;
84218427
(void) on;
84228428

8429+
#if defined(SO_EXCLUSIVEADDRUSE)
8430+
// Using SO_REUSEADDR for UDP sockets on Windows (issue #3125)
8431+
sockopt = proto == IPPROTO_UDP ? SO_REUSEADDR : SO_EXCLUSIVEADDRUSE;
8432+
// "Using SO_REUSEADDR and SO_EXCLUSIVEADDRUSE"
8433+
#elif defined(SO_REUSEADDR) && (!defined(LWIP_SOCKET) || SO_REUSE)
8434+
sockopt = SO_REUSEADDR;
8435+
// 1. SO_REUSEADDR semantics on UNIX and Windows is different. On
8436+
// Windows, SO_REUSEADDR allows to bind a socket to a port without error
8437+
// even if the port is already open by another program. This is not the
8438+
// behavior SO_REUSEADDR was designed for, and leads to hard-to-track
8439+
// failure scenarios.
8440+
//
8441+
// 2. For LWIP, SO_REUSEADDR should be explicitly enabled by defining
8442+
// SO_REUSE = 1 in lwipopts.h, otherwise the code below will compile but
8443+
// won't work! (setsockopt will return EINVAL)
8444+
#endif
8445+
8446+
MG_INFO(("%d %d", proto, IPPROTO_UDP));
8447+
84238448
if ((fd = socket(af, type, proto)) == MG_INVALID_SOCKET) {
84248449
MG_ERROR(("socket: %d", MG_SOCK_ERR(-1)));
8425-
#if defined(SO_EXCLUSIVEADDRUSE)
8426-
} else if ((rc = setsockopt(fd, SOL_SOCKET, SO_EXCLUSIVEADDRUSE,
8450+
} else if ((sockopt != -1) && (rc = setsockopt(fd, SOL_SOCKET, sockopt,
84278451
(char *) &on, sizeof(on))) != 0) {
8428-
// "Using SO_REUSEADDR and SO_EXCLUSIVEADDRUSE"
8452+
#if defined(SO_EXCLUSIVEADDRUSE)
84298453
MG_ERROR(("setsockopt(SO_EXCLUSIVEADDRUSE): %d %d", on, MG_SOCK_ERR(rc)));
8430-
#elif defined(SO_REUSEADDR) && (!defined(LWIP_SOCKET) || SO_REUSE)
8431-
} else if ((rc = setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, (char *) &on,
8432-
sizeof(on))) != 0) {
8433-
// 1. SO_REUSEADDR semantics on UNIX and Windows is different. On
8434-
// Windows, SO_REUSEADDR allows to bind a socket to a port without error
8435-
// even if the port is already open by another program. This is not the
8436-
// behavior SO_REUSEADDR was designed for, and leads to hard-to-track
8437-
// failure scenarios.
8438-
//
8439-
// 2. For LWIP, SO_REUSEADDR should be explicitly enabled by defining
8440-
// SO_REUSE = 1 in lwipopts.h, otherwise the code below will compile but
8441-
// won't work! (setsockopt will return EINVAL)
8454+
#else
84428455
MG_ERROR(("setsockopt(SO_REUSEADDR): %d", MG_SOCK_ERR(rc)));
84438456
#endif
84448457
#if MG_IPV6_V6ONLY

src/dns.c

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -340,8 +340,13 @@ static void mdns_cb(struct mg_connection *c, int ev, void *ev_data) {
340340

341341
void mg_multicast_add(struct mg_connection *c, char *ip);
342342
struct mg_connection *mg_mdns_listen(struct mg_mgr *mgr, char *name) {
343+
#if MG_ARCH == MG_ARCH_WIN32
344+
const char *mcast_url = "udp://0.0.0.0:5353";
345+
#else
346+
const char *mcast_url = "udp://224.0.0.251:5353";
347+
#endif
343348
struct mg_connection *c =
344-
mg_listen(mgr, "udp://224.0.0.251:5353", mdns_cb, name);
349+
mg_listen(mgr, mcast_url, mdns_cb, name);
345350
if (c != NULL) mg_multicast_add(c, (char *)"224.0.0.251");
346351
return c;
347352
}

src/sock.c

Lines changed: 23 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -207,27 +207,35 @@ bool mg_open_listener(struct mg_connection *c, const char *url) {
207207
int rc, on = 1, af = c->loc.is_ip6 ? AF_INET6 : AF_INET;
208208
int type = strncmp(url, "udp:", 4) == 0 ? SOCK_DGRAM : SOCK_STREAM;
209209
int proto = type == SOCK_DGRAM ? IPPROTO_UDP : IPPROTO_TCP;
210+
int sockopt = -1;
210211
(void) on;
211212

213+
#if defined(SO_EXCLUSIVEADDRUSE)
214+
// Using SO_REUSEADDR for UDP sockets on Windows (issue #3125)
215+
sockopt = proto == IPPROTO_UDP ? SO_REUSEADDR : SO_EXCLUSIVEADDRUSE;
216+
// "Using SO_REUSEADDR and SO_EXCLUSIVEADDRUSE"
217+
#elif defined(SO_REUSEADDR) && (!defined(LWIP_SOCKET) || SO_REUSE)
218+
sockopt = SO_REUSEADDR;
219+
// 1. SO_REUSEADDR semantics on UNIX and Windows is different. On
220+
// Windows, SO_REUSEADDR allows to bind a socket to a port without error
221+
// even if the port is already open by another program. This is not the
222+
// behavior SO_REUSEADDR was designed for, and leads to hard-to-track
223+
// failure scenarios.
224+
//
225+
// 2. For LWIP, SO_REUSEADDR should be explicitly enabled by defining
226+
// SO_REUSE = 1 in lwipopts.h, otherwise the code below will compile but
227+
// won't work! (setsockopt will return EINVAL)
228+
#endif
229+
230+
MG_INFO(("%d %d", proto, IPPROTO_UDP));
231+
212232
if ((fd = socket(af, type, proto)) == MG_INVALID_SOCKET) {
213233
MG_ERROR(("socket: %d", MG_SOCK_ERR(-1)));
214-
#if defined(SO_EXCLUSIVEADDRUSE)
215-
} else if ((rc = setsockopt(fd, SOL_SOCKET, SO_EXCLUSIVEADDRUSE,
234+
} else if ((sockopt != -1) && (rc = setsockopt(fd, SOL_SOCKET, sockopt,
216235
(char *) &on, sizeof(on))) != 0) {
217-
// "Using SO_REUSEADDR and SO_EXCLUSIVEADDRUSE"
236+
#if defined(SO_EXCLUSIVEADDRUSE)
218237
MG_ERROR(("setsockopt(SO_EXCLUSIVEADDRUSE): %d %d", on, MG_SOCK_ERR(rc)));
219-
#elif defined(SO_REUSEADDR) && (!defined(LWIP_SOCKET) || SO_REUSE)
220-
} else if ((rc = setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, (char *) &on,
221-
sizeof(on))) != 0) {
222-
// 1. SO_REUSEADDR semantics on UNIX and Windows is different. On
223-
// Windows, SO_REUSEADDR allows to bind a socket to a port without error
224-
// even if the port is already open by another program. This is not the
225-
// behavior SO_REUSEADDR was designed for, and leads to hard-to-track
226-
// failure scenarios.
227-
//
228-
// 2. For LWIP, SO_REUSEADDR should be explicitly enabled by defining
229-
// SO_REUSE = 1 in lwipopts.h, otherwise the code below will compile but
230-
// won't work! (setsockopt will return EINVAL)
238+
#else
231239
MG_ERROR(("setsockopt(SO_REUSEADDR): %d", MG_SOCK_ERR(rc)));
232240
#endif
233241
#if MG_IPV6_V6ONLY

0 commit comments

Comments
 (0)