Home | History | Annotate | Line # | Download | only in libsockin
sockin_user.c revision 1.1.6.2
      1 /*	$NetBSD: sockin_user.c,v 1.1.6.2 2014/05/22 11:41:17 yamt 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
     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
     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
    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
    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
    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
    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
    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 *
    267 translate_sockaddr(const struct sockaddr *addr, uint32_t len)
    268 {
    269 
    270 	return (struct sockaddr *)__UNCONST(addr);
    271 }
    272 
    273 static void
    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 *
    282 translate_msghdr(const struct rump_msghdr *bmsg, int *flags)
    283 {
    284 
    285 	return (struct msghdr *)__UNCONST(bmsg);
    286 }
    287 
    288 static void
    289 translate_msghdr_back(const struct msghdr *lmsg, struct rump_msghdr *bmsg)
    290 {
    291 
    292 	return;
    293 }
    294 
    295 #else
    296 static struct sockaddr *
    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
    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
    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 *
    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
    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
    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
    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
    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
    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
    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
    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
    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
    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
    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
    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