[BACK]Return to rumpclient.c CVS log [TXT][DIR] Up to [cvs.NetBSD.org] / src / lib / librumpclient

Annotation of src/lib/librumpclient/rumpclient.c, Revision 1.16.2.2

1.16.2.2! bouyer      1: /*      $NetBSD: rumpclient.c,v 1.32 2011/02/16 19:26:58 pooka Exp $   */
1.1       pooka       2:
                      3: /*
1.11      pooka       4:  * Copyright (c) 2010, 2011 Antti Kantee.  All Rights Reserved.
1.1       pooka       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:
1.5       pooka      35: #include <sys/param.h>
1.15      pooka      36: #include <sys/event.h>
1.1       pooka      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>
1.13      pooka      45: #include <dlfcn.h>
1.1       pooka      46: #include <errno.h>
                     47: #include <fcntl.h>
1.13      pooka      48: #include <link.h>
1.1       pooka      49: #include <poll.h>
                     50: #include <pthread.h>
1.11      pooka      51: #include <signal.h>
1.1       pooka      52: #include <stdarg.h>
1.16.2.1  bouyer     53: #include <stdbool.h>
1.1       pooka      54: #include <stdio.h>
                     55: #include <stdlib.h>
                     56: #include <string.h>
                     57: #include <unistd.h>
                     58:
                     59: #include <rump/rumpclient.h>
                     60:
1.13      pooka      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);
1.15      pooka      65: int    (*host_fcntl)(int, int, ...);
1.13      pooka      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);
1.16.2.2! bouyer     71: int    (*host_dup)(int);
1.13      pooka      72:
1.16.2.1  bouyer     73: int    (*host_kqueue)(void);
                     74: int    (*host_kevent)(int, const struct kevent *, size_t,
                     75:                       struct kevent *, size_t, const struct timespec *);
                     76:
1.16.2.2! bouyer     77: int    (*host_execve)(const char *, char *const[], char *const[]);
        !            78:
1.1       pooka      79: #include "sp_common.c"
                     80:
1.11      pooka      81: static struct spclient clispc = {
                     82:        .spc_fd = -1,
                     83: };
1.1       pooka      84:
1.16.2.1  bouyer     85: static int kq = -1;
1.15      pooka      86: static sigset_t fullset;
1.12      pooka      87:
1.16.2.1  bouyer     88: static int doconnect(bool);
1.16.2.2! bouyer     89: static int handshake_req(struct spclient *, int, void *, int, bool);
1.16.2.1  bouyer     90:
1.16.2.2! bouyer     91: /*
        !            92:  * Default: don't retry.  Most clients can't handle it
        !            93:  * (consider e.g. fds suddenly going missing).
        !            94:  */
        !            95: static time_t retrytimo = 0;
