1 /* Copyright (C) 2010-2022 The RetroArch team
3 * ---------------------------------------------------------------------------------------
4 * The following license statement only applies to this file (net_compat.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 <compat/strl.h>
27 #include <retro_miscellaneous.h>
28 #include <retro_timers.h>
30 #include <net/net_compat.h>
32 #if defined(_WIN32) && !defined(_XBOX)
33 #if !defined(_WIN32_WINNT) || _WIN32_WINNT < 0x0600
34 const char *inet_ntop(int af, const void *src, char *dst, socklen_t size)
36 struct sockaddr_storage addr;
41 memcpy(&((struct sockaddr_in*)&addr)->sin_addr, src,
42 sizeof(struct in_addr));
46 memcpy(&((struct sockaddr_in6*)&addr)->sin6_addr, src,
47 sizeof(struct in6_addr));
55 if (getnameinfo((struct sockaddr*)&addr, sizeof(addr), dst, size, NULL, 0,
62 int inet_pton(int af, const char *src, void *dst)
64 struct addrinfo *addr = NULL;
65 struct addrinfo hints = {0};
79 hints.ai_flags = AI_NUMERICHOST;
80 switch (getaddrinfo(src, NULL, &hints, &addr))
96 memcpy(dst, &((struct sockaddr_in*)addr->ai_addr)->sin_addr,
97 sizeof(struct in_addr));
101 memcpy(dst, &((struct sockaddr_in6*)addr->ai_addr)->sin6_addr,
102 sizeof(struct in6_addr));
116 struct hostent *gethostbyname(const char *name)
118 static struct in_addr addr = {0};
119 static struct hostent he = {0};
122 struct hostent *ret = NULL;
127 event = WSACreateEvent();
129 XNetDnsLookup(name, event, &dns);
133 WaitForSingleObject((HANDLE)event, INFINITE);
138 memcpy(&addr, dns->aina, sizeof(addr));
142 he.h_addrtype = AF_INET;
143 he.h_length = sizeof(addr);
144 he.h_addr_list = &he.h_addr;
145 he.h_addr = (char*)&addr;
150 WSACloseEvent(event);
158 #define COMPAT_NET_INIT_SIZE 0x80000
160 char *inet_ntoa(struct in_addr in)
162 static char ip_addr[16];
164 sceNetInetNtop(AF_INET, &in, ip_addr, sizeof(ip_addr));
169 int inet_aton(const char *cp, struct in_addr *inp)
171 return sceNetInetPton(AF_INET, cp, inp);
174 uint32_t inet_addr(const char *cp)
178 return (sceNetInetPton(AF_INET, cp, &in) == 1) ? in.s_addr : INADDR_NONE;
181 struct hostent *gethostbyname(const char *name)
183 static struct SceNetInAddr addr = {0};
184 static struct hostent he = {0};
186 struct hostent *ret = NULL;
191 rid = sceNetResolverCreate("resolver", NULL, 0);
195 if (sceNetResolverStartNtoa(rid, name, &addr, 0, 0, 0) < 0)
200 he.h_addrtype = AF_INET;
201 he.h_length = sizeof(addr);
202 he.h_addr_list = &he.h_addr;
203 he.h_addr = (char*)&addr;
208 sceNetResolverDestroy(rid);
214 const char *inet_ntop(int af, const void *src, char *dst, socklen_t size)
216 const char *addr_str = inet_ntoa(*(struct in_addr*)src);
220 strlcpy(dst, addr_str, size);
228 int inet_pton(int af, const char *src, void *dst)
230 if (inet_aton(src, (struct in_addr*)dst))
239 static int _net_compat_thread_entry(int argc, const char **argv)
241 void *buf = memalign(128, WIIU_RCVBUF + WIIU_SNDBUF);
246 somemopt(1, buf, WIIU_RCVBUF + WIIU_SNDBUF, 0);
253 static void _net_compat_thread_cleanup(OSThread *thread, void *stack)
260 #include <3ds/types.h>
261 #include <3ds/services/soc.h>
263 #define SOC_ALIGN 0x1000
264 #define SOC_BUFFERSIZE 0x100000
267 int getaddrinfo_retro(const char *node, const char *service,
268 struct addrinfo *hints, struct addrinfo **res)
270 #if defined(HAVE_SOCKET_LEGACY) || defined(WIIU)
271 struct addrinfo default_hints = {0};
274 hints = &default_hints;
275 if (!hints->ai_family)
276 hints->ai_family = AF_INET;
279 node = (hints->ai_flags & AI_PASSIVE) ? "0.0.0.0" : "127.0.0.1";
282 #ifdef HAVE_SOCKET_LEGACY
284 struct addrinfo *info = (struct addrinfo*)calloc(1, sizeof(*info));
285 struct sockaddr_in *addr = (struct sockaddr_in*)malloc(sizeof(*addr));
290 info->ai_family = AF_INET;
291 info->ai_socktype = hints->ai_socktype;
292 info->ai_protocol = hints->ai_protocol;
293 info->ai_addrlen = sizeof(*addr);
294 info->ai_addr = (struct sockaddr*)addr;
295 /* We ignore AI_CANONNAME; ai_canonname is always NULL. */
297 addr->sin_family = AF_INET;
301 /* We can only handle numeric ports; ignore AI_NUMERICSERV. */
302 char *service_end = NULL;
303 uint16_t port = (uint16_t)strtoul(service, &service_end, 10);
305 if (service_end == service || *service_end)
308 addr->sin_port = htons(port);
311 if (hints->ai_flags & AI_NUMERICHOST)
313 if (!inet_aton(node, &addr->sin_addr))
318 struct hostent *host = gethostbyname(node);
320 if (!host || !host->h_addr)
323 memcpy(&addr->sin_addr, host->h_addr, sizeof(addr->sin_addr));
337 return getaddrinfo(node, service, hints, res);
341 void freeaddrinfo_retro(struct addrinfo *res)
343 #ifdef HAVE_SOCKET_LEGACY
354 int getnameinfo_retro(const struct sockaddr *addr, socklen_t addrlen,
355 char *host, socklen_t hostlen, char *serv, socklen_t servlen, int flags)
357 #ifdef HAVE_SOCKET_LEGACY
358 const struct sockaddr_in *addr4 = (const struct sockaddr_in*)addr;
360 /* We cannot perform reverse DNS lookups here; ignore the following flags:
363 NI_NUMERICHOST (always enforced)
367 const char *_host = inet_ntoa(addr4->sin_addr);
372 strlcpy(host, _host, hostlen);
375 /* We cannot get service names here; ignore the following flags:
377 NI_NUMERICSERV (always enforced)
380 snprintf(serv, servlen, "%hu", (unsigned short)ntohs(addr4->sin_port));
384 return getnameinfo(addr, addrlen, host, hostlen, serv, servlen, flags);
388 bool addr_6to4(struct sockaddr_storage *addr)
392 static const uint16_t preffix[] = {0,0,0,0,0,0xffff};
395 struct sockaddr_in6 *addr6 = (struct sockaddr_in6*)addr;
396 struct sockaddr_in *addr4 = (struct sockaddr_in*)addr;
398 switch (addr->ss_family)
401 /* No need to convert. */
404 /* Is the address provided an IPv4? */
405 if (!memcmp(&addr6->sin6_addr, preffix, sizeof(preffix)))
408 /* We don't know how to handle this. */
412 memcpy(&address, ((uint8_t*)&addr6->sin6_addr) + sizeof(preffix),
414 port = addr6->sin6_port;
416 memset(addr, 0, sizeof(*addr));
418 addr4->sin_family = AF_INET;
419 addr4->sin_port = port;
420 memcpy(&addr4->sin_addr, &address, sizeof(addr4->sin_addr));
426 bool ipv4_is_lan_address(const struct sockaddr_in *addr)
428 static const uint32_t subnets[] = {0x0A000000, 0xAC100000, 0xC0A80000};
429 static const uint32_t masks[] = {0xFF000000, 0xFFF00000, 0xFFFF0000};
433 memcpy(&uaddr, &addr->sin_addr, sizeof(uaddr));
434 uaddr = ntohl(uaddr);
436 for (i = 0; i < ARRAY_SIZE(subnets); i++)
437 if ((uaddr & masks[i]) == subnets[i])
443 bool ipv4_is_cgnat_address(const struct sockaddr_in *addr)
445 static const uint32_t subnet = 0x64400000;
446 static const uint32_t mask = 0xFFC00000;
449 memcpy(&uaddr, &addr->sin_addr, sizeof(uaddr));
450 uaddr = ntohl(uaddr);
452 return (uaddr & mask) == subnet;
458 * Platform specific socket library initialization.
460 * @return true if successful, otherwise false.
462 bool network_init(void)
465 static bool initialized = false;
471 if (WSAStartup(MAKEWORD(2, 2), &wsaData))
482 #elif defined(__PSL1GHT__) || defined(__PS3__)
483 static bool initialized = false;
489 sysModuleLoad(SYSMODULE_NET);
492 if (netCtlInit() < 0)
499 if (netCtlGetState(&state) < 0)
501 if (state == NET_CTL_STATE_IPObtained)
517 netFinalizeNetwork();
519 sysModuleUnload(SYSMODULE_NET);
523 if (sceNetShowNetstat() == SCE_NET_ERROR_ENOTINIT)
525 SceNetInitParam param;
526 void *net_compat_memory = malloc(COMPAT_NET_INIT_SIZE);
528 if (!net_compat_memory)
531 param.memory = net_compat_memory;
532 param.size = COMPAT_NET_INIT_SIZE;
535 if (sceNetInit(¶m) < 0)
537 if (sceNetCtlInit() < 0)
546 free(net_compat_memory);
553 static bool initialized = false;
557 char localip[16] = {0};
558 char netmask[16] = {0};
559 char gateway[16] = {0};
561 if (if_config(localip, netmask, gateway, true, 10) < 0)
573 static OSThread net_compat_thread;
574 static bool initialized = false;
578 void *stack = malloc(0x1000);
585 if (!OSCreateThread(&net_compat_thread, _net_compat_thread_entry,
586 0, NULL, (void*)((size_t)stack + 0x1000), 0x1000, 3,
587 OS_THREAD_ATTRIB_AFFINITY_ANY))
594 OSSetThreadName(&net_compat_thread, "Network compat thread");
595 OSSetThreadDeallocator(&net_compat_thread, _net_compat_thread_cleanup);
596 OSResumeThread(&net_compat_thread);
603 static bool initialized = false;
607 u32 *net_compat_memory = (u32*)memalign(SOC_ALIGN, SOC_BUFFERSIZE);
609 if (!net_compat_memory)
613 if (socInit(net_compat_memory, SOC_BUFFERSIZE))
617 free(net_compat_memory);
627 static bool initialized = false;
631 /* Do not like SIGPIPE killing our app. */
632 signal(SIGPIPE, SIG_IGN);