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