1 // Copyright 2016 The Fuchsia Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4 
5 #include <assert.h>
6 #include <errno.h>
7 #include <fcntl.h>
8 #include <netdb.h>
9 #include <poll.h>
10 #include <stdarg.h>
11 #include <stdlib.h>
12 #include <string.h>
13 #include <sys/socket.h>
14 #include <threads.h>
15 #include <unistd.h>
16 
17 #include <fuchsia/net/c/fidl.h>
18 #include <zircon/device/vfs.h>
19 #include <zircon/syscalls.h>
20 
21 #include <lib/fdio/debug.h>
22 #include <lib/fdio/io.h>
23 #include <lib/fdio/util.h>
24 #include <lib/zxs/zxs.h>
25 
26 #include "private.h"
27 #include "private-socket.h"
28 #include "unistd.h"
29 
get_service_handle(const char * path,zx_handle_t * saved,mtx_t * lock,zx_handle_t * out)30 static zx_status_t get_service_handle(const char* path, zx_handle_t* saved,
31                                       mtx_t* lock, zx_handle_t* out) {
32     zx_status_t r;
33     zx_handle_t h0, h1;
34     mtx_lock(lock);
35     if (*saved == ZX_HANDLE_INVALID) {
36         if ((r = zx_channel_create(0, &h0, &h1)) != ZX_OK) {
37             mtx_unlock(lock);
38             return r;
39         }
40         if ((r = fdio_service_connect(path, h1)) != ZX_OK) {
41             mtx_unlock(lock);
42             zx_handle_close(h0);
43             return r;
44         }
45         *saved = h0;
46     }
47     *out = *saved;
48     mtx_unlock(lock);
49     return ZX_OK;
50 }
51 
52 // This wrapper waits for the service to publish the service handle.
53 // TODO(ZX-1890): move to a better mechanism when available.
get_service_with_retries(const char * path,zx_handle_t * saved,mtx_t * lock,zx_handle_t * out)54 static zx_status_t get_service_with_retries(const char* path, zx_handle_t* saved,
55                                             mtx_t* lock, zx_handle_t* out) {
56     zx_status_t r;
57     unsigned retry = 0;
58     while ((r = get_service_handle(path, saved, lock, out)) == ZX_ERR_NOT_FOUND) {
59         if (retry >= 24) {
60             // 10-second timeout
61             return ZX_ERR_NOT_FOUND;
62         }
63         retry++;
64         zx_nanosleep(zx_deadline_after((retry < 8) ? ZX_MSEC(250) : ZX_MSEC(500)));
65     }
66     return r;
67 }
68 
get_socket_provider(zx_handle_t * out)69 static zx_status_t get_socket_provider(zx_handle_t* out) {
70     static zx_handle_t saved = ZX_HANDLE_INVALID;
71     static mtx_t lock = MTX_INIT;
72     return get_service_with_retries("/svc/fuchsia.net.LegacySocketProvider", &saved, &lock, out);
73 }
74 
75 __EXPORT
socket(int domain,int type,int protocol)76 int socket(int domain, int type, int protocol) {
77     fdio_t* io = NULL;
78 
79     zx_handle_t socket_provider;
80     zx_status_t status = get_socket_provider(&socket_provider);
81     if (status != ZX_OK) {
82         return ERRNO(EIO);
83     }
84 
85     zxs_socket_t socket = {};
86     status = zxs_socket(socket_provider, domain,
87                         type & ~(SOCK_NONBLOCK | SOCK_CLOEXEC), protocol, NULL,
88                         0u, &socket);
89     if (status != ZX_OK) {
90         return STATUS(status);
91     }
92 
93     if (socket.flags & ZXS_FLAG_DATAGRAM) {
94         io = fdio_socket_create_datagram(socket.socket, 0);
95     } else {
96         io = fdio_socket_create_stream(socket.socket, 0);
97     }
98 
99     if (io == NULL) {
100         return ERRNO(EIO);
101     }
102 
103     if (type & SOCK_NONBLOCK) {
104         io->ioflag |= IOFLAG_NONBLOCK;
105     }
106 
107     // TODO(ZX-973): Implement CLOEXEC.
108     // if (type & SOCK_CLOEXEC) {
109     // }
110 
111     int fd;
112     if ((fd = fdio_bind_to_fd(io, -1, 0)) < 0) {
113         io->ops->close(io);
114         fdio_release(io);
115         return ERRNO(EMFILE);
116     }
117     return fd;
118 }
119 
120 __EXPORT
connect(int fd,const struct sockaddr * addr,socklen_t len)121 int connect(int fd, const struct sockaddr* addr, socklen_t len) {
122     const zxs_socket_t* socket = NULL;
123     fdio_t* io = fd_to_socket(fd, &socket);
124     if (io == NULL) {
125         return ERRNO(EBADF);
126     }
127 
128     zx_status_t status = zxs_connect(socket, addr, len);
129     if (status == ZX_ERR_SHOULD_WAIT) {
130         io->ioflag |= IOFLAG_SOCKET_CONNECTING;
131         fdio_release(io);
132         return ERRNO(EINPROGRESS);
133     } else if (status == ZX_OK) {
134         io->ioflag |= IOFLAG_SOCKET_CONNECTED;
135     }
136     fdio_release(io);
137     return STATUS(status);
138 }
139 
140 __EXPORT
bind(int fd,const struct sockaddr * addr,socklen_t len)141 int bind(int fd, const struct sockaddr* addr, socklen_t len) {
142     const zxs_socket_t* socket;
143     fdio_t* io = fd_to_socket(fd, &socket);
144     if (io == NULL) {
145         return ERRNO(EBADF);
146     }
147 
148     zx_status_t status = zxs_bind(socket, addr, len);
149     fdio_release(io);
150     return STATUS(status);
151 }
152 
153 __EXPORT
listen(int fd,int backlog)154 int listen(int fd, int backlog) {
155     const zxs_socket_t* socket;
156     fdio_t* io = fd_to_socket(fd, &socket);
157     if (io == NULL) {
158         return ERRNO(EBADF);
159     }
160 
161     zx_status_t status = zxs_listen(socket, backlog);
162 
163     if (status == ZX_OK) {
164         zxsio_t* sio = (zxsio_t*)io;
165         sio->flags |= ZXSIO_DID_LISTEN;
166     }
167 
168     fdio_release(io);
169     return STATUS(status);
170 }
171 
172 __EXPORT
accept4(int fd,struct sockaddr * restrict addr,socklen_t * restrict len,int flags)173 int accept4(int fd, struct sockaddr* restrict addr, socklen_t* restrict len,
174             int flags) {
175     if (flags & ~SOCK_NONBLOCK) {
176         return ERRNO(EINVAL);
177     }
178 
179     const zxs_socket_t* socket = NULL;
180     fdio_t* io = fd_to_socket(fd, &socket);
181     if (io == NULL) {
182         return ERRNO(EBADF);
183     }
184 
185     zxsio_t* sio = (zxsio_t*)io;
186     if (!(sio->flags & ZXSIO_DID_LISTEN)) {
187         fdio_release(io);
188         return ERROR(ZX_ERR_BAD_STATE);
189     }
190 
191     int nfd = fdio_reserve_fd(0);
192     if (nfd < 0) {
193         return nfd;
194     }
195 
196     size_t actual = 0u;
197     zxs_socket_t accepted;
198     memset(&accepted, 0, sizeof(accepted));
199     zx_status_t status = zxs_accept(socket, addr, len ? *len : 0u, &actual, &accepted);
200     fdio_release(io);
201     if (status == ZX_ERR_SHOULD_WAIT) {
202         fdio_release_reserved(nfd);
203         return ERRNO(EWOULDBLOCK);
204     } else if (status != ZX_OK) {
205         fdio_release_reserved(nfd);
206         return ERROR(status);
207     }
208 
209     fdio_t* io2 = NULL;
210     if ((io2 = fdio_socket_create_stream(accepted.socket, IOFLAG_SOCKET_CONNECTED)) == NULL) {
211         fdio_release_reserved(nfd);
212         return ERROR(ZX_ERR_NO_RESOURCES);
213     }
214 
215     if (flags & SOCK_NONBLOCK) {
216         io2->ioflag |= IOFLAG_NONBLOCK;
217     }
218 
219     if (len != NULL) {
220         *len = actual;
221     }
222 
223     if ((nfd = fdio_assign_reserved(nfd, io2)) < 0) {
224         io2->ops->close(io2);
225         fdio_release(io2);
226         return -1;
227     }
228     return nfd;
229 }
230 
addrinfo_status_to_eai(int32_t status)231 static int addrinfo_status_to_eai(int32_t status) {
232     switch (status) {
233     case fuchsia_net_AddrInfoStatus_ok:
234         return 0;
235     case fuchsia_net_AddrInfoStatus_bad_flags:
236         return EAI_BADFLAGS;
237     case fuchsia_net_AddrInfoStatus_no_name:
238         return EAI_NONAME;
239     case fuchsia_net_AddrInfoStatus_again:
240         return EAI_AGAIN;
241     case fuchsia_net_AddrInfoStatus_fail:
242         return EAI_FAIL;
243     case fuchsia_net_AddrInfoStatus_no_data:
244         return EAI_NONAME;
245     case fuchsia_net_AddrInfoStatus_buffer_overflow:
246         return EAI_OVERFLOW;
247     case fuchsia_net_AddrInfoStatus_system_error:
248         return EAI_SYSTEM;
249     default:
250         // unknown status
251         return EAI_SYSTEM;
252     }
253 }
254 
255 __EXPORT
getaddrinfo(const char * __restrict node,const char * __restrict service,const struct addrinfo * __restrict hints,struct addrinfo ** __restrict res)256 int getaddrinfo(const char* __restrict node,
257                 const char* __restrict service,
258                 const struct addrinfo* __restrict hints,
259                 struct addrinfo** __restrict res) {
260     if ((node == NULL && service == NULL) || res == NULL) {
261         errno = EINVAL;
262         return EAI_SYSTEM;
263     }
264 
265     zx_status_t r;
266     zx_handle_t sp;
267     r = get_socket_provider(&sp);
268     if (r != ZX_OK) {
269         errno = EIO;
270         return EAI_SYSTEM;
271     }
272 
273     size_t node_size = 0;
274     if (node) {
275         node_size = strlen(node);
276     }
277     size_t service_size = 0;
278     if (service) {
279         service_size = strlen(service);
280     }
281 
282 
283     fuchsia_net_AddrInfoHints ht_storage, *ht;
284     memset(&ht_storage, 0, sizeof(ht_storage));
285     ht = &ht_storage;
286     if (hints == NULL) {
287         ht = NULL;
288     } else {
289         ht->flags = hints->ai_flags;
290         ht->family = hints->ai_family;
291         ht->sock_type = hints->ai_socktype;
292         ht->protocol = hints->ai_protocol;
293     }
294 
295     fuchsia_net_AddrInfoStatus status = 0;
296     uint32_t nres = 0;
297     fuchsia_net_AddrInfo ai[4];
298     r = fuchsia_net_LegacySocketProviderGetAddrInfo(
299           sp, node, node_size, service, service_size, ht, &status, &nres, ai);
300 
301     if (r != ZX_OK) {
302         errno = fdio_status_to_errno(r);
303         return EAI_SYSTEM;
304     }
305     if (status != fuchsia_net_AddrInfoStatus_ok) {
306         int eai = addrinfo_status_to_eai(status);
307         if (eai == EAI_SYSTEM) {
308             errno = EIO;
309             return EAI_SYSTEM;
310         }
311         return eai;
312     }
313     if (nres > 4) {
314         errno = EIO;
315         return EAI_SYSTEM;
316     }
317 
318     struct res_entry {
319         struct addrinfo ai;
320         struct sockaddr_storage addr_storage;
321     };
322     struct res_entry* entry = calloc(nres, sizeof(struct res_entry));
323 
324     for (uint32_t i = 0; i < nres; i++) {
325         entry[i].ai.ai_flags = ai[i].flags;
326         entry[i].ai.ai_family = ai[i].family;
327         entry[i].ai.ai_socktype = ai[i].sock_type;
328         entry[i].ai.ai_protocol = ai[i].protocol;
329         entry[i].ai.ai_addr = (struct sockaddr*) &entry[i].addr_storage;
330         entry[i].ai.ai_canonname = NULL; // TODO: support canonname
331         switch (entry[i].ai.ai_family) {
332             case AF_INET: {
333                 struct sockaddr_in
334                     * addr = (struct sockaddr_in*) entry[i].ai.ai_addr;
335                 addr->sin_family = AF_INET;
336                 addr->sin_port = htons(ai[i].port);
337                 if (ai[i].addr.len > sizeof(ai[i].addr.val)) {
338                     free(entry);
339                     errno = EIO;
340                     return EAI_SYSTEM;
341                 }
342                 memcpy(&addr->sin_addr, ai[i].addr.val, ai[i].addr.len);
343                 entry[i].ai.ai_addrlen = sizeof(struct sockaddr_in);
344 
345                 break;
346             }
347 
348             case AF_INET6: {
349                 struct sockaddr_in6
350                     * addr = (struct sockaddr_in6*) entry[i].ai.ai_addr;
351                 addr->sin6_family = AF_INET6;
352                 addr->sin6_port = htons(ai[i].port);
353                 if (ai[i].addr.len > sizeof(ai[i].addr.val)) {
354                     free(entry);
355                     errno = EIO;
356                     return EAI_SYSTEM;
357                 }
358                 memcpy(&addr->sin6_addr, ai[i].addr.val, ai[i].addr.len);
359                 entry[i].ai.ai_addrlen = sizeof(struct sockaddr_in6);
360 
361                 break;
362             }
363 
364             default: {
365                 free(entry);
366                 errno = EIO;
367                 return EAI_SYSTEM;
368             }
369         }
370     }
371     struct addrinfo* next = NULL;
372     for (int i = nres - 1; i >= 0; --i) {
373         entry[i].ai.ai_next = next;
374         next = &entry[i].ai;
375     }
376     *res = next;
377 
378     return 0;
379 }
380 
381 __EXPORT
freeaddrinfo(struct addrinfo * res)382 void freeaddrinfo(struct addrinfo* res) {
383     free(res);
384 }
385 
386 __EXPORT
getsockname(int fd,struct sockaddr * restrict addr,socklen_t * restrict len)387 int getsockname(int fd, struct sockaddr* restrict addr, socklen_t* restrict len) {
388     if (len == NULL || addr == NULL) {
389         return ERRNO(EINVAL);
390     }
391 
392     const zxs_socket_t* socket = NULL;
393     fdio_t* io = fd_to_socket(fd, &socket);
394     if (io == NULL) {
395         return ERRNO(EBADF);
396     }
397 
398     size_t actual = 0u;
399     zx_status_t status = zxs_getsockname(socket, addr, *len, &actual);
400     if (status == ZX_OK) {
401         *len = actual;
402     }
403     fdio_release(io);
404     return STATUS(status);
405 }
406 
407 __EXPORT
getpeername(int fd,struct sockaddr * restrict addr,socklen_t * restrict len)408 int getpeername(int fd, struct sockaddr* restrict addr, socklen_t* restrict len) {
409     if (len == NULL || addr == NULL) {
410         return ERRNO(EINVAL);
411     }
412 
413     const zxs_socket_t* socket = NULL;
414     fdio_t* io = fd_to_socket(fd, &socket);
415     if (io == NULL) {
416         return ERRNO(EBADF);
417     }
418 
419     size_t actual = 0u;
420     zx_status_t status = zxs_getpeername(socket, addr, *len, &actual);
421     if (status == ZX_OK) {
422         *len = actual;
423     }
424     fdio_release(io);
425     return STATUS(status);
426 }
427 
428 __EXPORT
getsockopt(int fd,int level,int optname,void * restrict optval,socklen_t * restrict optlen)429 int getsockopt(int fd, int level, int optname, void* restrict optval,
430                socklen_t* restrict optlen) {
431     const zxs_socket_t* socket = NULL;
432     fdio_t* io = fd_to_socket(fd, &socket);
433     if (io == NULL) {
434         return ERRNO(EBADF);
435     }
436 
437     zx_status_t r;
438     if (level == SOL_SOCKET && optname == SO_ERROR) {
439         if (optval == NULL || optlen == NULL || *optlen < sizeof(int)) {
440             r = ZX_ERR_INVALID_ARGS;
441         } else {
442             zx_status_t status;
443             size_t actual = 0u;
444             r = zxs_getsockopt(socket, SOL_SOCKET, SO_ERROR, &status,
445                                sizeof(status), &actual);
446             if (r == ZX_OK) {
447                 int errno_ = 0;
448                 if (status != ZX_OK) {
449                     errno_ = fdio_status_to_errno(status);
450                 }
451                 *(int*)optval = errno_;
452                 *optlen = sizeof(int);
453             }
454         }
455     } else {
456         if (optval == NULL || optlen == NULL) {
457             r = ZX_ERR_INVALID_ARGS;
458         } else {
459             size_t actual = 0u;
460             r = zxs_getsockopt(socket, level, optname, optval, *optlen, &actual);
461             if (r == ZX_OK) {
462                 *optlen = actual;
463             }
464         }
465     }
466     fdio_release(io);
467 
468     return STATUS(r);
469 }
470 
471 __EXPORT
setsockopt(int fd,int level,int optname,const void * optval,socklen_t optlen)472 int setsockopt(int fd, int level, int optname, const void* optval,
473                socklen_t optlen) {
474     const zxs_socket_t* socket = NULL;
475     fdio_t* io = fd_to_socket(fd, &socket);
476     if (io == NULL) {
477         return ERRNO(EBADF);
478     }
479 
480     zxs_option_t option = {
481         .level = level,
482         .name = optname,
483         .value = optval,
484         .length = optlen,
485     };
486 
487     zx_status_t status = zxs_setsockopts(socket, &option, 1u);
488     fdio_release(io);
489     return STATUS(status);
490 }
491