Annotation of nono/host/netdriver.cpp, revision 1.1.1.6

1.1       root        1: //
                      2: // nono
1.1.1.3   root        3: // Copyright (C) 2020 nono project
                      4: // Licensed under nono-license.txt
1.1       root        5: //
                      6: 
                      7: #include "netdriver.h"
1.1.1.6 ! root        8: #include "autofd.h"
        !             9: #include "cvprompt.h"
1.1.1.2   root       10: #include "mainapp.h"
1.1.1.3   root       11: #include "mythread.h"
1.1.1.6 ! root       12: #include <sys/wait.h>
        !            13: #if defined(HAVE_SYS_EVENT_H)
        !            14: #include <sys/event.h>
        !            15: #endif
        !            16: #if defined(HAVE_KQUEUE_SYS_EVENT_H)
        !            17: #include <kqueue/sys/event.h>
        !            18: #endif
1.1       root       19: 
                     20: static void *netdriver_run(void *);
                     21: 
1.1.1.2   root       22: std::unique_ptr<NetDriver> gNetDriver;
1.1       root       23: 
                     24: // コンストラクタ
1.1.1.3   root       25: NetDriver::NetDriver(const char *drivername_, EthernetDevice *parent_,
1.1.1.6 ! root       26:        int loglevel_)
        !            27:        : inherited(std::string("HostNet") + drivername_)
1.1       root       28: {
1.1.1.6 ! root       29:        loglevel = loglevel_;
1.1.1.3   root       30:        drivername = drivername_;
                     31:        parent = parent_;
1.1.1.6 ! root       32:        fd = -1;
        !            33: 
        !            34:        monitor.func = (MonitorCallback_t)&NetDriver::MonitorUpdate;
        !            35:        monitor.SetSize(30, 7);
        !            36:        monitor.Regist(ID_MONITOR_HOSTNET);
1.1       root       37: }
                     38: 
                     39: // デストラクタ
                     40: NetDriver::~NetDriver()
                     41: {
                     42: }
                     43: 
1.1.1.6 ! root       44: // 初期化
        !            45: bool
        !            46: NetDriver::Init()
1.1       root       47: {
1.1.1.6 ! root       48:        // 対応する EthernetDevice があれば受信スレッド起動。
        !            49:        // NetDriverNone は連携不要なので parent == NULL になっている。
        !            50:        if (parent) {
        !            51:                pthread_t th;
        !            52:                int error;
        !            53: 
        !            54:                error = pthread_create(&th, NULL, netdriver_run, NULL);
        !            55:                if (error) {
        !            56:                        putmsg(0, "pthread_create: %s", strerror(error));
        !            57:                        return false;
        !            58:                }
        !            59:        }
        !            60:        return true;
1.1       root       61: }
                     62: 
1.1.1.6 ! root       63: // モニタ
        !            64: void
        !            65: NetDriver::MonitorUpdate(Monitor *, TextScreen& screen)
