www.pudn.com > QQ2004_Source_0.01.rar > PeerComm.cpp


#include "stdafx.h" 
#include "peercomm.h" 
 
#include  
using namespace std; 
 
#include "XMLParser.h" 
#include "Communication.h" 
 
CPeerComm::CPeerComm(void) 
{ 
	_listenThread = NULL; 
} 
 
CPeerComm::~CPeerComm(void) 
{ 
} 
 
UINT CPeerComm::listenProc(LPVOID wParam) 
{ 
	_ASSERTE(wParam != NULL); 
	if (wParam == NULL) 
		return -1; 
	auto_ptr param((LISTEN_PARAM*)wParam); 
 
	SOCKET sock = socket(AF_INET, SOCK_DGRAM, 0); 
	sockaddr_in addrListen; 
	addrListen.sin_family = AF_INET; 
	addrListen.sin_addr.S_un.S_addr = INADDR_ANY; 
	addrListen.sin_port = 0; 
	int ret = bind(sock, (SOCKADDR*)&addrListen, sizeof(sockaddr_in)); 
	if (ret != 0) 
	{ 
		::closesocket(sock); 
 
		int error = ::WSAGetLastError(); 
		TRACE("ERROR: Failed to bind the peer listen socket (%d).\n", error); 
		return -1; 
	} 
 
	while(TRUE) 
	{ 
		if (::WaitForSingleObject(*(param->finishEvent), 0) == WAIT_OBJECT_0) 
		{ 
			::closesocket(sock); 
 
			TRACE("NOTIFY: The peer's listening thread is finished.\n"); 
			::closesocket(sock); 
			return 0; 
		} 
 
		DWORD dataLen = 0; 
		ret = ::ioctlsocket(sock, FIONREAD, &dataLen); 
		if (ret != 0) 
		{ 
			::closesocket(sock); 
 
			int error = ::WSAGetLastError(); 
			TRACE("ERROR: Failed to ioctlsocket() in the peer's listening (%d).\n", error); 
			return -1; 
		} 
		if (dataLen <= 0) 
		{ 
			static int count = 0; 
			if (count++ >= 4) 
			{ 
				sockaddr_in *addr = &(param->serverAddr); 
				CPeerComm::sendOnlineRequest(sock, param->serverAddr, param->userID); 
				count = 0; 
 
				sockaddr_in addrBind; 
				int addrLen = sizeof(sockaddr_in); 
				int ret = getsockname(sock, (SOCKADDR*)&addrBind, &addrLen); 
				if (ret != 0) 
					count = 0; 
			} 
			Sleep(500); 
			continue ; 
		} 
 
		auto_ptr data(new char[dataLen]); 
		sockaddr_in addrFrom; 
		int addrLen = sizeof(sockaddr_in); 
		dataLen = ::recvfrom(sock, data.get(), dataLen, 0, (SOCKADDR*)&addrFrom, &addrLen); 
		if (dataLen == -1) 
		{ 
			int error = ::WSAGetLastError(); 
			TRACE("ERROR: Failed to receive the data from peer (%ld).\n", dataLen); 
			continue ; 
		} 
		CElement *root = NULL; 
		CXMLParser parser; 
		if (parser.LoadXML((BYTE*)(data.get()), dataLen) == 0) 
			root = parser.get_root(); 
		if (root == NULL) 
		{ 
			TRACE(_T("ERROR: Unknown client message.\n")); 
			continue ; 
		} 
 
		CString message = root->getChildContent(_T("message")); 
		CString friendID = root->getChildContent(_T("userID")); 
		if (message.IsEmpty() || friendID.IsEmpty()) 
			continue ; 
 
		TCHAR *szMessage = new TCHAR[message.GetLength() + 1]; 
		TCHAR *szFriendID = new TCHAR[friendID.GetLength() + 1]; 
		_tcscpy(szMessage, message); 
		_tcscpy(szFriendID, friendID); 
		param->wnd->PostMessage(WM_PEER_NOTIFY, (WPARAM)szMessage, (LPARAM)szFriendID); 
	} 
 
	return -1; 
} 
 
