Compare commits

..
21 Commits
Author SHA1 Message Date
Adrien Béraud 4a5eedbf0a value: add common crypto ops 2016-06-14 18:13:02 -04:00
Adrien Béraud fdfa10bd2e dht: clear search before expiring it 2016-06-13 15:55:34 -04:00
Adrien Béraud f200f9dfc2 pkgconfig: add private dependencies 2016-06-11 21:50:34 -04:00
Adrien Béraud 9615774114 cmake: build versioned shared library 2016-06-11 21:22:27 -04:00
Adrien Béraud c6b0e531c2 dht: add code documentation 2016-06-11 18:54:18 -04:00
Adrien Béraud 8e5f12dbf1 autotools: handle case where DESTDIR is empty 2016-06-11 16:10:52 -04:00
Adrien Béraud 5bcf1da505 autotools: cleanup 2016-06-11 16:10:27 -04:00
Adrien Béraud 97d88fcfed autotools: disable doxygen by default 2016-06-11 16:04:35 -04:00
Adrien Béraud 963dd6779e benchmark: don't block while putting values 2016-06-03 17:20:58 -04:00
Simon Désaulniers 54a4327039 dht: handle search expired before permanent put 2016-06-03 17:20:58 -04:00
Simon Désaulniers 10e5439048 securedht: permanent put of a certificate. 2016-06-03 17:20:58 -04:00
Simon Désaulniers dcca94aab7 dht,api: enable optional permanent put on dht
A permanent put is going to be executed once and every time the data expires on
each SearchNode.
2016-06-03 17:20:58 -04:00
Simon Désaulniers 173a9ee642 revert attempt to avoid securedht cert put fail 2016-06-03 17:20:58 -04:00
Simon Désaulniers ed1ca6db8f Revert "dht: wait for connection before running searches"
This reverts commit bd08506146.
2016-06-03 17:20:58 -04:00
Adrien Béraud 7367158284 dht: new insertNode algorithm 2016-06-03 17:20:58 -04:00
Adrien Béraud cf8d9ccd0d infohash: merge Windows includes 2016-06-02 17:52:07 -04:00
Adrien Béraud fdbdc91d55 Merge pull request #74 from sim590/python-destdir
[packaging] support python installation with make DESTDIR=$DIR
2016-06-02 15:41:55 -04:00
Simon Désaulniers cf9c63abb7 enable python make DESTDIR=$DIR install support 2016-06-02 14:48:05 -04:00
Simon Désaulniers 475b26048f cmake: pass $DESTDIR environnement var to setup.py 2016-06-02 12:36:21 -04:00
Andreas Traczyk df1615e8d1 Update README.md 2016-06-02 12:22:34 -04:00
Andreas Traczyk 9e461e0960 microsoft compiler support 2016-06-02 12:17:09 -04:00
26 changed files with 122 additions and 323 deletions

No files matched your search

