Annotation of nono/host/netdriver_slirp.cpp, revision 1.1.1.5

1.1       root        1: //
                      2: // nono
                      3: // Copyright (C) 2025 nono project
                      4: // Licensed under nono-license.txt
                      5: //
                      6: 
                      7: //
                      8: // ホストネットワークの usermode (SLIRP) ドライバ
                      9: //
                     10: 
                     11: //
                     12: // NetDriverSlirp            SlirpThread
                     13: // (HostNet スレッド)      : (裏スレッド)
                     14: //
                     15: // 送信時のフロー:
                     16: //     NetDriverSlirp() は送信パケットをパイプ txfd (=txfd_w) に書き込む。
                     17: //     SlirpThread 側で txfd_r に着信するので取り出して slirp_input() へ送る。
                     18: //
                     19: // NetDriverSlirp::Write() :
                     20: //     |
                     21: //     |    txfd(=txfd_w)       txfd_r
                     22: //     +--------------->| pipe |------+         … パイプで裏スレッドに送信
                     23: //     |                              |
                     24: //   <-+                   :          v
                     25: //                                   --- kevent @ ThreadRun()
                     26: //                         :          |
                     27: //                               SlirpThread::Write()
                     28: //                         :          |
                     29: //                                    +-----> slirp_input()
                     30: //
                     31: 
                     32: // 受信時のフロー:
                     33: //     SlirpThread 側のイベントループにて、管理する受信ディスクリプタに
                     34: //     着信があれば SlirpThread::Read() がそれを読み出してパイプ rxfd_w に
                     35: //     書き込む。
                     36: //     このパイプの対向は HostNetDevice に AddOuter() で登録したものなので
                     37: //     この書き込みに対する着信で HostDevice::Dispatch() が動き、
                     38: //     その結果 NetDriverSlirp() が呼ばれる。
                     39: //     NetDriverSlirp() はこのパイプからパケットを読み出して親に引き渡す。
                     40: //
                     41: //                                   --- kevent @ ThreadRun()
                     42: //                                    |
                     43: //                               SlirpThread::Read()
                     44: //                                    |
                     45: //          rxfd(=rxfd_r)       rxfd_w|
                     46: //      +---------------| pipe |<-----+
                     47: //      | 着信通知         ‖
                     48: //      v                  ‖
                     49: //     --- kqueue          ‖
                     50: //      |                  ‖
                     51: // HostNetDevice::Read()   ‖
                     52: //      |                  ‖
                     53: // NetDriverSlirp::Read()  ‖
                     54: //      |                  ‖
                     55: //    パイプから受信    <==++
                     56: //      |
                     57: //   <--+ VM 側へ
                     58: 
                     59: #include "netdriver_slirp.h"
                     60: #include "hostnet.h"
                     61: #include "scheduler.h"
                     62: #include <sys/socket.h>
                     63: #include <sys/uio.h>
                     64: #include <slirp/libslirp.h>
                     65: 
                     66: //
                     67: // NetDriver 側スレッド
                     68: //
                     69: 
                     70: // コンストラクタ
                     71: NetDriverSlirp::NetDriverSlirp(HostDevice *hostdev_)
1.1.1.3   root       72:        : inherited(hostdev_, "usermode")
1.1       root       73: {
                     74:        txd = -1;
                     75:        rxd = -1;
                     76: }
                     77: 
                     78: // デストラクタ
                     79: NetDriverSlirp::~NetDriverSlirp()
                     80: {
                     81:        Close();
                     82: }
                     83: 
                     84: // ログレベルを設定。
                     85: void
                     86: NetDriverSlirp::SetLogLevel(int loglevel_)
                     87: {
                     88:        inherited::SetLogLevel(loglevel_);
                     89: 
                     90:        // バックエンドにも伝達。
                     91:        if ((bool)backend) {
                     92:                backend->SetLogLevel(loglevel_);
                     93:        }
                     94: }
                     95: 
                     96: // ドライバ初期化
                     97: bool
1.1.1.3   root       98: NetDriverSlirp::InitDriver(bool startup)
1.1       root       99: {
                    100:        putmsg(1, "trying usermode...");
                    101: 
                    102:        if (slirp_occupied) {
1.1.1.3   root      103:                errmsg = "'usermode' is already in use by another hostnet-driver";
                    104:                putmsg(1, "%s", errmsg.c_str());
1.1       root      105:                return false;
                    106:        }
                    107: 
1.1.1.2   root      108:        try {
                    109:                backend.reset(new SlirpThread(this));
                    110:        } catch (...) { }
1.1       root      111:        if ((bool)backend == false) {
1.1.1.3   root      112:                errmsg = string_format("Failed to initialize SlirpThread at %s",
                    113:                        __method__);
                    114:                putmsg(1, "%s", errmsg.c_str());
1.1       root      115:                return false;
                    116:        }
                    117: 
                    118:        // ディスクリプタは裏スレッドが所有しているのでこちらでは解放しないこと。
                    119:        const std::string key = hostdev->GetConfigKey();
                    120:        if (backend->InitBackend(key, &rxd, &txd) == false) {
1.1.1.3   root      121:                errmsg = backend->errmsg;
                    122:                putmsg(1, "%s", errmsg.c_str());
1.1       root      123:                return false;
                    124:        }
                    125: 
                    126:        // 読み込み側を Slirp からの受信端として親に登録。
                    127:        if (hostdev->AddOuter(rxd) < 0) {
1.1.1.3   root      128:                errmsg = string_format("AddOuter(rxd=%d): %s", rxd, strerror(errno));
                    129:                putmsg(1, "%s", errmsg.c_str());
1.1       root      130:                return false;
                    131:        }
                    132: 
1.1.1.3   root      133:        // 起動時は一斉に StartThread() されて backend のスレッドも起動するが、
                    134:        // 再選択時はここで手動でスレッドを起動する必要がある。
                    135:        if (startup == false) {
                    136:                backend->StartThread();
                    137:        }
                    138: 
1.1       root      139:        slirp_occupied = true;
                    140:        putmsg(1, "opened");
                    141:        return true;
                    142: }
                    143: 
                    144: // クローズ
                    145: void
                    146: NetDriverSlirp::Close()
                    147: {
                    148:        // rxd がすでに閉じられていたらとかはここでは関係なくて、
                    149:        // この番号を kqueue から外す必要がある。(Linux)
1.1.1.3   root      150:        if (rxd >= 0) {
                    151:                hostdev->DelOuter(rxd);
                    152:        }
1.1       root      153: 
                    154:        // txd, rxd は裏スレッドの所有なのでこちらでは何もしない。
                    155: 
                    156:        if ((bool)backend) {
                    157:                backend->Terminate();
                    158:                backend->Close();
1.1.1.3   root      159:                backend.reset();
1.1       root      160:        }
                    161:        slirp_occupied = false;
                    162: }
                    163: 
                    164: // モニタ (ドライバ依存情報のみ)
                    165: void