1.16.2.1  bouyer     96:
1.12      pooka      97: static int
1.16.2.1  bouyer     98: send_with_recon(struct spclient *spc, const void *data, size_t dlen)
1.12      pooka      99: {
1.16.2.1  bouyer    100:        struct timeval starttime, curtime;
                    101:        time_t prevreconmsg;
                    102:        unsigned reconretries;
                    103:        int rv;
                    104:
                    105:        for (prevreconmsg = 0, reconretries = 0;;) {
                    106:                rv = dosend(spc, data, dlen);
                    107:                if (__predict_false(rv == ENOTCONN || rv == EBADF)) {
                    108:                        /* no persistent connections */
1.16.2.2! bouyer    109:                        if (retrytimo == 0) {
        !           110:                                rv = ENOTCONN;
1.16.2.1  bouyer    111:                                break;
1.16.2.2! bouyer    112:                        }
1.16.2.1  bouyer    113:                        if (retrytimo == RUMPCLIENT_RETRYCONN_DIE)
                    114:                                exit(1);
                    115:
                    116:                        if (!prevreconmsg) {
                    117:                                prevreconmsg = time(NULL);
                    118:                                gettimeofday(&starttime, NULL);
                    119:                        }
                    120:                        if (reconretries == 1) {
                    121:                                if (retrytimo == RUMPCLIENT_RETRYCONN_ONCE) {
                    122:                                        rv = ENOTCONN;
                    123:                                        break;
                    124:                                }
                    125:                                fprintf(stderr, "rump_sp: connection to "
                    126:                                    "kernel lost, trying to reconnect ...\n");
                    127:                        } else if (time(NULL) - prevreconmsg > 120) {
                    128:                                fprintf(stderr, "rump_sp: still trying to "
                    129:                                    "reconnect ...\n");
                    130:                                prevreconmsg = time(NULL);
                    131:                        }
                    132:
                    133:                        /* check that we aren't over the limit */
                    134:                        if (retrytimo > 0) {
                    135:                                struct timeval tmp;
                    136:
                    137:                                gettimeofday(&curtime, NULL);
                    138:                                timersub(&curtime, &starttime, &tmp);
                    139:                                if (tmp.tv_sec >= retrytimo) {
                    140:                                        fprintf(stderr, "rump_sp: reconnect "
                    141:                                            "failed, %lld second timeout\n",
                    142:                                            (long long)retrytimo);
                    143:                                        return ENOTCONN;
                    144:                                }
                    145:                        }
                    146:
                    147:                        /* adhoc backoff timer */
                    148:                        if (reconretries < 10) {
                    149:                                usleep(100000 * reconretries);
                    150:                        } else {
                    151:                                sleep(MIN(10, reconretries-9));
                    152:                        }
                    153:                        reconretries++;
                    154:
                    155:                        if ((rv = doconnect(false)) != 0)
                    156:                                continue;
1.16.2.2! bouyer    157:                        if ((rv = handshake_req(&clispc, HANDSHAKE_GUEST,
        !           158:                            NULL, 0, true)) != 0)
1.16.2.1  bouyer    159:                                continue;
                    160:
                    161:                        /*
                    162:                         * ok, reconnect succesful.  we need to return to
                    163:                         * the upper layer to get the entire PDU resent.
                    164:                         */
                    165:                        if (reconretries != 1)
                    166:                                fprintf(stderr, "rump_sp: reconnected!\n");
                    167:                        rv = EAGAIN;
                    168:                        break;
                    169:                } else {
                    170:                        _DIAGASSERT(errno != EAGAIN);
                    171:                        break;
                    172:                }
                    173:        }
                    174:
                    175:        return rv;
                    176: }
                    177:
                    178: static int
                    179: cliwaitresp(struct spclient *spc, struct respwait *rw, sigset_t *mask,
                    180:        bool keeplock)
                    181: {
                    182:        uint64_t mygen;
                    183:        bool imalive = true;
1.12      pooka     184:
1.15      pooka     185:        pthread_mutex_lock(&spc->spc_mtx);
1.16.2.1  bouyer    186:        if (!keeplock)
                    187:                sendunlockl(spc);
                    188:        mygen = spc->spc_generation;
1.12      pooka     189:
                    190:        rw->rw_error = 0;
1.16.2.1  bouyer    191:        while (!rw->rw_done && rw->rw_error == 0) {
                    192:                if (__predict_false(spc->spc_generation != mygen || !imalive))
                    193:                        break;
                    194:
1.12      pooka     195:                /* are we free to receive? */
                    196:                if (spc->spc_istatus == SPCSTATUS_FREE) {
1.15      pooka     197:                        struct kevent kev[8];
                    198:                        int gotresp, dosig, rv, i;
                    199:
1.12      pooka     200:                        spc->spc_istatus = SPCSTATUS_BUSY;
                    201:                        pthread_mutex_unlock(&spc->spc_mtx);
                    202:
1.15      pooka     203:                        dosig = 0;
                    204:                        for (gotresp = 0; !gotresp; ) {
                    205:                                switch (readframe(spc)) {
                    206:                                case 0:
1.16.2.1  bouyer    207:                                        rv = host_kevent(kq, NULL, 0,
1.15      pooka     208:                                            kev, __arraycount(kev), NULL);
1.16.2.1  bouyer    209:
1.16.2.2! bouyer    210:                                        if (__predict_false(rv == -1)) {
        !           211:                                                goto cleanup;
        !           212:                                        }
        !           213:
1.16.2.1  bouyer    214:                                        /*
                    215:                                         * XXX: don't know how this can
                    216:                                         * happen (timeout cannot expire
                    217:                                         * since there isn't one), but
                    218:                                         * it does happen
                    219:                                         */
                    220:                                        if (__predict_false(rv == 0))
                    221:                                                continue;
                    222:
1.15      pooka     223:                                        for (i = 0; i < rv; i++) {
                    224:                                                if (kev[i].filter
                    225:                                                    == EVFILT_SIGNAL)
                    226:                                                        dosig++;
                    227:                                        }
                    228:                                        if (dosig)
                    229:                                                goto cleanup;
                    230:
                    231:                                        continue;
                    232:                                case -1:
1.16.2.1  bouyer    233:                                        imalive = false;
1.15      pooka     234:                                        goto cleanup;
                    235:                                default:
                    236:                                        break;
                    237:                                }
1.12      pooka     238:
1.15      pooka     239:                                switch (spc->spc_hdr.rsp_class) {
1.12      pooka     240:                                case RUMPSP_RESP:
                    241:                                case RUMPSP_ERROR:
                    242:                                        kickwaiter(spc);
1.15      pooka     243:                                        gotresp = spc->spc_hdr.rsp_reqno ==
                    244:                                            rw->rw_reqno;
1.12      pooka     245:                                        break;
                    246:                                case RUMPSP_REQ:
                    247:                                        handlereq(spc);
                    248:                                        break;
                    249:                                default:
                    250:                                        /* panic */
                    251:                                        break;
1.15      pooka     252:                                }
1.12      pooka     253:                        }
                    254:
1.15      pooka     255:  cleanup:
                    256:                        pthread_mutex_lock(&spc->spc_mtx);
                    257:                        if (spc->spc_istatus == SPCSTATUS_WANTED)
                    258:                                kickall(spc);
                    259:                        spc->spc_istatus = SPCSTATUS_FREE;
                    260:
                    261:                        /* take one for the team */
                    262:                        if (dosig) {
                    263:                                pthread_mutex_unlock(&spc->spc_mtx);
                    264:                                pthread_sigmask(SIG_SETMASK, mask, NULL);
                    265:                                pthread_sigmask(SIG_SETMASK, &fullset, NULL);
                    266:                                pthread_mutex_lock(&spc->spc_mtx);
                    267:                        }
1.12      pooka     268:                } else {
                    269:                        spc->spc_istatus = SPCSTATUS_WANTED;
                    270:                        pthread_cond_wait(&rw->rw_cv, &spc->spc_mtx);
                    271:                }
                    272:        }
                    273:        TAILQ_REMOVE(&spc->spc_respwait, rw, rw_entries);
                    274:        pthread_mutex_unlock(&spc->spc_mtx);
                    275:        pthread_cond_destroy(&rw->rw_cv);
                    276:
1.16.2.1  bouyer    277:        if (spc->spc_generation != mygen || !imalive) {
1.12      pooka     278:                return ENOTCONN;
1.16.2.1  bouyer    279:        }
1.12      pooka     280:        return rw->rw_error;
                    281: }
                    282:
