libretro: adjust psxclock description
[pcsx_rearmed.git] / deps / libretro-common / net / net_compat.c
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
34 const 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
62 int 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)
116 struct 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
149 done:
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
160 char *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
169 int inet_aton(const char *cp, struct in_addr *inp)
170 {
171    return sceNetInetPton(AF_INET, cp, inp);
172 }
173
174 uint32_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
181 struct 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
207 done:
208    sceNetResolverDestroy(rid);
209
210    return ret;
211 }
212
213 #elif defined(GEKKO)
214 const 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
228 int 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
239 static 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
253 static 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
267 int 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
330 failure:
331       free(addr);
332       free(info);
333
334       return -1;
335    }
336 #else
337    return getaddrinfo(node, service, hints, res);
338 #endif
339 }
340
341 void 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
354 int 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
388 bool 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
426 bool 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
443 bool 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  **/
462 bool 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
515 failure:
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
542 failure:
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 }