|
@@ -1,797 +0,0 @@
|
|
|
-// ServerComm.cpp: implementation of the CServerComm class.
|
|
|
-//
|
|
|
-//////////////////////////////////////////////////////////////////////
|
|
|
-
|
|
|
-#include "stdafx.h"
|
|
|
-#include "ServerComm.h"
|
|
|
-#include "Package.h"
|
|
|
-
|
|
|
-#include <assert.h>
|
|
|
-#include <process.h>
|
|
|
-#include "openssl/rand.h"
|
|
|
-
|
|
|
-//////////////////////////////////////////////////////////////////////
|
|
|
-// Construction/Destruction
|
|
|
-//////////////////////////////////////////////////////////////////////
|
|
|
-#define SafeCallbackOnError(nConnectionID, nErrorCode) \
|
|
|
- try \
|
|
|
- { \
|
|
|
- string errMsg = GetSysErrorMsg(nErrorCode); \
|
|
|
- char buf[32]; \
|
|
|
- memset(buf, 0, sizeof(buf)); \
|
|
|
- _snprintf(buf, 31, "%d", nErrorCode); \
|
|
|
- m_pCallback->OnError(nConnectionID, buf, errMsg.c_str()); \
|
|
|
- } \
|
|
|
- catch(...) \
|
|
|
- {}
|
|
|
-
|
|
|
-#define SafeCallbackOnError2(nConnectionID, pErrCode, pErrMsg) \
|
|
|
- try \
|
|
|
- { \
|
|
|
- m_pCallback->OnError(nConnectionID, pErrCode, pErrMsg); \
|
|
|
- } \
|
|
|
- catch(...) \
|
|
|
- {}
|
|
|
-
|
|
|
-
|
|
|
-#define SocketErrorHandle(bHandleClose) \
|
|
|
- { \
|
|
|
- int nErrorCode = WSAGetLastError(); \
|
|
|
- if (nErrorCode != WSA_IO_PENDING) \
|
|
|
- { \
|
|
|
- SafeCallbackOnError(pContext->m_nConnectionID, nErrorCode); \
|
|
|
- if (nErrorCode == 10054 && bHandleClose) \
|
|
|
- HandleClose(pContext); \
|
|
|
- } \
|
|
|
- }
|
|
|
-
|
|
|
-CServerComm::CServerComm(CServerCallback *pCallback)
|
|
|
-{
|
|
|
- assert(pCallback != NULL);
|
|
|
- m_pCallback = pCallback;
|
|
|
- m_nThreadCount = 0;
|
|
|
- m_pWorkThreads = NULL;
|
|
|
- m_hListenSocket = INVALID_SOCKET;
|
|
|
- m_hAcceptThread = NULL;
|
|
|
- m_hExitEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
|
|
|
- m_hIOCompletionPort = NULL;
|
|
|
- m_nLastConnectionID =0;
|
|
|
-
|
|
|
- m_bHasInit = false;
|
|
|
-}
|
|
|
-
|
|
|
-CServerComm::~CServerComm()
|
|
|
-{
|
|
|
- if (m_bHasInit)
|
|
|
- EndService();
|
|
|
-
|
|
|
- delete m_pCallback;
|
|
|
- m_pCallback = NULL;
|
|
|
-}
|
|
|
-
|
|
|
-bool CServerComm::BeginService(int nListenPort)
|
|
|
-{
|
|
|
- if (m_bHasInit)
|
|
|
- return true;
|
|
|
-
|
|
|
-
|
|
|
- m_hIOCompletionPort = CreateIoCompletionPort(INVALID_HANDLE_VALUE, NULL, 0, 0);
|
|
|
-
|
|
|
- if (m_hIOCompletionPort == NULL)
|
|
|
- {
|
|
|
- SafeCallbackOnError(0, GetLastError());
|
|
|
- return false;
|
|
|
- }
|
|
|
-
|
|
|
- UINT nThreadID(0);
|
|
|
-
|
|
|
- //Overlapped I/O follows the model established in Windows and can be performed only on
|
|
|
- //sockets created through the WSASocket function
|
|
|
- m_hListenSocket = WSASocket(AF_INET, SOCK_STREAM, 0, NULL, 0, WSA_FLAG_OVERLAPPED);
|
|
|
-
|
|
|
- if (m_hListenSocket == INVALID_SOCKET)
|
|
|
- goto error;
|
|
|
-
|
|
|
- sockaddr_in addr;
|
|
|
- ZeroMemory((char *)&addr, sizeof(addr));
|
|
|
- addr.sin_family = AF_INET;
|
|
|
- addr.sin_addr.s_addr = htonl(INADDR_ANY);
|
|
|
- addr.sin_port = htons(nListenPort);
|
|
|
-
|
|
|
- if (SOCKET_ERROR == bind(m_hListenSocket, (struct sockaddr *) &addr, sizeof(addr)))
|
|
|
- goto error;
|
|
|
-
|
|
|
- m_hAcceptEvent = WSACreateEvent();
|
|
|
- if (WSA_INVALID_EVENT == m_hAcceptEvent)
|
|
|
- goto error;
|
|
|
-
|
|
|
- // select aceept event only
|
|
|
- if (SOCKET_ERROR == WSAEventSelect(m_hListenSocket, m_hAcceptEvent, FD_ACCEPT))
|
|
|
- {
|
|
|
- WSACloseEvent(m_hAcceptEvent);
|
|
|
- m_hAcceptEvent = NULL;
|
|
|
- goto error;
|
|
|
- }
|
|
|
-
|
|
|
- if (SOCKET_ERROR == listen(m_hListenSocket,SOMAXCONN))
|
|
|
- goto error;
|
|
|
-
|
|
|
- // create accept thread
|
|
|
- m_hAcceptThread = (HANDLE)_beginthreadex(NULL, 0, &AcceptThreadFunc, this, 0, &nThreadID);
|
|
|
-
|
|
|
- // create work thread
|
|
|
- m_nThreadCount = 2 * GetProcessorNum();
|
|
|
- m_pWorkThreads = new HANDLE[m_nThreadCount];
|
|
|
-
|
|
|
- int i;
|
|
|
- for(i=0; i<m_nThreadCount; i++)
|
|
|
- {
|
|
|
- m_pWorkThreads[i] = (HANDLE)_beginthreadex(NULL, 0, &WorkThreadFunc, this, 0, &nThreadID);
|
|
|
- }
|
|
|
-
|
|
|
- return true;
|
|
|
-
|
|
|
-error:
|
|
|
- SafeCallbackOnError(0, GetLastError());
|
|
|
-
|
|
|
- if (m_hIOCompletionPort != NULL)
|
|
|
- {
|
|
|
- CloseHandle(m_hIOCompletionPort);
|
|
|
- m_hIOCompletionPort = NULL;
|
|
|
- }
|
|
|
-
|
|
|
- if (m_hListenSocket != INVALID_SOCKET)
|
|
|
- {
|
|
|
- closesocket(m_hListenSocket);
|
|
|
- m_hListenSocket = INVALID_SOCKET;
|
|
|
- }
|
|
|
-
|
|
|
- return false;
|
|
|
-}
|
|
|
-
|
|
|
-
|
|
|
-UINT CServerComm::AcceptThreadFunc(void *pArg)
|
|
|
-{
|
|
|
- CServerComm *pThis = (CServerComm*) pArg;
|
|
|
- assert(pThis != NULL);
|
|
|
-
|
|
|
- //Accept thread will be around to look for accept event, until a Shutdown event is not Signaled.
|
|
|
- while(WAIT_OBJECT_0 != WaitForSingleObject(pThis->m_hExitEvent, 0))
|
|
|
- {
|
|
|
- DWORD dwResult = WSAWaitForMultipleEvents(1, &pThis->m_hAcceptEvent, FALSE, 100, FALSE);
|
|
|
-
|
|
|
- if (dwResult != WSA_WAIT_FAILED && dwResult != WSA_WAIT_TIMEOUT)
|
|
|
- {
|
|
|
- WSANETWORKEVENTS events;
|
|
|
- dwResult = WSAEnumNetworkEvents(pThis->m_hListenSocket, pThis->m_hAcceptEvent, &events);
|
|
|
-
|
|
|
- if ((dwResult != SOCKET_ERROR) && (events.lNetworkEvents & FD_ACCEPT) && (0 == events.iErrorCode[FD_ACCEPT_BIT]))
|
|
|
- {
|
|
|
- // accept socket
|
|
|
- pThis->AcceptConnection();
|
|
|
- }
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
- // 退出线程
|
|
|
- _endthreadex(0);
|
|
|
-
|
|
|
- return 0;
|
|
|
-}
|
|
|
-
|
|
|
-
|
|
|
-void CServerComm::AcceptConnection()
|
|
|
-{
|
|
|
- sockaddr_in clientAddr;
|
|
|
- int nAddrLen = sizeof(clientAddr);
|
|
|
-
|
|
|
- //Accept remote connection attempt from the client
|
|
|
- SOCKET hWorkSocket = accept(m_hListenSocket, (sockaddr*)&clientAddr, &nAddrLen);
|
|
|
-
|
|
|
- if (INVALID_SOCKET == hWorkSocket)
|
|
|
- {
|
|
|
- SafeCallbackOnError(0, GetLastError());
|
|
|
- return;
|
|
|
- }
|
|
|
-
|
|
|
- m_nLastConnectionID++;
|
|
|
-
|
|
|
- //Create a new ClientContext for this newly accepted client
|
|
|
- CConnectionContext *pContext = new CConnectionContext;
|
|
|
-
|
|
|
- pContext->m_hSocket = hWorkSocket;
|
|
|
- pContext->m_nConnectionID = m_nLastConnectionID;
|
|
|
-
|
|
|
- // associate socket with io completion port
|
|
|
- if (CreateIoCompletionPort((HANDLE)hWorkSocket, m_hIOCompletionPort, (DWORD)pContext, 0) == NULL)
|
|
|
- {
|
|
|
- delete pContext;
|
|
|
- return;
|
|
|
- }
|
|
|
-
|
|
|
- //Store this object
|
|
|
- {
|
|
|
- CAutoLock lock(&m_LockObject, 1000);
|
|
|
- m_CnnContextMap[m_nLastConnectionID] = pContext;
|
|
|
- }
|
|
|
-
|
|
|
- // invoke accept callback
|
|
|
- try
|
|
|
- {
|
|
|
- m_pCallback->OnAccept(pContext->m_nConnectionID, inet_ntoa(clientAddr.sin_addr), ntohs(clientAddr.sin_port));
|
|
|
- }
|
|
|
- catch(...){}
|
|
|
-
|
|
|
- //Once the data is successfully received, we will print it.
|
|
|
- WSABUF *pwbuf = pContext->GetRecvWSABuf();
|
|
|
-
|
|
|
- //Get data.
|
|
|
- DWORD dwFlags = 0;
|
|
|
- DWORD dwBytes = 0;
|
|
|
-
|
|
|
- //Post initial Recv
|
|
|
- //This is a right place to post a initial Recv
|
|
|
- //Posting a initial Recv in WorkerThread will create scalability issues.
|
|
|
- int nBytesRecv = WSARecv(pContext->m_hSocket, pwbuf, 1, &dwBytes, &dwFlags, &pContext->m_olRecv, NULL);
|
|
|
-
|
|
|
- if (SOCKET_ERROR == nBytesRecv)
|
|
|
- {
|
|
|
- SocketErrorHandle(true);
|
|
|
- }
|
|
|
-}
|
|
|
-
|
|
|
-UINT CServerComm::WorkThreadFunc(void *pArg)
|
|
|
-{
|
|
|
- CServerComm *pThis = (CServerComm*) pArg;
|
|
|
-
|
|
|
- while(WAIT_OBJECT_0 != WaitForSingleObject(pThis->m_hExitEvent, 0))
|
|
|
- {
|
|
|
- if (!pThis->WorkThreadProcess())
|
|
|
- break;
|
|
|
- }
|
|
|
-
|
|
|
- // 退出线程
|
|
|
- _endthreadex(0);
|
|
|
-
|
|
|
- return 0;
|
|
|
-}
|
|
|
-
|
|
|
-void CServerComm::HandleClose(CConnectionContext *pContext)
|
|
|
-{
|
|
|
- // connection close
|
|
|
- try
|
|
|
- {
|
|
|
- m_pCallback->OnClose(pContext->m_nConnectionID);
|
|
|
- }
|
|
|
- catch(...){}
|
|
|
-
|
|
|
- int nConnectionID = pContext->m_nConnectionID;
|
|
|
-
|
|
|
- CAutoLock lock(&m_LockObject);
|
|
|
- std::map<DWORD, CConnectionContext*>::iterator it = m_CnnContextMap.find(nConnectionID);
|
|
|
- if (it != m_CnnContextMap.end())
|
|
|
- m_CnnContextMap.erase(it);
|
|
|
-
|
|
|
- delete pContext;
|
|
|
-}
|
|
|
-
|
|
|
-
|
|
|
-// 返回参数表示是否退出工作线程
|
|
|
-bool CServerComm::WorkThreadProcess()
|
|
|
-{
|
|
|
- RVCOVERLAPPED *pOverlapped = NULL;
|
|
|
- CConnectionContext *pContext = NULL;
|
|
|
- DWORD dwBytesTransfered = 0;
|
|
|
-
|
|
|
-
|
|
|
- BOOL bRet = GetQueuedCompletionStatus(m_hIOCompletionPort,&dwBytesTransfered,
|
|
|
- (LPDWORD)&pContext, (LPOVERLAPPED *)&pOverlapped, INFINITE);
|
|
|
-
|
|
|
- // should exit now
|
|
|
- if (pContext == NULL)
|
|
|
- return false;
|
|
|
-
|
|
|
- if ((FALSE == bRet) || ((TRUE == bRet) && (0 == dwBytesTransfered)))
|
|
|
- {
|
|
|
- HandleClose(pContext);
|
|
|
- return true;
|
|
|
- }
|
|
|
-
|
|
|
- assert(pOverlapped != NULL);
|
|
|
- if (pOverlapped->IsSendOp())
|
|
|
- {
|
|
|
- assert(pOverlapped == &pContext->m_olSend);
|
|
|
-
|
|
|
- WSABUF *pBUF = NULL;
|
|
|
- {
|
|
|
- CAutoLock lock(&m_LockObject);
|
|
|
- pContext->AddSendLength(dwBytesTransfered);
|
|
|
- pBUF = pContext->GetSendWSABuf();
|
|
|
- }
|
|
|
-
|
|
|
- // 继续发送
|
|
|
- if (pBUF != NULL)
|
|
|
- {
|
|
|
- DWORD dwSendLen(0);
|
|
|
- int nRet = WSASend(pContext->m_hSocket, pBUF, 1, &dwSendLen, 0, &pContext->m_olSend, NULL);
|
|
|
-
|
|
|
- if (SOCKET_ERROR == nRet)
|
|
|
- {
|
|
|
- SocketErrorHandle(true);
|
|
|
- }
|
|
|
- }
|
|
|
- else
|
|
|
- {
|
|
|
- // 发送完成,修改标记
|
|
|
- CAutoLock lock(&m_LockObject);
|
|
|
- pContext->m_bSending = false;
|
|
|
- }
|
|
|
- }
|
|
|
- else
|
|
|
- {
|
|
|
- assert(pOverlapped == &pContext->m_olRecv);
|
|
|
-
|
|
|
- int nPackageLen =0;
|
|
|
- CCommPackage *ppkg = NULL;
|
|
|
-
|
|
|
- // 同时只有一个线程处理接收回调,无需同步
|
|
|
- pContext->m_nHasRecvLen += dwBytesTransfered;
|
|
|
-
|
|
|
- // 检查包头是否完整
|
|
|
- if (pContext->m_nHasRecvLen < sizeof(CPackageHeader))
|
|
|
- goto receive;
|
|
|
-
|
|
|
- // 提取整包长度
|
|
|
- nPackageLen = GetPackageLenFromRecvBuf(pContext);
|
|
|
-
|
|
|
- // 重新分配接收缓冲区
|
|
|
- if (nPackageLen > pContext->m_nRecvBufLen)
|
|
|
- {
|
|
|
- pContext->PrepareRecvBuf(nPackageLen);
|
|
|
- goto receive;
|
|
|
- }
|
|
|
-
|
|
|
- if (pContext->m_nHasRecvLen < nPackageLen)
|
|
|
- goto receive;
|
|
|
-
|
|
|
- // 解析整包长度
|
|
|
- ppkg = new CCommPackage(pContext->m_bHasAuthPass ? pContext->m_arrSessionKey : NULL, NULL);
|
|
|
-
|
|
|
- if (ppkg->ParseRecvData((BYTE*)pContext->m_pRecvBuf, &nPackageLen))
|
|
|
- {
|
|
|
- // 从缓冲区删除完整包数据
|
|
|
- pContext->RemovePackageData(nPackageLen);
|
|
|
-
|
|
|
- if (!pContext->m_bHasAuthPass)
|
|
|
- {
|
|
|
- if (strcmp(ppkg->GetServiceCode().c_str(), "__AUTH__") ==0)
|
|
|
- {
|
|
|
- HandleAuthReqPackage(pContext, ppkg);
|
|
|
- goto receive;
|
|
|
- }
|
|
|
- else if (strcmp(ppkg->GetServiceCode().c_str(), "_SHAKE_") ==0)
|
|
|
- {
|
|
|
- HandleShakeReqPackage(pContext, ppkg);
|
|
|
- goto receive;
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
- // 回调
|
|
|
- try
|
|
|
- {
|
|
|
- m_pCallback->OnReceive(pContext->m_nConnectionID, ppkg);
|
|
|
- }
|
|
|
- catch(...){}
|
|
|
- }
|
|
|
- else
|
|
|
- {
|
|
|
- // 解析失败
|
|
|
- delete ppkg;
|
|
|
-
|
|
|
- try
|
|
|
- {
|
|
|
- m_pCallback->OnError(pContext->m_nConnectionID, 0, "接收报文解析失败");
|
|
|
- }
|
|
|
- catch(...){}
|
|
|
- }
|
|
|
-
|
|
|
-receive:
|
|
|
- // 继续接收
|
|
|
- WSABUF *pwbuf = pContext->GetRecvWSABuf();
|
|
|
- DWORD dwFlags = 0;
|
|
|
- DWORD dwBytes = 0;
|
|
|
-
|
|
|
- int nRet = WSARecv(pContext->m_hSocket, pwbuf, 1, &dwBytes, &dwFlags, &pContext->m_olRecv, NULL);
|
|
|
-
|
|
|
- if (SOCKET_ERROR == nRet)
|
|
|
- {
|
|
|
- SocketErrorHandle(true);
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
- return true;
|
|
|
-}
|
|
|
-
|
|
|
-void CServerComm::HandleAuthReqPackage(CConnectionContext *pContext, IPackage *pReqPkg)
|
|
|
-{
|
|
|
- bool bRet = false;
|
|
|
- int nArrayNum =0;
|
|
|
-
|
|
|
- IPackage *preplyPkg = CreateReplyPackage(pReqPkg);
|
|
|
-
|
|
|
- int nBufLen = pReqPkg->GetStructLen("AUTH_REQ");
|
|
|
- if (nBufLen != sizeof(CConnAuthReq))
|
|
|
- {
|
|
|
- char buf[64];
|
|
|
- sprintf(buf, "鉴权请求结构[AUTH_REQ]长度有误: %d", nBufLen);
|
|
|
-
|
|
|
- SafeCallbackOnError2(pContext->m_nConnectionID, "AUTH101", buf);
|
|
|
- preplyPkg->SetErrMsg("AUTH101", buf);
|
|
|
-
|
|
|
- delete pReqPkg;
|
|
|
- goto reply;
|
|
|
- }
|
|
|
-
|
|
|
- CConnAuthReq authReq;
|
|
|
- memset(&authReq, 0, sizeof(authReq));
|
|
|
-
|
|
|
- bRet = pReqPkg->GetStructData("AUTH_REQ", (BYTE*)&authReq, &nBufLen, &nArrayNum);
|
|
|
- delete pReqPkg;
|
|
|
-
|
|
|
- if (!bRet)
|
|
|
- {
|
|
|
- SafeCallbackOnError2(pContext->m_nConnectionID, "AUTH102", "取鉴权请求结构[AUTHREQ]数据失败");
|
|
|
- preplyPkg->SetErrMsg("AUTH102", "取鉴权请求结构[AUTHREQ]数据失败");
|
|
|
- goto reply;
|
|
|
- }
|
|
|
-
|
|
|
-
|
|
|
- // 验证客户端Token及签名信息
|
|
|
- bRet = VerifyAuthReqInfo(pContext, &authReq);
|
|
|
- if (!bRet)
|
|
|
- {
|
|
|
- SafeCallbackOnError2(pContext->m_nConnectionID, "AUTH103", "验证客户端Token及签名失败");
|
|
|
- preplyPkg->SetErrMsg("AUTH103", "验证客户端Token及签名失败");
|
|
|
- goto reply;
|
|
|
- }
|
|
|
- else
|
|
|
- {
|
|
|
- // 生成临时会话密钥,并加密
|
|
|
- CConnAuthRet authRet;
|
|
|
- memset(&authRet, 0, sizeof(authRet));
|
|
|
-
|
|
|
- if (!GenerateSessionKey(pContext, &authReq, &authRet))
|
|
|
- {
|
|
|
- SafeCallbackOnError2(pContext->m_nConnectionID, "AUTH104", "生成临时会话密钥失败");
|
|
|
- preplyPkg->SetErrMsg("AUTH104", "生成临时会话密钥失败");
|
|
|
- goto reply;
|
|
|
- }
|
|
|
- else
|
|
|
- {
|
|
|
- //pContext->m_bHasAuthPass = true; // 由GenerateSessionKey设置
|
|
|
- preplyPkg->AddStruct("AUTH_RET", false, false, (BYTE*)&authRet, sizeof(authRet));
|
|
|
- goto reply;
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
-reply:
|
|
|
- Send(pContext->m_nConnectionID, preplyPkg);
|
|
|
- delete preplyPkg;
|
|
|
-}
|
|
|
-
|
|
|
-void CServerComm::HandleShakeReqPackage(CConnectionContext *pContext, IPackage *pReqPkg)
|
|
|
-{
|
|
|
- bool bRet = false;
|
|
|
- int nArrayNum =0;
|
|
|
- std::map<DWORD, CSessionItem*>::iterator it = m_CachedSessionKeys.end();
|
|
|
- CSessionItem *pItem = NULL;
|
|
|
-
|
|
|
- IPackage *preplyPkg = CreateReplyPackage(pReqPkg);
|
|
|
-
|
|
|
- int nBufLen = pReqPkg->GetStructLen("SHAKEREQ");
|
|
|
- if (nBufLen != sizeof(CSessionShakeReq))
|
|
|
- {
|
|
|
- char buf[64];
|
|
|
- sprintf(buf, "握手请求结构[SHAKEREQ]长度有误: %d", nBufLen);
|
|
|
-
|
|
|
- SafeCallbackOnError2(pContext->m_nConnectionID, "SHAKE101", buf);
|
|
|
- preplyPkg->SetErrMsg("SHAKE101", buf);
|
|
|
-
|
|
|
- delete pReqPkg;
|
|
|
- goto reply;
|
|
|
- }
|
|
|
-
|
|
|
- CSessionShakeReq shakeReq;
|
|
|
- memset(&shakeReq, 0, sizeof(shakeReq));
|
|
|
-
|
|
|
- bRet = pReqPkg->GetStructData("SHAKEREQ", (BYTE*)&shakeReq, &nBufLen, &nArrayNum);
|
|
|
- delete pReqPkg;
|
|
|
-
|
|
|
- if (!bRet)
|
|
|
- {
|
|
|
- SafeCallbackOnError2(pContext->m_nConnectionID, "SHAKE102", "取握手请求结构[SHAKEREQ]数据失败");
|
|
|
- preplyPkg->SetErrMsg("SHAKE102", "取握手请求结构[SHAKEREQ]数据失败");
|
|
|
- goto reply;
|
|
|
- }
|
|
|
-
|
|
|
- // 验证TerminalNo及SessionID
|
|
|
- {
|
|
|
- CAutoLock lock(&m_LockObject);
|
|
|
- it = m_CachedSessionKeys.find(shakeReq.m_dwSessionID);
|
|
|
- }
|
|
|
-
|
|
|
- if (it == m_CachedSessionKeys.end())
|
|
|
- {
|
|
|
- char buf[64];
|
|
|
- sprintf(buf, "找不到对应的SessionID: [%d]", shakeReq.m_dwSessionID);
|
|
|
-
|
|
|
- SafeCallbackOnError2(pContext->m_nConnectionID, "SHAKE103", buf);
|
|
|
- preplyPkg->SetErrMsg("SHAKE103", buf);
|
|
|
- goto reply;
|
|
|
- }
|
|
|
-
|
|
|
- // 比较TokenHash是否一致
|
|
|
- pItem = (CSessionItem*)(*it).second;
|
|
|
- if (pItem->m_dwTokenHash != shakeReq.m_dwTokenHash)
|
|
|
- {
|
|
|
- char buf[64];
|
|
|
- sprintf(buf, "令牌哈希值不符,握手失败");
|
|
|
-
|
|
|
- SafeCallbackOnError2(pContext->m_nConnectionID, "SHAKE104", buf);
|
|
|
- preplyPkg->SetErrMsg("SHAKE104", buf);
|
|
|
- goto reply;
|
|
|
- }
|
|
|
-
|
|
|
- // 找到对应会话密钥,直接使用
|
|
|
- memcpy(pContext->m_arrSessionKey, pItem->m_arrSessionKey, 16);
|
|
|
- pContext->m_bHasAuthPass = true;
|
|
|
-
|
|
|
-reply:
|
|
|
- Send(pContext->m_nConnectionID, preplyPkg);
|
|
|
- delete preplyPkg;
|
|
|
-}
|
|
|
-
|
|
|
-int CServerComm::GetPackageLenFromRecvBuf(CConnectionContext *pContext)
|
|
|
-{
|
|
|
- if (pContext->m_pRecvBuf == NULL || pContext->m_nRecvBufLen < sizeof(CPackageHeader) || pContext->m_nHasRecvLen < sizeof(CPackageHeader))
|
|
|
- return 0;
|
|
|
-
|
|
|
- CPackageHeader *pHead = (CPackageHeader*) pContext->m_pRecvBuf;
|
|
|
- return pHead->m_nPackageLen;
|
|
|
-}
|
|
|
-
|
|
|
-void CServerComm::EndService()
|
|
|
-{
|
|
|
- if (!m_bHasInit)
|
|
|
- return;
|
|
|
-
|
|
|
- SetEvent(m_hExitEvent);
|
|
|
-
|
|
|
- for (int i = 0; i < m_nThreadCount; i++)
|
|
|
- {
|
|
|
- //Help threads get out of blocking - GetQueuedCompletionStatus()
|
|
|
- PostQueuedCompletionStatus(m_hIOCompletionPort, 0, (DWORD) NULL, NULL);
|
|
|
- }
|
|
|
-
|
|
|
- WaitForSingleObject(m_hAcceptThread, INFINITE);
|
|
|
- WaitForMultipleObjects(m_nThreadCount, m_pWorkThreads, TRUE, INFINITE);
|
|
|
-
|
|
|
- std::map<DWORD, CConnectionContext*>::iterator it;
|
|
|
- for(it = m_CnnContextMap.begin(); it != m_CnnContextMap.end(); it++)
|
|
|
- {
|
|
|
- delete (*it).second;
|
|
|
- }
|
|
|
- m_CnnContextMap.clear();
|
|
|
-
|
|
|
- for (i = 0; i < m_nThreadCount; i++)
|
|
|
- {
|
|
|
- CloseHandle(m_pWorkThreads[i]);
|
|
|
- }
|
|
|
-
|
|
|
- delete[] m_pWorkThreads;
|
|
|
- m_pWorkThreads = NULL;
|
|
|
-
|
|
|
- WSACloseEvent(m_hAcceptEvent);
|
|
|
- m_hAcceptEvent = NULL;
|
|
|
- CloseHandle(m_hAcceptThread);
|
|
|
- m_hAcceptThread = NULL;
|
|
|
-
|
|
|
- CloseHandle(m_hExitEvent);
|
|
|
- m_hExitEvent = NULL;
|
|
|
-
|
|
|
- closesocket(m_hListenSocket);
|
|
|
- m_hListenSocket = INVALID_SOCKET;
|
|
|
-
|
|
|
- CloseHandle(m_hIOCompletionPort);
|
|
|
- m_hIOCompletionPort = NULL;
|
|
|
-
|
|
|
- m_bHasInit = false;
|
|
|
-}
|
|
|
-
|
|
|
-const string CServerComm::Send(int nConnectionID, const IPackage *pSendPkg)
|
|
|
-{
|
|
|
- CCommPackage *pkg = (CCommPackage*) pSendPkg;
|
|
|
- assert(pkg != NULL);
|
|
|
-
|
|
|
- int nBufLen = pkg->GetPackageLen();
|
|
|
- BYTE *pBuf = new BYTE[nBufLen];
|
|
|
- memset(pBuf, 0, nBufLen);
|
|
|
- pkg->GenerateSendData(pBuf, &nBufLen);
|
|
|
-
|
|
|
- std::map<DWORD, CConnectionContext*>::iterator it;
|
|
|
- {
|
|
|
- CAutoLock lock(&m_LockObject, 1000);
|
|
|
- it = m_CnnContextMap.find(nConnectionID);
|
|
|
- assert(it != m_CnnContextMap.end());
|
|
|
- }
|
|
|
-
|
|
|
- if (it == m_CnnContextMap.end())
|
|
|
- {
|
|
|
- try
|
|
|
- {
|
|
|
- m_pCallback->OnError(nConnectionID, 0, "连接标识无效");
|
|
|
- }
|
|
|
- catch(...){}
|
|
|
-
|
|
|
- delete[] pBuf;
|
|
|
- return "";
|
|
|
- }
|
|
|
-
|
|
|
- CConnectionContext *pContext = (*it).second;
|
|
|
- {
|
|
|
- CAutoLock lock(&m_LockObject);
|
|
|
- pContext->AddSendBuf((char*)pBuf, nBufLen);
|
|
|
- }
|
|
|
-
|
|
|
- // 发送操作不能并发
|
|
|
- if (pContext->m_bSending)
|
|
|
- return pkg->GetPackageReqID();
|
|
|
-
|
|
|
- {
|
|
|
- CAutoLock lock(&m_LockObject);
|
|
|
-
|
|
|
- // 再次检查
|
|
|
- if (pContext->m_bSending)
|
|
|
- return pkg->GetPackageReqID();
|
|
|
-
|
|
|
- pContext->m_bSending = true;
|
|
|
- }
|
|
|
-
|
|
|
- // 开始发送
|
|
|
- WSABUF *pBUF = pContext->GetSendWSABuf();
|
|
|
-
|
|
|
- DWORD dwSendLen(0);
|
|
|
- int nRet = WSASend(pContext->m_hSocket, pBUF, 1, &dwSendLen, 0, &pContext->m_olSend, NULL);
|
|
|
-
|
|
|
- if (SOCKET_ERROR == nRet)
|
|
|
- {
|
|
|
- // 避免并发,关闭处理全部移到工作线程中
|
|
|
- SocketErrorHandle(false);
|
|
|
- }
|
|
|
-
|
|
|
- return pkg->GetPackageReqID();
|
|
|
-}
|
|
|
-
|
|
|
-IPackage* CServerComm::CreateSendPackage(int nConnectionID, const char *pServiceCode)
|
|
|
-{
|
|
|
- // get sessionkey from connectionid
|
|
|
- BYTE *pSessionKey = NULL;
|
|
|
-
|
|
|
- std::map<DWORD, CConnectionContext*>::iterator it;
|
|
|
- {
|
|
|
- CAutoLock lock(&m_LockObject, 1000);
|
|
|
- it = m_CnnContextMap.find(nConnectionID);
|
|
|
- assert(it != m_CnnContextMap.end());
|
|
|
- }
|
|
|
-
|
|
|
- if (it != m_CnnContextMap.end() && (*it).second->m_bHasAuthPass)
|
|
|
- pSessionKey = (*it).second->m_arrSessionKey;
|
|
|
-
|
|
|
- return new CCommPackage(pSessionKey, pServiceCode);
|
|
|
-}
|
|
|
-
|
|
|
-IPackage* CServerComm::CreateReplyPackage(IPackage *pRecvPkg)
|
|
|
-{
|
|
|
- return new CCommPackage((CCommPackage*)pRecvPkg);
|
|
|
-}
|
|
|
-
|
|
|
-int CServerComm::GetProcessorNum()
|
|
|
-{
|
|
|
- static int nProcessors = 0;
|
|
|
-
|
|
|
- if (0 == nProcessors)
|
|
|
- {
|
|
|
- SYSTEM_INFO si;
|
|
|
- GetSystemInfo(&si);
|
|
|
- nProcessors = si.dwNumberOfProcessors;
|
|
|
- }
|
|
|
-
|
|
|
- return nProcessors;
|
|
|
-}
|
|
|
-
|
|
|
-// 验证令牌有效性,提取客户端公钥,解密设备信息,验证客户端是否合法,并保存客户端公钥到上下文m_TempPubKey中
|
|
|
-bool CServerComm::VerifyAuthReqInfo(CConnectionContext *pContext, CConnAuthReq *pReq)
|
|
|
-{
|
|
|
- // 用服务器公钥解密令牌
|
|
|
- BYTE *pSource = pReq->m_arrVerifyToken;
|
|
|
-
|
|
|
- BYTE buf[256] = {0};
|
|
|
- int nBufLen = 256;
|
|
|
-
|
|
|
- if (!DecWithServerPubKey(pSource, 256, buf, &nBufLen))
|
|
|
- return false;
|
|
|
-
|
|
|
- assert(nBufLen == sizeof(CTokenInfo));
|
|
|
- CTokenInfo *pToken = (CTokenInfo*) buf;
|
|
|
-
|
|
|
- // 计算Hash,并比较
|
|
|
- BYTE md5[16];
|
|
|
- MD5Hash(buf, sizeof(CTokenInfo) - 16, md5);
|
|
|
-
|
|
|
- if (memcmp(pToken->m_arrHash, md5, 16) != 0)
|
|
|
- return false;
|
|
|
-
|
|
|
- // 使用客户端公钥解密设备信息
|
|
|
- BYTE buf2[128] = {0};
|
|
|
- nBufLen = 128;
|
|
|
- if (!DecWithRsaPubKey(pReq->m_arrVerifyInfo, 128, buf2, &nBufLen, pToken->m_arrTempPubKey, 140))
|
|
|
- return false;
|
|
|
-
|
|
|
- if (nBufLen != sizeof(CVerifyInfo))
|
|
|
- return false;
|
|
|
-
|
|
|
- // 比较设备信息与令牌中信息是否一致
|
|
|
- CVerifyInfo *pDevice = (CVerifyInfo*)buf2;
|
|
|
- if (memcmp(pDevice->m_arrTerminalNo, pToken->m_arrTerminalNo, sizeof(pDevice->m_arrTerminalNo)) != 0)
|
|
|
- return false;
|
|
|
-
|
|
|
- if (memcmp(pDevice->m_arrIP, pToken->m_arrIP, sizeof(pDevice->m_arrIP)) != 0)
|
|
|
- return false;
|
|
|
-
|
|
|
- // 校验通过,保存客户端公钥到上下文
|
|
|
- CAutoLock lock(&m_LockObject);
|
|
|
- memcpy(pContext->m_arrTempPubKey, pToken->m_arrTempPubKey, 140);
|
|
|
-
|
|
|
- return true;
|
|
|
-}
|
|
|
-
|
|
|
-// 生成临时会话密钥,保存到上下文中,并使用客户端公钥加密后放入返回结构中
|
|
|
-bool CServerComm::GenerateSessionKey(CConnectionContext *pContext, CConnAuthReq *pReq, CConnAuthRet *pRet)
|
|
|
-{
|
|
|
- // 使用随机数生成器生成会话密钥
|
|
|
- BYTE buf[16];
|
|
|
- memset(buf, 0 ,sizeof(buf));
|
|
|
-
|
|
|
- int nRet = RAND_bytes(buf, 16);
|
|
|
- if (nRet <0)
|
|
|
- return false;
|
|
|
-
|
|
|
- // 使用m_TempPubKey加密buf到pRet中
|
|
|
- int nBufLen = 128;
|
|
|
- if (!EncWithRsaPubKey(buf, 16, pRet->m_arrEncSessionKey, &nBufLen, pContext->m_arrTempPubKey, 140))
|
|
|
- return false;
|
|
|
-
|
|
|
- // 生成SessionID并保存
|
|
|
- BYTE md5[16];
|
|
|
- memset(md5, 0, 16);
|
|
|
- MD5Hash(buf, 16, md5);
|
|
|
- DWORD dwSessionID = ((DWORD)md5[0]) << 24 | ((DWORD)md5[1]) << 16 | ((DWORD)md5[2]) << 8 | ((DWORD)md5[3]);
|
|
|
-
|
|
|
- // 生成TokenHash并保存
|
|
|
- memset(md5, 0, 16);
|
|
|
- MD5Hash(pReq->m_arrVerifyToken, sizeof(pReq->m_arrVerifyToken), md5);
|
|
|
- DWORD dwTokenHash = ((DWORD)md5[0]) << 24 | ((DWORD)md5[1]) << 16 | ((DWORD)md5[2]) << 8 | ((DWORD)md5[3]);
|
|
|
-
|
|
|
- CSessionItem *pItem = new CSessionItem();
|
|
|
- pItem->m_dwTokenHash = dwTokenHash;
|
|
|
- memcpy(pItem->m_arrSessionKey, buf, 16);
|
|
|
-
|
|
|
- CAutoLock lock(&m_LockObject);
|
|
|
- m_CachedSessionKeys[dwSessionID] = pItem;
|
|
|
-
|
|
|
- // 保存会话密钥
|
|
|
- memcpy(pContext->m_arrSessionKey, buf, 16);
|
|
|
- pContext->m_bHasAuthPass = true;
|
|
|
-
|
|
|
- return true;
|
|
|
-}
|