1 /* Copyright  (C) 2010-2020 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 <stdio.h>
24 #include <stdint.h>
25 #include <stdlib.h>
26 #include <sys/types.h>
27 #include <stdlib.h>
28 #include <ctype.h>
29 #include <string.h>
30 
31 #include <net/net_compat.h>
32 #include <net/net_socket.h>
33 #include <retro_timers.h>
34 #include <compat/strl.h>
35 
36 #if defined(_XBOX)
37 /* TODO - implement h_length and h_addrtype */
38 struct hostent
39 {
40    int h_addrtype;     /* host address type   */
41    int h_length;       /* length of addresses */
42    char **h_addr_list; /* list of addresses   */
43 };
44 
gethostbyname(const char * name)45 struct hostent *gethostbyname(const char *name)
46 {
47    WSAEVENT event;
48    static struct hostent he;
49    static struct in_addr addr;
50    static char *addr_ptr      = NULL;
51    XNDNS *dns                 = NULL;
52 
53    he.h_addr_list             = &addr_ptr;
54    addr_ptr                   = (char*)&addr;
55 
56    if (!name)
57       return NULL;
58 
59    event = WSACreateEvent();
60    XNetDnsLookup(name, event, &dns);
61    if (!dns)
62       goto error;
63 
64    WaitForSingleObject((HANDLE)event, INFINITE);
65    if (dns->iStatus)
66       goto error;
67 
68    memcpy(&addr, dns->aina, sizeof(addr));
69 
70    WSACloseEvent(event);
71    XNetDnsRelease(dns);
72 
73    return &he;
74 
75 error:
76    if (event)
77       WSACloseEvent(event);
78    return NULL;
79 }
80 #elif defined(VITA)
81 static void *_net_compat_net_memory = NULL;
82 #define COMPAT_NET_INIT_SIZE 512*1024
83 #define INET_ADDRSTRLEN sizeof(struct sockaddr_in)
84 #define MAX_NAME 512
85 
86 typedef uint32_t in_addr_t;
87 
88 struct in_addr
89 {
90    in_addr_t s_addr;
91 };
92 
inet_ntoa(struct SceNetInAddr in)93 char *inet_ntoa(struct SceNetInAddr in)
94 {
95 	static char ip_addr[INET_ADDRSTRLEN + 1];
96 
97    if (!inet_ntop_compat(AF_INET, &in, ip_addr, INET_ADDRSTRLEN))
98 		strlcpy(ip_addr, "Invalid", sizeof(ip_addr));
99 
100 	return ip_addr;
101 }
102 
inet_aton(const char * ip_addr)103 struct SceNetInAddr inet_aton(const char *ip_addr)
104 {
105    SceNetInAddr inaddr;
106 
107    inet_ptrton(AF_INET, ip_addr, &inaddr);
108    return inaddr;
109 }
110 
inet_addr(const char * cp)111 unsigned int inet_addr(const char *cp)
112 {
113    return inet_aton(cp).s_addr;
114 }
115 
gethostbyname(const char * name)116 struct hostent *gethostbyname(const char *name)
117 {
118    int err;
119    static struct hostent ent;
120    static char sname[MAX_NAME]      = {0};
121    static struct SceNetInAddr saddr = {0};
122    static char *addrlist[2]         = {(char *) &saddr, NULL };
123    int rid = sceNetResolverCreate("resolver", NULL, 0);
124 
125    if(rid < 0)
126       return NULL;
127 
128    err = sceNetResolverStartNtoa(rid, name, &saddr, 0,0,0);
129    sceNetResolverDestroy(rid);
130    if(err < 0)
131       return NULL;
132 
133    addrlist[0]     = inet_ntoa(saddr);
134    ent.h_name      = sname;
135    ent.h_aliases   = 0;
136    ent.h_addrtype  = AF_INET;
137    ent.h_length    = sizeof(struct in_addr);
138    ent.h_addr_list = addrlist;
139    ent.h_addr      = addrlist[0];
140 
141    return &ent;
142 }
143 
144 int retro_epoll_fd;
145 #elif defined(_3DS)
146 #include <malloc.h>
147 #include <3ds/types.h>
148 #include <3ds/services/soc.h>
149 #define SOC_ALIGN       0x1000
150 #define SOC_BUFFERSIZE  0x100000
151 static u32* _net_compat_net_memory;
152 #endif
153 
154 #if defined(_WIN32)
inet_aton(const char * cp,struct in_addr * inp)155 int inet_aton(const char *cp, struct in_addr *inp)
156 {
157 	uint32_t addr = 0;
158 #ifndef _XBOX
159 	if (cp == 0 || inp == 0)
160 		return -1;
161 #endif
162 
163 	addr = inet_addr(cp);
164 	if (addr == INADDR_NONE || addr == INADDR_ANY)
165 		return -1;
166 
167 	inp->s_addr = addr;
168    return 1;
169 }
170 #endif
171 
getaddrinfo_retro(const char * node,const char * service,struct addrinfo * hints,struct addrinfo ** res)172 int getaddrinfo_retro(const char *node, const char *service,
173       struct addrinfo *hints, struct addrinfo **res)
174 {
175    struct sockaddr_in *in_addr = NULL;
176    struct addrinfo *info       = NULL;
177 
178    (void)in_addr;
179    (void)info;
180 
181    if (!hints->ai_family)
182    {
183 #if defined(_WIN32) || defined(HAVE_SOCKET_LEGACY) || defined(WIIU)
184       hints->ai_family    = AF_INET;
185 #else
186       hints->ai_family    = AF_UNSPEC;
187 #endif
188    }
189 
190 #if defined(WIIU)
191    if (!node)
192    {
193       /* Wii U's socket library chokes on NULL node */
194       if (hints->ai_flags & AI_PASSIVE)
195          node = "0.0.0.0";
196       else
197          node = "127.0.0.1";
198    }
199 #endif
200 
201 #ifdef HAVE_SOCKET_LEGACY
202    info = (struct addrinfo*)calloc(1, sizeof(*info));
203    if (!info)
204       goto error;
205 
206    info->ai_family     = AF_INET;
207    info->ai_socktype   = hints->ai_socktype;
208    in_addr             = (struct sockaddr_in*)
209       calloc(1, sizeof(*in_addr));
210 
211    if (!in_addr)
212       goto error;
213 
214    info->ai_addrlen    = sizeof(*in_addr);
215    in_addr->sin_family = AF_INET;
216    in_addr->sin_port   = inet_htons(strtoul(service, NULL, 0));
217 
218    if (!node && (hints->ai_flags & AI_PASSIVE))
219       in_addr->sin_addr.s_addr = INADDR_ANY;
220    else if (node && isdigit((unsigned char)*node))
221       in_addr->sin_addr.s_addr = inet_addr(node);
222    else if (node && !isdigit((unsigned char)*node))
223    {
224       struct hostent *host = (struct hostent*)gethostbyname(node);
225 
226       if (!host || !host->h_addr_list[0])
227          goto error;
228 
229       in_addr->sin_family = host->h_addrtype;
230 
231 #if defined(AF_INET6) && !defined(__PS3__) || defined(VITA)
232       /* TODO/FIXME - In case we ever want to support IPv6 */
233       in_addr->sin_addr.s_addr = inet_addr(host->h_addr_list[0]);
234 #else
235       memcpy(&in_addr->sin_addr, host->h_addr, host->h_length);
236 #endif
237    }
238    else
239       goto error;
240 
241    info->ai_addr = (struct sockaddr*)in_addr;
242    *res          = info;
243 
244    return 0;
245 
246 error:
247    if (in_addr)
248       free(in_addr);
249    if (info)
250       free(info);
251    return -1;
252 #else
253    return getaddrinfo(node, service, hints, res);
254 #endif
255 }
256 
freeaddrinfo_retro(struct addrinfo * res)257 void freeaddrinfo_retro(struct addrinfo *res)
258 {
259 #ifdef HAVE_SOCKET_LEGACY
260    free(res->ai_addr);
261    free(res);
262 #else
263    freeaddrinfo(res);
264 #endif
265 }
266 
267 #if defined(WIIU)
268 #include <malloc.h>
269 
270 static OSThread wiiu_net_cmpt_thread;
wiiu_net_cmpt_thread_cleanup(OSThread * thread,void * stack)271 static void wiiu_net_cmpt_thread_cleanup(OSThread *thread, void *stack) {
272    free(stack);
273 }
wiiu_net_cmpt_thread_entry(int argc,const char ** argv)274 static int wiiu_net_cmpt_thread_entry(int argc, const char** argv) {
275    const int buf_size = WIIU_RCVBUF + WIIU_SNDBUF;
276    void* buf = memalign(128, buf_size);
277    if (!buf) return -1;
278 
279    somemopt(1, buf, buf_size, 0);
280 
281    free(buf);
282    return 0;
283 }
284 #endif
285 
286 /**
287  * network_init:
288  *
289  * Platform specific socket library initialization.
290  *
291  * Returns: true (1) if successful, otherwise false (0).
292  **/
network_init(void)293 bool network_init(void)
294 {
295 #ifdef _WIN32
296    WSADATA wsaData;
297 #endif
298    static bool inited = false;
299    if (inited)
300       return true;
301 
302 #if defined(_WIN32)
303    if (WSAStartup(MAKEWORD(2, 2), &wsaData) != 0)
304    {
305       network_deinit();
306       return false;
307    }
308 #elif defined(__PSL1GHT__) || defined(__PS3__)
309    int timeout_count = 10;
310 
311    sysModuleLoad(SYSMODULE_NET);
312    netInitialize();
313 
314    if (netCtlInit() < 0)
315       return false;
316 
317    for (;;)
318    {
319       int state;
320       if (netCtlGetState(&state) < 0)
321          return false;
322 
323       if (state == NET_CTL_STATE_IPObtained)
324          break;
325 
326       retro_sleep(500);
327       timeout_count--;
328       if (timeout_count < 0)
329          return 0;
330    }
331 #elif defined(VITA)
332    SceNetInitParam initparam;
333 
334    if (sceNetShowNetstat() == SCE_NET_ERROR_ENOTINIT)
335    {
336       _net_compat_net_memory = malloc(COMPAT_NET_INIT_SIZE);
337 
338       initparam.memory       = _net_compat_net_memory;
339       initparam.size         = COMPAT_NET_INIT_SIZE;
340       initparam.flags        = 0;
341 
342       sceNetInit(&initparam);
343 
344       sceNetCtlInit();
345    }
346 
347    retro_epoll_fd = sceNetEpollCreate("epoll", 0);
348 #elif defined(GEKKO)
349    char t[16];
350    if (if_config(t, NULL, NULL, TRUE, 10) < 0)
351       return false;
352 #elif defined(WIIU)
353    socket_lib_init();
354 
355    const int stack_size = 4096;
356    void* stack = malloc(stack_size);
357    if (stack && OSCreateThread(&wiiu_net_cmpt_thread,
358       wiiu_net_cmpt_thread_entry, 0, NULL, stack+stack_size, stack_size,
359       3, OS_THREAD_ATTRIB_AFFINITY_ANY)) {
360 
361       OSSetThreadName(&wiiu_net_cmpt_thread, "Network compat thread");
362       OSSetThreadDeallocator(&wiiu_net_cmpt_thread,
363          wiiu_net_cmpt_thread_cleanup);
364       OSResumeThread(&wiiu_net_cmpt_thread);
365    }
366 #elif defined(_3DS)
367     _net_compat_net_memory = (u32*)memalign(SOC_ALIGN, SOC_BUFFERSIZE);
368 	if (!_net_compat_net_memory)
369 		return false;
370 	Result ret = socInit(_net_compat_net_memory, SOC_BUFFERSIZE);//WIFI init
371 	if (ret != 0)
372 		return false;
373 #else
374    signal(SIGPIPE, SIG_IGN); /* Do not like SIGPIPE killing our app. */
375 #endif
376 
377    inited = true;
378    return true;
379 }
380 
381 /**
382  * network_deinit:
383  *
384  * Deinitialize platform specific socket libraries.
385  **/
network_deinit(void)386 void network_deinit(void)
387 {
388 #if defined(_WIN32)
389    WSACleanup();
390 #elif defined(__PSL1GHT__) || defined(__PS3__)
391    netCtlTerm();
392    netFinalizeNetwork();
393    sysModuleUnload(SYSMODULE_NET);
394 #elif defined(VITA)
395    sceNetCtlTerm();
396    sceNetTerm();
397 
398    if (_net_compat_net_memory)
399    {
400       free(_net_compat_net_memory);
401       _net_compat_net_memory = NULL;
402    }
403 #elif defined(GEKKO) && !defined(HW_DOL)
404    net_deinit();
405 #elif defined(_3DS)
406    socExit();
407 
408    if(_net_compat_net_memory)
409    {
410 	  free(_net_compat_net_memory);
411 	  _net_compat_net_memory = NULL;
412    }
413 #endif
414 }
415 
inet_htons(uint16_t hostshort)416 uint16_t inet_htons(uint16_t hostshort)
417 {
418 #if defined(VITA) || defined(__ORBIS__)
419    return sceNetHtons(hostshort);
420 #else
421    return htons(hostshort);
422 #endif
423 }
424 
425 
inet_ptrton(int af,const char * src,void * dst)426 int inet_ptrton(int af, const char *src, void *dst)
427 {
428 #if defined(VITA) || defined(__ORBIS__)
429    return sceNetInetPton(af, src, dst);
430 #elif defined(GEKKO) || defined(_WIN32)
431    /* TODO/FIXME - should use InetPton on Vista and later */
432    return inet_aton(src, (struct in_addr*)dst);
433 #else
434    return inet_pton(af, src, dst);
435 #endif
436 }
437 
438 struct in_addr6_compat
439 {
440    unsigned char ip_addr[16];
441 };
442 
443 #ifdef _XBOX
444 
445 #ifndef IM_IN6ADDRSZ
446 #define	IM_IN6ADDRSZ	16
447 #endif
448 
449 #ifndef IM_INT16SZ
450 #define	IM_INT16SZ		2
451 #endif
452 
453 #ifndef IM_INADDRSZ
454 #define	IM_INADDRSZ		4
455 #endif
456 /* Taken from https://github.com/skywind3000/easenet/blob/master/inetbase.c
457  */
458 
459 /* convert presentation format to network format */
460 static const char *
inet_ntop4x(const unsigned char * src,char * dst,size_t size)461 inet_ntop4x(const unsigned char *src, char *dst, size_t size)
462 {
463    char tmp[64];
464    size_t len = snprintf(tmp,
465          sizeof(tmp),
466          "%u.%u.%u.%u", src[0], src[1], src[2], src[3]);
467 
468    if (len >= size)
469       goto error;
470 
471    memcpy(dst, tmp, len + 1);
472    return dst;
473 
474 error:
475    errno = ENOSPC;
476    return NULL;
477 }
478 
479 /* convert presentation format to network format */
480 static const char *
inet_ntop6x(const unsigned char * src,char * dst,size_t size)481 inet_ntop6x(const unsigned char *src, char *dst, size_t size)
482 {
483    char tmp[64], *tp;
484    int i, inc;
485    struct { int base, len; } best, cur;
486    unsigned int words[IM_IN6ADDRSZ / IM_INT16SZ];
487 
488    memset(words, '\0', sizeof(words));
489    best.base = best.len = 0;
490    cur.base  = cur.len  = 0;
491 
492    for (i = 0; i < IM_IN6ADDRSZ; i++)
493       words[i / 2] |= (src[i] << ((1 - (i % 2)) << 3));
494 
495    best.base = -1;
496    cur.base  = -1;
497 
498    for (i = 0; i < (IM_IN6ADDRSZ / IM_INT16SZ); i++)
499    {
500       if (words[i] == 0)
501       {
502          if (cur.base == -1)
503          {
504             cur.base = i;
505             cur.len  = 1;
506          }
507          else cur.len++;
508       }
509       else
510       {
511          if (cur.base != -1)
512          {
513             if (best.base == -1 || cur.len > best.len)
514                best = cur;
515             cur.base = -1;
516          }
517       }
518    }
519    if (cur.base != -1)
520    {
521       if (best.base == -1 || cur.len > best.len)
522          best = cur;
523    }
524    if (best.base != -1 && best.len < 2)
525       best.base = -1;
526 
527    tp = tmp;
528    for (i = 0; i < (IM_IN6ADDRSZ / IM_INT16SZ); i++)
529    {
530       if (best.base != -1 && i >= best.base &&
531             i < (best.base + best.len))
532       {
533          if (i == best.base)
534             *tp++ = ':';
535          continue;
536       }
537 
538       if (i != 0)
539          *tp++ = ':';
540       if (i == 6 && best.base == 0 &&
541             (best.len == 6 || (best.len == 5 && words[5] == 0xffff)))
542       {
543          if (!inet_ntop4x(src+12, tp, sizeof(tmp) - (tp - tmp)))
544             return NULL;
545          tp += strlen(tp);
546          break;
547       }
548       inc = sprintf(tp, "%x", words[i]);
549       tp += inc;
550    }
551 
552    if (best.base != -1 && (best.base + best.len) ==
553          (IM_IN6ADDRSZ / IM_INT16SZ))
554       *tp++ = ':';
555 
556    *tp++ = '\0';
557 
558    if ((size_t)(tp - tmp) > size)
559       goto error;
560 
561    memcpy(dst, tmp, tp - tmp);
562    return dst;
563 
564 error:
565    errno = ENOSPC;
566    return NULL;
567 }
568 
569 /* convert network format to presentation format */
570 /* another inet_ntop, supports AF_INET/AF_INET6 */
isockaddr_ntop(int af,const void * src,char * dst,size_t size)571 static const char *isockaddr_ntop(int af,
572       const void *src, char *dst, size_t size)
573 {
574    switch (af)
575    {
576       case AF_INET:
577          return inet_ntop4x((const unsigned char*)src, dst, size);
578 #ifdef AF_INET6
579       case AF_INET6:
580          return inet_ntop6x((const unsigned char*)src, dst, size);
581 #endif
582       default:
583          if (af == -6)
584             return inet_ntop6x((const unsigned char*)src, dst, size);
585          errno = EAFNOSUPPORT;
586          return NULL;
587    }
588 }
589 #endif
590 
inet_ntop_compat(int af,const void * src,char * dst,socklen_t cnt)591 const char *inet_ntop_compat(int af, const void *src, char *dst, socklen_t cnt)
592 {
593 #if defined(VITA) || defined(__ORBIS__)
594    return sceNetInetNtop(af,src,dst,cnt);
595 #elif defined(WIIU)
596    return inet_ntop(af, src, dst, cnt);
597 #elif defined(_XBOX)
598    return isockaddr_ntop(af, src, dst, cnt);
599 #elif defined(_WIN32)
600    if (af == AF_INET)
601    {
602       struct sockaddr_in in;
603       memset(&in, 0, sizeof(in));
604       in.sin_family = AF_INET;
605       memcpy(&in.sin_addr, src, sizeof(struct in_addr));
606       getnameinfo((struct sockaddr *)&in, sizeof(struct
607                sockaddr_in), dst, cnt, NULL, 0, NI_NUMERICHOST);
608       return dst;
609    }
610 #if defined(AF_INET6) && !defined(HAVE_SOCKET_LEGACY)
611    else if (af == AF_INET6)
612    {
613       struct sockaddr_in6 in;
614       memset(&in, 0, sizeof(in));
615       in.sin6_family = AF_INET6;
616       memcpy(&in.sin6_addr, src, sizeof(struct in_addr6_compat));
617       getnameinfo((struct sockaddr *)&in, sizeof(struct
618                sockaddr_in6), dst, cnt, NULL, 0, NI_NUMERICHOST);
619       return dst;
620    }
621 #endif
622    else
623       return NULL;
624 #else
625    return inet_ntop(af, src, dst, cnt);
626 #endif
627 }
628 
udp_send_packet(const char * host,uint16_t port,const char * msg)629 bool udp_send_packet(const char *host,
630       uint16_t port, const char *msg)
631 {
632    char port_buf[16]           = {0};
633    struct addrinfo hints       = {0};
634    struct addrinfo *res        = NULL;
635    const struct addrinfo *tmp  = NULL;
636    int fd                      = -1;
637    bool ret                    = true;
638 
639    hints.ai_socktype           = SOCK_DGRAM;
640 
641    snprintf(port_buf, sizeof(port_buf), "%hu", (unsigned short)port);
642 
643    if (getaddrinfo_retro(host, port_buf, &hints, &res) != 0)
644       return false;
645 
646    /* Send to all possible targets.
647     * "localhost" might resolve to several different IPs. */
648    tmp = (const struct addrinfo*)res;
649    while (tmp)
650    {
651       ssize_t len, ret_len;
652 
653       fd = socket(tmp->ai_family, tmp->ai_socktype, tmp->ai_protocol);
654       if (fd < 0)
655       {
656          ret = false;
657          goto end;
658       }
659 
660       len     = strlen(msg);
661       ret_len = sendto(fd, msg, len, 0, tmp->ai_addr, tmp->ai_addrlen);
662 
663       if (ret_len < len)
664       {
665          ret = false;
666          goto end;
667       }
668 
669       socket_close(fd);
670       fd = -1;
671       tmp = tmp->ai_next;
672    }
673 
674 end:
675    freeaddrinfo_retro(res);
676    if (fd >= 0)
677       socket_close(fd);
678    return ret;
679 }
680