1.1.1.5 ! root      166: NetDriverSlirp::MonitorScreenMD(TextScreen& screen, int y)
1.1       root      167: {
                    168:        // なし
                    169: }
                    170: 
                    171: // パケットを送信する。
                    172: // と言っても裏スレッドに送り直すだけ。
                    173: void
                    174: NetDriverSlirp::Write(const void *buf, int buflen)
                    175: {
                    176:        struct iovec iov[2];
1.1.1.5 ! root      177:        ssize_t n;
1.1       root      178: 
                    179:        // 先頭4バイトに後続パケット長を入れておく。
                    180:        static_assert(sizeof(buflen) == sizeof(uint32), "");
                    181:        iov[0].iov_base = &buflen;
                    182:        iov[0].iov_len  = sizeof(buflen);
                    183:        iov[1].iov_base = const_cast<void *>(buf);
                    184:        iov[1].iov_len  = buflen;
1.1.1.5 ! root      185:        n = writev(txd, &iov[0], countof(iov));
        !           186:        if (n < 0) {
        !           187:                putmsg(0, "writev(%zu+%d) failed: %s",
        !           188:                        sizeof(buflen), buflen, strerror(errno));
        !           189:                return;
        !           190:        }
        !           191:        if (n < sizeof(buflen) + buflen) {
        !           192:                putmsg(0, "writev(%zu+%d): short(%zd)", sizeof(buflen), buflen, n);
1.1       root      193:                return;
                    194:        }
                    195: }
                    196: 
                    197: // パケットを受信する。
                    198: // これは rxd に着信があってから HostDevice::Dispatch() から呼ばれるほう。
                    199: int
                    200: NetDriverSlirp::Read(NetPacket *p)
                    201: {
1.1.1.5 ! root      202:        std::vector<uint8> databuf;
        !           203:        ssize_t r;
        !           204:        ssize_t len;
        !           205:        ssize_t bufsize;
        !           206:        uint8 *buf;
        !           207:        uint32 datalen;
1.1       root      208: 
                    209:        // 先頭4バイトに後続パケット長を入れてある。
1.1.1.5 ! root      210:        buf = reinterpret_cast<uint8 *>(&datalen);
        !           211:        bufsize = sizeof(datalen);
        !           212:        for (len = 0; len < bufsize; ) {
        !           213:                r = read(rxd, buf + len, bufsize - len);
        !           214:                if (r < 0) {
        !           215:                        putmsg(0, "read(len) failed: %s", strerror(errno));
        !           216:                        goto nodata;
        !           217:                }
        !           218:                if (r == 0) {
        !           219:                        putmsg(0, "read(len) failed: EOF?");
        !           220:                        goto nodata;
        !           221:                }
        !           222:                len += r;
1.1       root      223:        }
                    224: 
1.1.1.5 ! root      225:        // データ本体。
        !           226:        databuf.resize(datalen);
        !           227:        len = 0;
        !           228:        for (auto datasize = databuf.size(); len < datasize; ) {
        !           229:                r = read(rxd, databuf.data() + len, datasize - len);
        !           230:                if (r < 0) {
        !           231:                        putmsg(0, "read(data) failed: %s", strerror(errno));
        !           232:                        goto nodata;
        !           233:                }
        !           234:                if (r == 0) {
        !           235:                        putmsg(0, "read(data) failed: EOF?");
        !           236:                        goto nodata;
        !           237:                }
        !           238:                len += r;
1.1       root      239:        }
1.1.1.5 ! root      240:        p->Assign(databuf.data(), len);
1.1       root      241: 
                    242:        return 0;
1.1.1.5 ! root      243: 
        !           244:  nodata:
        !           245:        // 一旦全部読み捨てるくらいしか。
        !           246:        std::vector<uint8> dropbuf(1024);
        !           247:        for (;;) {
        !           248:                r = read(rxd, dropbuf.data(), dropbuf.size());
        !           249:                if (r <= 0) {
        !           250:                        break;
        !           251:                }
        !           252:        }
        !           253:        return NODATA;
1.1       root      254: }
                    255: 
                    256: // usermode を使えるのは同時に1人だけに限定する。
                    257: /*static*/ bool NetDriverSlirp::slirp_occupied = false;
                    258: 
                    259: 
                    260: //
                    261: // 裏スレッド
                    262: //
                    263: 
                    264: // おそらく同じはずなので無駄な変換はしない。
                    265: #if SLIRP_POLL_IN  == POLLIN  && \
                    266:        SLIRP_POLL_OUT == POLLOUT && \
                    267:        SLIRP_POLL_PRI == POLLPRI && \
                    268:        SLIRP_POLL_ERR == POLLERR && \
                    269:        SLIRP_POLL_HUP == POLLHUP
                    270: #define POLL_EVENT_to_SLIRP_EVENT(x)   (x)
                    271: #define SLIRP_EVENT_to_POLL_EVENT(x)   (x)
                    272: #else
                    273: static int POLL_EVENT_to_SLIRP_EVENT(int pollevents)
                    274: {
                    275:        int slevents = 0;
                    276:        if ((pollevents & POLLIN))      slevents |= SLIRP_POLL_IN;
                    277:        if ((pollevents & POLLOUT))     slevents |= SLIRP_POLL_OUT;
                    278:        if ((pollevents & POLLPRI))     slevents |= SLIRP_POLL_PRI;
                    279:        if ((pollevents & POLLERR))     slevents |= SLIRP_POLL_ERR;
                    280:        if ((pollevents & POLLHUP))     slevents |= SLIRP_POLL_HUP;
                    281:        return slevents;
                    282: }
                    283: static int SLIRP_EVENT_to_POLL_EVENT(int slevents)
                    284: {
                    285:        int pollevents = 0;
                    286:        if ((slevents & SLIRP_POLL_IN))         pollevents |= POLLIN;
                    287:        if ((slevents & SLIRP_POLL_OUT))        pollevents |= POLLOUT;
                    288:        if ((slevents & SLIRP_POLL_PRI))        pollevents |= POLLPRI;
                    289:        if ((slevents & SLIRP_POLL_ERR))        pollevents |= POLLERR;
                    290:        if ((slevents & SLIRP_POLL_HUP))        pollevents |= POLLHUP;
                    291:        return pollevents;
                    292: }
                    293: #endif
                    294: 
                    295: // タイマーは TimerNewCB() コールバックで確保して返す。
                    296: // 確保した領域そのものはライブラリが管理し、TimerFreeCB() コールバックで
                    297: // 解放する。
                    298: // 一方 timerlist は有効なタイマーのリストなので、期限が来たらこのリスト
                    299: // からは削除してよい。
                    300: class SlirpTimer
                    301: {
                    302:  public:
                    303:        SlirpTimer(SlirpTimerCb func_, void *arg_)
                    304:        {
                    305:                func = func_;
                    306:                arg = arg_;
                    307:        }
                    308: 
                    309:        SlirpTimerCb func {};
                    310:        void *arg {};
                    311:        int64 expire_msec {};   // 期限の(仮想?)絶対時刻 [msec]
                    312:        int num {};                             // デバッグ用のタイマー番号。
                    313: };
                    314: 
                    315: static ssize_t send_packet_cb(const void *, size_t, void *);
                    316: static void guest_error_cb(const char *msg, void *);
                    317: static int64 clock_get_ns_cb(void *);
                    318: static void *timer_new_cb(SlirpTimerCb cb, void *cb_arg, void *);
                    319: static void timer_free_cb(void *timer, void *);
                    320: static void timer_mod_cb(void *timer, int64 expire_msec, void *);
                    321: static void register_poll_fd_cb(int fd, void *);
                    322: static void unregister_poll_fd_cb(int fd, void *);
                    323: static void notify_cb(void *);
                    324: static int  add_poll_cb(int fd, int events, void *);
                    325: static int  get_revents_cb(int idx, void *);
                    326: 
                    327: static SlirpCb slirp_callbacks = {
                    328:        .send_packet            = send_packet_cb,
                    329:        .guest_error            = guest_error_cb,
                    330:        .clock_get_ns           = clock_get_ns_cb,
                    331:        .timer_new                      = timer_new_cb,
                    332:        .timer_free                     = timer_free_cb,
                    333:        .timer_mod                      = timer_mod_cb,
                    334:        .register_poll_fd       = register_poll_fd_cb,
                    335:        .unregister_poll_fd     = unregister_poll_fd_cb,
                    336:        .notify                         = notify_cb,
                    337: };
                    338: 
                    339: // コンストラクタ
                    340: SlirpThread::SlirpThread(NetDriverSlirp *parent_)
                    341:        : inherited(OBJ_NONE)
                    342: {
                    343:        parent = parent_;
                    344:        hostnet = dynamic_cast<HostNetDevice *>(parent->GetHostDev());
                    345:        SetName(parent->GetName());
1.1.1.4   root      346:        SetThreadName("SlirpThread");
1.1       root      347: 
                    348:        // コンストラクト後ただちにログ出力できるようここで一度追従しておく。
                    349:        // 以降は親 (NetDriver側) の SetLogLevel() で変更する。
                    350:        loglevel = parent->loglevel;
                    351: }
                    352: 
                    353: // デストラクタ
                    354: SlirpThread::~SlirpThread()
                    355: {
                    356:        TerminateThread();
1.1.1.3   root      357:        Close();
1.1       root      358: }
                    359: 
                    360: // 初期化。
                    361: // Device::Init() とは違い、NetDriver::InitDriver() から呼ばれる独自版。
                    362: // (表スレッドから見た裏スレッドへの) 受信側(RX)と送信側(TX)の
