void ClientStats::dump(std::ostream& os) const { // TODO: write client start date/time. const auto currentTime = getTimeStampMS(); os << "Runtime: " << ((currentTime - startTime) / 1000) << "s" << "\n" << "Potential runtime: " << ((potentialEndTime - startTime) / 1000 / 60) << "min" << "\n" << "CPU core: " << cpuCore << "\n" << "Replay speed: " << replaySpeed << "\n" << "Replays planned: " << replaysPlanned << "\n" << "Replays done: " << replaysDone << "\n" << "Meta directory: " << metaDir << "\n" << "Content types: "; for (const auto& ct : contentTypes) { os << ct << " "; } os << "\n" << "Files available: " << filesAvailable << "\n" << "Unique timestamps: " << uniqueTimestamps << "\n" << "Sleep time: " << (sleepTime / 1000) << "s" << "\n" << "Too late time: " << (tooLateTime / 1000) << "s" << "\n" << "Connections: " << connections << "\n" << "Files requested: " << filesRequested << "\n" << "Bytes sent: " << bytesSent << "\n" << "Bytes received: " << bytesReceived << "\n" << "Payload received: " << payloadReceived << "\n" << "Payload decompressed: " << bytesDecompressedPayload << "\n" << "Decompression time: " << (decompressionTimeUs / 1000) << "ms\n" << "Checksum time: " << (checksumTimeUs / 1000) << "ms" << std::endl; }
void TCPReassembler::purgeOld() { // for better performance, only call every x packets static uint32_t cnt = 0; if (++cnt < 64) {return;} cnt = 0; uint64_t curTs = getTimeStampMS(); auto stream = streams.begin(); while (stream != streams.end()) { uint64_t inactivity = curTs - stream->second->lastActivityTs; if (inactivity > timeoutMs) { auto toDelete = stream; ++stream; closeStream(toDelete->second); ++stats.numPurgedConnections; } else { ++stream; } } }
void TCPReassembler::onIPv4Packet(PacketIPv4* pkt) { // sanity checks assertNotNull(conListener, "set a connection-listener first before using the TCP-Reassembler!"); // silently ignore non tcp packets if (!pkt->containsTCP()) { error(DBG_TCP, "got non-TCP packet!!!"); return; } ++stats.global.numPackets; // get the TCP-Packet PacketTCP* tcp = pkt->getTCP(); // the ID will be created using both ports and IPs // the ID will thus be the same for BOTH directions!! // we store the local-port to distinguish between incoming and outgoing later const uint64_t ipSUM = (uint64_t)pkt->getDstIP() + (uint64_t)pkt->getSrcIP(); const uint64_t portSUM = (uint64_t)pkt->getTCP()->getSrcPort() + (uint64_t)pkt->getTCP()->getDstPort(); const uint64_t id = (ipSUM << 24) + portSUM; // the TCP-Stream (directional) all following functions will use TCPStream* stream = nullptr; // if this is a SYN packet (without ACK) // we have found a new connection-request if (tcp->isSyn() && !tcp->isAck()) { // sanity check. // there MUST NOT be a stream with this ID! // FIXME better solution to avoid collisions? if (streams.find(id) != streams.end()) { ++stats.numIDCollision; debug(DBG_TCP, DBG_LVL_ERR, "new connection but ID already in use -> skipping"); // we also need to close the connection with the existing ID // otherwise the traffic of both connection would be miked and lead to further problems! closeStream(streams[id]); return; } //assertTrue( streams.find(id) == streams.end(), "TCP id collision detected!" ); ++stats.numConnections; ++stats.numOpenConnections; ++stats.fromInitiator.numPackets; debug(DBG_TCP, DBG_LVL_INFO, "new connection with ID " << id << " (open connections: " << stats.numOpenConnections << ")"); // create a new stream for this connection stream = new TCPStream(); stream->id = id; // store the stream streams[id] = stream; // store the local port (= dst-port) the connection was accepted on, // to distinguish between incoming and outgoing later stream->localPort = tcp->getDstPort(); // set first sequence number stream->fromInitiator.nextSeqNumber = tcp->getSeqNumber(); // call the connection listener. // this listener MUST return a TCPStreamListener which will receive the data-flow stream->listener = conListener->onTCPAccepted(tcp->getDstPort()); // debug assertions assertNotNull(stream->listener, "the listener of the TCP-Stream has not been set. Is the TcpConnectionListener working correctly?"); // inform the stream-listener stream->listener->onOpen(); } else if (tcp->isSyn() && tcp->isAck()) { ++stats.toInitiator.numPackets; // proceed with existing streams only if (streams.find(id) == streams.end()) { ++stats.numPacketsIgnored; debug(DBG_TCP, DBG_LVL_WARN, "unknown connection ID (in SYN-ACK) -> skipping"); return; } // get stream by it's id stream = streams[id]; // set fist sequence number stream->toInitiator.nextSeqNumber = tcp->getSeqNumber(); } else { // proceed with existing streams only if (streams.find(id) == streams.end()) { ++stats.numPacketsIgnored; debug(DBG_TCP, DBG_LVL_WARN, "unknown connection ID -> skipping"); return; } // get the stream by it's id stream = streams[id]; } // we should only be here if everything is fine // update timestamp for timeout detection stream->lastActivityTs = getTimeStampMS(); // get stream's direction (from initiator / to initiator) bool isFromInitiator = tcp->getDstPort() == stream->localPort; TCPReassemblerDirStats* dirStats = (isFromInitiator) ? (&stats.fromInitiator) : (&stats.toInitiator); ++dirStats->numPackets; // get the stream behind this direction TCPStreamDirection* streamDir = (isFromInitiator) ? (&stream->fromInitiator) : (&stream->toInitiator); // get the payload of this packet Payload payload = pkt->getTCP()->getPayload(pkt->getPayloadLength()); stats.global.avgPayloadEmptySize.add(payload.length); dirStats->avgPayloadEmptySize.add(payload.length); // if we have a payload, reassemble and pass it to the listener if (payload.length != 0) { stats.global.avgPayloadSize.add(payload.length); dirStats->avgPayloadSize.add(payload.length); stats.global.sizePayload += payload.length; dirStats->sizePayload += payload.length; // syn with payload? if (tcp->isSyn()) { ++stats.global.numSynPayload; ++dirStats->numSynPayload; } // check and perform re-assembly bool ret = reAssemble(*streamDir, tcp->getSeqNumber(), payload, stream->listener); // reassembly failed? -> close stream if (!ret) {closeStream(stream); return;} } else { // adjust statistics ++stats.global.numWithoutPayload; ++dirStats->numWithoutPayload; if (tcp->getFlags() == TCP_FLAG_ACK) { ++stats.global.numAckOnly; ++dirStats->numAckOnly; } } // SYN-flag will increment seq-number by 1 if (tcp->isSyn()) {++streamDir->nextSeqNumber;} // track number of FIN packets if (tcp->isFin()) { ++stream->numFIN; } // if we have a 2xFIN or 1xRST flag, then close the stream // TODO (the ACK after the 2nd FIN will be added to "ignoredPacket" stats as the connection is already closed) if (stream->numFIN == 2 || tcp->isReset()) { debug(DBG_TCP, DBG_LVL_INFO, "connection closed: " << id); closeStream(stream); } // purge old connections that probably timed out purgeOld(); }
void tarch::logging::Log::error(const std::string& methodName, const std::string& message) const { UsedLogService::getInstance().error(getTimeStampMS(),getTimeStampHumanReadable(),getMachineInformation(),getTraceInformation(methodName),message); }
HTTPHeader::HTTPHeader() : method(0), code(0), length(0) { timestamp = getTimeStampMS(); }