1 /* $NetBSD: rumpclient.c,v 1.22 2011/02/05 12:38:19 pooka Exp $ */ 2 3 /* 4 * Copyright (c) 2010, 2011 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 /* 29 * Client side routines for rump syscall proxy. 30 */ 31 32 #include <sys/cdefs.h> 33 __RCSID("$NetBSD"); 34 35 #include <sys/param.h> 36 #include <sys/event.h> 37 #include <sys/mman.h> 38 #include <sys/socket.h> 39 40 #include <arpa/inet.h> 41 #include <netinet/in.h> 42 #include <netinet/tcp.h> 43 44 #include <assert.h> 45 #include <dlfcn.h> 46 #include <errno.h> 47 #include <fcntl.h> 48 #include <link.h> 49 #include <poll.h> 50 #include <pthread.h> 51 #include <signal.h> 52 #include <stdarg.h> 53 #include <stdbool.h> 54 #include <stdio.h> 55 #include <stdlib.h> 56 #include <string.h> 57 #include <unistd.h> 58 59 #include <rump/rumpclient.h> 60 61 #define HOSTOPS 62 int (*host_socket)(int, int, int); 63 int (*host_close)(int); 64 int (*host_connect)(int, const struct sockaddr *, socklen_t); 65 int (*host_fcntl)(int, int, ...); 66 int (*host_poll)(struct pollfd *, nfds_t, int); 67 ssize_t (*host_read)(int, void *, size_t); 68 ssize_t (*host_sendto)(int, const void *, size_t, int, 69 const struct sockaddr *, socklen_t); 70 int (*host_setsockopt)(int, int, int, const void *, socklen_t); 71 72 int (*host_kqueue)(void); 73 int (*host_kevent)(int, const struct kevent *, size_t, 74 struct kevent *, size_t, const struct timespec *); 75 76 #include "sp_common.c" 77 78 static struct spclient clispc = { 79 .spc_fd = -1, 80 }; 81 82 static int kq = -1; 83 static sigset_t fullset; 84 85 static int doconnect(bool); 86 static int handshake_req(struct spclient *, uint32_t *, int, bool); 87 88 time_t retrytimo = RUMPCLIENT_RETRYCONN_ONCE; 89 90 static int 91 send_with_recon(struct spclient *spc, const void *data, size_t dlen) 92 { 93 struct timeval starttime, curtime; 94 time_t prevreconmsg; 95 unsigned reconretries; 96 int rv; 97 98 for (prevreconmsg = 0, reconretries = 0;;) { 99 rv = dosend(spc, data, dlen); 100 if (__predict_false(rv == ENOTCONN || rv == EBADF)) { 101 /* no persistent connections */ 102 if (retrytimo == 0) 103 break; 104 105 if (!prevreconmsg) { 106 prevreconmsg = time(NULL); 107 gettimeofday(&starttime, NULL); 108 } 109 if (reconretries == 1) { 110 if (retrytimo == RUMPCLIENT_RETRYCONN_ONCE) { 111 rv = ENOTCONN; 112 break; 113 } 114 fprintf(stderr, "rump_sp: connection to " 115 "kernel lost, trying to reconnect ...\n"); 116 } else if (time(NULL) - prevreconmsg > 120) { 117 fprintf(stderr, "rump_sp: still trying to " 118 "reconnect ...\n"); 119 prevreconmsg = time(NULL); 120 } 121 122 /* check that we aren't over the limit */ 123 if (retrytimo > 0) { 124 struct timeval tmp; 125 126 gettimeofday(&curtime, NULL); 127 timersub(&curtime, &starttime, &tmp); 128 if (tmp.tv_sec >= retrytimo) { 129 fprintf(stderr, "rump_sp: reconnect " 130 "failed, %lld second timeout\n", 131 (long long)retrytimo); 132 return ENOTCONN; 133 } 134 } 135 136 /* adhoc backoff timer */ 137 if (reconretries < 10) { 138 usleep(100000 * reconretries); 139 } else { 140 sleep(MIN(10, reconretries-9)); 141 } 142 reconretries++; 143 144 if ((rv = doconnect(false)) != 0) 145 continue; 146 if ((rv = handshake_req(&clispc, NULL, 0, true)) != 0) 147 continue; 148 149 /* 150 * ok, reconnect succesful. we need to return to 151 * the upper layer to get the entire PDU resent. 152 */ 153 if (reconretries != 1) 154 fprintf(stderr, "rump_sp: reconnected!\n"); 155 rv = EAGAIN; 156 break; 157 } else { 158 _DIAGASSERT(errno != EAGAIN); 159 break; 160 } 161 } 162 163 return rv; 164 } 165 166 static int 167 cliwaitresp(struct spclient *spc, struct respwait *rw, sigset_t *mask, 168 bool keeplock) 169 { 170 uint64_t mygen; 171 bool imalive = true; 172 173 pthread_mutex_lock(&spc->spc_mtx); 174 if (!keeplock) 175 sendunlockl(spc); 176 mygen = spc->spc_generation; 177 178 rw->rw_error = 0; 179 while (!rw->rw_done && rw->rw_error == 0) { 180 if (__predict_false(spc->spc_generation != mygen || !imalive)) 181 break; 182 183 /* are we free to receive? */ 184 if (spc->spc_istatus == SPCSTATUS_FREE) { 185 struct kevent kev[8]; 186 int gotresp, dosig, rv, i; 187 188 spc->spc_istatus = SPCSTATUS_BUSY; 189 pthread_mutex_unlock(&spc->spc_mtx); 190 191 dosig = 0; 192 for (gotresp = 0; !gotresp; ) { 193 switch (readframe(spc)) { 194 case 0: 195 rv = host_kevent(kq, NULL, 0, 196 kev, __arraycount(kev), NULL); 197 198 /* 199 * XXX: don't know how this can 200 * happen (timeout cannot expire 201 * since there isn't one), but 202 * it does happen 203 */ 204 if (__predict_false(rv == 0)) 205 continue; 206 207 for (i = 0; i < rv; i++) { 208 if (kev[i].filter 209 == EVFILT_SIGNAL) 210 dosig++; 211 } 212 if (dosig) 213 goto cleanup; 214 215 continue; 216 case -1: 217 imalive = false; 218 goto cleanup; 219 default: 220 break; 221 } 222 223 switch (spc->spc_hdr.rsp_class) { 224 case RUMPSP_RESP: 225 case RUMPSP_ERROR: 226 kickwaiter(spc); 227 gotresp = spc->spc_hdr.rsp_reqno == 228 rw->rw_reqno; 229 break; 230 case RUMPSP_REQ: 231 handlereq(spc); 232 break; 233 default: 234 /* panic */ 235 break; 236 } 237 } 238 239 cleanup: 240 pthread_mutex_lock(&spc->spc_mtx); 241 if (spc->spc_istatus == SPCSTATUS_WANTED) 242 kickall(spc); 243 spc->spc_istatus = SPCSTATUS_FREE; 244 245 /* take one for the team */ 246 if (dosig) { 247 pthread_mutex_unlock(&spc->spc_mtx); 248 pthread_sigmask(SIG_SETMASK, mask, NULL); 249 pthread_sigmask(SIG_SETMASK, &fullset, NULL); 250 pthread_mutex_lock(&spc->spc_mtx); 251 } 252 } else { 253 spc->spc_istatus = SPCSTATUS_WANTED; 254 pthread_cond_wait(&rw->rw_cv, &spc->spc_mtx); 255 } 256 } 257 TAILQ_REMOVE(&spc->spc_respwait, rw, rw_entries); 258 pthread_mutex_unlock(&spc->spc_mtx); 259 pthread_cond_destroy(&rw->rw_cv); 260 261 if (spc->spc_generation != mygen || !imalive) { 262 return ENOTCONN; 263 } 264 return rw->rw_error; 265 } 266 267 static int 268 syscall_req(struct spclient *spc, int sysnum, 269 const void *data, size_t dlen, void **resp) 270 { 271 struct rsp_hdr rhdr; 272 struct respwait rw; 273 sigset_t omask; 274 int rv; 275 276 rhdr.rsp_len = sizeof(rhdr) + dlen; 277 rhdr.rsp_class = RUMPSP_REQ; 278 rhdr.rsp_type = RUMPSP_SYSCALL; 279 rhdr.rsp_sysnum = sysnum; 280 281 pthread_sigmask(SIG_SETMASK, &fullset, &omask); 282 do { 283 putwait(spc, &rw, &rhdr); 284 if ((rv = send_with_recon(spc, &rhdr, sizeof(rhdr))) != 0) { 285 unputwait(spc, &rw); 286 continue; 287 } 288 if ((rv = send_with_recon(spc, data, dlen)) != 0) { 289 unputwait(spc, &rw); 290 continue; 291 } 292 293 rv = cliwaitresp(spc, &rw, &omask, false); 294 if (rv == ENOTCONN) 295 rv = EAGAIN; 296 } while (rv == EAGAIN); 297 pthread_sigmask(SIG_SETMASK, &omask, NULL); 298 299 *resp = rw.rw_data; 300 return rv; 301 } 302 303 static int 304 handshake_req(struct spclient *spc, uint32_t *auth, int cancel, bool haslock) 305 { 306 struct handshake_fork rf; 307 struct rsp_hdr rhdr; 308 struct respwait rw; 309 sigset_t omask; 310 size_t bonus; 311 int rv; 312 313 if (auth) { 314 bonus = sizeof(rf); 315 } else { 316 bonus = strlen(getprogname())+1; 317 } 318 319 /* performs server handshake */ 320 rhdr.rsp_len = sizeof(rhdr) + bonus; 321 rhdr.rsp_class = RUMPSP_REQ; 322 rhdr.rsp_type = RUMPSP_HANDSHAKE; 323 if (auth) 324 rhdr.rsp_handshake = HANDSHAKE_FORK; 325 else 326 rhdr.rsp_handshake = HANDSHAKE_GUEST; 327 328 pthread_sigmask(SIG_SETMASK, &fullset, &omask); 329 if (haslock) 330 putwait_locked(spc, &rw, &rhdr); 331 else 332 putwait(spc, &rw, &rhdr); 333 rv = dosend(spc, &rhdr, sizeof(rhdr)); 334 if (auth) { 335 memcpy(rf.rf_auth, auth, AUTHLEN*sizeof(*auth)); 336 rf.rf_cancel = cancel; 337 rv = send_with_recon(spc, &rf, sizeof(rf)); 338 } else { 339 rv = dosend(spc, getprogname(), strlen(getprogname())+1); 340 } 341 if (rv || cancel) { 342 if (haslock) 343 unputwait_locked(spc, &rw); 344 else 345 unputwait(spc, &rw); 346 if (cancel) { 347 pthread_sigmask(SIG_SETMASK, &omask, NULL); 348 return rv; 349 } 350 } else { 351 rv = cliwaitresp(spc, &rw, &omask, haslock); 352 } 353 pthread_sigmask(SIG_SETMASK, &omask, NULL); 354 if (rv) 355 return rv; 356 357 rv = *(int *)rw.rw_data; 358 free(rw.rw_data); 359 360 return rv; 361 } 362 363 static int 364 prefork_req(struct spclient *spc, void **resp) 365 { 366 struct rsp_hdr rhdr; 367 struct respwait rw; 368 sigset_t omask; 369 int rv; 370 371 rhdr.rsp_len = sizeof(rhdr); 372 rhdr.rsp_class = RUMPSP_REQ; 373 rhdr.rsp_type = RUMPSP_PREFORK; 374 rhdr.rsp_error = 0; 375 376 pthread_sigmask(SIG_SETMASK, &fullset, &omask); 377 do { 378 putwait(spc, &rw, &rhdr); 379 rv = send_with_recon(spc, &rhdr, sizeof(rhdr)); 380 if (rv != 0) { 381 unputwait(spc, &rw); 382 continue; 383 } 384 385 rv = cliwaitresp(spc, &rw, &omask, false); 386 if (rv == ENOTCONN) 387 rv = EAGAIN; 388 } while (rv == EAGAIN); 389 pthread_sigmask(SIG_SETMASK, &omask, NULL); 390 391 *resp = rw.rw_data; 392 return rv; 393 } 394 395 /* 396 * prevent response code from deadlocking with reconnect code 397 */ 398 static int 399 resp_sendlock(struct spclient *spc) 400 { 401 int rv = 0; 402 403 pthread_mutex_lock(&spc->spc_mtx); 404 while (spc->spc_ostatus != SPCSTATUS_FREE) { 405 if (__predict_false(spc->spc_reconnecting)) { 406 rv = EBUSY; 407 goto out; 408 } 409 spc->spc_ostatus = SPCSTATUS_WANTED; 410 pthread_cond_wait(&spc->spc_cv, &spc->spc_mtx); 411 } 412 spc->spc_ostatus = SPCSTATUS_BUSY; 413 414 out: 415 pthread_mutex_unlock(&spc->spc_mtx); 416 return rv; 417 } 418 419 static void 420 send_copyin_resp(struct spclient *spc, uint64_t reqno, void *data, size_t dlen, 421 int wantstr) 422 { 423 struct rsp_hdr rhdr; 424 425 if (wantstr) 426 dlen = MIN(dlen, strlen(data)+1); 427 428 rhdr.rsp_len = sizeof(rhdr) + dlen; 429 rhdr.rsp_reqno = reqno; 430 rhdr.rsp_class = RUMPSP_RESP; 431 rhdr.rsp_type = RUMPSP_COPYIN; 432 rhdr.rsp_sysnum = 0; 433 434 if (resp_sendlock(spc) != 0) 435 return; 436 (void)dosend(spc, &rhdr, sizeof(rhdr)); 437 (void)dosend(spc, data, dlen); 438 sendunlock(spc); 439 } 440 441 static void 442 send_anonmmap_resp(struct spclient *spc, uint64_t reqno, void *addr) 443 { 444 struct rsp_hdr rhdr; 445 446 rhdr.rsp_len = sizeof(rhdr) + sizeof(addr); 447 rhdr.rsp_reqno = reqno; 448 rhdr.rsp_class = RUMPSP_RESP; 449 rhdr.rsp_type = RUMPSP_ANONMMAP; 450 rhdr.rsp_sysnum = 0; 451 452 if (resp_sendlock(spc) != 0) 453 return; 454 (void)dosend(spc, &rhdr, sizeof(rhdr)); 455 (void)dosend(spc, &addr, sizeof(addr)); 456 sendunlock(spc); 457 } 458 459 int 460 rumpclient_syscall(int sysnum, const void *data, size_t dlen, 461 register_t *retval) 462 { 463 struct rsp_sysresp *resp; 464 void *rdata; 465 int rv; 466 467 DPRINTF(("rumpsp syscall_req: syscall %d with %p/%zu\n", 468 sysnum, data, dlen)); 469 470 rv = syscall_req(&clispc, sysnum, data, dlen, &rdata); 471 if (rv) 472 return rv; 473 474 resp = rdata; 475 DPRINTF(("rumpsp syscall_resp: syscall %d error %d, rv: %d/%d\n", 476 sysnum, rv, resp->rsys_retval[0], resp->rsys_retval[1])); 477 478 memcpy(retval, &resp->rsys_retval, sizeof(resp->rsys_retval)); 479 rv = resp->rsys_error; 480 free(rdata); 481 482 return rv; 483 } 484 485 static void 486 handlereq(struct spclient *spc) 487 { 488 struct rsp_copydata *copydata; 489 struct rsp_hdr *rhdr = &spc->spc_hdr; 490 void *mapaddr; 491 size_t maplen; 492 int reqtype = spc->spc_hdr.rsp_type; 493 494 switch (reqtype) { 495 case RUMPSP_COPYIN: 496 case RUMPSP_COPYINSTR: 497 /*LINTED*/ 498 copydata = (struct rsp_copydata *)spc->spc_buf; 499 DPRINTF(("rump_sp handlereq: copyin request: %p/%zu\n", 500 copydata->rcp_addr, copydata->rcp_len)); 501 send_copyin_resp(spc, spc->spc_hdr.rsp_reqno, 502 copydata->rcp_addr, copydata->rcp_len, 503 reqtype == RUMPSP_COPYINSTR); 504 break; 505 case RUMPSP_COPYOUT: 506 case RUMPSP_COPYOUTSTR: 507 /*LINTED*/ 508 copydata = (struct rsp_copydata *)spc->spc_buf; 509 DPRINTF(("rump_sp handlereq: copyout request: %p/%zu\n", 510 copydata->rcp_addr, copydata->rcp_len)); 511 /*LINTED*/ 512 memcpy(copydata->rcp_addr, copydata->rcp_data, 513 copydata->rcp_len); 514 break; 515 case RUMPSP_ANONMMAP: 516 /*LINTED*/ 517 maplen = *(size_t *)spc->spc_buf; 518 mapaddr = mmap(NULL, maplen, PROT_READ|PROT_WRITE, 519 MAP_ANON, -1, 0); 520 if (mapaddr == MAP_FAILED) 521 mapaddr = NULL; 522 DPRINTF(("rump_sp handlereq: anonmmap: %p\n", mapaddr)); 523 send_anonmmap_resp(spc, spc->spc_hdr.rsp_reqno, mapaddr); 524 break; 525 case RUMPSP_RAISE: 526 DPRINTF(("rump_sp handlereq: raise sig %d\n", rhdr->rsp_signo)); 527 raise((int)rhdr->rsp_signo); 528 /* 529 * We most likely have signals blocked, but the signal 530 * will be handled soon enough when we return. 531 */ 532 break; 533 default: 534 printf("PANIC: INVALID TYPE %d\n", reqtype); 535 abort(); 536 break; 537 } 538 539 spcfreebuf(spc); 540 } 541 542 static unsigned ptab_idx; 543 static struct sockaddr *serv_sa; 544 545 static int 546 doconnect(bool noisy) 547 { 548 struct respwait rw; 549 struct rsp_hdr rhdr; 550 struct kevent kev[NSIG+1]; 551 char banner[MAXBANNER]; 552 struct pollfd pfd; 553 int s, error, flags, i; 554 ssize_t n; 555 556 if (kq != -1) 557 host_close(kq); 558 kq = -1; 559 s = -1; 560 561 if (clispc.spc_fd != -1) 562 host_close(clispc.spc_fd); 563 clispc.spc_fd = -1; 564 565 /* 566 * for reconnect, gate everyone out of the receiver code 567 */ 568 putwait_locked(&clispc, &rw, &rhdr); 569 570 pthread_mutex_lock(&clispc.spc_mtx); 571 clispc.spc_reconnecting = 1; 572 pthread_cond_broadcast(&clispc.spc_cv); 573 clispc.spc_generation++; 574 while (clispc.spc_istatus != SPCSTATUS_FREE) { 575 clispc.spc_istatus = SPCSTATUS_WANTED; 576 pthread_cond_wait(&rw.rw_cv, &clispc.spc_mtx); 577 } 578 kickall(&clispc); 579 580 /* 581 * we can release it already since we hold the 582 * send lock during reconnect 583 * XXX: assert it 584 */ 585 clispc.spc_istatus = SPCSTATUS_FREE; 586 pthread_mutex_unlock(&clispc.spc_mtx); 587 unputwait_locked(&clispc, &rw); 588 589 free(clispc.spc_buf); 590 clispc.spc_off = 0; 591 592 s = host_socket(parsetab[ptab_idx].domain, SOCK_STREAM, 0); 593 if (s == -1) 594 return -1; 595 596 pfd.fd = s; 597 pfd.events = POLLIN; 598 while (host_connect(s, serv_sa, (socklen_t)serv_sa->sa_len) == -1) { 599 if (errno == EINTR) 600 continue; 601 error = errno; 602 if (noisy) 603 fprintf(stderr, "rump_sp: client connect failed: %s\n", 604 strerror(errno)); 605 errno = error; 606 return -1; 607 } 608 609 if ((error = parsetab[ptab_idx].connhook(s)) != 0) { 610 error = errno; 611 if (noisy) 612 fprintf(stderr, "rump_sp: connect hook failed\n"); 613 errno = error; 614 return -1; 615 } 616 617 if ((n = host_read(s, banner, sizeof(banner)-1)) < 0) { 618 error = errno; 619 if (noisy) 620 fprintf(stderr, "rump_sp: failed to read banner\n"); 621 errno = error; 622 return -1; 623 } 624 625 if (banner[n-1] != '\n') { 626 if (noisy) 627 fprintf(stderr, "rump_sp: invalid banner\n"); 628 errno = EINVAL; 629 return -1; 630 } 631 banner[n] = '\0'; 632 /* parse the banner some day */ 633 634 flags = host_fcntl(s, F_GETFL, 0); 635 if (host_fcntl(s, F_SETFL, flags | O_NONBLOCK) == -1) { 636 if (noisy) 637 fprintf(stderr, "rump_sp: socket fd NONBLOCK: %s\n", 638 strerror(errno)); 639 errno = EINVAL; 640 return -1; 641 } 642 clispc.spc_fd = s; 643 clispc.spc_state = SPCSTATE_RUNNING; 644 clispc.spc_reconnecting = 0; 645 646 /* setup kqueue, we want all signals and the fd */ 647 if ((kq = host_kqueue()) == -1) { 648 error = errno; 649 if (noisy) 650 fprintf(stderr, "rump_sp: cannot setup kqueue"); 651 errno = error; 652 return -1; 653 } 654 655 for (i = 0; i < NSIG; i++) { 656 EV_SET(&kev[i], i+1, EVFILT_SIGNAL, EV_ADD|EV_ENABLE, 0, 0, 0); 657 } 658 EV_SET(&kev[NSIG], clispc.spc_fd, 659 EVFILT_READ, EV_ADD|EV_ENABLE, 0, 0, 0); 660 if (host_kevent(kq, kev, NSIG+1, NULL, 0, NULL) == -1) { 661 error = errno; 662 if (noisy) 663 fprintf(stderr, "rump_sp: kevent() failed"); 664 errno = error; 665 return -1; 666 } 667 668 return 0; 669 } 670 671 static int 672 doinit(void) 673 { 674 675 TAILQ_INIT(&clispc.spc_respwait); 676 pthread_mutex_init(&clispc.spc_mtx, NULL); 677 pthread_cond_init(&clispc.spc_cv, NULL); 678 679 return 0; 680 } 681 682 void *(*rumpclient_dlsym)(void *, const char *); 683 684 int 685 rumpclient_init() 686 { 687 char *p; 688 int error; 689 690 /* dlsym overrided by rumphijack? */ 691 if (!rumpclient_dlsym) 692 rumpclient_dlsym = dlsym; 693 694 /* 695 * sag mir, wo die symbol sind. zogen fort, der krieg beginnt. 696 * wann wird man je verstehen? wann wird man je verstehen? 697 */ 698 #define FINDSYM2(_name_,_syscall_) \ 699 if ((host_##_name_ = rumpclient_dlsym(RTLD_NEXT, \ 700 #_syscall_)) == NULL) \ 701 /* host_##_name_ = _syscall_ */; 702 #define FINDSYM(_name_) FINDSYM2(_name_,_name_) 703 FINDSYM2(socket,__socket30); 704 FINDSYM(close); 705 FINDSYM(connect); 706 FINDSYM(fcntl); 707 FINDSYM(poll); 708 FINDSYM(read); 709 FINDSYM(sendto); 710 FINDSYM(setsockopt); 711 FINDSYM(kqueue); 712 #if !__NetBSD_Prereq__(5,99,7) 713 FINDSYM(kevent); 714 #else 715 FINDSYM2(kevent,_sys___kevent50); 716 #endif 717 #undef FINDSYM 718 #undef FINDSY2 719 720 if ((p = getenv("RUMP_SERVER")) == NULL) { 721 errno = ENOENT; 722 return -1; 723 } 724 725 if ((error = parseurl(p, &serv_sa, &ptab_idx, 0)) != 0) { 726 errno = error; 727 return -1; 728 } 729 730 if (doinit() == -1) 731 return -1; 732 if (doconnect(true) == -1) 733 return -1; 734 735 error = handshake_req(&clispc, NULL, 0, false); 736 if (error) { 737 pthread_mutex_destroy(&clispc.spc_mtx); 738 pthread_cond_destroy(&clispc.spc_cv); 739 if (clispc.spc_fd != -1) 740 host_close(clispc.spc_fd); 741 errno = error; 742 return -1; 743 } 744 745 sigfillset(&fullset); 746 return 0; 747 } 748 749 struct rumpclient_fork { 750 uint32_t fork_auth[AUTHLEN]; 751 }; 752 753 struct rumpclient_fork * 754 rumpclient_prefork(void) 755 { 756 struct rumpclient_fork *rpf; 757 void *resp; 758 int rv; 759 760 rpf = malloc(sizeof(*rpf)); 761 if (rpf == NULL) 762 return NULL; 763 764 if ((rv = prefork_req(&clispc, &resp)) != 0) { 765 free(rpf); 766 errno = rv; 767 return NULL; 768 } 769 770 memcpy(rpf->fork_auth, resp, sizeof(rpf->fork_auth)); 771 free(resp); 772 773 return rpf; 774 } 775 776 int 777 rumpclient_fork_init(struct rumpclient_fork *rpf) 778 { 779 int error; 780 781 memset(&clispc, 0, sizeof(clispc)); 782 clispc.spc_fd = -1; 783 kq = -1; 784 785 if (doinit() == -1) 786 return -1; 787 if (doconnect(false) == -1) 788 return -1; 789 790 error = handshake_req(&clispc, rpf->fork_auth, 0, false); 791 if (error) { 792 pthread_mutex_destroy(&clispc.spc_mtx); 793 pthread_cond_destroy(&clispc.spc_cv); 794 errno = error; 795 return -1; 796 } 797 798 return 0; 799 } 800 801 void 802 rumpclient_setconnretry(time_t timeout) 803 { 804 805 if (timeout < RUMPCLIENT_RETRYCONN_ONCE) 806 return; /* gigo */ 807 808 retrytimo = timeout; 809 } 810