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