diff --git a/libretro-common/include/net/net_ifinfo.h b/libretro-common/include/net/net_ifinfo.h index ad8a5d789f..0511b3fbdc 100644 --- a/libretro-common/include/net/net_ifinfo.h +++ b/libretro-common/include/net/net_ifinfo.h @@ -20,10 +20,9 @@ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -#ifndef _LIBRETRO_NET_IFINFO_H -#define _LIBRETRO_NET_IFINFO_H +#ifndef _LIBRETRO_SDK_NET_IFINFO_H +#define _LIBRETRO_SDK_NET_IFINFO_H -#include #include #include @@ -34,22 +33,20 @@ RETRO_BEGIN_DECLS struct net_ifinfo_entry { - char *name; - char *host; + char name[256]; + char host[256]; }; -struct net_ifinfo +typedef struct net_ifinfo { struct net_ifinfo_entry *entries; size_t size; -}; - -typedef struct net_ifinfo net_ifinfo_t; - -void net_ifinfo_free(net_ifinfo_t *list); +} net_ifinfo_t; bool net_ifinfo_new(net_ifinfo_t *list); +void net_ifinfo_free(net_ifinfo_t *list); + bool net_ifinfo_best(const char *dst, void *src, bool ipv6); RETRO_END_DECLS diff --git a/libretro-common/net/net_ifinfo.c b/libretro-common/net/net_ifinfo.c index 4c5f16a296..b260aafc2c 100644 --- a/libretro-common/net/net_ifinfo.c +++ b/libretro-common/net/net_ifinfo.c @@ -20,274 +20,287 @@ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -#include #include -#include +#include -#include +#include +#include #if defined(_WIN32) && !defined(_XBOX) #ifdef _MSC_VER #pragma comment(lib, "Iphlpapi") #endif -#include #include -#include -#elif defined (GEKKO) && !defined(WIIU) -#include -#else -#include -#include -#include -#ifdef WANT_IFADDRS +#elif !defined(GEKKO) +#if defined(WANT_IFADDRS) #include -#else -#if !defined HAVE_LIBNX && !defined(_3DS) +#elif !defined(HAVE_LIBNX) && !defined(_3DS) #include -#endif +#include #endif #endif #include -#if defined(BSD) -#include -#endif - -void net_ifinfo_free(net_ifinfo_t *list) -{ - unsigned k; - - if (!list) - return; - - for (k = 0; k < list->size; k++) - { - struct net_ifinfo_entry *ptr = - (struct net_ifinfo_entry*)&list->entries[k]; - - if (*ptr->name) - free(ptr->name); - if (*ptr->host) - free(ptr->host); - - ptr->name = NULL; - ptr->host = NULL; - } - free(list->entries); -} - -#if defined(HAVE_LIBNX) || defined(_3DS) || defined(GEKKO) -static void convert_ip(char *dst, size_t size, uint32_t ip, bool inverted) -{ - unsigned char bytes[4]; - bytes[0] = ip & 0xFF; - bytes[1] = (ip >> 8) & 0xFF; - bytes[2] = (ip >> 16) & 0xFF; - bytes[3] = (ip >> 24) & 0xFF; - - if (inverted) - snprintf(dst, size, "%d.%d.%d.%d", bytes[0], bytes[1], bytes[2], bytes[3]); - else - snprintf(dst, size, "%d.%d.%d.%d", bytes[3], bytes[2], bytes[1], bytes[0]); -} -#endif - bool net_ifinfo_new(net_ifinfo_t *list) { -#if defined(GEKKO) - char hostname[128]; +#if defined(_WIN32) && !defined(_XBOX) + /* Microsoft docs recommend doing it this way. */ + char buf[512]; + ULONG result; + PIP_ADAPTER_ADDRESSES addr; + struct net_ifinfo_entry *entry; + size_t interfaces = 0; + ULONG flags = GAA_FLAG_SKIP_ANYCAST | + GAA_FLAG_SKIP_MULTICAST | GAA_FLAG_SKIP_DNS_SERVER; + ULONG len = 15 * 1024; + PIP_ADAPTER_ADDRESSES addresses = (PIP_ADAPTER_ADDRESSES)calloc(1, len); - memset(list, 0, sizeof(net_ifinfo_t)); + list->entries = NULL; - /* loopback */ - list->entries = (struct net_ifinfo_entry*) - malloc(2 * sizeof(struct net_ifinfo_entry)); + if (!addresses) + goto failure; - if (!list->entries) - goto error; - - list->entries[0].name = strdup("lo"); - list->entries[0].host = strdup("127.0.0.1"); - list->entries[1].name = strdup("gekko"); - convert_ip(hostname, sizeof(hostname), net_gethostip(), false); - list->entries[1].host = strdup(hostname); - list->size = 2; - - return true; - - /* - actual interface - can be wlan or eth (with a wiiu adapter) - so we just use "switch" as a name - */ -#elif defined(HAVE_LIBNX) || defined(_3DS) - uint32_t id; -#ifdef HAVE_LIBNX - Result rc; -#endif - char hostname[128]; - unsigned k = 0; - struct net_ifinfo_entry *ptr = NULL; - - memset(list, 0, sizeof(net_ifinfo_t)); - - /* loopback */ - convert_ip(hostname, sizeof(hostname), INADDR_LOOPBACK, false); - - ptr = (struct net_ifinfo_entry*) - realloc(list->entries, (k+1) * sizeof(struct net_ifinfo_entry)); - - if (!ptr) - goto error; - - list->entries = ptr; - - list->entries[k].name = strdup("lo"); - list->entries[k].host = strdup(hostname); - list->size = k + 1; - - k++; - - /* - actual interface - can be wlan or eth (with a wiiu adapter) - so we just use "switch" as a name - */ -#if defined(_3DS) || defined (GEKKO) - convert_ip(hostname, sizeof(hostname), gethostid(), true); -#else - rc = nifmGetCurrentIpAddress(&id); - - if (!R_SUCCEEDED(rc)) /* not connected to any network */ - return true; - - convert_ip(hostname, sizeof(hostname), id, true); -#endif - - ptr = (struct net_ifinfo_entry*) - realloc(list->entries, (k+1) * sizeof(struct net_ifinfo_entry)); - - if (!ptr) - goto error; - - list->entries = ptr; -#if defined(_3DS) - list->entries[k].name = strdup("wlan"); -#else - list->entries[k].name = strdup("switch"); -#endif - list->entries[k].host = strdup(hostname); - list->size = k + 1; - - return true; -#elif defined(_WIN32) && !defined(_XBOX) - unsigned k = 0; - PIP_ADAPTER_ADDRESSES adapter_addresses = NULL, aa = NULL; - PIP_ADAPTER_UNICAST_ADDRESS ua = NULL; -#ifdef _WIN32_WINNT_WINXP - DWORD size = 0; - DWORD rv = GetAdaptersAddresses(AF_UNSPEC, GAA_FLAG_INCLUDE_PREFIX, NULL, NULL, &size); - adapter_addresses = (PIP_ADAPTER_ADDRESSES)malloc(size); - rv = GetAdaptersAddresses(AF_UNSPEC, GAA_FLAG_INCLUDE_PREFIX, NULL, adapter_addresses, &size); - - memset(list, 0, sizeof(net_ifinfo_t)); - - if (rv != ERROR_SUCCESS) - goto error; -#endif - for (aa = adapter_addresses; aa != NULL; aa = aa->Next) + result = GetAdaptersAddresses(AF_UNSPEC, flags, NULL, addresses, &len); + if (result == ERROR_BUFFER_OVERFLOW) { - char name[PATH_MAX_LENGTH]; - memset(name, 0, sizeof(name)); + PIP_ADAPTER_ADDRESSES new_addresses = + (PIP_ADAPTER_ADDRESSES)realloc(addresses, len); - WideCharToMultiByte(CP_UTF8, 0, aa->FriendlyName, wcslen(aa->FriendlyName), - name, PATH_MAX_LENGTH, NULL, NULL); - - for (ua = aa->FirstUnicastAddress; ua != NULL; ua = ua->Next) + if (new_addresses) { - char host[PATH_MAX_LENGTH]; - struct net_ifinfo_entry *ptr = (struct net_ifinfo_entry*) - realloc(list->entries, (k+1) * sizeof(struct net_ifinfo_entry)); + memset(new_addresses, 0, len); - if (!ptr) - goto error; - - list->entries = ptr; - - memset(host, 0, sizeof(host)); - - getnameinfo(ua->Address.lpSockaddr, ua->Address.iSockaddrLength, - host, sizeof(host), NULL, NI_MAXSERV, NI_NUMERICHOST); - - list->entries[k].name = strdup(name); - list->entries[k].host = strdup(host); - list->size = k + 1; - - k++; + addresses = new_addresses; + result = GetAdaptersAddresses(AF_UNSPEC, flags, NULL, + addresses, &len); } } + if (result != ERROR_SUCCESS) + goto failure; - free(adapter_addresses); -#else - unsigned k = 0; - struct ifaddrs *ifa = NULL; - struct ifaddrs *ifaddr = NULL; + /* Count the number of valid interfaces first. */ + addr = addresses; - memset(list, 0, sizeof(net_ifinfo_t)); - - if (getifaddrs(&ifaddr) == -1) - goto error; - - if (!list) - goto error; - - for (ifa = ifaddr; ifa != NULL; ifa = ifa->ifa_next) + do { - char host[NI_MAXHOST]; - struct net_ifinfo_entry *ptr = NULL; + PIP_ADAPTER_UNICAST_ADDRESS unicast_addr = addr->FirstUnicastAddress; - if (!ifa->ifa_addr) + if (!unicast_addr) + continue; + if (addr->OperStatus != IfOperStatusUp) continue; - if (ifa->ifa_addr->sa_family != AF_INET) + do + { + interfaces++; + } while ((unicast_addr = unicast_addr->Next)); + } while ((addr = addr->Next)); + + if (!interfaces) + goto failure; + + list->entries = + (struct net_ifinfo_entry*)calloc(interfaces, sizeof(*list->entries)); + if (!list->entries) + goto failure; + list->size = 0; + + /* Now create the entries. */ + addr = addresses; + entry = list->entries; + + do + { + PIP_ADAPTER_UNICAST_ADDRESS unicast_addr = addr->FirstUnicastAddress; + + if (!unicast_addr) + continue; + if (addr->OperStatus != IfOperStatusUp) continue; - if (getnameinfo(ifa->ifa_addr, sizeof(struct sockaddr_in), - host, NI_MAXHOST, NULL, 0, NI_NUMERICHOST) != 0) - goto error; + buf[0] = '\0'; + if (addr->FriendlyName) + { + if (!WideCharToMultiByte(CP_UTF8, 0, addr->FriendlyName, -1, + buf, sizeof(buf), NULL, NULL)) + buf[0] = '\0'; /* Empty name on conversion failure. */ + } - ptr = (struct net_ifinfo_entry*) - realloc(list->entries, (k+1) * sizeof(struct net_ifinfo_entry)); + do + { + if (getnameinfo(unicast_addr->Address.lpSockaddr, + unicast_addr->Address.iSockaddrLength, + entry->host, sizeof(entry->host), NULL, 0, NI_NUMERICHOST)) + continue; - if (!ptr) - goto error; + strlcpy(entry->name, buf, sizeof(entry->name)); - list->entries = ptr; + if (++list->size >= interfaces) + break; - list->entries[k].name = strdup(ifa->ifa_name); - list->entries[k].host = strdup(host); - list->size = k + 1; + entry++; + } while ((unicast_addr = unicast_addr->Next)); - k++; - } + if (list->size >= interfaces) + break; + } while ((addr = addr->Next)); + + free(addresses); - freeifaddrs(ifaddr); -#endif return true; -error: -#ifdef _WIN32 - if (adapter_addresses) - free(adapter_addresses); -#elif !defined(HAVE_LIBNX) && !defined(_3DS) && !defined(GEKKO) - freeifaddrs(ifaddr); -#endif +failure: + free(addresses); net_ifinfo_free(list); return false; +#elif defined(HAVE_LIBNX) || defined(_3DS) || defined(GEKKO) + uint32_t addr = 0; + + list->entries = (struct net_ifinfo_entry*)calloc(2, sizeof(*list->entries)); + if (!list->entries) + { + list->size = 0; + + return false; + } + + strcpy_literal(list->entries[0].name, "lo"); + strcpy_literal(list->entries[0].host, "127.0.0.1"); + list->size = 1; + +#if defined(HAVE_LIBNX) + { + Result rc = nifmGetCurrentIpAddress(&addr); + + if (!R_SUCCEEDED(rc)) + return true; + } +#elif defined(_3DS) + addr = gethostid(); +#else + addr = net_gethostip(); +#endif + if (addr) + { + uint8_t *addr8 = (uint8_t*)&addr; + + strcpy_literal(list->entries[1].name, +#if defined(HAVE_LIBNX) + "switch" +#elif defined(_3DS) + "wlan" +#else + "gekko" +#endif + ); + snprintf(list->entries[1].host, sizeof(list->entries[1].host), + "%d.%d.%d.%d", + (int)addr8[0], (int)addr8[1], (int)addr8[2], (int)addr8[3]); + list->size++; + } + + return true; +#else + struct ifaddrs *addr; + struct net_ifinfo_entry *entry; + size_t interfaces = 0; + struct ifaddrs *addresses = NULL; + + list->entries = NULL; + + if (getifaddrs(&addresses) || !addresses) + goto failure; + + /* Count the number of valid interfaces first. */ + addr = addresses; + + do + { + if (!addr->ifa_addr) + continue; + if (!(addr->ifa_flags & IFF_UP)) + continue; + + switch (addr->ifa_addr->sa_family) + { + case AF_INET: + case AF_INET6: + interfaces++; + break; + default: + break; + } + } while ((addr = addr->ifa_next)); + + if (!interfaces) + goto failure; + + list->entries = + (struct net_ifinfo_entry*)calloc(interfaces, sizeof(*list->entries)); + if (!list->entries) + goto failure; + list->size = 0; + + /* Now create the entries. */ + addr = addresses; + entry = list->entries; + + do + { + socklen_t addrlen; + + if (!addr->ifa_addr) + continue; + if (!(addr->ifa_flags & IFF_UP)) + continue; + + switch (addr->ifa_addr->sa_family) + { + case AF_INET: + addrlen = sizeof(struct sockaddr_in); + break; + case AF_INET6: + addrlen = sizeof(struct sockaddr_in6); + break; + default: + continue; + } + + if (getnameinfo(addr->ifa_addr, addrlen, + entry->host, sizeof(entry->host), NULL, 0, NI_NUMERICHOST)) + continue; + + if (addr->ifa_name) + strlcpy(entry->name, addr->ifa_name, sizeof(entry->name)); + + if (++list->size >= interfaces) + break; + + entry++; + } while ((addr = addr->ifa_next)); + + freeifaddrs(addresses); + + return true; + +failure: + freeifaddrs(addresses); + net_ifinfo_free(list); + + return false; +#endif +} + +void net_ifinfo_free(net_ifinfo_t *list) +{ + free(list->entries); + + list->entries = NULL; + list->size = 0; } bool net_ifinfo_best(const char *dst, void *src, bool ipv6) @@ -300,42 +313,40 @@ bool net_ifinfo_best(const char *dst, void *src, bool ipv6) { /* Courtesy of MiniUPnP: https://github.com/miniupnp/miniupnp */ DWORD index; - unsigned long udst = inet_addr(dst); #ifdef __WINRT__ - struct sockaddr_in addr_dst = {0}; + struct sockaddr_in dst_addr = {0}; #endif - - if (udst == INADDR_NONE || udst == INADDR_ANY) - return ret; + IPAddr dst_ip = inet_addr(dst); if (!src) - return ret; + return false; + if (dst_ip == INADDR_NONE || dst_ip == INADDR_ANY) + return false; #ifdef __WINRT__ - addr_dst.sin_family = AF_INET; - addr_dst.sin_addr.s_addr = udst; - if (GetBestInterfaceEx((struct sockaddr *) &addr_dst, &index) - == NO_ERROR) + dst_addr.sin_family = AF_INET; + dst_addr.sin_addr.s_addr = dst_ip; + if (GetBestInterfaceEx((struct sockaddr*)&dst_addr, &index) == NO_ERROR) #else - if (GetBestInterface(udst, &index) == NO_ERROR) + if (GetBestInterface(dst_ip, &index) == NO_ERROR) #endif { /* Microsoft docs recommend doing it this way. */ - ULONG len = 15 * 1024; - PIP_ADAPTER_ADDRESSES addresses = (PIP_ADAPTER_ADDRESSES)calloc(1, len); + ULONG len = 15 * 1024; + PIP_ADAPTER_ADDRESSES addresses = + (PIP_ADAPTER_ADDRESSES)calloc(1, len); if (addresses) { - ULONG flags = GAA_FLAG_SKIP_ANYCAST | - GAA_FLAG_SKIP_MULTICAST | - GAA_FLAG_SKIP_DNS_SERVER | - GAA_FLAG_SKIP_FRIENDLY_NAME; + ULONG flags = GAA_FLAG_SKIP_ANYCAST | GAA_FLAG_SKIP_MULTICAST | + GAA_FLAG_SKIP_DNS_SERVER | GAA_FLAG_SKIP_FRIENDLY_NAME; ULONG result = GetAdaptersAddresses(AF_INET, flags, NULL, addresses, &len); if (result == ERROR_BUFFER_OVERFLOW) { - PIP_ADAPTER_ADDRESSES new_addresses = (PIP_ADAPTER_ADDRESSES)realloc(addresses, len); + PIP_ADAPTER_ADDRESSES new_addresses = + (PIP_ADAPTER_ADDRESSES)realloc(addresses, len); if (new_addresses) { @@ -358,8 +369,8 @@ bool net_ifinfo_best(const char *dst, void *src, bool ipv6) if (addr->FirstUnicastAddress) { struct sockaddr_in *addr_unicast = - (struct sockaddr_in *) - addr->FirstUnicastAddress->Address.lpSockaddr; + (struct sockaddr_in*) + addr->FirstUnicastAddress->Address.lpSockaddr; memcpy(src, &addr_unicast->sin_addr, sizeof(addr_unicast->sin_addr));