1.1       pooka     283: static int
1.16.2.1  bouyer    284: syscall_req(struct spclient *spc, sigset_t *omask, int sysnum,
1.3       pooka     285:        const void *data, size_t dlen, void **resp)
1.1       pooka     286: {
                    287:        struct rsp_hdr rhdr;
1.3       pooka     288:        struct respwait rw;
                    289:        int rv;
1.1       pooka     290:
                    291:        rhdr.rsp_len = sizeof(rhdr) + dlen;
1.3       pooka     292:        rhdr.rsp_class = RUMPSP_REQ;
                    293:        rhdr.rsp_type = RUMPSP_SYSCALL;
1.1       pooka     294:        rhdr.rsp_sysnum = sysnum;
                    295:
1.6       pooka     296:        do {
                    297:                putwait(spc, &rw, &rhdr);
1.16.2.1  bouyer    298:                if ((rv = send_with_recon(spc, &rhdr, sizeof(rhdr))) != 0) {
                    299:                        unputwait(spc, &rw);
                    300:                        continue;
                    301:                }
                    302:                if ((rv = send_with_recon(spc, data, dlen)) != 0) {
1.6       pooka     303:                        unputwait(spc, &rw);
1.16.2.1  bouyer    304:                        continue;
1.6       pooka     305:                }
                    306:
1.16.2.1  bouyer    307:                rv = cliwaitresp(spc, &rw, omask, false);
                    308:                if (rv == ENOTCONN)
                    309:                        rv = EAGAIN;
1.6       pooka     310:        } while (rv == EAGAIN);
1.3       pooka     311:
                    312:        *resp = rw.rw_data;
                    313:        return rv;
1.1       pooka     314: }
                    315:
                    316: static int
1.16.2.2! bouyer    317: handshake_req(struct spclient *spc, int type, void *data,
        !           318:        int cancel, bool haslock)
1.10      pooka     319: {
1.11      pooka     320:        struct handshake_fork rf;
1.10      pooka     321:        struct rsp_hdr rhdr;
                    322:        struct respwait rw;
1.12      pooka     323:        sigset_t omask;
1.16.2.1  bouyer    324:        size_t bonus;
1.10      pooka     325:        int rv;
                    326:
1.16.2.2! bouyer    327:        if (type == HANDSHAKE_FORK) {
1.16.2.1  bouyer    328:                bonus = sizeof(rf);
                    329:        } else {
                    330:                bonus = strlen(getprogname())+1;
                    331:        }
                    332:
1.10      pooka     333:        /* performs server handshake */
1.16.2.1  bouyer    334:        rhdr.rsp_len = sizeof(rhdr) + bonus;
1.10      pooka     335:        rhdr.rsp_class = RUMPSP_REQ;
                    336:        rhdr.rsp_type = RUMPSP_HANDSHAKE;
1.16.2.2! bouyer    337:        rhdr.rsp_handshake = type;
1.10      pooka     338:
1.12      pooka     339:        pthread_sigmask(SIG_SETMASK, &fullset, &omask);
1.16.2.1  bouyer    340:        if (haslock)
                    341:                putwait_locked(spc, &rw, &rhdr);
                    342:        else
                    343:                putwait(spc, &rw, &rhdr);
1.10      pooka     344:        rv = dosend(spc, &rhdr, sizeof(rhdr));
1.16.2.2! bouyer    345:        if (type == HANDSHAKE_FORK) {
        !           346:                memcpy(rf.rf_auth, data, sizeof(rf.rf_auth)); /* uh, why? */
1.11      pooka     347:                rf.rf_cancel = cancel;
1.16.2.1  bouyer    348:                rv = send_with_recon(spc, &rf, sizeof(rf));
                    349:        } else {
                    350:                rv = dosend(spc, getprogname(), strlen(getprogname())+1);
                    351:        }
                    352:        if (rv || cancel) {
                    353:                if (haslock)
                    354:                        unputwait_locked(spc, &rw);
                    355:                else
                    356:                        unputwait(spc, &rw);
                    357:                if (cancel) {
                    358:                        goto out;
                    359:                }
                    360:        } else {
                    361:                rv = cliwaitresp(spc, &rw, &omask, haslock);
1.10      pooka     362:        }
                    363:        if (rv)
1.16.2.1  bouyer    364:                goto out;
1.10      pooka     365:
                    366:        rv = *(int *)rw.rw_data;
                    367:        free(rw.rw_data);
                    368:
1.16.2.1  bouyer    369:  out:
                    370:        pthread_sigmask(SIG_SETMASK, &omask, NULL);
1.10      pooka     371:        return rv;
                    372: }
                    373:
                    374: static int
1.16.2.1  bouyer    375: prefork_req(struct spclient *spc, sigset_t *omask, void **resp)
1.11      pooka     376: {
                    377:        struct rsp_hdr rhdr;
                    378:        struct respwait rw;
                    379:        int rv;
                    380:
                    381:        rhdr.rsp_len = sizeof(rhdr);
                    382:        rhdr.rsp_class = RUMPSP_REQ;
                    383:        rhdr.rsp_type = RUMPSP_PREFORK;
                    384:        rhdr.rsp_error = 0;
                    385:
1.16.2.1  bouyer    386:        do {
                    387:                putwait(spc, &rw, &rhdr);
                    388:                rv = send_with_recon(spc, &rhdr, sizeof(rhdr));
                    389:                if (rv != 0) {
                    390:                        unputwait(spc, &rw);
                    391:                        continue;
                    392:                }
                    393:
                    394:                rv = cliwaitresp(spc, &rw, omask, false);
                    395:                if (rv == ENOTCONN)
                    396:                        rv = EAGAIN;
                    397:        } while (rv == EAGAIN);
1.11      pooka     398:
                    399:        *resp = rw.rw_data;
                    400:        return rv;
                    401: }
                    402:
1.16.2.1  bouyer    403: /*
                    404:  * prevent response code from deadlocking with reconnect code
                    405:  */
