/* */ #include "DHTRoutingTableDeserializer.h" #include #include #include #include #include "DHTNode.h" #include "DHTConstants.h" #include "bittorrent_helper.h" #include "DlAbortEx.h" #include "Logger.h" #include "a2netcompat.h" #include "fmt.h" #include "util.h" #include "array_fun.h" #include "LogFactory.h" #include "BufferedFile.h" namespace aria2 { DHTRoutingTableDeserializer::DHTRoutingTableDeserializer(int family): family_(family) {} DHTRoutingTableDeserializer::~DHTRoutingTableDeserializer() {} #define READ_CHECK(fp, ptr, count) \ if(fp.read((ptr), (count)) != (count)) { \ throw DL_ABORT_EX("Failed to load DHT routing table."); \ } namespace { void readBytes(BufferedFile& fp, unsigned char* buf, size_t buflen, size_t readlen) { assert(readlen <= buflen); READ_CHECK(fp, buf, readlen); } } // namespace void DHTRoutingTableDeserializer::deserialize(const std::string& filename) { A2_LOG_INFO(fmt("Loading DHT routing table from %s.", filename.c_str())); BufferedFile fp(filename.c_str(), BufferedFile::READ); if(!fp) { throw DL_ABORT_EX(fmt("Failed to load DHT routing table from %s", filename.c_str())); } char header[8]; memset(header, 0, sizeof(header)); // magic header[0] = 0xa1u; header[1] = 0xa2u; // format ID header[2] = 0x02u; // version header[6] = 0; header[7] = 0x03u; char headerCompat[8]; memset(headerCompat, 0, sizeof(headerCompat)); // magic headerCompat[0] = 0xa1u; headerCompat[1] = 0xa2u; // format ID headerCompat[2] = 0x02u; // version headerCompat[6] = 0; headerCompat[7] = 0x02u; char zero[18]; memset(zero, 0, sizeof(zero)); int version; // If you change the code to read more than the size of buf, then // expand the buf size here. array_wrapper buf; // header readBytes(fp, buf, buf.size(), 8); if(memcmp(header, buf, 8) == 0) { version = 3; } else if(memcmp(headerCompat, buf, 8) == 0) { version = 2; } else { throw DL_ABORT_EX (fmt("Failed to load DHT routing table from %s. cause:%s", filename.c_str(), "bad header")); } uint32_t temp32; uint64_t temp64; // time if(version == 2) { READ_CHECK(fp, &temp32, sizeof(temp32)); serializedTime_.setTimeInSec(ntohl(temp32)); // 4bytes reserved readBytes(fp, buf, buf.size(), 4); } else { READ_CHECK(fp, &temp64, sizeof(temp64)); serializedTime_.setTimeInSec(ntoh64(temp64)); } // localnode // 8bytes reserved readBytes(fp, buf, buf.size(), 8); // localnode ID readBytes(fp, buf, buf.size(), DHT_ID_LENGTH); SharedHandle localNode(new DHTNode(buf)); // 4bytes reserved readBytes(fp, buf, buf.size(), 4); // number of nodes READ_CHECK(fp, &temp32, sizeof(temp32)); uint32_t numNodes = ntohl(temp32); // 4bytes reserved readBytes(fp, buf, buf.size(), 4); std::vector > nodes; // nodes const int compactlen = bittorrent::getCompactLength(family_); for(size_t i = 0; i < numNodes; ++i) { // 1byte compact peer info length uint8_t peerInfoLen; READ_CHECK(fp, &peerInfoLen, sizeof(peerInfoLen)); if(peerInfoLen != compactlen) { // skip this entry readBytes(fp, buf, buf.size(), 7+48); continue; } // 7bytes reserved readBytes(fp, buf, buf.size(), 7); // compactlen bytes compact peer info readBytes(fp, buf, buf.size(), compactlen); if(memcmp(zero, buf, compactlen) == 0) { // skip this entry readBytes(fp, buf, buf.size(), 48-compactlen); continue; } std::pair peer = bittorrent::unpackcompact(buf, family_); if(peer.first.empty()) { // skip this entry readBytes(fp, buf, buf.size(), 48-compactlen); continue; } // 24-compactlen bytes reserved readBytes(fp, buf, buf.size(), 24-compactlen); // node ID readBytes(fp, buf, buf.size(), DHT_ID_LENGTH); SharedHandle node(new DHTNode(buf)); node->setIPAddress(peer.first); node->setPort(peer.second); // 4bytes reserved readBytes(fp, buf, buf.size(), 4); nodes.push_back(node); } localNode_ = localNode; nodes_ = nodes; A2_LOG_INFO("DHT routing table was loaded successfully"); } } // namespace aria2