Wifi Scanner App for Linux in C++ using Qt
--
Last year I’ve implemented a Wifi Scanner app for Linux. The source code of this app can be accessed on my Github profile.
By creating this app I was able to learn the following concepts and technologies:
- Qt (https://www.qt.io/): cross-platform GUI widget toolkit, originally developed by Trolltech, later by Nokia. It’s used by many big companies worldwide
- wifi-scan library (https://github.com/bmegli/wifi-scan): a small C/C++ library for monitoring signal strength of WiFi networks. Developed by Bartosz Meglicki (https://github.com/bmegli)
- thread handling: http://deathbytape.com/articles/2015/02/03/cpp-threading.html
- mutual exclusion: https://stackoverflow.com/questions/9640058/handling-mutual-exclusion-in-c11
- open a file: http://www.cplusplus.com/reference/fstream/ifstream/open/
- using vector: https://www.codeguru.com/cpp/cpp/cpp_mfc/stl/article.php/c4027/C-Tutorial-A-Beginners-Guide-to-stdvector-Part-1.htm
- using promise and future (
std::promise
andstd::future
) for timing: http://www.modernescpp.com/index.php/promise-and-future
The implementation is done in C++. The present article describes the implementation details with some code snippets.
Keywords: C, C++, Wifi, Wifi Scanner, threads, mutex, mutual exclusion, file, vector, promise, Qt, RSSI, QMake
DISCLAIMER: THE VIEWS AND OPINIONS EXPRESSED IN THIS ARTICLE ARE THOSE OF THE AUTHOR AND DO NOT REFLECT THE OFFICIAL POLICY OR POSITION OF THE EMPLOYER OF THE AUTHOR. THE ARTICLE IS NOT ENDORSED BY, DIRECTLY AFFILIATED WITH, MAINTAINED, AUTHORIZED, OR SPONSORED BY ANY CORPORATION OR ORGANIZATION. THE INFORMATION CONTAINED ON THIS ARTICLE IS INTENDED SOLELY TO PROVIDE GENERAL GUIDANCE ON MATTERS OF INTEREST FOR THE PERSONAL USE OF THE READER, WHO ACCEPTS FULL RESPONSIBILITY FOR ITS USE. ALTHOUGH THE AUTHOR HAS MADE EVERY EFFORT TO ENSURE THAT THE INFORMATION IN THIS ARTICLE WAS CORRECT AT THE TIME OF THE WRITING, THE AUTHOR DOES NOT ASSUME AND HEREBY DISCLAIM ANY LIABILITY TO ANY PARTY FOR ANY LOSS, DAMAGE, OR DISRUPTION CAUSED BY ERRORS OR OMISSIONS, WHETHER SUCH ERRORS OR OMISSIONS RESULT FROM NEGLIGENCE, ACCIDENT, OR ANY OTHER CAUSE.
Table of Content
The article is divided into the following chapters:
- Motivation
- Required knowledge
- Introduction
- Building the app
- Configuring the app
- Running the app
- Implementation details
- The main() method
- The wifiScannerThread() method
- The WifiAPCollection class
- The ShapedDashboard class
- The WifiAP class
- References
Motivation
During the year I spent in the university as a PhD student I had two research topics I worked on. One of them was Wi-Fi based positioning techniques for presence and location based services. I was implementing various positioning algorithms to be able to simulate their behavior and analyze their accuracy.
During this research work we have implemented an application in Java, which reads signal strengths of surrounding Wi-Fi routers and saves this information for further processing. I was interested in how to implement the reading of signal strengths in a programming language different from Java.
I like working in Linux environment, therefore I choose Linux and C++. In the meantime I found Qt as a suitable GUI widget toolkit for the visualization of signal strengths.
Required knowledge
In order to understand this article you need basic understanding of C++ programming, Qt, and Wi-Fi signal strengths. The following links can be a good starting point:
- C++: https://www.tutorialspoint.com/cplusplus/
- Qt Getting Started: http://doc.qt.io/qt-5/qtexamplesandtutorials.html
- Qt for Linux: http://doc.qt.io/qt-5/linux.html
- RSSI: https://en.wikipedia.org/wiki/Received_signal_strength_indication
Introduction
The Wifi Scanner App is built under Linux, and it shows a circle shaped window with the surrounding access point names. The size of the arc in the circle and the darkness of the color indicates the signal strength of the Wifi AP. The visualization was inspired by the Analog Clock example app of Qt: http://doc.qt.io/qt-5/qtwidgets-widgets-analogclock-example.html.
The app was built and tested on Ubuntu 17.10 (artful)
. Qt version 5.9.1
, QMake version 3.1
, g++ version 7.2.0 (Ubuntu 7.2.0–8ubuntu3.2)
.
Building the app
The build script will run qmake
to generate the Makefile
and the run make
to build the app:
./build.sh
The qmake project file MeerkatWifiScannerLinux.pro
contains the reference to be able to use libmnl
which is needed to build the app.
QMAKE_CFLAGS += -lmnl
QMAKE_LIBS += -lmnl
If you don’t have libmnl
in your system, try the following:
sudo apt-get update && sudo apt-get install build-essential libmnl0 libmnl-dev
The app requires Qt as well, which can be installed with:
sudo apt-get install qtcreator qt5-default qtdeclarative5-dev
Configuring the app
This script will get the default wireless adapter name and saves it to MeerkatWifiScanner.conf
:
./configure.sh
(Originally I called the app “MeerkatWifiScanner”, that’s why the config file is named like this.) The Wifi Scanner app reads this config file to determine which Wireless Adapter needs to be used. This script also calls xhost
to ensure that the app can be run as root.
Running the app
The Wifi Scanner app will run as root. This is needed to be able to query the list of AP’s.
./run.sh
Implementation details
The starting point of the application is main.cpp
. The application needs many standard libraries, as well as the Wi-Fi scanner library.
#include <QApplication>
#include <iostream>
#include <chrono>
#include <future>
#include <mutex>
#include <vector>
#include <fstream>#include "wifi_scan.h"
#include "shapeddashboard.h"
#include "wifiapcollection.h"
#include "wifiap.h"
We use mutex for handling the refresh of the list of Wi-Fi access points.
The list of Wi-Fi access points is read in a thread, and stored in a Vector. The method is defined before the main()
method in order to be able to use it there.
std::mutex mu;void wifiScannerThread(std::future<void> futureObj, std::string WifiIfName, WifiAPCollection *wifiAPCollection);
The main() method
First the configuration file is read, to get the default Wi-Fi adapter name (the name of the Wi-Fi device in your computer), then the WifiAPCollection
object is instantiated. This object stores the list of Wi-Fi access points. It will be described later. The WifiAPCollection
object is used as volatile, because it is modified in a thread.
The wifiScannerThread
method is registered with:
After this the Qt application is initialized.
For the thread handling we need to call the setValue() method of the exitSignal promise, and we need to call th.join() method:
The visualization, the dashboard is implemented in shapeddashboard.cpp
.
Themain()
method looks like the following:
The wifiScannerThread() method
The list of Wi-Fi access points is read in a thread, and stored in a Vector. The refresh frequency is 3 seconds. There is also a limit introduced that the max number of APs which are processed is 6.
The documentation of the Wi-Fi Scanner library can be accessed at: https://github.com/bmegli/wifi-scan
In order to visualize the signal strengths properly, some correction needed to be implemented on the result set returned by the Wi-Fi Scanner library.
To handle the 3 seconds refresh, I used
std::promise::get_future()
: http://www.cplusplus.com/reference/future/promise/get_future/std::future::wait_for()
: http://www.cplusplus.com/reference/future/future/wait_for/
The WifiAPCollection class
The list of APs with the signal strengths are stored in a class. This is implemented in wifiapcollection.cpp
.
The ShapedDashboard class
The ShapedDashboard
class is inherited from the QWidget
class. It processing the signal strength data and visualized it in the widget. Also a progress indicator is implemented, because the scanning might take some time, and therefore the signal strength data is not always available.
The moving of the window is also implemented by processing the corresponding mouse events.
The full implementation looks like the following.
The WifiAP class
To handle the data of one Wi-Fi access point, also a class was implemented. It’s a simple class.
References
To be able to implement this app, several sources were used on the web. Most important sources were the website of Qt, especially the example apps, and the docs of the Wi-Fi scanner library. Of course lot of information can be found on stackoverflow and also on C++ related websites.