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


#include "stdafx.h" 
#include "serverservice.h" 
 
#include "MainFrm.h" 
#include "xmlparser.h" 
#include "QQSocket.h" 
 
CServerService::CServerService(void) 
{ 
	_listenThread	= NULL; 
	_list			= NULL; 
} 
 
CServerService::~CServerService(void) 
{ 
} 
 
HRESULT CServerService::dealLogOnRequest(CXMLParser *request, CElement *responseRoot, CUserList &list) 
{ 
	DEAL_REQUEST_BEGIN() 
 
	CUserData *userData = list.getUserByID(requestRoot->getChildContent(_T("userID"))); 
	if (userData != NULL) 
	{ 
		if (requestRoot->getChildContent(_T("password")) != userData->_password) 
			userData = NULL; 
	} 
	if (userData == NULL) 
	{ 
		responseRoot->AddChild(_T("message"), _T("用户名或密码错误.")); 
		responseRoot->AddChild(_T("result"), _T("1")); 
		return S_OK; 
	} 
 
	responseRoot->AddChild(_T("result"), _T("0")); 
	responseRoot->AddChild(_T("nickname"), userData->_nickname); 
 
	return S_OK; 
} 
 
HRESULT CServerService::dealLogOffRequest(CXMLParser *request, CElement *responseRoot, CUserList &list) 
{ 
	DEAL_REQUEST_BEGIN() 
 
	CUserData *userData = list.getUserByID(requestRoot->getChildContent(_T("userID"))); 
	if (userData != NULL) 
	{ 
		userData->_online = FALSE; 
		userData->_lastReport = 0; 
		::ZeroMemory(&userData->_sockAddr, sizeof(sockaddr_in)); 
	} 
 
	return S_OK; 
} 
 
HRESULT CServerService::dealRegisterRequest(CXMLParser *request, CElement *responseRoot, CUserList &list) 
{ 
	DEAL_REQUEST_BEGIN() 
 
	CUserData *userData = list.getUserByID(requestRoot->getChildContent(_T("userID"))); 
	if (userData != NULL) 
	{ 
		responseRoot->AddChild(_T("result"), _T("1")); 
		responseRoot->AddChild(_T("message"), _T("这个ID已经有人使用了.")); 
		return S_OK; 
	} 
	 
	CUserData newUser; 
	newUser._clientID = requestRoot->getChildContent(_T("userID")); 
	newUser._password = requestRoot->getChildContent(_T("password")); 
	newUser._nickname = requestRoot->getChildContent(_T("nickname")); 
 
	list.addUser(&newUser); 
	responseRoot->AddChild(_T("result"), _T("0")); 
	return S_OK; 
} 
 
HRESULT CServerService::dealQueryUserRequest(CXMLParser *request, CElement *responseRoot, CUserList &list) 
{ 
	DEAL_REQUEST_BEGIN() 
 
	CString userID = requestRoot->getChildContent(_T("userID")); 
	CUserData *userData = list.getUserByID(userID); 
	if (userData == NULL) 
	{ 
		responseRoot->AddChild(_T("result"), _T("1")); 
	} 
	else 
	{ 
		responseRoot->AddChild(_T("result"), _T("0")); 
		responseRoot->AddChild(_T("userID"), userData->_clientID); 
		responseRoot->AddChild(_T("nickname"), userData->_nickname); 
		if (userData->_online) 
		{ 
			responseRoot->AddChild(_T("online"), _T("true")); 
			responseRoot->AddChild(_T("ipAddr"), CQQSocket::IPAddrToString(userData->_sockAddr)); 
			CString port; 
			port.Format("%d", userData->_sockAddr.sin_port); 
			responseRoot->AddChild(_T("port"), port); 
 
		} 
		else 
			responseRoot->AddChild(_T("online"), _T("false")); 
	} 
 
	return S_OK; 
} 
 
