#include "stdafx.h"

using namespace std;

namespace {
	const int maxInConnection = 16;
	const int maxOutConnection = 4;
	const int maxWaitingConnection = 2;
	const char * const p2pNodeFileName = "p2pnode.txt";
}

struct findFromAddr : public unary_function<TCPSocketBuffer<TimedTCPSocket>, bool> {
	findFromAddr(unsigned long naddr) : naddr_(naddr) {}
	bool operator()(const TCPSocketBuffer<TimedTCPSocket>& s) const
	{
		sockaddr_in sin;
		s.getpeername(reinterpret_cast<sockaddr*>(&sin));
		return sin.sin_addr.s_addr == naddr_;
	}
private:
	unsigned long naddr_;
};

unsigned int __stdcall p2p_thread(void* /*data*/)
{
	unsigned short p2p_port;
	try {
		p2p_port = boost::lexical_cast<unsigned short>(getIniString("o2on", "p2p_port", ""));
	} catch (boost::bad_lexical_cast&) {
		p2p_port = 7743;
	}

	// P2PProcessor
	P2PProcessor p2pprocessor(p2p_port);

	// P2P用servent起動
	TCPServer<TCPSocketBuffer<TimedTCPSocket>, P2PProcessor>
		p2pservent(p2pprocessor, maxInConnection);
	try {
		if (!p2pservent.start(p2p_port)) {
			MessageBox(NULL, "P2Pポートのオープンに失敗しました\n設定を変更して再起動してください", "o2on", MB_OK);
			return 0;
		}
	} catch (exception& e) {
		// もっとちゃんと…
		MessageBox(NULL, e.what(), "o2on", MB_OK);
		return 0;
	}

	while (do_thread) {
		p2pservent.process();
	}

	return 0;
}

inline void P2PProcessor::acceptDetected()
{// 何もしない
}

inline void P2PProcessor::disconnected()
{// 何もしない
}

void P2PProcessor::dosomething(std::list<TCPSocketBuffer<TimedTCPSocket> >& sockets)
{
	time_t nowtime;
	time(&nowtime);
	if (nowtime == pretime) {
		// 1sec経っていない場合は何もしない
		return;
	} else {
		pretime = nowtime;
	}

	// 90秒以上何も受信していない物を切断
	for (list<TCPSocketBuffer<TimedTCPSocket> >::iterator it = sockets.begin();
		it != sockets.end();
		)
	{
		if (it->getSocket().recvTimeout(90)) {
			it = server_->pop(it);
		} else {
			++it;
		}
	}

	// 60秒以上何も送信していない物にnode情報を入れたXMLを撃つ
	for (list<TCPSocketBuffer<TimedTCPSocket> >::iterator it = sockets.begin(), end = sockets.end();
		it != end;
		++it)
	{
		if (it->getSocket().sendTimeout(60)) {
			//it->send("NOOP\r\nContent-Length: 0\r\n\r\n", 27);
			string nodesxml = "<?xml version=\"1.0\" encoding=\"UTF-8\"?><o2on>";
			for (vector<NodeInfo>::iterator nodesit = nodes.begin();
				nodesit != nodes.end();
				++nodesit)
			{
				nodesxml += boost::str(boost::format("<nodeinfo host=\"%1%\" port=\"%2%\"/>")
					% nodesit->getHost() % nodesit->getPort());
			}
			nodesxml += "</o2on>";

			sendP2PMessage(it->getSocket(), "NODE",
				vector<char>(nodesxml.begin(), nodesxml.end()));
		}
	}

	using namespace boost::lambda;

	// 接続数が少ない場合外部に接続
	if (sockets.size() < maxOutConnection && nodes.size() > sockets.size()
		&& waitingSockets.size() < maxWaitingConnection) {
		// 優先度が高いほうから sockets.size() + 1 個のノードを取得
		vector<NodeInfo>::iterator nth = nodes.begin() + sockets.size() + 1;
		nth_element(nodes.begin(), nth, nodes.end(),
			(bind(&NodeInfo::getPriority, _1) > bind(&NodeInfo::getPriority, _2)));

		for (vector<NodeInfo>::iterator it = nodes.begin(); it != nth; ++it) {
			if (find_if(sockets.begin(), sockets.end(), findFromAddr(it->getAddr()))
				!= sockets.end())
			{
				continue;
			}

            TCPSocket new_sock;
			new_sock.nonblocking();
			if (new_sock.connect(it->getAddr(), it->getPort())) {
				SOCKET sock = new_sock.release();
#pragma warning(push, 3)
				FD_SET(sock, &waitingFd);
#pragma warning(pop)
				waitingSockets.push_back(sock);
			}
			it->decPriority();
			break;
		}
	}

	fd_set waiting = waitingFd;
	timeval waitval = {0, 1};
	// 接続できた物とハンドシェイクしてserventに登録
	if (select(FD_SETSIZE, NULL, &waiting, NULL, &waitval) > 0) {
		for (vector<SOCKET>::iterator it = waitingSockets.begin();
			it != waitingSockets.end();
			)
		{
			if (FD_ISSET(*it, &waiting)) {
				TCPSocket new_sock(*it);

				sockaddr_in sin;
				new_sock.getpeername(reinterpret_cast<sockaddr*>(&sin));
				vector<NodeInfo>::iterator nodesit = find_if(nodes.begin(), nodes.end(),
					bind(&NodeInfo::getAddr, _1) == sin.sin_addr.s_addr);
				if (nodesit != nodes.end()) {
					nodesit->incPriority();
				}

				// HandShake
				const char* tmp = "Hello, world!!!";
				vector<char> temp(tmp, tmp + 15);
				sendP2PMessage(new_sock, "HANDSHAKE", temp);

				server_->push(new_sock.release());
#pragma warning(push, 3)
				FD_CLR(*it, &waitingFd);
#pragma warning(pop)
				it = waitingSockets.erase(it);
			} else {
				++it;
			}
		}
	}

	// 接続に失敗した物を除去
	waiting = waitingFd;
	if (select(FD_SETSIZE, NULL, NULL, &waiting, &waitval) > 0) {
		for (vector<SOCKET>::iterator it = waitingSockets.begin();
			it != waitingSockets.end();
			)
		{
			if (FD_ISSET(*it, &waiting)) {
				shutdown(*it, 1);
				closesocket(*it);
#pragma warning(push, 3)
				FD_CLR(*it, &waitingFd);
#pragma warning(pop)
				it = waitingSockets.erase(it);
			} else {
				++it;
			}
		}
	}
}

