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;
}