HRESULT CPeerComm::sendMsgToFriend(CString msg,  
								   const sockaddr_in &friendAddr,  
								   CString userID) 
{ 
	CXMLParser parser; 
 
	CElement *root = parser.createElement(_T("MESSAGE"), _T("")); 
	root->AddChild(_T("userID"), userID); 
	root->AddChild(_T("message"), msg); 
	parser.set_root(root); 
 
	if (parser.BuildXML() != 0) 
		return E_FAIL; 
	CString sendOut = parser.get_xml(); 
 
	CQQSocket sock; 
	if (sock.create(0) != TRUE) 
		return E_FAIL; 
 
	HRESULT ret = sock.sendToHost((SOCKADDR*)&friendAddr,  
								(BYTE*)((LPCTSTR)sendOut),  
								sendOut.GetLength()); 
	if (ret != S_OK) 
	{ 
		AfxMessageBox("·¢ËÍÏûϢʧ°Ü."); 
		return E_FAIL; 
	} 
 
	return S_OK; 
} 
 
HRESULT CPeerComm::startListen(CWnd *wnd, CString userID, const sockaddr_in &serverAddr) 
{ 
	_ASSERTE(_listenThread == NULL); 
	if (_listenThread != NULL) 
		return E_UNEXPECTED; 
 
	LISTEN_PARAM *param = new LISTEN_PARAM; 
	param->finishEvent = &_finishEvent; 
	param->wnd = wnd; 
	param->userID = userID; 
	memcpy(¶m->serverAddr, &serverAddr, sizeof(sockaddr_in)); 
 
	CWinThread *pThread = AfxBeginThread(CPeerComm::listenProc, (LPVOID)param, 0, 0, CREATE_SUSPENDED); 
	_ASSERTE(pThread != NULL); 
	if (pThread == NULL) 
		return E_FAIL; 
 
	HANDLE hProcess = ::GetCurrentProcess(); 
	BOOL ret = ::DuplicateHandle(hProcess,  
								pThread->m_hThread,  
								hProcess,  
								&_listenThread,  
								0,  
								TRUE,  
								DUPLICATE_SAME_ACCESS); 
	_ASSERTE(ret != FALSE); 
	if (ret == FALSE) 
		return E_FAIL; 
 
	pThread->ResumeThread(); 
 
	return S_OK; 
} 
 
HRESULT CPeerComm::stopListen() 
{ 
	if(_listenThread == NULL) 
		return S_OK; 
 
	_finishEvent.SetEvent(); 
 
	DWORD ret = ::WaitForSingleObject(_listenThread, 10000); 
	_ASSERTE(ret == WAIT_OBJECT_0); 
	if (ret != WAIT_OBJECT_0) 
		return E_FAIL; 
 
	::CloseHandle(_listenThread); 
	_listenThread = NULL; 
 
	return S_OK; 
} 
 
HRESULT CPeerComm::sendOnlineRequest(SOCKET sock, const sockaddr_in &serverAddr, LPCTSTR userID) 
{ 
	CXMLParser parser; 
 
	int addrLen = sizeof(sockaddr_in); 
	sockaddr_in addrSock; 
	int ret = getsockname(sock, (SOCKADDR*)&addrSock, &addrLen); 
	if (ret != 0) 
	{ 
		int error = ::WSAGetLastError(); 
		TRACE("ERROR: Failed to get the listen socket port (%d).\n", error); 
		return E_FAIL; 
	} 
 
	CCommunication comm; 
	if (comm.create() != S_OK) 
		return E_FAIL; 
 
	if (comm.connect(CQQSocket::IPAddrToString(serverAddr)) != S_OK) 
		return E_FAIL; 
 
	return comm.sendOnlineRequest(userID, addrSock.sin_port); 
}