void HttpSocket::handleNewConnection() { DBUG; while (hasPendingConnections()) { QTcpSocket *socket = nextPendingConnection(); // prevent clients from sending too much data socket->setReadBufferSize(constMaxBuffer); static const QLatin1String constIpV6Prefix("::ffff:"); QString peer=socket->peerAddress().toString(); QString ifaceAddress=serverAddress().toString(); const bool hostOk=peer==ifaceAddress || peer==mpdAddr || peer==(constIpV6Prefix+mpdAddr) || peer==QLatin1String("127.0.0.1") || peer==(constIpV6Prefix+QLatin1String("127.0.0.1")); DBUG << "peer:" << peer << "mpd:" << mpdAddr << "iface:" << ifaceAddress << "ok:" << hostOk; if (!hostOk) { sendErrorResponse(socket, 400); socket->close(); DBUG << "Not from valid host"; return; } connect(socket, SIGNAL(readyRead()), this, SLOT(readClient())); connect(socket, SIGNAL(disconnected()), this, SLOT(discardClient())); } }
/* Function that is called whenever there is data ready to be processed. * This function should block until all data for the chunk has been read from * the device. */ void StreamChunker::next(QIODevice* device) { // Note: // The next() function is slowed down initially by allocating the // data chunks. // It is probably best therefore, when running the benchmark, to make sure // all chunks are allocated before the timing starts. QTcpSocket* socket = static_cast<QTcpSocket*>(device); quint64 totalBytesRead = 0; quint64 bytesRead = 0; // Header values. quint32 packetSize = 0; quint32 packetCounter = 0; quint32 packetTime = 0; qint32 numPackets = 0; qint32 reportInterval = 0; size_t headerSize = 3*sizeof(quint32) + 2*sizeof(qint32); // Read header values. while (isActive() && totalBytesRead != headerSize) { while (socket->bytesAvailable() < (qint64)(headerSize)) { socket->waitForReadyRead(-1); } bytesRead = socket->read((char*)&packetSize, (qint64)sizeof(quint32)); totalBytesRead+=bytesRead; bytesRead = socket->read((char*)&packetCounter, (qint64)sizeof(quint32)); totalBytesRead+=bytesRead; bytesRead = socket->read((char*)&packetTime, (qint64)sizeof(quint32)); totalBytesRead+=bytesRead; bytesRead = socket->read((char*)&numPackets, (qint64)sizeof(qint32)); totalBytesRead+=bytesRead; bytesRead = socket->read((char*)&reportInterval, (qint64)sizeof(qint32)); totalBytesRead+=bytesRead; } // // Writable chunks are obtained using the getDataStorage() method // using the the following priority: // // 1) A Pre-allocated chunk in the buffer that has already been served // and has been marked for reuse. // 2) Allocating a new chunk in the buffer if space allows. // 3) Overwriting the oldest chunk in the buffer that matches the space // requirements. // // If none of these conditions can be met, an invalid chunk is returned. // // If there are no usable chunks, i.e. the buffer is full we will // be overwriting chunks. #if 1 if (numUsableChunks(packetSize) == 0) { ++totalOverwriteCounter_; ++intervalOverwriteCounter_; } #endif // Ask the data manager for a writable data chunk and get its data pointer. pelican::WritableData chunk = getDataStorage(packetSize); // Check chunk->isValid() before proceeding! if (!chunk.isValid()) { QString error = "StreamChunker::next(): Unable to get a valid chunk. "; if (packetSize > maxChunkSize()) { error += QString( "\n== The requested packet size is greater than the maximum" "\n== chunk size allowed by the buffer."); } throw error; } // Extract the data pointer from the chunk char* chunkPtr = (char*)chunk.ptr(); // Write the header into the chunk. quint32* header1 = reinterpret_cast<quint32*>(chunkPtr); header1[0] = packetSize; header1[1] = packetCounter; header1[2] = packetTime; qint32* header2 = reinterpret_cast<qint32*>(chunkPtr+3*sizeof(quint32)); header2[0] = numPackets; header2[1] = reportInterval; // NOTE Setting the read buffer size may have an impact on performance. #if 0 socket->setReadBufferSize(2*1024*1024); #endif // NOTE The minimum read size has an impact on performance and has not // been optimised. quint64 minReadSize = 1024;//2*1024*1024; // bytes // Read data block directly into the chunk. quint64 dataRemaining = packetSize - headerSize; while (isActive() && dataRemaining > 0) { if (dataRemaining < minReadSize) minReadSize = dataRemaining; while (socket->bytesAvailable() < (qint64)minReadSize) { socket->waitForReadyRead(-1); } bytesRead = socket->read(chunkPtr+totalBytesRead, dataRemaining); totalBytesRead+=bytesRead; dataRemaining-=bytesRead; } chunkCounter_++; // Report performance if (chunkCounter_%reportInterval == 0) { const double B2MiB = 1.0/(1024.0*1024.0); int elapsed = timer_.elapsed(); size_t dataReceived = packetSize * reportInterval; size_t maxBufferSize_ = maxBufferSize(); size_t allocatedSize_ = allocatedSize(); size_t usedSize_ = usedSize(); size_t usableSize_ = usableSize(packetSize); // Buffer % full (how much of the buffer is in use as a %) double pBufferFull = ((maxBufferSize_-usableSize_)/(double)maxBufferSize_)*100.0; char prefix[10]; int l = (reportCounter_ < 10) ? 2 : ((reportCounter_ < 100) ? 1 : 0); sprintf(prefix, "S[%s%llu] ", string(l, '-').c_str(), reportCounter_); printf("%s\n", string(80,'*').c_str()); printf("%sTotal chunk count = %llu\n", prefix, chunkCounter_); printf("%sChunk size = %-7.3f MiB [%i B]\n", prefix, packetSize*B2MiB, packetSize); printf("%sTotal data received = %.1f MiB\n", prefix, (quint64)packetSize*chunkCounter_*B2MiB); printf("%s\n", prefix); printf("%sBuffer state:\n", prefix); printf("%s* Percent full = %.1f%%\n", prefix, pBufferFull); printf("%s* Total size = %-7.3f MiB [%lu B]\n", prefix, maxBufferSize_*B2MiB, maxBufferSize_); printf("%s* Allocated size = %-7.3f MiB [%lu B]\n", prefix, allocatedSize_*B2MiB, allocatedSize_); printf("%s* In use (active) = %-7.3f MiB [%lu B]\n", prefix, usedSize_*B2MiB, usedSize_); printf("%s* Usable space = %-7.3f MiB [%lu B]\n", prefix, usableSize_*B2MiB, usableSize_); printf("%s* Total chunks = %i\n", prefix, numChunks()); printf("%s* Active chunks = %i\n", prefix, numActiveChunks()); printf("%s* Expired chunks = %i\n", prefix, numExpiredChunks()); printf("%s* Usable chunks = %i\n", prefix, numUsableChunks(packetSize)); printf("%s* Overwritten chunks = %llu\n", prefix, totalOverwriteCounter_); printf("%s* Overwritten chunks = %i, %.1f%% (in report interval)\n", prefix, intervalOverwriteCounter_, (double)intervalOverwriteCounter_/reportInterval*100.0); printf("%s\n", prefix); printf("%sReport interval:\n", prefix); printf("%s* Chunks received = %i\n", prefix, reportInterval); printf("%s* Data received = %-7.3f MiB [%lu B] \n", prefix, dataReceived*B2MiB, dataReceived); printf("%s* Time taken = %.3f s\n", prefix, elapsed*1.0e-3); printf("%s* Data rate = ", prefix); if (elapsed > 0) printf("%-7.3f MiB/s\n", dataReceived*B2MiB/(elapsed*1.0e-3)); else printf("--- MiB/s\n"); printf("%s\n\n", string(80,'*').c_str()); fflush(stdout); reportCounter_++; intervalOverwriteCounter_ = 0; timer_.restart(); } }