diff --git a/inc/netif.h b/inc/netif.h index 96cd25c2..e569b992 100644 --- a/inc/netif.h +++ b/inc/netif.h @@ -171,6 +171,7 @@ class EXPORT_SPEC Interfaces { /** @brief Return the Interfaces singleton after possibly building * it by querying the system */ static Interfaces *theInterfaces(); + static void cleanup(); /** @brief Read the state from the system again */ bool refresh(); diff --git a/src/api/upnpapi.cpp b/src/api/upnpapi.cpp index 24eacb58..e85ff3b2 100644 --- a/src/api/upnpapi.cpp +++ b/src/api/upnpapi.cpp @@ -817,6 +817,7 @@ EXPORT_SPEC int UpnpFinish() UpnpRemoveAllVirtualDirs(); UpnpSdkInit = 0; UpnpCloseLog(); + NetIF::Interfaces::cleanup(); return UPNP_E_SUCCESS; } diff --git a/src/dispatcher/miniserver.cpp b/src/dispatcher/miniserver.cpp index b49fa81d..0288b514 100644 --- a/src/dispatcher/miniserver.cpp +++ b/src/dispatcher/miniserver.cpp @@ -741,8 +741,18 @@ int StartMiniServer(uint16_t *listen_port4, uint16_t *listen_port6) goto out; } + /* Check what port we should listen on */ + port = available_port(static_cast(*listen_port4)); + if (port < 0) { + UpnpPrintf(UPNP_CRITICAL, MSERV, __FILE__, __LINE__, + "miniserver: available_port() failed !\n"); + return port; + } + *listen_port4 = port; + *listen_port6 = port; + /* SSDP socket for discovery/advertising. */ - ret_code = get_ssdp_sockets(miniSocket); + ret_code = get_ssdp_sockets(miniSocket, port); if (ret_code != UPNP_E_SUCCESS) { UpnpPrintf(UPNP_CRITICAL, MSERV, __FILE__, __LINE__, "miniserver: get_ssdp_sockets() failed\n"); @@ -769,15 +779,6 @@ int StartMiniServer(uint16_t *listen_port4, uint16_t *listen_port6) } #ifdef INTERNAL_WEB_SERVER - port = available_port(static_cast(*listen_port4)); - if (port < 0) { - UpnpPrintf(UPNP_CRITICAL, MSERV, __FILE__, __LINE__, - "miniserver: available_port() failed !\n"); - return port; - } - *listen_port4 = port; - *listen_port6 = port; - mhdflags = MHD_USE_THREAD_PER_CONNECTION | MHD_USE_INTERNAL_POLLING_THREAD | MHD_USE_DEBUG; #ifdef UPNP_ENABLE_IPV6 @@ -825,6 +826,10 @@ int StopMiniServer() return 0; } +#ifdef INTERNAL_WEB_SERVER + MHD_stop_daemon(mhd); +#endif + sock = socket(AF_INET, SOCK_DGRAM, 0); if (sock == INVALID_SOCKET) { posix_strerror_r(errno, errorBuffer, ERROR_BUFFER_LEN); diff --git a/src/inc/ssdplib.h b/src/inc/ssdplib.h index 35096174..662ca5cb 100644 --- a/src/inc/ssdplib.h +++ b/src/inc/ssdplib.h @@ -187,7 +187,10 @@ void readFromSSDPSocket( */ int get_ssdp_sockets( /* [out] Array of SSDP sockets. */ - MiniServerSockArray *out); + MiniServerSockArray *out, + /* [in] Port to listen on. -1 for default */ + int port); + /*! diff --git a/src/ssdp/ssdp_server.cpp b/src/ssdp/ssdp_server.cpp index d36cbcc2..c787f94f 100644 --- a/src/ssdp/ssdp_server.cpp +++ b/src/ssdp/ssdp_server.cpp @@ -400,7 +400,7 @@ static int sock_make_no_blocking(SOCKET sock) } /* Create the SSDP IPv4 socket to be used by the control point. */ -static int create_ssdp_sock_reqv4(SOCKET *ssdpReqSock) +static int create_ssdp_sock_reqv4(SOCKET *ssdpReqSock, int port) { char ttl = 2; int ret = UPNP_E_SOCKET_ERROR; @@ -439,6 +439,24 @@ static int create_ssdp_sock_reqv4(SOCKET *ssdpReqSock) } sock_make_no_blocking(*ssdpReqSock); + + if (port > 0) + { + struct sockaddr_storage ss = {}; + auto ssdpAddr4 = reinterpret_cast(&ss); + + ssdpAddr4->sin_family = static_cast(AF_INET); + ssdpAddr4->sin_addr.s_addr = htonl(INADDR_ANY); + ssdpAddr4->sin_port = htons(port); + ret = bind(*ssdpReqSock, reinterpret_cast(ssdpAddr4), sizeof(*ssdpAddr4)); + + if (ret == -1) { + errorcause = "bind(INADDR_ANY)"; + ret = UPNP_E_SOCKET_BIND; + goto error_handler; + } + } + return UPNP_E_SUCCESS; error_handler: @@ -535,7 +553,7 @@ static int create_ssdp_sock_v6(bool isulagua, SOCKET *ssdpSock) #ifdef INCLUDE_CLIENT_APIS /* Create the SSDP IPv6 socket to be used by the control point. */ -static int create_ssdp_sock_reqv6(SOCKET *ssdpReqSock) +static int create_ssdp_sock_reqv6(SOCKET *ssdpReqSock, int port) { #ifdef _WIN32 DWORD hops = 1; @@ -567,6 +585,35 @@ static int create_ssdp_sock_reqv6(SOCKET *ssdpReqSock) sock_make_no_blocking(*ssdpReqSock); + if (port > 0) + { + int onOff = 1; + + // Set IPV6 socket to only bind to IPV6 (Linux Dual Stack) + ret = setsockopt(*ssdpReqSock, IPPROTO_IPV6, IPV6_V6ONLY, + reinterpret_cast(&onOff), sizeof(onOff)); + + if (ret == -1) { + errorcause = "setsockopt() IPV6_V6ONLY"; + goto error_handler; + } + + struct sockaddr_storage ss = {}; + auto ssdpAddr6 = reinterpret_cast(&ss); + + ssdpAddr6->sin6_family = static_cast(AF_INET6); + ssdpAddr6->sin6_addr = in6addr_any; + ssdpAddr6->sin6_scope_id = 0; + ssdpAddr6->sin6_port = htons(port); + ret = bind(*ssdpReqSock, reinterpret_cast(ssdpAddr6), sizeof(*ssdpAddr6)); + + if (ret == -1) { + errorcause = "bind(IN6ADDR_ANY)"; + ret = UPNP_E_SOCKET_BIND; + goto error_handler; + } + } + return UPNP_E_SUCCESS; error_handler: @@ -602,7 +649,7 @@ static void closeSockets(MiniServerSockArray *out, int doclose) maybeCLoseAndInvalidate(&out->ssdpSock6UlaGua, doclose); } -int get_ssdp_sockets(MiniServerSockArray *out) +int get_ssdp_sockets(MiniServerSockArray *out, int port) { int retVal = UPNP_E_SOCKET_ERROR; bool hasIPV4 = !apiFirstIPV4Str().empty(); @@ -613,7 +660,7 @@ int get_ssdp_sockets(MiniServerSockArray *out) if (using_ipv6()) { /* Create the IPv6 socket for SSDP REQUESTS */ if (hasIPV6) { - if ((retVal = create_ssdp_sock_reqv6(&out->ssdpReqSock6)) != UPNP_E_SUCCESS) { + if ((retVal = create_ssdp_sock_reqv6(&out->ssdpReqSock6, port)) != UPNP_E_SUCCESS) { goto out; } /* For use by ssdp control point. */ @@ -623,7 +670,7 @@ int get_ssdp_sockets(MiniServerSockArray *out) #endif /* UPNP_ENABLE_IPV6 */ /* Create the IPv4 socket for SSDP REQUESTS */ if (hasIPV4) { - if ((retVal = create_ssdp_sock_reqv4(&out->ssdpReqSock4)) != UPNP_E_SUCCESS) { + if ((retVal = create_ssdp_sock_reqv4(&out->ssdpReqSock4, port)) != UPNP_E_SUCCESS) { goto out; } /* For use by ssdp control point. */ diff --git a/src/utils/netif.cpp b/src/utils/netif.cpp index 4692388e..af804e78 100644 --- a/src/utils/netif.cpp +++ b/src/utils/netif.cpp @@ -37,6 +37,7 @@ #endif #include "netif.h" +#include "smallut.h" #include #include @@ -780,6 +781,11 @@ Interfaces *Interfaces::theInterfaces() return theInterfacesP; } +void Interfaces::cleanup() +{ + deleteZ(theInterfacesP); +} + std::ostream& Interfaces::print(std::ostream& out) { const auto& ifs = theInterfaces()->m->interfaces; for (const auto& entry : ifs) {