/* */ #include "DHTRoutingTableDeserializer.h" #include #include #include #include #include #include "DHTNode.h" #include "DHTConstants.h" #include "bittorrent_helper.h" #include "DlAbortEx.h" #include "Logger.h" #include "a2netcompat.h" #include "StringFormat.h" #include "util.h" #include "array_fun.h" namespace aria2 { DHTRoutingTableDeserializer::DHTRoutingTableDeserializer() {} DHTRoutingTableDeserializer::~DHTRoutingTableDeserializer() {} static void readBytes(unsigned char* buf, size_t buflen, std::istream& in, size_t readlen) { assert(readlen <= buflen); in.read(reinterpret_cast(buf), readlen); } #define CHECK_STREAM(in, length) \ if(in.gcount() != length) { \ throw DL_ABORT_EX \ (StringFormat("Failed to load DHT routing table. cause:%s", \ "Unexpected EOF").str()); \ } \ if(!in) { \ throw DL_ABORT_EX \ (StringFormat("Failed to load DHT routing table. cause:%s", \ strerror(errno)).str()); \ } void DHTRoutingTableDeserializer::deserialize(std::istream& in) { char header[8]; memset(header, 0, sizeof(header)); // magic header[0] = 0xa1; header[1] = 0xa2; // format ID header[2] = 0x02; // version header[6] = 0; header[7] = 0x03; char headerCompat[8]; memset(headerCompat, 0, sizeof(headerCompat)); // magic headerCompat[0] = 0xa1; headerCompat[1] = 0xa2; // format ID headerCompat[2] = 0x02; // version headerCompat[6] = 0; headerCompat[7] = 0x02; char zero[8]; 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(buf, buf.size(), in, 8); CHECK_STREAM(in, 8); if(memcmp(header, buf, 8) == 0) { version = 3; } else if(memcmp(headerCompat, buf, 8) == 0) { version = 2; } else { throw DL_ABORT_EX (StringFormat("Failed to load DHT routing table. cause:%s", "bad header").str()); } uint32_t temp32; uint64_t temp64; // time if(version == 2) { in.read(reinterpret_cast(&temp32), sizeof(temp32)); CHECK_STREAM(in, sizeof(temp32)); serializedTime_.setTimeInSec(ntohl(temp32)); // 4bytes reserved readBytes(buf, buf.size(), in, 4); CHECK_STREAM(in, 4); } else { in.read(reinterpret_cast(&temp64), sizeof(temp64)); CHECK_STREAM(in, sizeof(temp64)); serializedTime_.setTimeInSec(ntoh64(temp64)); } // localnode // 8bytes reserved readBytes(buf, buf.size(), in, 8); CHECK_STREAM(in, 8); // localnode ID readBytes(buf, buf.size(), in, DHT_ID_LENGTH); CHECK_STREAM(in, DHT_ID_LENGTH); SharedHandle localNode(new DHTNode(buf)); // 4bytes reserved readBytes(buf, buf.size(), in, 4); CHECK_STREAM(in, 4); // number of nodes in.read(reinterpret_cast(&temp32), sizeof(temp32)); CHECK_STREAM(in, sizeof(temp32)); uint32_t numNodes = ntohl(temp32); // 4bytes reserved readBytes(buf, buf.size(), in, 4); CHECK_STREAM(in, 4); std::vector > nodes; // nodes for(size_t i = 0; i < numNodes; ++i) { // Currently, only IPv4 addresses are supported. // 1byte compact peer info length uint8_t peerInfoLen; in >> peerInfoLen; if(peerInfoLen != 6) { // skip this entry readBytes(buf, buf.size(), in, 42+7+6); CHECK_STREAM(in, 42+7+6); continue; } // 7bytes reserved readBytes(buf, buf.size(), in, 7); CHECK_STREAM(in, 7); // 6bytes compact peer info readBytes(buf, buf.size(), in, 6); CHECK_STREAM(in, 6); if(memcmp(zero, buf, 6) == 0) { // skip this entry readBytes(buf, buf.size(), in, 42); CHECK_STREAM(in, 42); continue; } // TODO DHT6 protocol family should be configurable. std::pair peer = bittorrent::unpackcompact(buf, AF_INET); if(peer.first.empty()) { // skip this entry readBytes(buf, buf.size(), in, 42); CHECK_STREAM(in, 42); continue; } // 2bytes reserved readBytes(buf, buf.size(), in, 2); CHECK_STREAM(in, 2); // 16byte reserved readBytes(buf, buf.size(), in, 16); CHECK_STREAM(in, 16); // node ID readBytes(buf, buf.size(), in, DHT_ID_LENGTH); CHECK_STREAM(in, DHT_ID_LENGTH); SharedHandle node(new DHTNode(buf)); node->setIPAddress(peer.first); node->setPort(peer.second); // 4bytes reserved readBytes(buf, buf.size(), in, 4); CHECK_STREAM(in, 4); nodes.push_back(node); } localNode_ = localNode; nodes_ = nodes; } } // namespace aria2