495 lines
13 KiB
C++
495 lines
13 KiB
C++
#ifndef _WIN32
|
|
#include <dlfcn.h>
|
|
#endif
|
|
|
|
#include <stdexcept>
|
|
#include <string>
|
|
#include <vector>
|
|
#include <array>
|
|
#include <map>
|
|
#include <algorithm>
|
|
|
|
#include <boost/version.hpp>
|
|
|
|
#include <boost/asio/ip/address.hpp>
|
|
#include <boost/asio/ip/address_v4.hpp>
|
|
#include <boost/asio/ip/address_v6.hpp>
|
|
#include <boost/asio/ip/tcp.hpp>
|
|
#include <boost/asio/ip/udp.hpp>
|
|
|
|
#include <openssl/opensslv.h>
|
|
|
|
#include <libtorrent/config.hpp>
|
|
#include <libtorrent/time.hpp>
|
|
#include <libtorrent/buffer.hpp>
|
|
#include <libtorrent/utp_stream.hpp>
|
|
#include <libtorrent/socket_io.hpp>
|
|
#include <libtorrent/read_resume_data.hpp>
|
|
#include <libtorrent/write_resume_data.hpp>
|
|
#include <libtorrent/hex.hpp>
|
|
#include <libtorrent/extensions.hpp>
|
|
#include <libtorrent/bloom_filter.hpp>
|
|
#include <libtorrent/announce_entry.hpp>
|
|
#include <libtorrent/enum_net.hpp>
|
|
|
|
#include <libtorrent/kademlia/dht_tracker.hpp>
|
|
#include <libtorrent/kademlia/node_entry.hpp>
|
|
#include <libtorrent/kademlia/node.hpp>
|
|
#include <libtorrent/kademlia/node_id.hpp>
|
|
#include <libtorrent/kademlia/get_peers.hpp>
|
|
#include <libtorrent/kademlia/item.hpp>
|
|
#include <libtorrent/kademlia/ed25519.hpp>
|
|
|
|
#include <libtorrent/aux_/cpuid.hpp>
|
|
|
|
std::vector<int8_t> ed25519_create_seed() {
|
|
std::array<char, 32> seed = libtorrent::dht::ed25519_create_seed();
|
|
return std::vector<int8_t>(seed.data(), seed.end());
|
|
}
|
|
|
|
std::pair<std::vector<int8_t>, std::vector<int8_t>> ed25519_create_keypair(
|
|
std::vector<int8_t>& seed) {
|
|
using namespace libtorrent::dht;
|
|
|
|
public_key pk;
|
|
secret_key sk;
|
|
|
|
std::array<char, 32> s;
|
|
std::copy_n(seed.begin(), 32, s.begin());
|
|
|
|
std::tie(pk, sk) = ed25519_create_keypair(s);
|
|
|
|
return std::make_pair(std::vector<int8_t>(pk.bytes.begin(), pk.bytes.end()),
|
|
std::vector<int8_t>(sk.bytes.begin(), sk.bytes.end()));
|
|
}
|
|
|
|
std::vector<int8_t> ed25519_sign(std::vector<int8_t>& msg,
|
|
std::vector<int8_t>& pk, std::vector<int8_t>& sk) {
|
|
using namespace libtorrent::dht;
|
|
|
|
public_key pk1((char*)pk.data());
|
|
secret_key sk1((char*)sk.data());
|
|
|
|
signature sig = ed25519_sign({reinterpret_cast<char const*>(msg.data()), static_cast<long>(msg.size())},
|
|
pk1, sk1);
|
|
return std::vector<int8_t>(sig.bytes.begin(), sig.bytes.end());
|
|
}
|
|
|
|
bool ed25519_verify(std::vector<int8_t>& sig,
|
|
std::vector<int8_t>& msg,
|
|
std::vector<int8_t>& pk) {
|
|
using namespace libtorrent::dht;
|
|
|
|
signature sig1((char*)sig.data());
|
|
public_key pk1((char*)pk.data());
|
|
|
|
return ed25519_verify(sig1, {reinterpret_cast<char const*>(msg.data()), static_cast<long>(msg.size())}, pk1);
|
|
}
|
|
|
|
std::vector<int8_t> ed25519_add_scalar_public(std::vector<int8_t>& pk,
|
|
std::vector<int8_t>& scalar) {
|
|
using namespace libtorrent::dht;
|
|
|
|
public_key pk1((char*)pk.data());
|
|
|
|
std::array<char, 32> s;
|
|
std::copy_n(scalar.begin(), 32, s.begin());
|
|
|
|
public_key ret = ed25519_add_scalar(pk1, s);
|
|
return std::vector<int8_t>(ret.bytes.begin(), ret.bytes.end());
|
|
}
|
|
|
|
std::vector<int8_t> ed25519_add_scalar_secret(std::vector<int8_t>& sk,
|
|
std::vector<int8_t>& scalar) {
|
|
using namespace libtorrent::dht;
|
|
|
|
secret_key sk1((char*)sk.data());
|
|
|
|
std::array<char, 32> s;
|
|
std::copy_n(scalar.begin(), 32, s.begin());
|
|
|
|
secret_key ret = ed25519_add_scalar(sk1, s);
|
|
return std::vector<int8_t>(ret.bytes.begin(), ret.bytes.end());
|
|
}
|
|
|
|
std::vector<int8_t> ed25519_key_exchange(std::vector<int8_t>& pk,
|
|
std::vector<int8_t>& sk) {
|
|
using namespace libtorrent::dht;
|
|
|
|
public_key pk1((char*)pk.data());
|
|
secret_key sk1((char*)sk.data());
|
|
|
|
std::array<char, 32> secret = ed25519_key_exchange(pk1, sk1);
|
|
return std::vector<int8_t>(secret.begin(), secret.end());
|
|
}
|
|
|
|
struct alert_notify_callback {
|
|
|
|
virtual ~alert_notify_callback() {
|
|
}
|
|
|
|
virtual void on_alert() {
|
|
}
|
|
};
|
|
|
|
struct add_files_listener {
|
|
|
|
virtual ~add_files_listener() {
|
|
}
|
|
|
|
virtual bool pred(std::string const& p) {
|
|
return true;
|
|
}
|
|
};
|
|
|
|
void add_files_ex(libtorrent::file_storage& fs, std::string const& file,
|
|
add_files_listener* listener, libtorrent::create_flags_t flags) {
|
|
add_files(fs, file, std::bind(&add_files_listener::pred, listener, std::placeholders::_1), flags);
|
|
}
|
|
|
|
struct set_piece_hashes_listener {
|
|
|
|
virtual ~set_piece_hashes_listener() {
|
|
}
|
|
|
|
virtual void progress(int i) {
|
|
}
|
|
|
|
void progress_index(libtorrent::piece_index_t i) {
|
|
progress(static_cast<int>(i));
|
|
}
|
|
};
|
|
|
|
void set_piece_hashes_ex(libtorrent::create_torrent& t, std::string const& p,
|
|
set_piece_hashes_listener* listener, libtorrent::error_code& ec) {
|
|
set_piece_hashes(t, p, std::bind(&set_piece_hashes_listener::progress_index, listener, std::placeholders::_1), ec);
|
|
}
|
|
|
|
int boost_version() {
|
|
return BOOST_VERSION;
|
|
}
|
|
|
|
const char* boost_lib_version() {
|
|
return BOOST_LIB_VERSION;
|
|
}
|
|
|
|
int openssl_version_number() {
|
|
return OPENSSL_VERSION_NUMBER;
|
|
}
|
|
|
|
const char* openssl_version_text() {
|
|
return OPENSSL_VERSION_TEXT;
|
|
}
|
|
|
|
int find_metric_idx_s(std::string const& name) {
|
|
return libtorrent::find_metric_idx(name);
|
|
}
|
|
|
|
void dht_put_item_cb(libtorrent::entry& e, std::array<char, 64>& sig, std::int64_t& seq,
|
|
std::string salt, libtorrent::dht::public_key pk, libtorrent::dht::secret_key sk,
|
|
libtorrent::entry data) {
|
|
using namespace libtorrent::dht;
|
|
|
|
e = data;
|
|
std::vector<char> buf;
|
|
bencode(std::back_inserter(buf), e);
|
|
signature sign;
|
|
++seq;
|
|
sign = sign_mutable_item(buf, salt, sequence_number(seq), pk, sk);
|
|
sig = sign.bytes;
|
|
}
|
|
|
|
struct swig_plugin : libtorrent::plugin {
|
|
|
|
virtual ~swig_plugin() {
|
|
}
|
|
|
|
libtorrent::feature_flags_t implemented_features() {
|
|
return libtorrent::plugin::dht_request_feature;
|
|
}
|
|
|
|
virtual bool on_dht_request(libtorrent::string_view query,
|
|
libtorrent::udp::endpoint const& source,
|
|
libtorrent::bdecode_node const& message, libtorrent::entry& response) {
|
|
return false;
|
|
}
|
|
};
|
|
|
|
// enum_net functions, very useful for networking
|
|
struct ip_interface
|
|
{
|
|
libtorrent::address interface_address;
|
|
libtorrent::address netmask;
|
|
std::vector<std::int8_t> name;
|
|
std::vector<std::int8_t> friendly_name;
|
|
std::vector<std::int8_t> description;
|
|
bool preferred;
|
|
};
|
|
|
|
struct ip_route
|
|
{
|
|
libtorrent::address destination;
|
|
libtorrent::address netmask;
|
|
libtorrent::address gateway;
|
|
libtorrent::address source_hint;
|
|
std::vector<std::int8_t> name;
|
|
int mtu;
|
|
};
|
|
|
|
std::vector<ip_interface> enum_net_interfaces(libtorrent::session* s)
|
|
{
|
|
std::vector<ip_interface> ret;
|
|
boost::system::error_code ec;
|
|
auto v = libtorrent::enum_net_interfaces(s->get_io_service(), ec);
|
|
for (auto& e : v)
|
|
{
|
|
ip_interface iface;
|
|
iface.interface_address = e.interface_address;
|
|
iface.netmask = e.netmask;
|
|
iface.name = {e.name, e.name + sizeof(e.name)};
|
|
iface.friendly_name = {e.friendly_name, e.friendly_name + sizeof(e.friendly_name)};
|
|
iface.description = {e.description, e.description + sizeof(e.description)};
|
|
iface.preferred = e.preferred;
|
|
ret.push_back(iface);
|
|
}
|
|
return ret;
|
|
}
|
|
|
|
std::vector<ip_route> enum_routes(libtorrent::session* s)
|
|
{
|
|
std::vector<ip_route> ret;
|
|
boost::system::error_code ec;
|
|
auto v = libtorrent::enum_routes(s->get_io_service(), ec);
|
|
for (auto& e : v)
|
|
{
|
|
ip_route r;
|
|
r.destination = e.destination;
|
|
r.netmask = e.netmask;
|
|
r.gateway = e.gateway;
|
|
r.name = {e.name, e.name + sizeof(e.name)};
|
|
r.mtu = e.mtu;
|
|
ret.push_back(r);
|
|
}
|
|
return ret;
|
|
}
|
|
|
|
void copy_byte_vector_to_char_array(std::vector<std::int8_t> source, char* target, const unsigned int target_size)
|
|
{
|
|
std::memset(target, 0, target_size);
|
|
for (unsigned int i=0; i < source.size() || i <= target_size; i++) {
|
|
target[i] = source[i];
|
|
}
|
|
}
|
|
|
|
//boost::optional<address> get_gateway(ip_interface const& iface, span<ip_route const> routes);
|
|
//@see enum_net.hpp -> struct libtorrent::ip_interface
|
|
//@see enum_net.hpp -> struct libtorrent::ip_route
|
|
libtorrent::address get_gateway(ip_interface const& iface, std::vector<ip_route>& routes)
|
|
{
|
|
// convert our libtorrent.h defined types to native libtorrent:: types from enum_net.hpp
|
|
libtorrent::ip_interface lt_iface;
|
|
lt_iface.interface_address = iface.interface_address;
|
|
lt_iface.netmask = iface.netmask;
|
|
lt_iface.preferred = iface.preferred;
|
|
|
|
copy_byte_vector_to_char_array(iface.name, lt_iface.name, sizeof(lt_iface.name)); // 64
|
|
copy_byte_vector_to_char_array(iface.friendly_name, lt_iface.friendly_name, sizeof(lt_iface.friendly_name)); // 128
|
|
copy_byte_vector_to_char_array(iface.description, lt_iface.description, sizeof(lt_iface.description)); // 128
|
|
|
|
// convert ip_route_vector to vector<libtorrent::ip_route const> (cannot use const, gnu g++ explodes in linux/android thinking there's an ambiguity)
|
|
std::vector<libtorrent::ip_route> lt_routes;
|
|
for (auto const& r : routes) {
|
|
libtorrent::ip_route lt_ip_route;
|
|
lt_ip_route.destination = r.destination;
|
|
lt_ip_route.netmask = r.netmask;
|
|
lt_ip_route.gateway = r.gateway;
|
|
lt_ip_route.source_hint = r.source_hint;
|
|
lt_ip_route.mtu = r.mtu;
|
|
copy_byte_vector_to_char_array(r.name, lt_ip_route.name, sizeof(lt_ip_route.name)); //64
|
|
lt_routes.push_back(lt_ip_route);
|
|
}
|
|
|
|
return libtorrent::get_gateway(lt_iface, lt_routes).get();
|
|
}
|
|
|
|
bool arm_neon_support()
|
|
{
|
|
return libtorrent::aux::arm_neon_support;
|
|
}
|
|
|
|
#if defined TORRENT_ANDROID || defined TORRENT_BSD
|
|
#define WRAP_POSIX 1
|
|
#else
|
|
#define WRAP_POSIX 0
|
|
#endif
|
|
|
|
struct posix_stat_t {
|
|
int64_t size;
|
|
int64_t atime;
|
|
int64_t mtime;
|
|
int64_t ctime;
|
|
int mode;
|
|
};
|
|
|
|
#if WRAP_POSIX
|
|
void* get_libc() {
|
|
#if defined TORRENT_ANDROID
|
|
static void* h = dlopen("libc.so", RTLD_NOW);
|
|
#elif defined TORRENT_BSD
|
|
static void* h = dlopen("libc.dylib", RTLD_NOW);
|
|
#else
|
|
static void* h = nullptr;
|
|
#endif
|
|
return h;
|
|
}
|
|
|
|
int posix_open(const char* path, int flags, mode_t mode) {
|
|
typedef int func_t(const char*, int, ...);
|
|
static func_t* f = (func_t*) dlsym(get_libc(), "open");
|
|
#if defined TORRENT_ANDROID
|
|
flags |= O_LARGEFILE;
|
|
#endif
|
|
return (*f)(path, flags, mode);
|
|
}
|
|
|
|
int posix_stat(const char *path, struct ::stat *buf) {
|
|
typedef int func_t(const char*, struct ::stat*);
|
|
#if defined TORRENT_ANDROID && __ANDROID_API__ < 21
|
|
static func_t* f = (func_t*) dlsym(get_libc(), "stat");
|
|
#else
|
|
static func_t* f = (func_t*) dlsym(get_libc(), "stat64");
|
|
#endif
|
|
return (*f)(path, buf);
|
|
}
|
|
|
|
int posix_mkdir(const char *path, mode_t mode) {
|
|
typedef int func_t(const char*, mode_t);
|
|
static func_t* f = (func_t*) dlsym(get_libc(), "mkdir");
|
|
return (*f)(path, mode);
|
|
}
|
|
|
|
int posix_rename(const char *oldpath, const char *newpath) {
|
|
typedef int func_t(const char*, const char*);
|
|
static func_t* f = (func_t*) dlsym(get_libc(), "rename");
|
|
return (*f)(oldpath, newpath);
|
|
}
|
|
|
|
int posix_remove(const char *path) {
|
|
typedef int func_t(const char*);
|
|
static func_t* f = (func_t*) dlsym(get_libc(), "remove");
|
|
return (*f)(path);
|
|
}
|
|
#endif
|
|
|
|
struct posix_wrapper {
|
|
|
|
virtual ~posix_wrapper() {
|
|
}
|
|
|
|
virtual int open(const char* path, int flags, int mode) {
|
|
#if WRAP_POSIX
|
|
return posix_open(path, flags, mode);
|
|
#else
|
|
return -1;
|
|
#endif
|
|
}
|
|
|
|
virtual int stat(const char *path, posix_stat_t *buf) {
|
|
#if WRAP_POSIX
|
|
struct ::stat t;
|
|
int r = posix_stat(path, &t);
|
|
buf->size = t.st_size;
|
|
buf->atime = t.st_atime;
|
|
buf->mtime = t.st_mtime;
|
|
buf->ctime = t.st_ctime;
|
|
buf->mode = t.st_mode;
|
|
return r;
|
|
#else
|
|
return -1;
|
|
#endif
|
|
}
|
|
|
|
virtual int mkdir(const char *path, int mode) {
|
|
#if WRAP_POSIX
|
|
return posix_mkdir(path, mode);
|
|
#else
|
|
return -1;
|
|
#endif
|
|
}
|
|
|
|
virtual int rename(const char *oldpath, const char *newpath) {
|
|
#if WRAP_POSIX
|
|
return posix_rename(oldpath, newpath);
|
|
#else
|
|
return -1;
|
|
#endif
|
|
}
|
|
|
|
virtual int remove(const char *path) {
|
|
#if WRAP_POSIX
|
|
return posix_remove(path);
|
|
#else
|
|
return -1;
|
|
#endif
|
|
}
|
|
};
|
|
|
|
posix_wrapper* g_posix_wrapper = NULL;
|
|
|
|
void set_posix_wrapper(posix_wrapper *obj) {
|
|
g_posix_wrapper = obj;
|
|
}
|
|
|
|
#if WRAP_POSIX
|
|
extern "C" {
|
|
|
|
int open(const char *path, int flags, ...) {
|
|
mode_t mode = 0;
|
|
if (flags & O_CREAT) {
|
|
va_list v;
|
|
va_start(v, flags);
|
|
mode = (mode_t) va_arg(v, int);
|
|
va_end(v);
|
|
}
|
|
|
|
return g_posix_wrapper != NULL ?
|
|
g_posix_wrapper->open(path, flags, mode) :
|
|
posix_open(path, flags, mode);
|
|
}
|
|
|
|
int stat(const char *path, struct ::stat *buf) {
|
|
if (g_posix_wrapper != NULL) {
|
|
posix_stat_t t;
|
|
int r = g_posix_wrapper->stat(path, &t);
|
|
buf->st_size = t.size;
|
|
buf->st_atime = t.atime;
|
|
buf->st_mtime = t.mtime;
|
|
buf->st_ctime = t.ctime;
|
|
buf->st_mode = t.mode;
|
|
return r;
|
|
} else {
|
|
return posix_stat(path, buf);
|
|
}
|
|
}
|
|
|
|
int mkdir(const char *path, mode_t mode) {
|
|
return g_posix_wrapper != NULL ?
|
|
g_posix_wrapper->mkdir(path, mode) :
|
|
posix_mkdir(path, mode);
|
|
}
|
|
|
|
int rename(const char *oldpath, const char *newpath) {
|
|
return g_posix_wrapper != NULL ?
|
|
g_posix_wrapper->rename(oldpath, newpath) :
|
|
posix_rename(oldpath, newpath);
|
|
}
|
|
|
|
int remove(const char *path) {
|
|
return g_posix_wrapper != NULL ?
|
|
g_posix_wrapper->remove(path) :
|
|
posix_remove(path);
|
|
}
|
|
|
|
}
|
|
#endif
|