Merge pull request #1691 from G10h4ck/fixup_brodcastdiscovery

Fix some bugs in broadcast discovery
This commit is contained in:
G10h4ck 2019-10-25 23:06:13 +02:00 committed by GitHub
commit 584918388c
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 181 additions and 3 deletions

View File

@ -107,5 +107,45 @@ public:
*/
virtual std::vector<RsBroadcastDiscoveryResult> getDiscoveredPeers() = 0;
/**
* @brief Check if multicast listening is enabled
* @jsonapi{development}
* On some platforms such as Android multicast listening, which is needed
* for broadcast discovery, is not enabled by default at WiFi driver level
* @see enableMulticastListening, so this method check if it is enabled.
* On platforms that are not expected to have such a limitation this method
* always return true.
* @return true if enabled, false otherwise.
*/
virtual bool isMulticastListeningEnabled() = 0;
/**
* @brief On platforms that need it enable low level multicast listening
* @jsonapi{development}
* On Android and potencially other mobile platforms, WiFi drivers are
* configured by default to discard any packet that is not directed to the
* unicast mac address of the interface, this way they could save some
* battery but breaks anything that is not unicast, such as broadcast
* discovery. On such platforms this method enable low level multicast
* listening so we can receive advertisement from same broadcast domain
* nodes.
* On platforms without such limitation does nothing and always return
* false.
* It is exposed as a public API so the UI can decide the right equilibrium
* between discoverability and battery saving.
* @return true if multicast listening has been enabled due to this call,
* false otherwise.
*/
virtual bool enableMulticastListening() = 0;
/**
* @brief Disable multicast listening
* @jsonapi{development}
* The opposite of @see enableMulticastListening.
* @return true if multicast listening has been disabled due to this call,
* false otherwise.
*/
virtual bool disableMulticastListening() = 0;
virtual ~RsBroadcastDiscovery();
};

View File