bool P2PProcessor::recvDetected(TCPSocketBuffer<TimedTCPSocket>& sockbuf)
{
	if (sockbuf.getBuffer().length() > 1024 * 1024) {// 1MBにバッファを制限
		return false;
	}

	string& str = sockbuf.getBuffer();

	size_t pos;
	while (pos = str.find("\r\n\r\n"), strfound(pos)) {
		string header(str, 0, pos);
		istringstream iss(header);
		int length = 0;
		string method;
		while (iss) {
			string line;
			if (!getline(iss, line)) break;
			size_t pos = line.find(": ");
			if (!strfound(pos)) continue;
			string key(line, 0, pos);
			string value(line, pos + 2);
			if (key == "Method") {
				method = value;
			} else if (key == "Content-Length") {
				try {
					length = boost::lexical_cast<int>(value);
				} catch (boost::bad_lexical_cast&) {}
			}
		}
		if (str.size() < header.size() + 4 + length) return true;	// まだ全部届いてない

		str.erase(0, pos + 4); // Headerをバッファから消す

		if (length == 0) return true;

		vector<char> deflateBody(str.begin(), str.begin() + length);
		str.erase(0, length);
		vector<char> body;
		if (!zlib_inflate(deflateBody, body)) {
			// 解凍失敗
			return false;
		}

		string strbody(body.begin(), body.end());
		MessageBox(NULL, strbody.c_str(), "hogehoge - o2on", MB_OK);
	}

	return true;
}

void P2PProcessor::startProcessor()
{
	// Node読み込み
	ifstream nodeifs(p2pNodeFileName);
	if (!nodeifs.fail()) {
		string buf;
		while (getline(nodeifs, buf), !nodeifs.fail()) {
			NodeInfo node;
			size_t pos = buf.rfind(":");
			try {
				node = NodeInfo(buf.substr(0, pos),
					boost::lexical_cast<unsigned short>(buf.substr(pos + 1)));
				nodes.insert(nodes.end(), node);
			} catch (exception&) {}
		}
	}
	//sort(nodes.begin(), nodes.end());
	//nodes.erase(unique(nodes.begin(), nodes.end()), nodes.end());
	//vector<NodeInfo>(nodes).swap(nodes);
}

