rumpclient.c revision 1.18 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