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

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

unix.superglobalmegacorp.com

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