P2PProcessor::~P2PProcessor()
{
	// Node書き出し
	ofstream nodeofs(p2pNodeFileName);
	if (!nodeofs.fail()) {
		for (vector<NodeInfo>::iterator it = nodes.begin(), end = nodes.end();
			it != end;
			++it)
		{
			nodeofs << it->getHost() << ':' << boost::lexical_cast<string>(it->getPort()) << '\n';
		}
	}

	for (vector<SOCKET>::iterator it(waitingSockets.begin()), end(waitingSockets.end());
		it != end;
		++it)
	{
		shutdown(*it, 1);
		closesocket(*it);
	}
}

NodeInfo::NodeInfo(const std::string& host, unsigned short port)
	: host_(host), port_(port), priority(0)
{
	hostent* phostent = gethostbyname(host.c_str());
	if (!phostent)
		throw exception("Invalid Hostname");

	memcpy(&addr_, phostent->h_addr, sizeof addr_);
}

void sendP2PMessage(const TCPSocket& s, const string& method, const vector<char>& body)
{
	vector<char> deflated;
	//vector<char> deflated(body.begin(), body.end());
	if (zlib_deflate(body, deflated)) {
		string header = "Method: " + method;
		header += "\r\nContent-Length: ";
		header += boost::lexical_cast<string>(deflated.size());
		header += "\r\n\r\n";
		s.send(header.data(), header.length());
		s.send(&deflated[0], deflated.size());
	}
}

