2
* Copyright © 2012-2013 Canonical Ltd.
4
* This program is free software: you can redistribute it and/or modify it
5
* under the terms of the GNU Lesser General Public License version 3,
6
* as published by the Free Software Foundation.
8
* This program is distributed in the hope that it will be useful,
9
* but WITHOUT ANY WARRANTY; without even the implied warranty of
10
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11
* GNU Lesser General Public License for more details.
13
* You should have received a copy of the GNU Lesser General Public License
14
* along with this program. If not, see <http://www.gnu.org/licenses/>.
16
* Authored by: Thomas Voß <thomas.voss@canonical.com>
19
#include "ofono_nm_connectivity_manager.h"
21
namespace connectivity = com::ubuntu::location::connectivity;
22
namespace dbus = core::dbus;
23
namespace xdg = org::freedesktop;
26
connectivity::State from_nm_property(std::uint32_t value)
28
connectivity::State result{connectivity::State::unknown};
32
case xdg::NetworkManager::Properties::Connectivity::Values::unknown:
33
result = connectivity::State::unknown;
35
case xdg::NetworkManager::Properties::Connectivity::Values::none:
36
result = connectivity::State::none;
38
case xdg::NetworkManager::Properties::Connectivity::Values::portal:
39
result = connectivity::State::portal;
41
case xdg::NetworkManager::Properties::Connectivity::Values::limited:
42
result = connectivity::State::limited;
44
case xdg::NetworkManager::Properties::Connectivity::Values::full:
45
result = connectivity::State::full;
53
const core::Property<connectivity::State>& impl::OfonoNmConnectivityManager::state() const
58
void impl::OfonoNmConnectivityManager::request_scan_for_wireless_networks()
60
std::lock_guard<std::mutex> lg(d.cached.guard);
62
for (const auto& pair : d.cached.wireless_devices)
63
pair.second.request_scan();
66
const core::Signal<>& impl::OfonoNmConnectivityManager::wireless_network_scan_finished() const
68
return d.signals.wireless_network_scan_finished;
71
const core::Signal<connectivity::WirelessNetwork::Ptr>& impl::OfonoNmConnectivityManager::wireless_network_added() const
73
return d.signals.wireless_network_added;
76
const core::Signal<connectivity::WirelessNetwork::Ptr>& impl::OfonoNmConnectivityManager::wireless_network_removed() const
78
return d.signals.wireless_network_removed;
81
void impl::OfonoNmConnectivityManager::enumerate_visible_wireless_networks(const std::function<void(const connectivity::WirelessNetwork::Ptr&)>& f) const
83
std::lock_guard<std::mutex> lg(d.cached.guard);
84
for (const auto& wifi : d.cached.wifis)
88
const core::Signal<connectivity::RadioCell::Ptr>& impl::OfonoNmConnectivityManager::connected_cell_added() const
90
return d.signals.connected_cell_added;
93
const core::Signal<connectivity::RadioCell::Ptr>& impl::OfonoNmConnectivityManager::connected_cell_removed() const
95
return d.signals.connected_cell_removed;
98
void impl::OfonoNmConnectivityManager::enumerate_connected_radio_cells(const std::function<void(const connectivity::RadioCell::Ptr&)>& f) const
100
std::lock_guard<std::mutex> lg(d.cached.guard);
101
for (const auto& cell : d.cached.cells)
105
impl::OfonoNmConnectivityManager::Private::Private()
109
system_bus = std::make_shared<core::dbus::Bus>(core::dbus::WellKnownBus::system);
110
executor = dbus::asio::make_executor(system_bus);
111
system_bus->install_executor(executor);
113
worker = std::move(std::thread
121
setup_network_stack_access();
122
setup_radio_stack_access();
124
catch (const std::exception& e)
126
LOG(ERROR) << "Error while setting up access to radio and network stack: " << e.what();
130
impl::OfonoNmConnectivityManager::Private::~Private()
135
if (worker.joinable())
139
void impl::OfonoNmConnectivityManager::Private::setup_radio_stack_access()
141
modem_manager.reset(new org::Ofono::Manager(system_bus));
143
modem_manager->for_each_modem([this](const core::dbus::types::ObjectPath& path)
147
on_modem_added(path);
149
catch(const std::runtime_error& e)
151
LOG(WARNING) << "Exception while creating connected radio cell: " << e.what();
155
modem_manager->signals.modem_added->connect([this](const org::Ofono::Manager::ModemAdded::ArgumentType& arg)
159
on_modem_added(std::get<0>(arg));
161
catch(const std::exception& e)
163
LOG(WARNING) << "Exception while adding modem: " << e.what();
167
modem_manager->signals.modem_removed->connect([this](const core::dbus::types::ObjectPath& path)
171
on_modem_removed(path);
173
catch(const std::exception& e)
175
LOG(WARNING) << "Exception while removing modem: " << e.what();
180
void impl::OfonoNmConnectivityManager::Private::on_modem_added(const core::dbus::types::ObjectPath& path)
182
auto modem = modem_manager->modem_for_path(path);
184
// We first wire up to property changes here.
185
modem.signals.property_changed->connect([this, path](const std::tuple<std::string, core::dbus::types::Variant>& tuple)
187
const auto& key = std::get<0>(tuple); VLOG(10) << "Property changed for modem: " << key;
189
if (org::Ofono::Manager::Modem::Properties::Interfaces::name() == key)
191
auto interfaces = std::get<1>(tuple).as<std::vector<std::string> >();
192
if (VLOG_IS_ON(10)) for(const auto& interface : interfaces) VLOG(10) << interface;
193
on_modem_interfaces_changed(path, interfaces);
198
// And update our cache of modems and registered cells.
199
auto cell = std::make_shared<CachedRadioCell>(modem);
201
std::lock_guard<std::mutex> lg(cached.guard);
202
cached.modems.insert(std::make_pair(modem.object->path(), modem));
203
cached.cells.insert(std::make_pair(modem.object->path(), cell));
205
// Announce the newly added cell to API customers, without the lock
206
// on the cache being held.
207
signals.connected_cell_added(cell);
210
void impl::OfonoNmConnectivityManager::Private::on_modem_removed(const core::dbus::types::ObjectPath& path)
212
CachedRadioCell::Ptr cell;
214
std::lock_guard<std::mutex> lg(cached.guard);
216
// Update modem and cell cache.
217
auto itc = cached.cells.find(path);
218
auto itm = cached.modems.find(path);
220
if (itc != cached.cells.end())
223
cached.cells.erase(itc);
226
if (itm != cached.modems.end())
228
cached.modems.erase(path);
231
// Inform customers of the registered cell being removed, without
232
// the lock on the cache being held.
233
if (cell) signals.connected_cell_removed(cell);
236
void impl::OfonoNmConnectivityManager::Private::on_modem_interfaces_changed(
237
const core::dbus::types::ObjectPath& path,
238
const std::vector<std::string>& interfaces)
240
std::unique_lock<std::mutex> ul(cached.guard);
242
auto itm = cached.modems.find(path);
243
if (itm == cached.modems.end())
245
LOG(WARNING) << "Could not find a modem for path " << path.as_string();
249
auto itt = cached.cells.find(path);
250
const bool has_cell_for_modem = itt != cached.cells.end();
255
std::string{org::Ofono::Manager::Modem::Properties::Interfaces::network_registration});
256
const bool modem_has_network_registration = it != interfaces.end();
258
if (has_cell_for_modem and not modem_has_network_registration)
260
// A network registration was lost and we remove the corresponding
261
// cell instance from the cache.
262
auto cell = itt->second;
263
cached.cells.erase(itt);
265
// Cache is up to date now and we announce the removal of the cell
266
// to API customers, with the lock on the cache not being held.
267
ul.unlock(); signals.connected_cell_removed(cell);
268
} else if (not has_cell_for_modem and modem_has_network_registration)
270
// A new network registration is coming in and we have to create
271
// a corresponding cell instance.
272
auto cell = std::make_shared<CachedRadioCell>(itm->second);
273
cached.cells.insert(std::make_pair(path,cell));
274
// Cache is up to date now and we announce the new cell to
275
// API customers, with the lock on the cache not being held.
276
ul.unlock(); signals.connected_cell_added(cell);
280
void impl::OfonoNmConnectivityManager::Private::setup_network_stack_access()
282
network_manager.reset(new xdg::NetworkManager(system_bus));
284
network_manager->for_each_device([this](const core::dbus::types::ObjectPath& device_path)
286
auto device = network_manager->device_for_path(device_path);
288
if (device.type() == xdg::NetworkManager::Device::Type::wifi)
290
// Make the device known to the cache.
291
cached.wireless_devices.insert(std::make_pair(device_path, device));
293
// Iterate over all currently known wifis
294
device.for_each_access_point([this, device_path](const core::dbus::types::ObjectPath& path)
298
on_access_point_added(path, device_path);
300
catch (const std::exception& e)
302
LOG(ERROR) << "Error while creating ap/wifi: " << e.what();
306
device.signals.scan_done->connect([this]()
308
signals.wireless_network_scan_finished();
311
device.signals.ap_added->connect([this, device_path](const core::dbus::types::ObjectPath& path)
315
on_access_point_added(path, device_path);
317
catch (const std::exception& e)
319
LOG(ERROR) << "Error while creating ap/wifi: " << e.what();
323
device.signals.ap_removed->connect([this](const core::dbus::types::ObjectPath& path)
327
on_access_point_removed(path);
329
catch (const std::exception& e)
331
LOG(ERROR) << "Error while removing ap/wifi: " << e.what();
337
// Query the initial connectivity state
338
state.set(from_nm_property(network_manager->properties.connectivity->get()));
340
// And we wire up to property changes here
341
network_manager->signals.properties_changed->connect([this](const std::map<std::string, core::dbus::types::Variant>& dict)
343
for (const auto& pair : dict)
345
VLOG(1) << "Property has changed: " << std::endl
346
<< " " << pair.first;
348
if (xdg::NetworkManager::Properties::Connectivity::name() == pair.first)
350
state.set(from_nm_property(pair.second.as<xdg::NetworkManager::Properties::Connectivity::ValueType>()));
356
void impl::OfonoNmConnectivityManager::Private::on_access_point_added(
357
const core::dbus::types::ObjectPath& ap_path,
358
const core::dbus::types::ObjectPath& device_path)
360
std::unique_lock<std::mutex> ul(cached.guard);
362
// Let's see if we have a device known for the path. We return early
363
// if we do not know about the device.
364
auto itd = cached.wireless_devices.find(device_path);
365
if (itd == cached.wireless_devices.end())
368
xdg::NetworkManager::AccessPoint ap
370
network_manager->service->add_object_for_path(ap_path)
373
auto wifi = std::make_shared<CachedWirelessNetwork>(itd->second, ap);
374
cached.wifis[ap_path] = wifi;
376
// Let API consumers know that an AP appeared. The lock on the cache is
377
// not held to prevent from deadlocks.
378
ul.unlock(); signals.wireless_network_added(wifi);
381
void impl::OfonoNmConnectivityManager::Private::on_access_point_removed(const core::dbus::types::ObjectPath& ap_path)
383
std::unique_lock<std::mutex> ul(cached.guard);
385
// Let's see if we know about the wifi. We return early if not.
386
auto itw = cached.wifis.find(ap_path);
387
if (itw == cached.wifis.end())
390
// Update the cache and keep the wifi object alive until API consumers
391
// have been informed of the wifi going away.
392
connectivity::WirelessNetwork::Ptr wifi = itw->second;
393
cached.wifis.erase(itw);
395
// Let API consumers know that an AP disappeared. The lock on the cache is
396
// not held to prevent from deadlocks.
397
ul.unlock(); signals.wireless_network_removed(wifi);
400
const std::shared_ptr<connectivity::Manager>& connectivity::platform_default_manager()
402
static const std::shared_ptr<connectivity::Manager> instance{new impl::OfonoNmConnectivityManager{}};