Files
opendht/include/dhtcpp/infohash.h
T
2014-11-20 01:42:44 -05:00

160 lines
4.7 KiB
C++

/*
* Copyright (C) 2014 Savoir-Faire Linux Inc.
* Author : Adrien Béraud <adrien.beraud@savoirfairelinux.com>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Additional permission under GNU GPL version 3 section 7:
*
* If you modify this program, or any covered work, by linking or
* combining it with the OpenSSL project's OpenSSL library (or a
* modified version of that library), containing parts covered by the
* terms of the OpenSSL or SSLeay licenses, Savoir-Faire Linux Inc.
* grants you additional permission to convey the resulting work.
* Corresponding Source for a non-source form of such a combination
* shall include the source code for the parts of OpenSSL used as well
* as that of the covered work.
*/
#pragma once
#include <iostream>
#include <iomanip>
#include <array>
#include <vector>
#include <cstring>
// bytes
#define HASH_LEN 20
namespace dht {
class DhtException : public std::runtime_error {
public:
DhtException(const std::string &str = "") :
std::runtime_error("DhtException occured: " + str) {}
};
/**
* Represents an InfoHash.
* An InfoHash is a byte array of HASH_LEN bytes.
* InfoHashes identify nodes and values in the Dht.
*/
class InfoHash final : public std::array<uint8_t, HASH_LEN> {
public:
constexpr InfoHash() : std::array<uint8_t, HASH_LEN>() {}
constexpr InfoHash(const std::array<uint8_t, HASH_LEN>& h) : std::array<uint8_t, HASH_LEN>(h) {}
InfoHash(const uint8_t* h, size_t h_len=HASH_LEN) : std::array<uint8_t, HASH_LEN>() {
memcpy(data(), h, std::min((size_t)HASH_LEN, h_len));
}
/**
* Constructor from an hexadecimal string (without "0x").
* hex must be at least 2.HASH_LEN characters long.
* If too long, only the first 2.HASH_LEN characters are read.
*/
InfoHash(const std::string& hex);
/**
* Find the lowest 1 bit in an id.
* Result will allways be lower than 8*HASH_LEN
*/
inline unsigned lowbit() const {
int i, j;
for(i = HASH_LEN-1; i >= 0; i--)
if((*this)[i] != 0)
break;
if(i < 0)
return -1;
for(j = 7; j >= 0; j--)
if(((*this)[i] & (0x80 >> j)) != 0)
break;
return 8 * i + j;
}
/**
* Forget about the ``XOR-metric''. An id is just a path from the
* root of the tree, so bits are numbered from the start.
*/
static inline int cmp(const InfoHash& __restrict__ id1, const InfoHash& __restrict__ id2) {
return std::memcmp(id1.data(), id2.data(), HASH_LEN);
}
/** Find how many bits two ids have in common. */
static inline unsigned
commonBits(const InfoHash& id1, const InfoHash& id2)
{
unsigned i, j;
uint8_t x;
for(i = 0; i < HASH_LEN; i++) {
if(id1[i] != id2[i])
break;
}
if(i == HASH_LEN)
return 8*HASH_LEN;
x = id1[i] ^ id2[i];
j = 0;
while((x & 0x80) == 0) {
x <<= 1;
j++;
}
return 8 * i + j;
}
/** Determine whether id1 or id2 is closer to this */
int
xorCmp(const InfoHash& id1, const InfoHash& id2) const
{
unsigned i;
for(i = 0; i < HASH_LEN; i++) {
uint8_t xor1, xor2;
if(id1[i] == id2[i])
continue;
xor1 = id1[i] ^ (*this)[i];
xor2 = id2[i] ^ (*this)[i];
if(xor1 < xor2)
return -1;
else
return 1;
}
return 0;
}
static inline InfoHash get(const std::string& data) {
return get((const uint8_t*)data.data(), data.size());
}
static inline InfoHash get(const std::vector<uint8_t>& data) {
return get(data.data(), data.size());
}
/**
* Computes the hash from a given data buffer of size data_len.
*/
static InfoHash get(const uint8_t* data, size_t data_len);
friend std::ostream& operator<< (std::ostream& s, const InfoHash& h);
std::string toString() const;
};
}