@ -25,6 +25,10 @@
#include <vector>
#include <iostream>
#ifdef __ANDROID__
# include <QtAndroid>
#endif // def __ANDROID__
#include "services/broadcastdiscoveryservice.h"
#include "retroshare/rspeers.h"
#include "serialiser/rsserializable.h"
@ -94,6 +98,12 @@ BroadcastDiscoveryService::BroadcastDiscoveryService(
{
if(mRsPeers.isHiddenNode(mRsPeers.getOwnId())) return;
#ifdef __ANDROID__
createMulticastLock();
#endif // def __ANDROID__
enableMulticastListening();
mUdcParameters.set_can_discover(true);
mUdcParameters.set_can_be_discovered(true);
mUdcParameters.set_port(port);
@ -104,7 +114,10 @@ BroadcastDiscoveryService::BroadcastDiscoveryService(
}
BroadcastDiscoveryService::~BroadcastDiscoveryService()
{ mUdcPeer.Stop(true); }
{
mUdcPeer.Stop(true);
disableMulticastListening();
}
std::vector<RsBroadcastDiscoveryResult>
BroadcastDiscoveryService::getDiscoveredPeers()
@ -192,6 +205,7 @@ RsBroadcastDiscoveryResult BroadcastDiscoveryService::createResult(
BroadcastDiscoveryPack::fromSerializedString(uData);
RsBroadcastDiscoveryResult rbdr;
rbdr.mPgpFingerprint = bdp.mPgpFingerprint;
rbdr.mSslId = bdp.mSslId;
rbdr.mProfileName = bdp.mProfileName;
rbdr.mLocator.
@ -202,6 +216,95 @@ RsBroadcastDiscoveryResult BroadcastDiscoveryService::createResult(
return rbdr;
}
bool BroadcastDiscoveryService::isMulticastListeningEnabled()
{
#ifdef __ANDROID__
return assertMulticastLockIsvalid() &&
mWifiMulticastLock.callMethod<jboolean>("isHeld");
#endif // def __ANDROID__
return true;
}
bool BroadcastDiscoveryService::enableMulticastListening()
{
#ifdef __ANDROID__
if(assertMulticastLockIsvalid() && !isMulticastListeningEnabled())
{
mWifiMulticastLock.callMethod<void>("acquire");
return true;
}
#endif // def __ANDROID__
return false;
}
bool BroadcastDiscoveryService::disableMulticastListening()
{
#ifdef __ANDROID__
if(assertMulticastLockIsvalid() && isMulticastListeningEnabled())
{
mWifiMulticastLock.callMethod<void>("release");
return true;
}
#endif // def __ANDROID__
return false;
}
#ifdef __ANDROID__
bool BroadcastDiscoveryService::createMulticastLock()
{
Dbg2() << __PRETTY_FUNCTION__ << std::endl;
constexpr auto fname = __PRETTY_FUNCTION__;
const auto failure = [&](const std::string& err)
{
RsErr() << fname << " " << err << std::endl;
return false;
};
if(mWifiMulticastLock.isValid())
return failure("mWifiMulticastLock is already initialized");
QAndroidJniObject context = QtAndroid::androidContext();
if(!context.isValid())
return failure("Cannot retrieve Android context");
QAndroidJniObject WIFI_SERVICE = QAndroidJniObject::getStaticObjectField(
"android.content.Context", "WIFI_SERVICE", "Ljava/lang/String;");
if(!WIFI_SERVICE.isValid())
return failure("Cannot retrieve Context.WIFI_SERVICE value");
QAndroidJniObject wifiManager = context.callObjectMethod(
"getSystemService", "(Ljava/lang/String;)Ljava/lang/Object;",
WIFI_SERVICE.object<jstring>() );
if(!wifiManager.isValid())
return failure("Cannot retrieve Android Wifi Manager");
mWifiMulticastLock = wifiManager.callObjectMethod(
"createMulticastLock",
"(Ljava/lang/String;)Landroid/net/wifi/WifiManager$MulticastLock;",
QAndroidJniObject::fromString(fname).object<jstring>() );
if(!mWifiMulticastLock.isValid())
return failure("Cannot create WifiManager.MulticastLock");
return true;
}
bool BroadcastDiscoveryService::assertMulticastLockIsvalid()
{
if(!mWifiMulticastLock.isValid())
{
RsErr() << __PRETTY_FUNCTION__ << " mWifiMulticastLock is invalid!"
<< std::endl;
print_stacktrace();
return false;
}
return true;
}
#endif // def __ANDROID__
RsBroadcastDiscovery::~RsBroadcastDiscovery() = default;
RsBroadcastDiscoveryResult::~RsBroadcastDiscoveryResult() = default;
RsBroadcastDiscoveryPeerFoundEvent::~RsBroadcastDiscoveryPeerFoundEvent() = default;

View File

@ -27,8 +27,13 @@
#include <udp_discovery_peer.hpp>
#ifdef __ANDROID__
# include <QtAndroidExtras/QAndroidJniObject>
#endif // def __ANDROID__
#include "retroshare/rsbroadcastdiscovery.h"
#include "util/rsthreads.h"
#include "util/rsdebug.h"
namespace UDC = udpdiscovery;
class RsPeers;
@ -37,13 +42,21 @@ class BroadcastDiscoveryService :
public RsBroadcastDiscovery, public RsTickingThread
{
public:
// TODO: std::shared_ptr<RsPeers> mRsPeers;
BroadcastDiscoveryService(RsPeers& pRsPeers);
virtual ~BroadcastDiscoveryService() override;
~BroadcastDiscoveryService() override;
/// @see RsBroadcastDiscovery
std::vector<RsBroadcastDiscoveryResult> getDiscoveredPeers() override;
/// @see RsBroadcastDiscovery
bool isMulticastListeningEnabled() override;
/// @see RsBroadcastDiscovery
bool enableMulticastListening() override;
/// @see RsBroadcastDiscovery
bool disableMulticastListening() override;
/// @see RsTickingThread
void data_tick() override;
@ -63,4 +76,22 @@ protected:
RsBroadcastDiscoveryResult createResult(
const UDC::IpPort& ipp, const std::string& uData );
#ifdef __ANDROID__
/** Android WifiManager.MulticastLock */
QAndroidJniObject mWifiMulticastLock;
/** Initialize the wifi multicast lock without acquiring it
* Needed to enable multicast listening in Android, for RetroShare broadcast
* discovery inspired by:
* https://github.com/flutter/flutter/issues/16335#issuecomment-420547860
*/
bool createMulticastLock();
/** Return false if mWifiMulticastLock is invalid and print error messages */
bool assertMulticastLockIsvalid();
#endif // def __ANDROID__
RS_SET_CONTEXT_DEBUG_LEVEL(3)
};

View File

@ -85,4 +85,8 @@
<!-- Added by G10h4ck: Needed permission for network usage -->
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
<!-- Added by G10h4ck: Needed to listen for multicast packets, needed for
! broadcast discovery -->
<uses-permission android:name="android.permission.ACCESS_WIFI_STATE" />
<uses-permission android:name="android.permission.CHANGE_WIFI_MULTICAST_STATE" />
</manifest>