HRESULT CNktDvTransportEngine::SendMsg(__in DWORD dwPid, __inout NKT_DV_TMSG_COMMON *lpMsg, __in SIZE_T nMsgSize) { CNktDvShutdownAutoLock cSdLock(&cShutdownMtx); CConnectionAutoRef cConnAutoRef; CConnection *lpConn; CNktDvTransportOverlapped *lpOvr; HRESULT hRes; if (lpMsg == NULL) return E_POINTER; if (nMsgSize < sizeof(NKT_DV_TMSG_COMMON) || nMsgSize > NKT_DV_TRANSPORT_MAX_DATA_SIZE) return E_INVALIDARG; { CNktDvAutoCancellableFastMutex cLock(this, &cShutdownMtx); if (cLock.IsLockHeld() == FALSE || cShutdownMtx.IsShuttingDown() != FALSE) return NKT_DVERR_Cancelled; if (cShutdownMtx.IsSystemActive() == FALSE) return E_FAIL; //not initialized //find connection cConnAutoRef.Attach(lpConn = FindConnectionAndAddRef(dwPid), FALSE); if (lpConn == NULL) return NKT_DVERR_NotFound; NKT_DEBUGPRINTLNA(Nektra::dlTransport, ("%lu) TransportEngine[SendMsg]: Pid=%lu, Code=%lu, Id=%lu", ::GetTickCount(), dwPid, lpMsg->dwMsgCode & (~NKT_DV_TMSG_CODE_CALLBACK), lpMsg->dwMsgId & (~NKT_DV_TMSG_ID_CALLBACK))); } { CNktAutoFastMutex cConnAutoLock(lpConn); if (lpConn->nState != XSTATE_Connected) return E_FAIL; //not initialized //get a free buffer lpOvr = lpConn->GetBuffer(); if (lpOvr == NULL) return E_OUTOFMEMORY; //fill buffer nktMemCopy(lpOvr->sMsg.aBuf, lpMsg, nMsgSize); //do write prepare lpOvr->dwType = XTYPE_WriteRequest; lpOvr->nOrder = NktInterlockedIncrement(&(lpConn->nNextWriteOrder)); lpOvr->dwWrittenBytes = (DWORD)nMsgSize; lpConn->AddBufferToRwList(lpOvr); hRes = S_OK; if (::PostQueuedCompletionStatus(lpConn->hIocpCopy, 0, (ULONG_PTR)lpConn, &(lpOvr->sOvr)) == FALSE) hRes = NKT_HRESULT_FROM_LASTERROR(); } if (FAILED(hRes)) { lpConn->FreeBuffer(lpOvr); return hRes; } //done lpConn->AddRef(); NKT_DEBUGPRINTLNA(Nektra::dlTransport, ("%lu) TransportEngine[SendMsg]: Pid=%lu, Ovr=%IXh", ::GetTickCount(), dwPid, lpOvr)); return S_OK; }
VOID CNktDvTransportEngine::DispatcherThreadProc(__in SIZE_T nDispatcherPtr) { #define MESSAGES_PER_ROUND 4 CNktThread *lpThread; CNktDvTransportOverlapped *lpOvr[MESSAGES_PER_ROUND]; HANDLE hAvailableEvent; DWORD dwHitEvent; CConnection *lpConn; SIZE_T nProcessed, k, nRetrieved; CDispatcher *lpDispatcher; HRESULT hRes; lpDispatcher = (CDispatcher*)nDispatcherPtr; //---- lpCallback->TEC_WorkerThreadStarted(); //---- lpThread = &(lpDispatcher->cThread); hAvailableEvent = lpDispatcher->hEvent; while (1) { if (lpThread->CheckForAbort(INFINITE, 1, &hAvailableEvent, &dwHitEvent) != FALSE) break; if (dwHitEvent == 1) { ::ResetEvent(hAvailableEvent); //init working NktInterlockedExchange(&(lpDispatcher->nIsWorking), 1); while (lpThread->CheckForAbort(0) == FALSE) { { CNktAutoFastMutex cLock(lpDispatcher); lpOvr[0] = lpDispatcher->PeekNextOverlapped(); if (lpOvr[0] == NULL) break; lpOvr[0]->RemoveNode(); //remove from list //try to get more messages for (nRetrieved=1; nRetrieved<MESSAGES_PER_ROUND; nRetrieved++) { lpOvr[nRetrieved] = lpDispatcher->PeekNextOverlapped(); if (lpOvr[nRetrieved] == NULL || lpOvr[nRetrieved]->sEngineInternals.lpConn != lpOvr[0]->sEngineInternals.lpConn || lpOvr[nRetrieved]->sEngineInternals.dwThreadId != lpOvr[0]->sEngineInternals.dwThreadId) break; if (lpOvr[0]->sMsg.sMsgCommon.dwMsgCode == NKT_DV_TMSG_CODE_BigData) { if (lpOvr[nRetrieved]->sMsg.sMsgCommon.dwMsgCode != NKT_DV_TMSG_CODE_BigData) break; } else { if (lpOvr[nRetrieved]->sMsg.sMsgCommon.dwMsgCode == NKT_DV_TMSG_CODE_BigData) break; } lpOvr[nRetrieved]->RemoveNode(); //remove from list } } //at this point we have up to 'MESSAGES_PER_ROUND' messages to process of the same //connection/tid lpConn = (CConnection*)(lpOvr[0]->sEngineInternals.lpConn); hRes = S_OK; if (lpOvr[0]->sMsg.sMsgCommon.dwMsgCode == NKT_DV_TMSG_CODE_BigData) { CNktAutoFastMutex cConnAutoLock(lpConn); //try to process a sequence of "NKT_DV_TMSG_CODE_BigData" in the same round for (nProcessed=0; nProcessed<nRetrieved && SUCCEEDED(hRes); nProcessed++) { hRes = lpConn->cBigData->ProcessPacket(&(lpOvr[nProcessed]->sMsg.sMsgCommon)); //signal client message event if (SUCCEEDED(hRes)) hRes = SignalProcessedEvent(lpOvr[nProcessed]); //free buffer lpConn->FreeBuffer(lpOvr[nProcessed]); } } else { //try to process a sequence of standard packets for (nProcessed=0; nProcessed<nRetrieved && SUCCEEDED(hRes); nProcessed++) { //process hRes = lpCallback->TEC_OnAgentMessage(this, lpConn->dwPid, &(lpOvr[nProcessed]->sMsg.sMsgCommon), (SIZE_T)(lpOvr[nProcessed]->dwReadedBytes), lpConn->hAgentProc, lpConn->cBigData); //signal client message event if (SUCCEEDED(hRes)) hRes = SignalProcessedEvent(lpOvr[nProcessed]); } //free processed buffers { CNktAutoFastMutex cConnAutoLock(lpConn); for (k=0; k<nProcessed; k++) lpConn->FreeBuffer(lpOvr[k]); } } //if some packets were not processed, it is almost sure that it is because of an error if (nProcessed < nRetrieved) { //requeue non-processed buffers at the front CNktAutoFastMutex cLock(lpDispatcher); for (k=nRetrieved; k>nProcessed; ) lpDispatcher->AddOverlapped(lpOvr[--k], TRUE); } //release connection one for each processed packet from the list for (k=0; k<nProcessed; k++) lpConn->Release(); //handle errors if (FAILED(hRes)) { if (cShutdownMtx.IsSystemActive() != FALSE && cShutdownMtx.IsShuttingDown() == FALSE) lpCallback->TEC_OnTransportError(this, lpConn->dwPid, hRes); DisconnectAgent(lpConn->dwPid); } } //done working NktInterlockedExchange(&(lpDispatcher->nLastWorkTick), (LONG)::GetTickCount()); NktInterlockedExchange(&(lpDispatcher->nIsWorking), 0); } } //---- lpCallback->TEC_WorkerThreadEnded(); #undef MESSAGES_PER_ROUND return; }
VOID CNktDvTransportEngine::WorkerThreadProc(__in SIZE_T nIndex) { CConnection *lpConn; LPOVERLAPPED _lpOvr; CNktDvTransportOverlapped *lpOvr; HRESULT hRes; HANDLE hEventCopy; BOOL b, bReadPending; DWORD dwNumberOfBytes, dwWritten; lpCallback->TEC_WorkerThreadStarted(); //---- for (;;) { lpConn = NULL; lpOvr = NULL; b = ::GetQueuedCompletionStatus(hIOCP, &dwNumberOfBytes, (PULONG_PTR)&lpConn, &_lpOvr, INFINITE); if (lpConn == NULL) { break; //a completion key of 0 is posted to the iocp to request us to shut down... } hRes = (b != FALSE) ? S_OK : NKT_HRESULT_FROM_LASTERROR(); { CConnectionAutoRef cConnAutoRef(lpConn); lpOvr = CNktDvTransportOverlapped::ClassFromOverlapped(_lpOvr); bReadPending = FALSE; if (_lpOvr != NULL) { switch (lpOvr->dwType) { case XTYPE_Read: lpOvr->dwReadedBytes = dwNumberOfBytes; //add to read queue if (SUCCEEDED(hRes)) { lpConn->AddBufferInSortedReadedQueue(lpOvr); hRes = lpConn->SendReadPacket(); //setup read-ahead } NKT_DEBUGPRINTLNA(Nektra::dlTransport, ("%lu) TransportEngine[ReadCompleted]: Ovr=%IXh, " "hRes=%08X", ::GetTickCount(), lpOvr, hRes)); bReadPending = TRUE; break; case XTYPE_WriteRequest: { CNktAutoFastMutex cLock(lpConn); if (SUCCEEDED(hRes)) lpConn->AddBufferInSortedToWriteQueue(lpOvr); while (SUCCEEDED(hRes) && cShutdownMtx.IsSystemActive() != FALSE && cShutdownMtx.IsShuttingDown() == FALSE) { //get next sequenced block to write lpOvr = lpConn->GetBufferFromSortedToWriteQueue(lpConn->nNextWriteOrderToProcess); if (lpOvr == NULL) break; if (lpOvr->dwType != XTYPE_Discard) { lpConn->AddBufferToRwList(lpOvr); //do real write lpOvr->dwType = XTYPE_Write; if (lpOvr->sMsg.sMsgCommon.hProcessedEvent != NULL) { if (::DuplicateHandle(::GetCurrentProcess(), (HANDLE)(lpOvr->sMsg.sMsgCommon.hProcessedEvent), lpConn->hAgentProc, &hEventCopy, 0, FALSE, DUPLICATE_SAME_ACCESS) != FALSE) lpOvr->sMsg.sMsgCommon.hProcessedEvent = NKT_PTR_2_ULONGLONG(hEventCopy); else hRes = NKT_HRESULT_FROM_LASTERROR(); } if (SUCCEEDED(hRes)) { if (::WriteFile(lpConn->hPipe, &(lpOvr->sMsg), lpOvr->dwWrittenBytes, &dwWritten, &(lpOvr->sOvr)) == FALSE) { hRes = NKT_HRESULT_FROM_LASTERROR(); if (hRes == NKT_HRESULT_FROM_WIN32(ERROR_IO_PENDING)) hRes = S_OK; } } if (SUCCEEDED(hRes)) lpConn->AddRef(); else lpConn->FreeBuffer(lpOvr); NKT_DEBUGPRINTLNA(Nektra::dlTransport, ("%lu) TransportEngine[Write]: Ovr=%IXh, " "hRes=%08X", ::GetTickCount(), lpOvr, hRes)); } else { lpConn->FreeBuffer(lpOvr); } NktInterlockedIncrement(&(lpConn->nNextWriteOrderToProcess)); } } break; case XTYPE_Write: if (SUCCEEDED(hRes) && lpOvr->dwWrittenBytes != dwNumberOfBytes) hRes = NKT_HRESULT_FROM_WIN32(ERROR_WRITE_FAULT); NKT_DEBUGPRINTLNA(Nektra::dlTransport, ("%lu) TransportEngine[WriteCompleted]: Ovr=%IXh, " "hRes=%08X", ::GetTickCount(), lpOvr, hRes)); lpConn->FreeBuffer(lpOvr); break; case XTYPE_Discard: lpConn->FreeBuffer(lpOvr); break; default: NKT_ASSERT(FALSE); lpConn->FreeBuffer(lpOvr); break; } } else { hRes = NKT_DVERR_InvalidTransportData; } if (SUCCEEDED(hRes) && bReadPending != FALSE) { while (SUCCEEDED(hRes) && cShutdownMtx.IsSystemActive() != FALSE && cShutdownMtx.IsShuttingDown() == FALSE) { //get next sequenced block readed lpOvr = lpConn->GetBufferFromSortedReadedQueue(lpConn->nNextReadOrderToProcess); if (lpOvr == NULL) break; hRes = DispatchReadedMessage(lpConn, lpOvr); NktInterlockedIncrement(&(lpConn->nNextReadOrderToProcess)); } } if (FAILED(hRes)) { if (cShutdownMtx.IsSystemActive() != FALSE && cShutdownMtx.IsShuttingDown() == FALSE) lpCallback->TEC_OnTransportError(this, lpConn->dwPid, hRes); DisconnectAgent(lpConn->dwPid); } lpConn->Release(); } } //---- lpCallback->TEC_WorkerThreadEnded(); return; }
HRESULT CNktDvTransportEngine::SendBigPacketMsg(__out LPDWORD lpdwBigPacketId, __in DWORD dwPid, __in LPCVOID lpData, __in SIZE_T nDataSize) { CNktDvShutdownAutoLock cSdLock(&cShutdownMtx); CConnectionAutoRef cConnAutoRef; CConnection *lpConn; CNktDvTransportOverlapped *lpOvr; NKT_DV_TMSG_BIGDATA *lpMsgBd; HRESULT hRes; SIZE_T nThisBlockLen; DWORD dwOrderNo; const BYTE *s; if (lpdwBigPacketId == NULL) return E_POINTER; if (nDataSize < 1) return E_INVALIDARG; { CNktDvAutoCancellableFastMutex cLock(this, &cShutdownMtx); if (cLock.IsLockHeld() == FALSE || cShutdownMtx.IsShuttingDown() != FALSE) return NKT_DVERR_Cancelled; if (cShutdownMtx.IsSystemActive() == FALSE) return E_FAIL; //not initialized //find connection cConnAutoRef.Attach(lpConn = FindConnectionAndAddRef(dwPid), FALSE); if (lpConn == NULL) return NKT_DVERR_NotFound; NKT_DEBUGPRINTLNA(Nektra::dlTransport, ("%lu) TransportEngine[SendBigPacketMsg]: Pid=%lu, Size=%Iu", ::GetTickCount(), dwPid, nDataSize)); } //process the message { CNktAutoFastMutex cConnAutoLock(lpConn); if (lpConn->nState != XSTATE_Connected) return E_FAIL; //not initialized } //NOTE: Ensure that thread sending big packets is the same that later will send // the real message containing the packet id to avoid writing problems s = (const BYTE *)lpData; *lpdwBigPacketId = lpConn->cBigData->GetNextBuildId(); for (dwOrderNo=1; nDataSize>0; dwOrderNo++) { //get a free buffer lpOvr = lpConn->GetBuffer(); if (lpOvr == NULL) return E_OUTOFMEMORY; //build message with data lpMsgBd = (NKT_DV_TMSG_BIGDATA*)&(lpOvr->sMsg.sMsgCommon); hRes = NktDvTransportInitMessage(lpMsgBd, NKT_DV_TMSG_CODE_BigData, GetNextMsgId(), NULL, NULL); if (FAILED(hRes)) { lpConn->FreeBuffer(lpOvr); return hRes; } lpMsgBd->sBdHeader.dwThreadId = 0; lpMsgBd->sBdHeader.dwId = *lpdwBigPacketId; lpMsgBd->sBdHeader.dwOrderNo = dwOrderNo; if ((nThisBlockLen=nDataSize) > sizeof(lpMsgBd->aData)) nThisBlockLen = sizeof(lpMsgBd->aData); lpMsgBd->sBdHeader.dwDataLen = (DWORD)nThisBlockLen; nktMemCopy(lpMsgBd->aData, s, nThisBlockLen); //do write prepare lpOvr->dwType = XTYPE_WriteRequest; lpOvr->nOrder = NktInterlockedIncrement(&(lpConn->nNextWriteOrder)); lpOvr->dwWrittenBytes = (DWORD)(sizeof(lpOvr->sMsg.sMsgCommon) + sizeof(lpMsgBd->sBdHeader) + nThisBlockLen); lpConn->AddBufferToRwList(lpOvr); if (::PostQueuedCompletionStatus(lpConn->hIocpCopy, 0, (ULONG_PTR)lpConn, &(lpOvr->sOvr)) == FALSE) { hRes = NKT_HRESULT_FROM_LASTERROR(); lpConn->FreeBuffer(lpOvr); return hRes; } //done lpConn->AddRef(); //advance source data s += nThisBlockLen; nDataSize -= nThisBlockLen; NKT_DEBUGPRINTLNA(Nektra::dlTransport, ("%lu) TransportEngine[SendBigPacketMsg]: Pid=%lu, Ovr=%IXh, " "Id=%lu, Order=%lu, Size=%lu", ::GetTickCount(), dwPid, lpOvr, *lpdwBigPacketId, dwOrderNo, (DWORD)nThisBlockLen)); } NKT_DEBUGPRINTLNA(Nektra::dlTransport, ("%lu) TransportEngine[SendBigPacketMsg]: Pid=%lu", ::GetTickCount(), dwPid)); return S_OK; }