//#define BUF_LEN					8192
//
//struct HEADER {
//	unsigned char	type;
//	unsigned int	bodylen;
//};
//
//struct P2P_REQ_DATA {
//	unsigned char	type;
//	unsigned long	target_ip;
//	unsigned short	target_port;
//};
//
//void __cdecl p2p_request_handler(void *data);
//bool p2p_request(unsigned char type, NodeInfo &ni, void *data);
//
//extern HANDLE			p2p_listen_thread_handle;
//extern HANDLE			p2p_key_collect_thread_handle;
//extern Board			*board;
//extern KeyDB			*mykey;
//extern KeyDB			*otkey;
//extern unsigned long	global_ip;
//extern unsigned short	p2p_port;
//extern string			node_name;
//extern string			trip_name;
//extern string			profile;
////extern void				refresh_list(void);
//extern void append_log(char io, char *name, char *format, ...);
//extern void append_mes(NodeInfo *ni, char *mes);
//
//void make_header(HEADER *header, unsigned char type, unsigned int bodylen)
//{
//	header->type = type;
//	header->bodylen = bodylen;
//}
//
//void vcopy(char *target, vector<char> &source, size_t offset, size_t size)
//{
//	for (size_t i = 0; i < size; i++) target[i] = source[offset+i];
//}
//
////**************************************************************************
////*
////* p2p_listen_thread
////*	クライアントからのリクエストを待つスレッド
////*
////**************************************************************************
//unsigned int __stdcall p2p_listen_thread(void * /*data*/)
//{
//	// リスニングソケットを作成
//	TCPSocket listening_socket;
//	if (!listening_socket.listen(p2p_port, INADDR_ANY)) {
//		MessageBox(NULL, "P2Pポートのオープンに失敗しました\n設定を変更して再起動してください",
//			"o2on", MB_OK);
//		return 0;
//	}
//
//	//dprint("[P2P_LISTEN] start listen (port %d)\n", p2p_port);
//
//	while (do_thread) {
//		if (!listening_socket.readable(3, 0))
//			continue;
//
//		SOCKET new_socket = listening_socket.accept();
//
//		if (new_socket == INVALID_SOCKET)
//			continue;
//
//		//dprint("[P2P_LISTEN] incoming request (s:%d)\n", new_socket);
//		// リクエスト処理スレッドを起動
//		SOCKET *client_socket = new SOCKET(new_socket);	// p2p_request_handler 内でdeleteされる
//		_beginthread(p2p_request_handler, 0, client_socket);
//	}
//
//	return 0;
//}
//
////**************************************************************************
////*
////* p2p_request_handler
////*	クライアントからのリクエストを処理するスレッド
////*
////**************************************************************************
//void __cdecl p2p_request_handler(void* data)
//{
//	SOCKET *new_socket = static_cast<SOCKET*>(data);
//	TCPSocket client_socket(*new_socket);
//	delete new_socket;
//
//	char				buf[BUF_LEN];
//	int					read_size;
//	int					total;
//	HEADER				header = {0};
//	//string				req_head;
//	//string				req_body;
//	vector<char>		req_head;
//	vector<char>		req_body;
//	bool				head_read_flag;
//	bool				body_read_flag;
//	int					body_read_size;
//	NodeInfo			ni;
//	Key					key;
//	int					keynum;
//	int					len;
//	unsigned long		client_ip;
//	char				client_node_name[NODE_NAME_LEN];
//
//	sockaddr_in	peer_sin;
//	client_socket.getpeername(reinterpret_cast<sockaddr*>(&peer_sin));
//	client_ip = peer_sin.sin_addr.s_addr;
//
//	//*****************************************************
//	// クライアントのリクエストを受信
//	//*****************************************************
//	head_read_flag = false;
//	body_read_flag = false;
//	body_read_size = 0;
//	total = 0;
//	dprint("READ START\n");
//	while (do_thread) {
//		if (!client_socket.readable(5, 0))
//			break;
//
//		read_size = client_socket.recv(buf, sizeof(buf) -1);
//		dprint("RECV SIZE = %d\n", read_size);
//		if (read_size <= 0) break;
//		total += read_size;
//
//		buf[read_size] = '\0';
//
//		if (!body_read_flag) {
//			//リクエストヘッダの受信
//			req_head.insert(req_head.end(), &buf[0], &buf[read_size]);
//			//req_head.append(buf, 0, read_size);
//			//if (total >= P2P_REQ_HEADER_LEN) {
//			if (req_head.size() >= sizeof(HEADER)) {
//				head_read_flag = true;
//				//memcpy(&header, req_head.data(), P2P_REQ_HEADER_LEN);
//				//memset(&header, 0, sizeof(HEADER));
//				vcopy((char*)&header, req_head, 0, sizeof(HEADER));
//				if (header.bodylen == 0)
//					break;
//				body_read_flag = true;
//				//body_read_size = total - sizeof(P2P_REQ_HEADER_LEN);
//				//req_body.assign(req_head.c_str(), P2P_REQ_HEADER_LEN);
//				//req_head.erase(P2P_REQ_HEADER_LEN);
//
//				req_body.assign(req_head.begin() + sizeof(HEADER), req_head.end());
//				req_head.erase(req_head.begin() + sizeof(HEADER), req_head.end());
//
//				if (req_body.size() >= header.bodylen)
//					break;
//			}
//		} else {
//			//リクエストBODYの受信
//			//body_read_size += read_size;
//			//req_body.append(buf, 0, read_size);
//			req_body.insert(req_body.end(), &buf[0], &buf[read_size]);
//			if (req_body.size() >= header.bodylen)
//				break;
//		}
//		//} else {
//		//	break;
//		//}
//	}
//
//	if (!head_read_flag)
//		return;
//
//	dprint("[P2P_REQHANDLE] succeed receive request type=%d bodylen=%d\n",
//		header.type, header.bodylen);
//
//	//*****************************************************
//	//
//	//*****************************************************
//	if (req_body.size() >= sizeof(NodeInfo)) {
//		vcopy((char*)&ni, req_body, 0, sizeof(NodeInfo));
//		//
//		ni.name[NODE_NAME_LEN - 1] = '\0';
//		//
//		ni.node.ip = client_ip;
//		otkey->lock();
//		otkey->insert_node(ni.node, ni.name, time(NULL));
//		otkey->unlock();
//		strcpy(client_node_name, ni.name);
//		dprint("[P2P_REQHANDLE] receive request from (%d:%d[%s])\n", ni.node.ip, ni.node.port, ni.name);
//	}
//
//	//*****************************************************
//	// リクエストに答える
//	//*****************************************************
//	switch (header.type) {
//
//	//=======================
//	// P2P_TYPE_ASKMYIP
//	//=======================
//	case P2P_TYPE_ASKMYIP:
//		make_header(&header, P2P_TYPE_NONE, sizeof(client_ip));
//		client_socket.send(reinterpret_cast<char*>(&header), sizeof HEADER);
//		client_socket.send(reinterpret_cast<char*>(&client_ip), sizeof client_ip);
//		append_log(1, client_node_name, "ASKMYIP");
//		break;
//
//	//=======================
//	// P2P_TYPE_GETKEY
//	//=======================
//	case P2P_TYPE_GETKEY:
//		//保持しているNode情報を送信
//		mykey->lock();
//		otkey->lock();
//
//		keynum = mykey->count() + otkey->count();
//wsprintf(buf, "MYKEY:%d OTKEY:%d\n", mykey->count(), otkey->count());
//OutputDebugString(buf);
//		len = sizeof(Key) * keynum;
//		make_header(&header, P2P_TYPE_NONE, len);
//		client_socket.send(reinterpret_cast<char*>(&header), sizeof HEADER);
//
//		if (len > 0) {
//			mykey->rewind();
//			while (mykey->get(&key)) {
//				client_socket.send(reinterpret_cast<char*>(&key), sizeof Key);
//			}
//			otkey->rewind();
//			while (otkey->get(&key)) {
//				client_socket.send(reinterpret_cast<char*>(&key), sizeof Key);
//			}
//		}
//
//		mykey->unlock();
//		otkey->unlock();
//
//		append_log(1, client_node_name, "キーを送信しました(%d個 %dbyte)", keynum, len);
//		break;
//
//	//=======================
//	// P2P_TYPE_GETYOURKEY
//	//=======================
//	case P2P_TYPE_GETYOURKEY:
//		//保持しているNode情報を送信
//		mykey->lock();
//		keynum = mykey->count();
//
//		len = sizeof(Key) * keynum;
//		make_header(&header, P2P_TYPE_NONE, len);
//		client_socket.send(reinterpret_cast<char*>(&header), sizeof HEADER);
//
//		if (len > 0) {
//			mykey->rewind();
//			while (mykey->get(&key)) {
//				client_socket.send(reinterpret_cast<char*>(&key), sizeof Key);
//			}
//		}
//		mykey->unlock();
//
//		append_log(1, client_node_name, "キーを送信しました(%d個 %dbyte)", keynum, len);
//		break;
//
//	//=======================
//	// P2P_TYPE_GETPROFILE
//	//=======================
//	case P2P_TYPE_GETPROFILE:
//		len = profile.size();
//		make_header(&header, P2P_TYPE_NONE, len);
//		client_socket.send(reinterpret_cast<char*>(&header), sizeof HEADER);
//		client_socket.send(profile.c_str(), profile.size());
//		append_log(1, client_node_name, "参照されますた(*´Д`*)");
//		break;
//
//	//=======================
//	// P2P_TYPE_SENDMES
//	//=======================
//	case P2P_TYPE_SENDMES:
//		req_body.push_back('\0');
//		append_mes(&ni, &req_body[sizeof(NodeInfo)]);
//		break;
//
//	//=======================
//	// Unknown header type
//	//=======================
//	default:
//		append_log(0, client_node_name, "Unknown header type!!!");
//		break;
//	}
//
//	return;
//}
//
////**************************************************************************
////*
////* p2p_key_collect_thread
////*	キーを収集するスレッド
////*
////**************************************************************************
//unsigned int __stdcall p2p_key_collect_thread(void * /*data*/)
//{
//	Node		node;
//	NodeStatus	ns;
//	NodeInfo	ni;
//
//	while (do_thread) {
//		refresh_list();
//
//		//SetProcessWorkingSetSize(GetCurrentProcess(), 0xffffffff, 0xffffffff);//おまじない
//
//		if (otkey->node_count() == 0) {
//			dprint("[COLLECT] zzz...\n");
//
//		} else if (global_ip == 0) {
//			if (!otkey->get_rand_node(&node, &ns)) {
//				continue;
//			}
//			dprint("[COLLECT] ASK MY IP\n");
//			memcpy(&ni.node, &node, sizeof(Node));
//			strcpy(ni.name, ns.name);
//			p2p_request(P2P_TYPE_ASKMYIP, ni, NULL);
//
//		} else {
//			if (!otkey->get_rand_node(&node, &ns)) {
//				continue;
//			}
//			//dprint("[COLLECT] GET KEY\n");
//			memcpy(&ni.node, &node, sizeof(Node));
//			strcpy(ni.name, ns.name);
//			p2p_request(P2P_TYPE_GETKEY, ni, NULL);
//		}
//
//		Sleep(3000);
//	}
//
//	return 0;
//}
//
//
////**************************************************************************
////*
////* p2p_request
////*	リクエストを発行
////*
////**************************************************************************
//bool p2p_request(unsigned char type, NodeInfo &target_ni, void *data)
//{
//	//P2P_REQ_DATA		*reqdata;
//	string				request;
////	string				res_head;
////	string				res_body;
//	vector<char>		res_head;
//	vector<char>		res_body;
//	bool				head_read_flag;
//	bool				body_read_flag;
//	int					body_read_size;
//	int					total;
//	NodeInfo			ni;
//	Key					key;
//	int					read_size;
//	char				buf[BUF_LEN];
//	HEADER				header;
//	struct in_addr		sin_addr;
//	int					i;
//	char				*message = 0;
//	HWND				h;
//	int					len;
//
//	//reqdata = (P2P_REQ_DATA*)data;
//
//	/*
//	servhost = gethostbyname(reqdata->target_ip);
//	if (servhost == NULL) {
//		dprint("[P2P_REQUEST] ERROR: [%s] to IP fail\n", reqdata->target_ip);
//		goto endthread;
//	}
//	*/
//
//	TCPSocket p2p;
//	if (p2p.connect(target_ni.node.ip, target_ni.node.port)) {
//		return false;
//	}
//
//	//*****************************************************
//	// リクエストを送信
//	//*****************************************************
//	if (type == P2P_TYPE_SENDMES) {
//		message = (char*)data;
//		make_header(&header, type, sizeof(NodeInfo)+strlen(message));
//	} else {
//		make_header(&header, type, sizeof(NodeInfo));
//	}
//	memset(&ni, 0, sizeof(NodeInfo));
//	ni.node.port = p2p_port;
//	strcpy(ni.name, trip_name.c_str());
//	dprint("[P2P_REQUEST] send request (type=%d) to (%d:%d[%s])\n",
//		type, target_ni.node.ip, target_ni.node.port, target_ni.name);
//
//	p2p.send(reinterpret_cast<char*>(&header), sizeof HEADER);
//	p2p.send(reinterpret_cast<char*>(&ni), sizeof NodeInfo);
//
//	if (type == P2P_TYPE_SENDMES) {
//		p2p.send(message, strlen(message));
//		return true;
//	}
//	//Sleep(5000);
//
//	//*****************************************************
//	// レスポンスを受信
//	//*****************************************************
//	head_read_flag = false;
//	body_read_flag = false;
//	body_read_size = 0;
//	total = 0;
//	for (;;) {
//		if (!p2p.readable(20, 0))
//			break;
//
//		read_size = p2p.recv(buf, sizeof(buf) -1);
//		if (read_size <= 0) break;
//
//		dprint("[P2P_REQUEST] read_size = %d\n", read_size);
//		total += read_size;
//
//		buf[read_size] = '\0';
//
//		if (!body_read_flag) {
//			//ヘッダの受信
//			//res_head.append(buf, 0, read_size);
//			res_head.insert(res_head.end(), &buf[0], &buf[read_size]);
//			//if (total >= sizeof(HEADER)) {
//			if (res_head.size() >= sizeof(HEADER)) {
//				head_read_flag = true;
//				//memcpy(&header, res_head.c_str(), sizeof(HEADER));
//				vcopy((char*)&header, res_head, 0, sizeof(HEADER));
//				if (header.bodylen == 0)
//					break;
//				body_read_flag = true;
//				//body_read_size = total - sizeof(HEADER);
//				//res_body.assign(res_head.c_str(), sizeof(HEADER));
//				//res_head.erase(sizeof(HEADER));
//
//				res_body.assign(res_head.begin() + sizeof(HEADER), res_head.end());
//				res_head.erase(res_head.begin() + sizeof(HEADER), res_head.end());
//				if (res_body.size() >= header.bodylen)
//					break;
//			}
//		} else {
//			//BODYの受信
//			//body_read_size += read_size;
//			//res_body.append(buf, 0, read_size);
//			res_body.insert(res_body.end(), &buf[0], &buf[read_size]);
//			if (res_body.size() >= header.bodylen)
//				break;
//		}
//	}
//
//	if (!head_read_flag) {
//		return false;
//	}
//
//	dprint("[P2P_REQUEST] response (type=%d bodylen=%d)\n", header.type, header.bodylen);
//
//	switch (type) {
//	//=======================
//	// P2P_TYPE_ASKMYIP
//	//=======================
//	case P2P_TYPE_ASKMYIP:
//		//memcpy(&global_ip, res_body.c_str(), sizeof(global_ip));
//		vcopy((char*)&global_ip, res_body, 0, sizeof(global_ip));
//		memcpy(&sin_addr, &global_ip, sizeof(sin_addr));
//		dprint("[P2P_REQUEST] MY GLOBAL IP IS (%s)\n", inet_ntoa(sin_addr));
//		append_log(0, target_ni.name, "ASKMYIP -> (%s)", inet_ntoa(sin_addr));
//		break;
//	//=======================
//	// P2P_TYPE_GETKEY
//	//=======================
//	case P2P_TYPE_GETKEY:
//		for (i = 0; static_cast<unsigned>(i) < res_body.size()/sizeof(Key); i++) {
//			vcopy((char*)&key, res_body, i*sizeof(Key), sizeof(Key));
//			if (key.core.node.ip == global_ip && key.core.node.port == p2p_port) //自ノードを弾く
//				continue;
//			if (key.core.node.ip == 0) { //IPが未記入の場合は通信先のIPを記入
//				memcpy(&key.core.node, &target_ni.node, sizeof(Node));
//			}
//			otkey->insert(key);
//		}
//		append_log(0, target_ni.name, "キーを受信しました (%d個 %dbyte)",res_body.size()/sizeof(Key), res_body.size());
//		break;
//
//	//=======================
//	// P2P_TYPE_GETYOURKEY
//	//=======================
//	case P2P_TYPE_GETYOURKEY:
//		h = (HWND)data;
//		Edit_SetText(h, "");
//		for (i = 0; static_cast<unsigned>(i) < res_body.size()/sizeof(Key); i++) {
//			char	subj_key[256];
//			char	subject[256];
//			char	tmp[1024];
//
//			vcopy((char*)&key, res_body, i*sizeof(Key), sizeof(Key));
//			if (key.core.node.ip == global_ip && key.core.node.port == p2p_port) //自ノードを弾く
//				continue;
//			if (key.core.node.ip == 0) { //IPが未記入の場合は通信先のIPを記入
//				memcpy(&key.core.node, &target_ni.node, sizeof(Node));
//			}
//			otkey->insert(key);
//
//			wsprintf(subj_key, "%s%s%s%d",
//				key.core.site, key.core.category, key.core.board, key.core.surekey);
//			if (board->search_subject(subj_key, subject)) {
//				wsprintf(tmp, "[%s][%s][%s]%s\r\n", key.core.site, key.core.category, key.core.board, subject);
//			} else {
//				wsprintf(tmp, "[%s][%s][%s]%d.dat\r\n", key.core.site, key.core.category, key.core.board, key.core.surekey);
//			}
//			len = Edit_GetTextLength(h);
//			Edit_SetSel(h, len, len);
//			Edit_ReplaceSel(h, tmp);
//		}
//		append_log(0, target_ni.name, "キーを受信しました (%d個 %dbyte)",res_body.size()/sizeof(Key), res_body.size());
//		break;
//
//	//=======================
//	// P2P_TYPE_GETPROFILE
//	//=======================
//	case P2P_TYPE_GETPROFILE:
//		h = (HWND)data;
//		Edit_SetText(h, "");
//		res_body.push_back('\0');
//		Edit_SetText(h, &res_body[0]);
//		break;
//	}
//	dprint("[P2P_REQUEST] response receive ok (bodylen=%d)\n\n", header.bodylen);
//	//for (i = 0; i < res_body.size(); i++) dprint("[%x]", (unsigned char)res_body[i]);
//	//dprint("\n");
//
//	return true;
//}