HRESULT CServerService::dealAddFriendRequest(CXMLParser *request, CElement *responseRoot, CUserList &list) 
{ 
	DEAL_REQUEST_BEGIN() 
 
	CUserData *friendData = list.getUserByID(requestRoot->getChildContent(_T("friendID"))); 
	if (friendData != NULL) 
	{ 
		CUserData *userData = list.getUserByID(requestRoot->getChildContent(_T("userID"))); 
		HRESULT ret = userData->addFriend(friendData->_clientID); 
		if (ret == S_OK) 
		{ 
			responseRoot->AddChild(_T("result"), _T("0")); 
			return S_OK; 
		} 
 
		if (ret == S_FALSE) 
		{ 
			responseRoot->AddChild(_T("result"), _T("1")); 
			responseRoot->AddChild(_T("message"), _T("该用户已经在好友列表中.")); 
			return S_OK; 
		} 
 
		responseRoot->AddChild(_T("result"), _T("500")); 
		responseRoot->AddChild(_T("message"), _T("服务器内部错误.")); 
		return S_OK; 
	} 
 
	responseRoot->AddChild(_T("result"), _T("2")); 
	responseRoot->AddChild(_T("message"), _T("该用户不存在.")); 
	return S_OK; 
} 
 
HRESULT CServerService::dealDownloadFriendsRequest(CXMLParser *request, CElement *responseRoot, CUserList &list) 
{ 
	DEAL_REQUEST_BEGIN() 
	 
	CUserData *userData = list.getUserByID(requestRoot->getChildContent(_T("userID"))); 
	if (userData != NULL) 
	{ 
		responseRoot->AddChild(_T("result"), _T("0")); 
		for (int i = 0; i < userData->getFriendCount(); i++) 
		{ 
			responseRoot->AddChild(_T("friend"), userData->getFriendID(i)); 
		} 
	} 
	else 
	{ 
		responseRoot->AddChild(_T("result"), _T("1")); 
		responseRoot->AddChild(_T("message"), _T("要查询好友的用户不存在.")); 
	} 
 
	return S_OK; 
} 
 
HRESULT CServerService::dealOnlineRequest(CXMLParser *request, CElement *responseRoot, const sockaddr_in& addrFrom, CUserList &list) 
{ 
	DEAL_REQUEST_BEGIN() 
 
	CUserData *friendData = list.getUserByID(requestRoot->getChildContent(_T("userID"))); 
	if (friendData != NULL) 
	{ 
		CString csPort = requestRoot->getChildContent(_T("port")); 
		short port = _ttoi(csPort); 
 
		memcpy(&friendData->_sockAddr, &addrFrom, sizeof(sockaddr_in)); 
		friendData->_sockAddr.sin_port = port; 
 
		friendData->_lastReport = ::GetTickCount(); 
		friendData->_online	= TRUE; 
	} 
 
	return S_OK; 
} 
 