1.1       root       66: {
1.1.1.6 ! root       67:        screen.Clear();
1.1       root       68: 
1.1.1.6 ! root       69:        screen.Print(0, 0, "HostNet Driver: %s", drivername);
        !            70:        // 次の2行はドライバ依存情報
        !            71:        MonitorUpdateMD(screen);
        !            72: 
        !            73:        screen.Print(5, 4, "%9s %9s", "Packets", "Bytes");
        !            74:        screen.Print(0, 5, "Send %9" PRIu64 " %9" PRIu64, tx_pkts, tx_bytes);
        !            75:        screen.Print(0, 6, "Recv %9" PRIu64 " %9" PRIu64, rx_pkts, rx_bytes);
1.1       root       76: }
                     77: 
                     78: // 受信スレッドのエントリポイント
                     79: void *
                     80: netdriver_run(void *dummy)
                     81: {
1.1.1.6 ! root       82:        PTHREAD_SETNAME("NetDriver");
1.1       root       83:        pthread_detach(pthread_self());
                     84: 
                     85:        gNetDriver->ThreadRun();
                     86:        return NULL;
                     87: }
                     88: 
                     89: // ifup スクリプト実行
                     90: bool
                     91: NetDriver::Run_ifup()
                     92: {
                     93:        return RunScript("nono-ifup");
                     94: }
                     95: 
                     96: // ifdown スクリプト実行
                     97: bool
                     98: NetDriver::Run_ifdown()
                     99: {
                    100:        return RunScript("nono-ifdown");
                    101: }
                    102: 
                    103: // スクリプトを実行
                    104: bool
                    105: NetDriver::RunScript(const char *filename)
                    106: {
1.1.1.6 ! root      107:        std::string cmd;
        !           108:        int r;
        !           109: 
1.1       root      110:        // ファイルが存在するか
1.1.1.2   root      111:        std::string path = gMainApp.SearchFile(filename);
1.1       root      112:        if (path.empty()) {
1.1.1.6 ! root      113:                errmsg = string_format("%s not found", filename);
        !           114:                goto abort;
1.1       root      115:        }
                    116: 
                    117:        // コマンドラインを作成
1.1.1.6 ! root      118:        cmd = path + " " + ifname;
        !           119:        putmsg(1, "%s: command: %s", __func__, cmd.c_str());
1.1       root      120: 
                    121:        // 実行
1.1.1.6 ! root      122:        r = system(cmd.c_str());
        !           123:        if (r == -1) {
        !           124:                errmsg = string_format("system(\"%s\"): %s",
        !           125:                        cmd.c_str(), strerror(errno));
        !           126:                goto abort;
        !           127:        }
        !           128: 
        !           129:        if (WIFEXITED(r)) {
        !           130:                int exitcode = WEXITSTATUS(r);
        !           131:                if (exitcode == 0) {
        !           132:                        // ここが正常終了
        !           133:                        putmsg(1, "%s: \"%s\" exited successfully", __func__, cmd.c_str());
        !           134:                        return true;
        !           135:                }
        !           136:                if (exitcode == 127) {
        !           137:                        errmsg = string_format("\"%s\": shell execution failed",
        !           138:                                cmd.c_str());
        !           139:                } else {
        !           140:                        errmsg = string_format("\"%s\" exited with code %d",
        !           141:                                cmd.c_str(), exitcode);
        !           142:                }
        !           143:        } else if (WIFSIGNALED(r)) {
        !           144:                int signo = WTERMSIG(r);
        !           145:                errmsg = string_format("\"%s\" terminated with signal %d",
        !           146:                        cmd.c_str(), signo);
        !           147:        } else {
        !           148:                // どうしたらいいかよく分からんのでとりあえず表示だけ。
        !           149:                errmsg = string_format("\"%s\" terminated:"
        !           150:                        "IFSTOPPED=%d STOPSIG=%d IFCONTINUED=%d COREDUMP=%d",
        !           151:                        cmd.c_str(),
        !           152:                        WIFSTOPPED(r), WSTOPSIG(r), WIFCONTINUED(r), WCOREDUMP(r));
        !           153:        }
        !           154: 
        !           155:  abort:
        !           156:        putmsg(1, "%s: %s", __func__, errmsg.c_str());
        !           157:        return false;
        !           158: }
        !           159: 
        !           160: // VM 側の受信パケットキューにパケットを一つ追加する
        !           161: void
        !           162: NetDriver::RecvEnqueue(uint8 *ptr, size_t len)
        !           163: {
        !           164:        RXPacket packet { new qvector<uint8>(ptr, ptr + len) };
        !           165: 
        !           166:        // ホストカーネルから直接着信したパケット(というかフレームか)は
        !           167:        // 60バイトパディングされないまま読み出せるので、ここでパディングする。
        !           168:        if (len < 60) {
        !           169:                for (int i = len ; i < 60; i++) {
        !           170:                        packet->append(0);
        !           171:                }
        !           172:        }
        !           173: 
        !           174:        // CRC XXX 計算すること
        !           175:        for (int i = 0; i < 4; i++) {
        !           176:                packet->append(0);
        !           177:        }
        !           178: 
        !           179:        size_t n = packet->size();
        !           180: 
        !           181:        // 受信処理に引き渡す
        !           182:        // ただしデバッガプロンプトで停止してる状態なら VM に干渉しない。
        !           183:        if (gCVPrompt->IsPrompt() == false) {
        !           184:                putlog(2, "RecvPacket %zd bytes", n);
        !           185:                rx_pkts++;
        !           186:                rx_bytes += n;
        !           187:                parent->RecvPacket(std::move(packet));
        !           188:        }
        !           189: }
        !           190: 
        !           191: // 受信スレッド
        !           192: void
        !           193: NetDriver::ThreadRun()
        !           194: {
        !           195:        struct kevent kev;
        !           196:        autofd kq;
        !           197:        int r;
        !           198: 
        !           199:        kq = kqueue();
        !           200:        if (kq == -1) {
        !           201:                warn("NetDriver: kqueue");
        !           202:                return;
        !           203:        }
        !           204: 
        !           205:        EV_SET(&kev, fd, EVFILT_READ, EV_ADD, 0, 0, (kevent_udata_t)0);
        !           206:        r = kevent_set(kq, &kev, 1);
        !           207:        if (r == -1) {
        !           208:                warn("NetDriver: kevent_set(fd=%d)", fd);
        !           209:                return;
        !           210:        }
        !           211: 
        !           212:        for (;;) {
        !           213:                ssize_t n;
        !           214: 
        !           215:                // 何か起きるまで待つ
        !           216:                r = kevent_poll(kq, &kev, 1, NULL);
        !           217:                if (r == -1) {
        !           218:                        if (errno == EINTR) {
        !           219:                                continue;
        !           220:                        }
        !           221:                        // XXX ?
        !           222:                        warn("NetDriver: kevent_poll");
        !           223:                        break;
        !           224:                }
        !           225: 
        !           226:                // 自動的にデバイスに着信があったことになるはず
        !           227:                assert(r > 0);
        !           228: 
        !           229:                // パケットを読み込んで VM に引き渡す。
        !           230:                n = RecvPacket();
        !           231:                if (n == -1) {
        !           232:                        if (errno == EINTR) {
        !           233:                                continue;
        !           234:                        }
        !           235:                        warn("NetDriver: read");
        !           236:                        break;
        !           237:                }
        !           238:                if (n == 0) {   // EOF
        !           239:                        return;
        !           240:                }
1.1       root      241:        }
                    242: }

unix.superglobalmegacorp.com

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