Skip to content

Commit 9d2d3a4

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

File tree

4 files changed

+55
-32
lines changed

4 files changed

+55
-32
lines changed

mongoose.c

Lines changed: 27 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,33 @@ 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+
84238446
if ((fd = socket(af, type, proto)) == MG_INVALID_SOCKET) {
84248447
MG_ERROR(("socket: %d", MG_SOCK_ERR(-1)));
8425-
#if defined(SO_EXCLUSIVEADDRUSE)
8426-
} else if ((rc = setsockopt(fd, SOL_SOCKET, SO_EXCLUSIVEADDRUSE,
8448+
} else if ((sockopt != -1) && (rc = setsockopt(fd, SOL_SOCKET, sockopt,
84278449
(char *) &on, sizeof(on))) != 0) {
8428-
// "Using SO_REUSEADDR and SO_EXCLUSIVEADDRUSE"
8450+
#if defined(SO_EXCLUSIVEADDRUSE)
84298451
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)
8452+
#else
84428453
MG_ERROR(("setsockopt(SO_REUSEADDR): %d", MG_SOCK_ERR(rc)));
84438454
#endif
84448455
#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: 21 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -207,27 +207,33 @@ 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+
212230
if ((fd = socket(af, type, proto)) == MG_INVALID_SOCKET) {
213231
MG_ERROR(("socket: %d", MG_SOCK_ERR(-1)));
214-
#if defined(SO_EXCLUSIVEADDRUSE)
215-
} else if ((rc = setsockopt(fd, SOL_SOCKET, SO_EXCLUSIVEADDRUSE,
232+
} else if ((sockopt != -1) && (rc = setsockopt(fd, SOL_SOCKET, sockopt,
216233
(char *) &on, sizeof(on))) != 0) {
217-
// "Using SO_REUSEADDR and SO_EXCLUSIVEADDRUSE"
234+
#if defined(SO_EXCLUSIVEADDRUSE)
218235
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)
236+
#else
231237
MG_ERROR(("setsockopt(SO_REUSEADDR): %d", MG_SOCK_ERR(rc)));
232238
#endif
233239
#if MG_IPV6_V6ONLY

tutorials/udp/mdns-server/main.c

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ int main(void) {
1212

1313
// Desired name must NOT have any dots in it, nor a domain
1414
c = mg_mdns_listen(&mgr, "Mongoose"); // Start mDNS server
15+
if(!c) return 1;
1516
// if not using our built-in TCP/IP stack, pass the IP address you want to
1617
// use as a response, this depends on your underlying TCP/IP stack and number
1718
// of interfaces available

0 commit comments

Comments
 (0)