File:  [Isaki's NoNo m68k/m88k emulator] / nono / host / netdriver_selector.cpp
Revision 1.1.1.1 (vendor branch): download - view: text, annotated - select for diffs
Wed Apr 29 17:04:54 2026 UTC (2 months, 3 weeks ago) by root
Branches: MAIN, Isaki
CVS tags: v014, v013, v012, v011, HEAD
nono 0.2.0

//
// nono
// Copyright (C) 2021 nono project
// Licensed under nono-license.txt
//

// NetDriver セレクタ
//
// ログレベルを受け取るために他のデバイスとかと同様最初に作成されて、
// InitDriver() で実際に使うドライバを選択・作成するだけ。

#include "netdriver_selector.h"
#include "config.h"
#include "netdriver_none.h"
#if defined(HAVE_HOSTNET_AFPACKET)
#include "netdriver_afpacket.h"
#endif
#if defined(HAVE_HOSTNET_BPF)
#include "netdriver_bpf.h"
#endif
#if defined(HAVE_HOSTNET_TAP)
#include "netdriver_tap.h"
#endif

std::unique_ptr<NetDriverSelector> gNetDriverSelector;

// コンパイル済みのドライバ名一覧を返す
// (MainApp から呼ばれる)
/*static*/ std::vector<std::string>
NetDriverSelector::GetDrivers()
{
	std::vector<std::string> list;

#if defined(HAVE_HOSTNET_AFPACKET)
	list.emplace_back("afpacket");
#endif
#if defined(HAVE_HOSTNET_BPF)
	list.emplace_back("bpf");
#endif
#if defined(HAVE_HOSTNET_TAP)
	list.emplace_back("tap");
#endif

	return list;
}

// コンストラクタ
// (ここのログ名 HostNet がコマンドラインで指定するやつになるので
// HostNetSelector とかに変えないように)
NetDriverSelector::NetDriverSelector(EthernetDevice *parent_)
	: inherited("HostNet")
{
	parent = parent_;

	AddAlias("NetDriver");
}

// デストラクタ
NetDriverSelector::~NetDriverSelector()
{
}

// ここで実際の NetDriver を用意する (MainApp::Init1() から呼ばれる)。
// ここでは putmsg() が使える。また作成した NetDriver クラスも
// (NetDriverSelector のログレベルをコピーするので) putmsg() が使える。
// 成功すれば作成した NetDriver を返す。
// 終了する場合は warnx() を出力してから NULL を返す。
//
// 起動時のフェーズは Create() はログが使えない、Init() はログが使える、と
// 分かれており、ここもログが使えるので Init を冠しているが、やってることは
// Create なので関数名とメッセージ中の単語のずれは気持ち悪いけど仕方がない。
NetDriver *
NetDriverSelector::InitDriver()
{
	const ConfigItem& item = gConfig->Find("hostnet-driver");
	const std::string& type = item.AsString();
	bool fallback = gConfig->Find("hostnet-fallback").AsInt();
	NetDriver *driver;

	driver = NULL;

	if (type == "none") {
		driver = InitNone();

	} else if (type == "tap") {
#if defined(HAVE_HOSTNET_TAP)
		driver = InitTap();
#else
		item.Err("hostnet driver %s not compiled", type.c_str());
#endif

	} else if (type == "bpf") {
#if defined(HAVE_HOSTNET_BPF)
		driver = InitBPF();
#else
		item.Err("hostnet driver %s not compiled", type.c_str());
#endif

	} else if (type == "afpacket") {
#if defined(HAVE_HOSTNET_AFPACKET)
		driver = InitAFPacket();
#else
		item.Err("hostnet driver %s not compiled", type.c_str());
#endif

	} else if (type == "auto") {
		// auto なら Tap -> { BPF, AFPacket } の順で試す。
		//
		// Tap は事前の準備が面倒だが制約がない。
		// BPF, AFPacket (この2つは OS の違いだけでほぼ同じもの) は
		// 準備に手間がかからないが自ホストと通信できない制約がある。
		// そのためどの環境でも Tap が使えれば Tap を、そうでなければ
		// BPF, AFPacket を使う、という順にしておく。

		driver = InitTap();
		if (driver == NULL) {
			driver = InitAFPacket();
		}
		if (driver == NULL) {
			driver = InitBPF();
		}

	} else {
		// 知らないドライバ種別
		item.Err();
	}

	if (driver == NULL) {
		putmsg(1, "hostnet-fallback=%d", fallback ? 1 : 0);

		if (fallback) {
			// 出来てない場合でフォールバックが指示されていれば
			// None へフォールバックする
			driver = InitNone();
		} else {
			errmsg = "No host network driver found";
			putmsg(1, "%s", errmsg.c_str());
			warnx("%s (See details with options -C -Lhostnet=1)",
				errmsg.c_str());

			// NULL を返すと終了する
			return NULL;
		}
	}

	// ドライバ名は Capitalize だがログはほぼ小文字なので雰囲気を揃える…
	putmsg(1, "selected host driver: %s",
		string_tolower(driver->GetDriverName()).c_str());

	return driver;
}

// None の場合
NetDriver *
NetDriverSelector::InitNone()
{
	NetDriverNone *driver = new NetDriverNone(loglevel);
	// 失敗しても出来ることはあまりなさげ
	assert(driver);
	driver->InitDriver();
	return driver;
}

// Tap の場合
NetDriver *
NetDriverSelector::InitTap()
{
#if defined(HAVE_HOSTNET_TAP)
	const ConfigItem& item = gConfig->Find("hostnet-tap-devpath");
	const std::string& devpath = item.AsString();

	NetDriverTap *driver = NULL;
	try {
		driver = new NetDriverTap(parent, loglevel, devpath);
		if (driver->InitDriver()) {
			// 成功
			return driver;
		}
		errmsg = driver->errmsg;
		delete driver;
	} catch (...) {
		errmsg = "Creating NetDriverTap failed";
	}
#endif
	return NULL;
}

// bpf の場合
NetDriver *
NetDriverSelector::InitBPF()
{
#if defined(HAVE_HOSTNET_BPF)
	const ConfigItem& item = gConfig->Find("hostnet-bpf-ifname");
	const std::string& ifname = item.AsString();

	NetDriverBPF *driver = NULL;
	try {
		driver = new NetDriverBPF(parent, loglevel, ifname);
		if (driver->InitDriver()) {
			// 成功
			return driver;
		}
		errmsg = driver->errmsg;
		delete driver;
	} catch (...) {
		errmsg = "Creating NetDriverBPF failed";
	}
#endif
	return NULL;
}

// AFPacket の場合
NetDriver *
NetDriverSelector::InitAFPacket()
{
#if defined(HAVE_HOSTNET_AFPACKET)
	const ConfigItem& item = gConfig->Find("hostnet-afpacket-ifname");
	const std::string& ifname = item.AsString();

	NetDriverAFPacket *driver = NULL;
	try {
		driver = new NetDriverAFPacket(parent, loglevel, ifname);
		if (driver->InitDriver()) {
			// 成功
			return driver;
		}
		errmsg = driver->errmsg;
		delete driver;
	} catch (...) {
		errmsg = "Creating NetDriverAFPacket failed";
	}
#endif
	return NULL;
}

unix.superglobalmegacorp.com

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