1.1.1.3   root      363: // ディスクリプタを書き戻す。
                    364: // 成功すれば true を返す。
                    365: // 失敗すれば (こちらのメンバ変数の) errmsg をセットして false を返す。
1.1       root      366: // これはスレッド起動前に (VM スレッドで) 呼ばれる。
                    367: bool
                    368: SlirpThread::InitBackend(const std::string& key, int *rxdp, int *txdp)
                    369: {
                    370:        SlirpConfig config;
                    371:        struct in_addr vnetwork;
                    372:        struct in_addr vnetmask;
                    373:        struct in6_addr vprefix_addr6;
                    374:        uint vprefix_len;
                    375:        int fds[2];
                    376: 
1.1.1.3   root      377:        const ConfigItem& netitem = gConfig->Find(key + "-usermode-net");
                    378:        if (ParseConfigNet(netitem, &vnetwork, &vnetmask) == false) {
                    379:                return false;
1.1       root      380:        }
                    381: 
1.1.1.3   root      382:        const ConfigItem& net6item = gConfig->Find(key + "-usermode-net6");
                    383:        if (ParseConfigNet6(net6item, &vprefix_addr6, &vprefix_len) == false) {
                    384:                return false;
1.1       root      385:        }
                    386: 
1.1.1.3   root      387:        // hostnet-usermode-hostfwd=<entry1>[;<entry2>[;<entry3>...]]
1.1       root      388:        const ConfigItem& fwditem = gConfig->Find(key + "-usermode-hostfwd");
                    389:        auto entries = string_split(fwditem.AsString(), ';');
1.1.1.3   root      390:        if (entries.size() == 1) {
                    391:                std::string entry = string_trim(entries[0]);
                    392:                if (ParseConfigHostFwdEntry(fwditem, entry, "") == false) {
                    393:                        fwdinfo.clear();
1.1       root      394:                        return false;
                    395:                }
1.1.1.3   root      396:        } else {
                    397:                for (const auto& e : entries) {
                    398:                        std::string entry = string_trim(e);
                    399:                        // エントリが複数ある時はそのうちのどこで起きたか表示したい。
                    400:                        std::string where = " at \"" + entry + "\"";
                    401:                        if (ParseConfigHostFwdEntry(fwditem, entry, where) == false) {
                    402:                                fwdinfo.clear();
                    403:                                return false;
                    404:                        }
1.1       root      405:                }
                    406:        }
                    407: 
                    408:        // Slirp を初期化。
                    409:        memset(&config, 0, sizeof(config));
                    410:        config.version = 4;
                    411:        config.in_enabled = true;
                    412:        config.vnetwork = vnetwork;
                    413:        config.vnetmask = vnetmask;
                    414:        config.vhost.s_addr = htonl(ntohl(vnetwork.s_addr) + 0x01);
                    415:        config.vnameserver.s_addr = htonl(ntohl(vnetwork.s_addr) + 0x02);
                    416:        config.vdhcp_start.s_addr = htonl(ntohl(vnetwork.s_addr) + 0x0a);
                    417:        config.in6_enabled = true;
                    418:        config.vprefix_addr6 = vprefix_addr6;
                    419:        config.vprefix_len   = vprefix_len;
                    420:        config.vhost6 = vprefix_addr6;
                    421:        config.vhost6.s6_addr[15] = 1;
                    422:        config.vnameserver6 = vprefix_addr6;
                    423:        config.vnameserver6.s6_addr[15] = 2;
                    424:        gw6 = config.vhost6;
                    425:        dns6 = config.vnameserver6;
                    426: 
                    427:        sl = slirp_new(&config, &slirp_callbacks, this);
                    428:        if (sl == NULL) {
1.1.1.3   root      429:                errmsg = "slirp_new() failed";
1.1       root      430:                return false;
                    431:        }
                    432: 
                    433:        for (const auto& fwd : fwdinfo) {
                    434:                int r = slirp_add_hostfwd(sl, fwd.is_udp,
                    435:                        fwd.host.sin_addr, fwd.host.sin_port,
                    436:                        fwd.guest.sin_addr, fwd.guest.sin_port);
                    437:                if (r != 0) {
                    438:                        char hname[INET_ADDRSTRLEN];
                    439:                        char gname[INET_ADDRSTRLEN];
                    440:                        hname[0] = '\0';
                    441:                        gname[0] = '\0';
                    442:                        inet_ntop(AF_INET, &fwd.host.sin_addr,
                    443:                                hname, (socklen_t)sizeof(hname));
                    444:                        inet_ntop(AF_INET, &fwd.guest.sin_addr,
                    445:                                gname, (socklen_t)sizeof(gname));
1.1.1.3   root      446:                        errmsg = string_format("slirp_add_hostfwd(%s,%s:%d,%s:%d) failed",
1.1       root      447:                                (fwd.is_udp ? "udp" : "tcp"),
                    448:                                hname, fwd.host.sin_port, gname, fwd.guest.sin_port);
1.1.1.3   root      449:                        goto abort;
1.1       root      450:                }
                    451:        }
                    452: 
                    453:        // libslirp のバージョンをチェック。
1.1.1.3   root      454:        {
                    455:                const char *version_str = slirp_version_string();
                    456:                uint major;
                    457:                uint minor;
                    458:                uint patch;
                    459:                if (sscanf(version_str, "%u.%u.%u", &major, &minor, &patch) == 3) {
                    460:                        putmsg(1, "libslirp version %u.%u", major, minor);
                    461:                        ver = VER(major, minor, patch);
                    462:                }
1.1       root      463:        }
                    464: 
                    465:        // 送信用のパイプを用意。
                    466:        if (pipe(fds) < 0) {
1.1.1.3   root      467:                errmsg = string_format("pipe(): %s", strerror(errno));
                    468:                goto abort;
1.1       root      469:        }
                    470:        txd_r = fds[0];
                    471:        txd_w = fds[1];
                    472: 
                    473:        // 受信用のパイプを用意。
                    474:        if (pipe(fds) < 0) {
1.1.1.3   root      475:                errmsg = string_format("pipe(): %s", strerror(errno));
                    476:                goto abort;
1.1       root      477:        }
                    478:        rxd_r = fds[0];
                    479:        rxd_w = fds[1];
                    480: 
                    481:        *rxdp = rxd_r;
                    482:        *txdp = txd_w;
                    483: 
1.1.1.3   root      484:        // モニタを設定。(登録自体は hostnet で行ってある)
                    485:        monitor = gMonitorManager->Find(ID_MONITOR_SLIRP);
                    486:        assert(monitor);
                    487:        monitor->obj = this;
1.1.1.5 ! root      488:        monitor->SetCallback(&SlirpThread::MonitorScreen);
1.1       root      489:        monitor->SetSize(80, 40);
                    490: 
                    491:        return true;
1.1.1.3   root      492: 
                    493:  abort:
                    494:        Close();
                    495:        return false;
1.1       root      496: }
                    497: 
