Initial work on Broadcast Domain Discovery

Discover peers on the same broadcast domain/LAN
Implements own node announcement
Implements others announcement listening
Implements API to get notifiend when other nodes get discovered
Implements API to get discovered nodes
Add discovered peer locator to rsPeers if it is already friend

Yet a bunch of things to do to take full advantage of this new
implementation
This commit is contained in:
Gioacchino Mazzurco 2019-04-12 02:53:39 +02:00
parent 276328dd91
commit 7b38c1c75a
No known key found for this signature in database
GPG key ID: A1FBCA3872E87051
15 changed files with 583 additions and 70 deletions

4
.gitmodules vendored
View file

@ -7,3 +7,7 @@
[submodule "build_scripts/OBS"] [submodule "build_scripts/OBS"]
path = build_scripts/OBS path = build_scripts/OBS
url = https://github.com/RetroShare/OBS.git url = https://github.com/RetroShare/OBS.git
[submodule "supportlibs/udp-discovery-cpp"]
path = supportlibs/udp-discovery-cpp
url = https://github.com/truvorskameikin/udp-discovery-cpp.git
branch = develop

View file

@ -40,6 +40,9 @@ define_default_value QT_ANDROID_INSTALLER_SHA256 a214084e2295c9a9f8727e8a0131c37
define_default_value RESTBED_SOURCE_VERSION "4.6" define_default_value RESTBED_SOURCE_VERSION "4.6"
define_default_value UDP_DISCOVERY_CPP_SOURCE "https://github.com/truvorskameikin/udp-discovery-cpp.git"
define_default_value UDP_DISCOVERY_CPP_VERSION "develop"
define_default_value XAPIAN_SOURCE_VERSION "1.4.7" define_default_value XAPIAN_SOURCE_VERSION "1.4.7"
define_default_value XAPIAN_SOURCE_SHA256 13f08a0b649c7afa804fa0e85678d693fd6069dd394c9b9e7d41973d74a3b5d3 define_default_value XAPIAN_SOURCE_SHA256 13f08a0b649c7afa804fa0e85678d693fd6069dd394c9b9e7d41973d74a3b5d3
@ -203,7 +206,7 @@ build_bzlib()
rm -rf $B_dir rm -rf $B_dir
verified_download $B_dir.tar.gz $BZIP2_SOURCE_SHA256 \ verified_download $B_dir.tar.gz $BZIP2_SOURCE_SHA256 \
http://trumpetti.atm.tut.fi/gentoo/distfiles/bzip2-${BZIP2_SOURCE_VERSION}.tar.gz http://distfiles.gentoo.org/distfiles/bzip2-${BZIP2_SOURCE_VERSION}.tar.gz
tar -xf $B_dir.tar.gz tar -xf $B_dir.tar.gz
cd $B_dir cd $B_dir
@ -342,6 +345,23 @@ build_restbed()
cd .. cd ..
} }
build_udp-discovery-cpp()
{
S_dir="udp-discovery-cpp"
[ -d $S_dir ] || git clone $UDP_DISCOVERY_CPP_SOURCE $S_dir
cd $S_dir
git checkout $UDP_DISCOVERY_CPP_VERSION
cd ..
B_dir="udp-discovery-cpp-build"
rm -rf ${B_dir}; mkdir ${B_dir}; cd ${B_dir}
cmake -DCMAKE_INSTALL_PREFIX="${PREFIX}" -B. -H../udp-discovery-cpp
make -j${HOST_NUM_CPU}
cp libudp-discovery.a "${PREFIX}/lib/"
cp ../$S_dir/*.hpp "${PREFIX}/include/"
cd ..
}
build_xapian() build_xapian()
{ {
B_dir="xapian-core-${XAPIAN_SOURCE_VERSION}" B_dir="xapian-core-${XAPIAN_SOURCE_VERSION}"
@ -372,6 +392,7 @@ build_sqlcipher
build_libupnp build_libupnp
build_rapidjson build_rapidjson
build_restbed build_restbed
build_udp-discovery-cpp
build_xapian build_xapian
delete_copied_includes delete_copied_includes

View file

@ -1,20 +1,22 @@
/* /*******************************************************************************
* RetroShare JSON API * RetroShare JSON API *
* Copyright (C) 2018 Gioacchino Mazzurco <gio@eigenlab.org> * *
* * Copyright (C) 2018-2019 Gioacchino Mazzurco <gio@eigenlab.org> *
* This program is free software: you can redistribute it and/or modify * *
* it under the terms of the GNU Affero General Public License as * This program is free software: you can redistribute it and/or modify *
* published by the Free Software Foundation, either version 3 of the * it under the terms of the GNU Affero General Public License as *
* License, or (at your option) any later version. * 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 * This program is distributed in the hope that it will be useful, *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * but WITHOUT ANY WARRANTY; without even the implied warranty of *
* GNU Affero General Public License for more details. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
* * GNU Affero General Public License for more details. *
* You should have received a copy of the GNU Affero General Public License * *
* along with this program. If not, see <http://www.gnu.org/licenses/>. * You should have received a copy of the GNU Affero General Public License *
*/ * along with this program. If not, see <http://www.gnu.org/licenses/>. *
* *
*******************************************************************************/
#include <QtCore/QCoreApplication> #include <QtCore/QCoreApplication>
#include <QtCore/QDebug> #include <QtCore/QDebug>

View file

@ -1,21 +1,20 @@
/******************************************************************************* /*******************************************************************************
* libretroshare/src/gxs: jsonapi.cpp *
* *
* RetroShare JSON API * * RetroShare JSON API *
* Copyright (C) 2018 Gioacchino Mazzurco <gio@eigenlab.org> * * *
* Copyright (C) 2018-2019 Gioacchino Mazzurco <gio@eigenlab.org> *
* * * *
* This program is free software: you can redistribute it and/or modify * * This program is free software: you can redistribute it and/or modify *
* it under the terms of the GNU Lesser General Public License as * * it under the terms of the GNU Affero General Public License as *
* published by the Free Software Foundation, either version 3 of the * * published by the Free Software Foundation, either version 3 of the *
* License, or (at your option) any later version. * * License, or (at your option) any later version. *
* * * *
* This program is distributed in the hope that it will be useful, * * This program is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY; without even the implied warranty of * * but WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
* GNU Lesser General Public License for more details. * * GNU Affero General Public License for more details. *
* * * *
* You should have received a copy of the GNU Lesser General Public License * * You should have received a copy of the GNU Affero General Public License *
* along with this program. If not, see <https://www.gnu.org/licenses/>. * * along with this program. If not, see <http://www.gnu.org/licenses/>. *
* * * *
*******************************************************************************/ *******************************************************************************/
@ -96,7 +95,7 @@ JsonApiServer::corsOptionsHeaders =
/*static*/ bool JsonApiServer::checkRsServicePtrReady( /*static*/ bool JsonApiServer::checkRsServicePtrReady(
void* serviceInstance, const std::string& serviceName, const void* serviceInstance, const std::string& serviceName,
RsGenericSerializer::SerializeContext& ctx, RsGenericSerializer::SerializeContext& ctx,
const std::shared_ptr<restbed::Session> session) const std::shared_ptr<restbed::Session> session)
{ {

View file

@ -1,24 +1,22 @@
/******************************************************************************* /*******************************************************************************
* libretroshare/src/gxs: jsonapi.h *
* *
* RetroShare JSON API * * RetroShare JSON API *
* Copyright (C) 2018 Gioacchino Mazzurco <gio@eigenlab.org> * * *
* Copyright (C) 2018-2019 Gioacchino Mazzurco <gio@eigenlab.org> *
* * * *
* This program is free software: you can redistribute it and/or modify * * This program is free software: you can redistribute it and/or modify *
* it under the terms of the GNU Lesser General Public License as * * it under the terms of the GNU Affero General Public License as *
* published by the Free Software Foundation, either version 3 of the * * published by the Free Software Foundation, either version 3 of the *
* License, or (at your option) any later version. * * License, or (at your option) any later version. *
* * * *
* This program is distributed in the hope that it will be useful, * * This program is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY; without even the implied warranty of * * but WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
* GNU Lesser General Public License for more details. * * GNU Affero General Public License for more details. *
* * * *
* You should have received a copy of the GNU Lesser General Public License * * You should have received a copy of the GNU Affero General Public License *
* along with this program. If not, see <https://www.gnu.org/licenses/>. * * along with this program. If not, see <http://www.gnu.org/licenses/>. *
* * * *
*******************************************************************************/ *******************************************************************************/
#pragma once #pragma once
#include <string> #include <string>
@ -199,8 +197,18 @@ private:
static void handleCorsOptions(const std::shared_ptr<rb::Session> session); static void handleCorsOptions(const std::shared_ptr<rb::Session> session);
static bool checkRsServicePtrReady( static bool checkRsServicePtrReady(
void* serviceInstance, const std::string& serviceName, const void* serviceInstance, const std::string& serviceName,
RsGenericSerializer::SerializeContext& ctx, RsGenericSerializer::SerializeContext& ctx,
const std::shared_ptr<restbed::Session> session ); const std::shared_ptr<restbed::Session> session );
static inline bool checkRsServicePtrReady(
const std::shared_ptr<const void> serviceInstance,
const std::string& serviceName,
RsGenericSerializer::SerializeContext& ctx,
const std::shared_ptr<restbed::Session> session )
{
return checkRsServicePtrReady(
serviceInstance.get(), serviceName, ctx, session );
}
}; };

View file

@ -1,21 +1,20 @@
/******************************************************************************* /*******************************************************************************
* libretroshare/src/gxs: jsonapiitems.h *
* *
* RetroShare JSON API * * RetroShare JSON API *
* Copyright (C) 2018 Gioacchino Mazzurco <gio@eigenlab.org> * * *
* Copyright (C) 2018-2019 Gioacchino Mazzurco <gio@eigenlab.org> *
* * * *
* This program is free software: you can redistribute it and/or modify * * This program is free software: you can redistribute it and/or modify *
* it under the terms of the GNU Lesser General Public License as * * it under the terms of the GNU Affero General Public License as *
* published by the Free Software Foundation, either version 3 of the * * published by the Free Software Foundation, either version 3 of the *
* License, or (at your option) any later version. * * License, or (at your option) any later version. *
* * * *
* This program is distributed in the hope that it will be useful, * * This program is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY; without even the implied warranty of * * but WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
* GNU Lesser General Public License for more details. * * GNU Affero General Public License for more details. *
* * * *
* You should have received a copy of the GNU Lesser General Public License * * You should have received a copy of the GNU Affero General Public License *
* along with this program. If not, see <https://www.gnu.org/licenses/>. * * along with this program. If not, see <http://www.gnu.org/licenses/>. *
* * * *
*******************************************************************************/ *******************************************************************************/

View file

@ -865,21 +865,24 @@ rs_jsonapi {
DUMMYRESTBEDINPUT = FORCE DUMMYRESTBEDINPUT = FORCE
CMAKE_GENERATOR_OVERRIDE="" CMAKE_GENERATOR_OVERRIDE=""
win32-g++:CMAKE_GENERATOR_OVERRIDE="-G \"MSYS Makefiles\"" win32-g++:CMAKE_GENERATOR_OVERRIDE="-G \"MSYS Makefiles\""
genrestbedlib.name = Generating libresbed. genrestbedlib.name = Generating librestbed.
genrestbedlib.input = DUMMYRESTBEDINPUT genrestbedlib.input = DUMMYRESTBEDINPUT
genrestbedlib.output = $$clean_path($${RESTBED_BUILD_PATH}/librestbed.a) genrestbedlib.output = $$clean_path($${RESTBED_BUILD_PATH}/librestbed.a)
genrestbedlib.CONFIG += target_predeps combine genrestbedlib.CONFIG += target_predeps combine
genrestbedlib.variable_out = PRE_TARGETDEPS genrestbedlib.variable_out = PRE_TARGETDEPS
genrestbedlib.commands = \ genrestbedlib.commands = \
cd $${RS_SRC_PATH} && \ cd $${RS_SRC_PATH} && ( \
git submodule update --init --recommend-shallow supportlibs/restbed && \ git submodule update --init --recommend-shallow supportlibs/restbed ; \
cd $${RESTBED_SRC_PATH} && \ cd $${RESTBED_SRC_PATH} ; \
git submodule update --init --recommend-shallow dependency/asio && \ git submodule update --init --recommend-shallow dependency/asio ; \
git submodule update --init --recommend-shallow dependency/catch && \ git submodule update --init --recommend-shallow dependency/catch ; \
git submodule update --init --recommend-shallow dependency/kashmir && \ git submodule update --init --recommend-shallow dependency/kashmir ; \
mkdir -p $${RESTBED_BUILD_PATH}; cd $${RESTBED_BUILD_PATH} && \ true ) && \
cmake -DCMAKE_CXX_COMPILER=$$QMAKE_CXX $${CMAKE_GENERATOR_OVERRIDE} -DBUILD_SSL=OFF \ mkdir -p $${RESTBED_BUILD_PATH} && cd $${RESTBED_BUILD_PATH} && \
-DCMAKE_INSTALL_PREFIX=. -B. -H$$shell_path($${RESTBED_SRC_PATH}) && \ cmake -DCMAKE_CXX_COMPILER=$$QMAKE_CXX \
$${CMAKE_GENERATOR_OVERRIDE} -DBUILD_SSL=OFF \
-DCMAKE_INSTALL_PREFIX=. -B. \
-H$$shell_path($${RESTBED_SRC_PATH}) && \
make make
QMAKE_EXTRA_COMPILERS += genrestbedlib QMAKE_EXTRA_COMPILERS += genrestbedlib
@ -925,6 +928,36 @@ rs_deep_search {
HEADERS += deep_search/deep_search.h HEADERS += deep_search/deep_search.h
} }
rs_broadcast_discovery {
HEADERS += retroshare/rsbroadcastdiscovery.h \
services/broadcastdiscoveryservice.h
SOURCES += services/broadcastdiscoveryservice.cc
no_rs_cross_compiling {
DUMMYQMAKECOMPILERINPUT = FORCE
CMAKE_GENERATOR_OVERRIDE=""
win32-g++:CMAKE_GENERATOR_OVERRIDE="-G \"MSYS Makefiles\""
udpdiscoverycpplib.name = Generating libudp-discovery.a.
udpdiscoverycpplib.input = DUMMYQMAKECOMPILERINPUT
udpdiscoverycpplib.output = $$clean_path($${UDP_DISCOVERY_BUILD_PATH}/libudp-discovery.a)
udpdiscoverycpplib.CONFIG += target_predeps combine
udpdiscoverycpplib.variable_out = PRE_TARGETDEPS
udpdiscoverycpplib.commands = \
cd $${RS_SRC_PATH} && ( \
git submodule update --init --recommend-shallow supportlibs/udp-discovery-cpp || \
true ) && \
mkdir -p $${UDP_DISCOVERY_BUILD_PATH} && \
cd $${UDP_DISCOVERY_BUILD_PATH} && \
cmake -DCMAKE_CXX_COMPILER=$$QMAKE_CXX \
$${CMAKE_GENERATOR_OVERRIDE} \
-DBUILD_EXAMPLE=OFF -DBUILD_TOOL=OFF \
-DCMAKE_INSTALL_PREFIX=. -B. \
-H$$shell_path($${UDP_DISCOVERY_SRC_PATH}) && \
make
QMAKE_EXTRA_COMPILERS += udpdiscoverycpplib
}
}
########################################################################################################### ###########################################################################################################
# OLD CONFIG OPTIONS. # OLD CONFIG OPTIONS.
# Not used much - but might be useful one day. # Not used much - but might be useful one day.

View file

@ -0,0 +1,87 @@
/*******************************************************************************
* RetroShare Broadcast Domain Discovery *
* *
* Copyright (C) 2019 Gioacchino Mazzurco <gio@altermundi.net> *
* *
* This program is free software: you can redistribute it and/or modify *
* it under the terms of the GNU Affero 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 Affero General Public License for more details. *
* *
* You should have received a copy of the GNU Affero General Public License *
* along with this program. If not, see <http://www.gnu.org/licenses/>. *
* *
*******************************************************************************/
#pragma once
#include <functional>
#include <memory>
#include <vector>
#include <string>
#include "retroshare/rsids.h"
#include "retroshare/rstypes.h"
#include "serialiser/rsserializable.h"
#include "util/rstime.h"
#include "util/rsurl.h"
#include "util/rsmemory.h"
class RsBroadcastDiscovery;
/**
* Pointer to global instance of RsBroadcastDiscovery service implementation
* @jsonapi{development}
*/
extern std::shared_ptr<RsBroadcastDiscovery> rsBroadcastDiscovery;
struct RsBroadcastDiscoveryResult : RsSerializable
{
PGPFingerprintType mPgpFingerprint;
RsPeerId mSslId;
std::string mProfileName;
RsUrl locator;
void serial_process( RsGenericSerializer::SerializeJob j,
RsGenericSerializer::SerializeContext& ctx) override
{
RS_SERIAL_PROCESS(mPgpFingerprint);
RS_SERIAL_PROCESS(mSslId);
RS_SERIAL_PROCESS(mProfileName);
RS_SERIAL_PROCESS(locator);
}
};
class RsBroadcastDiscovery
{
public:
virtual ~RsBroadcastDiscovery();
/**
* @brief Get potential peers that have been discovered up until now
* @jsonapi{development}
* @return vector containing discovered peers, may be empty.
*/
virtual std::vector<RsBroadcastDiscoveryResult> getDiscoveredPeers() = 0;
/**
* @brief registerPeersDiscoveredEventHandler
* @jsonapi{development}
* @param multiCallback function that will be called each time a potential
* peer is discovered
* @param[in] maxWait maximum wait time in seconds for discovery results,
* passing std::numeric_limits<rstime_t>::max() means wait forever.
* @param[out] errorMessage Optional storage for error message, meaningful
* only on failure.
* @return false on error, true otherwise
*/
virtual bool registerPeersDiscoveredEventHandler(
const std::function<void (const RsBroadcastDiscoveryResult& result)>&
multiCallback,
rstime_t maxWait = 300,
std::string& errorMessage = RS_DEFAULT_STORAGE_PARAM(std::string) ) = 0;
};

View file

@ -34,7 +34,7 @@
#ifdef __ANDROID__ #ifdef __ANDROID__
# include <QFile> // To install bdboot.txt # include <QFile> // To install bdboot.txt
# include <QString> // for String::fromStdString(...) # include <QString> // for QString::fromStdString(...)
#endif #endif
#include "util/argstream.h" #include "util/argstream.h"
@ -98,6 +98,11 @@ RsDht *rsDht = NULL ;
# include "jsonapi/jsonapi.h" # include "jsonapi/jsonapi.h"
#endif #endif
#ifdef RS_BROADCAST_DISCOVERY
# include "retroshare/rsbroadcastdiscovery.h"
# include "services/broadcastdiscoveryservice.h"
#endif // def RS_BROADCAST_DISCOVERY
// #define GPG_DEBUG // #define GPG_DEBUG
// #define AUTHSSL_DEBUG // #define AUTHSSL_DEBUG
// #define FIM_DEBUG // #define FIM_DEBUG
@ -1462,6 +1467,12 @@ int RsServer::StartupRetroShare()
mHistoryMgr, *mGxsTrans ); mHistoryMgr, *mGxsTrans );
mStatusSrv = new p3StatusService(serviceCtrl); mStatusSrv = new p3StatusService(serviceCtrl);
#ifdef RS_BROADCAST_DISCOVERY
rsBroadcastDiscovery.reset(new BroadcastDiscoveryService(*rsPeers));
BroadcastDiscoveryService& tBroadcastDiscoveryService =
static_cast<BroadcastDiscoveryService&>(*rsBroadcastDiscovery);
#endif // def RS_BROADCAST_DISCOVERY
#ifdef ENABLE_GROUTER #ifdef ENABLE_GROUTER
p3GRouter *gr = new p3GRouter(serviceCtrl,mGxsIdService) ; p3GRouter *gr = new p3GRouter(serviceCtrl,mGxsIdService) ;
rsGRouter = gr ; rsGRouter = gr ;
@ -1863,10 +1874,14 @@ int RsServer::StartupRetroShare()
# ifdef RS_GXS_TRANS # ifdef RS_GXS_TRANS
startServiceThread(mGxsTrans, "gxs trans"); startServiceThread(mGxsTrans, "gxs trans");
startServiceThread(gxstrans_ns, "gxs trans ns"); startServiceThread(gxstrans_ns, "gxs trans ns");
# endif // RS_GXS_TRANS # endif // def RS_GXS_TRANS
#endif // RS_ENABLE_GXS #endif // RS_ENABLE_GXS
#ifdef RS_BROADCAST_DISCOVERY
startServiceThread(&tBroadcastDiscoveryService, "Broadcast Discovery");
#endif // def RS_BROADCAST_DISCOVERY
ftserver->StartupThreads(); ftserver->StartupThreads();
ftserver->ResumeTransfers(); ftserver->ResumeTransfers();

