File indexing completed on 2025-01-05 04:37:23
0001 /* 0002 SPDX-FileCopyrightText: 2009 Joris Guisson <joris.guisson@gmail.com> 0003 0004 SPDX-License-Identifier: GPL-2.0-or-later 0005 */ 0006 0007 #include "utmetadata.h" 0008 #include "peer.h" 0009 #include <QByteArray> 0010 #include <bcodec/bdecoder.h> 0011 #include <bcodec/bencoder.h> 0012 #include <bcodec/bnode.h> 0013 #include <magnet/metadatadownload.h> 0014 #include <torrent/torrent.h> 0015 #include <util/log.h> 0016 0017 namespace bt 0018 { 0019 UTMetaData::UTMetaData(const Torrent &tor, bt::Uint32 id, Peer *peer) 0020 : PeerProtocolExtension(id, peer) 0021 , tor(tor) 0022 , reported_metadata_size(0) 0023 , download(nullptr) 0024 { 0025 } 0026 0027 UTMetaData::~UTMetaData() 0028 { 0029 } 0030 0031 void UTMetaData::handlePacket(const bt::Uint8 *packet, Uint32 size) 0032 { 0033 QByteArray tmp = QByteArray::fromRawData((const char *)packet, size); 0034 BNode *node = nullptr; 0035 try { 0036 BDecoder dec(tmp, false, 2); 0037 node = dec.decode(); 0038 if (!node || node->getType() != BNode::DICT) { 0039 delete node; 0040 return; 0041 } 0042 0043 BDictNode *dict = (BDictNode *)node; 0044 int type = dict->getInt(QByteArrayLiteral("msg_type")); 0045 switch (type) { 0046 case 0: // request 0047 request(dict); 0048 break; 0049 case 1: { // data 0050 data(dict, tmp.mid(dec.position())); 0051 break; 0052 } 0053 case 2: // reject 0054 reject(dict); 0055 break; 0056 } 0057 } catch (...) { 0058 Out(SYS_CON | LOG_DEBUG) << "Invalid metadata packet" << endl; 0059 } 0060 delete node; 0061 } 0062 0063 void UTMetaData::data(BDictNode *dict, const QByteArray &piece_data) 0064 { 0065 if (download) { 0066 if (download->data(dict->getInt(QByteArrayLiteral("piece")), piece_data)) { 0067 peer->emitMetadataDownloaded(download->result()); 0068 } 0069 } 0070 } 0071 0072 void UTMetaData::reject(BDictNode *dict) 0073 { 0074 if (download) 0075 download->reject(dict->getInt(QByteArrayLiteral("piece"))); 0076 } 0077 0078 void UTMetaData::request(BDictNode *dict) 0079 { 0080 int piece = dict->getInt(QByteArrayLiteral("piece")); 0081 Out(SYS_CON | LOG_DEBUG) << "Received request for metadata piece " << piece << endl; 0082 if (!tor.isLoaded()) { 0083 sendReject(piece); 0084 return; 0085 } 0086 0087 const QByteArray &md = tor.getMetaData(); 0088 int num_pieces = md.size() / METADATA_PIECE_SIZE + (md.size() % METADATA_PIECE_SIZE == 0 ? 0 : 1); 0089 if (piece < 0 || piece >= num_pieces) { 0090 sendReject(piece); 0091 return; 0092 } 0093 0094 int off = piece * METADATA_PIECE_SIZE; 0095 int last_len = (md.size() % METADATA_PIECE_SIZE == 0) ? METADATA_PIECE_SIZE : (md.size() % METADATA_PIECE_SIZE); 0096 int len = piece == num_pieces - 1 ? last_len : METADATA_PIECE_SIZE; 0097 sendData(piece, md.size(), md.mid(off, len)); 0098 } 0099 0100 void UTMetaData::sendReject(int piece) 0101 { 0102 QByteArray data; 0103 BEncoder enc(new BEncoderBufferOutput(data)); 0104 enc.beginDict(); 0105 enc.write(QByteArrayLiteral("msg_type")); 0106 enc.write((bt::Uint32)2); 0107 enc.write(QByteArrayLiteral("piece")); 0108 enc.write((bt::Uint32)piece); 0109 enc.end(); 0110 sendPacket(data); 0111 } 0112 0113 void UTMetaData::sendData(int piece, int total_size, const QByteArray &data) 0114 { 0115 Out(SYS_CON | LOG_DEBUG) << "Sending metadata piece " << piece << endl; 0116 QByteArray tmp; 0117 BEncoder enc(new BEncoderBufferOutput(tmp)); 0118 enc.beginDict(); 0119 enc.write(QByteArrayLiteral("msg_type")); 0120 enc.write((bt::Uint32)1); 0121 enc.write(QByteArrayLiteral("piece")); 0122 enc.write((bt::Uint32)piece); 0123 enc.write(QByteArrayLiteral("total_size")); 0124 enc.write((bt::Uint32)total_size); 0125 enc.end(); 0126 tmp.append(data); 0127 sendPacket(tmp); 0128 } 0129 0130 void UTMetaData::setReportedMetadataSize(Uint32 metadata_size) 0131 { 0132 reported_metadata_size = metadata_size; 0133 if (reported_metadata_size > 0 && !tor.isLoaded() && !download) { 0134 download = new MetadataDownload(this, reported_metadata_size); 0135 } 0136 } 0137 0138 }