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 }