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

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

unix.superglobalmegacorp.com

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