1 /* Copyright  (C) 2010-2018 The RetroArch team
2  *
3  * ---------------------------------------------------------------------------------------
4  * The following license statement only applies to this file (net_socket.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 
24 #include <stdio.h>
25 
26 #ifdef _MSC_VER
27 #include <compat/msvc.h>
28 #endif
29 
30 #include <net/net_compat.h>
31 #include <net/net_socket.h>
32 
socket_init(void ** address,uint16_t port,const char * server,enum socket_type type)33 int socket_init(void **address, uint16_t port, const char *server, enum socket_type type)
34 {
35    char port_buf[16];
36    struct addrinfo hints = {0};
37    struct addrinfo **addrinfo = (struct addrinfo**)address;
38    struct addrinfo *addr = NULL;
39 
40    if (!network_init())
41       goto error;
42 
43    switch (type)
44    {
45       case SOCKET_TYPE_DATAGRAM:
46          hints.ai_socktype = SOCK_DGRAM;
47          break;
48       case SOCKET_TYPE_STREAM:
49          hints.ai_socktype = SOCK_STREAM;
50          break;
51       case SOCKET_TYPE_SEQPACKET:
52          /* TODO/FIXME - implement? */
53          break;
54    }
55 
56    if (!server)
57       hints.ai_flags = AI_PASSIVE;
58 
59    port_buf[0] = '\0';
60 
61    snprintf(port_buf, sizeof(port_buf), "%hu", (unsigned short)port);
62 
63    if (getaddrinfo_retro(server, port_buf, &hints, addrinfo) != 0)
64       goto error;
65 
66    addr = (struct addrinfo*)*addrinfo;
67 
68    if (!addr)
69       goto error;
70 
71    return socket(addr->ai_family, addr->ai_socktype, addr->ai_protocol);
72 
73 error:
74    return -1;
75 }
76 
socket_next(void ** addrinfo)77 int socket_next(void **addrinfo)
78 {
79    struct addrinfo *addr = (struct addrinfo*)*addrinfo;
80    if ((*addrinfo = addr = addr->ai_next))
81       return socket(addr->ai_family, addr->ai_socktype, addr->ai_protocol);
82    else
83       return -1;
84 }
85 
socket_receive_all_nonblocking(int fd,bool * error,void * data_,size_t size)86 ssize_t socket_receive_all_nonblocking(int fd, bool *error,
87       void *data_, size_t size)
88 {
89    const uint8_t *data = (const uint8_t*)data_;
90    ssize_t         ret = recv(fd, (char*)data, size, 0);
91 
92    if (ret > 0)
93       return ret;
94 
95    if (ret == 0)
96    {
97       /* Socket closed */
98       *error = true;
99       return -1;
100    }
101 
102    if (isagain((int)ret))
103       return 0;
104 
105    *error = true;
106    return -1;
107 }
108 
socket_receive_all_blocking(int fd,void * data_,size_t size)109 int socket_receive_all_blocking(int fd, void *data_, size_t size)
110 {
111    const uint8_t *data = (const uint8_t*)data_;
112 
113    while (size)
114    {
115       ssize_t ret = recv(fd, (char*)data, size, 0);
116       if (ret <= 0)
117          return false;
118 
119       data += ret;
120       size -= ret;
121    }
122 
123    return true;
124 }
125 
socket_nonblock(int fd)126 bool socket_nonblock(int fd)
127 {
128 #if defined(VITA) || defined(WIIU)
129    int i = 1;
130    setsockopt(fd, SOL_SOCKET, SO_NBIO, &i, sizeof(int));
131    return true;
132 #elif defined(_WIN32)
133    u_long mode = 1;
134    return ioctlsocket(fd, FIONBIO, &mode) == 0;
135 #else
136    return fcntl(fd, F_SETFL, fcntl(fd, F_GETFL) | O_NONBLOCK) == 0;
137 #endif
138 }
139 
socket_close(int fd)140 int socket_close(int fd)
141 {
142 #if defined(_WIN32) && !defined(_XBOX360)
143    /* WinSock has headers from the stone age. */
144    return closesocket(fd);
145 #elif defined(WIIU)
146    return socketclose(fd);
147 #elif defined(VITA)
148    return sceNetSocketClose(fd);
149 #else
150    return close(fd);
151 #endif
152 }
153 
socket_select(int nfds,fd_set * readfs,fd_set * writefds,fd_set * errorfds,struct timeval * timeout)154 int socket_select(int nfds, fd_set *readfs, fd_set *writefds,
155       fd_set *errorfds, struct timeval *timeout)
156 {
157 #if defined(VITA)
158    extern int retro_epoll_fd;
159    SceNetEpollEvent ev = {0};
160 
161    ev.events = SCE_NET_EPOLLIN | SCE_NET_EPOLLHUP;
162    ev.data.fd = nfds;
163 
164    if((sceNetEpollControl(retro_epoll_fd, SCE_NET_EPOLL_CTL_ADD, nfds, &ev)))
165    {
166       int ret = sceNetEpollWait(retro_epoll_fd, &ev, 1, 0);
167       sceNetEpollControl(retro_epoll_fd, SCE_NET_EPOLL_CTL_DEL, nfds, NULL);
168       return ret;
169    }
170    return 0;
171 #else
172    return select(nfds, readfs, writefds, errorfds, timeout);
173 #endif
174 }
175 
socket_send_all_blocking(int fd,const void * data_,size_t size,bool no_signal)176 int socket_send_all_blocking(int fd, const void *data_, size_t size,
177       bool no_signal)
178 {
179    const uint8_t *data = (const uint8_t*)data_;
180 
181    while (size)
182    {
183       ssize_t ret = send(fd, (const char*)data, size,
184             no_signal ? MSG_NOSIGNAL : 0);
185       if (ret <= 0)
186       {
187          if (isagain((int)ret))
188             continue;
189 
190          return false;
191       }
192 
193       data += ret;
194       size -= ret;
195    }
196 
197    return true;
198 }
199 
socket_send_all_nonblocking(int fd,const void * data_,size_t size,bool no_signal)200 ssize_t socket_send_all_nonblocking(int fd, const void *data_, size_t size,
201       bool no_signal)
202 {
203    const uint8_t *data = (const uint8_t*)data_;
204    ssize_t sent = 0;
205 
206    while (size)
207    {
208       ssize_t ret = send(fd, (const char*)data, size,
209             no_signal ? MSG_NOSIGNAL : 0);
210       if (ret < 0)
211       {
212          if (isagain((int)ret))
213             break;
214 
215          return -1;
216       }
217       else if (ret == 0)
218          break;
219 
220       data += ret;
221       size -= ret;
222       sent += ret;
223    }
224 
225    return sent;
226 }
227 
socket_bind(int fd,void * data)228 bool socket_bind(int fd, void *data)
229 {
230    int yes               = 1;
231    struct addrinfo *res  = (struct addrinfo*)data;
232    setsockopt(fd, SOL_SOCKET,
233          SO_REUSEADDR, (const char*)&yes, sizeof(int));
234    if (bind(fd, res->ai_addr, res->ai_addrlen) < 0)
235       return false;
236    return true;
237 }
238 
socket_connect(int fd,void * data,bool timeout_enable)239 int socket_connect(int fd, void *data, bool timeout_enable)
240 {
241    struct addrinfo *addr = (struct addrinfo*)data;
242 
243 #if !defined(_WIN32) && !defined(VITA) && !defined(WIIU) && !defined(_3DS)
244    if (timeout_enable)
245    {
246       struct timeval timeout;
247       timeout.tv_sec  = 4;
248       timeout.tv_usec = 0;
249 
250       setsockopt(fd, SOL_SOCKET, SO_SNDTIMEO, (char*)&timeout, sizeof timeout);
251    }
252 #endif
253 
254    return connect(fd, addr->ai_addr, addr->ai_addrlen);
255 }
256 
domain_get(enum socket_domain type)257 static int domain_get(enum socket_domain type)
258 {
259    switch (type)
260    {
261       case SOCKET_DOMAIN_INET:
262 #ifdef VITA
263          return SCE_NET_AF_INET;
264 #else
265          return AF_INET;
266 #endif
267       default:
268          break;
269    }
270 
271    return 0;
272 }
273 
socket_create(const char * name,enum socket_domain domain_type,enum socket_type socket_type,enum socket_protocol protocol_type)274 int socket_create(
275       const char *name,
276       enum socket_domain   domain_type,
277       enum socket_type     socket_type,
278       enum socket_protocol protocol_type)
279 {
280    int type     = 0;
281    int protocol = 0;
282    int domain   = domain_get(domain_type);
283 #ifdef VITA
284 
285    switch (socket_type)
286    {
287       case SOCKET_TYPE_DATAGRAM:
288          type = SCE_NET_SOCK_DGRAM;
289          break;
290       case SOCKET_TYPE_STREAM:
291          type = SCE_NET_SOCK_STREAM;
292          break;
293       case SOCKET_TYPE_SEQPACKET:
294          /* TODO/FIXME - implement */
295          break;
296    }
297 
298    switch (protocol_type)
299    {
300       case SOCKET_PROTOCOL_NONE:
301          protocol = 0;
302          break;
303       case SOCKET_PROTOCOL_TCP:
304          protocol = SCE_NET_IPPROTO_TCP;
305          break;
306       case SOCKET_PROTOCOL_UDP:
307          protocol = SCE_NET_IPPROTO_UDP;
308          break;
309    }
310 
311    return sceNetSocket(name, domain, type, protocol);
312 #else
313    switch (socket_type)
314    {
315       case SOCKET_TYPE_DATAGRAM:
316          type = SOCK_DGRAM;
317          break;
318       case SOCKET_TYPE_STREAM:
319          type = SOCK_STREAM;
320          break;
321       case SOCKET_TYPE_SEQPACKET:
322          /* TODO/FIXME - implement */
323          break;
324    }
325 
326    switch (protocol_type)
327    {
328       case SOCKET_PROTOCOL_NONE:
329          protocol = 0;
330          break;
331       case SOCKET_PROTOCOL_TCP:
332          protocol = IPPROTO_TCP;
333          break;
334       case SOCKET_PROTOCOL_UDP:
335          protocol = IPPROTO_UDP;
336          break;
337    }
338 
339    return socket(domain, type, protocol);
340 #endif
341 }
342 
socket_set_target(void * data,socket_target_t * in_addr)343 void socket_set_target(void *data, socket_target_t *in_addr)
344 {
345    struct sockaddr_in *out_target = (struct sockaddr_in*)data;
346 
347    out_target->sin_port   = inet_htons(in_addr->port);
348    out_target->sin_family = domain_get(in_addr->domain);
349 #ifdef VITA
350    out_target->sin_addr   = inet_aton(in_addr->server);
351 #else
352 #ifdef GEKKO
353    out_target->sin_len    = 8;
354 #endif
355 
356    inet_ptrton(AF_INET, in_addr->server, &out_target->sin_addr);
357 
358 #endif
359 }
360