File:  [Isaki's NoNo m68k/m88k emulator] / nono / debugger / console_tcp.cpp
Revision 1.1.1.2 (vendor branch): download - view: text, annotated - select for diffs
Wed Apr 29 17:04:33 2026 UTC (2 months, 3 weeks ago) by root
Branches: MAIN, Isaki
CVS tags: v014, v013, v012, v011, v010, v009, v008, v007, v006, v005, v004, HEAD
nono 0.1.0

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

#include "header.h"
#include "config.h"
#include "console.h"
#include <netdb.h>
#include <sys/socket.h>

//
// TCP コンソール
//

// コンストラクタ
ConsoleTCP::ConsoleTCP()
{
	ls = -1;
	sock = -1;

	// editline は使えないようだ...
	//use_editline = true;
}

// デストラクタ
ConsoleTCP::~ConsoleTCP()
{
	if (res) {
		freeaddrinfo(res);
		res = NULL;
	}
	if (sock != -1) {
		close(sock);
		sock = -1;
	}
	if (ls != -1) {
		close(ls);
		ls = -1;
	}
}

// 初期化
bool
ConsoleTCP::Init()
{
	struct addrinfo hints;
	int r;
	int on = 1;

	memset(&hints, 0, sizeof(hints));
	hints.ai_family = AF_UNSPEC;
	hints.ai_socktype = SOCK_STREAM;
	hints.ai_flags = AI_PASSIVE;

	const char *host = "::1";
	const ConfigItem& item = gConfig->Find("debugger-port");
	const std::string& port = item.AsString();
	int portnum = atoi(port.c_str());
	if (portnum < 0 || portnum > 65535) {
		item.Err();
		return false;
	}
	// 0 なら待ち受けしない
	if (portnum == 0) {
		return false;
	}

	r = getaddrinfo(host, port.c_str(), &hints, &res);
	if (r != 0) {
		const char *errmsg;
		if (r == EAI_SYSTEM) {
			errmsg = strerror(errno);
		} else {
			errmsg = gai_strerror(r);
		}
		warnx("getaddrinfo: %s: %s", host, errmsg);
		return false;
	}
	if (res == NULL) {
		warnx("getaddrinfo: %s: no address found", host);
		return false;
	}

	// res を順番に試して成功したらそれで待ち受ける
	ls = -1;
	for (ai = res; ai && ls == -1; ai = ai->ai_next) {
		ls = socket(ai->ai_family, ai->ai_socktype, ai->ai_protocol);
		if (ls == -1) {
			warn("socket");
			continue;
		}

		if (setsockopt(ls, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on))) {
			warn("setsockopt(SO_REUSEADDR)");
			close(ls);
			continue;
		}

		if (setsockopt(ls, SOL_SOCKET, SO_REUSEPORT, &on, sizeof(on))) {
			warn("setsockopt(SO_REUSEPORT)");
			close(ls);
			continue;
		}

		if (bind(ls, ai->ai_addr, ai->ai_addrlen) == -1) {
			warn("bind");
			close(ls);
			continue;
		}

		if (listen(ls, 0) == -1) {
			warn("listen");
			close(ls);
			continue;
		}

		// ここまで来たら成功
		break;
	}

	if (ls == -1) {
		return false;
	}

	return true;
}

// 受け付ける
bool
ConsoleTCP::Accept()
{
	for (;;) {
		sock = accept(ls, ai->ai_addr, &ai->ai_addrlen);
		if (sock == -1) {
			if (errno == EINTR) {
				continue;
			}
			warn("accept");
			return false;
		}
		break;
	}

	inp.fd = dup(sock);
	out.fd = dup(sock);
	FDOpen();

	// editline(3) を使う場合、出力側がフルバッファリングだと内部バッファが
	// 一杯になったか何かのタイミングでしか出力されなくなるので、少なくとも
	// 行バッファリングにはしないといけない。
	setlinebuf(out.file);
	// バッファリングなしにしてもプロンプトは表示されない...
	//setvbuf(out.file, NULL, _IONBF, 0);

	return true;
}

void
ConsoleTCP::Close()
{
	inherited::Close();

	if (sock != -1) {
		close(sock);
		sock = -1;
	}
}

unix.superglobalmegacorp.com

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