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