rumpuser_sp.c revision 1.26 1 /* $NetBSD: rumpuser_sp.c,v 1.26 2010/12/16 12:38:20 pooka Exp $ */
2
3 /*
4 * Copyright (c) 2010 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 * Sysproxy routines. This provides system RPC support over host sockets.
30 * The most notable limitation is that the client and server must share
31 * the same ABI. This does not mean that they have to be the same
32 * machine or that they need to run the same version of the host OS,
33 * just that they must agree on the data structures. This even *might*
34 * work correctly from one hardware architecture to another.
35 */
36
37 #include <sys/cdefs.h>
38 __RCSID("$NetBSD: rumpuser_sp.c,v 1.26 2010/12/16 12:38:20 pooka Exp $");
39
40 #include <sys/types.h>
41 #include <sys/atomic.h>
42 #include <sys/mman.h>
43 #include <sys/socket.h>
44
45 #include <arpa/inet.h>
46 #include <netinet/in.h>
47 #include <netinet/tcp.h>
48
49 #include <assert.h>
50 #include <errno.h>
51 #include <fcntl.h>
52 #include <poll.h>
53 #include <pthread.h>
54 #include <stdarg.h>
55 #include <stdio.h>
56 #include <stdlib.h>
57 #include <string.h>
58 #include <unistd.h>
59
60 #include <rump/rumpuser.h>
61 #include "rumpuser_int.h"
62
63 #include "sp_common.c"
64
65 #ifndef MAXCLI
66 #define MAXCLI 256
67 #endif
68 #ifndef MAXWORKER
69 #define MAXWORKER 128
70 #endif
71 #ifndef IDLEWORKER
72 #define IDLEWORKER 16
73 #endif
74 int rumpsp_maxworker = MAXWORKER;
75 int rumpsp_idleworker = IDLEWORKER;
76
77 static struct pollfd pfdlist[MAXCLI];
78 static struct spclient spclist[MAXCLI];
79 static unsigned int disco;
80 static volatile int spfini;
81
82 static struct rumpuser_sp_ops spops;
83
84 static char banner[MAXBANNER];
85
86 #define PROTOMAJOR 0
87 #define PROTOMINOR 0
88
89 /*
90 * Manual wrappers, since librump does not have access to the
91 * user namespace wrapped interfaces.
92 */
93
94 static void
95 lwproc_switch(struct lwp *l)
96 {
97
98 spops.spop_schedule();
99 spops.spop_lwproc_switch(l);
100 spops.spop_unschedule();
101 }
102
103 static void
104 lwproc_release(void)
105 {
106
107 spops.spop_schedule();
108 spops.spop_lwproc_release();
109 spops.spop_unschedule();
110 }
111
112 static int
113 lwproc_newproc(struct spclient *spc)
114 {
115 int rv;
116
117 spops.spop_schedule();
118 rv = spops.spop_lwproc_newproc(spc);
119 spops.spop_unschedule();
120
121 return rv;
122 }
123
124 static int
125 lwproc_newlwp(pid_t pid)
126 {
127 int rv;
128
129 spops.spop_schedule();
130 rv = spops.spop_lwproc_newlwp(pid);
131 spops.spop_unschedule();
132
133 return rv;
134 }
135
136 static struct lwp *
137 lwproc_curlwp(void)
138 {
139 struct lwp *l;
140
141 spops.spop_schedule();
142 l = spops.spop_lwproc_curlwp();
143 spops.spop_unschedule();
144
145 return l;
146 }
147
148 static pid_t
149 lwproc_getpid(void)
150 {
151 pid_t p;
152
153 spops.spop_schedule();
154 p = spops.spop_getpid();
155 spops.spop_unschedule();
156
157 return p;
158 }
159
160 static int
161 rumpsyscall(int sysnum, void *data, register_t *retval)
162 {
163 int rv;
164
165 spops.spop_schedule();
166 rv = spops.spop_syscall(sysnum, data, retval);
167 spops.spop_unschedule();
168
169 return rv;
170 }
171
172 static uint64_t
173 nextreq(struct spclient *spc)
174 {
175 uint64_t nw;
176
177 pthread_mutex_lock(&spc->spc_mtx);
178 nw = spc->spc_nextreq++;
179 pthread_mutex_unlock(&spc->spc_mtx);
180
181 return nw;
182 }
183
184 static void
185 send_error_resp(struct spclient *spc, uint64_t reqno, int error)
186 {
187 struct rsp_hdr rhdr;
188
189 rhdr.rsp_len = sizeof(rhdr);
190 rhdr.rsp_reqno = reqno;
191 rhdr.rsp_class = RUMPSP_ERROR;
192 rhdr.rsp_type = 0;
193 rhdr.rsp_error = error;
194
195 sendlock(spc);
196 (void)dosend(spc, &rhdr, sizeof(rhdr));
197 sendunlock(spc);
198 }
199
200 static int
201 send_syscall_resp(struct spclient *spc, uint64_t reqno, int error,
202 register_t *retval)
203 {
204 struct rsp_hdr rhdr;
205 struct rsp_sysresp sysresp;
206 int rv;
207
208 rhdr.rsp_len = sizeof(rhdr) + sizeof(sysresp);
209 rhdr.rsp_reqno = reqno;
210 rhdr.rsp_class = RUMPSP_RESP;
211 rhdr.rsp_type = RUMPSP_SYSCALL;
212 rhdr.rsp_sysnum = 0;
213
214 sysresp.rsys_error = error;
215 memcpy(sysresp.rsys_retval, retval, sizeof(sysresp.rsys_retval));
216
217 sendlock(spc);
218 rv = dosend(spc, &rhdr, sizeof(rhdr));
219 rv = dosend(spc, &sysresp, sizeof(sysresp));
220 sendunlock(spc);
221
222 return rv;
223 }
224
225 static int
226 copyin_req(struct spclient *spc, const void *remaddr, size_t *dlen,
227 int wantstr, void **resp)
228 {
229 struct rsp_hdr rhdr;
230 struct rsp_copydata copydata;
231 struct respwait rw;
232 int rv;
233
234 DPRINTF(("copyin_req: %zu bytes from %p\n", *dlen, remaddr));
235
236 rhdr.rsp_len = sizeof(rhdr) + sizeof(copydata);
237 rhdr.rsp_class = RUMPSP_REQ;
238 if (wantstr)
239 rhdr.rsp_type = RUMPSP_COPYINSTR;
240 else
241 rhdr.rsp_type = RUMPSP_COPYIN;
242 rhdr.rsp_sysnum = 0;
243
244 copydata.rcp_addr = __UNCONST(remaddr);
245 copydata.rcp_len = *dlen;
246
247 putwait(spc, &rw, &rhdr);
248 rv = dosend(spc, &rhdr, sizeof(rhdr));
249 rv = dosend(spc, ©data, sizeof(copydata));
250 if (rv) {
251 unputwait(spc, &rw);
252 return rv;
253 }
254
255 rv = waitresp(spc, &rw);
256
257 DPRINTF(("copyin: response %d\n", rv));
258
259 *resp = rw.rw_data;
260 if (wantstr)
261 *dlen = rw.rw_dlen;
262
263 return rv;
264
265 }
266
267 static int
268 send_copyout_req(struct spclient *spc, const void *remaddr,
269 const void *data, size_t dlen)
270 {
271 struct rsp_hdr rhdr;
272 struct rsp_copydata copydata;
273 int rv;
274
275 DPRINTF(("copyout_req (async): %zu bytes to %p\n", dlen, remaddr));
276
277 rhdr.rsp_len = sizeof(rhdr) + sizeof(copydata) + dlen;
278 rhdr.rsp_reqno = nextreq(spc);
279 rhdr.rsp_class = RUMPSP_REQ;
280 rhdr.rsp_type = RUMPSP_COPYOUT;
281 rhdr.rsp_sysnum = 0;
282
283 copydata.rcp_addr = __UNCONST(remaddr);
284 copydata.rcp_len = dlen;
285
286 sendlock(spc);
287 rv = dosend(spc, &rhdr, sizeof(rhdr));
288 rv = dosend(spc, ©data, sizeof(copydata));
289 rv = dosend(spc, data, dlen);
290 sendunlock(spc);
291
292 return rv;
293 }
294
295 static int
296 anonmmap_req(struct spclient *spc, size_t howmuch, void **resp)
297 {
298 struct rsp_hdr rhdr;
299 struct respwait rw;
300 int rv;
301
302 DPRINTF(("anonmmap_req: %zu bytes\n", howmuch));
303
304 rhdr.rsp_len = sizeof(rhdr) + sizeof(howmuch);
305 rhdr.rsp_class = RUMPSP_REQ;
306 rhdr.rsp_type = RUMPSP_ANONMMAP;
307 rhdr.rsp_sysnum = 0;
308
309 putwait(spc, &rw, &rhdr);
310 rv = dosend(spc, &rhdr, sizeof(rhdr));
311 rv = dosend(spc, &howmuch, sizeof(howmuch));
312 if (rv) {
313 unputwait(spc, &rw);
314 return rv;
315 }
316
317 rv = waitresp(spc, &rw);
318
319 *resp = rw.rw_data;
320
321 DPRINTF(("anonmmap: mapped at %p\n", **(void ***)resp));
322
323 return rv;
324 }
325
326 static void
327 spcref(struct spclient *spc)
328 {
329
330 pthread_mutex_lock(&spc->spc_mtx);
331 spc->spc_refcnt++;
332 pthread_mutex_unlock(&spc->spc_mtx);
333 }
334
335 static void
336 spcrelease(struct spclient *spc)
337 {
338 int ref;
339
340 pthread_mutex_lock(&spc->spc_mtx);
341 ref = --spc->spc_refcnt;
342 pthread_mutex_unlock(&spc->spc_mtx);
343
344 if (ref > 0)
345 return;
346
347 DPRINTF(("spcrelease: spc %p fd %d\n", spc, spc->spc_fd));
348
349 _DIAGASSERT(TAILQ_EMPTY(&spc->spc_respwait));
350 _DIAGASSERT(spc->spc_buf == NULL);
351
352 lwproc_switch(spc->spc_mainlwp);
353 lwproc_release();
354 spc->spc_mainlwp = NULL;
355
356 close(spc->spc_fd);
357 spc->spc_fd = -1;
358 spc->spc_dying = 0;
359
360 atomic_inc_uint(&disco);
361 }
362
363 static void
364 serv_handledisco(unsigned int idx)
365 {
366 struct spclient *spc = &spclist[idx];
367
368 DPRINTF(("rump_sp: disconnecting [%u]\n", idx));
369
370 pfdlist[idx].fd = -1;
371 pfdlist[idx].revents = 0;
372 pthread_mutex_lock(&spc->spc_mtx);
373 spc->spc_dying = 1;
374 kickall(spc);
375 pthread_mutex_unlock(&spc->spc_mtx);
376
377 /*
378 * Nobody's going to attempt to send/receive anymore,
379 * so reinit info relevant to that.
380 */
381 /*LINTED:pointer casts may be ok*/
382 memset((char *)spc + SPC_ZEROFF, 0, sizeof(*spc) - SPC_ZEROFF);
383
384 spcrelease(spc);
385 }
386
387 static void
388 serv_shutdown(void)
389 {
390 struct spclient *spc;
391 unsigned int i;
392
393 for (i = 1; i < MAXCLI; i++) {
394 spc = &spclist[i];
395 if (spc->spc_fd == -1)
396 continue;
397
398 shutdown(spc->spc_fd, SHUT_RDWR);
399 serv_handledisco(i);
400
401 spcrelease(spc);
402 }
403 }
404
405 static unsigned
406 serv_handleconn(int fd, connecthook_fn connhook, int busy)
407 {
408 struct sockaddr_storage ss;
409 socklen_t sl = sizeof(ss);
410 int newfd, flags;
411 unsigned i;
412
413 /*LINTED: cast ok */
414 newfd = accept(fd, (struct sockaddr *)&ss, &sl);
415 if (newfd == -1)
416 return 0;
417
418 if (busy) {
419 close(newfd); /* EBUSY */
420 return 0;
421 }
422
423 flags = fcntl(newfd, F_GETFL, 0);
424 if (fcntl(newfd, F_SETFL, flags | O_NONBLOCK) == -1) {
425 close(newfd);
426 return 0;
427 }
428
429 if (connhook(newfd) != 0) {
430 close(newfd);
431 return 0;
432 }
433
434 /* write out a banner for the client */
435 if (write(newfd, banner, strlen(banner)) != (ssize_t)strlen(banner)) {
436 close(newfd);
437 return 0;
438 }
439
440 /* find empty slot the simple way */
441 for (i = 0; i < MAXCLI; i++) {
442 if (pfdlist[i].fd == -1 && spclist[i].spc_dying == 0)
443 break;
444 }
445
446 if (lwproc_newproc(&spclist[i]) != 0) {
447 close(newfd);
448 return 0;
449 }
450
451 assert(i < MAXCLI);
452
453 pfdlist[i].fd = newfd;
454 spclist[i].spc_fd = newfd;
455 spclist[i].spc_mainlwp = lwproc_curlwp();
456 spclist[i].spc_istatus = SPCSTATUS_BUSY; /* dedicated receiver */
457 spclist[i].spc_pid = lwproc_getpid();
458 spclist[i].spc_refcnt = 1;
459
460 TAILQ_INIT(&spclist[i].spc_respwait);
461
462 DPRINTF(("rump_sp: added new connection fd %d at idx %u, pid %d\n",
463 newfd, i, lwproc_getpid()));
464
465 lwproc_switch(NULL);
466
467 return i;
468 }
469
470 static void
471 serv_handlesyscall(struct spclient *spc, struct rsp_hdr *rhdr, uint8_t *data)
472 {
473 register_t retval[2] = {0, 0};
474 int rv, sysnum;
475
476 sysnum = (int)rhdr->rsp_sysnum;
477 DPRINTF(("rump_sp: handling syscall %d from client %d\n",
478 sysnum, 0));
479
480 lwproc_newlwp(spc->spc_pid);
481 rv = rumpsyscall(sysnum, data, retval);
482 lwproc_release();
483
484 DPRINTF(("rump_sp: got return value %d & %d/%d\n",
485 rv, retval[0], retval[1]));
486
487 send_syscall_resp(spc, rhdr->rsp_reqno, rv, retval);
488 }
489
490 struct sysbouncearg {
491 struct spclient *sba_spc;
492 struct rsp_hdr sba_hdr;
493 uint8_t *sba_data;
494
495 TAILQ_ENTRY(sysbouncearg) sba_entries;
496 };
497 static pthread_mutex_t sbamtx;
498 static pthread_cond_t sbacv;
499 static int nworker, idleworker;
500 static TAILQ_HEAD(, sysbouncearg) syslist = TAILQ_HEAD_INITIALIZER(syslist);
501
502 /*ARGSUSED*/
503 static void *
504 serv_syscallbouncer(void *arg)
505 {
506 struct sysbouncearg *sba;
507
508 for (;;) {
509 pthread_mutex_lock(&sbamtx);
510 if (idleworker >= rumpsp_idleworker) {
511 nworker--;
512 pthread_mutex_unlock(&sbamtx);
513 break;
514 }
515 idleworker++;
516 while (TAILQ_EMPTY(&syslist)) {
517 pthread_cond_wait(&sbacv, &sbamtx);
518 }
519
520 sba = TAILQ_FIRST(&syslist);
521 TAILQ_REMOVE(&syslist, sba, sba_entries);
522 idleworker--;
523 pthread_mutex_unlock(&sbamtx);
524
525 serv_handlesyscall(sba->sba_spc,
526 &sba->sba_hdr, sba->sba_data);
527 spcrelease(sba->sba_spc);
528 free(sba->sba_data);
529 free(sba);
530 }
531
532 return NULL;
533 }
534
535 static int
536 sp_copyin(void *arg, const void *raddr, void *laddr, size_t *len, int wantstr)
537 {
538 struct spclient *spc = arg;
539 void *rdata = NULL; /* XXXuninit */
540 int rv, nlocks;
541
542 rumpuser__kunlock(0, &nlocks, NULL);
543
544 rv = copyin_req(spc, raddr, len, wantstr, &rdata);
545 if (rv)
546 goto out;
547
548 memcpy(laddr, rdata, *len);
549 free(rdata);
550
551 out:
552 rumpuser__klock(nlocks, NULL);
553 if (rv)
554 return EFAULT;
555 return 0;
556 }
557
558 int
559 rumpuser_sp_copyin(void *arg, const void *raddr, void *laddr, size_t len)
560 {
561
562 return sp_copyin(arg, raddr, laddr, &len, 0);
563 }
564
565 int
566 rumpuser_sp_copyinstr(void *arg, const void *raddr, void *laddr, size_t *len)
567 {
568
569 return sp_copyin(arg, raddr, laddr, len, 1);
570 }
571
572 static int
573 sp_copyout(void *arg, const void *laddr, void *raddr, size_t dlen)
574 {
575 struct spclient *spc = arg;
576 int nlocks, rv;
577
578 rumpuser__kunlock(0, &nlocks, NULL);
579 rv = send_copyout_req(spc, raddr, laddr, dlen);
580 rumpuser__klock(nlocks, NULL);
581
582 if (rv)
583 return EFAULT;
584 return 0;
585 }
586
587 int
588 rumpuser_sp_copyout(void *arg, const void *laddr, void *raddr, size_t dlen)
589 {
590
591 return sp_copyout(arg, laddr, raddr, dlen);
592 }
593
594 int
595 rumpuser_sp_copyoutstr(void *arg, const void *laddr, void *raddr, size_t *dlen)
596 {
597
598 return sp_copyout(arg, laddr, raddr, *dlen);
599 }
600
601 int
602 rumpuser_sp_anonmmap(void *arg, size_t howmuch, void **addr)
603 {
604 struct spclient *spc = arg;
605 void *resp, *rdata;
606 int nlocks, rv;
607
608 rumpuser__kunlock(0, &nlocks, NULL);
609
610 rv = anonmmap_req(spc, howmuch, &rdata);
611 if (rv) {
612 rv = EFAULT;
613 goto out;
614 }
615
616 resp = *(void **)rdata;
617 free(rdata);
618
619 if (resp == NULL) {
620 rv = ENOMEM;
621 }
622
623 *addr = resp;
624
625 out:
626 rumpuser__klock(nlocks, NULL);
627
628 if (rv)
629 return rv;
630 return 0;
631 }
632
633 /*
634 *
635 * Startup routines and mainloop for server.
636 *
637 */
638
639 struct spservarg {
640 int sps_sock;
641 connecthook_fn sps_connhook;
642 };
643
644 static pthread_attr_t pattr_detached;
645 static void
646 handlereq(struct spclient *spc)
647 {
648 struct sysbouncearg *sba;
649 pthread_t pt;
650 int retries;
651
652 if (__predict_false(spc->spc_hdr.rsp_type != RUMPSP_SYSCALL)) {
653 send_error_resp(spc, spc->spc_hdr.rsp_reqno, EINVAL);
654 spcfreebuf(spc);
655 return;
656 }
657
658 retries = 0;
659 while ((sba = malloc(sizeof(*sba))) == NULL) {
660 if (nworker == 0 || retries > 10) {
661 send_error_resp(spc, spc->spc_hdr.rsp_reqno, EAGAIN);
662 spcfreebuf(spc);
663 return;
664 }
665 /* slim chance of more memory? */
666 usleep(10000);
667 }
668
669 sba->sba_spc = spc;
670 sba->sba_hdr = spc->spc_hdr;
671 sba->sba_data = spc->spc_buf;
672 spcresetbuf(spc);
673
674 spcref(spc);
675
676 pthread_mutex_lock(&sbamtx);
677 TAILQ_INSERT_TAIL(&syslist, sba, sba_entries);
678 if (idleworker > 0) {
679 /* do we have a daemon's tool (i.e. idle threads)? */
680 pthread_cond_signal(&sbacv);
681 } else if (nworker < rumpsp_maxworker) {
682 /*
683 * Else, need to create one
684 * (if we can, otherwise just expect another
685 * worker to pick up the syscall)
686 */
687 if (pthread_create(&pt, &pattr_detached,
688 serv_syscallbouncer, NULL) == 0)
689 nworker++;
690 }
691 pthread_mutex_unlock(&sbamtx);
692 }
693
694 static void *
695 spserver(void *arg)
696 {
697 struct spservarg *sarg = arg;
698 struct spclient *spc;
699 unsigned idx;
700 int seen;
701 int rv;
702 unsigned int nfds, maxidx;
703
704 for (idx = 0; idx < MAXCLI; idx++) {
705 pfdlist[idx].fd = -1;
706 pfdlist[idx].events = POLLIN;
707
708 spc = &spclist[idx];
709 pthread_mutex_init(&spc->spc_mtx, NULL);
710 pthread_cond_init(&spc->spc_cv, NULL);
711 spc->spc_fd = -1;
712 }
713 pfdlist[0].fd = spclist[0].spc_fd = sarg->sps_sock;
714 pfdlist[0].events = POLLIN;
715 nfds = 1;
716 maxidx = 0;
717
718 pthread_attr_init(&pattr_detached);
719 pthread_attr_setdetachstate(&pattr_detached, PTHREAD_CREATE_DETACHED);
720 /* XXX: doesn't stacksize currently work on NetBSD */
721 pthread_attr_setstacksize(&pattr_detached, 32*1024);
722
723 pthread_mutex_init(&sbamtx, NULL);
724 pthread_cond_init(&sbacv, NULL);
725
726 DPRINTF(("rump_sp: server mainloop\n"));
727
728 for (;;) {
729 int discoed;
730
731 /* g/c hangarounds (eventually) */
732 discoed = atomic_swap_uint(&disco, 0);
733 while (discoed--) {
734 nfds--;
735 idx = maxidx;
736 while (idx) {
737 if (pfdlist[idx].fd != -1) {
738 maxidx = idx;
739 break;
740 }
741 idx--;
742 }
743 DPRINTF(("rump_sp: set maxidx to [%u]\n",
744 maxidx));
745 }
746
747 DPRINTF(("rump_sp: loop nfd %d\n", maxidx+1));
748 seen = 0;
749 rv = poll(pfdlist, maxidx+1, INFTIM);
750 assert(maxidx+1 <= MAXCLI);
751 assert(rv != 0);
752 if (rv == -1) {
753 if (errno == EINTR)
754 continue;
755 fprintf(stderr, "rump_spserver: poll returned %d\n",
756 errno);
757 break;
758 }
759
760 for (idx = 0; seen < rv && idx < MAXCLI; idx++) {
761 if ((pfdlist[idx].revents & POLLIN) == 0)
762 continue;
763
764 seen++;
765 DPRINTF(("rump_sp: activity at [%u] %d/%d\n",
766 idx, seen, rv));
767 if (idx > 0) {
768 spc = &spclist[idx];
769 DPRINTF(("rump_sp: mainloop read [%u]\n", idx));
770 switch (readframe(spc)) {
771 case 0:
772 break;
773 case -1:
774 serv_handledisco(idx);
775 break;
776 default:
777 switch (spc->spc_hdr.rsp_class) {
778 case RUMPSP_RESP:
779 kickwaiter(spc);
780 break;
781 case RUMPSP_REQ:
782 handlereq(spc);
783 break;
784 default:
785 send_error_resp(spc,
786 spc->spc_hdr.rsp_reqno,
787 ENOENT);
788 spcfreebuf(spc);
789 break;
790 }
791 break;
792 }
793
794 } else {
795 DPRINTF(("rump_sp: mainloop new connection\n"));
796
797 if (__predict_false(spfini)) {
798 close(spclist[0].spc_fd);
799 serv_shutdown();
800 goto out;
801 }
802
803 idx = serv_handleconn(pfdlist[0].fd,
804 sarg->sps_connhook, nfds == MAXCLI);
805 if (idx)
806 nfds++;
807 if (idx > maxidx)
808 maxidx = idx;
809 DPRINTF(("rump_sp: maxid now %d\n", maxidx));
810 }
811 }
812 }
813
814 out:
815 return NULL;
816 }
817
818 static unsigned cleanupidx;
819 static struct sockaddr *cleanupsa;
820 int
821 rumpuser_sp_init(const char *url, const struct rumpuser_sp_ops *spopsp,
822 const char *ostype, const char *osrelease, const char *machine)
823 {
824 pthread_t pt;
825 struct spservarg *sarg;
826 struct sockaddr *sap;
827 char *p;
828 unsigned idx;
829 int error, s;
830
831 p = strdup(url);
832 if (p == NULL)
833 return ENOMEM;
834 error = parseurl(p, &sap, &idx, 1);
835 free(p);
836 if (error)
837 return error;
838
839 snprintf(banner, sizeof(banner), "RUMPSP-%d.%d-%s-%s/%s\n",
840 PROTOMAJOR, PROTOMINOR, ostype, osrelease, machine);
841
842 s = socket(parsetab[idx].domain, SOCK_STREAM, 0);
843 if (s == -1)
844 return errno;
845
846 spops = *spopsp;
847 sarg = malloc(sizeof(*sarg));
848 if (sarg == NULL) {
849 close(s);
850 return ENOMEM;
851 }
852
853 sarg->sps_sock = s;
854 sarg->sps_connhook = parsetab[idx].connhook;
855
856 cleanupidx = idx;
857 cleanupsa = sap;
858
859 /* sloppy error recovery */
860
861 /*LINTED*/
862 if (bind(s, sap, sap->sa_len) == -1) {
863 fprintf(stderr, "rump_sp: server bind failed\n");
864 return errno;
865 }
866
867 if (listen(s, MAXCLI) == -1) {
868 fprintf(stderr, "rump_sp: server listen failed\n");
869 return errno;
870 }
871
872 if ((error = pthread_create(&pt, NULL, spserver, sarg)) != 0) {
873 fprintf(stderr, "rump_sp: cannot create wrkr thread\n");
874 return errno;
875 }
876 pthread_detach(pt);
877
878 return 0;
879 }
880
881 void
882 rumpuser_sp_fini()
883 {
884
885 if (spclist[0].spc_fd) {
886 parsetab[cleanupidx].cleanup(cleanupsa);
887 shutdown(spclist[0].spc_fd, SHUT_RDWR);
888 spfini = 1;
889 }
890 }
891