예제 #1
0
	void JobThreadFunc(void)
	{
		Lock();
		O2IMessages queue(Queue);
		Queue.clear();
		Unlock();

		if (queue.size() == 0)
			return;

		hashT myid;
		Profile->GetID(myid);

		O2IMessagesIt it;
		for (it = queue.begin(); it != queue.end() && IsActive(); it++) {
			O2IMessage &im = *it;

			TRACEA("[BroadcastJob]");
			TRACEW(it->msg.c_str());
			TRACEA("\n");

			O2NodeDB::NodeListT neighbors;
			if (NodeDB->neighbors(myid, neighbors, false, O2_BROADCAST_PATH_LIMIT+2) == 0)
				return;

			O2NodeDB::NodeListT::iterator nit = neighbors.begin();
			while (nit != neighbors.end()) {
				if (nit->id == im.id) {
					nit = neighbors.erase(nit);
					continue;
				}
				hashListT::iterator hit = std::find(im.paths.begin(), im.paths.end(), nit->id);
				if (hit != im.paths.end()) {
					nit = neighbors.erase(nit);
					continue;
				}
				nit++;
			}

			if (neighbors.empty())
				continue;

			hashT myid;
			Profile->GetID(myid);
			im.paths.push_back(myid);
			while (im.paths.size() > O2_BROADCAST_PATH_LIMIT)
				im.paths.pop_front();

			for (nit = neighbors.begin(); nit != neighbors.end() && IsActive(); nit++) {
				nit->lastlink = 0;
				nit->reset();

				// Broadcast発行
				O2SocketSession ss;
				ss.ip = nit->ip;
				ss.port = nit->port;

				string xml;
				BroadcastDB->MakeSendXML(im, xml);

				string url;
				MakeURL(ss.ip, ss.port, O2PROTOPATH_BROADCAST, url);

				HTTPHeader hdr(HTTPHEADERTYPE_REQUEST);
				hdr.method = "POST";
				hdr.SetURL(url.c_str());
				AddRequestHeaderFields(hdr, Profile);
				AddContentFields(hdr, xml.size(), "text/xml", DEFAULT_XML_CHARSET);
				hdr.Make(ss.sbuff);
				ss.sbuff += xml;

				Client->AddRequest(&ss);
				ss.Wait();

				HTTPHeader *header = (HTTPHeader*)ss.data;
				if (CheckResponse(&ss, header, NodeDB, *nit)) {
					;
				}

				if (header) delete header;
				Sleep(1000);
			}

			for (nit = neighbors.begin(); nit != neighbors.end() && IsActive(); nit++) {
				if (nit->lastlink) {
					// 成功したノードをtouch
					NodeDB->touch(*nit);
				}
				else {
					// 失敗したノードをremove
					NodeDB->remove(*nit);
					KeyDB->DeleteKeyByNodeID(nit->id);
				}
			}

			Sleep(IsActive() ? 1000 : 0);
		}
	}
