@@ -461,8 +461,13 @@ static void mdns_cb(struct mg_connection *c, int ev, void *ev_data) {
461461
462462void mg_multicast_add(struct mg_connection *c, char *ip);
463463struct 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
0 commit comments