HRESULT CServerService::dealRequest(BYTE *data,  
									int dataLen,  
									const SOCKET &sock,  
									const sockaddr_in &addrFrom,  
									CUserList* list) 
{ 
	_ASSERTE(data != NULL); 
	if (data == NULL) 
		return E_INVALIDARG; 
 
	CXMLParser request; 
	if (request.LoadXML(data, dataLen) != 0) 
		return E_FAIL; 
 
	CElement *requestRoot = request.get_root(); 
	_ASSERTE(requestRoot->get_tag() == _T("REQUEST")); 
	 
	CElement *type = requestRoot->GetFirstChildByTag(_T("type")); 
	_ASSERTE(type != NULL); 
	if (type == NULL) 
		return E_FAIL; 
	 
	if (type->get_content() != _T("ONLINE")) 
	{ 
		CString log = logMessage(&request, addrFrom); 
		TCHAR *msg = new TCHAR[log.GetLength() + 1]; 
		_tcscpy(msg, log); 
		AfxGetMainWnd()->PostMessage(WM_SERVICE_NOTIFY, (WPARAM)msg, 0); 
	} 
 
	CXMLParser response; 
	CElement *responseRoot = response.createElement(_T("RESPONSE"), _T("")); 
	 
	// Add the new request deal code here. 
	if (type->get_content() == _T("LOGON")) 
	{ 
		HRESULT ret = dealLogOnRequest(&request, responseRoot, *list); 
		if (ret != S_OK) 
		{ 
			delete responseRoot; 
			return ret; 
		} 
	} 
 
	if (type->get_content() == _T("REGISTER")) 
	{ 
		HRESULT ret = dealRegisterRequest(&request, responseRoot, *list); 
		if (ret != S_OK) 
		{ 
			delete responseRoot; 
			return ret; 
		} 
	} 
 
	if (type->get_content() == _T("ADDFRIEND")) 
	{ 
		HRESULT ret = dealAddFriendRequest(&request, responseRoot, *list); 
		if (ret != S_OK) 
		{ 
			delete responseRoot; 
			return ret; 
		} 
	} 
 
	if (type->get_content() == _T("DOWNLOADFRIENDS")) 
	{ 
		HRESULT ret = dealDownloadFriendsRequest(&request, responseRoot, *list); 
		if (ret != S_OK) 
		{ 
			delete responseRoot; 
			return ret; 
		} 
	} 
 
	if (type->get_content() == _T("QUERYUSER")) 
	{ 
		HRESULT ret = dealQueryUserRequest(&request, responseRoot, *list); 
		if (ret != S_OK) 
		{ 
			delete responseRoot; 
			return ret; 
		} 
	} 
 
	if (type->get_content() == _T("ONLINE")) 
	{ 
		dealOnlineRequest(&request, responseRoot, addrFrom, *list); 
		delete responseRoot; 
		return S_OK; 
	} 
 
	if (type->get_content() == _T("LOGOFF")) 
	{ 
		dealLogOffRequest(&request, responseRoot, *list); 
		delete responseRoot; 
		return S_OK; 
	} 
	// End of adding request deal code. 
 
	response.set_root(responseRoot); 
	if (response.BuildXML() != 0) 
	{ 
		TRACE("ERROR: Failed to build the response xml.\n"); 
		return E_FAIL; 
	} 
	CString xml = response.get_xml(); 
 
	int ret = send(sock, ((LPCTSTR)xml), xml.GetLength() * sizeof(TCHAR), 0); 
	if (ret == SOCKET_ERROR) 
		return E_FAIL; 
 
	return S_OK; 
} 
 
