📄 peerwireclient.cpp
字号:
{ char buffer[1024]; qint64 totalRead = 0; do { qint64 bytesRead = QTcpSocket::readData(buffer, qMin<qint64>(sizeof(buffer), bytes - totalRead)); if (bytesRead <= 0) break; qint64 oldSize = incomingBuffer.size(); incomingBuffer.resize(oldSize + bytesRead); memcpy(incomingBuffer.data() + oldSize, buffer, bytesRead); totalRead += bytesRead; } while (totalRead < bytes); if (totalRead > 0) { downloadSpeedData[0] += totalRead; emit bytesReceived(totalRead); processIncomingData(); } return totalRead;}// Returns the average number of bytes per second this client is// downloading.qint64 PeerWireClient::downloadSpeed() const{ qint64 sum = 0; for (unsigned int i = 0; i < sizeof(downloadSpeedData) / sizeof(qint64); ++i) sum += downloadSpeedData[i]; return sum / (8 * 2);}// Returns the average number of bytes per second this client is// uploading.qint64 PeerWireClient::uploadSpeed() const{ qint64 sum = 0; for (unsigned int i = 0; i < sizeof(uploadSpeedData) / sizeof(qint64); ++i) sum += uploadSpeedData[i]; return sum / (8 * 2);}bool PeerWireClient::canTransferMore() const{ return !incomingBuffer.isEmpty() || QTcpSocket::bytesAvailable() > 0 || !outgoingBuffer.isEmpty() || !pendingBlocks.isEmpty();}void PeerWireClient::timerEvent(QTimerEvent *event){ if (event->timerId() == transferSpeedTimer) { // Rotate the upload / download records. for (int i = 6; i >= 0; --i) { uploadSpeedData[i + 1] = uploadSpeedData[i]; downloadSpeedData[i + 1] = downloadSpeedData[i]; } uploadSpeedData[0] = 0; downloadSpeedData[0] = 0; } else if (event->timerId() == timeoutTimer) { // Disconnect if we timed out; otherwise the timeout is // restarted. if (invalidateTimeout) { invalidateTimeout = false; } else { abort(); } } else if (event->timerId() == pendingRequestTimer) { abort(); } else if (event->timerId() == keepAliveTimer) { sendKeepAlive(); } QTcpSocket::timerEvent(event);}// Sends the handshake to the peer.void PeerWireClient::sendHandShake(){ sentHandShake = true; // Restart the timeout if (timeoutTimer) killTimer(timeoutTimer); timeoutTimer = startTimer(ClientTimeout); // Write the 68 byte PeerWire handshake. write(&ProtocolIdSize, 1); write(ProtocolId, ProtocolIdSize); write(QByteArray(8, '\0')); write(infoHash); write(peerIdString);}void PeerWireClient::processIncomingData(){ invalidateTimeout = true; if (!receivedHandShake) { // Check that we received enough data if (incomingBuffer.size() < MinimalHeaderSize) return; // Sanity check the protocol ID QByteArray id = read(ProtocolIdSize + 1); if (id.at(0) != ProtocolIdSize || !id.mid(1).startsWith(ProtocolId)) { abort(); return; } // Discard 8 reserved bytes, then read the info hash and peer ID (void) read(8); // Read infoHash QByteArray peerInfoHash = read(20); if (!infoHash.isEmpty() && peerInfoHash != infoHash) { abort(); return; } emit infoHashReceived(peerInfoHash); if (infoHash.isEmpty()) { abort(); return; } // Send handshake if (!sentHandShake) sendHandShake(); receivedHandShake = true; } // Handle delayed peer id arrival if (!gotPeerId) { if (incomingBuffer.size() < 20) return; gotPeerId = true; if (read(20) == peerIdString) { // We connected to ourself abort(); return; } } // Initialize keep-alive timer if (!keepAliveTimer) keepAliveTimer = startTimer(KeepAliveInterval); do { // Find the packet length if (nextPacketLength == -1) { if (incomingBuffer.size() < 4) return; char tmp[4]; read(tmp, sizeof(tmp)); nextPacketLength = fromNetworkData(tmp); if (nextPacketLength < 0 || nextPacketLength > 200000) { // Prevent DoS abort(); return; } } // KeepAlive if (nextPacketLength == 0) { nextPacketLength = -1; continue; } // Wait with parsing until the whole packet has been received if (incomingBuffer.size() < nextPacketLength) return; // Read the packet QByteArray packet = read(nextPacketLength); if (packet.size() != nextPacketLength) { abort(); return; } switch (packet.at(0)) { case ChokePacket: // We have been choked. pwState |= ChokedByPeer; incoming.clear(); if (pendingRequestTimer) killTimer(pendingRequestTimer); emit choked(); break; case UnchokePacket: // We have been unchoked. pwState &= ~ChokedByPeer; emit unchoked(); break; case InterestedPacket: // The peer is interested in downloading. pwState |= PeerIsInterested; emit interested(); break; case NotInterestedPacket: // The peer is not interested in downloading. pwState &= ~PeerIsInterested; emit notInterested(); break; case HavePacket: { // The peer has a new piece available. quint32 index = fromNetworkData(&packet.data()[1]); if (index < quint32(peerPieces.size())) { // Only accept indexes within the valid range. peerPieces.setBit(int(index)); } emit piecesAvailable(availablePieces()); break; } case BitFieldPacket: // The peer has the following pieces available. for (int i = 1; i < packet.size(); ++i) { for (int bit = 0; bit < 8; ++bit) { if (packet.at(i) & (1 << (7 - bit))) { int bitIndex = int(((i - 1) * 8) + bit); if (bitIndex >= 0 && bitIndex < peerPieces.size()) { // Occasionally, broken clients claim to have // pieces whose index is outside the valid range. // The most common mistake is the index == size // case. peerPieces.setBit(bitIndex); } } } } emit piecesAvailable(availablePieces()); break; case RequestPacket: { // The peer requests a block. quint32 index = fromNetworkData(&packet.data()[1]); quint32 begin = fromNetworkData(&packet.data()[5]); quint32 length = fromNetworkData(&packet.data()[9]); emit blockRequested(int(index), int(begin), int(length)); break; } case PiecePacket: { int index = int(fromNetworkData(&packet.data()[1])); int begin = int(fromNetworkData(&packet.data()[5])); incoming.removeAll(TorrentBlock(index, begin, packet.size() - 9)); // The peer sends a block. emit blockReceived(index, begin, packet.mid(9)); // Kill the pending block timer. if (pendingRequestTimer) { killTimer(pendingRequestTimer); pendingRequestTimer = 0; } break; } case CancelPacket: { // The peer cancels a block request. quint32 index = fromNetworkData(&packet.data()[1]); quint32 begin = fromNetworkData(&packet.data()[5]); quint32 length = fromNetworkData(&packet.data()[9]); for (int i = 0; i < pendingBlocks.size(); ++i) { const BlockInfo &blockInfo = pendingBlocks.at(i); if (blockInfo.pieceIndex == int(index) && blockInfo.offset == int(begin) && blockInfo.length == int(length)) { pendingBlocks.removeAt(i); break; } } break; } default: // Unsupported packet type; just ignore it. break; } nextPacketLength = -1; } while (incomingBuffer.size() > 0);}qint64 PeerWireClient::readData(char *data, qint64 size){ int n = qMin<int>(size, incomingBuffer.size()); memcpy(data, incomingBuffer.constData(), n); incomingBuffer.remove(0, n); return n;}qint64 PeerWireClient::readLineData(char *data, qint64 maxlen){ return QIODevice::readLineData(data, maxlen);}qint64 PeerWireClient::writeData(const char *data, qint64 size){ int oldSize = outgoingBuffer.size(); outgoingBuffer.resize(oldSize + size); memcpy(outgoingBuffer.data() + oldSize, data, size); emit readyToTransfer(); return size;}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -