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 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