File indexing completed on 2025-01-05 04:37:23

0001 /*
0002     SPDX-FileCopyrightText: 2005 Joris Guisson <joris.guisson@gmail.com>
0003 
0004     SPDX-License-Identifier: GPL-2.0-or-later
0005 */
0006 #include "utpex.h"
0007 
0008 #include "peer.h"
0009 #include "peermanager.h"
0010 #include <bcodec/bdecoder.h>
0011 #include <bcodec/bencoder.h>
0012 #include <bcodec/bnode.h>
0013 #include <net/address.h>
0014 #include <util/functions.h>
0015 #include <util/log.h>
0016 
0017 namespace bt
0018 {
0019 bool UTPex::pex_enabled = true;
0020 
0021 UTPex::UTPex(Peer *peer, Uint32 id)
0022     : PeerProtocolExtension(id, peer)
0023     , last_updated(0)
0024 {
0025 }
0026 
0027 UTPex::~UTPex()
0028 {
0029 }
0030 
0031 void UTPex::handlePacket(const Uint8 *packet, Uint32 size)
0032 {
0033     if (size <= 2 || packet[1] != 1)
0034         return;
0035 
0036     QByteArray tmp = QByteArray::fromRawData((const char *)packet, size);
0037     BNode *node = nullptr;
0038     try {
0039         BDecoder dec(tmp, false, 2);
0040         node = dec.decode();
0041         if (node && node->getType() == BNode::DICT) {
0042             BDictNode *dict = (BDictNode *)node;
0043 
0044             // ut_pex packet, emit signal to notify PeerManager
0045             BValueNode *val = dict->getValue("added");
0046             if (val) {
0047                 QByteArray data = val->data().toByteArray();
0048                 peer->emitPex(data);
0049             }
0050         }
0051     } catch (...) {
0052         // just ignore invalid packets
0053         Out(SYS_CON | LOG_DEBUG) << "Invalid ut_pex packet" << endl;
0054     }
0055     delete node;
0056 }
0057 
0058 bool UTPex::needsUpdate() const
0059 {
0060     return bt::CurrentTime() - last_updated >= 60 * 1000;
0061 }
0062 
0063 void UTPex::visit(const bt::Peer::Ptr p)
0064 {
0065     if (p.data() != peer) {
0066         npeers.insert(std::make_pair(p->getID(), p->getAddress()));
0067         if (peers.count(p->getID()) == 0) {
0068             // new one, add to added
0069             added.insert(std::make_pair(p->getID(), p->getAddress()));
0070 
0071             if (p->getAddress().ipVersion() == 4) {
0072                 Uint8 flag = 0;
0073                 if (p->isSeeder())
0074                     flag |= 0x02;
0075                 if (p->getStats().fast_extensions)
0076                     flag |= 0x01;
0077                 flags.insert(std::make_pair(p->getID(), flag));
0078             }
0079         } else {
0080             // erase from old list, so only the dropped ones are left
0081             peers.erase(p->getID());
0082         }
0083     }
0084 }
0085 
0086 void UTPex::update()
0087 {
0088     PeerManager *pman = peer->getPeerManager();
0089     last_updated = bt::CurrentTime();
0090 
0091     pman->visit(*this);
0092 
0093     if (!(peers.size() == 0 && added.size() == 0)) {
0094         // encode the whole lot
0095         QByteArray data;
0096         BEncoder enc(new BEncoderBufferOutput(data));
0097         enc.beginDict();
0098         enc.write(QByteArrayLiteral("added"));
0099         encode(enc, added);
0100         enc.write(QByteArrayLiteral("added.f"));
0101         if (added.size() == 0) {
0102             enc.write(QByteArray());
0103         } else {
0104             encodeFlags(enc, flags);
0105         }
0106         enc.write(QByteArrayLiteral("dropped"));
0107         encode(enc, peers);
0108         enc.end();
0109 
0110         peer->sendExtProtMsg(id, data);
0111     }
0112 
0113     peers = npeers;
0114     added.clear();
0115     flags.clear();
0116     npeers.clear();
0117 }
0118 
0119 void UTPex::encode(BEncoder &enc, const std::map<Uint32, net::Address> &ps)
0120 {
0121     if (ps.size() == 0) {
0122         enc.write(QByteArray());
0123         return;
0124     }
0125 
0126     Uint8 *buf = new Uint8[ps.size() * 6];
0127     Uint32 size = 0;
0128 
0129     std::map<Uint32, net::Address>::const_iterator i = ps.begin();
0130     while (i != ps.end()) {
0131         const net::Address &addr = i->second;
0132         if (addr.ipVersion() == 4) {
0133             quint32 ip = htonl(addr.toIPv4Address());
0134             memcpy(buf + size, &ip, 4);
0135             WriteUint16(buf, size + 4, addr.port());
0136             size += 6;
0137         }
0138         ++i;
0139     }
0140 
0141     enc.write(buf, size);
0142     delete[] buf;
0143 }
0144 
0145 void UTPex::encodeFlags(BEncoder &enc, const std::map<Uint32, Uint8> &flags)
0146 {
0147     if (flags.size() == 0) {
0148         enc.write(QByteArray());
0149         return;
0150     }
0151 
0152     Uint8 *buf = new Uint8[flags.size()];
0153     Uint32 idx = 0;
0154 
0155     std::map<Uint32, Uint8>::const_iterator i = flags.begin();
0156     while (i != flags.end()) {
0157         buf[idx++] = i->second;
0158         ++i;
0159     }
0160 
0161     enc.write(buf, flags.size());
0162     delete[] buf;
0163 }
0164 }