libretro: adjust psxclock description
[pcsx_rearmed.git] / deps / libretro-common / net / net_compat.c
CommitLineData
3719602c
PC
1/* Copyright (C) 2010-2022 The RetroArch team
2 *
3 * ---------------------------------------------------------------------------------------
4 * The following license statement only applies to this file (net_compat.c).
5 * ---------------------------------------------------------------------------------------
6 *
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:
12 *
13 * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
14 *
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.
21 */
22
23#include <stdlib.h>
24#include <stdio.h>
25
26#include <compat/strl.h>
27#include <retro_miscellaneous.h>
28#include <retro_timers.h>
29
30#include <net/net_compat.h>
31
32#if defined(_WIN32) && !defined(_XBOX)
33#if !defined(_WIN32_WINNT) || _WIN32_WINNT < 0x0600
34const char *inet_ntop(int af, const void *src, char *dst, socklen_t size)
35{
36 struct sockaddr_storage addr;
37
38 switch (af)
39 {
40 case AF_INET:
41 memcpy(&((struct sockaddr_in*)&addr)->sin_addr, src,
42 sizeof(struct in_addr));
43 break;
44#ifdef HAVE_INET6
45 case AF_INET6:
46 memcpy(&((struct sockaddr_in6*)&addr)->sin6_addr, src,
47 sizeof(struct in6_addr));
48 break;
49#endif
50 default:
51 return NULL;
52 }
53
54 addr.ss_family = af;
55 if (getnameinfo((struct sockaddr*)&addr, sizeof(addr), dst, size, NULL, 0,
56 NI_NUMERICHOST))
57 return NULL;
58
59 return dst;
60}
61
62int inet_pton(int af, const char *src, void *dst)
63{
64 struct addrinfo *addr = NULL;
65 struct addrinfo hints = {0};
66
67 switch (af)
68 {
69 case AF_INET:
70#ifdef HAVE_INET6
71 case AF_INET6:
72#endif
73 break;
74 default:
75 return -1;
76 }
77
78 hints.ai_family = af;
79 hints.ai_flags = AI_NUMERICHOST;
80 switch (getaddrinfo(src, NULL, &hints, &addr))
81 {
82 case 0:
83 break;
84 case EAI_NONAME:
85 return 0;
86 default:
87 return -1;
88 }
89
90 if (!addr)
91 return -1;
92
93 switch (af)
94 {
95 case AF_INET:
96 memcpy(dst, &((struct sockaddr_in*)addr->ai_addr)->sin_addr,
97 sizeof(struct in_addr));
98 break;
99#ifdef HAVE_INET6
100 case AF_INET6:
101 memcpy(dst, &((struct sockaddr_in6*)addr->ai_addr)->sin6_addr,
102 sizeof(struct in6_addr));
103 break;
104#endif
105 default:
106 break;
107 }
108
109 freeaddrinfo(addr);
110
111 return 1;
112}
113#endif
114
115#elif defined(_XBOX)
116struct hostent *gethostbyname(const char *name)
117{
118 static struct in_addr addr = {0};
119 static struct hostent he = {0};
120 WSAEVENT event;
121 XNDNS *dns = NULL;
122 struct hostent *ret = NULL;
123
124 if (!name)
125 return NULL;
126
127 event = WSACreateEvent();
128
129 XNetDnsLookup(name, event, &dns);
130 if (!dns)
131 goto done;
132
133 WaitForSingleObject((HANDLE)event, INFINITE);
134
135 if (dns->iStatus)
136 goto done;
137
138 memcpy(&addr, dns->aina, sizeof(addr));
139
140 he.h_name = NULL;
141 he.h_aliases = NULL;
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;
146
147 ret = &he;
148
149done:
150 WSACloseEvent(event);
151 if (dns)
152 XNetDnsRelease(dns);
153
154 return ret;
155}
156
157#elif defined(VITA)
158#define COMPAT_NET_INIT_SIZE 0x80000
159
160char *inet_ntoa(struct in_addr in)
161{
162 static char ip_addr[16];
163
164 sceNetInetNtop(AF_INET, &in, ip_addr, sizeof(ip_addr));
165
166 return ip_addr;
167}
168
169int inet_aton(const char *cp, struct in_addr *inp)
170{
171 return sceNetInetPton(AF_INET, cp, inp);
172}
173
174uint32_t inet_addr(const char *cp)
175{
176 struct in_addr in;
177
178 return (sceNetInetPton(AF_INET, cp, &in) == 1) ? in.s_addr : INADDR_NONE;
179}
180
181struct hostent *gethostbyname(const char *name)
182{
183 static struct SceNetInAddr addr = {0};
184 static struct hostent he = {0};
185 int rid;
186 struct hostent *ret = NULL;
187
188 if (!name)
189 return NULL;
190
191 rid = sceNetResolverCreate("resolver", NULL, 0);
192 if (rid < 0)
193 return NULL;
194
195 if (sceNetResolverStartNtoa(rid, name, &addr, 0, 0, 0) < 0)
196 goto done;
197
198 he.h_name = NULL;
199 he.h_aliases = NULL;
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;
204
205 ret = &he;
206
207done:
208 sceNetResolverDestroy(rid);
209
210 return ret;
211}
212
213#elif defined(GEKKO)
214const char *inet_ntop(int af, const void *src, char *dst, socklen_t size)
215{
216 const char *addr_str = inet_ntoa(*(struct in_addr*)src);
217
218 if (addr_str)
219 {
220 strlcpy(dst, addr_str, size);
221
222 return dst;
223 }
224
225 return NULL;
226}
227
228int inet_pton(int af, const char *src, void *dst)
229{
230 if (inet_aton(src, (struct in_addr*)dst))
231 return 1;
232
233 return 0;
234}
235
236#elif defined(WIIU)
237#include <malloc.h>
238
239static int _net_compat_thread_entry(int argc, const char **argv)
240{
241 void *buf = memalign(128, WIIU_RCVBUF + WIIU_SNDBUF);
242
243 if (!buf)
244 return -1;
245
246 somemopt(1, buf, WIIU_RCVBUF + WIIU_SNDBUF, 0);
247
248 free(buf);
249
250 return 0;
251}
252
253static void _net_compat_thread_cleanup(OSThread *thread, void *stack)
254{
255 free(stack);
256}
257
258#elif defined(_3DS)
259#include <malloc.h>
260#include <3ds/types.h>
261#include <3ds/services/soc.h>
262
263#define SOC_ALIGN 0x1000
264#define SOC_BUFFERSIZE 0x100000
265#endif
266
267int getaddrinfo_retro(const char *node, const char *service,
268 struct addrinfo *hints, struct addrinfo **res)
269{
270#if defined(HAVE_SOCKET_LEGACY) || defined(WIIU)
271 struct addrinfo default_hints = {0};
272
273 if (!hints)
274 hints = &default_hints;
275 if (!hints->ai_family)
276 hints->ai_family = AF_INET;
277
278 if (!node)
279 node = (hints->ai_flags & AI_PASSIVE) ? "0.0.0.0" : "127.0.0.1";
280#endif
281
282#ifdef HAVE_SOCKET_LEGACY
283 {
284 struct addrinfo *info = (struct addrinfo*)calloc(1, sizeof(*info));
285 struct sockaddr_in *addr = (struct sockaddr_in*)malloc(sizeof(*addr));
286
287 if (!info || !addr)
288 goto failure;
289
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. */
296
297 addr->sin_family = AF_INET;
298
299 if (service)
300 {
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);
304
305 if (service_end == service || *service_end)
306 goto failure;
307
308 addr->sin_port = htons(port);
309 }
310
311 if (hints->ai_flags & AI_NUMERICHOST)
312 {
313 if (!inet_aton(node, &addr->sin_addr))
314 goto failure;
315 }
316 else
317 {
318 struct hostent *host = gethostbyname(node);
319
320 if (!host || !host->h_addr)
321 goto failure;
322
323 memcpy(&addr->sin_addr, host->h_addr, sizeof(addr->sin_addr));
324 }
325
326 *res = info;
327
328 return 0;
329
330failure:
331 free(addr);
332 free(info);
333
334 return -1;
335 }
336#else
337 return getaddrinfo(node, service, hints, res);
338#endif
339}
340
341void freeaddrinfo_retro(struct addrinfo *res)
342{
343#ifdef HAVE_SOCKET_LEGACY
344 if (res)
345 {
346 free(res->ai_addr);
347 free(res);
348 }
349#else
350 freeaddrinfo(res);
351#endif
352}
353
354int getnameinfo_retro(const struct sockaddr *addr, socklen_t addrlen,
355 char *host, socklen_t hostlen, char *serv, socklen_t servlen, int flags)
356{
357#ifdef HAVE_SOCKET_LEGACY
358 const struct sockaddr_in *addr4 = (const struct sockaddr_in*)addr;
359
360 /* We cannot perform reverse DNS lookups here; ignore the following flags:
361 NI_NAMEREQD
362 NI_NOFQDN
363 NI_NUMERICHOST (always enforced)
364 */
365 if (host && hostlen)
366 {
367 const char *_host = inet_ntoa(addr4->sin_addr);
368
369 if (!_host)
370 return -1;
371
372 strlcpy(host, _host, hostlen);
373 }
374
375 /* We cannot get service names here; ignore the following flags:
376 NI_DGRAM
377 NI_NUMERICSERV (always enforced)
378 */
379 if (serv && servlen)
380 snprintf(serv, servlen, "%hu", (unsigned short)ntohs(addr4->sin_port));
381
382 return 0;
383#else
384 return getnameinfo(addr, addrlen, host, hostlen, serv, servlen, flags);
385#endif
386}
387
388bool addr_6to4(struct sockaddr_storage *addr)
389{
390#ifdef HAVE_INET6
391 /* ::ffff:a.b.c.d */
392 static const uint16_t preffix[] = {0,0,0,0,0,0xffff};
393 uint32_t address;
394 uint16_t port;
395 struct sockaddr_in6 *addr6 = (struct sockaddr_in6*)addr;
396 struct sockaddr_in *addr4 = (struct sockaddr_in*)addr;
397
398 switch (addr->ss_family)
399 {
400 case AF_INET:
401 /* No need to convert. */
402 return true;
403 case AF_INET6:
404 /* Is the address provided an IPv4? */
405 if (!memcmp(&addr6->sin6_addr, preffix, sizeof(preffix)))
406 break;
407 default:
408 /* We don't know how to handle this. */
409 return false;
410 }
411
412 memcpy(&address, ((uint8_t*)&addr6->sin6_addr) + sizeof(preffix),
413 sizeof(address));
414 port = addr6->sin6_port;
415
416 memset(addr, 0, sizeof(*addr));
417
418 addr4->sin_family = AF_INET;
419 addr4->sin_port = port;
420 memcpy(&addr4->sin_addr, &address, sizeof(addr4->sin_addr));
421#endif
422
423 return true;
424}
425
426bool ipv4_is_lan_address(const struct sockaddr_in *addr)
427{
428 static const uint32_t subnets[] = {0x0A000000, 0xAC100000, 0xC0A80000};
429 static const uint32_t masks[] = {0xFF000000, 0xFFF00000, 0xFFFF0000};
430 size_t i;
431 uint32_t uaddr;
432
433 memcpy(&uaddr, &addr->sin_addr, sizeof(uaddr));
434 uaddr = ntohl(uaddr);
435
436 for (i = 0; i < ARRAY_SIZE(subnets); i++)
437 if ((uaddr & masks[i]) == subnets[i])
438 return true;
439
440 return false;
441}
442
443bool ipv4_is_cgnat_address(const struct sockaddr_in *addr)
444{
445 static const uint32_t subnet = 0x64400000;
446 static const uint32_t mask = 0xFFC00000;
447 uint32_t uaddr;
448
449 memcpy(&uaddr, &addr->sin_addr, sizeof(uaddr));
450 uaddr = ntohl(uaddr);
451
452 return (uaddr & mask) == subnet;
453}
454
455/**
456 * network_init:
457 *
458 * Platform specific socket library initialization.
459 *
460 * @return true if successful, otherwise false.
461 **/
462bool network_init(void)
463{
464#if defined(_WIN32)
465 static bool initialized = false;
466
467 if (!initialized)
468 {
469 WSADATA wsaData;
470
471 if (WSAStartup(MAKEWORD(2, 2), &wsaData))
472 {
473 WSACleanup();
474
475 return false;
476 }
477
478 initialized = true;
479 }
480
481 return true;
482#elif defined(__PSL1GHT__) || defined(__PS3__)
483 static bool initialized = false;
484
485 if (!initialized)
486 {
487 int tries;
488
489 sysModuleLoad(SYSMODULE_NET);
490
491 netInitialize();
492 if (netCtlInit() < 0)
493 goto failure;
494
495 for (tries = 10;;)
496 {
497 int state;
498
499 if (netCtlGetState(&state) < 0)
500 goto failure;
501 if (state == NET_CTL_STATE_IPObtained)
502 break;
503
504 if (!(--tries))
505 goto failure;
506
507 retro_sleep(500);
508 }
509
510 initialized = true;
511 }
512
513 return true;
514
515failure:
516 netCtlTerm();
517 netFinalizeNetwork();
518
519 sysModuleUnload(SYSMODULE_NET);
520
521 return false;
522#elif defined(VITA)
523 if (sceNetShowNetstat() == SCE_NET_ERROR_ENOTINIT)
524 {
525 SceNetInitParam param;
526 void *net_compat_memory = malloc(COMPAT_NET_INIT_SIZE);
527
528 if (!net_compat_memory)
529 return false;
530
531 param.memory = net_compat_memory;
532 param.size = COMPAT_NET_INIT_SIZE;
533 param.flags = 0;
534
535 if (sceNetInit(&param) < 0)
536 goto failure;
537 if (sceNetCtlInit() < 0)
538 goto failure;
539
540 return true;
541
542failure:
543 sceNetCtlTerm();
544 sceNetTerm();
545
546 free(net_compat_memory);
547
548 return false;
549 }
550
551 return true;
552#elif defined(GEKKO)
553 static bool initialized = false;
554
555 if (!initialized)
556 {
557 char localip[16] = {0};
558 char netmask[16] = {0};
559 char gateway[16] = {0};
560
561 if (if_config(localip, netmask, gateway, true, 10) < 0)
562 {
563 net_deinit();
564
565 return false;
566 }
567
568 initialized = true;
569 }
570
571 return true;
572#elif defined(WIIU)
573 static OSThread net_compat_thread;
574 static bool initialized = false;
575
576 if (!initialized)
577 {
578 void *stack = malloc(0x1000);
579
580 if (!stack)
581 return false;
582
583 socket_lib_init();
584
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))
588 {
589 free(stack);
590
591 return false;
592 }
593
594 OSSetThreadName(&net_compat_thread, "Network compat thread");
595 OSSetThreadDeallocator(&net_compat_thread, _net_compat_thread_cleanup);
596 OSResumeThread(&net_compat_thread);
597
598 initialized = true;
599 }
600
601 return true;
602#elif defined(_3DS)
603 static bool initialized = false;
604
605 if (!initialized)
606 {
607 u32 *net_compat_memory = (u32*)memalign(SOC_ALIGN, SOC_BUFFERSIZE);
608
609 if (!net_compat_memory)
610 return false;
611
612 /* WIFI init */
613 if (socInit(net_compat_memory, SOC_BUFFERSIZE))
614 {
615 socExit();
616
617 free(net_compat_memory);
618
619 return false;
620 }
621
622 initialized = true;
623 }
624
625 return true;
626#else
627 static bool initialized = false;
628
629 if (!initialized)
630 {
631 /* Do not like SIGPIPE killing our app. */
632 signal(SIGPIPE, SIG_IGN);
633
634 initialized = true;
635 }
636
637 return true;
638#endif
639}