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