#ifndef USE_NETWORKMANAGER #include "P2PManager.hpp" #include "ss.hpp" #include #include #include #include "WpaInterfaces.hpp" #include "NMP2pSettings.hpp" #include #include #include #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 reloadRequested{false}; std::atomic 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 stopping; std::vector 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 connectedPeers; std::string oldWpasDebugLevel; clock::time_point stage2Timeout; clock::time_point waitUntilDoneTimeout; }; P2PManager::ptr P2PManager::Create() { return std::make_unique(); } P2PManagerImpl::~P2PManagerImpl() { Stop(); } static const char hexDigits[] = "0123456789abcdef"; static std::string AddressToString(const std::vector &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 &properties) { this->HandleInterfaceAdded(path); }); this->wpaSupplicant->OnInterfaceRemoved.add( [this](const sdbus::ObjectPath &path) { this->HandleInterfaceRemoved(path); }); RemoveExistingInterfaces(); if (wpaSupplicant->Interfaces().size() == 0) { std::map 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 &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 &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 &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 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 inviteArgs; inviteArgs["peer"] = peer_object; inviteArgs["persistent_group_object"] = this->persistentGroupPath; p2pDevice->Invite(inviteArgs); #endif } static bool ValidateSetting(const std::map &properties, const std::string &key, int32_t value) { auto iter = properties.find(key); if (iter == properties.end()) return false; if (!iter->second.containsValueOfType()) return false; return iter->second.get() == value; } static bool ValidateSetting(const std::map &properties, const std::string &key, const std::string &value) { auto iter = properties.find(key); if (iter == properties.end()) return false; if (!iter->second.containsValueOfType()) return false; return iter->second.get() == value; } bool P2PManagerImpl::HasPersistentGroup() { auto persistentGroups = p2pDevice->PersistentGroups(); return persistentGroups.size() != 0; } void P2PManagerImpl::InitWpaP2PDevice() { p2pDevice->Country(settings.country()); std::map deviceConfig; deviceConfig["DeviceName"] = SS(settings.device_name()); deviceConfig["PrimaryDeviceType"] = std::vector{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{172, 23, 0, 2}; deviceConfig["IpAddrMask"] = std::vector{255, 255, 0, 0}; deviceConfig["IpAddrStart"] = std::vector{172, 23, 0, 4}; deviceConfig["IpAddrEnd"] = std::vector{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 &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 &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 &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 &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 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 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(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(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 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 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 args; args["service_type"] = "upnp"; args["version"] = (int32_t)10; args["service"] = UpnpServiceName(); std::vector 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 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 listenArgs; listenArgs["interval"] = (int32_t)3000; // listen for... listenArgs["period"] = (int32_t)250; // check every... this->p2pDevice->ExtendedListen(listenArgs); } } #endif