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 }