1.11      pooka     406: static int
1.16.2.1  bouyer    407: resp_sendlock(struct spclient *spc)
                    408: {
                    409:        int rv = 0;
                    410:
                    411:        pthread_mutex_lock(&spc->spc_mtx);
                    412:        while (spc->spc_ostatus != SPCSTATUS_FREE) {
                    413:                if (__predict_false(spc->spc_reconnecting)) {
                    414:                        rv = EBUSY;
                    415:                        goto out;
                    416:                }
                    417:                spc->spc_ostatus = SPCSTATUS_WANTED;
                    418:                pthread_cond_wait(&spc->spc_cv, &spc->spc_mtx);
                    419:        }
                    420:        spc->spc_ostatus = SPCSTATUS_BUSY;
                    421:
                    422:  out:
                    423:        pthread_mutex_unlock(&spc->spc_mtx);
                    424:        return rv;
                    425: }
                    426:
                    427: static void
1.5       pooka     428: send_copyin_resp(struct spclient *spc, uint64_t reqno, void *data, size_t dlen,
                    429:        int wantstr)
1.1       pooka     430: {
                    431:        struct rsp_hdr rhdr;
                    432:
1.5       pooka     433:        if (wantstr)
                    434:                dlen = MIN(dlen, strlen(data)+1);
                    435:
1.1       pooka     436:        rhdr.rsp_len = sizeof(rhdr) + dlen;
                    437:        rhdr.rsp_reqno = reqno;
1.3       pooka     438:        rhdr.rsp_class = RUMPSP_RESP;
                    439:        rhdr.rsp_type = RUMPSP_COPYIN;
1.1       pooka     440:        rhdr.rsp_sysnum = 0;
                    441:
1.16.2.1  bouyer    442:        if (resp_sendlock(spc) != 0)
                    443:                return;
                    444:        (void)dosend(spc, &rhdr, sizeof(rhdr));
                    445:        (void)dosend(spc, data, dlen);
1.3       pooka     446:        sendunlock(spc);
1.1       pooka     447: }
                    448:
1.16.2.1  bouyer    449: static void
1.1       pooka     450: send_anonmmap_resp(struct spclient *spc, uint64_t reqno, void *addr)
                    451: {
                    452:        struct rsp_hdr rhdr;
                    453:
                    454:        rhdr.rsp_len = sizeof(rhdr) + sizeof(addr);
                    455:        rhdr.rsp_reqno = reqno;
1.3       pooka     456:        rhdr.rsp_class = RUMPSP_RESP;
                    457:        rhdr.rsp_type = RUMPSP_ANONMMAP;
1.1       pooka     458:        rhdr.rsp_sysnum = 0;
                    459:
1.16.2.1  bouyer    460:        if (resp_sendlock(spc) != 0)
                    461:                return;
                    462:        (void)dosend(spc, &rhdr, sizeof(rhdr));
                    463:        (void)dosend(spc, &addr, sizeof(addr));
1.3       pooka     464:        sendunlock(spc);
1.1       pooka     465: }
                    466:
                    467: int
                    468: rumpclient_syscall(int sysnum, const void *data, size_t dlen,
                    469:        register_t *retval)
                    470: {
                    471:        struct rsp_sysresp *resp;
1.16.2.1  bouyer    472:        sigset_t omask;
1.3       pooka     473:        void *rdata;
                    474:        int rv;
                    475:
1.16.2.1  bouyer    476:        pthread_sigmask(SIG_SETMASK, &fullset, &omask);
                    477:
1.3       pooka     478:        DPRINTF(("rumpsp syscall_req: syscall %d with %p/%zu\n",
                    479:            sysnum, data, dlen));
                    480:
1.16.2.1  bouyer    481:        rv = syscall_req(&clispc, &omask, sysnum, data, dlen, &rdata);
1.3       pooka     482:        if (rv)
1.16.2.1  bouyer    483:                goto out;
1.3       pooka     484:
                    485:        resp = rdata;
                    486:        DPRINTF(("rumpsp syscall_resp: syscall %d error %d, rv: %d/%d\n",
                    487:            sysnum, rv, resp->rsys_retval[0], resp->rsys_retval[1]));
1.1       pooka     488:
1.3       pooka     489:        memcpy(retval, &resp->rsys_retval, sizeof(resp->rsys_retval));
                    490:        rv = resp->rsys_error;
                    491:        free(rdata);
1.1       pooka     492:
1.16.2.1  bouyer    493:  out:
                    494:        pthread_sigmask(SIG_SETMASK, &omask, NULL);
1.3       pooka     495:        return rv;
                    496: }
1.1       pooka     497:
1.3       pooka     498: static void
                    499: handlereq(struct spclient *spc)
                    500: {
                    501:        struct rsp_copydata *copydata;
1.16      pooka     502:        struct rsp_hdr *rhdr = &spc->spc_hdr;
1.3       pooka     503:        void *mapaddr;
                    504:        size_t maplen;
1.5       pooka     505:        int reqtype = spc->spc_hdr.rsp_type;
1.1       pooka     506:
1.5       pooka     507:        switch (reqtype) {
1.3       pooka     508:        case RUMPSP_COPYIN:
1.5       pooka     509:        case RUMPSP_COPYINSTR:
1.3       pooka     510:                /*LINTED*/
                    511:                copydata = (struct rsp_copydata *)spc->spc_buf;
                    512:                DPRINTF(("rump_sp handlereq: copyin request: %p/%zu\n",
                    513:                    copydata->rcp_addr, copydata->rcp_len));
                    514:                send_copyin_resp(spc, spc->spc_hdr.rsp_reqno,
1.5       pooka     515:                    copydata->rcp_addr, copydata->rcp_len,
                    516:                    reqtype == RUMPSP_COPYINSTR);
1.3       pooka     517:                break;
                    518:        case RUMPSP_COPYOUT:
1.5       pooka     519:        case RUMPSP_COPYOUTSTR:
1.3       pooka     520:                /*LINTED*/
                    521:                copydata = (struct rsp_copydata *)spc->spc_buf;
                    522:                DPRINTF(("rump_sp handlereq: copyout request: %p/%zu\n",
                    523:                    copydata->rcp_addr, copydata->rcp_len));
                    524:                /*LINTED*/
                    525:                memcpy(copydata->rcp_addr, copydata->rcp_data,
                    526:                    copydata->rcp_len);
                    527:                break;
                    528:        case RUMPSP_ANONMMAP:
                    529:                /*LINTED*/
                    530:                maplen = *(size_t *)spc->spc_buf;
                    531:                mapaddr = mmap(NULL, maplen, PROT_READ|PROT_WRITE,
                    532:                    MAP_ANON, -1, 0);
                    533:                if (mapaddr == MAP_FAILED)
                    534:                        mapaddr = NULL;
                    535:                DPRINTF(("rump_sp handlereq: anonmmap: %p\n", mapaddr));
                    536:                send_anonmmap_resp(spc, spc->spc_hdr.rsp_reqno, mapaddr);
                    537:                break;
1.16      pooka     538:        case RUMPSP_RAISE:
                    539:                DPRINTF(("rump_sp handlereq: raise sig %d\n", rhdr->rsp_signo));
1.16.2.1  bouyer    540:                raise((int)rhdr->rsp_signo);
1.16      pooka     541:                /*
                    542:                 * We most likely have signals blocked, but the signal
                    543:                 * will be handled soon enough when we return.
                    544:                 */
                    545:                break;
1.3       pooka     546:        default:
1.12      pooka     547:                printf("PANIC: INVALID TYPE %d\n", reqtype);
1.3       pooka     548:                abort();
                    549:                break;
1.1       pooka     550:        }
                    551:
1.6       pooka     552:        spcfreebuf(spc);
1.1       pooka     553: }
                    554:
