VPN Status

This commit is contained in:
Syping 2020-02-02 00:44:30 +01:00
commit 73cbd92121
8 changed files with 348 additions and 0 deletions

78
Ping.cpp Normal file
View file

@ -0,0 +1,78 @@
#include <QAbstractSocket>
#include <QHostAddress>
#include <QTextStream>
#include <QHostInfo>
#include <QList>
#include "Ping.h"
extern "C" {
#include "oping.h"
}
double Ping::ping(const QString &host, int tries, double timeout)
{
double latency;
pingobj_t *pingObj;
pingobj_iter_t *pingIter;
if ((pingObj = ping_construct()) == NULL) {
QTextStream(stderr) << "Ping construction failed " << endl;
return -1;
}
if (ping_setopt(pingObj, PING_OPT_TIMEOUT, (void*)(&timeout)) < 0) {
QTextStream(stderr) << "Setting timeout to" << timeout << " have failed" << endl;
ping_destroy(pingObj);
return -1;
}
QHostAddress hostAddress(host);
if (QAbstractSocket::IPv4Protocol == hostAddress.protocol()) {
if (ping_host_add(pingObj, hostAddress.toString().toStdString().c_str()) < 0) {
ping_destroy(pingObj);
return -1;
}
}
else if (QAbstractSocket::IPv6Protocol == hostAddress.protocol()) {
if (ping_host_add(pingObj, hostAddress.toString().toStdString().c_str()) < 0) {
ping_destroy(pingObj);
return -1;
}
}
else {
QList<QHostAddress> hostAddresses = QHostInfo::fromName(host).addresses();
if (hostAddresses.length() >= 1) {
QString ipStr = hostAddresses.at(0).toString();
if (ping_host_add(pingObj, ipStr.toStdString().c_str()) < 0) {
ping_destroy(pingObj);
return -1;
}
}
else {
ping_destroy(pingObj);
return -1;
}
}
bool hostUp = false;
int curTry = 0;
while (!hostUp && curTry != tries) {
if (ping_send(pingObj) < 0) {
QTextStream(stderr) << "Pinging host " << host << " has failed" << endl;
ping_destroy(pingObj);
return -1;
}
bool pingSuccess = false;
for (pingIter = ping_iterator_get(pingObj); pingIter != NULL; pingIter =
ping_iterator_next(pingIter)) {
size_t len;
len = sizeof(double);
ping_iterator_get_info(pingIter, PING_INFO_LATENCY, &latency, &len);
pingSuccess = !(latency < 0);
}
if (pingSuccess) {
hostUp = true;
}
curTry++;
}
ping_destroy(pingObj);
if (hostUp)
return latency;
return -1;
}

12
Ping.h Normal file
View file

@ -0,0 +1,12 @@
#ifndef PING_H
#define PING_H
#include <QString>
class Ping
{
public:
static double ping(const QString &host, int tries, double timeout = 2.5);
};
#endif // PING_H

69
Runner.cpp Normal file
View file

@ -0,0 +1,69 @@
#include <QDateTime>
#include "Runner.h"
#include "Ping.h"
Runner::Runner(QList<QString> pingHosts) :
pingHosts_p(pingHosts)
{
}
void Runner::refresh()
{
QMutexLocker locker(&mutex);
refreshed_p = QDateTime::currentDateTimeUtc().toTime_t();
}
uint Runner::refreshed()
{
QMutexLocker locker(&mutex);
return refreshed_p;
}
const QString Runner::currentHost()
{
QMutexLocker locker(&mutex);
return currentHost_p;
}
const QMap<QString, double> Runner::pingData()
{
QMutexLocker locker(&mutex);
return pingData_p;
}
void Runner::setCurrentHost(const QString &currentHost)
{
QMutexLocker locker(&mutex);
currentHost_p = currentHost;
}
void Runner::setPingData(const QMap<QString, double> &pingData)
{
QMutexLocker locker(&mutex);
pingData_p = pingData;
}
void Runner::run()
{
// Ping data initialisation
QMap<QString, double> pingData_l;
for (const QString &host : pingHosts_p) {
pingData_l.insert(host, -1);
}
setPingData(pingData_l);
refresh();
forever {
if (QThread::currentThread()->isInterruptionRequested()) {
return;
}
for (const QString &host : pingHosts_p) {
setCurrentHost(host);
refresh();
double ping = Ping::ping(host, 3);
pingData_l[host] = ping;
setPingData(pingData_l);
refresh();
}
}
}

33
Runner.h Normal file
View file

@ -0,0 +1,33 @@
#ifndef RUNNER_H
#define RUNNER_H
#include <QMutexLocker>
#include <QObject>
#include <QThread>
#include <QMutex>
#include <QMap>
class Runner : public QThread
{
Q_OBJECT
public:
Runner(QList<QString> pingHosts);
void refresh();
uint refreshed();
const QString currentHost();
const QMap<QString, double> pingData();
void setCurrentHost(const QString &currentHost);
void setPingData(const QMap<QString, double> &pingData);
private:
QMap<QString, double> pingData_p;
QList<QString> pingHosts_p;
QString currentHost_p;
uint refreshed_p;
mutable QMutex mutex;
protected:
void run();
};
#endif // RUNNER_H