1.1.1.3   root      498: // hostnetN-usermode-net の引数 <addr>/<netmask> or <addr>/<netlen> を
                    499: // パースして *pnetwork, *pnetmask に格納する。
                    500: // 失敗したら errmsg をセットして false を返す。
1.1       root      501: bool
1.1.1.3   root      502: SlirpThread::ParseConfigNet(const ConfigItem& item,
                    503:        struct in_addr *pnetwork, struct in_addr *pnetmask)
1.1       root      504: {
1.1.1.3   root      505:        std::string net = item.AsString();
1.1       root      506: 
1.1.1.3   root      507:        auto list = string_split(net, '/');
                    508:        if (list.empty()) {
                    509:         syntax_error:
                    510:                errmsg = item.ErrMsg("Syntax is <addr>/<netmask>");
                    511:                return false;
                    512:        }
1.1       root      513: 
1.1.1.3   root      514:        // アドレス。
                    515:        auto addr = list[0];
                    516:        if (addr.empty()) {
                    517:                goto syntax_error;
                    518:        }
                    519:        if (inet_pton(AF_INET, addr.c_str(), pnetwork) < 1) {
                    520:                errmsg = item.ErrMsg("Invalid network address");
                    521:                return false;
                    522:        }
                    523: 
                    524:        // 区切りの '/'。
                    525:        if (list.size() == 1) {
                    526:                goto syntax_error;
                    527:        }
                    528: 
                    529:        // ここからネットマスク or ネットマスク長。
                    530:        auto mask = list[1];
                    531:        const char *p = mask.c_str();
                    532: 
                    533:        // アドレスでも長さでも必ず1文字目は10進数値。
                    534:        // 特に strtoul() は先頭のスペースを無視して成功してしまうので
                    535:        // 先頭がスペースでないことはチェックする必要がある。
                    536:        if (*p < '0' || *p > '9') {
                    537:                goto syntax_error;
                    538:        }
                    539:        char *end;
                    540:        errno = 0;
                    541:        unsigned long netlen = strtoul(p, &end, 10);
                    542:        if (*end == '\0') {
                    543:                // 数値だけから成っていれば、ネットマスク長かも知れない。
                    544: 
                    545:                if (errno == ERANGE) {
                    546:                 out_of_range:
                    547:                        errmsg = item.ErrMsg("netmask len is out of range");
1.1       root      548:                        return false;
1.1.1.3   root      549:                } else if (errno != 0) {
                    550:                        errmsg = item.ErrMsg("Invalid netmask len: %s", strerror(errno));
                    551:                        return false;
                    552:                }
                    553:                // DHCP 配布アドレスまで入れるには最小でも /28 (16-2個) が必要。
                    554:                if (netlen < 1 || netlen > 28) {
                    555:                        goto out_of_range;
1.1       root      556:                }
1.1.1.3   root      557:                pnetmask->s_addr = htonl(((1U << netlen) - 1) << (32 - netlen));
                    558:        } else {
                    559:                // 数値以外も含まれていれば、ネットマスクかも知れない。
                    560:                if (inet_pton(AF_INET, p, pnetmask) < 1) {
                    561:                        errmsg = item.ErrMsg("Invalid netmask");
1.1       root      562:                        return false;
                    563:                }
1.1.1.3   root      564:        }
                    565: 
                    566:        // これ以上続くのはエラー。
                    567:        if (list.size() > 2) {
                    568:                goto syntax_error;
                    569:        }
                    570: 
                    571:        return true;
                    572: }
                    573: 
                    574: // hostnetN-usermode-net6 の引数 <addr6>/<prefixlen> をパースして
                    575: // *paddr6, *plen に格納する。
                    576: // 失敗したら errmsg をセットして false を返す。
                    577: bool
                    578: SlirpThread::ParseConfigNet6(const ConfigItem& item,
                    579:        struct in6_addr *paddr6, uint *plen)
                    580: {
                    581:        std::string net6 = item.AsString();
                    582: 
                    583:        auto list = string_split(net6, '/');
                    584:        if (list.empty()) {
                    585:         syntax_error:
                    586:                errmsg = item.ErrMsg("Syntax is <v6addr>/<len>");
                    587:                return false;
                    588:        }
                    589: 
                    590:        // アドレス。
                    591:        auto addr = list[0];
                    592:        if (addr.empty()) {
                    593:                goto syntax_error;
                    594:        }
                    595:        if (inet_pton(AF_INET6, addr.c_str(), paddr6) < 1) {
                    596:                errmsg = item.ErrMsg("Invalid network address");
                    597:                return false;
                    598:        }
                    599: 
                    600:        // 区切りの '/'。
                    601:        if (list.size() == 1) {
                    602:                goto syntax_error;
                    603:        }
                    604: 
                    605:        // プレフィックス長。
                    606:        auto prefixlen = list[1];
                    607:        const char *p = prefixlen.c_str();
                    608: 
                    609:        // strtoul() は先頭のスペースを無視して成功してしまうので
                    610:        // 先頭がスペースでないことはチェックする必要がある。
                    611:        if (*p < '0' || *p > '9') {
                    612:                goto syntax_error;
                    613:        }
                    614:        char *end;
                    615:        errno = 0;
                    616:        unsigned long len = strtoul(p, &end, 10);
                    617:        if (*end != '\0') {
                    618:                goto syntax_error;
                    619:        }
                    620:        if (errno == ERANGE) {
                    621:         out_of_range:
                    622:                errmsg = item.ErrMsg("prefixlen is out of range");
                    623:                return false;
                    624:        } else if (errno != 0) {
                    625:                errmsg = item.ErrMsg("Invalid netmask len: %s", strerror(errno));
                    626:                return false;
                    627:        }
                    628:        // 適切な範囲がよく分からないのでとりあえず物理限界だけチェック。
                    629:        if (len < 1 || len > 124) {
                    630:                goto out_of_range;
                    631:        }
                    632:        *plen = len;
                    633: 
                    634:        // これ以上続くのはエラー。
                    635:        if (list.size() > 2) {
                    636:                goto syntax_error;
                    637:        }
                    638: 
                    639:        return true;
                    640: }
                    641: 
                    642: // hostnetN-usermode-hostfwd の引数のエントリ1つ分をパースして fwdinfo に
                    643: // 追加する。失敗したら errmsg をセットして false を返す。
                    644: //
                    645: // 引数は <entry> を複数ならセミコロンで区切ったもの。
                    646: // ここに渡される一つの <entry> の書式は次の通り。
                    647: // <entry> := <proto>,[<hostaddr>:]<hostport>,[<guestaddr>:]<guestport>
                    648: bool
                    649: SlirpThread::ParseConfigHostFwdEntry(const ConfigItem& item,
                    650:        const std::string& entry, const std::string& where)
                    651: {
                    652:        int r;
                    653: 
                    654:        // エントリが空なのは許容するか。
                    655:        if (entry.empty()) {
                    656:                return true;
                    657:        }
                    658: 
                    659:        auto val = string_split(entry, ',');
                    660:        if (val.size() != 3) {
                    661:         syntax_error:
                    662:                errmsg = item.ErrMsg(
                    663:                 "Syntax is <proto>,[<hostaddr>:]<port>,[<guestaddr>]:<port>[;...]"
                    664:                        + where);
                    665:                return false;
                    666:        }
                    667: 
                    668:        FwdInfo fwd;
                    669:        memset(&fwd, 0, sizeof(fwd));
                    670: 
                    671:        // proto
                    672:        auto proto = string_trim(val[0]);
                    673:        if (strcasecmp(proto.c_str(), "tcp") == 0) {
                    674:                fwd.is_udp = 0;
                    675:        } else if (strcasecmp(proto.c_str(), "udp") == 0) {
                    676:                fwd.is_udp = 1;
1.1       root      677:        } else {
1.1.1.3   root      678:                errmsg = item.ErrMsg("protocol must be \"tcp\" or \"udp\"" + where);
                    679:                return false;
1.1       root      680:        }
                    681: 
1.1.1.3   root      682:        // host
                    683:        r = ParseAddrPort(item, val[1], &fwd.host, "host", where);
                    684:        if (r < 0) {
                    685:                goto syntax_error;
                    686:        } else if (r == 0) {
1.1       root      687:                return false;
                    688:        }
1.1.1.3   root      689: 
                    690:        // guest
                    691:        r = ParseAddrPort(item, val[2], &fwd.guest, "guest", where);
                    692:        if (r < 0) {
                    693:                goto syntax_error;
                    694:        } else if (r == 0) {
                    695:                return false;
                    696:        }
                    697: 
                    698:        fwdinfo.push_back(fwd);
1.1       root      699: 
                    700:        return true;
                    701: }
                    702: 