1.11      pooka     555: static unsigned ptab_idx;
                    556: static struct sockaddr *serv_sa;
                    557:
1.16.2.2! bouyer    558: /* dup until we get a "good" fd which does not collide with stdio */
        !           559: static int
        !           560: dupgood(int myfd, int mustchange)
        !           561: {
        !           562:        int ofds[4];
        !           563:        int i;
        !           564:
        !           565:        for (i = 0; (myfd <= 2 || mustchange) && myfd != -1; i++) {
        !           566:                assert(i < __arraycount(ofds));
        !           567:                ofds[i] = myfd;
        !           568:                myfd = host_dup(myfd);
        !           569:                if (mustchange) {
        !           570:                        i--; /* prevent closing old fd */
        !           571:                        mustchange = 0;
        !           572:                }
        !           573:        }
        !           574:
        !           575:        for (i--; i >= 0; i--) {
        !           576:                host_close(ofds[i]);
        !           577:        }
        !           578:
        !           579:        return myfd;
        !           580: }
        !           581:
1.11      pooka     582: static int
1.16.2.1  bouyer    583: doconnect(bool noisy)
1.1       pooka     584: {
1.16.2.1  bouyer    585:        struct respwait rw;
                    586:        struct rsp_hdr rhdr;
1.15      pooka     587:        struct kevent kev[NSIG+1];
1.9       pooka     588:        char banner[MAXBANNER];
1.16.2.1  bouyer    589:        struct pollfd pfd;
1.15      pooka     590:        int s, error, flags, i;
1.9       pooka     591:        ssize_t n;
1.1       pooka     592:
1.16.2.1  bouyer    593:        if (kq != -1)
                    594:                host_close(kq);
                    595:        kq = -1;
                    596:        s = -1;
                    597:
                    598:        if (clispc.spc_fd != -1)
                    599:                host_close(clispc.spc_fd);
                    600:        clispc.spc_fd = -1;
                    601:
                    602:        /*
                    603:         * for reconnect, gate everyone out of the receiver code
                    604:         */
                    605:        putwait_locked(&clispc, &rw, &rhdr);
                    606:
                    607:        pthread_mutex_lock(&clispc.spc_mtx);
                    608:        clispc.spc_reconnecting = 1;
                    609:        pthread_cond_broadcast(&clispc.spc_cv);
                    610:        clispc.spc_generation++;
                    611:        while (clispc.spc_istatus != SPCSTATUS_FREE) {
                    612:                clispc.spc_istatus = SPCSTATUS_WANTED;
                    613:                pthread_cond_wait(&rw.rw_cv, &clispc.spc_mtx);
                    614:        }
                    615:        kickall(&clispc);
                    616:
                    617:        /*
                    618:         * we can release it already since we hold the
                    619:         * send lock during reconnect
                    620:         * XXX: assert it
                    621:         */
                    622:        clispc.spc_istatus = SPCSTATUS_FREE;
                    623:        pthread_mutex_unlock(&clispc.spc_mtx);
                    624:        unputwait_locked(&clispc, &rw);
                    625:
                    626:        free(clispc.spc_buf);
                    627:        clispc.spc_off = 0;
                    628:
1.16.2.2! bouyer    629:        s = dupgood(host_socket(parsetab[ptab_idx].domain, SOCK_STREAM, 0), 0);
1.11      pooka     630:        if (s == -1)
1.2       pooka     631:                return -1;
1.1       pooka     632:
1.16.2.1  bouyer    633:        pfd.fd = s;
                    634:        pfd.events = POLLIN;
                    635:        while (host_connect(s, serv_sa, (socklen_t)serv_sa->sa_len) == -1) {
                    636:                if (errno == EINTR)
                    637:                        continue;
1.11      pooka     638:                error = errno;
1.16.2.1  bouyer    639:                if (noisy)
                    640:                        fprintf(stderr, "rump_sp: client connect failed: %s\n",
                    641:                            strerror(errno));
1.2       pooka     642:                errno = error;
                    643:                return -1;
                    644:        }
1.1       pooka     645:
1.11      pooka     646:        if ((error = parsetab[ptab_idx].connhook(s)) != 0) {
1.2       pooka     647:                error = errno;
1.16.2.1  bouyer    648:                if (noisy)
                    649:                        fprintf(stderr, "rump_sp: connect hook failed\n");
1.2       pooka     650:                errno = error;
                    651:                return -1;
1.1       pooka     652:        }
1.4       pooka     653:
1.13      pooka     654:        if ((n = host_read(s, banner, sizeof(banner)-1)) < 0) {
1.2       pooka     655:                error = errno;
1.16.2.1  bouyer    656:                if (noisy)
                    657:                        fprintf(stderr, "rump_sp: failed to read banner\n");
1.2       pooka     658:                errno = error;
                    659:                return -1;
1.1       pooka     660:        }
1.9       pooka     661:
                    662:        if (banner[n-1] != '\n') {
1.16.2.1  bouyer    663:                if (noisy)
                    664:                        fprintf(stderr, "rump_sp: invalid banner\n");
1.9       pooka     665:                errno = EINVAL;
                    666:                return -1;
                    667:        }
                    668:        banner[n] = '\0';
1.16.2.1  bouyer    669:        /* parse the banner some day */
1.9       pooka     670:
1.15      pooka     671:        flags = host_fcntl(s, F_GETFL, 0);
                    672:        if (host_fcntl(s, F_SETFL, flags | O_NONBLOCK) == -1) {
1.16.2.1  bouyer    673:                if (noisy)
                    674:                        fprintf(stderr, "rump_sp: socket fd NONBLOCK: %s\n",
                    675:                            strerror(errno));
1.15      pooka     676:                errno = EINVAL;
                    677:                return -1;
                    678:        }
1.16.2.1  bouyer    679:        clispc.spc_fd = s;
                    680:        clispc.spc_state = SPCSTATE_RUNNING;
                    681:        clispc.spc_reconnecting = 0;
1.9       pooka     682:
1.15      pooka     683:        /* setup kqueue, we want all signals and the fd */
1.16.2.2! bouyer    684:        if ((kq = dupgood(host_kqueue(), 0)) == -1) {
1.15      pooka     685:                error = errno;
1.16.2.1  bouyer    686:                if (noisy)
                    687:                        fprintf(stderr, "rump_sp: cannot setup kqueue");
1.15      pooka     688:                errno = error;
                    689:                return -1;
                    690:        }
                    691:
                    692:        for (i = 0; i < NSIG; i++) {
                    693:                EV_SET(&kev[i], i+1, EVFILT_SIGNAL, EV_ADD|EV_ENABLE, 0, 0, 0);
                    694:        }
1.16.2.1  bouyer    695:        EV_SET(&kev[NSIG], clispc.spc_fd,
                    696:            EVFILT_READ, EV_ADD|EV_ENABLE, 0, 0, 0);
                    697:        if (host_kevent(kq, kev, NSIG+1, NULL, 0, NULL) == -1) {
1.15      pooka     698:                error = errno;
1.16.2.1  bouyer    699:                if (noisy)
                    700:                        fprintf(stderr, "rump_sp: kevent() failed");
1.15      pooka     701:                errno = error;
                    702:                return -1;
                    703:        }
                    704:
1.16.2.1  bouyer    705:        return 0;
                    706: }
                    707:
                    708: static int
                    709: doinit(void)
                    710: {
                    711:
1.11      pooka     712:        TAILQ_INIT(&clispc.spc_respwait);
                    713:        pthread_mutex_init(&clispc.spc_mtx, NULL);
                    714:        pthread_cond_init(&clispc.spc_cv, NULL);
                    715:
                    716:        return 0;
                    717: }
                    718:
