1 /****************************************************************************
2 **
3 ** Copyright (C) 2012 Digia Plc and/or its subsidiary(-ies).
4 ** Contact: http://www.qt-project.org/legal
5 **
6 ** This file is part of the QtSystems module of the Qt Toolkit.
7 **
8 ** $QT_BEGIN_LICENSE:LGPL$
9 ** Commercial License Usage
10 ** Licensees holding valid commercial Qt licenses may use this file in
11 ** accordance with the commercial license agreement provided with the
12 ** Software or, alternatively, in accordance with the terms contained in
13 ** a written agreement between you and Digia. For licensing terms and
14 ** conditions see http://qt.digia.com/licensing. For further information
15 ** use the contact form at http://qt.digia.com/contact-us.
16 **
17 ** GNU Lesser General Public License Usage
18 ** Alternatively, this file may be used under the terms of the GNU Lesser
19 ** General Public License version 2.1 as published by the Free Software
20 ** Foundation and appearing in the file LICENSE.LGPL included in the
21 ** packaging of this file. Please review the following information to
22 ** ensure the GNU Lesser General Public License version 2.1 requirements
23 ** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
24 **
25 ** In addition, as a special exception, Digia gives you certain additional
26 ** rights. These rights are described in the Digia Qt LGPL Exception
27 ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
28 **
29 ** GNU General Public License Usage
30 ** Alternatively, this file may be used under the terms of the GNU
31 ** General Public License version 3.0 as published by the Free Software
32 ** Foundation and appearing in the file LICENSE.GPL included in the
33 ** packaging of this file. Please review the following information to
34 ** ensure the GNU General Public License version 3.0 requirements will be
35 ** met: http://www.gnu.org/copyleft/gpl.html.
36 **
37 **
38 ** $QT_END_LICENSE$
39 **
40 ****************************************************************************/
41
42 #include "qnetworkinfo_linux_p.h"
43
44 #if !defined(QT_NO_OFONO)
45 #include "qofonowrapper_p.h"
46 #endif
47
48 #include <QtCore/qdir.h>
49 #include <QtCore/qfile.h>
50 #include <QtCore/qmetaobject.h>
51 #include <QtCore/qtextstream.h>
52 #include <QtCore/qtimer.h>
53 #if !defined(QT_NO_BLUEZ)
54 #include <bluetooth/bluetooth.h>
55 #include <bluetooth/hci.h>
56 #include <bluetooth/hci_lib.h>
57 #endif // QT_NO_BLUEZ
58
59 #if !defined(QT_NO_UDEV)
60 #include <QtCore/qsocketnotifier.h>
61 #include <libudev.h>
62 #endif // QT_NO_UDEV
63
64 #include <cmath>
65 #include <linux/wireless.h>
66 #include <sys/ioctl.h>
67 #include <sys/socket.h>
68 #include <sys/types.h>
69 #include <unistd.h>
70
71 QT_BEGIN_NAMESPACE
72
73 Q_GLOBAL_STATIC_WITH_ARGS(const QString, NETWORK_SYSFS_PATH, (QLatin1String("/sys/class/net/")))
74
75 Q_GLOBAL_STATIC_WITH_ARGS(const QStringList, WLAN_MASK, (QStringList() << QLatin1String("wlan*")))
76 Q_GLOBAL_STATIC_WITH_ARGS(const QStringList, ETHERNET_MASK, (QStringList() << QLatin1String("eth*") << QLatin1String("usb*")))
77
QNetworkInfoPrivate(QNetworkInfo * parent)78 QNetworkInfoPrivate::QNetworkInfoPrivate(QNetworkInfo *parent)
79 : QObject(parent)
80 , q_ptr(parent)
81 #if !defined(QT_NO_OFONO)
82 , ofonoWrapper(0)
83 #endif
84 #if !defined(QT_NO_UDEV)
85 , udevNotifier(0)
86 , udevHandle(0)
87 , udevMonitor(0)
88 #endif // QT_NO_UDEV
89 {
90 }
91
~QNetworkInfoPrivate()92 QNetworkInfoPrivate::~QNetworkInfoPrivate()
93 {
94 #if !defined(QT_NO_UDEV)
95 if (udevMonitor)
96 udev_monitor_unref(udevMonitor);
97
98 if (udevHandle)
99 udev_unref(udevHandle);
100 #endif // QT_NO_UDEV
101 }
102
networkInterfaceCount(QNetworkInfo::NetworkMode mode)103 int QNetworkInfoPrivate::networkInterfaceCount(QNetworkInfo::NetworkMode mode)
104 {
105 if (watchNetworkInterfaceCount && (mode == QNetworkInfo::WlanMode
106 || mode == QNetworkInfo::EthernetMode
107 || mode == QNetworkInfo::BluetoothMode)) {
108 return networkInterfaceCounts.value(mode);
109 } else
110 return getNetworkInterfaceCount(mode);
111 }
112
networkSignalStrength(QNetworkInfo::NetworkMode mode,int interface)113 int QNetworkInfoPrivate::networkSignalStrength(QNetworkInfo::NetworkMode mode, int interface)
114 {
115 if (watchNetworkSignalStrength && (mode == QNetworkInfo::WlanMode
116 || mode == QNetworkInfo::EthernetMode
117 || mode == QNetworkInfo::BluetoothMode)) {
118 return networkSignalStrengths.value(QPair<QNetworkInfo::NetworkMode, int>(mode, interface));
119 } else
120 return getNetworkSignalStrength(mode, interface);
121 }
122
currentCellDataTechnology(int interface)123 QNetworkInfo::CellDataTechnology QNetworkInfoPrivate::currentCellDataTechnology(int interface)
124 {
125 #if !defined(QT_NO_OFONO)
126 if (QOfonoWrapper::isOfonoAvailable()) {
127 if (!ofonoWrapper)
128 ofonoWrapper = new QOfonoWrapper(this);
129 QStringList modems = ofonoWrapper->allModems();
130 if (interface < modems.size()) {
131 QString modem = ofonoWrapper->allModems().at(interface);
132 if (!modem.isEmpty())
133 return ofonoWrapper->currentCellDataTechnology(modem);
134 }
135 }
136 #else
137 Q_UNUSED(interface)
138 #endif
139 return QNetworkInfo::UnknownDataTechnology;
140 }
141
currentNetworkMode()142 QNetworkInfo::NetworkMode QNetworkInfoPrivate::currentNetworkMode()
143 {
144 if (watchCurrentNetworkMode)
145 return currentMode;
146 else
147 return getCurrentNetworkMode();
148 }
149
networkStatus(QNetworkInfo::NetworkMode mode,int interface)150 QNetworkInfo::NetworkStatus QNetworkInfoPrivate::networkStatus(QNetworkInfo::NetworkMode mode, int interface)
151 {
152 if (watchNetworkStatus && (mode == QNetworkInfo::WlanMode
153 || mode == QNetworkInfo::EthernetMode
154 || mode == QNetworkInfo::BluetoothMode)) {
155 return networkStatuses.value(QPair<QNetworkInfo::NetworkMode, int>(mode, interface));
156 } else
157 return getNetworkStatus(mode, interface);
158 }
159
160 #ifndef QT_NO_NETWORKINTERFACE
interfaceForMode(QNetworkInfo::NetworkMode mode,int interface)161 QNetworkInterface QNetworkInfoPrivate::interfaceForMode(QNetworkInfo::NetworkMode mode, int interface)
162 {
163 switch (mode) {
164 case QNetworkInfo::WlanMode: {
165 QStringList dirs = QDir(*NETWORK_SYSFS_PATH()).entryList(*WLAN_MASK());
166 if (interface < dirs.size()) {
167 QNetworkInterface networkInterface = QNetworkInterface::interfaceFromName(dirs.at(interface));
168 if (networkInterface.isValid())
169 return networkInterface;
170 }
171 break;
172 }
173
174 case QNetworkInfo::EthernetMode: {
175 QStringList dirs = QDir(*NETWORK_SYSFS_PATH()).entryList(*ETHERNET_MASK());
176 if (interface < dirs.size()) {
177 QNetworkInterface networkInterface = QNetworkInterface::interfaceFromName(dirs.at(interface));
178 if (networkInterface.isValid())
179 return networkInterface;
180 }
181 break;
182 }
183
184 // case QNetworkInfo::BluetoothMode:
185 // case QNetworkInfo::GsmMode:
186 // case QNetworkInfo::CdmaMode:
187 // case QNetworkInfo::WcdmaMode:
188 // case QNetworkInfo::WimaxMode:
189 // case QNetworkInfo::LteMode:
190 // case QNetworkInfo::TdscdmaMode:
191 default:
192 break;
193 };
194
195 return QNetworkInterface();
196 }
197 #endif // QT_NO_NETWORKINTERFACE
198
cellId(int interface)199 QString QNetworkInfoPrivate::cellId(int interface)
200 {
201 #if !defined(QT_NO_OFONO)
202 if (QOfonoWrapper::isOfonoAvailable()) {
203 if (!ofonoWrapper)
204 ofonoWrapper = new QOfonoWrapper(this);
205 QStringList modems = ofonoWrapper->allModems();
206 if (interface < modems.size()) {
207 QString modem = ofonoWrapper->allModems().at(interface);
208 if (!modem.isEmpty())
209 return ofonoWrapper->cellId(modem);
210 }
211 }
212 #else
213 Q_UNUSED(interface)
214 #endif
215 return QString();
216 }
217
currentMobileCountryCode(int interface)218 QString QNetworkInfoPrivate::currentMobileCountryCode(int interface)
219 {
220 #if !defined(QT_NO_OFONO)
221 if (QOfonoWrapper::isOfonoAvailable()) {
222 if (!ofonoWrapper)
223 ofonoWrapper = new QOfonoWrapper(this);
224 QStringList modems = ofonoWrapper->allModems();
225 if (interface < modems.size()) {
226 QString modem = ofonoWrapper->allModems().at(interface);
227 if (!modem.isEmpty())
228 return ofonoWrapper->currentMcc(modem);
229 }
230 }
231 #else
232 Q_UNUSED(interface)
233 #endif
234 return QString();
235 }
236
currentMobileNetworkCode(int interface)237 QString QNetworkInfoPrivate::currentMobileNetworkCode(int interface)
238 {
239 #if !defined(QT_NO_OFONO)
240 if (QOfonoWrapper::isOfonoAvailable()) {
241 if (!ofonoWrapper)
242 ofonoWrapper = new QOfonoWrapper(this);
243 QStringList modems = ofonoWrapper->allModems();
244 if (interface < modems.size()) {
245 QString modem = ofonoWrapper->allModems().at(interface);
246 if (!modem.isEmpty())
247 return ofonoWrapper->currentMnc(modem);
248 }
249 }
250 #else
251 Q_UNUSED(interface)
252 #endif
253 return QString();
254 }
255
homeMobileCountryCode(int interface)256 QString QNetworkInfoPrivate::homeMobileCountryCode(int interface)
257 {
258 #if !defined(QT_NO_OFONO)
259 if (QOfonoWrapper::isOfonoAvailable()) {
260 if (!ofonoWrapper)
261 ofonoWrapper = new QOfonoWrapper(this);
262 QStringList modems = ofonoWrapper->allModems();
263 if (interface < modems.size()) {
264 QString modem = ofonoWrapper->allModems().at(interface);
265 if (!modem.isEmpty())
266 return ofonoWrapper->homeMcc(modem);
267 }
268 }
269 #else
270 Q_UNUSED(interface)
271 #endif
272 return QString();
273 }
274
homeMobileNetworkCode(int interface)275 QString QNetworkInfoPrivate::homeMobileNetworkCode(int interface)
276 {
277 #if !defined(QT_NO_OFONO)
278 if (QOfonoWrapper::isOfonoAvailable()) {
279 if (!ofonoWrapper)
280 ofonoWrapper = new QOfonoWrapper(this);
281 QStringList modems = ofonoWrapper->allModems();
282 if (interface < modems.size()) {
283 QString modem = ofonoWrapper->allModems().at(interface);
284 if (!modem.isEmpty())
285 return ofonoWrapper->homeMnc(modem);
286 }
287 }
288 #else
289 Q_UNUSED(interface)
290 #endif
291 return QString();
292 }
293
imsi(int interface)294 QString QNetworkInfoPrivate::imsi(int interface)
295 {
296 #if !defined(QT_NO_OFONO)
297 if (QOfonoWrapper::isOfonoAvailable()) {
298 if (!ofonoWrapper)
299 ofonoWrapper = new QOfonoWrapper(this);
300 QStringList modems = ofonoWrapper->allModems();
301 if (interface < modems.size()) {
302 QString modem = ofonoWrapper->allModems().at(interface);
303 if (!modem.isEmpty())
304 return ofonoWrapper->imsi(modem);
305 }
306 }
307 #else
308 Q_UNUSED(interface)
309 #endif
310 return QString();
311 }
312
locationAreaCode(int interface)313 QString QNetworkInfoPrivate::locationAreaCode(int interface)
314 {
315 #if !defined(QT_NO_OFONO)
316 if (QOfonoWrapper::isOfonoAvailable()) {
317 if (!ofonoWrapper)
318 ofonoWrapper = new QOfonoWrapper(this);
319 QStringList modems = ofonoWrapper->allModems();
320 if (interface < modems.size()) {
321 QString modem = ofonoWrapper->allModems().at(interface);
322 if (!modem.isEmpty())
323 return ofonoWrapper->lac(modem);
324 }
325 }
326 #else
327 Q_UNUSED(interface)
328 #endif
329 return QString();
330 }
331
macAddress(QNetworkInfo::NetworkMode mode,int interface)332 QString QNetworkInfoPrivate::macAddress(QNetworkInfo::NetworkMode mode, int interface)
333 {
334 switch (mode) {
335 case QNetworkInfo::WlanMode: {
336 QStringList dirs = QDir(*NETWORK_SYSFS_PATH()).entryList(*WLAN_MASK());
337 if (interface < dirs.size()) {
338 QFile carrier(*NETWORK_SYSFS_PATH() + dirs.at(interface) + QString(QStringLiteral("/address")));
339 if (carrier.open(QIODevice::ReadOnly))
340 return QString::fromLatin1(carrier.readAll().simplified().data());
341 }
342 break;
343 }
344
345 case QNetworkInfo::EthernetMode: {
346 QStringList dirs = QDir(*NETWORK_SYSFS_PATH()).entryList(*ETHERNET_MASK());
347 if (interface < dirs.size()) {
348 QFile carrier(*NETWORK_SYSFS_PATH() + dirs.at(interface) + QString(QStringLiteral("/address")));
349 if (carrier.open(QIODevice::ReadOnly))
350 return QString::fromLatin1(carrier.readAll().simplified().data());
351 }
352 break;
353 }
354
355 case QNetworkInfo::BluetoothMode: {
356 #if !defined(QT_NO_BLUEZ)
357 int ctl = socket(AF_BLUETOOTH, SOCK_RAW, BTPROTO_HCI);
358 if (ctl < 0)
359 break;
360 struct hci_dev_list_req *deviceList = (struct hci_dev_list_req *)malloc(HCI_MAX_DEV * sizeof(struct hci_dev_req) + sizeof(uint16_t));
361 deviceList->dev_num = HCI_MAX_DEV;
362 QString macAddress;
363 if (ioctl(ctl, HCIGETDEVLIST, deviceList) == 0) {
364 int count = deviceList->dev_num;
365 if (interface < count) {
366 struct hci_dev_info deviceInfo;
367 deviceInfo.dev_id = (deviceList->dev_req + interface)->dev_id;
368 if (ioctl(ctl, HCIGETDEVINFO, &deviceInfo) == 0) {
369 // do not use BDADDR_ANY, fails with gcc 4.6
370 bdaddr_t bdaddr_any = (bdaddr_t) {{0, 0, 0, 0, 0, 0}};
371 if (hci_test_bit(HCI_RAW, &deviceInfo.flags) && !bacmp(&deviceInfo.bdaddr, &bdaddr_any)) {
372 int hciDevice = hci_open_dev(deviceInfo.dev_id);
373 hci_read_bd_addr(hciDevice, &deviceInfo.bdaddr, 1000);
374 hci_close_dev(hciDevice);
375 }
376 char address[18];
377 ba2str(&deviceInfo.bdaddr, address);
378 macAddress = QString::fromLatin1(address);
379 }
380 }
381 }
382 free(deviceList);
383 close(ctl);
384 return macAddress;
385 #else
386 break;
387 #endif // QT_NO_BLUEZ
388 }
389
390 // case QNetworkInfo::GsmMode:
391 // case QNetworkInfo::CdmaMode:
392 // case QNetworkInfo::WcdmaMode:
393 // case QNetworkInfo::WimaxMode:
394 // case QNetworkInfo::LteMode:
395 // case QNetworkInfo::TdscdmaMode:
396 default:
397 break;
398 };
399
400 return QString();
401 }
402
networkName(QNetworkInfo::NetworkMode mode,int interface)403 QString QNetworkInfoPrivate::networkName(QNetworkInfo::NetworkMode mode, int interface)
404 {
405 if (watchNetworkName && (mode == QNetworkInfo::WlanMode
406 || mode == QNetworkInfo::EthernetMode
407 || mode == QNetworkInfo::BluetoothMode)) {
408 return networkNames.value(QPair<QNetworkInfo::NetworkMode, int>(mode, interface));
409 } else
410 return getNetworkName(mode, interface);
411 }
412
413 extern QMetaMethod proxyToSourceSignal(const QMetaMethod &, QObject *);
414
connectNotify(const QMetaMethod & signal)415 void QNetworkInfoPrivate::connectNotify(const QMetaMethod &signal)
416 {
417 #if !defined(QT_NO_OFONO)
418 if (QOfonoWrapper::isOfonoAvailable()) {
419 if (!ofonoWrapper)
420 ofonoWrapper = new QOfonoWrapper(this);
421 QMetaMethod sourceSignal = proxyToSourceSignal(signal, ofonoWrapper);
422 connect(ofonoWrapper, sourceSignal, this, signal, Qt::UniqueConnection);
423 }
424 #endif
425
426 static const QMetaMethod currentNetworkModeChangedSignal = QMetaMethod::fromSignal(&QNetworkInfoPrivate::currentNetworkModeChanged);
427 static const QMetaMethod networkNameChangedSignal = QMetaMethod::fromSignal(&QNetworkInfoPrivate::networkNameChanged);
428 static const QMetaMethod networkSignalStrengthChangedSignal = QMetaMethod::fromSignal(&QNetworkInfoPrivate::networkSignalStrengthChanged);
429 static const QMetaMethod networkStatusChangedSignal = QMetaMethod::fromSignal(&QNetworkInfoPrivate::networkStatusChanged);
430
431 // we always monitor "networkInterfaceCount" , as long as users connect any signals,
432 // with update to date network interface counts, we can compute network mode, strength,
433 // status, name properties in an efficient way
434 if (!watchNetworkInterfaceCount) {
435 QList<QNetworkInfo::NetworkMode> modes;
436 modes << QNetworkInfo::WlanMode << QNetworkInfo::EthernetMode << QNetworkInfo::BluetoothMode;
437 networkInterfaceCounts.clear();
438 foreach (QNetworkInfo::NetworkMode mode, modes)
439 networkInterfaceCounts[mode] = getNetworkInterfaceCount(mode);
440 #if !defined(QT_NO_UDEV)
441 if (!udevHandle) {
442 udevHandle = udev_new();
443 udevMonitor = udev_monitor_new_from_netlink(udevHandle, "udev");
444 udev_monitor_filter_add_match_subsystem_devtype(udevMonitor, "net", NULL);
445 udev_monitor_enable_receiving(udevMonitor);
446 udevNotifier = new QSocketNotifier(udev_monitor_get_fd(udevMonitor), QSocketNotifier::Read, this);
447 connect(udevNotifier, SIGNAL(activated(int)), this, SLOT(onUdevChanged()));
448 }
449 udevNotifier->setEnabled(true);
450
451 #endif // QT_NO_UDEV
452 watchNetworkInterfaceCount = true;
453 }
454
455 if (signal == currentNetworkModeChangedSignal) {
456 // we monitor "networkStatus" by default, as long as currentNetworkModeChanged signal
457 // is connected, with always up to date network status, current network mode can
458 // be fast computed.
459 if (!watchNetworkStatus) {
460 QList<QNetworkInfo::NetworkMode> modes;
461 modes << QNetworkInfo::WlanMode << QNetworkInfo::EthernetMode << QNetworkInfo::BluetoothMode;
462 networkStatuses.clear();
463 foreach (QNetworkInfo::NetworkMode mode, modes) {
464 int count = networkInterfaceCount(mode);
465 for (int i = 0; i < count; ++i)
466 networkStatuses[QPair<QNetworkInfo::NetworkMode, int>(mode, i)] = getNetworkStatus(mode, i);
467 }
468 watchNetworkStatus = true;
469 }
470 currentMode = getCurrentNetworkMode();
471 watchCurrentNetworkMode = true;
472 } else if (signal == networkSignalStrengthChangedSignal) {
473 QList<QNetworkInfo::NetworkMode> modes;
474 modes << QNetworkInfo::WlanMode << QNetworkInfo::EthernetMode << QNetworkInfo::BluetoothMode;
475 networkSignalStrengths.clear();
476 foreach (QNetworkInfo::NetworkMode mode, modes) {
477 int count = networkInterfaceCount(mode);
478 for (int i = 0; i < count; ++i)
479 networkSignalStrengths[QPair<QNetworkInfo::NetworkMode, int>(mode, i)] = getNetworkSignalStrength(mode, i);
480 }
481
482 watchNetworkSignalStrength = true;
483 } else if (signal == networkStatusChangedSignal) {
484 QList<QNetworkInfo::NetworkMode> modes;
485 modes << QNetworkInfo::WlanMode << QNetworkInfo::EthernetMode << QNetworkInfo::BluetoothMode;
486 networkStatuses.clear();
487 foreach (QNetworkInfo::NetworkMode mode, modes) {
488 int count = networkInterfaceCount(mode);
489 for (int i = 0; i < count; ++i)
490 networkStatuses[QPair<QNetworkInfo::NetworkMode, int>(mode, i)] = getNetworkStatus(mode, i);
491 }
492
493 watchNetworkStatus = true;
494 } else if (signal == networkNameChangedSignal) {
495 QList<QNetworkInfo::NetworkMode> modes;
496 modes << QNetworkInfo::WlanMode << QNetworkInfo::EthernetMode << QNetworkInfo::BluetoothMode;
497 networkNames.clear();
498 foreach (QNetworkInfo::NetworkMode mode, modes) {
499 int count = networkInterfaceCount(mode);
500 for (int i = 0; i < count; ++i)
501 networkNames[QPair<QNetworkInfo::NetworkMode, int>(mode, i)] = getNetworkName(mode, i);
502 }
503
504 watchNetworkName = true;
505 } else if (signal == currentNetworkModeChangedSignal) {
506 currentMode = getCurrentNetworkMode();
507 watchCurrentNetworkMode = true;
508 } else {
509 return;
510 }
511
512 if (!timer) {
513 timer = new QTimer(this);
514 timer->setInterval(2000);
515 connect(timer, SIGNAL(timeout()), this, SLOT(onTimeout()));
516 }
517
518 if (!timer->isActive())
519 timer->start();
520 }
521
disconnectNotify(const QMetaMethod & signal)522 void QNetworkInfoPrivate::disconnectNotify(const QMetaMethod &signal)
523 {
524 #if !defined(QT_NO_OFONO)
525 if (!QOfonoWrapper::isOfonoAvailable() || !ofonoWrapper)
526 return;
527
528 {
529 QMetaMethod sourceSignal = proxyToSourceSignal(signal, ofonoWrapper);
530 disconnect(ofonoWrapper, sourceSignal, this, signal);
531 }
532 #endif
533
534 static const QMetaMethod currentNetworkModeChangedSignal = QMetaMethod::fromSignal(&QNetworkInfoPrivate::currentNetworkModeChanged);
535 static const QMetaMethod networkInterfaceCountChangedSignal = QMetaMethod::fromSignal(&QNetworkInfoPrivate::networkInterfaceCountChanged);
536 static const QMetaMethod networkNameChangedSignal = QMetaMethod::fromSignal(&QNetworkInfoPrivate::networkNameChanged);
537 static const QMetaMethod networkSignalStrengthChangedSignal = QMetaMethod::fromSignal(&QNetworkInfoPrivate::networkSignalStrengthChanged);
538 static const QMetaMethod networkStatusChangedSignal = QMetaMethod::fromSignal(&QNetworkInfoPrivate::networkStatusChanged);
539
540 if (signal == networkInterfaceCountChangedSignal
541 && !watchNetworkStatus && !watchNetworkName && !watchNetworkSignalStrength ) {
542 #if !defined(QT_NO_UDEV)
543 udevNotifier->setEnabled(false);
544 watchNetworkInterfaceCount = false;
545 return;
546 #endif // QT_NO_UDEV
547 watchNetworkInterfaceCount = false;
548 } else if (signal == networkSignalStrengthChangedSignal) {
549 watchNetworkSignalStrength = false;
550 } else if ((!watchCurrentNetworkMode) && (signal == networkStatusChangedSignal)) {
551 watchNetworkStatus = false;
552 } else if (signal == networkNameChangedSignal) {
553 watchNetworkName = false;
554 } else if (signal == currentNetworkModeChangedSignal) {
555 watchCurrentNetworkMode = false;
556 } else {
557 return;
558 }
559
560 if (!watchNetworkInterfaceCount && !watchNetworkSignalStrength && !watchNetworkStatus && !watchNetworkName && !watchCurrentNetworkMode)
561 timer->stop();
562 }
563
564 #if !defined(QT_NO_UDEV)
onUdevChanged()565 void QNetworkInfoPrivate::onUdevChanged()
566 {
567 struct udev_device *udevDevice = udev_monitor_receive_device(udevMonitor);
568 if (!udevDevice)
569 return;
570
571 if (0 != strcmp(udev_device_get_subsystem(udevDevice), "net"))
572 return;
573
574 QString sysname(QString::fromLocal8Bit(udev_device_get_sysname(udevDevice)));
575 if (watchNetworkInterfaceCount) {
576 if (sysname.startsWith(QString(QStringLiteral("eth"))) || sysname.startsWith(QString(QStringLiteral("usb")))) {
577 if (0 == strcmp(udev_device_get_action(udevDevice), "add"))
578 ++networkInterfaceCounts[QNetworkInfo::EthernetMode];
579 else if (0 == strcmp(udev_device_get_action(udevDevice), "remove"))
580 --networkInterfaceCounts[QNetworkInfo::EthernetMode];
581 emit networkInterfaceCountChanged(QNetworkInfo::EthernetMode,
582 networkInterfaceCounts[QNetworkInfo::EthernetMode]);
583 } else if (sysname.startsWith(QString(QStringLiteral("wlan")))) {
584 if (0 == strcmp(udev_device_get_action(udevDevice), "add"))
585 ++networkInterfaceCounts[QNetworkInfo::WlanMode];
586 else if (0 == strcmp(udev_device_get_action(udevDevice), "remove"))
587 --networkInterfaceCounts[QNetworkInfo::WlanMode];
588 emit networkInterfaceCountChanged(QNetworkInfo::WlanMode,
589 networkInterfaceCounts[QNetworkInfo::WlanMode]);
590 }
591 }
592
593 udev_device_unref(udevDevice);
594 }
595 #endif // QT_NO_UDEV
596
onTimeout()597 void QNetworkInfoPrivate::onTimeout()
598 {
599 #if defined(QT_NO_UDEV)
600 if (watchNetworkInterfaceCount) {
601 QList<QNetworkInfo::NetworkMode> modes;
602 modes << QNetworkInfo::WlanMode << QNetworkInfo::EthernetMode << QNetworkInfo::BluetoothMode;
603 foreach (QNetworkInfo::NetworkMode mode, modes) {
604 int value = getNetworkInterfaceCount(mode);
605 if (networkInterfaceCounts.value(mode) != value) {
606 networkInterfaceCounts[mode] = value;
607 emit networkInterfaceCountChanged(mode, value);
608 }
609 }
610 }
611 #endif // QT_NO_UDEV
612
613 if (!watchNetworkSignalStrength && !watchNetworkStatus && !watchNetworkName && !watchCurrentNetworkMode)
614 return;
615
616 QList<QNetworkInfo::NetworkMode> modes;
617 modes << QNetworkInfo::WlanMode << QNetworkInfo::EthernetMode << QNetworkInfo::BluetoothMode;
618 foreach (QNetworkInfo::NetworkMode mode, modes) {
619 int count = networkInterfaceCount(mode);
620 for (int i = 0; i < count; ++i) {
621 if (watchNetworkSignalStrength) {
622 int value = getNetworkSignalStrength(mode, i);
623 QPair<QNetworkInfo::NetworkMode, int> key(mode, i);
624 if (networkSignalStrengths.value(key) != value) {
625 networkSignalStrengths[key] = value;
626 emit networkSignalStrengthChanged(mode, i, value);
627 }
628 }
629
630 if (watchNetworkStatus) {
631 QNetworkInfo::NetworkStatus value = getNetworkStatus(mode, i);
632 QPair<QNetworkInfo::NetworkMode, int> key(mode, i);
633 if (networkStatuses.value(key) != value) {
634 networkStatuses[key] = value;
635 emit networkStatusChanged(mode, i, value);
636 }
637 }
638
639 if (watchNetworkName) {
640 QString value = getNetworkName(mode, i);
641 QPair<QNetworkInfo::NetworkMode, int> key(mode, i);
642 if (networkNames.value(key) != value) {
643 networkNames[key] = value;
644 emit networkNameChanged(mode, i, value);
645 }
646 }
647 }
648 }
649
650 if (watchCurrentNetworkMode) {
651 QNetworkInfo::NetworkMode value = getCurrentNetworkMode();
652 if (currentMode != value) {
653 currentMode = value;
654 emit currentNetworkModeChanged(value);
655 }
656 }
657
658 }
659
getNetworkInterfaceCount(QNetworkInfo::NetworkMode mode)660 int QNetworkInfoPrivate::getNetworkInterfaceCount(QNetworkInfo::NetworkMode mode)
661 {
662 switch (mode) {
663 case QNetworkInfo::WlanMode:
664 return QDir(*NETWORK_SYSFS_PATH()).entryList(*WLAN_MASK()).size();
665
666 case QNetworkInfo::EthernetMode:
667 return QDir(*NETWORK_SYSFS_PATH()).entryList(*ETHERNET_MASK()).size();
668
669 case QNetworkInfo::BluetoothMode: {
670 int count = -1;
671 #if !defined(QT_NO_BLUEZ)
672 int ctl = socket(AF_BLUETOOTH, SOCK_RAW, BTPROTO_HCI);
673 if (ctl < 0)
674 return count;
675 struct hci_dev_list_req *deviceList = (struct hci_dev_list_req *)malloc(HCI_MAX_DEV * sizeof(struct hci_dev_req) + sizeof(uint16_t));
676 deviceList->dev_num = HCI_MAX_DEV;
677 if (ioctl(ctl, HCIGETDEVLIST, deviceList) == 0)
678 count = deviceList->dev_num;
679 free(deviceList);
680 close(ctl);
681 #endif // QT_NO_BLUEZ
682 return count;
683 }
684
685 case QNetworkInfo::GsmMode:
686 case QNetworkInfo::CdmaMode:
687 case QNetworkInfo::WcdmaMode:
688 case QNetworkInfo::LteMode:
689 case QNetworkInfo::TdscdmaMode:
690 #if !defined(QT_NO_OFONO)
691 if (QOfonoWrapper::isOfonoAvailable()) {
692 if (!ofonoWrapper)
693 ofonoWrapper = new QOfonoWrapper(this);
694 return ofonoWrapper->allModems().size();
695 }
696 #endif
697
698 // case QNetworkInfo::WimaxMode:
699 default:
700 return -1;
701 };
702 }
703
getNetworkSignalStrength(QNetworkInfo::NetworkMode mode,int interface)704 int QNetworkInfoPrivate::getNetworkSignalStrength(QNetworkInfo::NetworkMode mode, int interface)
705 {
706 switch (mode) {
707 case QNetworkInfo::WlanMode: {
708 QFile file(QString(QStringLiteral("/proc/net/wireless")));
709 if (!file.open(QIODevice::ReadOnly | QIODevice::Text))
710 return -1;
711
712 QTextStream in(&file);
713 QString interfaceName = interfaceForMode(QNetworkInfo::WlanMode, interface).name();
714
715 QStringList lines = in.readAll().split(QStringLiteral("\n"));
716 for (int i = 0; i < lines.size(); i++) {
717 QString line = lines.at(i);
718 if (!line.isNull() && line.left(6).contains(interfaceName)) {
719 // A typical wireless received signal power over a network falls into the range of (-120, -20),
720 // we shift the dbm value, which is read from the field "Quality - level" in "/proc/net/wireless",
721 // from (-120, -20) to (0, 100) by adding 120. In case of outliers, we restrict them to the
722 // corresponding boundary value.
723 QString token = line.section(QString(QStringLiteral(" ")), 3, 3, QString::SectionSkipEmpty).simplified();
724 token.chop(1);
725 bool ok;
726 int signalStrength = token.toInt(&ok);
727 if (ok) {
728 signalStrength += 120;
729 if (signalStrength > 100)
730 signalStrength = 100;
731 else if (signalStrength < 0)
732 signalStrength = 0;
733 return signalStrength;
734 } else {
735 return -1;
736 }
737 }
738 }
739
740 break;
741 }
742
743 case QNetworkInfo::EthernetMode:
744 if (networkStatus(QNetworkInfo::EthernetMode, interface) == QNetworkInfo::HomeNetwork)
745 return 100;
746 else
747 return -1;
748
749 case QNetworkInfo::GsmMode:
750 case QNetworkInfo::CdmaMode:
751 case QNetworkInfo::WcdmaMode:
752 case QNetworkInfo::LteMode:
753 case QNetworkInfo::TdscdmaMode:
754 #if !defined(QT_NO_OFONO)
755 if (QOfonoWrapper::isOfonoAvailable()) {
756 if (!ofonoWrapper)
757 ofonoWrapper = new QOfonoWrapper(this);
758 QStringList modems = ofonoWrapper->allModems();
759 if (interface < modems.size()) {
760 QString modem = ofonoWrapper->allModems().at(interface);
761 if (!modem.isEmpty())
762 return ofonoWrapper->signalStrength(modem);
763 }
764 }
765 #endif
766 break;
767
768 case QNetworkInfo::BluetoothMode: {
769 int signalStrength = -1;
770 #if !defined(QT_NO_BLUEZ)
771 int ctl = socket(AF_BLUETOOTH, SOCK_RAW, BTPROTO_HCI);
772 if (ctl < 0)
773 break;
774 struct hci_dev_list_req *deviceList = (struct hci_dev_list_req *)malloc(HCI_MAX_DEV * sizeof(struct hci_dev_req) + sizeof(uint16_t));
775 deviceList->dev_num = HCI_MAX_DEV;
776 if (ioctl(ctl, HCIGETDEVLIST, deviceList) == 0) {
777 int count = deviceList->dev_num;
778 if (interface < count) {
779 signalStrength = 0; // Valid interface
780
781 struct hci_conn_list_req *connectionList = (struct hci_conn_list_req *)malloc(sizeof(struct hci_conn_info) + sizeof(struct hci_conn_list_req));
782 connectionList->dev_id = (deviceList->dev_req + interface)->dev_id;
783 connectionList->conn_num = 1;
784 if (ioctl(ctl, HCIGETCONNLIST, connectionList) == 0) {
785 if (connectionList->conn_num == 1) {
786 int fd = hci_open_dev((deviceList->dev_req + interface)->dev_id);
787 if (fd > 0) {
788 struct hci_conn_info_req *connectionInfo = (struct hci_conn_info_req *)malloc(sizeof(struct hci_conn_info_req) + sizeof(struct hci_conn_info));
789 bacpy(&connectionInfo->bdaddr, &connectionList->conn_info->bdaddr);
790 connectionInfo->type = ACL_LINK;
791 if (ioctl(fd, HCIGETCONNINFO, connectionInfo) == 0) {
792 uint8_t linkQuality;
793 if (hci_read_link_quality(fd, htobs(connectionInfo->conn_info->handle), &linkQuality, 0) == 0)
794 signalStrength = linkQuality * 100 / 255;
795 }
796 free(connectionInfo);
797 }
798 }
799 }
800 free (connectionList);
801 }
802 }
803 free(deviceList);
804 close(ctl);
805 #endif // QT_NO_BLUEZ
806 return signalStrength;
807 }
808
809 // case QNetworkInfo::WimaxMode:
810 default:
811 break;
812 };
813
814 return -1;
815 }
816
getCurrentNetworkMode()817 QNetworkInfo::NetworkMode QNetworkInfoPrivate::getCurrentNetworkMode()
818 {
819 // TODO multiple-interface support
820 if (networkStatus(QNetworkInfo::EthernetMode, 0) == QNetworkInfo::HomeNetwork)
821 return QNetworkInfo::EthernetMode;
822 else if (networkStatus(QNetworkInfo::WlanMode, 0) == QNetworkInfo::HomeNetwork)
823 return QNetworkInfo::WlanMode;
824 else if (networkStatus(QNetworkInfo::BluetoothMode, 0) == QNetworkInfo::HomeNetwork)
825 return QNetworkInfo::BluetoothMode;
826 else if (networkStatus(QNetworkInfo::WimaxMode, 0) == QNetworkInfo::HomeNetwork)
827 return QNetworkInfo::WimaxMode;
828 else if (networkStatus(QNetworkInfo::LteMode, 0) == QNetworkInfo::HomeNetwork)
829 return QNetworkInfo::LteMode;
830 else if (networkStatus(QNetworkInfo::WcdmaMode, 0) == QNetworkInfo::HomeNetwork)
831 return QNetworkInfo::WcdmaMode;
832 else if (networkStatus(QNetworkInfo::CdmaMode, 0) == QNetworkInfo::HomeNetwork)
833 return QNetworkInfo::CdmaMode;
834 else if (networkStatus(QNetworkInfo::GsmMode, 0) == QNetworkInfo::HomeNetwork)
835 return QNetworkInfo::GsmMode;
836 else if (networkStatus(QNetworkInfo::TdscdmaMode, 0) == QNetworkInfo::HomeNetwork)
837 return QNetworkInfo::TdscdmaMode;
838 else if (networkStatus(QNetworkInfo::WimaxMode, 0) == QNetworkInfo::Roaming)
839 return QNetworkInfo::WimaxMode;
840 else if (networkStatus(QNetworkInfo::LteMode, 0) == QNetworkInfo::Roaming)
841 return QNetworkInfo::LteMode;
842 else if (networkStatus(QNetworkInfo::WcdmaMode, 0) == QNetworkInfo::Roaming)
843 return QNetworkInfo::WcdmaMode;
844 else if (networkStatus(QNetworkInfo::CdmaMode, 0) == QNetworkInfo::Roaming)
845 return QNetworkInfo::CdmaMode;
846 else if (networkStatus(QNetworkInfo::GsmMode, 0) == QNetworkInfo::Roaming)
847 return QNetworkInfo::GsmMode;
848 else if (networkStatus(QNetworkInfo::TdscdmaMode, 0) == QNetworkInfo::Roaming)
849 return QNetworkInfo::TdscdmaMode;
850 else
851 return QNetworkInfo::UnknownMode;
852 }
853
getNetworkStatus(QNetworkInfo::NetworkMode mode,int interface)854 QNetworkInfo::NetworkStatus QNetworkInfoPrivate::getNetworkStatus(QNetworkInfo::NetworkMode mode, int interface)
855 {
856 switch (mode) {
857 case QNetworkInfo::WlanMode: {
858 if (interface < networkInterfaceCount(QNetworkInfo::WlanMode)) {
859 QString fileName = (*WLAN_MASK()).at(0);
860 fileName.chop(1);
861 fileName.append(QString::number(interface));
862 QFile carrier(*NETWORK_SYSFS_PATH() + fileName + QStringLiteral("/carrier"));
863 if (carrier.open(QIODevice::ReadOnly)) {
864 char state;
865 if ((carrier.read(&state, 1) == 1) &&
866 (state == '1')) {
867 return QNetworkInfo::HomeNetwork;
868 }
869 }
870 }
871 return QNetworkInfo::NoNetworkAvailable;
872 }
873
874 case QNetworkInfo::EthernetMode: {
875 if (interface < networkInterfaceCount(QNetworkInfo::EthernetMode)) {
876 for (int i = 0; i < (*ETHERNET_MASK()).length(); i++) {
877 QString fileName = (*ETHERNET_MASK()).at(i);
878 fileName.chop(1);
879 fileName.append(QString::number(interface));
880 QFile carrier(*NETWORK_SYSFS_PATH() + fileName + QStringLiteral("/carrier"));
881 if (carrier.open(QIODevice::ReadOnly)) {
882 char state;
883 if ((carrier.read(&state, 1) == 1) && (state == '1'))
884 return QNetworkInfo::HomeNetwork;
885 }
886 }
887 }
888 return QNetworkInfo::NoNetworkAvailable;
889 }
890
891 case QNetworkInfo::BluetoothMode: {
892 QNetworkInfo::NetworkStatus status = QNetworkInfo::UnknownStatus;
893
894 #if !defined(QT_NO_BLUEZ)
895 int ctl = socket(AF_BLUETOOTH, SOCK_RAW, BTPROTO_HCI);
896 if (ctl < 0)
897 break;
898 struct hci_dev_list_req *deviceList = (struct hci_dev_list_req *)malloc(HCI_MAX_DEV * sizeof(struct hci_dev_req) + sizeof(uint16_t));
899 deviceList->dev_num = HCI_MAX_DEV;
900 if (ioctl(ctl, HCIGETDEVLIST, deviceList) == 0) {
901 int count = deviceList->dev_num;
902 if (interface < count) {
903 status = QNetworkInfo::NoNetworkAvailable; // Valid interface, so either not connected or connected
904 // TODO add support for searching and denied
905 struct hci_conn_list_req *connectionList = (struct hci_conn_list_req *)malloc(sizeof(struct hci_conn_info) + sizeof(struct hci_conn_list_req));
906 connectionList->dev_id = (deviceList->dev_req + interface)->dev_id;
907 connectionList->conn_num = 1;
908 if (ioctl(ctl, HCIGETCONNLIST, connectionList) == 0) {
909 if (connectionList->conn_num == 1)
910 status = QNetworkInfo::HomeNetwork;
911 }
912 free (connectionList);
913 }
914 }
915 free(deviceList);
916 close(ctl);
917 #endif // QT_NO_BLUEZ
918
919 return status;
920 }
921
922 case QNetworkInfo::GsmMode:
923 case QNetworkInfo::CdmaMode:
924 case QNetworkInfo::WcdmaMode:
925 case QNetworkInfo::LteMode:
926 case QNetworkInfo::TdscdmaMode:
927 #if !defined(QT_NO_OFONO)
928 if (QOfonoWrapper::isOfonoAvailable()) {
929 if (!ofonoWrapper)
930 ofonoWrapper = new QOfonoWrapper(this);
931 QStringList modems = ofonoWrapper->allModems();
932 if (interface < modems.size()) {
933 QString modem = ofonoWrapper->allModems().at(interface);
934 if (!modem.isEmpty())
935 return ofonoWrapper->networkStatus(modem);
936 }
937 }
938 #endif
939 break;
940
941 // case QNetworkInfo::WimaxMode:
942 default:
943 break;
944 };
945
946 return QNetworkInfo::UnknownStatus;
947 }
948
getNetworkName(QNetworkInfo::NetworkMode mode,int interface)949 QString QNetworkInfoPrivate::getNetworkName(QNetworkInfo::NetworkMode mode, int interface)
950 {
951 switch (mode) {
952 case QNetworkInfo::WlanMode: {
953 if (interface < networkInterfaceCount(QNetworkInfo::WlanMode)) {
954 int sock = socket(PF_INET, SOCK_DGRAM, 0);
955 if (sock > 0) {
956 char buffer[IW_ESSID_MAX_SIZE + 1];
957 iwreq iwInfo;
958
959 iwInfo.u.essid.pointer = (caddr_t)&buffer;
960 iwInfo.u.essid.length = IW_ESSID_MAX_SIZE + 1;
961 iwInfo.u.essid.flags = 0;
962 QString fileName = (*WLAN_MASK()).at(0);
963 fileName.chop(1);
964 fileName.append(QString::number(interface));
965 strncpy(iwInfo.ifr_name, fileName.toLocal8Bit().constData(), IFNAMSIZ);
966 if (ioctl(sock, SIOCGIWESSID, &iwInfo) == 0) {
967 close(sock);
968 return QString::fromLatin1((const char *)iwInfo.u.essid.pointer);
969 }
970
971 close(sock);
972 }
973 }
974 break;
975 }
976
977 case QNetworkInfo::EthernetMode: {
978 // TODO multiple-interface support
979 char domainName[64];
980 if (getdomainname(domainName, 64) == 0) {
981 if (strcmp(domainName, "(none)") != 0)
982 return QString::fromLatin1(domainName);
983 }
984 break;
985 }
986
987 case QNetworkInfo::BluetoothMode: {
988 #if !defined(QT_NO_BLUEZ)
989 int ctl = socket(AF_BLUETOOTH, SOCK_RAW, BTPROTO_HCI);
990 if (ctl < 0)
991 break;
992 struct hci_dev_list_req *deviceList = (struct hci_dev_list_req *)malloc(HCI_MAX_DEV * sizeof(struct hci_dev_req) + sizeof(uint16_t));
993 deviceList->dev_num = HCI_MAX_DEV;
994 QString networkName;
995 if (ioctl(ctl, HCIGETDEVLIST, deviceList) == 0) {
996 int count = deviceList->dev_num;
997 if (interface < count) {
998 int fd = hci_open_dev((deviceList->dev_req + interface)->dev_id);
999 if (fd > 0) {
1000 char name[249];
1001 if (hci_read_local_name(fd, sizeof(name), name, 0) == 0)
1002 networkName = QString::fromLatin1(name);
1003 }
1004 }
1005 }
1006 free(deviceList);
1007 close(ctl);
1008 return networkName;
1009 #endif // QT_NO_BLUEZ
1010 break;
1011 }
1012
1013 case QNetworkInfo::GsmMode:
1014 case QNetworkInfo::CdmaMode:
1015 case QNetworkInfo::WcdmaMode:
1016 case QNetworkInfo::LteMode:
1017 case QNetworkInfo::TdscdmaMode:
1018 #if !defined(QT_NO_OFONO)
1019 if (QOfonoWrapper::isOfonoAvailable()) {
1020 if (!ofonoWrapper)
1021 ofonoWrapper = new QOfonoWrapper(this);
1022 QStringList modems = ofonoWrapper->allModems();
1023 if (interface < modems.size()) {
1024 QString modem = ofonoWrapper->allModems().at(interface);
1025 if (!modem.isEmpty())
1026 return ofonoWrapper->operatorName(modem);
1027 }
1028 }
1029 #endif
1030 break;
1031
1032 // case QNetworkInfo::WimaxMode:
1033 default:
1034 break;
1035 };
1036
1037 return QString();
1038 }
1039
1040 QT_END_NAMESPACE
1041