42
Socket.cpp Normal file
View file

@ -0,0 +1,42 @@
#include <QJsonDocument>
#include <QLocalSocket>
#include <QJsonObject>
#include "Socket.h"
Socket::Socket(Runner *runner) :
runner(runner)
{
}
void Socket::incomingConnection(quintptr socketDescriptor)
{
QLocalSocket *socket = new QLocalSocket;
if (!socket->setSocketDescriptor(socketDescriptor, QLocalSocket::ConnectedState, QLocalSocket::WriteOnly)) {
QTextStream(stderr) << "Socket failed to initialise." << endl;
delete socket;
return;
}
QObject::connect(socket, SIGNAL(disconnected()), socket, SLOT(deleteLater()));
QJsonObject pingObject;
QMap<QString, double> pingData_l = runner->pingData();
QMap<QString, double>::const_iterator it = pingData_l.constBegin();
QMap<QString, double>::const_iterator end = pingData_l.constEnd();
while (it != end) {
pingObject.insert(it.key(), it.value());
it++;
}
QJsonObject object;
object.insert("Current", runner->currentHost());
object.insert("Ping", pingObject);
object.insert("Refreshed", QString::number(runner->refreshed(), 16));
QJsonDocument document;
document.setObject(object);
QByteArray jsonData = document.toJson(QJsonDocument::Compact);
socket->write(jsonData + "\n");
socket->disconnectFromServer();
}

19
Socket.h Normal file
View file

@ -0,0 +1,19 @@
#ifndef SOCKET_H
#define SOCKET_H
#include "Runner.h"
#include <QObject>
#include <QLocalServer>
class Socket : public QLocalServer
{
Q_OBJECT
public:
Socket(Runner *runner);
void incomingConnection(quintptr socketDescriptor);
private:
Runner *runner;
};
#endif // SOCKET_H

76
main.cpp Normal file
View file

@ -0,0 +1,76 @@
#include <QCommandLineParser>
#include <QCoreApplication>
#include <QJsonDocument>
#include <QTextStream>
#include <QJsonObject>
#include <QJsonArray>
#include <QFile>
#include "Runner.h"
#include "Socket.h"
int main(int argc, char *argv[])
{
QCoreApplication::setSetuidAllowed(true);
QCoreApplication a(argc, argv);
QCommandLineParser parser;
parser.addPositionalArgument("config", "Ping configuration");
parser.addPositionalArgument("socket", "Unix socket");
parser.process(a);
const QStringList args = parser.positionalArguments();
if (args.length() != 2) {
QTextStream(stderr) << "Not enough or too many arguments was given!" << endl;
return 1;
}
const QString pingConfig = args.at(0);
const QString unixSocket = args.at(1);
QByteArray jsonContent;
QFile jsonFile(pingConfig);
if (jsonFile.open(QFile::ReadOnly)) {
jsonContent = jsonFile.readAll();
jsonFile.close();
}
else {
QTextStream(stderr) << "Failed to read Ping configuration!" << endl;
return 1;
}
QList<QString> pingHosts;
QJsonDocument jsonDocument = QJsonDocument::fromJson(jsonContent);
QJsonObject jsonObject = jsonDocument.object();
QJsonObject::const_iterator it = jsonObject.constBegin();
QJsonObject::const_iterator end = jsonObject.constEnd();
while (it != end) {
if (it.value().isArray()) {
QJsonArray array = it.value().toArray();
QJsonArray::const_iterator it = array.constBegin();
QJsonArray::const_iterator end = array.constEnd();
while (it != end) {
const QString host = array.at(it.i).toString();
if (!host.isEmpty() && host != "none" && !pingHosts.contains(host))
pingHosts << host;
it++;
}
}
else if (it.value().isString()) {
const QString host = it.value().toString();
if (!host.isEmpty() && host != "none" && !pingHosts.contains(host))
pingHosts << host;
}
it++;
}
Runner runner(pingHosts);
Socket socket(&runner);
socket.setSocketOptions(QLocalServer::WorldAccessOption);
if (!socket.listen(unixSocket)) {
QTextStream(stderr) << "Failed to initialise Unix socket!" << endl;
return 1;
}
runner.start();
return a.exec();
}

19
vpnstatus.pro Normal file
View file

@ -0,0 +1,19 @@
QT -= gui
QT += network
CONFIG += c++11 console
CONFIG -= app_bundle
unix: DEFINES += PRIVILEGE_DROP_REQUIRED
unix: LIBS += -loping
SOURCES += \
main.cpp \
Ping.cpp \
Runner.cpp \
Socket.cpp
HEADERS += \
Ping.h \
Runner.h \
Socket.h