QString QAutoGenDialog::GetFileParameter(const QString & strParam, const QString & strFilename, unsigned int iVehicle) { std::map<QString, std::vector<QString> >::iterator iterFileData = m_mapFileData.find(strFilename); if (iterFileData == m_mapFileData.end()) { QFile fileData(strFilename); if (fileData.exists() && fileData.open(QIODevice::ReadOnly | QIODevice::Text)) { Q3TextStream streamData(&fileData); QString strLine; iterFileData = m_mapFileData.insert(std::pair<QString, std::vector<QString> >(strFilename, std::vector<QString>())).first; while (!(strLine = streamData.readLine()).isNull()) { strLine = strLine.stripWhiteSpace(); if (strLine.isEmpty()) continue; iterFileData->second.push_back(strLine); } fileData.close(); } } if (iterFileData == m_mapFileData.end()) return ""; else return iterFileData->second[iVehicle % iterFileData->second.size()]; }
//-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- bool RifEclipseUserDataParserTools::isFixedWidthHeader(const std::string& lines) { std::stringstream streamData(lines); std::vector<std::string> headerLines = RifEclipseUserDataParserTools::findValidHeaderLines(streamData); if (headerLines.size() > 1) { std::vector<size_t> firstLine = RifEclipseUserDataParserTools::columnIndexForWords(headerLines[0]); for (auto line : headerLines) { std::vector<size_t> columnIndicesForLine = RifEclipseUserDataParserTools::columnIndexForWords(line); for (auto index : columnIndicesForLine) { if (std::find(firstLine.begin(), firstLine.end(), index) == firstLine.end()) { return false; } } } return true; } return false; }
BOOL CFileStreamParser::OpenFile(LPCTSTR szFile) { CloseFile(); m_hFileStream = ::CreateFile(szFile, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL); if (m_hFileStream != INVALID_HANDLE_VALUE) { _tcscpy(m_szFilename, szFile); std::auto_ptr<BYTE> streamData(new BYTE[ MAX_FRAME_LENGTH ]); memset(streamData.get(), 0, MAX_FRAME_LENGTH); FRAME_HEADER fh; INT nRet = GetOneFrame(streamData.get(), &fh); if (nRet <= 0) { nRet = GetOneFrame(streamData.get(), &fh); if ( nRet <= 0) { m_nFirstFrameTime = 0; m_nLastFrameTime = 0; return TRUE; } } m_nFirstFrameTime = htonl(fh.FrameTime); dwFileSize = GetFileSize(); DWORD dwMovePos = dwFileSize-100; DWORD dwCurPos = 0; if (dwMovePos > 0 && INVALID_SET_FILE_POINTER != (dwCurPos = ::SetFilePointer(m_hFileStream, dwMovePos, 0, FILE_BEGIN))) { nRet = GetOneFrame(streamData.get(), &fh); while((nRet <= 0 && (dwMovePos - 100)) > 0 || (nRet > 0 && (fh.FrameRate != 25 || fh.FrameType == 10))) { dwMovePos -= 100; if (INVALID_SET_FILE_POINTER == (dwCurPos = ::SetFilePointer(m_hFileStream, dwMovePos, 0, FILE_BEGIN))) break; nRet = GetOneFrame(streamData.get(), &fh); } if (nRet > 0) { m_nLastFrameTime = htonl(fh.FrameTime); } } ::SetFilePointer(m_hFileStream, 0, 0, FILE_BEGIN); return TRUE; } return FALSE; }
static void TestPDFStream(skiatest::Reporter* reporter) { char streamBytes[] = "Test\nFoo\tBar"; SkAutoTUnref<SkMemoryStream> streamData(new SkMemoryStream( streamBytes, strlen(streamBytes), true)); SkAutoTUnref<SkPDFStream> stream(new SkPDFStream(streamData.get())); SimpleCheckObjectOutput( reporter, stream.get(), "<</Length 12\n>> stream\nTest\nFoo\tBar\nendstream"); stream->insert("Attribute", new SkPDFInt(42))->unref(); SimpleCheckObjectOutput(reporter, stream.get(), "<</Length 12\n/Attribute 42\n>> stream\n" "Test\nFoo\tBar\nendstream"); if (SkFlate::HaveFlate()) { char streamBytes2[] = "This is a longer string, so that compression " "can do something with it. With shorter strings, " "the short circuit logic cuts in and we end up " "with an uncompressed string."; SkAutoDataUnref streamData2(SkData::NewWithCopy(streamBytes2, strlen(streamBytes2))); SkAutoTUnref<SkPDFStream> stream(new SkPDFStream(streamData2.get())); SkDynamicMemoryWStream compressedByteStream; SkFlate::Deflate(streamData2.get(), &compressedByteStream); SkAutoDataUnref compressedData(compressedByteStream.copyToData()); // Check first without compression. SkDynamicMemoryWStream expectedResult1; expectedResult1.writeText("<</Length 167\n>> stream\n"); expectedResult1.writeText(streamBytes2); expectedResult1.writeText("\nendstream"); SkAutoDataUnref expectedResultData1(expectedResult1.copyToData()); CheckObjectOutput(reporter, stream.get(), (const char*) expectedResultData1->data(), expectedResultData1->size(), true, false); // Then again with compression. SkDynamicMemoryWStream expectedResult2; expectedResult2.writeText("<</Filter /FlateDecode\n/Length 116\n" ">> stream\n"); expectedResult2.write(compressedData->data(), compressedData->size()); expectedResult2.writeText("\nendstream"); SkAutoDataUnref expectedResultData2(expectedResult2.copyToData()); CheckObjectOutput(reporter, stream.get(), (const char*) expectedResultData2->data(), expectedResultData2->size(), true, true); } }
HRESULT STDMETHODCALLTYPE SkDWriteFontFileStreamWrapper::ReadFileFragment( void const** fragmentStart, UINT64 fileOffset, UINT64 fragmentSize, void** fragmentContext) { // The loader is responsible for doing a bounds check. UINT64 fileSize; this->GetFileSize(&fileSize); if (fileOffset > fileSize || fragmentSize > fileSize - fileOffset) { *fragmentStart = NULL; *fragmentContext = NULL; return E_FAIL; } if (!SkTFitsIn<size_t>(fileOffset + fragmentSize)) { return E_FAIL; } const void* data = fStream->getMemoryBase(); if (NULL != data) { *fragmentStart = static_cast<BYTE const*>(data) + static_cast<size_t>(fileOffset); *fragmentContext = NULL; } else { //May be called from multiple threads. SkAutoMutexAcquire ama(fStreamMutex); *fragmentStart = NULL; *fragmentContext = NULL; if (!fStream->rewind()) { return E_FAIL; } if (fStream->skip(static_cast<size_t>(fileOffset)) != fileOffset) { return E_FAIL; } SkAutoTMalloc<uint8_t> streamData(static_cast<size_t>(fragmentSize)); if (fStream->read(streamData.get(), static_cast<size_t>(fragmentSize)) != fragmentSize) { return E_FAIL; } *fragmentStart = streamData.get(); *fragmentContext = streamData.detach(); } return S_OK; }
static void TestPDFStream(skiatest::Reporter* reporter) { char streamBytes[] = "Test\nFoo\tBar"; SkAutoTDelete<SkMemoryStream> streamData(new SkMemoryStream( streamBytes, strlen(streamBytes), true)); SkAutoTUnref<SkPDFStream> stream(new SkPDFStream(streamData.get())); ASSERT_EMIT_EQ(reporter, *stream, "<</Length 12>> stream\nTest\nFoo\tBar\nendstream"); stream->insertInt("Attribute", 42); ASSERT_EMIT_EQ(reporter, *stream, "<</Length 12\n/Attribute 42>> stream\n" "Test\nFoo\tBar\nendstream"); { char streamBytes2[] = "This is a longer string, so that compression " "can do something with it. With shorter strings, " "the short circuit logic cuts in and we end up " "with an uncompressed string."; SkAutoDataUnref streamData2(SkData::NewWithCopy(streamBytes2, strlen(streamBytes2))); SkAutoTUnref<SkPDFStream> stream(new SkPDFStream(streamData2.get())); SkDynamicMemoryWStream compressedByteStream; SkDeflateWStream deflateWStream(&compressedByteStream); deflateWStream.write(streamBytes2, strlen(streamBytes2)); deflateWStream.finalize(); SkDynamicMemoryWStream expected; expected.writeText("<</Filter /FlateDecode\n/Length 116>> stream\n"); compressedByteStream.writeToStream(&expected); compressedByteStream.reset(); expected.writeText("\nendstream"); SkAutoDataUnref expectedResultData2(expected.copyToData()); SkString result = emit_to_string(*stream); ASSERT_EQL(reporter, result, (const char*)expectedResultData2->data(), expectedResultData2->size()); } }
/** Activates XMLterm and instantiates LineTerm; * called at the the end of Init page loading. */ NS_IMETHODIMP mozXMLTerminal::Activate(void) { nsresult result = NS_OK; #if 0 // TEMPORARY: Testing mozIXMLTermStream nsAutoString streamData( "<HTML><HEAD><TITLE>Stream Title</TITLE>" "<SCRIPT language='JavaScript'>" "function clik(){ dump('click\\n');return(false);}" "</SCRIPT></HEAD>" "<BODY><B>Stream Body " "<SPAN STYLE='color: blue' onClick='return clik();'>Clik</SPAN></B><BR>" "<TABLE WIDTH=720><TR><TD WIDTH=700 BGCOLOR=maroon> </TABLE>" "<BR>ABCD<BR>EFGH<BR>JKLM<BR>" "</BODY></HTML>" ); nsCOMPtr<mozIXMLTermStream> stream; result = NS_NewXMLTermStream(getter_AddRefs(stream)); if (NS_FAILED(result)) { XMLT_ERROR("mozXMLTerminal::Activate: Failed to create stream\n"); return result; } nsCOMPtr<nsIDocShell> docShell = do_QueryReferent(mDocShell); if (!docShell) return NS_ERROR_FAILURE; nsCOMPtr<nsIDOMWindowInternal> outerDOMWindow; result = mozXMLTermUtils::ConvertDocShellToDOMWindow(docShell, getter_AddRefs(outerDOMWindow)); if (NS_FAILED(result) || !outerDOMWindow) { XMLT_ERROR("mozXMLTerminal::Activate: Failed to convert docshell\n"); return NS_ERROR_FAILURE; } result = stream->Open(outerDOMWindow, "iframet", "chrome://dummy", "text/html", 800); if (NS_FAILED(result)) { XMLT_ERROR("mozXMLTerminal::Activate: Failed to open stream\n"); return result; } result = stream->Write(streamData.get()); if (NS_FAILED(result)) { XMLT_ERROR("mozXMLTerminal::Activate: Failed to write to stream\n"); return result; } result = stream->Close(); if (NS_FAILED(result)) { XMLT_ERROR("mozXMLTerminal::Activate: Failed to close stream\n"); return result; } #endif XMLT_LOG(mozXMLTerminal::Activate,20,("\n")); if (!mInitialized) return NS_ERROR_NOT_INITIALIZED; PR_ASSERT(mDocShell != nsnull); if ((mDOMDocument != nsnull) || (mPresShell != nsnull)) return NS_ERROR_FAILURE; nsCOMPtr<nsIDocShell> docShell = do_QueryReferent(mDocShell); if (!docShell) return NS_ERROR_FAILURE; // Get reference to presentation shell nsCOMPtr<nsPresContext> presContext; result = docShell->GetPresContext(getter_AddRefs(presContext)); if (NS_FAILED(result) || !presContext) return NS_ERROR_FAILURE; nsCOMPtr<nsIPresShell> presShell; result = docShell->GetPresShell(getter_AddRefs(presShell)); if (NS_FAILED(result) || !presShell) return NS_ERROR_FAILURE; // Get reference to DOMDocument nsIDocument *document = presShell->GetDocument(); if (!document) return NS_ERROR_FAILURE; nsCOMPtr<nsIDOMDocument> domDoc = do_QueryInterface(document); if (!domDoc) return NS_ERROR_FAILURE; // Save weak references to presentation shell and DOMDocument mPresShell = do_GetWeakReference(presShell); // weak ref mDOMDocument = do_GetWeakReference(domDoc); // weak ref // Show caret ShowCaret(); // Determine current screen dimensions PRInt32 nRows, nCols, xPixels, yPixels; result = ScreenSize(&nRows, &nCols, &xPixels, &yPixels); if (NS_FAILED(result)) return result; // The above call does not return the correct screen dimensions. // (because rendering is still in progress?) // As a workaround, explicitly set screen dimensions nRows = 24; nCols = 80; xPixels = 0; yPixels = 0; // Instantiate and initialize XMLTermSession object mXMLTermSession = new mozXMLTermSession(); if (!mXMLTermSession) { return NS_ERROR_OUT_OF_MEMORY; } result = mXMLTermSession->Init(this, presShell, domDoc, nRows, nCols); if (NS_FAILED(result)) { XMLT_WARNING("mozXMLTerminal::Activate: Warning - Failed to initialize XMLTermSession\n"); return NS_ERROR_FAILURE; } // Instantiate LineTerm XMLT_LOG(mozXMLTerminal::Activate,22, ("instantiating lineterm, nRows=%d, nCols=%d\n", nRows, nCols)); mLineTermAux = do_CreateInstance(MOZLINETERM_CONTRACTID, &result); if (NS_FAILED(result)) { XMLT_WARNING("mozXMLTerminal::Activate: Warning - Failed to instantiate LineTermAux\n"); return result; } // Open LineTerm to execute command // Non-owning reference to this; delete LineTerm before deleting self PRInt32 options = 0; XMLT_LOG(mozXMLTerminal::Activate,22,("Opening LineTerm\n")); nsCOMPtr<nsIObserver> anObserver = this; #ifdef NO_CALLBACK anObserver = nsnull; #endif nsAutoString cookie; result = mLineTermAux->OpenAux(mCommand.get(), mInitInput.get(), mPromptExpr.get(), options, LTERM_DETERMINE_PROCESS, nRows, nCols, xPixels, yPixels, domDoc, anObserver, cookie); if (NS_FAILED(result)) { XMLT_WARNING("mozXMLTerminal::Activate: Warning - Failed to open LineTermAux\n"); return result; } XMLT_LOG(mozXMLTerminal::Activate,22,("Opened LineTerm\n")); // Save cookie mCookie = cookie; // Get the DOM event receiver for document nsCOMPtr<nsIDOMEventReceiver> eventReceiver; result = domDoc->QueryInterface(NS_GET_IID(nsIDOMEventReceiver), getter_AddRefs(eventReceiver)); if (NS_FAILED(result)) { XMLT_WARNING("mozXMLTerminal::Activate: Warning - Failed to get DOM receiver\n"); return result; } // Create a key listener result = NS_NewXMLTermKeyListener(getter_AddRefs(mKeyListener), this); if (NS_OK != result) { XMLT_WARNING("mozXMLTerminal::Activate: Warning - Failed to get key listener\n"); return result; } // Register the key listener with the DOM event receiver result = eventReceiver->AddEventListenerByIID(mKeyListener, NS_GET_IID(nsIDOMKeyListener)); if (NS_FAILED(result)) { XMLT_WARNING("mozXMLTerminal::Activate: Warning - Failed to register key listener\n"); return result; } // Create a text listener result = NS_NewXMLTermTextListener(getter_AddRefs(mTextListener), this); if (NS_OK != result) { XMLT_WARNING("mozXMLTerminal::Activate: Warning - Failed to get text listener\n"); return result; } // Register the text listener with the DOM event receiver result = eventReceiver->AddEventListenerByIID(mTextListener, NS_GET_IID(nsIDOMTextListener)); if (NS_FAILED(result)) { XMLT_WARNING("mozXMLTerminal::Activate: Warning - Failed to register text listener\n"); return result; } // Create a mouse listener result = NS_NewXMLTermMouseListener(getter_AddRefs(mMouseListener), this); if (NS_OK != result) { XMLT_WARNING("mozXMLTerminal::Activate: Warning - Failed to get mouse listener\n"); return result; } // Register the mouse listener with the DOM event receiver result = eventReceiver->AddEventListenerByIID(mMouseListener, NS_GET_IID(nsIDOMMouseListener)); if (NS_FAILED(result)) { XMLT_WARNING("mozXMLTerminal::Activate: Warning - Failed to register mouse listener\n"); return result; } // Create a drag listener result = NS_NewXMLTermDragListener(getter_AddRefs(mDragListener), this); if (NS_OK != result) { XMLT_WARNING("mozXMLTerminal::Activate: Warning - Failed to get drag listener\n"); return result; } // Register the drag listener with the DOM event receiver result = eventReceiver->AddEventListenerByIID(mDragListener, NS_GET_IID(nsIDOMDragListener)); if (NS_FAILED(result)) { XMLT_WARNING("mozXMLTerminal::Activate: Warning - Failed to register drag listener\n"); return result; } return NS_OK; }
void TcpReassembly::checkOutOfOrderFragments(TcpReassemblyData* tcpReassemblyData, int sideIndex, bool cleanWholeFragList) { bool foundSomething = false; do { LOG_DEBUG("Starting first iteration of checkOutOfOrderFragments - looking for fragments that match the current sequence or have smaller sequence"); int index = 0; foundSomething = false; do { index = 0; foundSomething = false; // first fragment list iteration - go over the whole fragment list and see if can find fragments that match the current sequence // or have smaller sequence but have big enough payload to get new data while (index < (int)tcpReassemblyData->twoSides[sideIndex].tcpFragmentList.size()) { TcpFragment* curTcpFrag = tcpReassemblyData->twoSides[sideIndex].tcpFragmentList.at(index); // if fragment sequence matches the current sequence if (curTcpFrag->sequence == tcpReassemblyData->twoSides[sideIndex].sequence) { // update sequence tcpReassemblyData->twoSides[sideIndex].sequence += curTcpFrag->dataLength; if (curTcpFrag->data != NULL) { LOG_DEBUG("Found an out-of-order packet matching to the current sequence with size %d on side %d. Pulling it out of the list and sending the data to the callback", (int)curTcpFrag->dataLength, sideIndex); // send new data to callback if (m_OnMessageReadyCallback != NULL) { TcpStreamData streamData(curTcpFrag->data, curTcpFrag->dataLength, tcpReassemblyData->connData); streamData.setDeleteDataOnDestruction(false); m_OnMessageReadyCallback(sideIndex, streamData, m_UserCookie); } } // remove fragment from list tcpReassemblyData->twoSides[sideIndex].tcpFragmentList.erase(tcpReassemblyData->twoSides[sideIndex].tcpFragmentList.begin() + index); foundSomething = true; continue; } // if fragment sequence has lower sequence than the current sequence if (curTcpFrag->sequence < tcpReassemblyData->twoSides[sideIndex].sequence) { // check if it still has new data uint32_t newSequence = curTcpFrag->sequence + curTcpFrag->dataLength; // it has new data if (newSequence > tcpReassemblyData->twoSides[sideIndex].sequence) { // calculate the delta new data size uint32_t newLength = tcpReassemblyData->twoSides[sideIndex].sequence - curTcpFrag->sequence; LOG_DEBUG("Found a fragment in the out-of-order list which its sequence is lower than expected but its payload is long enough to contain new data. " "Calling the callback with the new data. Fragment size is %d on side %d, new data size is %d", (int)curTcpFrag->dataLength, sideIndex, (int)(curTcpFrag->dataLength - newLength)); // update current sequence with the delta new data size tcpReassemblyData->twoSides[sideIndex].sequence += curTcpFrag->dataLength - newLength; // send only the new data to the callback if (m_OnMessageReadyCallback != NULL) { TcpStreamData streamData(curTcpFrag->data + newLength, curTcpFrag->dataLength - newLength, tcpReassemblyData->connData); streamData.setDeleteDataOnDestruction(false); m_OnMessageReadyCallback(sideIndex, streamData, m_UserCookie); } foundSomething = true; } else { LOG_DEBUG("Found a fragment in the out-of-order list which doesn't contain any new data, ignoring it. Fragment size is %d on side %d", (int)curTcpFrag->dataLength, sideIndex); } // delete fragment from list tcpReassemblyData->twoSides[sideIndex].tcpFragmentList.erase(tcpReassemblyData->twoSides[sideIndex].tcpFragmentList.begin() + index); continue; } //if got to here it means the fragment has higher sequence than current sequence, increment index and continue index++; } // if managed to find new segment, do the search all over again } while (foundSomething); // if got here it means we're left only with fragments that have higher sequence than current sequence. This means out-of-order packets or // missing data. If we don't want to clear the frag list yet, assume it's out-of-order and return if (!cleanWholeFragList) return; LOG_DEBUG("Starting second iteration of checkOutOfOrderFragments - handle missing data"); // second fragment list iteration - now we're left only with fragments that have higher sequence than current sequence. This means missing data. // Search for the fragment with the closest sequence to the current one uint32_t closestSequence = 0xffffffff; int closestSequenceFragIndex = -1; index = 0; while (index < (int)tcpReassemblyData->twoSides[sideIndex].tcpFragmentList.size()) { // extract segment at current index TcpFragment* curTcpFrag = tcpReassemblyData->twoSides[sideIndex].tcpFragmentList.at(index); // check if its sequence is closer than current closest sequence if (curTcpFrag->sequence < closestSequence) { closestSequence = curTcpFrag->sequence; closestSequenceFragIndex = index; } index++; } // this means fragment list is not empty at this stage if (closestSequenceFragIndex > -1) { // get the fragment with the closest sequence TcpFragment* curTcpFrag = tcpReassemblyData->twoSides[sideIndex].tcpFragmentList.at(closestSequenceFragIndex); // calculate number of missing bytes uint32_t missingDataLen = curTcpFrag->sequence - tcpReassemblyData->twoSides[sideIndex].sequence; // update sequence tcpReassemblyData->twoSides[sideIndex].sequence = curTcpFrag->sequence + curTcpFrag->dataLength; if (curTcpFrag->data != NULL) { // send new data to callback if (m_OnMessageReadyCallback != NULL) { // prepare missing data text std::string missingDataTextStr = prepareMissingDataMessage(missingDataLen); // add missing data text to the data that will be sent to the callback. This means that the data will look something like: // "[xx bytes missing]<original_data>" size_t dataWithMissingDataTextLen = missingDataTextStr.length() + curTcpFrag->dataLength; uint8_t* dataWithMissingDataText = new uint8_t[dataWithMissingDataTextLen]; memcpy(dataWithMissingDataText, missingDataTextStr.c_str(), missingDataTextStr.length()); memcpy(dataWithMissingDataText + missingDataTextStr.length(), curTcpFrag->data, curTcpFrag->dataLength); //TcpStreamData streamData(curTcpFrag->data, curTcpFrag->dataLength, tcpReassemblyData->connData); //streamData.setDeleteDataOnDestruction(false); TcpStreamData streamData(dataWithMissingDataText, dataWithMissingDataTextLen, tcpReassemblyData->connData); m_OnMessageReadyCallback(sideIndex, streamData, m_UserCookie); LOG_DEBUG("Found missing data on side %d: %d byte are missing. Sending the closest fragment which is in size %d + missing text message which size is %d", sideIndex, missingDataLen, (int)curTcpFrag->dataLength, (int)missingDataTextStr.length()); } } // remove fragment from list tcpReassemblyData->twoSides[sideIndex].tcpFragmentList.erase(tcpReassemblyData->twoSides[sideIndex].tcpFragmentList.begin() + closestSequenceFragIndex); LOG_DEBUG("Calling checkOutOfOrderFragments again from the start"); // call the method again from the start to do the whole search again (both iterations). // the stop condition is when the list is empty (so closestSequenceFragIndex == -1) foundSomething = true; } } while (foundSomething); }
void TcpReassembly::reassemblePacket(Packet& tcpData) { // get IP layer Layer* ipLayer = NULL; if (tcpData.isPacketOfType(IPv4)) ipLayer = (Layer*)tcpData.getLayerOfType<IPv4Layer>(); else if (tcpData.isPacketOfType(IPv6)) ipLayer = (Layer*)tcpData.getLayerOfType<IPv6Layer>(); if (ipLayer == NULL) return; // Ignore non-TCP packets TcpLayer* tcpLayer = tcpData.getLayerOfType<TcpLayer>(); if (tcpLayer == NULL) return; // Ignore the packet if it's an ICMP packet that has a TCP layer // Several ICMP messages (like "destination unreachable") have TCP data as part of the ICMP message. // This is not real TCP data and packet can be ignored if (tcpData.isPacketOfType(ICMP)) { LOG_DEBUG("Packet is of type ICMP so TCP data is probably part of the ICMP message. Ignoring this packet"); return; } // calculate the TCP payload size size_t tcpPayloadSize = tcpLayer->getLayerPayloadSize(); // calculate if this packet has FIN or RST flags bool isFin = (tcpLayer->getTcpHeader()->finFlag == 1); bool isRst = (tcpLayer->getTcpHeader()->rstFlag == 1); bool isFinOrRst = isFin || isRst; // ignore ACK packets or TCP packets with no payload (except for SYN, FIN or RST packets which we'll later need) if (tcpPayloadSize == 0 && tcpLayer->getTcpHeader()->synFlag == 0 && !isFinOrRst) return; // if the actual TCP payload is smaller than the value written in IPV4's "total length" field then adjust tcpPayloadSize to avoid buffer overflow if (tcpLayer->getLayerPayloadSize() < tcpPayloadSize) { LOG_DEBUG("Got a packet where actual TCP payload size is smaller then the value written in IPv4's 'total length' header. Adjusting tcpPayloadSize to avoid buffer overflow"); tcpPayloadSize = tcpLayer->getLayerPayloadSize(); } TcpReassemblyData* tcpReassemblyData = NULL; // calculate flow key for this packet uint32_t flowKey = hash5Tuple(&tcpData); // if this packet belongs to a connection that was already closed (for example: data packet that comes after FIN), ignore it if (m_ClosedConnectionList.find(flowKey) != m_ClosedConnectionList.end()) { LOG_DEBUG("Ignoring packet of already closed flow [0x%X]", flowKey); return; } // calculate packet's source and dest IP address IPAddress* srcIP = NULL; IPAddress* dstIP = NULL; IPv4Address srcIP4Addr = IPv4Address::Zero; IPv6Address srcIP6Addr = IPv6Address::Zero; IPv4Address dstIP4Addr = IPv4Address::Zero; IPv6Address dstIP6Addr = IPv6Address::Zero; if (ipLayer->getProtocol() == IPv4) { srcIP4Addr = ((IPv4Layer*)ipLayer)->getSrcIpAddress(); srcIP = &srcIP4Addr; dstIP4Addr = ((IPv4Layer*)ipLayer)->getDstIpAddress(); dstIP = &dstIP4Addr; } else if (ipLayer->getProtocol() == IPv6) { srcIP6Addr = ((IPv6Layer*)ipLayer)->getSrcIpAddress(); srcIP = &srcIP6Addr; dstIP6Addr = ((IPv6Layer*)ipLayer)->getDstIpAddress(); dstIP = &dstIP6Addr; } // find the connection in the connection map std::map<uint32_t, TcpReassemblyData*>::iterator iter = m_ConnectionList.find(flowKey); if (iter == m_ConnectionList.end()) { // if it's a packet of a new connection, create a TcpReassemblyData object and add it to the active connection list tcpReassemblyData = new TcpReassemblyData(); tcpReassemblyData->connData.setSrcIpAddress(srcIP); tcpReassemblyData->connData.setDstIpAddress(dstIP); tcpReassemblyData->connData.srcPort = ntohs(tcpLayer->getTcpHeader()->portSrc); tcpReassemblyData->connData.dstPort = ntohs(tcpLayer->getTcpHeader()->portDst); tcpReassemblyData->connData.flowKey = flowKey; m_ConnectionList[flowKey] = tcpReassemblyData; m_ConnectionInfo.push_back(tcpReassemblyData->connData); // fire connection start callback if (m_OnConnStart != NULL) m_OnConnStart(tcpReassemblyData->connData, m_UserCookie); } else // connection already exists tcpReassemblyData = iter->second; int sideIndex = -1; bool first = false; // calculate packet's source port uint16_t srcPort = tcpLayer->getTcpHeader()->portSrc; // if this is a new connection and it's the first packet we see on that connection if (tcpReassemblyData->numOfSides == 0) { LOG_DEBUG("Setting side for new connection"); // open the first side of the connection, side index is 0 sideIndex = 0; tcpReassemblyData->twoSides[sideIndex].setSrcIP(srcIP); tcpReassemblyData->twoSides[sideIndex].srcPort = srcPort; tcpReassemblyData->numOfSides++; first = true; } // if there is already one side in this connection (which will be at side index 0) else if (tcpReassemblyData->numOfSides == 1) { // check if packet belongs to that side if (tcpReassemblyData->twoSides[0].srcIP->equals(srcIP) && tcpReassemblyData->twoSides[0].srcPort == srcPort) { sideIndex = 0; } else { // this means packet belong to the second side which doesn't yet exist. Open a second side with side index 1 LOG_DEBUG("Setting second side of a connection"); sideIndex = 1; tcpReassemblyData->twoSides[sideIndex].setSrcIP(srcIP); tcpReassemblyData->twoSides[sideIndex].srcPort = srcPort; tcpReassemblyData->numOfSides++; first = true; } } // if there are already 2 sides open for this connection else if (tcpReassemblyData->numOfSides == 2) { // check if packet matches side 0 if (tcpReassemblyData->twoSides[0].srcIP->equals(srcIP) && tcpReassemblyData->twoSides[0].srcPort == srcPort) { sideIndex = 0; } // check if packet matches side 1 else if (tcpReassemblyData->twoSides[1].srcIP->equals(srcIP) && tcpReassemblyData->twoSides[1].srcPort == srcPort) { sideIndex = 1; } // packet doesn't match either side. This case doesn't make sense but it's handled anyway. Packet will be ignored else { LOG_ERROR("Error occurred - packet doesn't match either side of the connection!!"); return; } } // there are more than 2 side - this case doesn't make sense and shouldn't happen, but handled anyway. Packet will be ignored else { LOG_ERROR("Error occurred - connection has more than 2 sides!!"); return; } // if this side already got FIN or RST packet before, ignore this packet as this side is considered closed if (tcpReassemblyData->twoSides[sideIndex].gotFinOrRst) { LOG_DEBUG("Got a packet after FIN or RST were already seen on this side (%d). Ignoring this packet", sideIndex); return; } // handle FIN/RST packets that don't contain additional TCP data if (isFinOrRst && tcpPayloadSize == 0) { LOG_DEBUG("Got FIN or RST packet without data on side %d", sideIndex); handleFinOrRst(tcpReassemblyData, sideIndex, flowKey); return; } // check if this packet contains data from a different side than the side seen before. // If this is the case then treat the out-of-order packet list as missing data and send them to the user (callback) together with an indication that some data was missing. // Why? because a new packet from the other side means the previous message was probably already received and a new message is starting. // In this case out-of-order packets are probably actually missing data // For example: let's assume these are HTTP messages. If we're seeing the first packet of a response this means the server has already received the full request and is now starting // to send the response. So if we still have out-of-order packets from the request it probably means that some packets were lost during the capture. So we don't expect the client to // continue sending packets of the previous request, so we'll treat the out-of-order packets as missing data // // I'm aware that there are edge cases where the situation I described above is not true, but at some point we must clean the out-of-order packet list to avoid memory leak. // I decided to do what Wireshark does and clean this list when starting to see a message from the other side if (!first && tcpPayloadSize > 0 && tcpReassemblyData->prevSide != -1 && tcpReassemblyData->prevSide != sideIndex && tcpReassemblyData->twoSides[tcpReassemblyData->prevSide].tcpFragmentList.size() > 0) { LOG_DEBUG("Seeing a first data packet from a different side. Previous side was %d, current side is %d", tcpReassemblyData->prevSide, sideIndex); checkOutOfOrderFragments(tcpReassemblyData, tcpReassemblyData->prevSide, true); } tcpReassemblyData->prevSide = sideIndex; // extract sequence value from packet uint32_t sequence = ntohl(tcpLayer->getTcpHeader()->sequenceNumber); // if it's the first packet we see on this side of the connection if (first) { LOG_DEBUG("First data from this side of the connection"); // set initial sequence tcpReassemblyData->twoSides[sideIndex].sequence = sequence + tcpPayloadSize; if (tcpLayer->getTcpHeader()->synFlag != 0) tcpReassemblyData->twoSides[sideIndex].sequence++; // send data to the callback if (tcpPayloadSize != 0 && m_OnMessageReadyCallback != NULL) { TcpStreamData streamData(tcpLayer->getLayerPayload(), tcpPayloadSize, tcpReassemblyData->connData); streamData.setDeleteDataOnDestruction(false); m_OnMessageReadyCallback(sideIndex, streamData, m_UserCookie); } // handle case where this packet is FIN or RST (although it's unlikely) if (isFinOrRst) handleFinOrRst(tcpReassemblyData, sideIndex, flowKey); // return - nothing else to do here return; } // if packet sequence is smaller than expected - this means that part or all of the TCP data is being re-transmitted if (sequence < tcpReassemblyData->twoSides[sideIndex].sequence) { LOG_DEBUG("Found new data with the sequence lower than expected"); // calculate the sequence after this packet to see if this TCP payload contains also new data uint32_t newSequence = sequence + tcpPayloadSize; // this means that some of payload is new if (newSequence > tcpReassemblyData->twoSides[sideIndex].sequence) { // calculate the size of the new data uint32_t newLength = tcpReassemblyData->twoSides[sideIndex].sequence - sequence; LOG_DEBUG("Although sequence is lower than expected payload is long enough to contain new data. Calling the callback with the new data"); // update the sequence for this side to include the new data that was seen tcpReassemblyData->twoSides[sideIndex].sequence += tcpPayloadSize - newLength; // send only the new data to the callback if (m_OnMessageReadyCallback != NULL) { TcpStreamData streamData(tcpLayer->getLayerPayload() + newLength, tcpPayloadSize - newLength, tcpReassemblyData->connData); streamData.setDeleteDataOnDestruction(false); m_OnMessageReadyCallback(sideIndex, streamData, m_UserCookie); } } // handle case where this packet is FIN or RST if (isFinOrRst) handleFinOrRst(tcpReassemblyData, sideIndex, flowKey); // return - nothing else to do here return; } // if packet sequence is exactly as expected - this is the "good" case and the most common one else if (sequence == tcpReassemblyData->twoSides[sideIndex].sequence) { // if TCP data size is 0 - nothing to do if (tcpPayloadSize == 0) { LOG_DEBUG("Payload length is 0, doing nothing"); // handle case where this packet is FIN or RST if (isFinOrRst) handleFinOrRst(tcpReassemblyData, sideIndex, flowKey); return; } LOG_DEBUG("Found new data with expected sequence. Calling the callback"); // update the sequence for this side to include TCP data from this packet tcpReassemblyData->twoSides[sideIndex].sequence += tcpPayloadSize; // if this is a SYN packet - add +1 to the sequence if (tcpLayer->getTcpHeader()->synFlag != 0) tcpReassemblyData->twoSides[sideIndex].sequence++; // send the data to the callback if (m_OnMessageReadyCallback != NULL) { TcpStreamData streamData(tcpLayer->getLayerPayload(), tcpPayloadSize, tcpReassemblyData->connData); streamData.setDeleteDataOnDestruction(false); m_OnMessageReadyCallback(sideIndex, streamData, m_UserCookie); } //while (checkOutOfOrderFragments(tcpReassemblyData, sideIndex)) {} // now that we've seen new data, go over the list of out-of-order packets and see if one or more of them fits now checkOutOfOrderFragments(tcpReassemblyData, sideIndex, false); // handle case where this packet is FIN or RST if (isFinOrRst) handleFinOrRst(tcpReassemblyData, sideIndex, flowKey); // return - nothing else to do here return; } // this case means sequence size of the packet is higher than expected which means the packet is out-of-order or some packets were lost (missing data). // we don't know which of the 2 cases it is at this point so we just add this data to the out-of-order packet list else { // if TCP data size is 0 - nothing to do if (tcpPayloadSize == 0) { LOG_DEBUG("Payload length is 0, doing nothing"); // handle case where this packet is FIN or RST if (isFinOrRst) handleFinOrRst(tcpReassemblyData, sideIndex, flowKey); return; } // create a new TcpFragment, copy the TCP data to it and add this packet to the the out-of-order packet list TcpFragment* newTcpFrag = new TcpFragment(); newTcpFrag->data = new uint8_t[tcpPayloadSize]; newTcpFrag->dataLength = tcpPayloadSize; newTcpFrag->sequence = sequence; memcpy(newTcpFrag->data, tcpLayer->getLayerPayload(), tcpPayloadSize); tcpReassemblyData->twoSides[sideIndex].tcpFragmentList.pushBack(newTcpFrag); LOG_DEBUG("Found out-of-order packet and added a new TCP fragment with size %d to the out-of-order list of side %d", (int)tcpPayloadSize, sideIndex); // handle case where this packet is FIN or RST if (isFinOrRst) { handleFinOrRst(tcpReassemblyData, sideIndex, flowKey); return; } } }