+1 -2
View File
@@ -1,7 +1,7 @@
cmake_minimum_required (VERSION 2.8.6)
project (opendht)
set (opendht_VERSION_MAJOR 0)
set (opendht_VERSION_MINOR 6.3)
set (opendht_VERSION_MINOR 6.1)
set (opendht_VERSION ${opendht_VERSION_MAJOR}.${opendht_VERSION_MINOR})
set (PACKAGE_VERSION ${opendht_VERSION})
set (VERSION "${opendht_VERSION}")
@@ -132,7 +132,6 @@ endif ()
if (OPENDHT_TOOLS)
add_subdirectory(tools)
endif ()
add_subdirectory(doc)
if (OPENDHT_PYTHON)
add_subdirectory(python)
+2
View File
@@ -10,7 +10,9 @@ if USE_CYTHON
SUBDIRS += python
endif
if HAVE_DOXYGEN
SUBDIRS += doc
endif
ACLOCAL_AMFLAGS = -I m4
+1 -5
View File
@@ -97,11 +97,7 @@ Licence
-
Copyright (C) 2014-2016 Savoir-faire Linux Inc.
OpenDHT 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.
See COPYING or https://www.gnu.org/licenses/gpl-3.0.en.html for the full GPLv3 licence.
Licenced under the GNU General Public License version 3 (see COPYING for the full licence).
This project is independent from another project called OpenDHT (Sean Rhea. Ph.D. Thesis, 2005), now extinct.
+2 -13
View File
@@ -1,21 +1,10 @@
dnl define macros
m4_define([opendht_major_version], 0)
m4_define([opendht_minor_version], 6)
m4_define([opendht_patch_version], 3)
m4_define([opendht_version],
[opendht_major_version.opendht_minor_version.opendht_patch_version])
AC_INIT(opendht, [opendht_version])
AC_INIT(opendht, 0.6.1)
AC_CONFIG_AUX_DIR(ac)
AM_INIT_AUTOMAKE([foreign subdir-objects])
AC_CONFIG_HEADERS([config.h])
AC_CONFIG_MACRO_DIR([m4])
AC_CANONICAL_HOST
AC_SUBST(OPENDHT_MAJOR_VERSION, opendht_major_version)
AC_SUBST(OPENDHT_MINOR_VERSION, opendht_minor_version)
AC_SUBST(OPENDHT_PATCH_VERSION, opendht_patch_version)
AC_ARG_ENABLE([debug], AS_HELP_STRING([--enable-debug], [Build in debug mode, adds stricter warnings, disables optimization]))
AS_IF([test "x$enable_debug" = "xyes"],
[CXXFLAGS="${CXXFLAGS} -g -Wno-return-type -Wall -Wextra -Wnon-virtual-dtor -O0"],
@@ -99,7 +88,7 @@ AM_COND_IF([ENABLE_TOOLS], [
])
])
AC_CONFIG_FILES([doc/Doxyfile doc/Makefile])
AM_COND_IF([HAVE_DOXYGEN], [AC_CONFIG_FILES([doc/Doxyfile doc/Makefile])])
dnl Configure setup.py if we build the python module
AM_COND_IF([USE_CYTHON], [
-3
View File
@@ -1,3 +0,0 @@
if (OPENDHT_TOOLS)
INSTALL(FILES ${CMAKE_CURRENT_SOURCE_DIR}/dhtnode.1 DESTINATION ${CMAKE_INSTALL_PREFIX}/share/man/man1)
endif ()
-4
View File
@@ -1,6 +1,3 @@
dist_man1_MANS = dhtnode.1
if HAVE_DOXYGEN
doxyfile.stamp:
$(DOXYGEN) Doxyfile
echo stamp > doxyfile.stamp
@@ -10,4 +7,3 @@ CLEANFILES = doxyfile.stamp
all-local: doxyfile.stamp
clean-local:
rm -rf $(top_srcdir)/doc/man $(top_srcdir)/doc/html
endif
-85
View File
@@ -1,85 +0,0 @@
.TH DHTNODE 1 2016-06-27
.SH NAME
.B dhtnode
- a simple OpenDHT command line node runner.
.SH SYNOPSIS
.B dhtnode [-h]
.B dhtnode [-v[\fIlogfile\fP]] [-i] [-d] [-n \fInetwork_id\fP] [-p \fIlocal_port\fP] [-b[\fIbootstrap_host\fP[:\fIport\fP]]]
.SH DESCRIPTION
This program runs a simple OpenDHT node in an interactive way. If you rather
want to run the node in daemon mode, option \fB'-d'\fP is provided. When running
in the interactive shell, you benefit from the readline capabilities for writing
your commands such as command history. Here are the available commands in the
interactive shell:
.EE
h, help Print this help message.
q, quit Quit the program.
log Start/stop printing DHT logs.
Node information:
ll Print basic information and stats about the current node.
ls Print basic information about current searches.
ld Print basic information about currenty stored values on this node.
lr Print the full current routing table of this node
Operations on the DHT:
b ip:port Ping potential node at given IP address/port.
g [key] Get values at [key].
l [key] Listen for value changes at [key].
p [key] [str] Put string value at [key].
s [key] [str] Put string value at [key], signed with our generated
private key.
e [key] [dest] [str] Put string value at [key], encrypted for [dest] with
its public key (if found).
.SH OPTIONS
.TP
\fB-h\fP
Prints some help.
.TP
\fB-v\fP[\fIlogfile\fP]
Enable the verbose mode. Optionally provide a log file.
.TP
\fB-i\fP
Generate cryptographic identity for the node.
.TP
\fB-d\fP
Run the program in daemon mode (will fork in the background).
.TP
\fB-n\fP \fInetwork_id\fP
Specify the network id. This let you connect to distinct networks and prevents
the merge of two different networks (available since OpenDHT v0.6.1).
.TP
\fB-p\fP \fIlocal_port\fP
Use port \fIlocal_port\fP for the program to bind to.
.TP
\fB-b\fP[\fIbootstrap_host\fP[:\fIport\fP]]
The program needs to be given a node to connect to the network. You use this
option to provide the ip address of that node. If no argument is provided, the
node runs in \fBbootstrap mode\fP, i.e. it will especially serve as entry point
in the network.
.SH AUTHORS
.TP
Program written by
.IP \(bu
.\}
Adrien Béraud <adrien.beraud@savoirfairelinux.com>
.TP
Man page written by
.IP \(bu
.\}
Simon Désaulniers <sim.desaulniers@gmail.com>
+2 -21
View File
@@ -30,44 +30,23 @@ namespace dht {
struct Node;
/**
* Current status of a DHT node.
*/
enum class NodeStatus {
Disconnected, // 0 nodes
Connecting, // 1+ nodes
Connected // 1+ good nodes
};
/**
* Dht configuration.
*/
struct Config {
/** DHT node ID */
InfoHash node_id;
/**
* DHT network ID. A node will only talk with other nodes having
* the same network ID.
* Network ID 0 (default) represents the main public network.
*/
NetId network;
/** For testing purposes only, enables bootstrap mode */
bool is_bootstrap;
};
/**
* SecureDht configuration.
*/
struct SecureDhtConfig
{
Config node_config;
crypto::Identity id;
};
static constexpr size_t DEFAULT_STORAGE_LIMIT {1024 * 1024 * 64};
using ValuesExport = std::pair<InfoHash, Blob>;
using GetCallback = std::function<bool(const std::vector<std::shared_ptr<Value>>& values)>;
@@ -78,6 +57,8 @@ using CertificateStoreQuery = std::function<std::vector<std::shared_ptr<crypto::
typedef bool (*GetCallbackRaw)(std::shared_ptr<Value>, void *user_data);
static constexpr size_t DEFAULT_STORAGE_LIMIT {1024 * 1024 * 64};
GetCallbackSimple bindGetCb(GetCallbackRaw raw_cb, void* user_data);
GetCallback bindGetCb(GetCallbackSimple cb);
+1 -1
View File
@@ -392,7 +392,7 @@ private:
RoutingTable buckets {};
RoutingTable buckets6 {};
std::vector<std::unique_ptr<Storage>> store;
std::vector<Storage> store;
size_t total_values {0};
size_t total_store_size {0};
size_t max_store_size {DEFAULT_STORAGE_LIMIT};
+2 -3
View File
@@ -268,13 +268,12 @@ public:
* @param threaded: If false, ::loop() must be called periodically. Otherwise a thread is launched.
* @param cb: Optional callback to receive general state information.
*/
void run(in_port_t port, const crypto::Identity identity, bool threaded = false, NetId network = 0) {
void run(in_port_t port, const crypto::Identity identity, bool threaded = false, bool is_bootstrap = false) {
run(port, {
/*.dht_config = */{
/*.node_config = */{
/*.node_id = */{},
/*.network = */network,
/*.is_bootstrap = */false
/*.is_bootstrap = */is_bootstrap
},
/*.id = */identity
},
+2 -3
View File
@@ -256,7 +256,7 @@ public:
using RequestExpiredCb = std::function<void(const Request&, bool)>;
NetworkEngine(Logger& log, Scheduler& scheduler) : myid(zeroes), DHT_LOG(log), scheduler(scheduler) {}
NetworkEngine(InfoHash& myid, NetId net, int s, int s6, Logger& log, Scheduler& scheduler,
NetworkEngine(InfoHash& myid, int s, int s6, Logger& log, Scheduler& scheduler,
decltype(NetworkEngine::onError) onError,
decltype(NetworkEngine::onNewNode) onNewNode,
decltype(NetworkEngine::onReportedAddr) onReportedAddr,
@@ -266,7 +266,7 @@ public:
decltype(NetworkEngine::onListen) onListen,
decltype(NetworkEngine::onAnnounce) onAnnounce) :
onError(onError), onNewNode(onNewNode), onReportedAddr(onReportedAddr), onPing(onPing), onFindNode(onFindNode),
onGetValues(onGetValues), onListen(onListen), onAnnounce(onAnnounce), myid(myid), network(net),
onGetValues(onGetValues), onListen(onListen), onAnnounce(onAnnounce), myid(myid),
dht_socket(s), dht_socket6(s6), DHT_LOG(log), scheduler(scheduler)
{
transaction_id = std::uniform_int_distribution<decltype(transaction_id)>{1}(rd_device);
@@ -376,7 +376,6 @@ private:
/* DHT info */
const InfoHash& myid;
const NetId network {0};
const int dht_socket {-1};
const int dht_socket6 {-1};
const Logger& DHT_LOG;
-2
View File
@@ -23,8 +23,6 @@
namespace dht {
static constexpr unsigned TARGET_NODES {8};
struct Bucket {
Bucket() : cached() {}
Bucket(sa_family_t af, const InfoHash& f = {}, time_point t = time_point::min())
+6 -3
View File
@@ -126,13 +126,16 @@ public:
Value decrypt(const Value& v);
void findCertificate(const InfoHash& node, std::function<void(const std::shared_ptr<crypto::Certificate>)> cb);
void findPublicKey(const InfoHash& node, std::function<void(const std::shared_ptr<const crypto::PublicKey>)> cb);
void findPublicKey(const InfoHash& node, std::function<void(const std::shared_ptr<crypto::PublicKey>)> cb);
const std::shared_ptr<crypto::Certificate> registerCertificate(const InfoHash& node, const Blob& cert);
void registerCertificate(std::shared_ptr<crypto::Certificate>& cert);
const std::shared_ptr<crypto::Certificate> getCertificate(const InfoHash& node) const;
const std::shared_ptr<const crypto::PublicKey> getPublicKey(const InfoHash& node) const;
const std::shared_ptr<crypto::PublicKey> getPublicKey(const InfoHash& node) const;
/**
* Allows to set a custom callback called by the library to find a locally-stored certificate.
@@ -158,7 +161,7 @@ private:
// our certificate cache
std::map<InfoHash, std::shared_ptr<crypto::Certificate>> nodesCertificates_ {};
std::map<InfoHash, std::shared_ptr<const crypto::PublicKey>> nodesPubKeys_ {};
std::map<InfoHash, std::shared_ptr<crypto::PublicKey>> nodesPubKeys_ {};
std::uniform_int_distribution<Value::Id> rand_id {};
};
+2 -1
View File
@@ -40,8 +40,9 @@
namespace dht {
static constexpr unsigned TARGET_NODES {8};
using Address = std::pair<sockaddr_storage, socklen_t>;
using NetId = uint32_t;
using want_t = int_fast8_t;
std::string print_addr(const sockaddr* sa, socklen_t slen);
+3 -3
View File
@@ -256,7 +256,7 @@ struct Value
void sign(const crypto::PrivateKey& key) {
if (isEncrypted())
throw DhtException("Can't sign encrypted data.");
owner = std::make_shared<const crypto::PublicKey>(key.getPublicKey());
owner = std::make_shared<crypto::PublicKey>(key.getPublicKey());
signature = key.sign(getToSign());
}
@@ -273,7 +273,7 @@ struct Value
}
/**
* Sign the value with from and returns the encrypted version for to.
*
*/
Value encrypt(const crypto::PrivateKey& from, const crypto::PublicKey& to) {
if (isEncrypted())
@@ -429,7 +429,7 @@ struct Value
/**
* Public key of the signer.
*/
std::shared_ptr<const crypto::PublicKey> owner {};
std::shared_ptr<crypto::PublicKey> owner {};
/**
* Hash of the recipient (optional).
-45
View File
@@ -1,45 +0,0 @@
# Benchmark
The `benchmark.py` script is used for testing OpenDHT in various cases. If you
run `benchmark.py --help`, you should find the following text:
optional arguments:
-h, --help show this help message and exit
--performance Launches performance benchmark test. Available args
for "-t" are: gets.
--data-persistence Launches data persistence benchmark test. Available
args for "-t" are: delete, replace, mult_time.
Available args for "-o" are : dump_str_log,
keep_alive, trigger, traffic_plot, op_plot. Use "-m"
to specify the number of producers on the DHT.Use "-e"
to specify the number of values to put on the DHT.
These options specify the feature to be tested. Each feature has its own tests.
You specify the test by using `-t` flag (see `benchmark.py --help` for full
help).
## Python dependencies
- pyroute2 >=0.3.14
- matplotlib
- GeoIP (used by `scanner.py` for drawing map of the world)
- ipaddress
- netifaces
- networkx
- numpy
## Usage
Before running the script, you have to build and install OpenDHT and its cython
wrapper (`cython3` has to be installed) on the system so that it can be found by
the benchmark script.
$ cd $OPENDHT_SRC_DIR
$ ./autogen.sh
$ ./configure
$ make && sudo make install
Then, you can use the script like so:
$ cd $OPENDHT_SRC_DIR/python/tools/
$ python3 benchmark.py --performance -t gets -n 2048
+13 -10
View File
@@ -208,23 +208,23 @@ class DhtFeatureTest(FeatureTest):
FeatureTest.lock.notify()
def _dhtPut(self, producer, _hash, *values):
for val in values:
with FeatureTest.lock:
vstr = val.__str__()[:100]
DhtNetwork.log('[PUT]:', _hash.toString(), '->', vstr + ("..." if len(vstr) > 100 else ""))
FeatureTest.done += 1
while FeatureTest.done > 0:
with FeatureTest.lock:
for val in values:
vstr = val.__str__()[:100]
DhtNetwork.log('[PUT]:', _hash.toString(), '->', vstr + ("..." if len(vstr) > 100 else ""))
FeatureTest.done += 1
producer.put(_hash, val, DhtFeatureTest.putDoneCb)
FeatureTest.lock.wait()
while FeatureTest.done > 0:
FeatureTest.lock.wait()
def _dhtGet(self, consumer, _hash):
DhtFeatureTest.foreignValues = []
DhtFeatureTest.foreignNodes = []
with FeatureTest.lock:
FeatureTest.done += 1
DhtNetwork.log('[GET]:', _hash.toString())
consumer.get(_hash, DhtFeatureTest.getcb, DhtFeatureTest.getDoneCb)
while FeatureTest.done > 0:
DhtNetwork.log('[GET]:', _hash.toString())
consumer.get(_hash, DhtFeatureTest.getcb, DhtFeatureTest.getDoneCb)
FeatureTest.lock.wait()
def _gottaGetThemAllPokeNodes(self, consumer, hashes, nodes=None):
@@ -356,7 +356,7 @@ class PersistenceTest(DhtFeatureTest):
bootstrap = self.bootstrap
# Value representing an ICE packet. Each ICE packet is around 1KB.
VALUE_SIZE = 1024
NUM_VALUES = self._num_values/wb.node_num if self._num_values else 50
NUM_VALUES = self._num_values/wb.node_num if self._num_values else 5
nr_values = NUM_VALUES * wb.node_num
nr_nodes = wb.node_num
nr_nodes_cv = threading.Condition()
@@ -365,8 +365,11 @@ class PersistenceTest(DhtFeatureTest):
hashes = [random_hash() for _ in range(wb.node_num)]
# initial set of values
i = 0
for h in hashes:
self._dhtPut(bootstrap.front(), h, *[Value(v) for v in values])
print("at: ", i)
i += 1
def normalBehavior(do, t, log=None):
nonlocal nr_values
+1 -1
View File
@@ -3,7 +3,7 @@ SUBDIRS = argon2
lib_LTLIBRARIES = libopendht.la
AM_CPPFLAGS = -I../include/opendht
libopendht_la_LDFLAGS = @LDFLAGS@ @GnuTLS_LIBS@ @Nettle_LIBS@ -version-number @OPENDHT_MAJOR_VERSION@:@OPENDHT_MINOR_VERSION@:@OPENDHT_PATCH_VERSION@
libopendht_la_LDFLAGS = @LDFLAGS@ @GnuTLS_LIBS@ @Nettle_LIBS@
libopendht_la_LIBADD = ./argon2/libargon2.la
libopendht_la_SOURCES = \
+43 -43
View File
@@ -396,7 +396,7 @@ Dht::shutdown(ShutdownCallback cb) {
};
for (const auto& str : store) {
*remaining += maintainStorage(str->id, true, str_donecb);
*remaining += maintainStorage(str.id, true, str_donecb);
}
DHT_LOG.WARN("Shuting down node: %u ops remaining.", *remaining);
if (!*remaining && cb) { cb(); }
@@ -1370,12 +1370,12 @@ Dht::listen(const InfoHash& id, GetCallback cb, Value::Filter&& f)
auto st = findStorage(id);
size_t tokenlocal = 0;
if (st == store.end() && store.size() < MAX_HASHES) {
store.emplace_back(new Storage(id, scheduler.time()));
store.emplace_back(id, scheduler.time());
st = std::prev(store.end());
}
if (st != store.end()) {
if (not (*st)->empty()) {
std::vector<std::shared_ptr<Value>> newvals = (*st)->get(f);
if (not st->empty()) {
std::vector<std::shared_ptr<Value>> newvals = st->get(f);
if (not newvals.empty()) {
if (!cb(newvals))
return 0;
@@ -1386,8 +1386,8 @@ Dht::listen(const InfoHash& id, GetCallback cb, Value::Filter&& f)
}
}
}
tokenlocal = ++(*st)->listener_token;
(*st)->local_listeners.emplace(tokenlocal, LocalListener{f, gcb});
tokenlocal = ++st->listener_token;
st->local_listeners.emplace(tokenlocal, LocalListener{f, gcb});
}
auto token4 = Dht::listenTo(id, AF_INET, gcb, f);
@@ -1412,7 +1412,7 @@ Dht::cancelListen(const InfoHash& id, size_t token)
auto st = findStorage(id);
auto tokenlocal = std::get<0>(it->second);
if (st != store.end() && tokenlocal)
(*st)->local_listeners.erase(tokenlocal);
st->local_listeners.erase(tokenlocal);
auto searches_cancel_listen = [&](std::map<InfoHash, std::shared_ptr<Search>> srs) {
for (auto& sp : srs) {
@@ -1545,7 +1545,7 @@ Dht::getLocal(const InfoHash& id, Value::Filter f) const
{
auto s = findStorage(id);
if (s == store.end()) return {};
return (*s)->get(f);
return s->get(f);
}
std::shared_ptr<Value>
@@ -1553,7 +1553,7 @@ Dht::getLocalById(const InfoHash& id, Value::Id vid) const
{
auto s = findStorage(id);
if (s != store.end())
return (*s)->getById(vid);
return s->getById(vid);
return {};
}
@@ -1626,15 +1626,15 @@ Dht::cancelPut(const InfoHash& id, const Value::Id& vid)
decltype(Dht::store)::iterator
Dht::findStorage(const InfoHash& id)
{
return std::find_if(store.begin(), store.end(), [&](const std::unique_ptr<Storage>& st) {
return st->id == id;
return std::find_if(store.begin(), store.end(), [&](const Storage& st) {
return st.id == id;
});
}
decltype(Dht::store)::const_iterator
Dht::findStorage(const InfoHash& id) const
{
return std::find_if(store.cbegin(), store.cend(), [&](const std::unique_ptr<Storage>& st) {
return st->id == id;
return std::find_if(store.cbegin(), store.cend(), [&](const Storage& st) {
return st.id == id;
});
}
@@ -1674,15 +1674,15 @@ Dht::storageStore(const InfoHash& id, const std::shared_ptr<Value>& value, time_
if (st == store.end()) {
if (store.size() >= MAX_HASHES)
return false;
store.emplace_back(new Storage(id, now));
store.emplace_back(id, now);
st = std::prev(store.end());
}
auto store = (*st)->store(value, created, max_store_size - total_store_size);
auto store = st->store(value, created, max_store_size - total_store_size);
if (std::get<0>(store)) {
total_store_size += std::get<1>(store);
total_values += std::get<2>(store);
storageChanged(*(*st), *std::get<0>(store));
storageChanged(*st, *std::get<0>(store));
}
return std::get<0>(store);
}
@@ -1731,12 +1731,12 @@ Dht::storageAddListener(const InfoHash& id, const std::shared_ptr<Node>& node, s
if (st == store.end()) {
if (store.size() >= MAX_HASHES)
return;
store.emplace_back(new Storage(id, now));
store.emplace_back(id, now);
st = std::prev(store.end());
}
auto l = (*st)->listeners.find(node);
if (l == (*st)->listeners.end()) {
const auto& stvalues = (*st)->getValues();
auto l = st->listeners.find(node);
if (l == st->listeners.end()) {
const auto& stvalues = st->getValues();
if (not stvalues.empty()) {
std::vector<std::shared_ptr<Value>> values(stvalues.size());
std::transform(stvalues.begin(), stvalues.end(), values.begin(), [=](const ValueStorage& vs) { return vs.data; });
@@ -1745,7 +1745,7 @@ Dht::storageAddListener(const InfoHash& id, const std::shared_ptr<Node>& node, s
buckets.findClosestNodes(id, now, TARGET_NODES), buckets6.findClosestNodes(id, now, TARGET_NODES),
values);
}
(*st)->listeners.emplace(node, Listener {rid, now});
st->listeners.emplace(node, Listener {rid, now});
}
else
l->second.refresh(rid, now);
@@ -1757,21 +1757,21 @@ Dht::expireStorage()
const auto& now = scheduler.time();
auto i = store.begin();
while (i != store.end()) {
for (auto l = (*i)->listeners.cbegin(); l != (*i)->listeners.cend();){
for (auto l = i->listeners.cbegin(); l != i->listeners.cend();){
bool expired = l->second.time + Node::NODE_EXPIRE_TIME < now;
if (expired) {
DHT_LOG.DEBUG("Discarding expired listener %s", l->first->id.toString().c_str());
(*i)->listeners.erase(l++);
i->listeners.erase(l++);
} else
++l;
}
auto stats = (*i)->expire(types, now);
auto stats = i->expire(types, now);
total_store_size += stats.first;
total_values += stats.second;
if ((*i)->empty() && (*i)->listeners.empty() && (*i)->local_listeners.empty()) {
DHT_LOG.DEBUG("Discarding expired value %s", (*i)->id.toString().c_str());
if (i->empty() && i->listeners.empty() && i->local_listeners.empty()) {
DHT_LOG.DEBUG("Discarding expired value %s", i->id.toString().c_str());
i = store.erase(i);
}
else
@@ -2052,10 +2052,10 @@ Dht::getStorageLog() const
using namespace std::chrono;
std::stringstream out;
for (const auto& st : store) {
out << "Storage " << (*st).id << " " << (*st).listeners.size() << " list., " << (*st).valueCount() << " values (" << (*st).totalSize() << " bytes)" << std::endl;
if (not (*st).local_listeners.empty())
out << " " << (*st).local_listeners.size() << " local listeners" << std::endl;
for (const auto& l : (*st).listeners) {
out << "Storage " << st.id << " " << st.listeners.size() << " list., " << st.valueCount() << " values (" << st.totalSize() << " bytes)" << std::endl;
if (not st.local_listeners.empty())
out << " " << st.local_listeners.size() << " local listeners" << std::endl;
for (const auto& l : st.listeners) {
out << " " << "Listener " << l.first->toString();
auto since = duration_cast<seconds>(now - l.second.time);
auto expires = duration_cast<seconds>(l.second.time + Node::NODE_EXPIRE_TIME - now);
@@ -2102,7 +2102,7 @@ Dht::Dht() : store(), network_engine(DHT_LOG, scheduler) {}
Dht::Dht(int s, int s6, Config config)
: myid(config.node_id), is_bootstrap(config.is_bootstrap), store(),
network_engine(myid, config.network, s, s6, DHT_LOG, scheduler,
network_engine(myid, s, s6, DHT_LOG, scheduler,
std::bind(&Dht::onError, this, _1, _2),
std::bind(&Dht::onNewNode, this, _1, _2),
std::bind(&Dht::onReportedAddr, this, _1, _2, _3),
@@ -2238,11 +2238,11 @@ Dht::dataPersistence() {
const auto& now = scheduler.time();
auto storage_maintenance_time = time_point::max();
for (auto &str : store) {
if (now > str->maintenance_time) {
maintainStorage(str->id);
str->maintenance_time = now + MAX_STORAGE_MAINTENANCE_EXPIRE_TIME;
if (now > str.maintenance_time) {
maintainStorage(str.id);
str.maintenance_time = now + MAX_STORAGE_MAINTENANCE_EXPIRE_TIME;
}
storage_maintenance_time = std::min(storage_maintenance_time, str->maintenance_time);
storage_maintenance_time = std::min(storage_maintenance_time, str.maintenance_time);
}
scheduler.add(storage_maintenance_time, std::bind(&Dht::dataPersistence, this));
}
@@ -2259,7 +2259,7 @@ Dht::maintainStorage(InfoHash id, bool force, DoneCallback donecb) {
auto nodes = buckets.findClosestNodes(id, now);
if (!nodes.empty()) {
if (force || id.xorCmp(nodes.back()->id, myid) < 0) {
for (auto &value : (*local_storage)->getValues()) {
for (auto &value : local_storage->getValues()) {
const auto& vt = getType(value.data->type);
if (force || value.time + vt.expiration > now + MAX_STORAGE_MAINTENANCE_EXPIRE_TIME) {
// gotta put that value there
@@ -2275,7 +2275,7 @@ Dht::maintainStorage(InfoHash id, bool force, DoneCallback donecb) {
auto nodes6 = buckets6.findClosestNodes(id, now);
if (!nodes6.empty()) {
if (force || id.xorCmp(nodes6.back()->id, myid) < 0) {
for (auto &value : (*local_storage)->getValues()) {
for (auto &value : local_storage->getValues()) {
const auto& vt = getType(value.data->type);
if (force || value.time + vt.expiration > now + MAX_STORAGE_MAINTENANCE_EXPIRE_TIME) {
// gotta put that value there
@@ -2290,7 +2290,7 @@ Dht::maintainStorage(InfoHash id, bool force, DoneCallback donecb) {
if (not want4 and not want6) {
DHT_LOG.DEBUG("Discarding storage values %s", id.toString().c_str());
(*local_storage)->clear();
local_storage->clear();
}
return announce_per_af;
@@ -2383,12 +2383,12 @@ Dht::exportValues() const
e.reserve(store.size());
for (const auto& h : store) {
ValuesExport ve;
ve.first = h->id;
ve.first = h.id;
msgpack::sbuffer buffer;
msgpack::packer<msgpack::sbuffer> pk(&buffer);
pk.pack_array(h->getValues().size());
for (const auto& v : h->getValues()) {
pk.pack_array(h.getValues().size());
for (const auto& v : h.getValues()) {
pk.pack_array(2);
pk.pack(v.time.time_since_epoch().count());
v.data->msgpack_pack(pk);
@@ -2551,8 +2551,8 @@ Dht::onGetValues(std::shared_ptr<Node> node, InfoHash& hash, want_t)
answer.ntoken = makeToken((sockaddr*)&node->ss, false);
answer.nodes4 = buckets.findClosestNodes(hash, now, TARGET_NODES);
answer.nodes6 = buckets6.findClosestNodes(hash, now, TARGET_NODES);
if (st != store.end() && not (*st)->empty()) {
auto values = (*st)->getValues();
if (st != store.end() && not st->empty()) {
auto values = st->getValues();
answer.values.resize(values.size());
std::transform(values.begin(), values.end(), answer.values.begin(), [](const ValueStorage& vs) {
return vs.data;
+14 -53
View File
@@ -49,7 +49,6 @@ static const uint8_t v4prefix[16] = {
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0xFF, 0xFF, 0, 0, 0, 0
};
constexpr unsigned SEND_NODES {8};
enum class MessageType {
Error = 0,
@@ -64,7 +63,6 @@ enum class MessageType {
struct ParsedMessage {
MessageType type;
InfoHash id; /* the id of the sender */
NetId network {0}; /* network id */
InfoHash info_hash; /* hash for which values are requested */
InfoHash target; /* target id around which to find nodes */
NetworkEngine::TransId tid; /* transaction id */
@@ -295,11 +293,6 @@ NetworkEngine::processMessage(const uint8_t *buf, size_t buflen, const sockaddr*
return;
}
if (msg.network != network) {
DHT_LOG.DEBUG("Received message from other network %u.", msg.network);
return;
}
if (msg.id == myid || msg.id == zeroes) {
DHT_LOG.DEBUG("Received message from self.");
return;
@@ -458,10 +451,9 @@ packToken(msgpack::packer<msgpack::sbuffer>& pk, Blob token)
}
void
insertAddr(msgpack::packer<msgpack::sbuffer>& pk, const sockaddr *sa, socklen_t sa_len)
insertAddr(msgpack::packer<msgpack::sbuffer>& pk, const sockaddr *sa, socklen_t)
{
size_t addr_len = std::min<size_t>(sa_len,
(sa->sa_family == AF_INET) ? sizeof(in_addr) : sizeof(in6_addr));
size_t addr_len = (sa->sa_family == AF_INET) ? sizeof(in_addr) : sizeof(in6_addr);
void* addr_ptr = (sa->sa_family == AF_INET) ? (void*)&((sockaddr_in*)sa)->sin_addr
: (void*)&((sockaddr_in6*)sa)->sin6_addr;
pk.pack("sa");
@@ -493,7 +485,7 @@ NetworkEngine::sendPing(std::shared_ptr<Node> node, RequestCb on_done, RequestEx
auto tid = TransId {TransPrefix::PING, getNewTid()};
msgpack::sbuffer buffer;
msgpack::packer<msgpack::sbuffer> pk(&buffer);
pk.pack_map(5+(network?1:0));
pk.pack_map(5);
pk.pack(std::string("a")); pk.pack_map(1);
pk.pack(std::string("id")); pk.pack(myid);
@@ -503,9 +495,6 @@ NetworkEngine::sendPing(std::shared_ptr<Node> node, RequestCb on_done, RequestEx
pk.pack_bin_body((const char*)tid.data(), tid.size());
pk.pack(std::string("y")); pk.pack(std::string("q"));
pk.pack(std::string("v")); pk.pack(my_v);
if (network) {
pk.pack(std::string("n")); pk.pack(network);
}
Blob b {buffer.data(), buffer.data() + buffer.size()};
std::shared_ptr<Request> req(new Request {tid.getTid(), node, std::move(b),
@@ -530,7 +519,7 @@ void
NetworkEngine::sendPong(const sockaddr* sa, socklen_t salen, TransId tid) {
msgpack::sbuffer buffer;
msgpack::packer<msgpack::sbuffer> pk(&buffer);
pk.pack_map(4+(network?1:0));
pk.pack_map(4);
pk.pack(std::string("r")); pk.pack_map(2);
pk.pack(std::string("id")); pk.pack(myid);
@@ -540,9 +529,6 @@ NetworkEngine::sendPong(const sockaddr* sa, socklen_t salen, TransId tid) {
pk.pack_bin_body((const char*)tid.data(), tid.size());
pk.pack(std::string("y")); pk.pack(std::string("r"));
pk.pack(std::string("v")); pk.pack(my_v);
if (network) {
pk.pack(std::string("n")); pk.pack(network);
}
send(buffer.data(), buffer.size(), 0, sa, salen);
}
@@ -553,7 +539,7 @@ NetworkEngine::sendFindNode(std::shared_ptr<Node> n, const InfoHash& target, wan
auto tid = TransId {TransPrefix::FIND_NODE, getNewTid()};
msgpack::sbuffer buffer;
msgpack::packer<msgpack::sbuffer> pk(&buffer);
pk.pack_map(5+(network?1:0));
pk.pack_map(5);
pk.pack(std::string("a")); pk.pack_map(2 + (want>0?1:0));
pk.pack(std::string("id")); pk.pack(myid);
@@ -570,9 +556,7 @@ NetworkEngine::sendFindNode(std::shared_ptr<Node> n, const InfoHash& target, wan
pk.pack_bin_body((const char*)tid.data(), tid.size());
pk.pack(std::string("y")); pk.pack(std::string("q"));
pk.pack(std::string("v")); pk.pack(my_v);
if (network) {
pk.pack(std::string("n")); pk.pack(network);
}
Blob b {buffer.data(), buffer.data() + buffer.size()};
std::shared_ptr<Request> req(new Request {tid.getTid(), n, std::move(b),
@@ -599,7 +583,7 @@ NetworkEngine::sendGetValues(std::shared_ptr<Node> n, const InfoHash& info_hash,
auto tid = TransId {TransPrefix::GET_VALUES, getNewTid()};
msgpack::sbuffer buffer;
msgpack::packer<msgpack::sbuffer> pk(&buffer);
pk.pack_map(5+(network?1:0));
pk.pack_map(5);
pk.pack(std::string("a")); pk.pack_map(2 + (want>0?1:0));
pk.pack(std::string("id")); pk.pack(myid);
@@ -616,9 +600,6 @@ NetworkEngine::sendGetValues(std::shared_ptr<Node> n, const InfoHash& info_hash,
pk.pack_bin_body((const char*)tid.data(), tid.size());
pk.pack(std::string("y")); pk.pack(std::string("q"));
pk.pack(std::string("v")); pk.pack(my_v);
if (network) {
pk.pack(std::string("n")); pk.pack(network);
}
Blob b {buffer.data(), buffer.data() + buffer.size()};
std::shared_ptr<Request> req(new Request {tid.getTid(), n, std::move(b),
@@ -683,7 +664,7 @@ NetworkEngine::sendNodesValues(const sockaddr* sa, socklen_t salen, TransId tid,
const std::vector<std::shared_ptr<Value>>& st, const Blob& token) {
msgpack::sbuffer buffer;
msgpack::packer<msgpack::sbuffer> pk(&buffer);
pk.pack_map(4+(network?1:0));
pk.pack_map(4);
pk.pack(std::string("r"));
pk.pack_map(2 + (not st.empty()?1:0) + (nodes.size()>0?1:0) + (nodes6.size()>0?1:0) + (not token.empty()?1:0));
@@ -734,9 +715,6 @@ NetworkEngine::sendNodesValues(const sockaddr* sa, socklen_t salen, TransId tid,
pk.pack_bin_body((const char*)tid.data(), tid.size());
pk.pack(std::string("y")); pk.pack(std::string("r"));
pk.pack(std::string("v")); pk.pack(my_v);
if (network) {
pk.pack(std::string("n")); pk.pack(network);
}
send(buffer.data(), buffer.size(), 0, sa, salen);
}
@@ -747,7 +725,7 @@ NetworkEngine::bufferNodes(sa_family_t af, const InfoHash& id, std::vector<std::
std::sort(nodes.begin(), nodes.end(), [&](const std::shared_ptr<Node>& a, const std::shared_ptr<Node>& b){
return id.xorCmp(a->id, b->id) < 0;
});
size_t nnode = std::min<size_t>(SEND_NODES, nodes.size());
size_t nnode = std::min<size_t>(TARGET_NODES, nodes.size());
Blob bnodes;
if (af == AF_INET) {
bnodes.resize(NODE4_INFO_BUF_LEN * nnode);
@@ -799,7 +777,7 @@ NetworkEngine::sendListen(std::shared_ptr<Node> n, const InfoHash& infohash, con
auto tid = TransId {TransPrefix::LISTEN, getNewTid()};
msgpack::sbuffer buffer;
msgpack::packer<msgpack::sbuffer> pk(&buffer);
pk.pack_map(5+(network?1:0));
pk.pack_map(5);
pk.pack(std::string("a")); pk.pack_map(3);
pk.pack(std::string("id")); pk.pack(myid);
@@ -811,9 +789,7 @@ NetworkEngine::sendListen(std::shared_ptr<Node> n, const InfoHash& infohash, con
pk.pack_bin_body((const char*)tid.data(), tid.size());
pk.pack(std::string("y")); pk.pack(std::string("q"));
pk.pack(std::string("v")); pk.pack(my_v);
if (network) {
pk.pack(std::string("n")); pk.pack(network);
}
Blob b {buffer.data(), buffer.data() + buffer.size()};
std::shared_ptr<Request> req(new Request {tid.getTid(), n, std::move(b),
@@ -836,7 +812,7 @@ void
NetworkEngine::sendListenConfirmation(const sockaddr* sa, socklen_t salen, TransId tid) {
msgpack::sbuffer buffer;
msgpack::packer<msgpack::sbuffer> pk(&buffer);
pk.pack_map(4+(network?1:0));
pk.pack_map(4);
pk.pack(std::string("r")); pk.pack_map(2);
pk.pack(std::string("id")); pk.pack(myid);
@@ -846,9 +822,6 @@ NetworkEngine::sendListenConfirmation(const sockaddr* sa, socklen_t salen, Trans
pk.pack_bin_body((const char*)tid.data(), tid.size());
pk.pack(std::string("y")); pk.pack(std::string("r"));
pk.pack(std::string("v")); pk.pack(my_v);
if (network) {
pk.pack(std::string("n")); pk.pack(network);
}
send(buffer.data(), buffer.size(), 0, sa, salen);
}
@@ -859,7 +832,7 @@ NetworkEngine::sendAnnounceValue(std::shared_ptr<Node> n, const InfoHash& infoha
auto tid = TransId {TransPrefix::ANNOUNCE_VALUES, getNewTid()};
msgpack::sbuffer buffer;
msgpack::packer<msgpack::sbuffer> pk(&buffer);
pk.pack_map(5+(network?1:0));
pk.pack_map(5);
pk.pack(std::string("a")); pk.pack_map((created < scheduler.time() ? 5 : 4));
pk.pack(std::string("id")); pk.pack(myid);
@@ -876,9 +849,6 @@ NetworkEngine::sendAnnounceValue(std::shared_ptr<Node> n, const InfoHash& infoha
pk.pack_bin_body((const char*)tid.data(), tid.size());
pk.pack(std::string("y")); pk.pack(std::string("q"));
pk.pack(std::string("v")); pk.pack(my_v);
if (network) {
pk.pack(std::string("n")); pk.pack(network);
}
Blob b {buffer.data(), buffer.data() + buffer.size()};
std::shared_ptr<Request> req(new Request {tid.getTid(), n, std::move(b),
@@ -908,7 +878,7 @@ void
NetworkEngine::sendValueAnnounced(const sockaddr* sa, socklen_t salen, TransId tid, Value::Id vid) {
msgpack::sbuffer buffer;
msgpack::packer<msgpack::sbuffer> pk(&buffer);
pk.pack_map(4+(network?1:0));
pk.pack_map(4);
pk.pack(std::string("r")); pk.pack_map(3);
pk.pack(std::string("id")); pk.pack(myid);
@@ -919,9 +889,6 @@ NetworkEngine::sendValueAnnounced(const sockaddr* sa, socklen_t salen, TransId t
pk.pack_bin_body((const char*)tid.data(), tid.size());
pk.pack(std::string("y")); pk.pack(std::string("r"));
pk.pack(std::string("v")); pk.pack(my_v);
if (network) {
pk.pack(std::string("n")); pk.pack(network);
}
send(buffer.data(), buffer.size(), 0, sa, salen);
}
@@ -950,9 +917,6 @@ NetworkEngine::sendError(const sockaddr* sa,
pk.pack_bin_body((const char*)tid.data(), tid.size());
pk.pack(std::string("y")); pk.pack(std::string("e"));
pk.pack(std::string("v")); pk.pack(my_v);
if (network) {
pk.pack(std::string("n")); pk.pack(network);
}
send(buffer.data(), buffer.size(), 0, sa, salen);
}
@@ -996,9 +960,6 @@ ParsedMessage::msgpack_unpack(msgpack::object msg)
error_code = e->via.array.ptr[0].as<uint16_t>();
}
if (auto netid = findMapValue(msg, "n"))
network = netid->as<NetId>();
if (auto rid = findMapValue(req, "id"))
id = {*rid};
+3 -3
View File
@@ -141,7 +141,7 @@ SecureDht::getCertificate(const InfoHash& node) const
return it->second;
}
const std::shared_ptr<const crypto::PublicKey>
const std::shared_ptr<crypto::PublicKey>
SecureDht::getPublicKey(const InfoHash& node) const
{
if (node == getId())
@@ -226,7 +226,7 @@ SecureDht::findCertificate(const InfoHash& node, std::function<void(const std::s
}
void
SecureDht::findPublicKey(const InfoHash& node, std::function<void(const std::shared_ptr<const crypto::PublicKey>)> cb)
SecureDht::findPublicKey(const InfoHash& node, std::function<void(const std::shared_ptr<crypto::PublicKey>)> cb)
{
auto pk = getPublicKey(node);
if (pk && *pk) {
@@ -342,7 +342,7 @@ SecureDht::putSigned(const InfoHash& hash, std::shared_ptr<Value> val, DoneCallb
void
SecureDht::putEncrypted(const InfoHash& hash, const InfoHash& to, std::shared_ptr<Value> val, DoneCallback callback, bool permanent)
{
findPublicKey(to, [=](const std::shared_ptr<const crypto::PublicKey> pk) {
findPublicKey(to, [=](const std::shared_ptr<crypto::PublicKey> pk) {
if(!pk || !*pk) {
if (callback)
callback(false, {});
+2 -3
View File
@@ -142,9 +142,8 @@ Value::msgpack_unpack_body(const msgpack::object& o)
seq = rseq->as<decltype(seq)>();
else
throw msgpack::type_error();
crypto::PublicKey new_owner;
new_owner.msgpack_unpack(*rowner);
owner = std::make_shared<const crypto::PublicKey>(std::move(new_owner));
owner = std::make_shared<crypto::PublicKey>();
owner->msgpack_unpack(*rowner);
if (auto rrecipient = findMapValue(*rbody, "to")) {
recipient = rrecipient->as<InfoHash>();
}
+1 -1
View File
@@ -53,7 +53,7 @@ main(int argc, char **argv)
throw std::runtime_error(std::string("Error initializing GnuTLS: ")+gnutls_strerror(rc));
DhtRunner dht;
dht.run(params.port, dht::crypto::generateIdentity("DHT Chat Node"), true, params.network);
dht.run(params.port, dht::crypto::generateIdentity("DHT Chat Node"), true);
if (not params.bootstrap.first.empty())
dht.bootstrap(params.bootstrap.first.c_str(), params.bootstrap.second.c_str());
+2 -2
View File
@@ -29,7 +29,7 @@ extern "C" {
using namespace dht;
void print_usage() {
std::cout << "Usage: dhtnode [-v[logfile]] [-i] [-d] [-n network_id] [-p local_port] [-b[bootstrap_host[:port]]]" << std::endl << std::endl;
std::cout << "Usage: dhtnode [-p local_port] [-b bootstrap_host:port]" << std::endl << std::endl;
std::cout << "dhtnode, a simple OpenDHT command line node runner." << std::endl;
std::cout << "Report bugs to: http://opendht.net" << std::endl;
}
@@ -256,7 +256,7 @@ main(int argc, char **argv)
crt = dht::crypto::generateIdentity("DHT Node", ca_tmp);
}
dht.run(params.port, crt, true, params.network);
dht.run(params.port, crt, true, params.is_bootstrap_node);
if (params.log) {
if (not params.logfile.empty())
+1 -1
View File
@@ -80,7 +80,7 @@ main(int argc, char **argv)
auto crt_tmp = dht::crypto::generateIdentity("Scanner node", ca_tmp);
DhtRunner dht;
dht.run(params.port, crt_tmp, true, params.network);
dht.run(params.port, crt_tmp, true, [](dht::NodeStatus /* ipv4 */, dht::NodeStatus /* ipv6 */) {});
if (not params.bootstrap.first.empty())
dht.bootstrap(params.bootstrap.first.c_str(), params.bootstrap.second.c_str());
+18 -12
View File
@@ -142,7 +142,6 @@ struct dht_params {
bool log {false};
std::string logfile {};
in_port_t port {0};
dht::NetId network {0};
bool is_bootstrap_node {false};
bool generate_identity {false};
bool daemonize {false};
@@ -152,10 +151,9 @@ struct dht_params {
static const constexpr struct option long_options[] = {
{"help", no_argument, nullptr, 'h'},
{"port", required_argument, nullptr, 'p'},
{"net", required_argument, nullptr, 'n'},
{"bootstrap", optional_argument, nullptr, 'b'},
{"identity", no_argument , nullptr, 'i'},
{"verbose", optional_argument, nullptr, 'v'},
{"verbose", no_argument , nullptr, 'v'},
{"daemonize", no_argument , nullptr, 'd'},
{nullptr, 0, nullptr, 0}
};
@@ -164,19 +162,16 @@ dht_params
parseArgs(int argc, char **argv) {
dht_params params;
int opt;
while ((opt = getopt_long(argc, argv, "hidv::p:n:b::", long_options, nullptr)) != -1) {
while ((opt = getopt_long(argc, argv, ":hidv:p:b:", long_options, nullptr)) != -1) {
switch (opt) {
case 'p': {
int port_arg = atoi(optarg);
if (port_arg >= 0 && port_arg < 0x10000)
params.port = port_arg;
else
std::cerr << "Invalid port: " << port_arg << std::endl;
std::cout << "Invalid port: " << port_arg << std::endl;
}
break;
case 'n':
params.network = strtoul(optarg, nullptr, 0);
break;
case 'b':
if (optarg) {
params.bootstrap = splitPort((optarg[0] == '=') ? optarg+1 : optarg);
@@ -185,7 +180,8 @@ parseArgs(int argc, char **argv) {
ss << DHT_DEFAULT_PORT;
params.bootstrap.second = ss.str();
}
} else
}
else
params.is_bootstrap_node = true;
break;
case 'h':
@@ -202,9 +198,19 @@ parseArgs(int argc, char **argv) {
case 'd':
params.daemonize = true;
break;
case '?':
std::cerr << "unrecognized option -- '" << static_cast<char>(optopt) << '\'' << std::endl;
exit(EXIT_FAILURE);
case ':':
switch (optopt) {
case 'b':
params.is_bootstrap_node = true;
break;
case 'v':
params.log = true;
break;
default:
std::cout << "option requires an argument -- '" << optopt << '\'' << std::endl;
break;
}
break;
default:
break;
}