Merge pull request #12860 from monojenkins/backport-pr-12856-to-2019-02
[mono-project.git] / support / sys-socket.c
blob9d43087ecdd0a7dc85b75758c493e2f5f66cefb2
1 /*
2 * <sys/socket.h> wrapper functions.
4 * Authors:
5 * Steffen Kiess (s-kiess@web.de)
7 * Copyright (C) 2015 Steffen Kiess
8 */
10 #include <sys/socket.h>
11 #include <sys/time.h>
12 #include <netinet/in.h>
13 #include <sys/un.h>
14 #include <unistd.h>
16 #include <stddef.h>
18 #include "map.h"
19 #include "mph.h"
20 #include "sys-uio.h"
22 G_BEGIN_DECLS
24 int
25 Mono_Posix_SockaddrStorage_get_size (void)
27 return sizeof (struct sockaddr_storage);
30 int
31 Mono_Posix_SockaddrUn_get_sizeof_sun_path (void)
33 struct sockaddr_un sun;
34 return sizeof (sun.sun_path);
37 int
38 Mono_Posix_Cmsghdr_getsize (void)
40 return sizeof (struct cmsghdr);
43 int
44 Mono_Posix_FromInAddr (struct Mono_Posix_InAddr* source, void* destination)
46 memcpy (&((struct in_addr*)destination)->s_addr, &source->s_addr, 4);
47 return 0;
50 int
51 Mono_Posix_ToInAddr (void* source, struct Mono_Posix_InAddr* destination)
53 memcpy (&destination->s_addr, &((struct in_addr*)source)->s_addr, 4);
54 return 0;
57 int
58 Mono_Posix_FromIn6Addr (struct Mono_Posix_In6Addr* source, void* destination)
60 memcpy (&((struct in6_addr*)destination)->s6_addr, &source->addr0, 16);
61 return 0;
64 int
65 Mono_Posix_ToIn6Addr (void* source, struct Mono_Posix_In6Addr* destination)
67 memcpy (&destination->addr0, &((struct in6_addr*)source)->s6_addr, 16);
68 return 0;
72 int
73 Mono_Posix_Syscall_socketpair (int domain, int type, int protocol, int* socket1, int* socket2)
75 int filedes[2] = {-1, -1};
76 int r;
78 r = socketpair (domain, type, protocol, filedes);
80 *socket1 = filedes[0];
81 *socket2 = filedes[1];
82 return r;
85 int
86 Mono_Posix_Syscall_getsockopt (int socket, int level, int option_name, void* option_value, gint64* option_len)
88 socklen_t len;
89 int r;
91 mph_return_if_socklen_t_overflow (*option_len);
93 len = *option_len;
95 r = getsockopt (socket, level, option_name, option_value, &len);
97 *option_len = len;
99 return r;
103 Mono_Posix_Syscall_getsockopt_timeval (int socket, int level, int option_name, struct Mono_Posix_Timeval* option_value)
105 struct timeval tv;
106 int r;
107 socklen_t size;
109 size = sizeof (struct timeval);
110 r = getsockopt (socket, level, option_name, &tv, &size);
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;
121 return r;
125 Mono_Posix_Syscall_getsockopt_linger (int socket, int level, int option_name, struct Mono_Posix_Linger* option_value)
127 struct linger ling;
128 int r;
129 socklen_t size;
131 size = sizeof (struct linger);
132 r = getsockopt (socket, level, option_name, &ling, &size);
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;
143 return r;
147 Mono_Posix_Syscall_setsockopt (int socket, int level, int option_name, void* option_value, gint64 option_len)
149 mph_return_if_socklen_t_overflow (option_len);
151 return setsockopt (socket, level, option_name, option_value, option_len);
155 Mono_Posix_Syscall_setsockopt_timeval (int socket, int level, int option_name, struct Mono_Posix_Timeval* option_value)
157 struct timeval tv;
159 if (Mono_Posix_FromTimeval (option_value, &tv) != 0)
160 return -1;
162 return setsockopt (socket, level, option_name, &tv, sizeof (struct timeval));
166 Mono_Posix_Syscall_setsockopt_linger (int socket, int level, int option_name, struct Mono_Posix_Linger* option_value)
168 struct linger ling;
170 if (Mono_Posix_FromLinger (option_value, &ling) != 0)
171 return -1;
173 return setsockopt (socket, level, option_name, &ling, sizeof (struct linger));
176 static int
177 get_addrlen (struct Mono_Posix__SockaddrHeader* address, socklen_t* addrlen)
179 if (!address) {
180 *addrlen = 0;
181 return 0;
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;
204 Mono_Posix_Sockaddr_GetNativeSize (struct Mono_Posix__SockaddrHeader* address, gint64* size)
206 socklen_t value;
207 int r;
209 r = get_addrlen (address, &value);
210 *size = value;
211 return r;
215 Mono_Posix_FromSockaddr (struct Mono_Posix__SockaddrHeader* source, void* destination)
217 if (!source)
218 return 0;
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;
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;
229 case Mono_Posix_SockaddrType_Sockaddr:
230 break;
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;
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;
242 default:
243 errno = EINVAL;
244 return -1;
247 int family;
248 if (Mono_Posix_FromUnixAddressFamily (source->sa_family, &family) != 0)
249 return -1;
250 ((struct sockaddr*) destination)->sa_family = family;
252 return 0;
256 Mono_Posix_ToSockaddr (void* source, gint64 size, struct Mono_Posix__SockaddrHeader* destination)
258 struct Mono_Posix__SockaddrDynamic* destination_dyn;
260 if (!destination)
261 return 0;
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;
269 break;
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;
277 destination_dyn->len = size;
278 break;
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;
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;
290 case Mono_Posix_SockaddrType_SockaddrIn:
291 if (size != sizeof (struct sockaddr_in)) {
292 errno = ENOBUFS;
293 return -1;
295 if (Mono_Posix_ToSockaddrIn ((struct sockaddr_in*) source, (struct Mono_Posix_SockaddrIn*) destination) != 0)
296 return -1;
297 break;
299 case Mono_Posix_SockaddrType_SockaddrIn6:
300 if (size != sizeof (struct sockaddr_in6)) {
301 errno = ENOBUFS;
302 return -1;
304 if (Mono_Posix_ToSockaddrIn6 ((struct sockaddr_in6*) source, (struct Mono_Posix_SockaddrIn6*) destination) != 0)
305 return -1;
306 break;
308 default:
309 errno = EINVAL;
310 return -1;
313 if (Mono_Posix_ToUnixAddressFamily (((struct sockaddr*) source)->sa_family, &destination->sa_family) != 0)
314 destination->sa_family = Mono_Posix_UnixAddressFamily_Unknown;
316 return 0;
319 // Macro for allocating space for the native sockaddr_* structure
320 // Must be a macro because it is using alloca()
322 #define ALLOC_SOCKADDR \
323 socklen_t addrlen; \
324 struct sockaddr* addr; \
325 gboolean need_free = 0; \
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); \
345 Mono_Posix_Syscall_bind (int socket, struct Mono_Posix__SockaddrHeader* address)
347 int r;
349 ALLOC_SOCKADDR
350 if (Mono_Posix_FromSockaddr (address, addr) != 0) {
351 if (need_free)
352 free (addr);
353 return -1;
356 r = bind (socket, addr, addrlen);
358 if (need_free)
359 free (addr);
361 return r;
365 Mono_Posix_Syscall_connect (int socket, struct Mono_Posix__SockaddrHeader* address)
367 int r;
369 ALLOC_SOCKADDR
370 if (Mono_Posix_FromSockaddr (address, addr) != 0) {
371 if (need_free)
372 free (addr);
373 return -1;
376 r = connect (socket, addr, addrlen);
378 if (need_free)
379 free (addr);
381 return r;
385 Mono_Posix_Syscall_accept (int socket, struct Mono_Posix__SockaddrHeader* address)
387 int r;
389 ALLOC_SOCKADDR
391 r = accept (socket, addr, &addrlen);
393 if (r != -1 && Mono_Posix_ToSockaddr (addr, addrlen, address) != 0) {
394 close (r);
395 r = -1;
398 if (need_free)
399 free (addr);
401 return r;
404 #ifdef HAVE_ACCEPT4
406 Mono_Posix_Syscall_accept4 (int socket, struct Mono_Posix__SockaddrHeader* address, int flags)
408 int r;
410 ALLOC_SOCKADDR
412 r = accept4 (socket, addr, &addrlen, flags);
414 if (r != -1 && Mono_Posix_ToSockaddr (addr, addrlen, address) != 0) {
415 close (r);
416 r = -1;
419 if (need_free)
420 free (addr);
422 return r;
424 #endif
427 Mono_Posix_Syscall_getpeername (int socket, struct Mono_Posix__SockaddrHeader* address)
429 int r;
431 ALLOC_SOCKADDR
433 r = getpeername (socket, addr, &addrlen);
435 if (r != -1 && Mono_Posix_ToSockaddr (addr, addrlen, address) != 0)
436 r = -1;
438 if (need_free)
439 free (addr);
441 return r;
445 Mono_Posix_Syscall_getsockname (int socket, struct Mono_Posix__SockaddrHeader* address)
447 int r;
449 ALLOC_SOCKADDR
451 r = getsockname (socket, addr, &addrlen);
453 if (r != -1 && Mono_Posix_ToSockaddr (addr, addrlen, address) != 0)
454 r = -1;
456 if (need_free)
457 free (addr);
459 return r;
462 gint64
463 Mono_Posix_Syscall_recv (int socket, void* message, guint64 length, int flags)
465 mph_return_if_size_t_overflow (length);
467 return recv (socket, message, length, flags);
470 gint64
471 Mono_Posix_Syscall_send (int socket, void* message, guint64 length, int flags)
473 mph_return_if_size_t_overflow (length);
475 return send (socket, message, length, flags);
478 gint64
479 Mono_Posix_Syscall_recvfrom (int socket, void* buffer, guint64 length, int flags, struct Mono_Posix__SockaddrHeader* address)
481 int r;
483 mph_return_if_size_t_overflow (length);
485 ALLOC_SOCKADDR
487 r = recvfrom (socket, buffer, length, flags, addr, &addrlen);
489 if (r != -1 && Mono_Posix_ToSockaddr (addr, addrlen, address) != 0)
490 r = -1;
492 if (need_free)
493 free (addr);
495 return r;
498 gint64
499 Mono_Posix_Syscall_sendto (int socket, void* message, guint64 length, int flags, struct Mono_Posix__SockaddrHeader* address)
501 int r;
503 mph_return_if_size_t_overflow (length);
505 ALLOC_SOCKADDR
506 if (Mono_Posix_FromSockaddr (address, addr) != 0) {
507 if (need_free)
508 free (addr);
509 return -1;
512 r = sendto (socket, message, length, flags, addr, addrlen);
514 if (need_free)
515 free (addr);
517 return r;
520 gint64
521 Mono_Posix_Syscall_recvmsg (int socket, struct Mono_Posix_Syscall__Msghdr* message, struct Mono_Posix__SockaddrHeader* address, int flags)
523 struct msghdr hdr;
524 int r;
526 ALLOC_SOCKADDR
528 memset (&hdr, 0, sizeof (struct msghdr));
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;
536 hdr.msg_iov = _mph_from_iovec_array (message->msg_iov, message->msg_iovlen);
538 r = recvmsg (socket, &hdr, flags);
540 if (r != -1 && Mono_Posix_ToSockaddr (addr, hdr.msg_namelen, address) != 0)
541 r = -1;
543 free (hdr.msg_iov);
544 if (need_free)
545 free (addr);
547 message->msg_controllen = hdr.msg_controllen;
548 message->msg_flags = hdr.msg_flags;
550 return r;
553 gint64
554 Mono_Posix_Syscall_sendmsg (int socket, struct Mono_Posix_Syscall__Msghdr* message, struct Mono_Posix__SockaddrHeader* address, int flags)
556 struct msghdr hdr;
557 int r;
559 ALLOC_SOCKADDR
560 if (Mono_Posix_FromSockaddr (address, addr) != 0) {
561 if (need_free)
562 free (addr);
563 return -1;
566 memset (&hdr, 0, sizeof (struct msghdr));
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;
574 hdr.msg_iov = _mph_from_iovec_array (message->msg_iov, message->msg_iovlen);
576 r = sendmsg (socket, &hdr, flags);
578 free (hdr.msg_iov);
579 if (need_free)
580 free (addr);
582 return r;
585 static inline void make_msghdr (struct msghdr* hdr, unsigned char* msg_control, gint64 msg_controllen)
587 memset (hdr, 0, sizeof (struct msghdr));
588 hdr->msg_control = msg_control;
589 hdr->msg_controllen = msg_controllen;
591 static inline struct cmsghdr* from_offset (unsigned char* msg_control, gint64 offset)
593 if (offset == -1)
594 return NULL;
595 return (struct cmsghdr*) (msg_control + offset);
597 static inline gint64 to_offset (unsigned char* msg_control, void* hdr)
599 if (!hdr)
600 return -1;
601 return ((unsigned char*) hdr) - msg_control;
604 #ifdef CMSG_FIRSTHDR
605 gint64
606 Mono_Posix_Syscall_CMSG_FIRSTHDR (unsigned char* msg_control, gint64 msg_controllen)
608 struct msghdr hdr;
610 make_msghdr (&hdr, msg_control, msg_controllen);
611 return to_offset (msg_control, CMSG_FIRSTHDR (&hdr));
613 #endif
615 #ifdef CMSG_NXTHDR
616 gint64
617 Mono_Posix_Syscall_CMSG_NXTHDR (unsigned char* msg_control, gint64 msg_controllen, gint64 cmsg)
619 struct msghdr hdr;
621 make_msghdr (&hdr, msg_control, msg_controllen);
622 return to_offset (msg_control, CMSG_NXTHDR (&hdr, from_offset (msg_control, cmsg)));
624 #endif
626 #ifdef CMSG_DATA
627 gint64
628 Mono_Posix_Syscall_CMSG_DATA (unsigned char* msg_control, gint64 msg_controllen, gint64 cmsg)
630 return to_offset (msg_control, CMSG_DATA (from_offset (msg_control, cmsg)));
632 #endif
634 #ifdef CMSG_ALIGN
635 guint64
636 Mono_Posix_Syscall_CMSG_ALIGN (guint64 length)
638 return CMSG_ALIGN (length);
640 #endif
642 #ifdef CMSG_SPACE
643 guint64
644 Mono_Posix_Syscall_CMSG_SPACE (guint64 length)
646 return CMSG_SPACE (length);
648 #endif
650 #ifdef CMSG_LEN
651 guint64
652 Mono_Posix_Syscall_CMSG_LEN (guint64 length)
654 return CMSG_LEN (length);
656 #endif
659 * vim: noexpandtab
662 // vim: noexpandtab
663 // Local Variables:
664 // tab-width: 4
665 // c-basic-offset: 4
666 // indent-tabs-mode: t
667 // End: