Files
op-pedal/NetworkManagerP2P/src/P2PManager.cpp.bak
T
2024-08-08 12:53:02 -04:00

1062 lines
32 KiB
Plaintext

#ifndef USE_NETWORKMANAGER
#include "P2PManager.hpp"
#include "ss.hpp"
#include <future>
#include <chrono>
#include <poll.h>
#include "WpaInterfaces.hpp"
#include "NMP2pSettings.hpp"
#include <thread>
#include <chrono>
#include <memory>
#include "DBusDispatcher.hpp"
#include "NetworkManagerInterfaces.hpp"
#include "DBusVariantHelper.hpp"
#include "SignalHandler.hpp"
static const char CONFIG_METHODS[] = "keypad";
static const char CONFIG_CONNECT_METHOD[] = "display";
class P2PManagerImpl : public P2PManager
{
public:
P2PManagerImpl() : dispatcher(true) {}
virtual ~P2PManagerImpl();
void Init() override;
void Run() override;
void Stop() override;
bool IsFinished() override;
void Wait() override;
bool ReloadRequested() override;
private:
using clock = std::chrono::steady_clock;
void StartListen();
void SignalStop();
void SignalHangup();
void ExecuteOrderlyShutdown();
void ShutdownStage2();
void TurnOnWifi();
void UnInitialize();
void StartWaitUntilDone();
void PostWaitUntilDone();
void MaybeRemoveGroup();
void CancelMaybeRemoveGroup();
void MaybeCancel();
void StartGroup();
bool HasPersistentGroup();
void AddExistingInterfaces();
void RemoveExistingInterfaces();
void HandleInterfaceAdded(const std::string &objectPath);
void HandleInterfaceRemoved(const std::string &objectPath);
void InitWpaP2PDevice();
void InitWpaP2PGoDevice();
void ConnectDevice(const sdbus::ObjectPath &peer_object);
bool HasClient();
std::string UpnpServiceName();
void StartServiceBroadcast();
void StopServiceBroadcast();
std::atomic<bool> reloadRequested{false};
std::atomic<bool> signalStop{false};
bool signalStopStarted = false;
bool shutdownExecuted = false;
bool waited = false;
bool serviceBroadcastStarted = false;
DBusDispatcher dispatcher;
DBusDispatcher::PostHandle maybeCloseHandle = 0;
std::mutex postMutex;
std::atomic<bool> stopping;
std::vector<std::string> pendingAddedInterfaces;
using PostCallback = DBusDispatcher::PostCallback;
void Post(PostCallback &&fn);
WpaSupplicant::ptr wpaSupplicant;
WpaInterface::ptr deviceInterface;
WpaP2PDevice::ptr p2pDevice;
WpaP2PDevice::ptr p2pGoDevice;
WpaWPS::ptr wpsDevice;
sdbus::ObjectPath persistentGroupPath;
P2pSettings settings{};
WpaGroup::ptr wpaGroup;
std::vector<WpaPeer::ptr> connectedPeers;
std::string oldWpasDebugLevel;
clock::time_point stage2Timeout;
clock::time_point waitUntilDoneTimeout;
};
P2PManager::ptr P2PManager::Create()
{
return std::make_unique<P2PManagerImpl>();
}
P2PManagerImpl::~P2PManagerImpl()
{
Stop();
}
static const char hexDigits[] = "0123456789abcdef";
static std::string AddressToString(const std::vector<uint8_t> &address)
{
std::stringstream ss;
bool firstTime = true;
for (auto byte : address)
{
if (!firstTime)
{
ss << ":";
}
firstTime = false;
ss << hexDigits[(byte >> 4) & 0x0F] << hexDigits[byte & 0x0F];
}
return ss.str();
}
void P2PManagerImpl::RemoveExistingInterfaces()
{
try
{
while (true)
{
if (!this->wpaSupplicant)
break;
auto interfaces = this->wpaSupplicant->Interfaces();
if (interfaces.size() == 0)
break;
wpaSupplicant->RemoveInterface(interfaces[0]);
}
}
catch (const std::exception &e)
{
LogWarning("P2PManagerImpl", "RemoveExistingInterfaces", e.what());
}
}
void P2PManagerImpl::Init()
{
settings.Load();
LogInfo(
"P2PManager",
"Init",
SS(
"Configuration:"
<< " " << settings.country()
<< " " << settings.wlan()
<< " " << settings.device_name()
<< " " << settings.web_server_port()
<< " " << settings.listen_channel()
<< " " << settings.op_channel()
));
SignalHandler::HandleSignal(
SignalHandler::Interrupt,
[this]()
{
this->SignalStop();
});
SignalHandler::HandleSignal(
SignalHandler::Terminate,
[this]()
{
this->SignalStop();
});
SignalHandler::HandleSignal(
SignalHandler::Hangup,
[this]()
{
this->SignalStop(); // we can't restart, but at lease we can do an orderly shutdown.
// disable this, because sdbus::dispatcher doesn't seem to be able to handle a restart.
// this->SignalHangup();
});
#ifdef DEBUG
dispatcher.Connection().setMethodCallTimeout(500 * 1000 * 1000);
#endif
for (int retry = 0; retry < 4 ; ++retry) // defend against slow starup of wpa_supplicant
{
try {
this->wpaSupplicant = WpaSupplicant::Create(dispatcher.Connection());
this->wpaSupplicant->DebugLevel();
if (retry != 0)
{
LogInfo("P2PManager","Init","wpa_supplicant DBus connection established.");
}
break;
} catch (std::exception&e)
{
if (retry == 0)
{
LogInfo("P2PManager","Init","Waiting for wpa_supplicant DBus connection.");
}
this->wpaSupplicant = nullptr;
std::this_thread::sleep_for(std::chrono::seconds(5));
}
}
if (!this->wpaSupplicant)
{
throw std::runtime_error("wpa_supplicant service is not reachable by DBus.");
}
std::string wpaLogLevel = "info";
switch (GetDBusLogLevel())
{
default:
case DBusLogLevel::Info:
wpaLogLevel = "info";
break;
case DBusLogLevel::Debug:
wpaLogLevel = "debug";
break;
case DBusLogLevel::Warning:
wpaLogLevel = "warning";
break;
case DBusLogLevel::Error:
wpaLogLevel = "error";
break;
case DBusLogLevel::Trace:
wpaLogLevel = "debug";
break;
}
oldWpasDebugLevel = wpaSupplicant->DebugLevel();
wpaSupplicant->DebugLevel(wpaLogLevel);
if (!oldWpasDebugLevel.empty())
{
wpaSupplicant->DebugLevel(oldWpasDebugLevel);
}
TurnOnWifi();
this->wpaSupplicant->OnInterfaceAdded.add(
[this](const sdbus::ObjectPath &path, const std::map<std::string, sdbus::Variant> &properties)
{
this->HandleInterfaceAdded(path);
});
this->wpaSupplicant->OnInterfaceRemoved.add(
[this](const sdbus::ObjectPath &path)
{
this->HandleInterfaceRemoved(path);
});
RemoveExistingInterfaces();
if (wpaSupplicant->Interfaces().size() == 0)
{
std::map<std::string, sdbus::Variant> createArgs;
createArgs["Ifname"] = settings.wlan();
createArgs["Driver"] = settings.driver();
createArgs["ConfigFile"] = settings.wpas_config_file();
wpaSupplicant->CreateInterface(createArgs);
}
}
void P2PManagerImpl::AddExistingInterfaces()
{
if (!this->p2pDevice)
{
for (const auto &objectPath : this->wpaSupplicant->Interfaces())
{
HandleInterfaceAdded(objectPath);
}
}
}
void P2PManagerImpl::HandleInterfaceRemoved(const std::string &objectPath)
{
bool deleted = false;
// removal from pending list can be done in a handler.
for (auto i = this->pendingAddedInterfaces.begin(); i != pendingAddedInterfaces.end(); ++i)
{
if (*i == objectPath)
{
pendingAddedInterfaces.erase(i);
return;
}
}
// removal of existing objects needs to be posted.
Post([this, objectPath]()
{
if (this->p2pDevice && this->p2pDevice->getObjectPath() == objectPath)
{
this->p2pDevice = nullptr;
this->deviceInterface = nullptr;
this->wpsDevice = nullptr;
}
if (this->p2pGoDevice && this->p2pGoDevice->getObjectPath() == objectPath)
{
this->wpaGroup = nullptr;
this->p2pGoDevice = nullptr;
StartListen();
} });
}
void P2PManagerImpl::HandleInterfaceAdded(const std::string &objectPath)
{
// Create the objects in the callback, but defer processing.
// Guard against the interface being synchronously removed before the async post handler excecutes./
this->pendingAddedInterfaces.push_back(objectPath.c_str());
{
std::string msg = SS("Device added: " << objectPath.c_str());
LogDebug("P2PManagerImpl", "HandleInterfaceAdded", msg);
}
Post([this,
objectPath]() mutable
{
// check to see whether the new interface was removed from pending list.
auto found = std::find(pendingAddedInterfaces.begin(),pendingAddedInterfaces.end(),objectPath);
if (found != pendingAddedInterfaces.end())
{
pendingAddedInterfaces.erase(found);
try {
auto interface = WpaInterface::Create(dispatcher.Connection(), objectPath);
auto p2pDevice = WpaP2PDevice::Create(dispatcher.Connection(), objectPath);
LogDebug(objectPath,"HandleInterfaceAdded",SS("Role: " << p2pDevice->Role()));
if (interface)
{
if (p2pDevice->Role() == "device" && ((!this->p2pDevice) || this->p2pDevice->getObjectPath() != objectPath))
{
LogDebug("P2PManagerImpl", "HandleInterfaceAdded", "P2P device found.");
this->deviceInterface = std::move(interface);
this->p2pDevice = std::move(p2pDevice);
this->wpsDevice = WpaWPS::Create(dispatcher.Connection(), objectPath);
InitWpaP2PDevice();
}
else if (p2pDevice->Role() == "GO" && ((!this->p2pGoDevice) || this->p2pGoDevice->getObjectPath() != objectPath))
{
LogDebug("P2PManagerImpl", "HandleInterfaceAdded", "P2P GO group interface found.");
this->p2pGoDevice = std::move(p2pDevice);
InitWpaP2PGoDevice();
}
}
} catch (const std::exception&e)
{
LogError("P2PManagerImpl","HandleInterfaceAdded",SS("Failed to add " << objectPath.c_str() << " (" << e.what() << ")"));
}
} });
}
void P2PManagerImpl::InitWpaP2PGoDevice()
{
if (IsDBusLoggingEnabled(DBusLogLevel::Trace))
{
auto deviceConfig = p2pGoDevice->P2PDeviceConfig();
std::stringstream s;
s << deviceConfig;
LogTrace("P2PManagerImpl", "InitWpaP2PGoDevice", SS("GO Device config: " << s.str()));
}
LogTrace("P2PManagerImpl", "InitWpaP2PGoDevice", SS("ConfigMethods: " << p2pGoDevice->ConfigMethods()));
p2pGoDevice->OnStaAuthorized.add(
[this](const std::string&name) {
LogInfo(
p2pGoDevice->getObjectPath(),
"OnStationAuthorized",
SS("Station authorized: " << name));
});
p2pGoDevice->OnStaDeauthorized.add(
[this](const std::string&name) {
LogInfo(
p2pGoDevice->getObjectPath(),
"OnStationDeauthorized",
SS("Station deauthorized: " << name));
});
p2pGoDevice->OnWpsFailed.add(
[this](const std::string &name, const std::map<std::string, sdbus::Variant> &args)
{
{
std::stringstream ss;
ss << name << " " << args << " ";
LogError("P2PManagerImp", "OnWpsFailed", ss.str());
}
try
{
this->p2pGoDevice->Cancel();
}
catch (const std::exception &)
{
}
MaybeRemoveGroup();
});
p2pGoDevice->OnGONegotiationFailure.add(
[this](const std::map<std::string, sdbus::Variant> &info)
{
std::stringstream ss;
ss << info;
LogError(p2pGoDevice->getObjectPath().c_str(),"OnGoNegotiationFailure",ss.str()); });
p2pGoDevice->OnGroupFormationFailure.add(
[this](const std::string &message)
{
std::stringstream ss;
ss << message;
LogError(p2pGoDevice->getObjectPath().c_str(), "OnGroupFormationFailure", ss.str());
MaybeRemoveGroup();
});
p2pGoDevice->OnStationAdded.add(
[this](const sdbus::ObjectPath &path, const std::map<std::string, sdbus::Variant> &properties) {
});
p2pGoDevice->OnStationRemoved.add(
[this](const sdbus::ObjectPath &)
{
MaybeRemoveGroup();
});
LogTrace("P2PManagerImpl", "InitWpaP2PGoDevice", SS("GoCountry: " << p2pGoDevice->Country()));
p2pGoDevice->OnProvisionDiscoveryRequestDisplayPin.add(
[this](const sdbus::ObjectPath &peer_object, const std::string &pin)
{
LogTrace("P2PManagerImpl", "InitWpaP2PGoDevice",
SS("GO OnProvisionDiscoveryRequestDisplayPin - " << peer_object.c_str() << " pin: " << pin));
});
}
bool P2PManagerImpl::HasClient()
{
return this->p2pDevice->Stations().size() != 0;
}
void P2PManagerImpl::ConnectDevice(const sdbus::ObjectPath &peer_object)
{
#if 1
try
{
int retry = 0;
while (true)
{
try
{
std::map<std::string, sdbus::Variant> connectArgs;
connectArgs["peer"] = peer_object;
connectArgs["persistent"] = true;
// connecconnectArgs["frequency"] = this->settings.frequency();
connectArgs["go_intent"] = (int32_t)this->settings.p2p_go_intent();
connectArgs["wps_method"] = CONFIG_CONNECT_METHOD;
connectArgs["pin"] = this->settings.pin();
connectArgs["authorize_only"] = false;
connectArgs["join"] = false; //HasClient();
this->p2pDevice->Connect(connectArgs);
break;
}
catch (const std::exception &e)
{
try
{
p2pDevice->Cancel();
}
catch (const std::exception &)
{
}
if (++retry == 2)
{
MaybeRemoveGroup();
throw;
}
}
}
}
catch (const std::exception &e)
{
LogError("P2pManager", "Connect", e.what());
return;
}
#else
std::map<std::string, sdbus::Variant> inviteArgs;
inviteArgs["peer"] = peer_object;
inviteArgs["persistent_group_object"] = this->persistentGroupPath;
p2pDevice->Invite(inviteArgs);
#endif
}
static bool ValidateSetting(const std::map<std::string, sdbus::Variant> &properties, const std::string &key, int32_t value)
{
auto iter = properties.find(key);
if (iter == properties.end())
return false;
if (!iter->second.containsValueOfType<int32_t>())
return false;
return iter->second.get<int32_t>() == value;
}
static bool ValidateSetting(const std::map<std::string, sdbus::Variant> &properties, const std::string &key, const std::string &value)
{
auto iter = properties.find(key);
if (iter == properties.end())
return false;
if (!iter->second.containsValueOfType<std::string>())
return false;
return iter->second.get<std::string>() == value;
}
bool P2PManagerImpl::HasPersistentGroup()
{
auto persistentGroups = p2pDevice->PersistentGroups();
return persistentGroups.size() != 0;
}
void P2PManagerImpl::InitWpaP2PDevice()
{
p2pDevice->Country(settings.country());
std::map<std::string, sdbus::Variant> deviceConfig;
deviceConfig["DeviceName"] = SS(settings.device_name());
deviceConfig["PrimaryDeviceType"] = std::vector<uint8_t>{0x00, 0x01, 0x00, 0x50, 0xF2, 0x04, 0x00, 0x01};
deviceConfig["GOIntent"] = (uint32_t)15;
deviceConfig["ListenChannel"] = (uint32_t)settings.listen_channel();
deviceConfig["OperChannel"] = (uint32_t)settings.op_channel();
// deviceConfig["ListenRegClass"] = (uint32_t)81;
// deviceConfig["ListenChannel"] = (uint32_t)settings.listen_channel();
// deviceConfig["OperRegClass"] = (uint32_t)81;
// deviceConfig["OperChannel"] = (uint32_t)settings.op_channel(); // ch 1
deviceConfig["SsidPostfix"] = SS("-" << settings.device_name());
deviceConfig["IpAddrGo"] = std::vector<uint8_t>{172, 23, 0, 2};
deviceConfig["IpAddrMask"] = std::vector<uint8_t>{255, 255, 0, 0};
deviceConfig["IpAddrStart"] = std::vector<uint8_t>{172, 23, 0, 4};
deviceConfig["IpAddrEnd"] = std::vector<uint8_t>{172, 23, 0, 9};
deviceConfig["IntraBss"] = false;
deviceConfig["PersistentReconnect"] = true;
// per_sta_psk
p2pDevice->P2PDeviceConfig(deviceConfig);
{
auto deviceConfig = p2pDevice->P2PDeviceConfig();
std::stringstream s;
s << deviceConfig;
LogTrace("P2PManager", "InitWpaP2PDevice", SS("P2PDeviceConfig: " << s.str()));
}
LogDebug("P2PManager","InitWpaP2PDevice",SS("ConfigMethods" << p2pDevice->ConfigMethods()));
p2pDevice->ConfigMethods(CONFIG_METHODS);
// deviceInterface->P2pGoHt40(settings.p2p_go_ht40() ? "1" : "0");
std::string groupName = p2pDevice->Group().c_str();
auto t = wpsDevice->DeviceType();
wpsDevice->DeviceName(settings.device_name());
wpsDevice->Manufacturer(settings.manufacturer());
wpsDevice->ModelName(settings.model_name());
wpsDevice->ModelNumber(settings.model_number());
wpsDevice->SerialNumber(settings.serial_number());
wpsDevice->DeviceType(settings.device_type());
p2pDevice->OnGroupStarted.add(
[this](const std::map<std::string, sdbus::Variant> &args)
{
try
{
LogDebug("P2PManager", "OnGroupStarted", "GroupStarted");
const sdbus::Variant &vGroup = args.at("group_object");
sdbus::ObjectPath group = vGroup;
if (!group.empty())
{
wpaGroup = WpaGroup::Create(dispatcher.Connection(), group);
wpaGroup->OnPeerJoined.add(
[this](const sdbus::ObjectPath &path)
{
Post(
[this, path]()
{
try
{
LogDebug("P2PManager", "OnPeerJoined", path.c_str());
this->connectedPeers.push_back(WpaPeer::Create(dispatcher.Connection(), path));
}
catch (const std::exception &e)
{
LogError("P2PManager", "OnPeerJoined", e.what());
}
});
});
wpaGroup->OnPeerDisconnected.add(
[this](const sdbus::ObjectPath &path)
{
Post(
[this, path]()
{
LogDebug("P2PManager","OnPeerDisconnected",path.c_str());
this->connectedPeers.push_back(WpaPeer::Create(dispatcher.Connection(),path));
for (auto iter = this->connectedPeers.begin(); iter != this->connectedPeers.end(); iter++)
{
if ((*iter)->getObjectPath() == path)
{
this->connectedPeers.erase(iter);
break;
}
} });
});
}
}
catch (const std::exception &e)
{
LogError("InitWpaP2PDevice", "OnGroupAdded", e.what());
}
});
p2pDevice->OnGONegotiationFailure.add(
[this](const std::map<std::string, sdbus::Variant> &info)
{
std::stringstream ss;
ss << info;
LogError(p2pDevice->getObjectPath().c_str(), "OnGoNegotiationFailure", ss.str());
});
p2pDevice->OnGroupFormationFailure.add(
[this](const std::string &reason)
{
LogError(p2pDevice->getObjectPath().c_str(), "OnGroupFormationFailure", reason);
});
p2pDevice->OnGroupFinished.add([this](const std::map<std::string, sdbus::Variant> &properties)
{
LogInfo("P2PManager","OnGroupFinished","");
wpaGroup = nullptr; });
p2pDevice->OnGroupFormationFailure.add(
[this](const std::string &reason)
{
Post([this]()
{
if (this->p2pDevice)
{
try {
StartListen();
} catch (const std::exception&e)
{
LogError("P2PManager","OnGroupFormationFailure", SS("Listen failed: " << e.what()));
}
} });
});
p2pDevice->OnGONegotiationFailure.add(
[this](const std::map<std::string, sdbus::Variant> &info)
{
Post([this]()
{
if (this->p2pDevice)
{
try {
StartListen();
} catch (const std::exception&e)
{
LogError("P2PManager","OnGONegotiationFailure", SS("Listen failed: " << e.what()));
}
} });
});
p2pDevice->OnProvisionDiscoveryEnterPin.add(
[this](const sdbus::ObjectPath &peer_object)
{
// old android device picks wrong method. pretend they asked for OnProvisionDiscoveryRequestDisplayPin instead
LogDebug(p2pDevice->getObjectPath(), "OnProvisionDiscoveryEnterPin",
peer_object.c_str());
Post(
[this, peer_object]()
{
if (!this->p2pDevice)
return;
ConnectDevice(peer_object);
});
});
p2pDevice->OnProvisionDiscoveryRequestDisplayPin.add(
[this](const sdbus::ObjectPath &peer_object, const std::string &pin)
{
LogDebug(p2pDevice->getObjectPath(), "OnProvisionDiscoveryRequestDisplayPin",
SS(peer_object.c_str()));
Post(
[this, peer_object]()
{
if (!this->p2pDevice)
return;
ConnectDevice(peer_object);
});
});
if (!HasPersistentGroup() || settings.auth_changed())
{
if (settings.auth_changed())
{
LogInfo("P2PManagerImpl","InitWpaP2PDevice","Auth has changed. Resetting persistent groups");
}
p2pDevice->RemoveAllPersistentGroups();
std::map<std::string, sdbus::Variant> persistentGroupAddParams;
persistentGroupAddParams["bssid"] = settings.bssid();
persistentGroupAddParams["ssid"] = settings.device_name();
persistentGroupAddParams["psk"] = settings.pin();
persistentGroupAddParams["mode"] = (uint32_t)3; //"3";
sdbus::ObjectPath persistentGroupPath = p2pDevice->AddPersistentGroup(persistentGroupAddParams);
this->persistentGroupPath = persistentGroupPath;
if (settings.auth_changed())
{
settings.auth_changed(false);
settings.Save();
}
}
else
{
this->persistentGroupPath = p2pDevice->PersistentGroups()[0];
}
StartListen();
StartServiceBroadcast();
LogInfo(this->p2pDevice->getObjectPath(), "InitWpaP2PDevice", "Listening");
}
void P2PManagerImpl::Post(PostCallback &&fn)
{
dispatcher.Post(std::move(fn));
}
void P2PManagerImpl::Run()
{
dispatcher.Run();
}
void P2PManagerImpl::ExecuteOrderlyShutdown()
{
dispatcher.Post(
[this]()
{
if (this->shutdownExecuted)
return;
this->shutdownExecuted = true;
StopServiceBroadcast();
CancelMaybeRemoveGroup();
if (this->p2pDevice)
{
// no parameters cancels Extended listen.
std::map<std::string, sdbus::Variant> listenArgs;
this->p2pDevice->ExtendedListen(listenArgs);
}
if (this->p2pGoDevice)
{
try
{
this->p2pGoDevice->Disconnect();
}
catch (const std::exception &e)
{
LogWarning("P2PManagerImpl", "Stop", SS("Can't disconnect " << this->p2pGoDevice->Ifname()));
}
}
stage2Timeout = clock::now() + std::chrono::duration_cast<clock::duration>(std::chrono::milliseconds(1500));
ShutdownStage2();
});
}
void P2PManagerImpl::ShutdownStage2()
{
if (clock::now() > stage2Timeout)
{
LogError("P2PManagerImpl","ShutdownStage2","Stage2 shutdown timeout exipred.");
} else {
// wait until the Disconnect has completed.
if (this->p2pGoDevice)
{
dispatcher.PostDelayed(std::chrono::milliseconds(50),
[this]() {
ShutdownStage2();
});
return;
}
}
LogDebug("P2PManagerImpl","ShutdownStage2","Sutdown Stage2 complete.");
if (this->p2pDevice)
{
this->wpaSupplicant->RemoveInterface(p2pDevice->getObjectPath());
}
StartWaitUntilDone();
}
void P2PManagerImpl::Stop()
{
SignalStop();
Wait();
}
bool P2PManagerImpl::IsFinished()
{
return dispatcher.IsFinished();
}
bool P2PManagerImpl::ReloadRequested()
{
return this->reloadRequested;
}
void P2PManagerImpl::Wait()
{
if (!waited)
{
waited = true;
dispatcher.Wait();
LogInfo("P2PManager", "Stop", "Shutdown complete.");
}
}
void P2PManagerImpl::StartWaitUntilDone()
{
this->waitUntilDoneTimeout = clock::now() + std::chrono::duration_cast<clock::duration>(std::chrono::milliseconds(1000));
PostWaitUntilDone();
}
void P2PManagerImpl::PostWaitUntilDone()
{
if (clock::now() > this->waitUntilDoneTimeout)
{
LogError("P2PManager","PostWaitUntilDone", "WaitUntilDone timeout expired.");
} else {
auto interfaces = this->wpaSupplicant->Interfaces();
if (interfaces.size() > 0)
{
dispatcher.PostDelayed(
std::chrono::milliseconds(100),
[this]()
{
PostWaitUntilDone();
});
}
}
// the dispatcher won't exit while there's a pending post.
dispatcher.PostDelayed(
std::chrono::milliseconds(100),
[this]()
{
UnInitialize();
});
}
void P2PManagerImpl::StartGroup()
{
std::map<std::string, sdbus::Variant> args;
args["persistent_group_object"] = this->persistentGroupPath;
this->p2pDevice->GroupAdd(args);
}
void P2PManagerImpl::CancelMaybeRemoveGroup()
{
if (maybeCloseHandle)
{
dispatcher.CancelPost(maybeCloseHandle);
maybeCloseHandle = 0;
}
}
void P2PManagerImpl::MaybeRemoveGroup()
{
CancelMaybeRemoveGroup();
if (dispatcher.IsStopping())
{
return;
}
maybeCloseHandle = dispatcher.PostDelayed(
std::chrono::milliseconds(100),
[this]()
{
maybeCloseHandle = 0;
if (this->p2pDevice->Stations().size() == 0)
{
if (this->p2pGoDevice)
{
try
{
p2pGoDevice->Disconnect();
}
catch (const std::exception &e)
{
LogTrace(p2pGoDevice->getObjectPath(), "MaybeRemoveGroup", "Failed to disconnect.");
}
}
}
});
}
std::vector<std::string> s_idleStates{
"disconnected",
"inactive",
"interface_disabled",
"scanning",
//"authenticating",
//"associating",
//"associated",
//"4way_handshake",
//"group_handshake",
"completed",
//"unknown",
};
void P2PManagerImpl::MaybeCancel()
{
std::string state = this->p2pDevice->State();
for (const auto &idleState : s_idleStates)
{
if (idleState == state)
{
return;
}
}
try
{
this->p2pDevice->Cancel();
}
catch (const std::exception &)
{
}
}
std::string P2PManagerImpl::UpnpServiceName()
{
return SS("uuid:" << settings.service_uuid() << "::urn:schemas-twoplay-com:service:PiPedal:1"
<< "::port:" << settings.web_server_port());
}
void P2PManagerImpl::StartServiceBroadcast()
{
// Upnp service advertising allows the android client to automatically discover pipedal Wifi P2P devices.
try
{
std::map<std::string, sdbus::Variant> args;
args["service_type"] = "upnp";
args["version"] = (int32_t)10;
args["service"] = UpnpServiceName();
std::vector<std::uint8_t> response;
args["response"] = response;
p2pDevice->AddService(
args);
serviceBroadcastStarted = true;
}
catch (const std::exception &e)
{
LogError(
p2pDevice->getObjectPath(),
"StartServiceBroadcast",
SS("Failed to start Wi-Fi service broadcast. " << e.what()));
}
}
void P2PManagerImpl::StopServiceBroadcast()
{
try
{
if (serviceBroadcastStarted)
{
serviceBroadcastStarted = false;
std::map<std::string, sdbus::Variant> args;
args["service_type"] = "upnp";
args["version"] = (int32_t)10;
args["service"] = UpnpServiceName();
p2pDevice->DeleteService(args);
}
}
catch (std::exception &e)
{
LogDebug("P2PManager", "StopServiceBroadcast", e.what());
}
}
void P2PManagerImpl::UnInitialize()
{
// should all have been released at this point,
// but still best to check.
this->connectedPeers.clear();
this->wpaGroup = nullptr;
this->p2pGoDevice = nullptr;
this->p2pDevice = nullptr;
this->deviceInterface = nullptr;
this->wpsDevice = nullptr;
wpaSupplicant->DebugLevel(oldWpasDebugLevel);
wpaSupplicant = nullptr; // completely shut down after this.
}
void P2PManagerImpl::TurnOnWifi()
{
bool wirelessEnabled;
auto networkManager = NetworkManager::Create(dispatcher);
try
{
wirelessEnabled = networkManager->WirelessEnabled();
}
catch (const std::exception &e)
{
LogDebug("P2PManager", "TurnOnWifi", "NetworkManager is not available.");
return;
}
if (!wirelessEnabled)
{
networkManager->WirelessEnabled(true);
}
}
void P2PManagerImpl::SignalHangup()
{
if (signalStop)
return;
//reloadRequested = true;
dispatcher.SignalStop([this]()
{
dispatcher.Post([this]()
{
LogInfo("P2PManager","SignalHangup","Reload requested.");
ExecuteOrderlyShutdown();
});
ExecuteOrderlyShutdown(); });
signalStop = true;
}
void P2PManagerImpl::SignalStop()
{
if (signalStop)
return;
dispatcher.SignalStop([this]()
{ ExecuteOrderlyShutdown(); });
signalStop = true;
}
void P2PManagerImpl::StartListen()
{
if (!dispatcher.IsStopping())
{
p2pDevice->Listen((int32_t)5);
std::map<std::string, sdbus::Variant> listenArgs;
listenArgs["interval"] = (int32_t)3000; // listen for...
listenArgs["period"] = (int32_t)250; // check every...
this->p2pDevice->ExtendedListen(listenArgs);
}
}
#endif