1.1.1.3   root      703: // "[アドレス:]ポート" 形式の hostport_arg からアドレスとポートを取り出して
                    704: // sin に格納する。
                    705: // 戻り値は 1 が成功、
                    706: // 0 なら失敗で errno はセット済み、
                    707: // -1 なら失敗で呼び出し元で syntax_error へ分岐。
                    708: int
                    709: SlirpThread::ParseAddrPort(const ConfigItem& item,
                    710:        const std::string& hostport_arg, struct sockaddr_in *sin,
                    711:        const char *which, const std::string& where)
                    712: {
                    713:        std::string hostport = string_trim(hostport_arg);
                    714:        if (hostport.empty()) {
                    715:                return -1;
                    716:        }
                    717: 
                    718:        // ':' で分離。
                    719:        std::string port;
                    720:        auto list = string_split(hostport, ':');
                    721:        if (list.size() == 1) {
                    722:                // ポートのみ。
                    723:                port = list[0];
                    724:        } else {
                    725:                // list.size() == 0 はないので、2以上。
                    726:                std::string host;
                    727:                host = list[0];
                    728:                port = list[1];
                    729: 
                    730:                // アドレス。
                    731:                if (host.empty()) {
                    732:                        return -1;
                    733:                }
                    734:                if (inet_pton(AF_INET, host.c_str(), &sin->sin_addr) < 1) {
                    735:                        errmsg = item.ErrMsg("Invalid %s address%s", which, where.c_str());
                    736:                        return 0;
                    737:                }
                    738:        }
                    739: 
                    740:        // ポート。
                    741:        const char *p = port.c_str();
                    742:        if (*p < '0' || *p > '9') {
                    743:         invalid_port:
                    744:                errmsg = item.ErrMsg("Invalid %s port%s", which, where.c_str());
                    745:                return 0;
                    746:        }
                    747:        char *end;
                    748:        errno = 0;
                    749:        unsigned long portnum = strtoul(p, &end, 10);
                    750:        if (*end != '\0') {
                    751:                goto invalid_port;
                    752:        }
                    753:        if (errno == ERANGE) {
                    754:         out_of_range:
                    755:                errmsg = item.ErrMsg("%s port is out of range%s", which, where.c_str());
                    756:                return 0;
                    757:        }
                    758:        if (errno != 0) {
                    759:                errmsg = item.ErrMsg("%s port: %s%s",
                    760:                        which, strerror(errno), where.c_str());
                    761:                return 0;
                    762:        }
                    763:        if (portnum < 1 || portnum > 65535) {
                    764:                goto out_of_range;
                    765:        }
                    766: 
                    767:        // これ以上続くのはエラー。
                    768:        if (list.size() > 2) {
                    769:                return -1;
                    770:        }
                    771: 
                    772:        sin->sin_port = portnum;
                    773:        return 1;
                    774: }
                    775: 
