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

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

unix.superglobalmegacorp.com

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