View file

@ -0,0 +1,237 @@
/*******************************************************************************
* RetroShare Broadcast Domain Discovery *
* *
* Copyright (C) 2019 Gioacchino Mazzurco <gio@altermundi.net> *
* *
* This program is free software: you can redistribute it and/or modify *
* it under the terms of the GNU Affero 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 Affero General Public License for more details. *
* *
* You should have received a copy of the GNU Affero General Public License *
* along with this program. If not, see <http://www.gnu.org/licenses/>. *
* *
*******************************************************************************/
#include <functional>
#include <set>
#include <thread>
#include <chrono>
#include <vector>
#include <iostream>
#include "services/broadcastdiscoveryservice.h"
#include "retroshare/rspeers.h"
#include "serialiser/rsserializable.h"
#include "serialiser/rsserializer.h"
/*extern*/ std::shared_ptr<RsBroadcastDiscovery> rsBroadcastDiscovery(nullptr);
RsBroadcastDiscovery::~RsBroadcastDiscovery() { /* Beware of Rs prefix! */ }
struct BroadcastDiscoveryPack : RsSerializable
{
BroadcastDiscoveryPack() : mLocalPort(0) {}
PGPFingerprintType mPgpFingerprint;
RsPeerId mSslId;
uint16_t mLocalPort;
std::string mProfileName;
void serial_process( RsGenericSerializer::SerializeJob j,
RsGenericSerializer::SerializeContext& ctx ) override
{
RS_SERIAL_PROCESS(mPgpFingerprint);
RS_SERIAL_PROCESS(mSslId);
RS_SERIAL_PROCESS(mLocalPort);
RS_SERIAL_PROCESS(mProfileName);
}
static BroadcastDiscoveryPack fromPeerDetails(const RsPeerDetails& pd)
{
BroadcastDiscoveryPack bdp;
bdp.mPgpFingerprint = pd.fpr;
bdp.mSslId = pd.id;
bdp.mLocalPort = pd.localPort;
bdp.mProfileName = pd.name;
return bdp;
}
static BroadcastDiscoveryPack fromSerializedString(const std::string& st)
{
RsGenericSerializer::SerializeContext ctx(
reinterpret_cast<uint8_t*>(const_cast<char*>(st.data())),
static_cast<uint32_t>(st.size()) );
BroadcastDiscoveryPack bdp;
bdp.serial_process(RsGenericSerializer::DESERIALIZE, ctx);
return bdp;
}
std::string serializeToString()
{
/* After some experiments it seems very unlikely that UDP broadcast
* packets bigger then this could get trought a network */
std::vector<uint8_t> buffer(512, 0);
RsGenericSerializer::SerializeContext ctx(
buffer.data(), static_cast<uint32_t>(buffer.size()) );
serial_process(RsGenericSerializer::SERIALIZE, ctx);
return std::string(reinterpret_cast<char*>(buffer.data()), ctx.mOffset);
}
};
BroadcastDiscoveryService::BroadcastDiscoveryService(
RsPeers& pRsPeers ) :
mDiscoveredDataMutex("BroadcastDiscoveryService discovered data mutex"),
mRsPeers(pRsPeers),
mPeersDiscoveredEventHandlersListMutex(
"BroadcastDiscoveryService event handlers mutex" )
{
if(mRsPeers.isHiddenNode(mRsPeers.getOwnId())) return;
mUdcParameters.set_can_discover(true);
mUdcParameters.set_can_be_discovered(true);
mUdcParameters.set_port(port);
mUdcParameters.set_application_id(appId);
mUdcEndpoint.Start(mUdcParameters, "");
updatePublishedData();
}
BroadcastDiscoveryService::~BroadcastDiscoveryService()
{ mUdcEndpoint.Stop(true); }
std::vector<RsBroadcastDiscoveryResult>
BroadcastDiscoveryService::getDiscoveredPeers()
{
std::vector<RsBroadcastDiscoveryResult> ret;
RS_STACK_MUTEX(mDiscoveredDataMutex);
for(auto&& pp: mDiscoveredData)
ret.push_back(createResult(pp.first, pp.second));
return ret;
}
void BroadcastDiscoveryService::updatePublishedData()
{
RsPeerDetails od;
mRsPeers.getPeerDetails(mRsPeers.getOwnId(), od);
mUdcEndpoint.SetUserData(
BroadcastDiscoveryPack::fromPeerDetails(od).serializeToString());
}
void BroadcastDiscoveryService::data_tick()
{
auto nextRunAt = std::chrono::system_clock::now() + std::chrono::seconds(5);
if( mUdcParameters.can_discover() &&
!mRsPeers.isHiddenNode(mRsPeers.getOwnId()) )
{
auto newEndpoints = mUdcEndpoint.ListDiscovered();
std::set< std::pair<UDC::IpPort, std::string> > mChangedData;
mDiscoveredDataMutex.lock();
for(auto&& dEndpoint: newEndpoints)
{
auto findIt = mDiscoveredData.find(dEndpoint.ip_port());
if( !dEndpoint.user_data().empty() && (
findIt == mDiscoveredData.end() ||
(*findIt).second != dEndpoint.user_data() ) )
{
mDiscoveredData[dEndpoint.ip_port()] = dEndpoint.user_data();
mChangedData.insert(std::make_pair(
dEndpoint.ip_port(),
dEndpoint.user_data() ));
}
}
mDiscoveredDataMutex.unlock();
cleanTimedOutEventHandlers();
mPeersDiscoveredEventHandlersListMutex.lock();
if(!mChangedData.empty() && !mPeersDiscoveredEventHandlersList.empty())
{
for (auto&& pp : mChangedData)
{
std::cout << __PRETTY_FUNCTION__ << " Got: >>>" << pp.second
<< "<<< from: " << UDC::IpToString(pp.first.ip())
<< std::endl;
RsBroadcastDiscoveryResult rbdr =
createResult(pp.first, pp.second);
mRsPeers.addPeerLocator(rbdr.mSslId, rbdr.locator);
for( const timedDiscHandlers_t& evtHandler :
mPeersDiscoveredEventHandlersList ) evtHandler.first(rbdr);
}
}
mPeersDiscoveredEventHandlersListMutex.unlock();
}
/* Probably this would be better if done only on actual change */
if( mUdcParameters.can_be_discovered() &&
!mRsPeers.isHiddenNode(mRsPeers.getOwnId()) ) updatePublishedData();
std::this_thread::sleep_until(nextRunAt);
}
RsBroadcastDiscoveryResult BroadcastDiscoveryService::createResult(
const udpdiscovery::IpPort& ipp, const std::string& uData )
{
BroadcastDiscoveryPack bdp =
BroadcastDiscoveryPack::fromSerializedString(uData);
RsBroadcastDiscoveryResult rbdr;
rbdr.mPgpFingerprint = bdp.mPgpFingerprint;
rbdr.mSslId = bdp.mSslId;
rbdr.mProfileName = bdp.mProfileName;
rbdr.locator.
setScheme("ipv4").
setHost(UDC::IpToString(ipp.ip())).
setPort(static_cast<uint16_t>(ipp.port()) );
return rbdr;
}
void BroadcastDiscoveryService::cleanTimedOutEventHandlers()
{
auto now = std::chrono::system_clock::now();
RS_STACK_MUTEX(mPeersDiscoveredEventHandlersListMutex);
mPeersDiscoveredEventHandlersList.remove_if(
[&](timedDiscHandlers_t h) { return h.second <= now; } );
}
bool BroadcastDiscoveryService::registerPeersDiscoveredEventHandler(
const std::function<void (const RsBroadcastDiscoveryResult&)>&
multiCallback, rstime_t maxWait, std::string& errorMessage )
{
auto now = std::chrono::system_clock::now();
auto timeout = std::chrono::system_clock::time_point::max();
if(maxWait != std::numeric_limits<rstime_t>::max())
timeout = now + std::chrono::seconds(maxWait);
if(timeout <= now)
{
errorMessage = " Invalid maxWait value: " + std::to_string(maxWait) +
" either too big or too little, use: " +
"std::numeric_limits<rstime_t>::max() == " +
std::to_string(std::numeric_limits<rstime_t>::max()) +
" if you meant \"wait forever\"";
std::cerr << __PRETTY_FUNCTION__ << errorMessage << std::endl;
return false;
}
RS_STACK_MUTEX(mPeersDiscoveredEventHandlersListMutex);
mPeersDiscoveredEventHandlersList.push_front(
std::make_pair(multiCallback,timeout) );
return true;
}