1.1       root      776: void
                    777: SlirpThread::Close()
                    778: {
                    779:        txd_r.Close();
                    780:        txd_w.Close();
                    781:        rxd_r.Close();
                    782:        rxd_w.Close();
                    783: 
                    784:        if (sl) {
                    785:                for (const auto& fwd : fwdinfo) {
                    786:                        slirp_remove_hostfwd(sl, fwd.is_udp,
                    787:                                fwd.host.sin_addr, fwd.host.sin_port);
                    788:                }
                    789:                slirp_cleanup(sl);
                    790:                sl = NULL;
                    791:        }
                    792: }
                    793: 
                    794: // スレッドの終了を指示
                    795: void
                    796: SlirpThread::Terminate()
                    797: {
                    798:        txd_r.Close();
1.1.1.5 ! root      799:        txd_w.Close();
        !           800:        rxd_r.Close();
        !           801:        rxd_w.Close();
1.1       root      802: }
                    803: 
                    804: // スレッド
                    805: void
                    806: SlirpThread::ThreadRun()
                    807: {
                    808:        SetThreadAffinityHint(AffinityClass::Light);
                    809: 
                    810:        while (exit_requested == false) {
                    811:                // タイマー処理。
1.1.1.5 ! root      812:                int64 cur_msec = nsec_to_msec(ClockGetNsCB());
1.1       root      813:                for (auto it = timerlist.begin(); it != timerlist.end(); ) {
                    814:                        SlirpTimer *timer = *it;
                    815:                        if (timer->expire_msec <= cur_msec) {
                    816:                                // 期限が来ていれば登録されているハンドラを実行。
                    817:                                // このハンドラ内から TimerModCB() が呼ばれて
                    818:                                // timerlist が書き換わる可能性があるので先に削除。
                    819:                                timerlist.erase(it);
                    820:                                timer->func(timer->arg);
                    821:                                // この場合 it の状態が保証されなくなるので、
                    822:                                // もう一度先頭からやり直す。
                    823:                                it = timerlist.begin();
                    824:                        } else {
                    825:                                it++;
                    826:                        }
                    827:                }
                    828: 
                    829:                // poll に入る前に内部のテーブル(文字列)を取得しておく。
                    830:                UpdateInfo();
                    831: 
                    832:                // 先頭を txd とする。
                    833:                pollfds.clear();
                    834:                AddPollCB(txd_r, SLIRP_POLL_IN);
                    835: 
                    836:                // slirp ハンドルが持っているディスクリプタを pollfds[] にセット。
                    837:                // コールバックで都度 AddPollCB() が呼ばれてそいつが追加している。
                    838:                //
                    839:                // slirp_pollfds_fill() の &timeout_ms 引数は、timeout_ms を
                    840:                // 書き出す(out パラメータ)ではなく、現行の timeout_ms を必要に
                    841:                // 応じて更新というか短くする(ref パラメータ)。つまり呼び出し前に
                    842:                // 適切な値をセットしておく必要がある。値は必ず 1000 以下にしてくる
                    843:                // ため、初期値も 1000 をセットするのがよさそう。
                    844:                // ドキュメントをちゃんと書け。
                    845:                uint32 timeout_ms = 1000;
                    846:                slirp_pollfds_fill(sl, &timeout_ms, add_poll_cb, this);
                    847: 
                    848:                int err = poll(pollfds.data(), pollfds.size(), timeout_ms);
                    849:                if (err < 0) {
                    850:                        if (errno == EINTR) {
                    851:                                continue;
                    852:                        }
                    853:                        // XXX どうする?
                    854:                        putmsg(0, "poll failed: %s", strerror(errno));
                    855:                        break;
                    856:                }
                    857: 
                    858:                // txd に何か起きた。
                    859:                if (pollfds[0].revents != 0) {
                    860:                        // txd のクローズはこのスレッドの終了通知。
                    861:                        if ((pollfds[0].revents & (POLLERR | POLLHUP | POLLNVAL))) {
                    862:                                exit_requested = true;
                    863:                                continue;
                    864:                        }
                    865: 
                    866:                        // txd への着信は VM (-> HostNet スレッド) からのパケット送信。
                    867:                        if ((pollfds[0].revents & POLLIN)) {
                    868:                                Write();
                    869:                        }
                    870:                }
                    871: 
                    872:                // poll() 完了後に slirp ハンドルの持っている各ディスクリプタの
                    873:                // revents (GetReventsCB() コールバックを通じて取得する) に応じた
                    874:                // 処理をするようだ。
                    875:                slirp_pollfds_poll(sl, (err < 0), get_revents_cb, this);
                    876:        }
                    877: }
                    878: 
                    879: // slirp_pollfds_fill() から呼ばれるコールバック。
                    880: // fd, events をこっちの pollfds[] に追加し、追加したインデックスを返す。
                    881: int
                    882: SlirpThread::AddPollCB(int fd, int slevents)
                    883: {
                    884:        struct pollfd pfd;
                    885: 
                    886:        pfd.fd = fd;
                    887:        pfd.events = SLIRP_EVENT_to_POLL_EVENT(slevents);
                    888:        pfd.revents = 0;
                    889: 
                    890:        int idx = pollfds.size();
                    891:        pollfds.emplace_back(pfd);
                    892:        return idx;
                    893: }
                    894: 
                    895: // slirp_pollfds_poll() から呼ばれるコールバック。
                    896: // pollfds[idx] の revents (SLRIP_POLL_*) を返す。
                    897: int
                    898: SlirpThread::GetReventsCB(int idx)
                    899: {
                    900:        if (idx < 0 || idx >= pollfds.size()) {
                    901:                return 0;
                    902:        }
                    903: 
                    904:        int slevents = POLL_EVENT_to_SLIRP_EVENT(pollfds[idx].revents);
                    905:        return slevents;
                    906: }
                    907: 
                    908: // HostNet(NetDriver) スレッドから txd に着信したパケットを Slirp に送信する。
                    909: void
                    910: SlirpThread::Write()
                    911: {
                    912:        uint32 len;
                    913:        int r;
                    914: 
                    915:        // 先頭4バイトに後続パケット長を入れてある。
                    916:        r = read(txd_r, &len, sizeof(len));
                    917:        if (r < 0) {
                    918:                putmsg(0, "Write: read(len) failed: %s", strerror(errno));
                    919:                return;
                    920:        }
                    921: 
                    922:        std::vector<uint8> buf(len);
                    923:        r = read(txd_r, buf.data(), buf.size());
                    924:        if (r < 0) {
                    925:                putmsg(0, "Write: read(buf) failed: %s", strerror(errno));
                    926:                return;
                    927:        }
                    928: 
                    929:        // 一部のフレームを libslirp に渡す前にこちらで処理する。
                    930:        if (__predict_false(WriteHook(buf))) {
                    931:                return;
                    932:        }
                    933: 
                    934:        if (__predict_false(loglevel >= 2)) {
                    935:                putmsgn("Send to SLIRP:");
                    936:                DumpFrame(buf.data(), buf.size());
                    937:        }
                    938:        slirp_input(sl, buf.data(), buf.size());
                    939: }
                    940: 
                    941: // 一部の frame を libslirp に渡す前にこちらで処理する。
                    942: // 処理した (libslirp に渡さない) 場合は true を返す。
                    943: // 処理しない (libslirp に渡す) 場合は false を返す。
                    944: //
                    945: // 現状、自分(ルータと DNS サーバ)以外への ICMPv6 Echo Request が該当。
                    946: bool
                    947: SlirpThread::WriteHook(const std::vector<uint8>& frame) const
                    948: {
                    949:        const uint8 *payload;
                    950:        size_t payloadlen;
                    951: 
                    952:        // XXX libslirp-4.7.0 は、自身が管理するルータ・DNS サーバ以外の
                    953:        // アドレスへの ICMPv6 Echo Request の送出に対する処理が未実装。
                    954:        // それ自体はいいのだが、slirp_input() がそのパケットを受け取ると
                    955:        // GLib の機構でコンソールにログを出してしまい、このログはこちらで制御
                    956:        // 出来ない (しにくい) のにユーザに目立つ形で表示されるので大変困る。
                    957:        // そこで、このパケットを事前にここで検出して、自分で処理というか
                    958:        // ドロップして putmsg() で控えめにログを出すことにする。
                    959:        // libslirp-4.8.0 で修正された。
                    960:        if (ver >= VER(4, 8, 0)) {
                    961:                return false;
                    962:        }
                    963: 
                    964:        // イーサネットフレームが IPv6。
                    965:        if (__predict_false(frame.size() < 14)) {
                    966:                return false;
                    967:        }
                    968:        if (frame[12] != 0x86 || frame[13] != 0xdd) {
                    969:                return false;
                    970:        }
                    971: 
                    972:        struct ipv6_hdr {
                    973:                uint8 ver_cls;          // 上位4ビットが version
                    974:                uint8 clf_flw;
                    975:                uint16 flowlabel;
                    976:                uint16 payloadlen;
                    977:                uint8 nexthdr;
                    978:                uint8 hoplimit;
                    979:                uint8 srcip[16];
                    980:                uint8 dstip[16];
                    981:        } __packed;
                    982:        payload = frame.data() + 14;
                    983:        payloadlen = frame.size() - 14;
                    984:        const ipv6_hdr& ipv6 = *(const ipv6_hdr *)payload;
                    985:        if (__predict_false(payloadlen < sizeof(ipv6_hdr))) {
                    986:                return false;
                    987:        }
                    988:        // 先に NextHdr をチェック。途中に別ヘッダが挟まるケースは諦める。
                    989:        if (ipv6.nexthdr != 58) {
                    990:                return false;
                    991:        }
                    992: 
                    993:        struct icmp_hdr {
                    994:                uint8  type;
                    995:                uint8  code;
                    996:                uint16 cksum;
                    997:        } __packed;
                    998:        payload += sizeof(ipv6_hdr);
                    999:        payloadlen -= sizeof(ipv6_hdr);
                   1000:        const icmp_hdr& icmp = *(const icmp_hdr *)payload;
                   1001:        if (__predict_false(payloadlen < sizeof(icmp_hdr))) {
                   1002:                return false;
                   1003:        }
                   1004:        if (icmp.type != 128) { // ICMPV6 Echo Request
                   1005:                return false;
                   1006:        }
                   1007: 
                   1008:        // ICMPv6 Echo Reuqest は確定したのでここで宛先をチェック。
                   1009:        if (0) {
                   1010:                char srcname[100];
                   1011:                char dstname[100];
                   1012:                inet_ntop(AF_INET6, ipv6.srcip, srcname, (socklen_t)sizeof(srcname));
                   1013:                inet_ntop(AF_INET6, ipv6.dstip, dstname, (socklen_t)sizeof(dstname));
                   1014:                printf("ICMPv6 src=%s dst=%s\n", srcname, dstname);
                   1015:        }
                   1016: 
                   1017:        // 宛先が自分のルータか DNS サーバなら処理可能なので何もしない。
                   1018:        if (memcmp(ipv6.dstip, &gw6, sizeof(gw6)) == 0) {
                   1019:                return false;
                   1020:        }
                   1021:        if (memcmp(ipv6.dstip, &dns6, sizeof(dns6)) == 0) {
                   1022:                return false;
                   1023:        }
1.1.1.2   root     1024:        // リンクローカルはここで作って比較。
                   1025:        struct in6_addr linklocal;
                   1026:        memset(&linklocal, 0, sizeof(linklocal));
                   1027:        linklocal.s6_addr[0] = 0xfe;
                   1028:        linklocal.s6_addr[1] = 0x80;
                   1029:        memcpy(&linklocal.s6_addr[8], &gw6.s6_addr[8], 8);
                   1030:        if (memcmp(ipv6.dstip, &linklocal, sizeof(linklocal)) == 0) {
                   1031:                return false;
                   1032:        }
                   1033:        memcpy(&linklocal.s6_addr[8], &dns6.s6_addr[8], 8);
                   1034:        if (memcmp(ipv6.dstip, &linklocal, sizeof(linklocal)) == 0) {
                   1035:                return false;
                   1036:        }
1.1       root     1037: 
                   1038:        // ここから未実装ログが出る組み合わせ。
                   1039: 
                   1040:        // 統計情報。
                   1041:        hostnet->CountTXUnsupp(frame.size());
                   1042: 
                   1043:        return true;
                   1044: }
                   1045: 
                   1046: // Slirp ライブラリがパケットを "送信した" 時に呼ばれるコールバック。
                   1047: // なのでこちらから見れば HUB から NIC への着信。
                   1048: ssize_t
                   1049: SlirpThread::SendPacketCB(const void *src, size_t srclen)
                   1050: {
                   1051:        if (__predict_false(loglevel >= 2)) {
                   1052:                putmsgn("Recv from SLIRP");
                   1053:                DumpFrame(src, srclen);
                   1054:        }
                   1055: 
                   1056:        // 受信ディスクリプタ (の書き込み端) に書き込む。
                   1057:        // 先頭4バイトはホストバイトオーダーでの後続のパケット長。
                   1058:        uint32 lenbuf = srclen;
                   1059: 
                   1060:        struct iovec iov[2];
                   1061:        iov[0].iov_base = &lenbuf;
                   1062:        iov[0].iov_len  = sizeof(lenbuf);
                   1063:        iov[1].iov_base = const_cast<void *>(src);
                   1064:        iov[1].iov_len  = srclen;
                   1065: 
                   1066:        ssize_t r = writev(rxd_w, &iov[0], countof(iov));
                   1067:        if (r < 0) {
                   1068:                putmsg(0, "writev failed: %s", strerror(errno));
                   1069:                return -1;
                   1070:        }
                   1071:        if (r < sizeof(lenbuf) + srclen) {
                   1072:                putmsg(0, "writev failed: too short");
                   1073:                return -1;
                   1074:        }
                   1075: 
                   1076:        return srclen;
                   1077: }
                   1078: 
                   1079: // 現在の仮想時間を返すコールバック。
                   1080: int64
                   1081: SlirpThread::ClockGetNsCB() const
                   1082: {
                   1083:        // XXX scheduler がセットされる前から呼ばれるのでとりあえず。
                   1084:        if (__predict_false(scheduler == NULL)) {
                   1085:                return 0;
                   1086:        }
                   1087:        uint64 time = scheduler->GetVirtTime();
                   1088:        return (int64)time;
                   1089: }
                   1090: 
                   1091: // 新しいタイマー(イベント)を返すコールバック。
                   1092: // 引数は時間が来たら呼ぶハンドラと引数。
                   1093: void *
                   1094: SlirpThread::TimerNewCB(SlirpTimerCb func, void *arg)
                   1095: {
                   1096:        SlirpTimer *newtimer = new SlirpTimer(func, arg);
                   1097:        newtimer->num = latest_timer_num++;
                   1098:        return newtimer;
                   1099: }
                   1100: 
                   1101: // タイマーを削除する。
                   1102: void
                   1103: SlirpThread::TimerFreeCB(SlirpTimer *timer)
                   1104: {
                   1105:        // まだアクティブならそれも削除する。
                   1106:        timerlist.remove(timer);
                   1107:        delete timer;
                   1108: }
                   1109: 
                   1110: // タイマーの期限を新しく設定する?。
                   1111: void
                   1112: SlirpThread::TimerModCB(SlirpTimer *timer, int64 expire_msec)
                   1113: {
                   1114:        timer->expire_msec = expire_msec;
                   1115: 
                   1116:        // リストから一旦削除してから、適切なところに挿入し直す。
                   1117:        timerlist.remove(timer);
                   1118:        if (timerlist.empty()) {
                   1119:                timerlist.push_back(timer);
                   1120:        } else {
                   1121:                for (auto it = timerlist.begin(); it != timerlist.end(); ++it) {
                   1122:                        auto *t = *it;
                   1123:                        if (t->expire_msec > timer->expire_msec) {
                   1124:                                timerlist.insert(it, timer);
                   1125:                                break;
                   1126:                        }
                   1127:                }
                   1128:        }
                   1129: }
                   1130: 
                   1131: // ゲスト (VM) から送信しようとしたパケットのエラーメッセージ。
                   1132: // とりあえずログに出しておく。
                   1133: void
                   1134: SlirpThread::GuestErrorCB(const char *msg)
                   1135: {
                   1136:        putmsg(1, "libslirp: %s", msg);
                   1137: }
                   1138: 
                   1139: // Slirp の内部テーブルのこちら側のコピーを更新する。
                   1140: // メインループ内から呼ばれる。
                   1141: void
                   1142: SlirpThread::UpdateInfo()
                   1143: {
                   1144:        // 取得。
                   1145:        char *newconn = slirp_connection_info(sl);
                   1146:        char *newnbr = slirp_neighbor_info(sl);
                   1147: 
                   1148:        // 更新が必要か。前回と同じなら今取得したほうを解放。
                   1149:        if (conninfo && strcmp(conninfo, newconn) == 0) {
                   1150:                free(newconn);
                   1151:                newconn = NULL;
                   1152:        }
                   1153:        if (nbrinfo && strcmp(nbrinfo, newnbr) == 0) {
                   1154:                free(newnbr);
                   1155:                newnbr = NULL;
                   1156:        }
                   1157:        // どちらも更新なしならここで終了。
                   1158:        if (newconn == NULL && newnbr == NULL) {
                   1159:                return;
                   1160:        }
                   1161: 
                   1162:        // 更新。
                   1163:        char *oldconn = NULL;
                   1164:        char *oldnbr = NULL;
                   1165:        {
1.1.1.4   root     1166:                std::lock_guard<std::mutex> lock(info_mtx);
1.1       root     1167: 
                   1168:                if (newconn) {
                   1169:                        oldconn = conninfo;
                   1170:                        conninfo = newconn;
                   1171:                }
                   1172:                if (newnbr) {
                   1173:                        oldnbr = nbrinfo;
                   1174:                        nbrinfo = newnbr;
                   1175:                }
                   1176:        }
                   1177: 
                   1178:        free(oldconn);
                   1179:        free(oldnbr);
                   1180: }
                   1181: 
                   1182: void