1.13      pooka     719: void *(*rumpclient_dlsym)(void *, const char *);
1.16.2.2! bouyer    720: static int init_done = 0;
1.13      pooka     721:
1.11      pooka     722: int
                    723: rumpclient_init()
                    724: {
                    725:        char *p;
                    726:        int error;
1.16.2.2! bouyer    727:        int rv = -1;
        !           728:        int hstype;
        !           729:
        !           730:        if (init_done)
        !           731:                return 0;
        !           732:        init_done = 1;
1.11      pooka     733:
1.16.2.1  bouyer    734:        sigfillset(&fullset);
                    735:
1.13      pooka     736:        /* dlsym overrided by rumphijack? */
                    737:        if (!rumpclient_dlsym)
                    738:                rumpclient_dlsym = dlsym;
                    739:
                    740:        /*
                    741:         * sag mir, wo die symbol sind.  zogen fort, der krieg beginnt.
                    742:         * wann wird man je verstehen?  wann wird man je verstehen?
                    743:         */
                    744: #define FINDSYM2(_name_,_syscall_)                                     \
                    745:        if ((host_##_name_ = rumpclient_dlsym(RTLD_NEXT,                \
                    746:            #_syscall_)) == NULL)                                       \
                    747:                /* host_##_name_ = _syscall_ */;
                    748: #define FINDSYM(_name_) FINDSYM2(_name_,_name_)
                    749:        FINDSYM2(socket,__socket30);
                    750:        FINDSYM(close);
                    751:        FINDSYM(connect);
1.15      pooka     752:        FINDSYM(fcntl);
1.13      pooka     753:        FINDSYM(poll);
                    754:        FINDSYM(read);
                    755:        FINDSYM(sendto);
                    756:        FINDSYM(setsockopt);
1.16.2.2! bouyer    757:        FINDSYM(dup);
1.16.2.1  bouyer    758:        FINDSYM(kqueue);
1.16.2.2! bouyer    759:        FINDSYM(execve);
1.16.2.1  bouyer    760: #if !__NetBSD_Prereq__(5,99,7)
                    761:        FINDSYM(kevent);
                    762: #else
                    763:        FINDSYM2(kevent,_sys___kevent50);
                    764: #endif
1.13      pooka     765: #undef FINDSYM
                    766: #undef FINDSY2
                    767:
1.16.2.2! bouyer    768:        if ((p = getenv("RUMP__PARSEDSERVER")) == NULL) {
        !           769:                if ((p = getenv("RUMP_SERVER")) == NULL) {
        !           770:                        errno = ENOENT;
        !           771:                        goto out;
        !           772:                }
1.11      pooka     773:        }
                    774:
                    775:        if ((error = parseurl(p, &serv_sa, &ptab_idx, 0)) != 0) {
                    776:                errno = error;
1.16.2.2! bouyer    777:                goto out;
1.11      pooka     778:        }
                    779:
1.16.2.1  bouyer    780:        if (doinit() == -1)
1.16.2.2! bouyer    781:                goto out;
        !           782:
        !           783:        if ((p = getenv("RUMPCLIENT__EXECFD")) != NULL) {
        !           784:                sscanf(p, "%d,%d", &clispc.spc_fd, &kq);
        !           785:                unsetenv("RUMPCLIENT__EXECFD");
        !           786:                hstype = HANDSHAKE_EXEC;
        !           787:        } else {
        !           788:                if (doconnect(true) == -1)
        !           789:                        goto out;
        !           790:                hstype = HANDSHAKE_GUEST;
        !           791:        }
1.11      pooka     792:
1.16.2.2! bouyer    793:        error = handshake_req(&clispc, hstype, NULL, 0, false);
1.11      pooka     794:        if (error) {
                    795:                pthread_mutex_destroy(&clispc.spc_mtx);
                    796:                pthread_cond_destroy(&clispc.spc_cv);
1.16.2.1  bouyer    797:                if (clispc.spc_fd != -1)
                    798:                        host_close(clispc.spc_fd);
1.10      pooka     799:                errno = error;
1.16.2.2! bouyer    800:                goto out;
1.10      pooka     801:        }
1.16.2.2! bouyer    802:        rv = 0;
1.10      pooka     803:
1.16.2.2! bouyer    804:  out:
        !           805:        if (rv == -1)
        !           806:                init_done = 0;
        !           807:        return rv;
1.11      pooka     808: }
                    809:
                    810: struct rumpclient_fork {
                    811:        uint32_t fork_auth[AUTHLEN];
1.16.2.2! bouyer    812:        struct spclient fork_spc;
        !           813:        int fork_kq;
1.11      pooka     814: };
                    815:
                    816: struct rumpclient_fork *
                    817: rumpclient_prefork(void)
                    818: {
                    819:        struct rumpclient_fork *rpf;
1.16.2.1  bouyer    820:        sigset_t omask;
1.11      pooka     821:        void *resp;
                    822:        int rv;
                    823:
1.16.2.1  bouyer    824:        pthread_sigmask(SIG_SETMASK, &fullset, &omask);
1.11      pooka     825:        rpf = malloc(sizeof(*rpf));
                    826:        if (rpf == NULL)
1.16.2.2! bouyer    827:                goto out;
1.11      pooka     828:
1.16.2.1  bouyer    829:        if ((rv = prefork_req(&clispc, &omask, &resp)) != 0) {
1.11      pooka     830:                free(rpf);
                    831:                errno = rv;
1.16.2.1  bouyer    832:                rpf = NULL;
                    833:                goto out;
1.11      pooka     834:        }
                    835:
                    836:        memcpy(rpf->fork_auth, resp, sizeof(rpf->fork_auth));
                    837:        free(resp);
                    838:
1.16.2.2! bouyer    839:        rpf->fork_spc = clispc;
        !           840:        rpf->fork_kq = kq;
        !           841:
1.16.2.1  bouyer    842:  out:
                    843:        pthread_sigmask(SIG_SETMASK, &omask, NULL);
1.11      pooka     844:        return rpf;
                    845: }
                    846:
                    847: int
                    848: rumpclient_fork_init(struct rumpclient_fork *rpf)
                    849: {
                    850:        int error;
1.16.2.1  bouyer    851:        int osock;
1.11      pooka     852:
1.16.2.1  bouyer    853:        osock = clispc.spc_fd;
1.11      pooka     854:        memset(&clispc, 0, sizeof(clispc));
1.16.2.1  bouyer    855:        clispc.spc_fd = osock;
                    856:
                    857:        kq = -1; /* kqueue descriptor is not copied over fork() */
1.11      pooka     858:
1.16.2.1  bouyer    859:        if (doinit() == -1)
                    860:                return -1;
                    861:        if (doconnect(false) == -1)
1.11      pooka     862:                return -1;
1.10      pooka     863:
1.16.2.2! bouyer    864:        error = handshake_req(&clispc, HANDSHAKE_FORK, rpf->fork_auth,
        !           865:            0, false);
1.10      pooka     866:        if (error) {
                    867:                pthread_mutex_destroy(&clispc.spc_mtx);
                    868:                pthread_cond_destroy(&clispc.spc_cv);
1.11      pooka     869:                errno = error;
                    870:                return -1;
1.10      pooka     871:        }
1.11      pooka     872:
                    873:        return 0;
1.1       pooka     874: }
1.16.2.1  bouyer    875:
                    876: void
1.16.2.2! bouyer    877: rumpclient_fork_cancel(struct rumpclient_fork *rpf)
        !           878: {
        !           879:
        !           880:        /* EUNIMPL */
        !           881: }
        !           882:
        !           883: void
        !           884: rumpclient_fork_vparent(struct rumpclient_fork *rpf)
        !           885: {
        !           886:
        !           887:        clispc = rpf->fork_spc;
        !           888:        kq = rpf->fork_kq;
        !           889: }
        !           890:
        !           891: void
1.16.2.1  bouyer    892: rumpclient_setconnretry(time_t timeout)
                    893: {
                    894:
                    895:        if (timeout < RUMPCLIENT_RETRYCONN_DIE)
                    896:                return; /* gigo */
                    897:
                    898:        retrytimo = timeout;
                    899: }
1.16.2.2! bouyer    900:
        !           901: int
        !           902: rumpclient__closenotify(int *fdp, enum rumpclient_closevariant variant)
        !           903: {
        !           904:        int fd = *fdp;
        !           905:        int untilfd, rv;
        !           906:        int newfd;
        !           907:
        !           908:        switch (variant) {
        !           909:        case RUMPCLIENT_CLOSE_FCLOSEM:
        !           910:                untilfd = MAX(clispc.spc_fd, kq);
        !           911:                for (; fd <= untilfd; fd++) {
        !           912:                        if (fd == clispc.spc_fd || fd == kq)
        !           913:                                continue;
        !           914:                        rv = host_close(fd);
        !           915:                        if (rv == -1)
        !           916:                                return -1;
        !           917:                }
        !           918:                *fdp = fd;
        !           919:                break;
        !           920:
        !           921:        case RUMPCLIENT_CLOSE_CLOSE:
        !           922:        case RUMPCLIENT_CLOSE_DUP2:
        !           923:                if (fd == clispc.spc_fd) {
        !           924:                        struct kevent kev[2];
        !           925:
        !           926:                        newfd = dupgood(clispc.spc_fd, 1);
        !           927:                        if (newfd == -1)
        !           928:                                return -1;
        !           929:                        /*
        !           930:                         * now, we have a new socket number, so change
        !           931:                         * the file descriptor that kqueue is
        !           932:                         * monitoring.  remove old and add new.
        !           933:                         */
        !           934:                        EV_SET(&kev[0], clispc.spc_fd,
        !           935:                            EVFILT_READ, EV_DELETE, 0, 0, 0);
        !           936:                        EV_SET(&kev[1], newfd,
        !           937:                            EVFILT_READ, EV_ADD|EV_ENABLE, 0, 0, 0);
        !           938:                        if (host_kevent(kq, kev, 2, NULL, 0, NULL) == -1) {
        !           939:                                int sverrno = errno;
        !           940:                                host_close(newfd);
        !           941:                                errno = sverrno;
        !           942:                                return -1;
        !           943:                        }
        !           944:                        clispc.spc_fd = newfd;
        !           945:                }
        !           946:                if (fd == kq) {
        !           947:                        newfd = dupgood(kq, 1);
        !           948:                        if (newfd == -1)
        !           949:                                return -1;
        !           950:                        kq = newfd;
        !           951:                }
        !           952:                break;
        !           953:        }
        !           954:
        !           955:        return 0;
        !           956: }
        !           957:
        !           958: pid_t
        !           959: rumpclient_fork()
        !           960: {
        !           961:
        !           962:        return rumpclient__dofork(fork);
        !           963: }
        !           964:
        !           965: /*
        !           966:  * Process is about to exec.  Save info about our existing connection
        !           967:  * in the env.  rumpclient will check for this info in init().
        !           968:  * This is mostly for the benefit of rumphijack, but regular applications
        !           969:  * may use it as well.
        !           970:  */
        !           971: int
        !           972: rumpclient_exec(const char *path, char *const argv[], char *const envp[])
        !           973: {
        !           974:        char buf[4096];
        !           975:        char **newenv;
        !           976:        char *envstr, *envstr2;
        !           977:        size_t nelem;
        !           978:        int rv, sverrno;
        !           979:
        !           980:        snprintf(buf, sizeof(buf), "RUMPCLIENT__EXECFD=%d,%d",
        !           981:            clispc.spc_fd, kq);
        !           982:        envstr = malloc(strlen(buf)+1);
        !           983:        if (envstr == NULL) {
        !           984:                return ENOMEM;
        !           985:        }
        !           986:        strcpy(envstr, buf);
        !           987:
        !           988:        /* do we have a fully parsed url we want to forward in the env? */
        !           989:        if (*parsedurl != '\0') {
        !           990:                snprintf(buf, sizeof(buf),
        !           991:                    "RUMP__PARSEDSERVER=%s", parsedurl);
        !           992:                envstr2 = malloc(strlen(buf)+1);
        !           993:                if (envstr2 == NULL) {
        !           994:                        free(envstr);
        !           995:                        return ENOMEM;
        !           996:                }
        !           997:                strcpy(envstr2, buf);
        !           998:        } else {
        !           999:                envstr2 = NULL;
        !          1000:        }
        !          1001:
        !          1002:        for (nelem = 0; envp && envp[nelem]; nelem++)
        !          1003:                continue;
        !          1004:
        !          1005:        newenv = malloc(sizeof(*newenv) * nelem+3);
        !          1006:        if (newenv == NULL) {
        !          1007:                free(envstr2);
        !          1008:                free(envstr);
        !          1009:                return ENOMEM;
        !          1010:        }
        !          1011:        memcpy(&newenv[0], envp, nelem*sizeof(*envp));
        !          1012:
        !          1013:        newenv[nelem] = envstr;
        !          1014:        newenv[nelem+1] = envstr2;
        !          1015:        newenv[nelem+2] = NULL;
        !          1016:
        !          1017:        rv = host_execve(path, argv, newenv);
        !          1018:
        !          1019:        _DIAGASSERT(rv != 0);
        !          1020:        sverrno = errno;
        !          1021:        free(envstr2);
        !          1022:        free(envstr);
        !          1023:        free(newenv);
        !          1024:        errno = sverrno;
        !          1025:        return rv;
        !          1026: }
        !          1027:
        !          1028: int
        !          1029: rumpclient_daemon(int nochdir, int noclose)
        !          1030: {
        !          1031:        struct rumpclient_fork *rf;
        !          1032:        int sverrno;
        !          1033:
        !          1034:        if ((rf = rumpclient_prefork()) == NULL)
        !          1035:                return -1;
        !          1036:
        !          1037:        if (daemon(nochdir, noclose) == -1) {
        !          1038:                sverrno = errno;
        !          1039:                rumpclient_fork_cancel(rf);
        !          1040:                errno = sverrno;
        !          1041:                return -1;
        !          1042:        }
        !          1043:
        !          1044:        if (rumpclient_fork_init(rf) == -1)
        !          1045:                return -1;
        !          1046:
        !          1047:        return 0;
        !          1048: }

CVSweb <webmaster@jp.NetBSD.org>