View file

@ -0,0 +1,83 @@
/*******************************************************************************
* RetroShare Broadcast Domain Discovery *
* *
* Copyright (C) 2019 Gioacchino Mazzurco <gio@altermundi.net> *
* *
* This program is free software: you can redistribute it and/or modify *
* it under the terms of the GNU Affero 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 Affero General Public License for more details. *
* *
* You should have received a copy of the GNU Affero General Public License *
* along with this program. If not, see <http://www.gnu.org/licenses/>. *
* *
*******************************************************************************/
#pragma once
#include <cstdint>
#include <map>
#include <iostream>
#include <endpoint.hpp>
#include <memory>
#include <forward_list>
#include "retroshare/rsbroadcastdiscovery.h"
#include "util/rsthreads.h"
namespace UDC = udpdiscovery;
class RsPeers;
class BroadcastDiscoveryService :
public RsBroadcastDiscovery, public RsTickingThread
{
public:
// TODO: std::shared_ptr<RsPeers> mRsPeers;
BroadcastDiscoveryService(RsPeers& pRsPeers);
virtual ~BroadcastDiscoveryService() override;
/// @see RsBroadcastDiscovery
std::vector<RsBroadcastDiscoveryResult> getDiscoveredPeers() override;
/// @see RsBroadcastDiscovery
bool registerPeersDiscoveredEventHandler(
const std::function<void (const RsBroadcastDiscoveryResult&)>&
multiCallback,
rstime_t maxWait = 300,
std::string& errorMessage = RS_DEFAULT_STORAGE_PARAM(std::string)
) override;
/// @see RsTickingThread
void data_tick() override;
protected:
constexpr static uint16_t port = 36405;
constexpr static uint32_t appId = 904571;
void updatePublishedData();
UDC::EndpointParameters mUdcParameters;
UDC::Endpoint mUdcEndpoint;
std::map<UDC::IpPort, std::string> mDiscoveredData;
RsMutex mDiscoveredDataMutex;
RsPeers& mRsPeers; // TODO: std::shared_ptr<RsPeers> mRsPeers;
typedef std::pair<
std::function<void (const RsBroadcastDiscoveryResult&)>,
std::chrono::system_clock::time_point > timedDiscHandlers_t;
/** Store peer discovered event handlers with timeout */
std::forward_list<timedDiscHandlers_t> mPeersDiscoveredEventHandlersList;
RsMutex mPeersDiscoveredEventHandlersListMutex;
/// Cleanup mPeersDiscoveredEventHandlersList
void cleanTimedOutEventHandlers();
RsBroadcastDiscoveryResult createResult(
const UDC::IpPort& ipp, const std::string& uData );
};