1.1.1.5 ! root     1183: SlirpThread::MonitorScreen(Monitor *, TextScreen& screen)
1.1       root     1184: {
                   1185:        std::string local_conn;
                   1186:        std::string local_nbr;
                   1187:        int y;
                   1188: 
                   1189:        // スレッド越しにコピーを取る。
                   1190:        {
1.1.1.4   root     1191:                std::lock_guard<std::mutex> lock(info_mtx);
1.1       root     1192:                local_conn = std::string(conninfo);
                   1193:                local_nbr  = std::string(nbrinfo);
                   1194:        }
                   1195: 
1.1.1.3   root     1196:        // Connection State の UDP 欄は [0 sec] の次に一瞬だけ [42949?? sec]
                   1197:        // くらいになる。これは slirp_connection_info() が文字列を返してきた時点で
1.1       root     1198:        // こうなっているのでこっちの話ではないのだが、あまりに幼稚すぎて
                   1199:        // 自分のソフトでこれが表示されるのは恥ずかしいのでパッチしておく。
1.1.1.3   root     1200:        //                            UDP[4294967 sec]
                   1201:        static const char udphdr[] = "UDP[";
                   1202:        static const char patch[]  =     "expired]    ";
                   1203:        for (char *s = &local_conn[0]; (s = strstr(s, udphdr)) != NULL; ) {
                   1204:                const char *end;
                   1205:                s += 4;
                   1206:                for (end = s; '0' <= *end && *end <= '9'; end++)
                   1207:                        ; // nop
                   1208:                if (__predict_false(end - s >= 7)) {
                   1209:                        for (const char *p = patch; *s && *p; ) {
                   1210:                                *s++ = *p++;
                   1211:                        }
                   1212:                }
1.1       root     1213:        }
                   1214: 
                   1215:        screen.Clear();
                   1216:        y = 0;
                   1217: 
                   1218:        auto lines = string_split(local_conn, '\n');
                   1219:        for (auto& buf : lines) {
                   1220:                screen.Puts(0, y++, buf.c_str());
                   1221:        }
                   1222: 
                   1223:        lines = string_split(local_nbr, '\n');
                   1224:        for (auto& buf : lines) {
                   1225:                screen.Puts(0, y++, buf.c_str());
                   1226:        }
                   1227:        // あふれたら諦める…。
                   1228: }
                   1229: 
                   1230: // src から srclen バイトの16進ダンプをログに(無条件に)出力する。
                   1231: void
                   1232: SlirpThread::DumpHex(const void *src, size_t srclen) const
                   1233: {
                   1234:        std::vector<std::string> lines = HostNetDevice::DumpHex(src, srclen);
                   1235:        for (auto& line : lines) {
                   1236:                putmsgn("%s", line.c_str());
                   1237:        }
                   1238: }
                   1239: 
                   1240: // イーサネットフレームを整形してログに(無条件に)出力する。
                   1241: void
                   1242: SlirpThread::DumpFrame(const void *src, size_t srclen) const
                   1243: {
                   1244:        std::vector<std::string> lines = HostNetDevice::DumpFrame(src, srclen);
                   1245:        for (auto& line : lines) {
                   1246:                putmsgn("%s", line.c_str());
                   1247:        }
                   1248: }
                   1249: 
                   1250: // コールバックのトランポリン関数たち
                   1251: 
                   1252: static ssize_t
                   1253: send_packet_cb(const void *buf, size_t buflen, void *opaque)
                   1254: {
                   1255:        auto *backend = reinterpret_cast<SlirpThread *>(opaque);
                   1256:        return backend->SendPacketCB(buf, buflen);
                   1257: }
                   1258: 
                   1259: static void
                   1260: guest_error_cb(const char *msg, void *opaque)
                   1261: {
                   1262:        auto *backend = reinterpret_cast<SlirpThread *>(opaque);
                   1263:        backend->GuestErrorCB(msg);
                   1264: }
                   1265: 
                   1266: static int64
                   1267: clock_get_ns_cb(void *opaque)
                   1268: {
                   1269:        auto *backend = reinterpret_cast<SlirpThread *>(opaque);
                   1270:        return backend->ClockGetNsCB();
                   1271: }
                   1272: 
                   1273: static void *
                   1274: timer_new_cb(SlirpTimerCb func, void *arg, void *opaque)
                   1275: {
                   1276:        auto *backend = reinterpret_cast<SlirpThread *>(opaque);
                   1277:        return backend->TimerNewCB(func, arg);
                   1278: }
                   1279: 
                   1280: static void
                   1281: timer_free_cb(void *timer, void *opaque)
                   1282: {
                   1283:        auto *backend = reinterpret_cast<SlirpThread *>(opaque);
                   1284:        auto *sltimer = reinterpret_cast<SlirpTimer *>(timer);
                   1285:        return backend->TimerFreeCB(sltimer);
                   1286: }
                   1287: 
                   1288: static void
                   1289: timer_mod_cb(void *timer, int64 expire_msec, void *opaque)
                   1290: {
                   1291:        auto *backend = reinterpret_cast<SlirpThread *>(opaque);
                   1292:        auto *sltimer = reinterpret_cast<SlirpTimer *>(timer);
                   1293:        backend->TimerModCB(sltimer, expire_msec);
                   1294: }
                   1295: 
                   1296: // おそらく不要で何もしなくていいのだが、コールバックを NULL に出来ないため。
                   1297: static void
                   1298: register_poll_fd_cb(int fd, void *)
                   1299: {
                   1300: }
                   1301: 
                   1302: // おそらく不要で何もしなくていいのだが、コールバックを NULL に出来ないため。
                   1303: static void
                   1304: unregister_poll_fd_cb(int fd, void *)
                   1305: {
                   1306: }
                   1307: 
                   1308: // シングルスレッド動作なので不要なはずだが、コールバックを NULL に出来ない。
                   1309: static void
                   1310: notify_cb(void *)
                   1311: {
                   1312: }
                   1313: 
                   1314: static int
                   1315: add_poll_cb(int fd, int events, void *opaque)
                   1316: {
                   1317:        auto *backend = reinterpret_cast<SlirpThread *>(opaque);
                   1318:        return backend->AddPollCB(fd, events);
                   1319: }
                   1320: 
                   1321: static int
                   1322: get_revents_cb(int idx, void *opaque)
                   1323: {
                   1324:        auto *backend = reinterpret_cast<SlirpThread *>(opaque);
                   1325:        return backend->GetReventsCB(idx);
                   1326: }

unix.superglobalmegacorp.com

This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.