sockin_user.c revision 1.3 1 /* $NetBSD: sockin_user.c,v 1.3 2019/01/27 02:08:50 pgoyette Exp $ */
2
3 /*
4 * Copyright (c) 2008 Antti Kantee. All Rights Reserved.
5 *
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
8 * are met:
9 * 1. Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer.
11 * 2. Redistributions in binary form must reproduce the above copyright
12 * notice, this list of conditions and the following disclaimer in the
13 * documentation and/or other materials provided with the distribution.
14 *
15 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS
16 * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
17 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
18 * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
19 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
20 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
21 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
22 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
23 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
24 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
25 * SUCH DAMAGE.
26 */
27
28 #include <sys/cdefs.h>
29 __KERNEL_RCSID(0, "$NetBSD: sockin_user.c,v 1.3 2019/01/27 02:08:50 pgoyette Exp $");
30
31 /* for struct msghdr content visibility */
32 #define _XOPEN_SOURCE 4
33 #define _XOPEN_SOURCE_EXTENDED 1
34
35 #ifndef _KERNEL
36 #include <sys/types.h>
37 #include <sys/socket.h>
38
39 #include <errno.h>
40 #include <poll.h>
41 #include <stdlib.h>
42 #include <string.h>
43 #include <stdint.h>
44
45 #include <rump/rumpuser_component.h>
46 #include <rump/rumpdefs.h>
47
48 #include "sockin_user.h"
49
50 #define seterror(_v_) if ((_v_) == -1) rv = errno; else rv = 0;
51
52 #ifndef __arraycount
53 #define __arraycount(a) (sizeof(a) / sizeof(*a))
54 #endif
55
56 #ifndef __UNCONST
57 #define __UNCONST(a) ((void*)(const void*)a)
58 #endif
59
60 #include <netinet/in.h>
61 #include <netinet/tcp.h>
62 #include <netinet/udp.h>
63
64
65 static int translate_so_sockopt(int);
66 static int translate_ip_sockopt(int);
67 static int translate_tcp_sockopt(int);
68 static int translate_domain(int);
69
70 #define translate(_a_) case RUMP_##_a_: return _a_
71 static int
72 translate_so_sockopt(int lopt)
73 {
74
75 switch (lopt) {
76 translate(SO_DEBUG);
77 #ifndef SO_REUSEPORT
78 case RUMP_SO_REUSEPORT: return SO_REUSEADDR;
79 #else
80 translate(SO_REUSEPORT);
81 #endif
82 translate(SO_TYPE);
83 translate(SO_ERROR);
84 translate(SO_DONTROUTE);
85 translate(SO_BROADCAST);
86 translate(SO_SNDBUF);
87 translate(SO_RCVBUF);
88 translate(SO_KEEPALIVE);
89 translate(SO_OOBINLINE);
90 translate(SO_LINGER);
91 default: return -1;
92 }
93 }
94
95 static int
96 translate_ip_sockopt(int lopt)
97 {
98
99 switch (lopt) {
100 translate(IP_TOS);
101 translate(IP_TTL);
102 translate(IP_HDRINCL);
103 translate(IP_MULTICAST_TTL);
104 translate(IP_MULTICAST_LOOP);
105 translate(IP_MULTICAST_IF);
106 translate(IP_ADD_MEMBERSHIP);
107 translate(IP_DROP_MEMBERSHIP);
108 default: return -1;
109 }
110 }
111
112 static int
113 translate_tcp_sockopt(int lopt)
114 {
115
116 switch (lopt) {
117 translate(TCP_NODELAY);
118 translate(TCP_MAXSEG);
119 default: return -1;
120 }
121 }
122
123 static int
124 translate_domain(int domain)
125 {
126
127 switch (domain) {
128 translate(AF_INET);
129 translate(AF_INET6);
130 default: return AF_UNSPEC;
131 }
132 }
133
134 #undef translate
135
136 static void
137 translate_sockopt(int *levelp, int *namep)
138 {
139 int level, name;
140
141 level = *levelp;
142 name = *namep;
143
144 switch (level) {
145 case RUMP_SOL_SOCKET:
146 level = SOL_SOCKET;
147 name = translate_so_sockopt(name);
148 break;
149 case RUMP_IPPROTO_IP:
150 #ifdef SOL_IP
151 level = SOL_IP;
152 #else
153 level = IPPROTO_IP;
154 #endif
155 name = translate_ip_sockopt(name);
156 break;
157 case RUMP_IPPROTO_TCP:
158 #ifdef SOL_TCP
159 level = SOL_TCP;
160 #else
161 level = IPPROTO_TCP;
162 #endif
163 name = translate_tcp_sockopt(name);
164 break;
165 case RUMP_IPPROTO_UDP:
166 #ifdef SOL_UDP
167 level = SOL_UDP;
168 #else
169 level = IPPROTO_UDP;
170 #endif
171 name = -1;
172 break;
173 default:
174 level = -1;
175 }
176 *levelp = level;
177 *namep = name;
178 }
179
180 #ifndef __NetBSD__
181 static const struct {
182 int bfl;
183 int lfl;
184 } bsd_to_native_msg_flags_[] = {
185 {RUMP_MSG_OOB, MSG_OOB},
186 {RUMP_MSG_PEEK, MSG_PEEK},
187 {RUMP_MSG_DONTROUTE, MSG_DONTROUTE},
188 {RUMP_MSG_EOR, MSG_EOR},
189 {RUMP_MSG_TRUNC, MSG_TRUNC},
190 {RUMP_MSG_CTRUNC, MSG_CTRUNC},
191 {RUMP_MSG_WAITALL, MSG_WAITALL},
192 {RUMP_MSG_DONTWAIT, MSG_DONTWAIT},
193
194 /* might be better to always set NOSIGNAL ... */
195 #ifdef MSG_NOSIGNAL
196 {RUMP_MSG_NOSIGNAL, MSG_NOSIGNAL},
197 #endif
198 };
199
200 static int native_to_bsd_msg_flags(int);
201
202 static int
203 native_to_bsd_msg_flags(int lflag)
204 {
205 unsigned int i;
206 int bfl, lfl;
207 int bflag = 0;
208
209 if (lflag == 0)
210 return (0);
211
212 for(i = 0; i < __arraycount(bsd_to_native_msg_flags_); i++) {
213 bfl = bsd_to_native_msg_flags_[i].bfl;
214 lfl = bsd_to_native_msg_flags_[i].lfl;
215
216 if (lflag & lfl) {
217 lflag ^= lfl;
218 bflag |= bfl;
219 }
220 }
221 if (lflag != 0)
222 return (-1);
223
224 return (bflag);
225 }
226
227 static int
228 bsd_to_native_msg_flags(int bflag)
229 {
230 unsigned int i;
231 int lflag = 0;
232
233 if (bflag == 0)
234 return (0);
235
236 for(i = 0; i < __arraycount(bsd_to_native_msg_flags_); i++) {
237 if (bflag & bsd_to_native_msg_flags_[i].bfl)
238 lflag |= bsd_to_native_msg_flags_[i].lfl;
239 }
240
241 return (lflag);
242 }
243 #endif
244
245 struct rump_sockaddr {
246 uint8_t sa_len; /* total length */
247 uint8_t sa_family; /* address family */
248 char sa_data[14]; /* actually longer; address value */
249 };
250
251 struct rump_msghdr {
252 void *msg_name; /* optional address */
253 uint32_t msg_namelen; /* size of address */
254 struct iovec *msg_iov; /* scatter/gather array */
255 int msg_iovlen; /* # elements in msg_iov */
256 void *msg_control; /* ancillary data, see below */
257 uint32_t msg_controllen; /* ancillary data buffer len */
258 int msg_flags; /* flags on received message */
259 };
260
261 static struct sockaddr *translate_sockaddr(const struct sockaddr *,
262 uint32_t);
263 static void translate_sockaddr_back(const struct sockaddr *,
264 struct rump_sockaddr *, uint32_t len);
265 static struct msghdr *translate_msghdr(const struct rump_msghdr *, int *);
266 static void translate_msghdr_back(const struct msghdr *, struct rump_msghdr *);
267
268 #if defined(__NetBSD__)
269 static struct sockaddr *
270 translate_sockaddr(const struct sockaddr *addr, uint32_t len)
271 {
272
273 return (struct sockaddr *)__UNCONST(addr);
274 }
275
276 static void
277 translate_sockaddr_back(const struct sockaddr *laddr,
278 struct rump_sockaddr *baddr, uint32_t len)
279 {
280
281 return;
282 }
283
284 static struct msghdr *
285 translate_msghdr(const struct rump_msghdr *bmsg, int *flags)
286 {
287
288 return (struct msghdr *)__UNCONST(bmsg);
289 }
290
291 static void
292 translate_msghdr_back(const struct msghdr *lmsg, struct rump_msghdr *bmsg)
293 {
294
295 return;
296 }
297
298 #else
299 static struct sockaddr *
300 translate_sockaddr(const struct sockaddr *addr, uint32_t len)
301 {
302 struct sockaddr *laddr;
303 const struct rump_sockaddr *baddr;
304
305 baddr = (const struct rump_sockaddr *)addr;
306 laddr = malloc(len);
307 if (laddr == NULL)
308 return NULL;
309 memcpy(laddr, baddr, len);
310 laddr->sa_family = translate_domain(baddr->sa_family);
311 /* No sa_len for Linux and SunOS */
312 #if defined(__DragonFly__) || defined(__FreeBSD__) || defined(__OpenBSD__)
313 laddr->sa_len = len;
314 #endif
315 return laddr;
316 }
317
318 #define translate_back(_a_) case _a_: return RUMP_##_a_
319 static int translate_domain_back(int);
320 static int
321 translate_domain_back(int domain)
322 {
323
324 switch (domain) {
325 translate_back(AF_INET);
326 translate_back(AF_INET6);
327 default: return RUMP_AF_UNSPEC;
328 }
329 }
330 #undef translate_back
331
332 static void
333 translate_sockaddr_back(const struct sockaddr *laddr,
334 struct rump_sockaddr *baddr,
335 uint32_t len)
336 {
337
338 if (baddr != NULL) {
339 memcpy(baddr, laddr, len);
340 baddr->sa_family = translate_domain_back(laddr->sa_family);
341 baddr->sa_len = len;
342 }
343 free(__UNCONST(laddr));
344 }
345
346 static struct msghdr *
347 translate_msghdr(const struct rump_msghdr *bmsg, int *flags)
348 {
349 struct msghdr *rv;
350
351 *flags = bsd_to_native_msg_flags(*flags);
352 if (*flags < 0)
353 *flags = 0;
354
355 rv = malloc(sizeof(*rv));
356 rv->msg_namelen = bmsg->msg_namelen;
357 rv->msg_iov = bmsg->msg_iov;
358 rv->msg_iovlen = bmsg->msg_iovlen;
359 rv->msg_control = bmsg->msg_control;
360 rv->msg_controllen = bmsg->msg_controllen;
361 rv->msg_flags = 0;
362
363 if (bmsg->msg_name != NULL) {
364 rv->msg_name = translate_sockaddr(bmsg->msg_name,
365 bmsg->msg_namelen);
366 if (rv->msg_name == NULL) {
367 free(rv);
368 return NULL;
369 }
370 } else
371 rv->msg_name = NULL;
372 return rv;
373 }
374
375 static void
376 translate_msghdr_back(const struct msghdr *lmsg, struct rump_msghdr *bmsg)
377 {
378
379 if (bmsg == NULL) {
380 if (lmsg->msg_name != NULL)
381 free(lmsg->msg_name);
382 free(__UNCONST(lmsg));
383 return;
384 }
385 bmsg->msg_namelen = lmsg->msg_namelen;
386 bmsg->msg_iov = lmsg->msg_iov;
387 bmsg->msg_iovlen = lmsg->msg_iovlen;
388 bmsg->msg_control = lmsg->msg_control;
389 bmsg->msg_controllen = lmsg->msg_controllen;
390 bmsg->msg_flags = native_to_bsd_msg_flags(lmsg->msg_flags);
391
392 if (lmsg->msg_name != NULL)
393 translate_sockaddr_back(lmsg->msg_name, bmsg->msg_name,
394 bmsg->msg_namelen);
395 else
396 bmsg->msg_name = NULL;
397
398 free(__UNCONST(lmsg));
399 }
400 #endif
401
402 int
403 rumpcomp_sockin_socket(int domain, int type, int proto, int *s)
404 {
405 void *cookie;
406 int rv;
407
408 domain = translate_domain(domain);
409
410 cookie = rumpuser_component_unschedule();
411 *s = socket(domain, type, proto);
412 seterror(*s);
413 rumpuser_component_schedule(cookie);
414
415 return rumpuser_component_errtrans(rv);
416 }
417
418 int
419 rumpcomp_sockin_sendmsg(int s, const struct msghdr *msg, int flags, size_t *snd)
420 {
421 void *cookie;
422 ssize_t nn;
423 int rv;
424
425 msg = translate_msghdr((struct rump_msghdr *)msg, &flags);
426
427 cookie = rumpuser_component_unschedule();
428 nn = sendmsg(s, msg, flags);
429 seterror(nn);
430 *snd = (size_t)nn;
431 rumpuser_component_schedule(cookie);
432
433 translate_msghdr_back(msg, NULL);
434
435 return rumpuser_component_errtrans(rv);
436 }
437
438 int
439 rumpcomp_sockin_recvmsg(int s, struct msghdr *msg, int flags, size_t *rcv)
440 {
441 void *cookie;
442 ssize_t nn;
443 int rv;
444 struct rump_msghdr *saveptr;
445
446 saveptr = (struct rump_msghdr *)msg;
447 msg = translate_msghdr(saveptr, &flags);
448
449 cookie = rumpuser_component_unschedule();
450 nn = recvmsg(s, msg, flags);
451 seterror(nn);
452 *rcv = (size_t)nn;
453 rumpuser_component_schedule(cookie);
454
455 translate_msghdr_back(msg, saveptr);
456
457 return rumpuser_component_errtrans(rv);
458 }
459
460 int
461 rumpcomp_sockin_connect(int s, const struct sockaddr *name, int len)
462 {
463 void *cookie;
464 int rv;
465
466 name = translate_sockaddr(name, len);
467
468 cookie = rumpuser_component_unschedule();
469 rv = connect(s, name, (socklen_t)len);
470 seterror(rv);
471 rumpuser_component_schedule(cookie);
472
473 translate_sockaddr_back(name, NULL, len);
474
475 return rumpuser_component_errtrans(rv);
476 }
477
478 int
479 rumpcomp_sockin_bind(int s, const struct sockaddr *name, int len)
480 {
481 void *cookie;
482 int rv;
483
484 name = translate_sockaddr(name, len);
485
486 cookie = rumpuser_component_unschedule();
487 rv = bind(s, name, (socklen_t)len);
488 seterror(rv);
489 rumpuser_component_schedule(cookie);
490
491 translate_sockaddr_back(name, NULL, len);
492
493 return rumpuser_component_errtrans(rv);
494 }
495
496 int
497 rumpcomp_sockin_accept(int s, struct sockaddr *name, int *lenp, int *s2)
498 {
499 void *cookie;
500 int rv;
501 struct rump_sockaddr *saveptr;
502
503 saveptr = (struct rump_sockaddr *)name;
504 name = translate_sockaddr(name, *lenp);
505
506 cookie = rumpuser_component_unschedule();
507 *s2 = accept(s, name, (socklen_t *)lenp);
508 seterror(*s2);
509 rumpuser_component_schedule(cookie);
510
511 translate_sockaddr_back(name, saveptr, *lenp);
512
513 return rumpuser_component_errtrans(rv);
514 }
515
516 int
517 rumpcomp_sockin_listen(int s, int backlog)
518 {
519 void *cookie;
520 int rv;
521
522 cookie = rumpuser_component_unschedule();
523 rv = listen(s, backlog);
524 seterror(rv);
525 rumpuser_component_schedule(cookie);
526
527 return rumpuser_component_errtrans(rv);
528 }
529
530 int
531 rumpcomp_sockin_getname(int s, struct sockaddr *so, int *lenp,
532 enum rumpcomp_sockin_getnametype which)
533 {
534 socklen_t slen = *lenp;
535 int rv;
536 struct rump_sockaddr *saveptr;
537
538 saveptr = (struct rump_sockaddr *)so;
539 so = translate_sockaddr(so, *lenp);
540
541 if (which == RUMPCOMP_SOCKIN_SOCKNAME)
542 rv = getsockname(s, so, &slen);
543 else
544 rv = getpeername(s, so, &slen);
545
546 seterror(rv);
547 translate_sockaddr_back(so, saveptr, *lenp);
548
549 *lenp = slen;
550
551 return rumpuser_component_errtrans(rv);
552 }
553
554 int
555 rumpcomp_sockin_setsockopt(int s, int level, int name,
556 const void *data, int dlen)
557 {
558 socklen_t slen = dlen;
559 int rv;
560
561 translate_sockopt(&level, &name);
562 if (level == -1 || name == -1) {
563 #ifdef SETSOCKOPT_STRICT
564 errno = EINVAL;
565 rv = -1;
566 #else
567 rv = 0;
568 #endif
569 } else
570 rv = setsockopt(s, level, name, data, slen);
571
572 seterror(rv);
573
574 return rumpuser_component_errtrans(rv);
575 }
576
577 int
578 rumpcomp_sockin_poll(struct pollfd *fds, int nfds, int timeout, int *nready)
579 {
580 void *cookie;
581 int rv;
582
583 cookie = rumpuser_component_unschedule();
584 *nready = poll(fds, (nfds_t)nfds, timeout);
585 seterror(*nready);
586 rumpuser_component_schedule(cookie);
587
588 return rumpuser_component_errtrans(rv);
589 }
590 #endif
591