Merge pull request #5714 from alexischr/update_bockbuild
[mono.git] / support / sys-socket.c
1 /*
2  * <sys/socket.h> wrapper functions.
3  *
4  * Authors:
5  *   Steffen Kiess (s-kiess@web.de)
6  *
7  * Copyright (C) 2015 Steffen Kiess
8  */
9
10 #include <sys/socket.h>
11 #include <sys/time.h>
12 #include <netinet/in.h>
13 #include <sys/un.h>
14 #include <unistd.h>
15
16 #include <stddef.h>
17
18 #include "map.h"
19 #include "mph.h"
20 #include "sys-uio.h"
21
22 G_BEGIN_DECLS
23
24 int
25 Mono_Posix_SockaddrStorage_get_size (void)
26 {
27         return sizeof (struct sockaddr_storage);
28 }
29
30 int
31 Mono_Posix_SockaddrUn_get_sizeof_sun_path (void)
32 {
33         struct sockaddr_un sun;
34         return sizeof (sun.sun_path);
35 }
36
37 int
38 Mono_Posix_Cmsghdr_getsize (void)
39 {
40         return sizeof (struct cmsghdr);
41 }
42
43 int
44 Mono_Posix_FromInAddr (struct Mono_Posix_InAddr* source, void* destination)
45 {
46         memcpy (&((struct in_addr*)destination)->s_addr, &source->s_addr, 4);
47         return 0;
48 }
49
50 int
51 Mono_Posix_ToInAddr (void* source, struct Mono_Posix_InAddr* destination)
52 {
53         memcpy (&destination->s_addr, &((struct in_addr*)source)->s_addr, 4);
54         return 0;
55 }
56
57 int
58 Mono_Posix_FromIn6Addr (struct Mono_Posix_In6Addr* source, void* destination)
59 {
60         memcpy (&((struct in6_addr*)destination)->s6_addr, &source->addr0, 16);
61         return 0;
62 }
63
64 int
65 Mono_Posix_ToIn6Addr (void* source, struct Mono_Posix_In6Addr* destination)
66 {
67         memcpy (&destination->addr0, &((struct in6_addr*)source)->s6_addr, 16);
68         return 0;
69 }
70
71
72 int
73 Mono_Posix_Syscall_socketpair (int domain, int type, int protocol, int* socket1, int* socket2)
74 {
75         int filedes[2] = {-1, -1};
76         int r;
77
78         r = socketpair (domain, type, protocol, filedes);
79
80         *socket1 = filedes[0];
81         *socket2 = filedes[1];
82         return r;
83 }
84
85 int
86 Mono_Posix_Syscall_getsockopt (int socket, int level, int option_name, void* option_value, gint64* option_len)
87 {
88         socklen_t len;
89         int r;
90
91         mph_return_if_socklen_t_overflow (*option_len);
92
93         len = *option_len;
94
95         r = getsockopt (socket, level, option_name, option_value, &len);
96
97         *option_len = len;
98
99         return r;
100 }
101
102 int
103 Mono_Posix_Syscall_getsockopt_timeval (int socket, int level, int option_name, struct Mono_Posix_Timeval* option_value)
104 {
105         struct timeval tv;
106         int r;
107         socklen_t size;
108
109         size = sizeof (struct timeval);
110         r = getsockopt (socket, level, option_name, &tv, &size);
111
112         if (r != -1 && size == sizeof (struct timeval)) {
113                 if (Mono_Posix_ToTimeval (&tv, option_value) != 0)
114                         return -1;
115         } else {
116                 memset (option_value, 0, sizeof (struct Mono_Posix_Timeval));
117                 if (r != -1)
118                         errno = EINVAL;
119         }
120
121         return r;
122 }
123
124 int
125 Mono_Posix_Syscall_getsockopt_linger (int socket, int level, int option_name, struct Mono_Posix_Linger* option_value)
126 {
127         struct linger ling;
128         int r;
129         socklen_t size;
130
131         size = sizeof (struct linger);
132         r = getsockopt (socket, level, option_name, &ling, &size);
133
134         if (r != -1 && size == sizeof (struct linger)) {
135                 if (Mono_Posix_ToLinger (&ling, option_value) != 0)
136                         return -1;
137         } else {
138                 memset (option_value, 0, sizeof (struct Mono_Posix_Linger));
139                 if (r != -1)
140                         errno = EINVAL;
141         }
142
143         return r;
144 }
145
146 int
147 Mono_Posix_Syscall_setsockopt (int socket, int level, int option_name, void* option_value, gint64 option_len)
148 {
149         mph_return_if_socklen_t_overflow (option_len);
150
151         return setsockopt (socket, level, option_name, option_value, option_len);
152 }
153
154 int
155 Mono_Posix_Syscall_setsockopt_timeval (int socket, int level, int option_name, struct Mono_Posix_Timeval* option_value)
156 {
157         struct timeval tv;
158
159         if (Mono_Posix_FromTimeval (option_value, &tv) != 0)
160                 return -1;
161
162         return setsockopt (socket, level, option_name, &tv, sizeof (struct timeval));
163 }
164
165 int
166 Mono_Posix_Syscall_setsockopt_linger (int socket, int level, int option_name, struct Mono_Posix_Linger* option_value)
167 {
168         struct linger ling;
169
170         if (Mono_Posix_FromLinger (option_value, &ling) != 0)
171                 return -1;
172
173         return setsockopt (socket, level, option_name, &ling, sizeof (struct linger));
174 }
175
176 static int
177 get_addrlen (struct Mono_Posix__SockaddrHeader* address, socklen_t* addrlen)
178 {
179         if (!address) {
180                 *addrlen = 0;
181                 return 0;
182         }
183
184         switch (address->type) {
185         case Mono_Posix_SockaddrType_SockaddrStorage:
186                 mph_return_if_socklen_t_overflow (((struct Mono_Posix__SockaddrDynamic*) address)->len);
187                 *addrlen = ((struct Mono_Posix__SockaddrDynamic*) address)->len;
188                 return 0;
189         case Mono_Posix_SockaddrType_SockaddrUn:
190                 mph_return_if_socklen_t_overflow (offsetof (struct sockaddr_un, sun_path) + ((struct Mono_Posix__SockaddrDynamic*) address)->len);
191                 *addrlen = offsetof (struct sockaddr_un, sun_path) + ((struct Mono_Posix__SockaddrDynamic*) address)->len;
192                 return 0;
193         case Mono_Posix_SockaddrType_Sockaddr: *addrlen = sizeof (struct sockaddr); return 0;
194         case Mono_Posix_SockaddrType_SockaddrIn: *addrlen = sizeof (struct sockaddr_in); return 0;
195         case Mono_Posix_SockaddrType_SockaddrIn6: *addrlen = sizeof (struct sockaddr_in6); return 0;
196         default:
197                 *addrlen = 0;
198                 errno = EINVAL;
199                 return -1;
200         }
201 }
202
203 int
204 Mono_Posix_Sockaddr_GetNativeSize (struct Mono_Posix__SockaddrHeader* address, gint64* size)
205 {
206         socklen_t value;
207         int r;
208
209         r = get_addrlen (address, &value);
210         *size = value;
211         return r;
212 }
213
214 int
215 Mono_Posix_FromSockaddr (struct Mono_Posix__SockaddrHeader* source, void* destination)
216 {
217         if (!source)
218                 return 0;
219
220         switch (source->type) {
221         case Mono_Posix_SockaddrType_SockaddrStorage:
222                 // Do nothing, don't copy source->sa_family into addr->sa_family
223                 return 0;
224
225         case Mono_Posix_SockaddrType_SockaddrUn:
226                 memcpy (((struct sockaddr_un*) destination)->sun_path, ((struct Mono_Posix__SockaddrDynamic*) source)->data, ((struct Mono_Posix__SockaddrDynamic*) source)->len);
227                 break;
228
229         case Mono_Posix_SockaddrType_Sockaddr:
230                 break;
231
232         case Mono_Posix_SockaddrType_SockaddrIn:
233                 if (Mono_Posix_FromSockaddrIn ((struct Mono_Posix_SockaddrIn*) source, (struct sockaddr_in*) destination) != 0)
234                         return -1;
235                 break;
236
237         case Mono_Posix_SockaddrType_SockaddrIn6:
238                 if (Mono_Posix_FromSockaddrIn6 ((struct Mono_Posix_SockaddrIn6*) source, (struct sockaddr_in6*) destination) != 0)
239                         return -1;
240                 break;
241
242         default:
243                 errno = EINVAL;
244                 return -1;
245         }
246
247         int family;
248         if (Mono_Posix_FromUnixAddressFamily (source->sa_family, &family) != 0)
249                 return -1;
250         ((struct sockaddr*) destination)->sa_family = family;
251
252         return 0;
253 }
254
255 int
256 Mono_Posix_ToSockaddr (void* source, gint64 size, struct Mono_Posix__SockaddrHeader* destination)
257 {
258         struct Mono_Posix__SockaddrDynamic* destination_dyn;
259
260         if (!destination)
261                 return 0;
262
263         switch (destination->type) {
264         case Mono_Posix_SockaddrType_Sockaddr:
265                 if (size < offsetof (struct sockaddr, sa_family) + sizeof (sa_family_t)) {
266                         errno = ENOBUFS;
267                         return -1;
268                 }
269                 break;
270
271         case Mono_Posix_SockaddrType_SockaddrStorage:
272                 destination_dyn = ((struct Mono_Posix__SockaddrDynamic*) destination);
273                 if (size > destination_dyn->len) {
274                         errno = ENOBUFS;
275                         return -1;
276                 }
277                 destination_dyn->len = size;
278                 break;
279
280         case Mono_Posix_SockaddrType_SockaddrUn:
281                 destination_dyn = ((struct Mono_Posix__SockaddrDynamic*) destination);
282                 if (size - offsetof (struct sockaddr_un, sun_path) > destination_dyn->len) {
283                         errno = ENOBUFS;
284                         return -1;
285                 }
286                 destination_dyn->len = size - offsetof (struct sockaddr_un, sun_path);
287                 memcpy (destination_dyn->data, ((struct sockaddr_un*) source)->sun_path, size);
288                 break;
289
290         case Mono_Posix_SockaddrType_SockaddrIn:
291                 if (size != sizeof (struct sockaddr_in)) {
292                         errno = ENOBUFS;
293                         return -1;
294                 }
295                 if (Mono_Posix_ToSockaddrIn ((struct sockaddr_in*) source, (struct Mono_Posix_SockaddrIn*) destination) != 0)
296                         return -1;
297                 break;
298
299         case Mono_Posix_SockaddrType_SockaddrIn6:
300                 if (size != sizeof (struct sockaddr_in6)) {
301                         errno = ENOBUFS;
302                         return -1;
303                 }
304                 if (Mono_Posix_ToSockaddrIn6 ((struct sockaddr_in6*) source, (struct Mono_Posix_SockaddrIn6*) destination) != 0)
305                         return -1;
306                 break;
307
308         default:
309                 errno = EINVAL;
310                 return -1;
311         }
312
313         if (Mono_Posix_ToUnixAddressFamily (((struct sockaddr*) source)->sa_family, &destination->sa_family) != 0)
314                 destination->sa_family = Mono_Posix_UnixAddressFamily_Unknown;
315
316         return 0;
317 }
318
319 // Macro for allocating space for the native sockaddr_* structure
320 // Must be a macro because it is using alloca()
321
322 #define ALLOC_SOCKADDR                                                  \
323     socklen_t addrlen;                                                  \
324     struct sockaddr* addr;                                              \
325     gboolean need_free = 0;                                             \
326                                                                         \
327     if (get_addrlen (address, &addrlen) != 0)                           \
328         return -1;                                                      \
329     if (address == NULL) {                                              \
330         addr = NULL;                                                    \
331     } else if (address->type == Mono_Posix_SockaddrType_SockaddrStorage) { \
332         addr = (struct sockaddr*) ((struct Mono_Posix__SockaddrDynamic*) address)->data; \
333     } else if (address->type == Mono_Posix_SockaddrType_SockaddrUn) { \
334         /* Use alloca() for up to 2048 bytes, use malloc() otherwise */ \
335         need_free = addrlen > 2048;                                     \
336         addr = need_free ? malloc (addrlen) : alloca (addrlen);         \
337         if (!addr)                                                      \
338             return -1;                                                  \
339     } else {                                                            \
340         addr = alloca (addrlen);                                        \
341     }
342
343
344 int
345 Mono_Posix_Syscall_bind (int socket, struct Mono_Posix__SockaddrHeader* address)
346 {
347         int r;
348
349         ALLOC_SOCKADDR
350         if (Mono_Posix_FromSockaddr (address, addr) != 0) {
351                 if (need_free)
352                         free (addr);
353                 return -1;
354         }
355
356         r = bind (socket, addr, addrlen);
357
358         if (need_free)
359                 free (addr);
360
361         return r;
362 }
363
364 int
365 Mono_Posix_Syscall_connect (int socket, struct Mono_Posix__SockaddrHeader* address)
366 {
367         int r;
368
369         ALLOC_SOCKADDR
370         if (Mono_Posix_FromSockaddr (address, addr) != 0) {
371                 if (need_free)
372                         free (addr);
373                 return -1;
374         }
375
376         r = connect (socket, addr, addrlen);
377
378         if (need_free)
379                 free (addr);
380
381         return r;
382 }
383
384 int
385 Mono_Posix_Syscall_accept (int socket, struct Mono_Posix__SockaddrHeader* address)
386 {
387         int r;
388
389         ALLOC_SOCKADDR
390
391         r = accept (socket, addr, &addrlen);
392
393         if (r != -1 && Mono_Posix_ToSockaddr (addr, addrlen, address) != 0) {
394                 close (r);
395                 r = -1;
396         }
397
398         if (need_free)
399                 free (addr);
400
401         return r;
402 }
403
404 #ifdef HAVE_ACCEPT4
405 int
406 Mono_Posix_Syscall_accept4 (int socket, struct Mono_Posix__SockaddrHeader* address, int flags)
407 {
408         int r;
409
410         ALLOC_SOCKADDR
411
412         r = accept4 (socket, addr, &addrlen, flags);
413
414         if (r != -1 && Mono_Posix_ToSockaddr (addr, addrlen, address) != 0) {
415                 close (r);
416                 r = -1;
417         }
418
419         if (need_free)
420                 free (addr);
421
422         return r;
423 }
424 #endif
425
426 int
427 Mono_Posix_Syscall_getpeername (int socket, struct Mono_Posix__SockaddrHeader* address)
428 {
429         int r;
430
431         ALLOC_SOCKADDR
432
433         r = getpeername (socket, addr, &addrlen);
434
435         if (r != -1 && Mono_Posix_ToSockaddr (addr, addrlen, address) != 0)
436                 r = -1;
437
438         if (need_free)
439                 free (addr);
440
441         return r;
442 }
443
444 int
445 Mono_Posix_Syscall_getsockname (int socket, struct Mono_Posix__SockaddrHeader* address)
446 {
447         int r;
448
449         ALLOC_SOCKADDR
450
451         r = getsockname (socket, addr, &addrlen);
452
453         if (r != -1 && Mono_Posix_ToSockaddr (addr, addrlen, address) != 0)
454                 r = -1;
455
456         if (need_free)
457                 free (addr);
458
459         return r;
460 }
461
462 gint64
463 Mono_Posix_Syscall_recv (int socket, void* message, guint64 length, int flags)
464 {
465         mph_return_if_size_t_overflow (length);
466
467         return recv (socket, message, length, flags);
468 }
469
470 gint64
471 Mono_Posix_Syscall_send (int socket, void* message, guint64 length, int flags)
472 {
473         mph_return_if_size_t_overflow (length);
474
475         return send (socket, message, length, flags);
476 }
477
478 gint64
479 Mono_Posix_Syscall_recvfrom (int socket, void* buffer, guint64 length, int flags, struct Mono_Posix__SockaddrHeader* address)
480 {
481         int r;
482
483         mph_return_if_size_t_overflow (length);
484
485         ALLOC_SOCKADDR
486
487         r = recvfrom (socket, buffer, length, flags, addr, &addrlen);
488
489         if (r != -1 && Mono_Posix_ToSockaddr (addr, addrlen, address) != 0)
490                 r = -1;
491
492         if (need_free)
493                 free (addr);
494
495         return r;
496 }
497
498 gint64
499 Mono_Posix_Syscall_sendto (int socket, void* message, guint64 length, int flags, struct Mono_Posix__SockaddrHeader* address)
500 {
501         int r;
502
503         mph_return_if_size_t_overflow (length);
504
505         ALLOC_SOCKADDR
506         if (Mono_Posix_FromSockaddr (address, addr) != 0) {
507                 if (need_free)
508                         free (addr);
509                 return -1;
510         }
511
512         r = sendto (socket, message, length, flags, addr, addrlen);
513
514         if (need_free)
515                 free (addr);
516
517         return r;
518 }
519
520 gint64
521 Mono_Posix_Syscall_recvmsg (int socket, struct Mono_Posix_Syscall__Msghdr* message, struct Mono_Posix__SockaddrHeader* address, int flags)
522 {
523         struct msghdr hdr;
524         int r;
525
526         ALLOC_SOCKADDR
527
528         memset (&hdr, 0, sizeof (struct msghdr));
529
530         hdr.msg_name = addr;
531         hdr.msg_namelen = addrlen;
532         hdr.msg_iovlen = message->msg_iovlen;
533         hdr.msg_control = message->msg_control;
534         hdr.msg_controllen = message->msg_controllen;
535
536         hdr.msg_iov = _mph_from_iovec_array (message->msg_iov, message->msg_iovlen);
537
538         r = recvmsg (socket, &hdr, flags);
539
540         if (r != -1 && Mono_Posix_ToSockaddr (addr, hdr.msg_namelen, address) != 0)
541                 r = -1;
542
543         free (hdr.msg_iov);
544         if (need_free)
545                 free (addr);
546
547         message->msg_controllen = hdr.msg_controllen;
548         message->msg_flags = hdr.msg_flags;
549
550         return r;
551 }
552
553 gint64
554 Mono_Posix_Syscall_sendmsg (int socket, struct Mono_Posix_Syscall__Msghdr* message, struct Mono_Posix__SockaddrHeader* address, int flags)
555 {
556         struct msghdr hdr;
557         int r;
558
559         ALLOC_SOCKADDR
560         if (Mono_Posix_FromSockaddr (address, addr) != 0) {
561                 if (need_free)
562                         free (addr);
563                 return -1;
564         }
565
566         memset (&hdr, 0, sizeof (struct msghdr));
567
568         hdr.msg_name = addr;
569         hdr.msg_namelen = addrlen;
570         hdr.msg_iovlen = message->msg_iovlen;
571         hdr.msg_control = message->msg_control;
572         hdr.msg_controllen = message->msg_controllen;
573
574         hdr.msg_iov = _mph_from_iovec_array (message->msg_iov, message->msg_iovlen);
575
576         r = sendmsg (socket, &hdr, flags);
577
578         free (hdr.msg_iov);
579         if (need_free)
580                 free (addr);
581
582         return r;
583 }
584
585 static inline void make_msghdr (struct msghdr* hdr, unsigned char* msg_control, gint64 msg_controllen)
586 {
587         memset (hdr, 0, sizeof (struct msghdr));
588         hdr->msg_control = msg_control;
589         hdr->msg_controllen = msg_controllen;
590 }
591 static inline struct cmsghdr* from_offset (unsigned char* msg_control, gint64 offset)
592 {
593         if (offset == -1)
594                 return NULL;
595         return (struct cmsghdr*) (msg_control + offset);
596 }
597 static inline gint64 to_offset (unsigned char* msg_control, void* hdr)
598 {
599         if (!hdr)
600                 return -1;
601         return ((unsigned char*) hdr) - msg_control;
602 }
603
604 #ifdef CMSG_FIRSTHDR
605 gint64
606 Mono_Posix_Syscall_CMSG_FIRSTHDR (unsigned char* msg_control, gint64 msg_controllen)
607 {
608         struct msghdr hdr;
609
610         make_msghdr (&hdr, msg_control, msg_controllen);
611         return to_offset (msg_control, CMSG_FIRSTHDR (&hdr));
612 }
613 #endif
614
615 #ifdef CMSG_NXTHDR
616 gint64
617 Mono_Posix_Syscall_CMSG_NXTHDR (unsigned char* msg_control, gint64 msg_controllen, gint64 cmsg)
618 {
619         struct msghdr hdr;
620
621         make_msghdr (&hdr, msg_control, msg_controllen);
622         return to_offset (msg_control, CMSG_NXTHDR (&hdr, from_offset (msg_control, cmsg)));
623 }
624 #endif
625
626 #ifdef CMSG_DATA
627 gint64
628 Mono_Posix_Syscall_CMSG_DATA (unsigned char* msg_control, gint64 msg_controllen, gint64 cmsg)
629 {
630         return to_offset (msg_control, CMSG_DATA (from_offset (msg_control, cmsg)));
631 }
632 #endif
633
634 #ifdef CMSG_ALIGN
635 guint64
636 Mono_Posix_Syscall_CMSG_ALIGN (guint64 length)
637 {
638         return CMSG_ALIGN (length);
639 }
640 #endif
641
642 #ifdef CMSG_SPACE
643 guint64
644 Mono_Posix_Syscall_CMSG_SPACE (guint64 length)
645 {
646         return CMSG_SPACE (length);
647 }
648 #endif
649
650 #ifdef CMSG_LEN
651 guint64
652 Mono_Posix_Syscall_CMSG_LEN (guint64 length)
653 {
654         return CMSG_LEN (length);
655 }
656 #endif
657
658 /*
659  * vim: noexpandtab
660  */
661
662 // vim: noexpandtab
663 // Local Variables: 
664 // tab-width: 4
665 // c-basic-offset: 4
666 // indent-tabs-mode: t
667 // End: