1 /* Copyright (C) 2010-2022 The RetroArch team
3 * ---------------------------------------------------------------------------------------
4 * The following license statement only applies to this file (net_ifinfo.c).
5 * ---------------------------------------------------------------------------------------
7 * Permission is hereby granted, free of charge,
8 * to any person obtaining a copy of this software and associated documentation files (the "Software"),
9 * to deal in the Software without restriction, including without limitation the rights to
10 * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,
11 * and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
13 * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
15 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
16 * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
18 * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
19 * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
26 #include <string/stdstring.h>
27 #include <net/net_compat.h>
29 #if defined(_WIN32) && !defined(_XBOX)
31 #pragma comment(lib, "Iphlpapi")
36 #elif !defined(VITA) && !defined(GEKKO)
37 #if defined(WANT_IFADDRS)
38 #include <compat/ifaddrs.h>
39 #elif !defined(HAVE_LIBNX) && !defined(_3DS)
47 #include <net/net_ifinfo.h>
49 bool net_ifinfo_new(net_ifinfo_t *list)
51 #if defined(_WIN32) && !defined(_XBOX)
52 /* Microsoft docs recommend doing it this way. */
55 PIP_ADAPTER_ADDRESSES addr;
56 struct net_ifinfo_entry *entry;
57 size_t interfaces = 0;
58 ULONG flags = GAA_FLAG_SKIP_ANYCAST
59 | GAA_FLAG_SKIP_MULTICAST
60 | GAA_FLAG_SKIP_DNS_SERVER;
61 ULONG len = 15 * 1024;
62 PIP_ADAPTER_ADDRESSES addresses = (PIP_ADAPTER_ADDRESSES)calloc(1, len);
69 result = GetAdaptersAddresses(AF_UNSPEC, flags, NULL, addresses, &len);
70 if (result == ERROR_BUFFER_OVERFLOW)
72 PIP_ADAPTER_ADDRESSES new_addresses =
73 (PIP_ADAPTER_ADDRESSES)realloc(addresses, len);
77 memset(new_addresses, 0, len);
79 addresses = new_addresses;
80 result = GetAdaptersAddresses(AF_UNSPEC, flags, NULL,
84 if (result != ERROR_SUCCESS)
87 /* Count the number of valid interfaces first. */
92 PIP_ADAPTER_UNICAST_ADDRESS unicast_addr = addr->FirstUnicastAddress;
96 if (addr->OperStatus != IfOperStatusUp)
102 } while ((unicast_addr = unicast_addr->Next));
103 } while ((addr = addr->Next));
108 if (!(list->entries =
109 (struct net_ifinfo_entry*)calloc(interfaces, sizeof(*list->entries))))
113 /* Now create the entries. */
115 entry = list->entries;
119 PIP_ADAPTER_UNICAST_ADDRESS unicast_addr = addr->FirstUnicastAddress;
123 if (addr->OperStatus != IfOperStatusUp)
127 if (addr->FriendlyName)
129 if (!WideCharToMultiByte(CP_UTF8, 0, addr->FriendlyName, -1,
130 buf, sizeof(buf), NULL, NULL))
131 buf[0] = '\0'; /* Empty name on conversion failure. */
136 if (getnameinfo_retro(unicast_addr->Address.lpSockaddr,
137 unicast_addr->Address.iSockaddrLength,
138 entry->host, sizeof(entry->host), NULL, 0, NI_NUMERICHOST))
141 strlcpy(entry->name, buf, sizeof(entry->name));
143 if (++list->size >= interfaces)
147 } while ((unicast_addr = unicast_addr->Next));
149 if (list->size >= interfaces)
151 } while ((addr = addr->Next));
159 net_ifinfo_free(list);
164 if (!(list->entries = (struct net_ifinfo_entry*)calloc(2, sizeof(*list->entries))))
170 strlcpy(list->entries[0].name, "lo", sizeof(list->entries[0].name));
171 strlcpy(list->entries[0].host, "127.0.0.1", sizeof(list->entries[0].host));
174 if (!sceNetCtlInetGetInfo(SCE_NETCTL_INFO_GET_IP_ADDRESS, &info))
176 strlcpy(list->entries[1].name, "wlan", sizeof(list->entries[1].name));
177 strlcpy(list->entries[1].host, info.ip_address,
178 sizeof(list->entries[1].host));
183 #elif defined(HAVE_LIBNX) || defined(_3DS) || defined(GEKKO)
185 if (!(list->entries = (struct net_ifinfo_entry*)calloc(2, sizeof(*list->entries))))
191 strlcpy(list->entries[0].name, "lo", sizeof(list->entries[0].name));
192 strlcpy(list->entries[0].host, "127.0.0.1", sizeof(list->entries[0].host));
195 #if defined(HAVE_LIBNX)
197 Result rc = nifmGetCurrentIpAddress(&addr);
199 if (!R_SUCCEEDED(rc))
205 addr = net_gethostip();
209 uint8_t *addr8 = (uint8_t*)&addr;
210 strlcpy(list->entries[1].name,
211 #if defined(HAVE_LIBNX)
218 , sizeof(list->entries[1].name));
219 snprintf(list->entries[1].host, sizeof(list->entries[1].host),
221 (int)addr8[0], (int)addr8[1], (int)addr8[2], (int)addr8[3]);
227 struct ifaddrs *addr;
228 struct net_ifinfo_entry *entry;
229 size_t interfaces = 0;
230 struct ifaddrs *addresses = NULL;
232 list->entries = NULL;
234 if (getifaddrs(&addresses) || !addresses)
237 /* Count the number of valid interfaces first. */
245 if (!(addr->ifa_flags & IFF_UP))
249 switch (addr->ifa_addr->sa_family)
260 } while ((addr = addr->ifa_next));
266 (struct net_ifinfo_entry*)calloc(interfaces, sizeof(*list->entries));
271 /* Now create the entries. */
273 entry = list->entries;
282 if (!(addr->ifa_flags & IFF_UP))
286 switch (addr->ifa_addr->sa_family)
289 addrlen = sizeof(struct sockaddr_in);
293 addrlen = sizeof(struct sockaddr_in6);
300 if (getnameinfo_retro(addr->ifa_addr, addrlen,
301 entry->host, sizeof(entry->host), NULL, 0, NI_NUMERICHOST))
305 strlcpy(entry->name, addr->ifa_name, sizeof(entry->name));
307 if (++list->size >= interfaces)
311 } while ((addr = addr->ifa_next));
313 freeifaddrs(addresses);
318 freeifaddrs(addresses);
319 net_ifinfo_free(list);
325 void net_ifinfo_free(net_ifinfo_t *list)
329 list->entries = NULL;
333 bool net_ifinfo_best(const char *dst, void *src, bool ipv6)
337 /* TODO/FIXME: Implement for other platforms, if necessary. */
338 #if defined(_WIN32) && !defined(_XBOX)
341 /* Courtesy of MiniUPnP: https://github.com/miniupnp/miniupnp */
344 struct sockaddr_in dst_addr = {0};
346 ULONG dst_ip = (ULONG)inet_addr(dst);
350 if (dst_ip == INADDR_NONE || dst_ip == INADDR_ANY)
354 dst_addr.sin_family = AF_INET;
355 dst_addr.sin_addr.s_addr = dst_ip;
356 if (GetBestInterfaceEx((struct sockaddr*)&dst_addr, &index) == NO_ERROR)
358 if (GetBestInterface(dst_ip, &index) == NO_ERROR)
361 /* Microsoft docs recommend doing it this way. */
362 ULONG len = 15 * 1024;
363 PIP_ADAPTER_ADDRESSES addresses =
364 (PIP_ADAPTER_ADDRESSES)calloc(1, len);
368 ULONG flags = GAA_FLAG_SKIP_ANYCAST | GAA_FLAG_SKIP_MULTICAST |
369 GAA_FLAG_SKIP_DNS_SERVER | GAA_FLAG_SKIP_FRIENDLY_NAME;
370 ULONG result = GetAdaptersAddresses(AF_INET, flags, NULL,
373 if (result == ERROR_BUFFER_OVERFLOW)
375 PIP_ADAPTER_ADDRESSES new_addresses =
376 (PIP_ADAPTER_ADDRESSES)realloc(addresses, len);
380 memset(new_addresses, 0, len);
382 addresses = new_addresses;
383 result = GetAdaptersAddresses(AF_INET, flags, NULL,
388 if (result == NO_ERROR)
390 PIP_ADAPTER_ADDRESSES addr = addresses;
394 if (addr->IfIndex == index)
396 if (addr->FirstUnicastAddress)
398 struct sockaddr_in *addr_unicast =
399 (struct sockaddr_in*)
400 addr->FirstUnicastAddress->Address.lpSockaddr;
402 memcpy(src, &addr_unicast->sin_addr,
403 sizeof(addr_unicast->sin_addr));
410 } while ((addr = addr->Next));