예제 #2
0
파일: O2Agent.cpp 프로젝트: idobatter/o2on
uint
O2Agent::
NetIOThread(void)
{
	O2SocketSessionListIt ssit;
	int lasterror;

	while (Active) {
		//setup FD
		fd_set readfds;
		fd_set writefds;
		FD_ZERO(&readfds);
		FD_ZERO(&writefds);

		//wait
		Lock();
		uint n = sss.size();
		Unlock();
		if (n == 0) {
			ResetEvent(SessionAvailableEvent);
		}
		WaitForSingleObject(SessionAvailableEvent, INFINITE);
		if (!Active)
			break;

		//FD
		Lock();
		for (ssit = sss.begin(); ssit != sss.end(); ssit++) {
			O2SocketSession *ss = *ssit;
			if (!ss->sendcomplete)
				FD_SET(ss->sock, &writefds);
			else
				FD_SET(ss->sock, &readfds);
		}
		Unlock();

		//select
		struct timeval tv;
		tv.tv_sec = SELECT_TIMEOUT_MS/1000;
		tv.tv_usec = SELECT_TIMEOUT_MS%1000;
		select(0, &readfds, &writefds, NULL, &tv);

		//
		//	既存セッションとの送受信
		//
		Lock();
		ssit = sss.begin();
		Unlock();
		while (1) {
			bool loopend = false;
			Lock();
			if (ssit == sss.end())
				loopend = true;
			Unlock();
			if (loopend)
				break;

#if DEBUG_THREADLOOP && defined(_DEBUG)
			TRACEA("[NetIO]\n");
#endif
			O2SocketSession *ss = *ssit;
			O2AgentService *service = (O2AgentService*)ss->service;

			ushort port = htons(ss->sin.sin_port);
			wstring ipstr;
#if defined (_DEBUG)
			ulong2ipstr(ss->sin.sin_addr.S_un.S_addr, ipstr);
#else
			ip2e(ss->sin.sin_addr.S_un.S_addr, ipstr);
#endif
			//send
			if (FD_ISSET(ss->sock, &writefds)) {
				int len;
				const char *buff = ss->GetSendBuffer(len);
				if (len > 0) {
					int n = send(ss->sock, buff, len, 0);
#if DEBUG_THREADLOOP && defined(_DEBUG)
					TRACEA("[A]send\n");
#endif
					if (n > 0) {
						ss->UpdateSend(n);
						NodeDB->IncrementSendByte_me2n(ss->sin.sin_addr.S_un.S_addr, n);
						service->IncrementSendByte(n);
						service->OnSend(ss);
						ss->UpdateTimer();

						if (hwndSetIconCallback) {
							PostMessage(hwndSetIconCallback, msgSetIconCallback, 1, 0);
						}
					}
					else if (n == 0) {
						;
					}
					else if ((lasterror = WSAGetLastError()) != WSAEWOULDBLOCK) {
						if (Logger) {
							Logger->AddLog(O2LT_NET, MODULE,
								L"送信エラー(%d) (%s %s:%d %dbyte)",
								lasterror, service->GetName(), ipstr.c_str(), port, ss->sbuff.size());
						}
						ss->SetActive(false);
					}
				}
			}

			//recv
			if (FD_ISSET(ss->sock, &readfds)) {
				char buff[RECVBUFFSIZE];
				int n = recv(ss->sock, buff, RECVBUFFSIZE, 0);
#if DEBUG_THREADLOOP && defined(_DEBUG)
				TRACEA("[A]recv\n");
#endif
				if (n > 0) {
					ss->AppendRecv(buff, n);
					NodeDB->IncrementRecvByte_me2n(ss->sin.sin_addr.S_un.S_addr, n);
					service->IncrementRecvByte(n);
					service->OnRecv(ss);
					ss->UpdateTimer();

					if (hwndSetIconCallback) {
						PostMessage(hwndSetIconCallback, msgSetIconCallback, 0, 0);
					}
				}
				else if (n == 0) {
					if (Logger) {
						Logger->AddLog(O2LT_NET, MODULE,
							L"受信0 (%s %s:%d)",
								service->GetName(), ipstr.c_str(), port);
					}
					ss->SetActive(false);

				}
				else if ((lasterror = WSAGetLastError()) != WSAEWOULDBLOCK) {
					if (Logger) {
						Logger->AddLog(O2LT_NET, MODULE,
						L"受信エラー(%d) (%s %s:%d %dbyte)",
						lasterror, service->GetName(), ipstr.c_str(), port, ss->rbuff.size());
					}
					ss->SetActive(false);
				}
			}

			//delete
			if (!ss->IsActive() || ss->GetPastTime() >= SOCKET_TIMEOUT_S) {
				void *databk = ss->data;
				ulong ip = ss->sin.sin_addr.S_un.S_addr;
				closesocket(ss->sock);
				service->OnClose(ss);
				NodeDB->RemoveStatusBit(ip, O2_NODESTATUS_LINKEDTO);
				NodeDB->AddStatusBit(ip, O2_NODESTATUS_PASTLINKEDTO);
				service->DecrementCount();

				if (!ss->rbuff.empty() && !ss->sbuff.empty()) {
					NodeDB->UpdateLastModified(ip, 2);
					service->IncrementTotalSessionCount();
				}
				else if (ss->rbuff.empty())
					NodeDB->IncrementErrorCount(ip, 1);
				if (!ss->rbuff.empty() && (!databk || ss->rbuff[0] != 'H')) {
					NodeDB->DeleteNode(ip);

					if (Logger) {
						Logger->AddLog(O2LT_WARNING, MODULE,
							L"不正データ受信 (ノード削除: %s:%d)",
							ipstr.c_str(), htons(ss->sin.sin_port));
					}

					if (O2DEBUG) {
						char filename[256];
						sprintf_s(filename, 256, "dump\\A_%d.txt", rand());
						FILE *fp;
						fopen_s(&fp, filename, "wb");
						fwrite(ss->rbuff.c_str(), ss->rbuff.size(), 1, fp);
						fclose(fp);
					}
				}
#if DEBUG_SESSION_COUNT && defined(_DEBUG)
				wchar_t abc[256]; swprintf(abc, L"■■削除■■ count:%d  limit:%d  %s\n",
					service->GetSessionCount(), service->GetSessionLimit(), service->GetName());
				TRACEW(abc);
#endif
				Lock();
				ssit = sss.erase(ssit);
				Unlock();
				delete ss;
				continue;
			}

			Sleep(1);
			ssit++;
		}
	}

	//end
	Lock();
	for (ssit = sss.begin(); ssit != sss.end(); ssit++) {
		O2SocketSession *ss = *ssit;
		closesocket(ss->sock);
		ss->sock = 0;
		((O2AgentService*)((O2AgentService*)ss->service))->OnClose(ss);
		delete ss;
	}
	sss.clear();
	Unlock();

	return (0);
}
예제 #3
0
파일: O2Agent.cpp 프로젝트: idobatter/o2on
uint
O2Agent::
LaunchThread(void)
{
	for (uint i = 0; i < Services.size(); i++) {
		Services[i]->SetActive(true);
		Services[i]->OnServiceStart();
	}
	Agent_GetGlobalIP->SetActive(true);
	Agent_GetGlobalIP->OnServiceStart();

	if (Logger)
		Logger->AddLog(O2LT_INFO, MODULE, L"エージェント正常起動");

	time_t prevconnecttime = time(NULL);
	uint index = 0;

	while (Active) {

		index %= Services.size();

		/*
		 *	ウェイト処理
		 */
		if (NodeDB->Count() == 0) {
#if DEBUG_THREADLOOP && defined(_DEBUG)
			TRACEA("■Node 0\n");
#endif
			Sleep(1000);
			continue;
		}

		uint pasttime_ms = ((uint)time(NULL) - (uint)prevconnecttime) * 1000;
		if (pasttime_ms < Interval) {
			uint sleeptime_ms = Interval - pasttime_ms;
#if DEBUG_THREADLOOP && defined(_DEBUG)
			TRACEA("Wait interval\n");
#endif
			if (Agent_GetGlobalIP->IsActive()) {
				;
				//グローバルIP未確定のときは急ぐ
			}
			else {
				if (sleeptime_ms < 1000)
					Sleep(sleeptime_ms);
				else
					Sleep(1000);
				continue;
			}
		}

		/*
		 *	サービス起動
		 */
		O2AgentService *service = Services[index];
		if (Agent_GetGlobalIP->IsActive())	//グローバルIP未決定のとき
			service = Agent_GetGlobalIP;	//強制的にAgent_GetGlobalIP起動

#if DEBUG_SESSION_COUNT && defined(_DEBUG)
		wchar_t abc[256]; swprintf(abc, L"● count:%d  limit:%d  %s\n",
			service->GetSessionCount(), service->GetSessionLimit(), service->GetName());
		TRACEW(abc);
#endif
		
		if (!service->IsActive()) {
			index++;
			continue;
		}
		if (service->GetSessionCount() >= service->GetSessionLimit()) {
			Sleep(500);
			index++;
			continue;
		}
		
		O2SocketSession *ss = new O2SocketSession();
		ss->service = (void*)service;
		
		ulong ip;
		ushort port;
		wstring ipstr;

		//接続先ノード決定
		//接続 TODO:クラスタリング
		if (service->HaveNodeDecision()) {
			service->OnLaunch(ss);
			if (!ss->IsActive()) {
				delete ss;
				index++;
				continue;
			}
			ip = ss->sin.sin_addr.S_un.S_addr;
			port = htons(ss->sin.sin_port);
		}
		else if (!NodeDB->GetNodeByPriority(ip, port)) {
			if (Logger) {
				Logger->AddLog(O2LT_WARNING, MODULE,
					L"有効なノード情報が無いので接続不可(%s)",
					service->GetName());
			}
			delete ss;
			index++;
			continue;
		}

#if !defined(_DEBUG)
		if (ip == Profile->GetIP() || ip == 0x0100007f) {
#if 0
			struct in_addr addr;
			addr.S_un.S_addr = ip;
			if (Logger) {
				Logger->AddLog(O2LT_WARNING, MODULE,
					"自ノード情報破棄 IP: %s Port: %d",
					inet_ntoa(addr), port);
			}
#endif
			NodeDB->DeleteNode(ip);
			delete ss;
			index++;
			continue;
		}
#endif

#if defined(_DEBUG)
		ulong2ipstr(ip, ipstr);
#else
		ip2e(ip, ipstr);
#endif
		
		/*
		 *	Socket生成
		 */
		ss->sock = socket(AF_INET, SOCK_STREAM, 0);
		if (ss->sock == INVALID_SOCKET) {
			if (Logger)
				Logger->AddLog(O2LT_ERROR, MODULE, L"ソケット生成に失敗");
			delete ss;
			index++;
			continue;
		}

		ss->sin.sin_family = AF_INET;
		ss->sin.sin_port = htons(port);
		ss->sin.sin_addr.S_un.S_addr = ip;
		

		/*
		 *	Connect
		 */
		int timeout = service == Agent_GetGlobalIP ? GIP_CONNECT_TIMEOUT_MS : CONNECT_TIMEOUT_MS;
		if (connect2(ss->sock, (struct sockaddr*)&ss->sin, sizeof(ss->sin), timeout) != 0) {
			//NodeDB->DeleteNode(ip);
			NodeDB->IncrementErrorCount(ip, 1);
			if (Logger) {
				Logger->AddLog(O2LT_NET, MODULE,
					L"connect失敗(%s %s:%d)",
					service->GetName(), ipstr.c_str(), port);
			}
			closesocket(ss->sock);
			delete ss;
			index++;
			continue;
		}
		if (hwndSetIconCallback) {
			PostMessage(hwndSetIconCallback, msgSetIconCallback, 1, 0);
		}

		//launch
		if (!service->HaveNodeDecision()) {
			service->OnLaunch(ss);
			if (!ss->IsActive()) {
				closesocket(ss->sock);
				delete ss;
				index++;
				continue;
			}
		}
		ss->UpdateTimer();
		service->IncrementCount();

		Lock();
		sss.push_back(ss);
		Unlock();
		SetEvent(SessionAvailableEvent);
		
		NodeDB->AddStatusBit(ip, O2_NODESTATUS_LINKEDTO);
		prevconnecttime = time(NULL);
		index++;
		
#if DEBUG_SESSION_COUNT && defined(_DEBUG)
		swprintf(abc, L"●● count:%d  limit:%d  %s\n",
			service->GetSessionCount(), service->GetSessionLimit(), service->GetName());
		TRACEW(abc);
#endif
		if (Logger) {
			Logger->AddLog(O2LT_NET, MODULE,
				L"connect成功 (%s %s:%d)",
				service->GetName(), ipstr.c_str(), port);
		}
	}

	//end
	Lock();
	SetEvent(SessionAvailableEvent);
	Unlock();

	for (uint i = 0; i < Services.size(); i++) {
		O2AgentService *service = Services[i];
		if (service->IsActive()) {
			service->SetActive(false);
			service->OnServiceEnd();
		}
	}

	if (Logger)
		Logger->AddLog(O2LT_INFO, MODULE, L"エージェント正常終了");
	return (0);
}
예제 #4
0
void
O2Client::
NetIOThread(void)
{
	O2SocketSessionPListIt ssit;
	int lasterror;

	while (Active) {

		// Signal Off
		SessionListLock.Lock();
		{
			if (sss.empty())
				SessionExistSignal.Off();
		}
		SessionListLock.Unlock();

		// Wait
		SessionExistSignal.Wait();
		if (!Active) break;

		// Setup FD
		fd_set readfds;
		fd_set writefds;
		FD_ZERO(&readfds);
		FD_ZERO(&writefds);

		SessionListLock.Lock();
		{
			for (ssit = sss.begin(); ssit != sss.end(); ssit++) {
				O2SocketSession *ss = *ssit;
				if (ss->can_send)
					FD_SET(ss->sock, &writefds);
				if (ss->can_recv)
					FD_SET(ss->sock, &readfds);
			}
		}
		SessionListLock.Unlock();

		// select
		struct timeval tv;
		tv.tv_sec = SELECT_TIMEOUT_MS/1000;
		tv.tv_usec = SELECT_TIMEOUT_MS%1000;
		select(0, &readfds, &writefds, NULL, &tv);
		if (!Active) break;

		//
		//	既存セッションとの送受信
		//
		SessionListLock.Lock();
		ssit = sss.begin();
		SessionListLock.Unlock();

		while (Active) {
			bool end = false;
			SessionListLock.Lock();
			{
				if (ssit == sss.end())
					end = true;
			}
			SessionListLock.Unlock();
			if (end) break;

			O2SocketSession *ss = *ssit;

			// IP文字列
			wstring ipstr;
			if (O2DEBUG)
				ulong2ipstr(ss->ip, ipstr);
			else
				ip2e(ss->ip, ipstr);

			// Send
			if (FD_ISSET(ss->sock, &writefds)) {
				int len;
				const char *buff = ss->GetNextSend(len);
				if (len > 0) {
					int n = send(ss->sock, buff, len, 0);
					if (n > 0) 
					{
						ss->UpdateSend(n);
						ss->UpdateTimer();

						SendByte += n;
						OnSend(ss);

						if (hwndSetIconCallback) 
						{
#if defined(_WIN32) && !defined(__WXWINDOWS__) /** Use ordinary windows api */
							PostMessage(hwndSetIconCallback, msgSetIconCallback, 1, 0);
#else                                          /** Platform is not windows */
		                                        #warning "TODO: implement wxWidgets event method here"
#endif
						}
					}
					else if (n == 0) 
					{
						// do nothing
					}
#ifdef _WIN32                           /** Windows */
					else if ((lasterror = WSAGetLastError()) != WSAEWOULDBLOCK) 
#else                                   /** Unix */
					else if (errno == EAGAIN)
#endif
					{
						if (Logger) 
						{
							Logger->AddLog(O2LT_NETERR, ClientName.c_str(),
								       ss->ip, ss->port, L"送信エラー(%d)", lasterror);
						}
						ss->error = true;
						ss->Deactivate();
					}
				}
			}

			// Recv
			if (FD_ISSET(ss->sock, &readfds)) 
			{
				char buff[RECVBUFFSIZE];
				int n = recv(ss->sock, buff, RECVBUFFSIZE, 0);
				if (n > 0) 
				{
					ss->AppendRecv(buff, n);
					ss->UpdateTimer();

					RecvByte += n;
					OnRecv(ss);

					if (hwndSetIconCallback) 
					{
#if defined(_WIN32) && !defined(__WXWINDOWS__)  /** Use ordinary windows api */
						PostMessage(hwndSetIconCallback, msgSetIconCallback, 0, 0);
#else                                           /** Platform is not windows */
		                                #warning "TODO: implement wxWidgets event method here"
#endif
					}
				}
				else if (n == 0) 
				{
					/*if (Logger) {
						Logger->AddLog(O2LT_NETERR, ClientName.c_str(),
							ss->ip, ss->port, L"受信0");
					}*/
					ss->Deactivate();
				}
#ifdef _WIN32                   /** Windows */
				else if ((lasterror = WSAGetLastError()) != WSAEWOULDBLOCK) 
#else                           /** Unix */
				else if (errno == EAGAIN)
#endif
				{
					if (Logger) 
					{
						Logger->AddLog(O2LT_NETERR, ClientName.c_str(),
							       ss->ip, ss->port, L"受信エラー(%d)", lasterror);
					}
					ss->error = true;
					ss->Deactivate();
				}
			}
예제 #5
0
	void JobThreadFunc(void)
	{
		Lock();
		O2KeyList keylist(RequestQueue);
		RequestQueue.clear();
		Unlock();

		if (keylist.size() == 0)
			return;

		O2NodeDB::NodeListT Nodes;

		// キーでループ
		O2KeyListIt it;
		for (it = keylist.begin(); it != keylist.end() && IsActive(); it++) {
			O2Key &key = *it;

			TRACEA("[GETDAT]");
			TRACEW(it->url.c_str());
			TRACEA("\n");

			O2Node node;
			node.id = it->nodeid;
			node.ip = it->ip;
			node.port = it->port;

			// リクエスト発行
			O2SocketSession ss;
			ss.ip = key.ip;
			ss.port = key.port;
			MakeRequest_Dat(&key.hash, NULL, &ss, Profile, DatIO, ss.sbuff);

			Client->AddRequest(&ss);
			ss.Wait();

			HTTPHeader *header = (HTTPHeader*)ss.data;
			if (CheckResponse(&ss, header, NodeDB, node)) {
				// 本文のdat取り込み
				const char *rawdata = &ss.rbuff[header->length];
				uint64 datsize = ss.rbuff.size() - header->length;

				ImportDat(DatIO, Profile, NULL, *header, rawdata, datsize,
					Logger, ss.ip, ss.port, QueryDB, hwndBaloonCallback, msgBaloonCallback);
			}

			if (header) delete header;
			Nodes.push_back(node);

			Sleep(IsActive() ? QUERY_DAT_INTERVAL_MS : 0);
		}

		O2NodeDB::NodeListT::iterator nit;
		for (nit = Nodes.begin(); nit != Nodes.end() && IsActive(); nit++) {
			if (nit->lastlink) {
				// 成功したノードをtouch
				NodeDB->touch(*nit);
			}
			else {
				// 失敗したノードをremove
				NodeDB->remove(*nit);
				KeyDB->DeleteKeyByNodeID(nit->id);
			}
		}
	}
예제 #6
0
파일: O2Client.cpp 프로젝트: idobatter/o2on
void
O2Client::
NetIOThread(void)
{
	O2SocketSessionPListIt ssit;
	int lasterror;

	while (Active) {

		// Signal Off
		SessionListLock.Lock();
		{
			if (sss.empty())
				SessionExistSignal.Off();
		}
		SessionListLock.Unlock();

		// Wait
		SessionExistSignal.Wait();
		if (!Active) break;

		// Setup FD
		fd_set readfds;
		fd_set writefds;
		FD_ZERO(&readfds);
		FD_ZERO(&writefds);

		SessionListLock.Lock();
		{
			for (ssit = sss.begin(); ssit != sss.end(); ssit++) {
				O2SocketSession *ss = *ssit;
				if (ss->can_send)
					FD_SET(ss->sock, &writefds);
				if (ss->can_recv)
					FD_SET(ss->sock, &readfds);
			}
		}
		SessionListLock.Unlock();

		// select
		struct timeval tv;
		tv.tv_sec = SELECT_TIMEOUT_MS/1000;
		tv.tv_usec = SELECT_TIMEOUT_MS%1000;
		select(0, &readfds, &writefds, NULL, &tv);
		if (!Active) break;

		//
		//	既存セッションとの送受信
		//
		SessionListLock.Lock();
		ssit = sss.begin();
		SessionListLock.Unlock();

		while (Active) {
			bool end = false;
			SessionListLock.Lock();
			{
				if (ssit == sss.end())
					end = true;
			}
			SessionListLock.Unlock();
			if (end) break;

			O2SocketSession *ss = *ssit;

			// IP文字列
			wstring ipstr;
			if (O2DEBUG)
				ulong2ipstr(ss->ip, ipstr);
			else
				ip2e(ss->ip, ipstr);

			// Send
			if (FD_ISSET(ss->sock, &writefds)) {
				int len;
				const char *buff = ss->GetNextSend(len);
				if (len > 0) {
					int n = send(ss->sock, buff, len, 0);
					if (n > 0) {
						ss->UpdateSend(n);
						ss->UpdateTimer();

						SendByte += n;
						OnSend(ss);

						if (hwndSetIconCallback) {
							PostMessage(hwndSetIconCallback, msgSetIconCallback, 1, 0);
						}
					}
					else if (n == 0) {
						;
					}
					else if ((lasterror = WSAGetLastError()) != WSAEWOULDBLOCK) {
						if (Logger) {
							Logger->AddLog(O2LT_NETERR, ClientName.c_str(),
								ss->ip, ss->port, L"送信エラー(%d)", lasterror);
						}
						ss->error = true;
						ss->Deactivate();
					}
				}
			}

			// Recv
			if (FD_ISSET(ss->sock, &readfds)) {
				char buff[RECVBUFFSIZE];
				int n = recv(ss->sock, buff, RECVBUFFSIZE, 0);
				if (n > 0) {
					ss->AppendRecv(buff, n);
					ss->UpdateTimer();

					RecvByte += n;
					OnRecv(ss);

					if (hwndSetIconCallback) {
						PostMessage(hwndSetIconCallback, msgSetIconCallback, 0, 0);
					}
				}
				else if (n == 0) {
					/*if (Logger) {
						Logger->AddLog(O2LT_NETERR, ClientName.c_str(),
							ss->ip, ss->port, L"受信0");
					}*/
					ss->Deactivate();
				}
				else if ((lasterror = WSAGetLastError()) != WSAEWOULDBLOCK) {
					if (Logger) {
						Logger->AddLog(O2LT_NETERR, ClientName.c_str(),
							ss->ip, ss->port, L"受信エラー(%d)", lasterror);
					}
					ss->error = true;
					ss->Deactivate();
				}
			}

			// Delete
			if (ss->CanDelete()) {
				bool timeout = ss->GetPastTime() >= ss->timeout_s ? true : false;
				if (!ss->IsActive() || timeout) {
					if (timeout) {
						if (Logger) {
							Logger->AddLog(O2LT_NETERR, ClientName.c_str(),
								ss->ip, ss->port, L"timeout");
						}
					}

					closesocket(ss->sock);
					ss->sock = 0;

					SessionListLock.Lock();
					ssit = sss.erase(ssit);
					SessionListLock.Unlock();

					OnClose(ss);
					continue;
				}
			}

			Sleep(1);

			SessionListLock.Lock();
			ssit++;
			SessionListLock.Unlock();
		}
	}

	// End
	SessionListLock.Lock();
	for (ssit = sss.begin(); ssit != sss.end(); ssit++) {
		O2SocketSession *ss = *ssit;
		closesocket(ss->sock);
		ss->sock = 0;
		OnClose(ss);
	}
	sss.clear();
	SessionListLock.Unlock();
}