UINT CServerService::serviceProc(LPVOID wParam) 
{ 
	auto_ptr param((LISTEN_PARAM*)wParam); 
 
	SOCKET sock = socket(AF_INET, SOCK_STREAM, 0); 
	sockaddr_in addrListen; 
	addrListen.sin_family = AF_INET; 
	addrListen.sin_addr.S_un.S_addr = INADDR_ANY; 
	addrListen.sin_port = htons(6000); 
	int ret = bind(sock, (SOCKADDR*)&addrListen, sizeof(sockaddr_in)); 
	if (ret != 0) 
	{ 
		::closesocket(sock); 
 
		int error = ::WSAGetLastError(); 
		TRACE("ERROR: Failed to bind the server listen socket (%d).\n", error); 
		return -1; 
	} 
 
	ret = listen(sock, 5); 
	if (ret != 0) 
	{ 
		::closesocket(sock); 
 
		int error = ::WSAGetLastError(); 
		TRACE("ERROR: Failed to listen the server listen socket (%d).\n", error); 
		return -1; 
	} 
 
	u_long arg = TRUE; 
	ret = ioctlsocket(sock, FIONBIO, &arg); 
	if (ret != 0) 
	{ 
		::closesocket(sock); 
 
		int error = ::WSAGetLastError(); 
		TRACE("ERROR: Failed to ioctlsocket the socket to non-blocking mode (%d).\n", error); 
		return -1; 
	} 
 
	while(TRUE) 
	{ 
		while(TRUE) 
		{ 
			if (::WaitForSingleObject(*(param->finishEvent), 0) == WAIT_OBJECT_0) 
			{ 
				::closesocket(sock); 
 
				TRACE("NOTIFY: The server's listening thread is finished.\n"); 
				return 0; 
			} 
 
			fd_set readset; 
			FD_ZERO(&readset); 
			FD_SET(sock, &readset); 
			TIMEVAL time; 
			time.tv_sec = 0; 
			time.tv_usec = 1; 
 
			int ret = select(0, &readset, NULL, NULL, &time); 
			if (ret == SOCKET_ERROR) 
			{ 
				::closesocket(sock); 
 
				int error = ::WSAGetLastError(); 
				TRACE("ERROR: Failed to select the socket states (%d).\n", error); 
				return -1; 
			} 
 
			if (ret != 0) 
				break ; 
		} 
 
		sockaddr_in addrFrom; 
		::ZeroMemory(&addrFrom, sizeof(sockaddr_in)); 
		int addrLen = sizeof(sockaddr_in); 
		SOCKET acceptedSock = accept(sock, (SOCKADDR*)&addrFrom, &addrLen); 
		_ASSERTE(acceptedSock != INVALID_SOCKET); 
		if (acceptedSock == INVALID_SOCKET) 
		{ 
			::closesocket(sock); 
 
			int error = ::WSAGetLastError(); 
			TRACE("ERROR: Failed to accept a connect (%d).\n", error); 
			return -1; 
		} 
 
		u_long arg = FALSE; 
		ret = ioctlsocket(acceptedSock, FIONBIO, &arg); 
		if (ret != 0) 
		{ 
			::closesocket(acceptedSock); 
			::closesocket(sock); 
 
			int error = ::WSAGetLastError(); 
			TRACE("ERROR: Failed to ioctlsocket the socket to non-blocking mode (%d).\n", error); 
			return -1; 
		} 
			 
		while(TRUE) 
		{ 
			if (::WaitForSingleObject(*(param->finishEvent), 0) == WAIT_OBJECT_0) 
			{ 
				::closesocket(acceptedSock); 
				::closesocket(sock); 
 
				TRACE("NOTIFY: The server's listening thread is finished.\n"); 
				return 0; 
			} 
 
			DWORD dataLen = 0; 
			ret = ::ioctlsocket(acceptedSock, FIONREAD, &dataLen); 
			if (ret != 0) 
			{ 
				::closesocket(acceptedSock); 
				::closesocket(sock); 
 
				int error = ::WSAGetLastError(); 
				TRACE("ERROR: Failed to ioctlsocket() on the accepted socket (%d).\n", error); 
				return -1; 
			} 
			if (dataLen <= 0) 
			{ 
				Sleep(50); 
				continue ; 
			} 
 
			auto_ptr data(new BYTE[dataLen]); 
			dataLen = recv(acceptedSock, (char*)(data.get()), dataLen, 0); 
			if (dataLen == SOCKET_ERROR) 
			{ 
				::closesocket(acceptedSock); 
				::closesocket(sock); 
 
				int error = ::WSAGetLastError(); 
				TRACE("ERROR: Failed to receive the request (%d).\n", error); 
				return -1; 
			}				 
			 
            dealRequest(data.get(), dataLen, acceptedSock, addrFrom, param->list); 
			break ; 
		} 
		closesocket(acceptedSock); 
	} 
 
	return -1; 
} 
 
HRESULT CServerService::startListen(CUserList *list) 
{ 
	_ASSERTE(_listenThread == NULL); 
	if (_listenThread != NULL) 
		return E_UNEXPECTED; 
 
	_list = list; 
 
	LISTEN_PARAM *param = new LISTEN_PARAM; 
	param->finishEvent = &_finishEvent; 
	param->list = list; 
 
	CWinThread *pThread = AfxBeginThread(CServerService::serviceProc, (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 CServerService::stopListen() 
{ 
	if(_listenThread == NULL) 
		return S_OK; 
 
	_finishEvent.SetEvent(); 
 
	DWORD ret = ::WaitForSingleObject(_listenThread, 5000); 
	_ASSERTE(ret == WAIT_OBJECT_0); 
	if (ret != WAIT_OBJECT_0) 
		return E_FAIL; 
 
	::CloseHandle(_listenThread); 
	_listenThread = NULL; 
 
	return S_OK; 
} 
 
CString CServerService::logMessage(CXMLParser *msg, const sockaddr_in &addrFrom) 
{ 
	CString notifyMsg = _T("Received a request from "); 
	notifyMsg += CQQSocket::IPAddrToString(addrFrom); 
 
	CElementList list; 
	msg->get_root()->GetChildrenByTag(NULL, list); 
 
	POSITION pos = list.GetHeadPosition(); 
	while(pos != NULL) 
	{ 
		CElement *element = list.GetNext(pos); 
		_ASSERTE(element != NULL); 
		if (element == NULL) 
			return _T(""); 
 
		CString csElement; 
		csElement.Format(" %s=%s", element->get_tag(), element->get_content()); 
		notifyMsg += csElement; 
	} 
 
	return notifyMsg; 
}