View file

@ -15,13 +15,16 @@
# You should have received a copy of the GNU Lesser General Public License # # You should have received a copy of the GNU Lesser General Public License #
# along with this program. If not, see <https://www.gnu.org/licenses/>. # # along with this program. If not, see <https://www.gnu.org/licenses/>. #
################################################################################ ################################################################################
DEPENDPATH *= $$clean_path($${PWD}/../../libretroshare/src/) RS_SRC_PATH=$$clean_path($${PWD}/../../)
INCLUDEPATH *= $$clean_path($${PWD}/../../libretroshare/src) RS_BUILD_PATH=$$clean_path($${OUT_PWD}/../../)
LIBS *= -L$$clean_path($${OUT_PWD}/../../libretroshare/src/lib/) -lretroshare
DEPENDPATH *= $$clean_path($${RS_SRC_PATH}/libretroshare/src/)
INCLUDEPATH *= $$clean_path($${RS_SRC_PATH}/libretroshare/src)
LIBS *= -L$$clean_path($${RS_BUILD_PATH}/libretroshare/src/lib/) -lretroshare
equals(TARGET, retroshare):equals(TEMPLATE, lib){ equals(TARGET, retroshare):equals(TEMPLATE, lib){
} else { } else {
PRE_TARGETDEPS *= $$clean_path($$OUT_PWD/../../libretroshare/src/lib/libretroshare.a) PRE_TARGETDEPS *= $$clean_path($${RS_BUILD_PATH}/libretroshare/src/lib/libretroshare.a)
} }
!include("../../openpgpsdk/src/use_openpgpsdk.pri"):error("Including") !include("../../openpgpsdk/src/use_openpgpsdk.pri"):error("Including")
@ -48,9 +51,6 @@ mLibs = $$RS_SQL_LIB ssl crypto $$RS_THREAD_LIB $$RS_UPNP_LIB
dLibs = dLibs =
rs_jsonapi { rs_jsonapi {
RS_SRC_PATH=$$clean_path($${PWD}/../../)
RS_BUILD_PATH=$$clean_path($${OUT_PWD}/../../)
no_rs_cross_compiling { no_rs_cross_compiling {
RESTBED_SRC_PATH=$$clean_path($${RS_SRC_PATH}/supportlibs/restbed) RESTBED_SRC_PATH=$$clean_path($${RS_SRC_PATH}/supportlibs/restbed)
RESTBED_BUILD_PATH=$$clean_path($${RS_BUILD_PATH}/supportlibs/restbed) RESTBED_BUILD_PATH=$$clean_path($${RS_BUILD_PATH}/supportlibs/restbed)
@ -73,6 +73,20 @@ rs_deep_search {
win32-g++:mLibs += rpcrt4 win32-g++:mLibs += rpcrt4
} }
rs_broadcast_discovery {
no_rs_cross_compiling {
UDP_DISCOVERY_SRC_PATH=$$clean_path($${RS_SRC_PATH}/supportlibs/udp-discovery-cpp/)
UDP_DISCOVERY_BUILD_PATH=$$clean_path($${RS_BUILD_PATH}/supportlibs/udp-discovery-cpp/)
INCLUDEPATH *= $$clean_path($${UDP_DISCOVERY_SRC_PATH})
DEPENDPATH *= $$clean_path($${UDP_DISCOVERY_BUILD_PATH})
QMAKE_LIBDIR *= $$clean_path($${UDP_DISCOVERY_BUILD_PATH})
# Using sLibs would fail as libudp-discovery.a is generated at compile-time
LIBS *= -L$$clean_path($${UDP_DISCOVERY_BUILD_PATH}) -ludp-discovery
} else:sLibs *= udp-discovery
win32-g++:dLibs *= wsock32
}
static { static {
sLibs *= $$mLibs sLibs *= $$mLibs
} else { } else {

View file

@ -45,11 +45,14 @@ typedef int64_t rstime_t;
// Do we really need this? Our names have rs prefix to avoid pollution already! // Do we really need this? Our names have rs prefix to avoid pollution already!
namespace rstime { namespace rstime {
/*! /**
* \brief This is a cross-system definition of usleep, which accepts any 32 bits number of micro-seconds. * @deprecated { std::this_thread::sleep_for or
*/ * std::this_thread::sleep_until instead }
RS_DEPRECATED_FOR("std::this_thread::sleep_for") * @brief This is a cross-system definition of usleep, which accepts any
int rs_usleep(uint32_t micro_seconds); * 32 bits number of micro-seconds.
*/
RS_DEPRECATED_FOR("std::this_thread::sleep_for")
int rs_usleep(uint32_t micro_seconds);
/* Use this class to measure and display time duration of a given environment: /* Use this class to measure and display time duration of a given environment:

View file

@ -167,10 +167,15 @@ CONFIG *= no_rs_deep_search
rs_deep_search:CONFIG -= no_rs_deep_search rs_deep_search:CONFIG -= no_rs_deep_search
# To enable native dialogs append the following assignation to qmake command # To enable native dialogs append the following assignation to qmake command
#line "CONFIG+=rs_use_native_dialogs" # line "CONFIG+=rs_use_native_dialogs"
CONFIG *= no_rs_use_native_dialogs CONFIG *= no_rs_use_native_dialogs
rs_use_native_dialogs:CONFIG -= no_rs_use_native_dialogs rs_use_native_dialogs:CONFIG -= no_rs_use_native_dialogs
# To disable broadcast discovery happend the following assignation to qmake
# command line "CONFIG+=no_rs_broadcast_discovery"
CONFIG *= rs_broadcast_discovery
no_rs_broadcast_discovery:CONFIG -= rs_broadcast_discovery
# Specify host precompiled jsonapi-generator path, appending the following # Specify host precompiled jsonapi-generator path, appending the following
# assignation to qmake command line # assignation to qmake command line
# 'JSONAPI_GENERATOR_EXE=/myBuildDir/jsonapi-generator'. Required for JSON API # 'JSONAPI_GENERATOR_EXE=/myBuildDir/jsonapi-generator'. Required for JSON API
@ -488,6 +493,8 @@ rs_deep_search {
rs_use_native_dialogs:DEFINES *= RS_NATIVEDIALOGS rs_use_native_dialogs:DEFINES *= RS_NATIVEDIALOGS
rs_broadcast_discovery:DEFINES *= RS_BROADCAST_DISCOVERY
debug { debug {
QMAKE_CXXFLAGS -= -O2 -fomit-frame-pointer QMAKE_CXXFLAGS -= -O2 -fomit-frame-pointer
QMAKE_CFLAGS -= -O2 -fomit-frame-pointer QMAKE_CFLAGS -= -O2 -fomit-frame-pointer

@ -0,0 +1 @@
Subproject commit ab3f9745b1f2c6a91de38d9942dfe4b47c5c358c