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