Merge pull request #2429 from alexanderkyte/nunit_lite_integration
[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
21 G_BEGIN_DECLS
22
23 int
24 Mono_Posix_SockaddrStorage_get_size (void)
25 {
26         return sizeof (struct sockaddr_storage);
27 }
28
29 int
30 Mono_Posix_SockaddrUn_get_sizeof_sun_path (void)
31 {
32         struct sockaddr_un sun;
33         return sizeof (sun.sun_path);
34 }
35
36 int
37 Mono_Posix_FromInAddr (struct Mono_Posix_InAddr* source, void* destination)
38 {
39         memcpy (&((struct in_addr*)destination)->s_addr, &source->s_addr, 4);
40         return 0;
41 }
42
43 int
44 Mono_Posix_ToInAddr (void* source, struct Mono_Posix_InAddr* destination)
45 {
46         memcpy (&destination->s_addr, &((struct in_addr*)source)->s_addr, 4);
47         return 0;
48 }
49
50 int
51 Mono_Posix_FromIn6Addr (struct Mono_Posix_In6Addr* source, void* destination)
52 {
53         memcpy (&((struct in6_addr*)destination)->s6_addr, &source->addr0, 16);
54         return 0;
55 }
56
57 int
58 Mono_Posix_ToIn6Addr (void* source, struct Mono_Posix_In6Addr* destination)
59 {
60         memcpy (&destination->addr0, &((struct in6_addr*)source)->s6_addr, 16);
61         return 0;
62 }
63
64
65 int
66 Mono_Posix_Syscall_socketpair (int domain, int type, int protocol, int* socket1, int* socket2)
67 {
68         int filedes[2] = {-1, -1};
69         int r;
70
71         r = socketpair (domain, type, protocol, filedes);
72
73         *socket1 = filedes[0];
74         *socket2 = filedes[1];
75         return r;
76 }
77
78 int
79 Mono_Posix_Syscall_getsockopt (int socket, int level, int option_name, void* option_value, gint64* option_len)
80 {
81         socklen_t len;
82         int r;
83
84         mph_return_if_socklen_t_overflow (*option_len);
85
86         len = *option_len;
87
88         r = getsockopt (socket, level, option_name, option_value, &len);
89
90         *option_len = len;
91
92         return r;
93 }
94
95 int
96 Mono_Posix_Syscall_getsockopt_timeval (int socket, int level, int option_name, struct Mono_Posix_Timeval* option_value)
97 {
98         struct timeval tv;
99         int r;
100         socklen_t size;
101
102         size = sizeof (struct timeval);
103         r = getsockopt (socket, level, option_name, &tv, &size);
104
105         if (r != -1 && size == sizeof (struct timeval)) {
106                 if (Mono_Posix_ToTimeval (&tv, option_value) != 0)
107                         return -1;
108         } else {
109                 memset (option_value, 0, sizeof (struct Mono_Posix_Timeval));
110                 if (r != -1)
111                         errno = EINVAL;
112         }
113
114         return r;
115 }
116
117 int
118 Mono_Posix_Syscall_getsockopt_linger (int socket, int level, int option_name, struct Mono_Posix_Linger* option_value)
119 {
120         struct linger ling;
121         int r;
122         socklen_t size;
123
124         size = sizeof (struct linger);
125         r = getsockopt (socket, level, option_name, &ling, &size);
126
127         if (r != -1 && size == sizeof (struct linger)) {
128                 if (Mono_Posix_ToLinger (&ling, option_value) != 0)
129                         return -1;
130         } else {
131                 memset (option_value, 0, sizeof (struct Mono_Posix_Linger));
132                 if (r != -1)
133                         errno = EINVAL;
134         }
135
136         return r;
137 }
138
139 int
140 Mono_Posix_Syscall_setsockopt (int socket, int level, int option_name, void* option_value, gint64 option_len)
141 {
142         mph_return_if_socklen_t_overflow (option_len);
143
144         return setsockopt (socket, level, option_name, option_value, option_len);
145 }
146
147 int
148 Mono_Posix_Syscall_setsockopt_timeval (int socket, int level, int option_name, struct Mono_Posix_Timeval* option_value)
149 {
150         struct timeval tv;
151
152         if (Mono_Posix_FromTimeval (option_value, &tv) != 0)
153                 return -1;
154
155         return setsockopt (socket, level, option_name, &tv, sizeof (struct timeval));
156 }
157
158 int
159 Mono_Posix_Syscall_setsockopt_linger (int socket, int level, int option_name, struct Mono_Posix_Linger* option_value)
160 {
161         struct linger ling;
162
163         if (Mono_Posix_FromLinger (option_value, &ling) != 0)
164                 return -1;
165
166         return setsockopt (socket, level, option_name, &ling, sizeof (struct linger));
167 }
168
169 static int
170 get_addrlen (struct Mono_Posix__SockaddrHeader* address, socklen_t* addrlen)
171 {
172         if (!address) {
173                 *addrlen = 0;
174                 return 0;
175         }
176
177         switch (address->type) {
178         case Mono_Posix_SockaddrType_SockaddrStorage:
179                 mph_return_if_socklen_t_overflow (((struct Mono_Posix__SockaddrDynamic*) address)->len);
180                 *addrlen = ((struct Mono_Posix__SockaddrDynamic*) address)->len;
181                 return 0;
182         case Mono_Posix_SockaddrType_SockaddrUn:
183                 mph_return_if_socklen_t_overflow (offsetof (struct sockaddr_un, sun_path) + ((struct Mono_Posix__SockaddrDynamic*) address)->len);
184                 *addrlen = offsetof (struct sockaddr_un, sun_path) + ((struct Mono_Posix__SockaddrDynamic*) address)->len;
185                 return 0;
186         case Mono_Posix_SockaddrType_Sockaddr: *addrlen = sizeof (struct sockaddr); return 0;
187         case Mono_Posix_SockaddrType_SockaddrIn: *addrlen = sizeof (struct sockaddr_in); return 0;
188         case Mono_Posix_SockaddrType_SockaddrIn6: *addrlen = sizeof (struct sockaddr_in6); return 0;
189         default:
190                 *addrlen = 0;
191                 errno = EINVAL;
192                 return -1;
193         }
194 }
195
196 int
197 Mono_Posix_Sockaddr_GetNativeSize (struct Mono_Posix__SockaddrHeader* address, gint64* size)
198 {
199         socklen_t value;
200         int r;
201
202         r = get_addrlen (address, &value);
203         *size = value;
204         return r;
205 }
206
207 int
208 Mono_Posix_FromSockaddr (struct Mono_Posix__SockaddrHeader* source, void* destination)
209 {
210         if (!source)
211                 return 0;
212
213         switch (source->type) {
214         case Mono_Posix_SockaddrType_SockaddrStorage:
215                 // Do nothing, don't copy source->sa_family into addr->sa_family
216                 return 0;
217
218         case Mono_Posix_SockaddrType_SockaddrUn:
219                 memcpy (((struct sockaddr_un*) destination)->sun_path, ((struct Mono_Posix__SockaddrDynamic*) source)->data, ((struct Mono_Posix__SockaddrDynamic*) source)->len);
220                 break;
221
222         case Mono_Posix_SockaddrType_Sockaddr:
223                 break;
224
225         case Mono_Posix_SockaddrType_SockaddrIn:
226                 if (Mono_Posix_FromSockaddrIn ((struct Mono_Posix_SockaddrIn*) source, (struct sockaddr_in*) destination) != 0)
227                         return -1;
228                 break;
229
230         case Mono_Posix_SockaddrType_SockaddrIn6:
231                 if (Mono_Posix_FromSockaddrIn6 ((struct Mono_Posix_SockaddrIn6*) source, (struct sockaddr_in6*) destination) != 0)
232                         return -1;
233                 break;
234
235         default:
236                 errno = EINVAL;
237                 return -1;
238         }
239
240         int family;
241         if (Mono_Posix_FromUnixAddressFamily (source->sa_family, &family) != 0)
242                 return -1;
243         ((struct sockaddr*) destination)->sa_family = family;
244
245         return 0;
246 }
247
248 int
249 Mono_Posix_ToSockaddr (void* source, gint64 size, struct Mono_Posix__SockaddrHeader* destination)
250 {
251         struct Mono_Posix__SockaddrDynamic* destination_dyn;
252
253         if (!destination)
254                 return 0;
255
256         switch (destination->type) {
257         case Mono_Posix_SockaddrType_Sockaddr:
258                 if (size < offsetof (struct sockaddr, sa_family) + sizeof (sa_family_t)) {
259                         errno = ENOBUFS;
260                         return -1;
261                 }
262                 break;
263
264         case Mono_Posix_SockaddrType_SockaddrStorage:
265                 destination_dyn = ((struct Mono_Posix__SockaddrDynamic*) destination);
266                 if (size > destination_dyn->len) {
267                         errno = ENOBUFS;
268                         return -1;
269                 }
270                 destination_dyn->len = size;
271                 break;
272
273         case Mono_Posix_SockaddrType_SockaddrUn:
274                 destination_dyn = ((struct Mono_Posix__SockaddrDynamic*) destination);
275                 if (size - offsetof (struct sockaddr_un, sun_path) > destination_dyn->len) {
276                         errno = ENOBUFS;
277                         return -1;
278                 }
279                 destination_dyn->len = size - offsetof (struct sockaddr_un, sun_path);
280                 memcpy (destination_dyn->data, ((struct sockaddr_un*) source)->sun_path, size);
281                 break;
282
283         case Mono_Posix_SockaddrType_SockaddrIn:
284                 if (size != sizeof (struct sockaddr_in)) {
285                         errno = ENOBUFS;
286                         return -1;
287                 }
288                 if (Mono_Posix_ToSockaddrIn ((struct sockaddr_in*) source, (struct Mono_Posix_SockaddrIn*) destination) != 0)
289                         return -1;
290                 break;
291
292         case Mono_Posix_SockaddrType_SockaddrIn6:
293                 if (size != sizeof (struct sockaddr_in6)) {
294                         errno = ENOBUFS;
295                         return -1;
296                 }
297                 if (Mono_Posix_ToSockaddrIn6 ((struct sockaddr_in6*) source, (struct Mono_Posix_SockaddrIn6*) destination) != 0)
298                         return -1;
299                 break;
300
301         default:
302                 errno = EINVAL;
303                 return -1;
304         }
305
306         if (Mono_Posix_ToUnixAddressFamily (((struct sockaddr*) source)->sa_family, &destination->sa_family) != 0)
307                 destination->sa_family = Mono_Posix_UnixAddressFamily_Unknown;
308
309         return 0;
310 }
311
312 // Macro for allocating space for the native sockaddr_* structure
313 // Must be a macro because it is using alloca()
314
315 #define ALLOC_SOCKADDR                                                  \
316     socklen_t addrlen;                                                  \
317     struct sockaddr* addr;                                              \
318     gboolean need_free = 0;                                             \
319                                                                         \
320     if (get_addrlen (address, &addrlen) != 0)                           \
321         return -1;                                                      \
322     if (address == NULL) {                                              \
323         addr = NULL;                                                    \
324     } else if (address->type == Mono_Posix_SockaddrType_SockaddrStorage) { \
325         addr = (struct sockaddr*) ((struct Mono_Posix__SockaddrDynamic*) address)->data; \
326     } else if (address->type == Mono_Posix_SockaddrType_SockaddrUn) { \
327         /* Use alloca() for up to 2048 bytes, use malloc() otherwise */ \
328         need_free = addrlen > 2048;                                     \
329         addr = need_free ? malloc (addrlen) : alloca (addrlen);         \
330         if (!addr)                                                      \
331             return -1;                                                  \
332     } else {                                                            \
333         addr = alloca (addrlen);                                        \
334     }
335
336
337 int
338 Mono_Posix_Syscall_bind (int socket, struct Mono_Posix__SockaddrHeader* address)
339 {
340         int r;
341
342         ALLOC_SOCKADDR
343         if (Mono_Posix_FromSockaddr (address, addr) != 0) {
344                 if (need_free)
345                         free (addr);
346                 return -1;
347         }
348
349         r = bind (socket, addr, addrlen);
350
351         if (need_free)
352                 free (addr);
353
354         return r;
355 }
356
357 int
358 Mono_Posix_Syscall_connect (int socket, struct Mono_Posix__SockaddrHeader* address)
359 {
360         int r;
361
362         ALLOC_SOCKADDR
363         if (Mono_Posix_FromSockaddr (address, addr) != 0) {
364                 if (need_free)
365                         free (addr);
366                 return -1;
367         }
368
369         r = connect (socket, addr, addrlen);
370
371         if (need_free)
372                 free (addr);
373
374         return r;
375 }
376
377 int
378 Mono_Posix_Syscall_accept (int socket, struct Mono_Posix__SockaddrHeader* address)
379 {
380         int r;
381
382         ALLOC_SOCKADDR
383
384         r = accept (socket, addr, &addrlen);
385
386         if (r != -1 && Mono_Posix_ToSockaddr (addr, addrlen, address) != 0) {
387                 close (r);
388                 r = -1;
389         }
390
391         if (need_free)
392                 free (addr);
393
394         return r;
395 }
396
397 int
398 Mono_Posix_Syscall_accept4 (int socket, struct Mono_Posix__SockaddrHeader* address, int flags)
399 {
400 #ifdef HAVE_ACCEPT4
401         int r;
402
403         ALLOC_SOCKADDR
404
405         r = accept4 (socket, addr, &addrlen, flags);
406
407         if (r != -1 && Mono_Posix_ToSockaddr (addr, addrlen, address) != 0) {
408                 close (r);
409                 r = -1;
410         }
411
412         if (need_free)
413                 free (addr);
414
415         return r;
416 #else
417         errno = EINVAL;
418         return -1;
419 #endif
420 }
421
422 int
423 Mono_Posix_Syscall_getpeername (int socket, struct Mono_Posix__SockaddrHeader* address)
424 {
425         int r;
426
427         ALLOC_SOCKADDR
428
429         r = getpeername (socket, addr, &addrlen);
430
431         if (r != -1 && Mono_Posix_ToSockaddr (addr, addrlen, address) != 0)
432                 r = -1;
433
434         if (need_free)
435                 free (addr);
436
437         return r;
438 }
439
440 int
441 Mono_Posix_Syscall_getsockname (int socket, struct Mono_Posix__SockaddrHeader* address)
442 {
443         int r;
444
445         ALLOC_SOCKADDR
446
447         r = getsockname (socket, addr, &addrlen);
448
449         if (r != -1 && Mono_Posix_ToSockaddr (addr, addrlen, address) != 0)
450                 r = -1;
451
452         if (need_free)
453                 free (addr);
454
455         return r;
456 }
457
458 gint64
459 Mono_Posix_Syscall_recv (int socket, void* message, guint64 length, int flags)
460 {
461         mph_return_if_size_t_overflow (length);
462
463         return recv (socket, message, length, flags);
464 }
465
466 gint64
467 Mono_Posix_Syscall_send (int socket, void* message, guint64 length, int flags)
468 {
469         mph_return_if_size_t_overflow (length);
470
471         return send (socket, message, length, flags);
472 }
473
474 gint64
475 Mono_Posix_Syscall_recvfrom (int socket, void* buffer, guint64 length, int flags, struct Mono_Posix__SockaddrHeader* address)
476 {
477         int r;
478
479         mph_return_if_size_t_overflow (length);
480
481         ALLOC_SOCKADDR
482
483         r = recvfrom (socket, buffer, length, flags, addr, &addrlen);
484
485         if (r != -1 && Mono_Posix_ToSockaddr (addr, addrlen, address) != 0)
486                 r = -1;
487
488         if (need_free)
489                 free (addr);
490
491         return r;
492 }
493
494 gint64
495 Mono_Posix_Syscall_sendto (int socket, void* message, guint64 length, int flags, struct Mono_Posix__SockaddrHeader* address)
496 {
497         int r;
498
499         mph_return_if_size_t_overflow (length);
500
501         ALLOC_SOCKADDR
502         if (Mono_Posix_FromSockaddr (address, addr) != 0) {
503                 if (need_free)
504                         free (addr);
505                 return -1;
506         }
507
508         r = sendto (socket, message, length, flags, addr, addrlen);
509
510         if (need_free)
511                 free (addr);
512
513         return r;
514 }
515
516 // vim: noexpandtab
517 // Local Variables: 
518 // tab-width: 4
519 // c-basic-offset: 4
520 // indent-tabs-mode: t
521 // End: