WireGuard for MacOS (#248)
* WireGuard for MacOS * Fix openvpn block-outside-dns
This commit is contained in:
parent
ed5dc7cdfd
commit
35ecb8499d
118 changed files with 5150 additions and 3486 deletions
286
client/mozilla/shared/ipaddress.cpp
Normal file
286
client/mozilla/shared/ipaddress.cpp
Normal file
|
|
@ -0,0 +1,286 @@
|
|||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#include "ipaddress.h"
|
||||
|
||||
#include <QtMath>
|
||||
|
||||
#include "leakdetector.h"
|
||||
|
||||
IPAddress::IPAddress() { MZ_COUNT_CTOR(IPAddress); }
|
||||
|
||||
IPAddress::IPAddress(const QString& ip) {
|
||||
MZ_COUNT_CTOR(IPAddress);
|
||||
if (ip.contains("/")) {
|
||||
QPair<QHostAddress, int> p = QHostAddress::parseSubnet(ip);
|
||||
m_address = p.first;
|
||||
m_prefixLength = p.second;
|
||||
} else {
|
||||
m_address = QHostAddress(ip);
|
||||
m_prefixLength = 999999;
|
||||
}
|
||||
|
||||
if (m_address.protocol() == QAbstractSocket::IPv4Protocol) {
|
||||
if (m_prefixLength >= 32) {
|
||||
m_prefixLength = 32;
|
||||
}
|
||||
} else if (m_address.protocol() == QAbstractSocket::IPv6Protocol) {
|
||||
if (m_prefixLength >= 128) {
|
||||
m_prefixLength = 128;
|
||||
}
|
||||
} else {
|
||||
Q_ASSERT(false);
|
||||
}
|
||||
}
|
||||
|
||||
IPAddress::IPAddress(const IPAddress& other) {
|
||||
MZ_COUNT_CTOR(IPAddress);
|
||||
*this = other;
|
||||
}
|
||||
|
||||
IPAddress& IPAddress::operator=(const IPAddress& other) {
|
||||
if (this == &other) return *this;
|
||||
|
||||
m_address = other.m_address;
|
||||
m_prefixLength = other.m_prefixLength;
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
IPAddress::IPAddress(const QHostAddress& address) : m_address(address) {
|
||||
MZ_COUNT_CTOR(IPAddress);
|
||||
|
||||
if (address.protocol() == QAbstractSocket::IPv4Protocol) {
|
||||
m_prefixLength = 32;
|
||||
} else {
|
||||
Q_ASSERT(address.protocol() == QAbstractSocket::IPv6Protocol);
|
||||
m_prefixLength = 128;
|
||||
}
|
||||
}
|
||||
|
||||
IPAddress::IPAddress(const QHostAddress& address, int prefixLength)
|
||||
: m_address(address), m_prefixLength(prefixLength) {
|
||||
MZ_COUNT_CTOR(IPAddress);
|
||||
|
||||
if (address.protocol() == QAbstractSocket::IPv4Protocol) {
|
||||
Q_ASSERT(prefixLength >= 0 && prefixLength <= 32);
|
||||
} else {
|
||||
Q_ASSERT(address.protocol() == QAbstractSocket::IPv6Protocol);
|
||||
Q_ASSERT(prefixLength >= 0 && prefixLength <= 128);
|
||||
}
|
||||
}
|
||||
|
||||
IPAddress::~IPAddress() { MZ_COUNT_DTOR(IPAddress); }
|
||||
|
||||
QAbstractSocket::NetworkLayerProtocol IPAddress::type() const {
|
||||
return m_address.protocol();
|
||||
}
|
||||
|
||||
QHostAddress IPAddress::netmask() const {
|
||||
if (m_address.protocol() == QAbstractSocket::IPv6Protocol) {
|
||||
Q_IPV6ADDR rawNetmask = {0};
|
||||
Q_ASSERT(m_prefixLength <= 128);
|
||||
memset(&rawNetmask, 0xff, m_prefixLength / 8);
|
||||
if (m_prefixLength % 8) {
|
||||
rawNetmask[m_prefixLength / 8] = 0xFF ^ (0xFF >> (m_prefixLength % 8));
|
||||
}
|
||||
return QHostAddress(rawNetmask);
|
||||
} else if (m_address.protocol() == QAbstractSocket::IPv4Protocol) {
|
||||
quint32 rawNetmask = 0xffffffff;
|
||||
Q_ASSERT(m_prefixLength <= 32);
|
||||
if (m_prefixLength < 32) {
|
||||
rawNetmask ^= (0xffffffff >> m_prefixLength);
|
||||
}
|
||||
return QHostAddress(rawNetmask);
|
||||
} else {
|
||||
return QHostAddress();
|
||||
}
|
||||
}
|
||||
|
||||
QHostAddress IPAddress::hostmask() const {
|
||||
if (m_address.protocol() == QAbstractSocket::IPv6Protocol) {
|
||||
Q_IPV6ADDR rawHostmask = {0};
|
||||
int offset = (m_prefixLength + 7) / 8;
|
||||
Q_ASSERT(m_prefixLength <= 128);
|
||||
memset(&rawHostmask[offset], 0xff, sizeof(rawHostmask) - offset);
|
||||
if (m_prefixLength % 8) {
|
||||
rawHostmask[m_prefixLength / 8] = 0xFF >> (m_prefixLength % 8);
|
||||
}
|
||||
return QHostAddress(rawHostmask);
|
||||
} else if (m_address.protocol() == QAbstractSocket::IPv4Protocol) {
|
||||
if (m_prefixLength < 32) {
|
||||
return QHostAddress(0xffffffff >> m_prefixLength);
|
||||
} else {
|
||||
quint32 zero = 0;
|
||||
return QHostAddress(zero);
|
||||
}
|
||||
} else {
|
||||
return QHostAddress();
|
||||
}
|
||||
}
|
||||
|
||||
QHostAddress IPAddress::broadcastAddress() const {
|
||||
if (m_address.protocol() == QAbstractSocket::IPv6Protocol) {
|
||||
Q_IPV6ADDR rawAddress = m_address.toIPv6Address();
|
||||
int offset = (m_prefixLength + 7) / 8;
|
||||
memset(&rawAddress[offset], 0xff, sizeof(rawAddress) - offset);
|
||||
if (m_prefixLength % 8) {
|
||||
rawAddress[m_prefixLength / 8] |= 0xFF >> (m_prefixLength % 8);
|
||||
}
|
||||
return QHostAddress(rawAddress);
|
||||
} else if (m_address.protocol() == QAbstractSocket::IPv4Protocol) {
|
||||
quint32 rawAddress = m_address.toIPv4Address();
|
||||
if (m_prefixLength < 32) {
|
||||
rawAddress |= (0xffffffff >> m_prefixLength);
|
||||
}
|
||||
return QHostAddress(rawAddress);
|
||||
} else {
|
||||
return QHostAddress();
|
||||
}
|
||||
}
|
||||
|
||||
bool IPAddress::overlaps(const IPAddress& other) const {
|
||||
if (m_prefixLength < other.m_prefixLength) {
|
||||
return contains(other.m_address);
|
||||
} else {
|
||||
return other.contains(m_address);
|
||||
}
|
||||
}
|
||||
|
||||
bool IPAddress::contains(const QHostAddress& address) const {
|
||||
if (address.protocol() != m_address.protocol()) {
|
||||
return false;
|
||||
}
|
||||
if (m_prefixLength == 0) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (m_address.protocol() == QAbstractSocket::IPv6Protocol) {
|
||||
Q_IPV6ADDR a = m_address.toIPv6Address();
|
||||
Q_IPV6ADDR b = address.toIPv6Address();
|
||||
int bytes = m_prefixLength / 8;
|
||||
if (bytes > 0) {
|
||||
if (memcmp(&a, &b, bytes) != 0) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
if (m_prefixLength % 8) {
|
||||
quint8 diff = (a[bytes] ^ b[bytes]) >> (8 - m_prefixLength % 8);
|
||||
return (diff == 0);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
if (m_address.protocol() == QAbstractSocket::IPv4Protocol) {
|
||||
quint32 diff = m_address.toIPv4Address() ^ address.toIPv4Address();
|
||||
if (m_prefixLength < 32) {
|
||||
diff >>= (32 - m_prefixLength);
|
||||
}
|
||||
return (diff == 0);
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool IPAddress::operator==(const IPAddress& other) const {
|
||||
return m_address == other.m_address && m_prefixLength == other.m_prefixLength;
|
||||
}
|
||||
|
||||
bool IPAddress::subnetOf(const IPAddress& other) const {
|
||||
if (other.m_address.protocol() != m_address.protocol()) {
|
||||
return false;
|
||||
}
|
||||
if (m_prefixLength < other.m_prefixLength) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return other.contains(m_address);
|
||||
}
|
||||
|
||||
QList<IPAddress> IPAddress::subnets() const {
|
||||
QList<IPAddress> list;
|
||||
|
||||
if (m_address.protocol() == QAbstractSocket::IPv4Protocol) {
|
||||
if (m_prefixLength >= 32) {
|
||||
list.append(*this);
|
||||
return list;
|
||||
}
|
||||
|
||||
quint32 rawAddress = m_address.toIPv4Address();
|
||||
list.append(IPAddress(QHostAddress(rawAddress), m_prefixLength + 1));
|
||||
|
||||
rawAddress |= (0x80000000 >> m_prefixLength);
|
||||
list.append(IPAddress(QHostAddress(rawAddress), m_prefixLength + 1));
|
||||
|
||||
return list;
|
||||
}
|
||||
|
||||
Q_ASSERT(m_address.protocol() == QAbstractSocket::IPv6Protocol);
|
||||
|
||||
if (m_prefixLength >= 128) {
|
||||
list.append(*this);
|
||||
return list;
|
||||
}
|
||||
|
||||
Q_IPV6ADDR rawAddress = m_address.toIPv6Address();
|
||||
list.append(IPAddress(QHostAddress(rawAddress), m_prefixLength + 1));
|
||||
|
||||
rawAddress[m_prefixLength / 8] |= (0x80 >> (m_prefixLength % 8));
|
||||
list.append(IPAddress(QHostAddress(rawAddress), m_prefixLength + 1));
|
||||
|
||||
return list;
|
||||
}
|
||||
|
||||
// static
|
||||
QList<IPAddress> IPAddress::excludeAddresses(
|
||||
const QList<IPAddress>& sourceList, const QList<IPAddress>& excludeList) {
|
||||
QList<IPAddress> results = sourceList;
|
||||
|
||||
for (const IPAddress& exclude : excludeList) {
|
||||
QList<IPAddress> newResults;
|
||||
|
||||
for (const IPAddress& ip : results) {
|
||||
if (!ip.overlaps(exclude)) {
|
||||
newResults.append(ip);
|
||||
} else if (exclude.subnetOf(ip) && exclude != ip) {
|
||||
QList<IPAddress> range = ip.excludeAddresses(exclude);
|
||||
newResults.append(range);
|
||||
}
|
||||
}
|
||||
|
||||
results = newResults;
|
||||
}
|
||||
|
||||
return results;
|
||||
}
|
||||
|
||||
QList<IPAddress> IPAddress::excludeAddresses(const IPAddress& ip) const {
|
||||
QList<IPAddress> sn = subnets();
|
||||
Q_ASSERT(sn.length() >= 2);
|
||||
|
||||
QList<IPAddress> result;
|
||||
while (sn[0] != ip && sn[1] != ip) {
|
||||
if (ip.subnetOf(sn[0])) {
|
||||
result.append(sn[1]);
|
||||
sn = sn[0].subnets();
|
||||
} else if (ip.subnetOf(sn[1])) {
|
||||
result.append(sn[0]);
|
||||
sn = sn[1].subnets();
|
||||
} else {
|
||||
Q_ASSERT(false);
|
||||
}
|
||||
}
|
||||
|
||||
if (sn[0] == ip) {
|
||||
result.append(sn[1]);
|
||||
} else if (sn[1] == ip) {
|
||||
result.append(sn[0]);
|
||||
} else {
|
||||
Q_ASSERT(false);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
53
client/mozilla/shared/ipaddress.h
Normal file
53
client/mozilla/shared/ipaddress.h
Normal file
|
|
@ -0,0 +1,53 @@
|
|||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#ifndef IPADDRESS_H
|
||||
#define IPADDRESS_H
|
||||
|
||||
#include <QHostAddress>
|
||||
|
||||
class IPAddress final {
|
||||
public:
|
||||
static QList<IPAddress> excludeAddresses(const QList<IPAddress>& sourceList,
|
||||
const QList<IPAddress>& excludeList);
|
||||
|
||||
IPAddress();
|
||||
IPAddress(const QString& ip);
|
||||
IPAddress(const QHostAddress& address);
|
||||
IPAddress(const QHostAddress& address, int prefixLength);
|
||||
IPAddress(const IPAddress& other);
|
||||
IPAddress& operator=(const IPAddress& other);
|
||||
~IPAddress();
|
||||
|
||||
QString toString() const {
|
||||
return QString("%1/%2").arg(m_address.toString()).arg(m_prefixLength);
|
||||
}
|
||||
|
||||
const QHostAddress& address() const { return m_address; }
|
||||
int prefixLength() const { return m_prefixLength; }
|
||||
QHostAddress netmask() const;
|
||||
QHostAddress hostmask() const;
|
||||
QHostAddress broadcastAddress() const;
|
||||
|
||||
bool overlaps(const IPAddress& other) const;
|
||||
|
||||
bool contains(const QHostAddress& address) const;
|
||||
|
||||
bool operator==(const IPAddress& other) const;
|
||||
bool operator!=(const IPAddress& other) const { return !operator==(other); }
|
||||
|
||||
bool subnetOf(const IPAddress& other) const;
|
||||
|
||||
QList<IPAddress> subnets() const;
|
||||
|
||||
QList<IPAddress> excludeAddresses(const IPAddress& ip) const;
|
||||
|
||||
QAbstractSocket::NetworkLayerProtocol type() const;
|
||||
|
||||
private:
|
||||
QHostAddress m_address;
|
||||
int m_prefixLength;
|
||||
};
|
||||
|
||||
#endif // IPADDRESS_H
|
||||
75
client/mozilla/shared/leakdetector.cpp
Normal file
75
client/mozilla/shared/leakdetector.cpp
Normal file
|
|
@ -0,0 +1,75 @@
|
|||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#include "leakdetector.h"
|
||||
|
||||
#include <QHash>
|
||||
#include <QMutex>
|
||||
#include <QObject>
|
||||
#include <QTextStream>
|
||||
|
||||
#ifdef MZ_DEBUG
|
||||
static QMutex s_leakDetector;
|
||||
|
||||
QHash<QString, QHash<void*, uint32_t>> s_leaks;
|
||||
#endif
|
||||
|
||||
LeakDetector::LeakDetector() {
|
||||
#ifndef MZ_DEBUG
|
||||
qFatal("LeakDetector _must_ be created in debug builds only!");
|
||||
#endif
|
||||
}
|
||||
|
||||
LeakDetector::~LeakDetector() {
|
||||
#ifdef MZ_DEBUG
|
||||
QTextStream out(stderr);
|
||||
|
||||
out << "== MZ - Leak report ===================" << Qt::endl;
|
||||
|
||||
bool hasLeaks = false;
|
||||
for (auto i = s_leaks.begin(); i != s_leaks.end(); ++i) {
|
||||
QString className = i.key();
|
||||
|
||||
if (i->size() == 0) {
|
||||
continue;
|
||||
}
|
||||
|
||||
hasLeaks = true;
|
||||
out << className << Qt::endl;
|
||||
|
||||
for (auto l = i->begin(); l != i->end(); ++l) {
|
||||
out << " - ptr: " << l.key() << " size:" << l.value() << Qt::endl;
|
||||
}
|
||||
}
|
||||
|
||||
if (!hasLeaks) {
|
||||
out << "No leaks detected." << Qt::endl;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
#ifdef MZ_DEBUG
|
||||
void LeakDetector::logCtor(void* ptr, const char* typeName, uint32_t size) {
|
||||
QMutexLocker lock(&s_leakDetector);
|
||||
|
||||
QString type(typeName);
|
||||
if (!s_leaks.contains(type)) {
|
||||
s_leaks.insert(type, QHash<void*, uint32_t>());
|
||||
}
|
||||
|
||||
s_leaks[type].insert(ptr, size);
|
||||
}
|
||||
|
||||
void LeakDetector::logDtor(void* ptr, const char* typeName, uint32_t size) {
|
||||
QMutexLocker lock(&s_leakDetector);
|
||||
|
||||
QString type(typeName);
|
||||
Q_ASSERT(s_leaks.contains(type));
|
||||
|
||||
QHash<void*, uint32_t>& leak = s_leaks[type];
|
||||
Q_ASSERT(leak.contains(ptr));
|
||||
Q_ASSERT(leak[ptr] == size);
|
||||
leak.remove(ptr);
|
||||
}
|
||||
#endif
|
||||
41
client/mozilla/shared/leakdetector.h
Normal file
41
client/mozilla/shared/leakdetector.h
Normal file
|
|
@ -0,0 +1,41 @@
|
|||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#ifndef LEAKDETECTOR_H
|
||||
#define LEAKDETECTOR_H
|
||||
|
||||
#include <QObject>
|
||||
|
||||
#ifdef MZ_DEBUG
|
||||
# define MZ_COUNT_CTOR(_type) \
|
||||
do { \
|
||||
static_assert(std::is_class<_type>(), \
|
||||
"Token '" #_type "' is not a class type."); \
|
||||
LeakDetector::logCtor((void*)this, #_type, sizeof(*this)); \
|
||||
} while (0)
|
||||
|
||||
# define MZ_COUNT_DTOR(_type) \
|
||||
do { \
|
||||
static_assert(std::is_class<_type>(), \
|
||||
"Token '" #_type "' is not a class type."); \
|
||||
LeakDetector::logDtor((void*)this, #_type, sizeof(*this)); \
|
||||
} while (0)
|
||||
|
||||
#else
|
||||
# define MZ_COUNT_CTOR(_type)
|
||||
# define MZ_COUNT_DTOR(_type)
|
||||
#endif
|
||||
|
||||
class LeakDetector {
|
||||
public:
|
||||
LeakDetector();
|
||||
~LeakDetector();
|
||||
|
||||
#ifdef MZ_DEBUG
|
||||
static void logCtor(void* ptr, const char* typeName, uint32_t size);
|
||||
static void logDtor(void* ptr, const char* typeName, uint32_t size);
|
||||
#endif
|
||||
};
|
||||
|
||||
#endif // LEAKDETECTOR_H
|
||||
16
client/mozilla/shared/loglevel.h
Normal file
16
client/mozilla/shared/loglevel.h
Normal file
|
|
@ -0,0 +1,16 @@
|
|||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#ifndef LOGLEVEL_H
|
||||
#define LOGLEVEL_H
|
||||
|
||||
enum LogLevel {
|
||||
Trace = 0,
|
||||
Debug,
|
||||
Info,
|
||||
Warning,
|
||||
Error,
|
||||
};
|
||||
|
||||
#endif // LOGLEVEL_H
|
||||
76
client/mozilla/shared/signalhandler.cpp
Normal file
76
client/mozilla/shared/signalhandler.cpp
Normal file
|
|
@ -0,0 +1,76 @@
|
|||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#include "signalhandler.h"
|
||||
|
||||
#include <fcntl.h>
|
||||
#include <signal.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include "logger.h"
|
||||
|
||||
namespace {
|
||||
|
||||
Logger logger("SignalHandler");
|
||||
|
||||
int s_signalpipe = -1;
|
||||
|
||||
} // namespace
|
||||
|
||||
SignalHandler::SignalHandler() {
|
||||
Q_ASSERT(s_signalpipe < 0);
|
||||
|
||||
int quitSignals[] = {SIGQUIT, SIGINT, SIGTERM, SIGHUP};
|
||||
|
||||
sigset_t mask;
|
||||
sigemptyset(&mask);
|
||||
for (auto sig : quitSignals) {
|
||||
sigaddset(&mask, sig);
|
||||
}
|
||||
|
||||
if (pipe(m_pipefds) != 0) {
|
||||
logger.error() << "Unable to create signal wakeup pipe";
|
||||
return;
|
||||
}
|
||||
fcntl(m_pipefds[0], F_SETFL, fcntl(m_pipefds[0], F_GETFL) | O_NONBLOCK);
|
||||
s_signalpipe = m_pipefds[1];
|
||||
m_notifier = new QSocketNotifier(m_pipefds[0], QSocketNotifier::Read, this);
|
||||
connect(m_notifier, &QSocketNotifier::activated, this,
|
||||
&SignalHandler::pipeReadReady);
|
||||
|
||||
struct sigaction sa;
|
||||
sa.sa_handler = SignalHandler::saHandler;
|
||||
sa.sa_mask = mask;
|
||||
sa.sa_flags = 0;
|
||||
|
||||
for (auto sig : quitSignals) {
|
||||
sigaction(sig, &sa, nullptr);
|
||||
}
|
||||
}
|
||||
|
||||
SignalHandler::~SignalHandler() {
|
||||
s_signalpipe = -1;
|
||||
if (m_pipefds[0] >= 0) {
|
||||
close(m_pipefds[0]);
|
||||
}
|
||||
if (m_pipefds[1] >= 1) {
|
||||
close(m_pipefds[1]);
|
||||
}
|
||||
}
|
||||
|
||||
void SignalHandler::pipeReadReady() {
|
||||
int signal;
|
||||
if (read(m_pipefds[0], &signal, sizeof(signal)) == sizeof(signal)) {
|
||||
logger.debug() << "Signal" << signal;
|
||||
emit quitRequested();
|
||||
}
|
||||
}
|
||||
|
||||
void SignalHandler::saHandler(int signal) {
|
||||
if (s_signalpipe >= 0) {
|
||||
if (write(s_signalpipe, &signal, sizeof(signal)) != sizeof(signal)) {
|
||||
logger.warning() << "Unable to write in the pipe";
|
||||
}
|
||||
}
|
||||
}
|
||||
31
client/mozilla/shared/signalhandler.h
Normal file
31
client/mozilla/shared/signalhandler.h
Normal file
|
|
@ -0,0 +1,31 @@
|
|||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#ifndef SIGNALHANDLER_H
|
||||
#define SIGNALHANDLER_H
|
||||
|
||||
#include <QObject>
|
||||
#include <QSocketNotifier>
|
||||
|
||||
class SignalHandler final : public QObject {
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
SignalHandler();
|
||||
~SignalHandler();
|
||||
|
||||
private slots:
|
||||
void pipeReadReady();
|
||||
|
||||
private:
|
||||
static void saHandler(int signal);
|
||||
|
||||
int m_pipefds[2] = {-1, -1};
|
||||
QSocketNotifier* m_notifier = nullptr;
|
||||
|
||||
signals:
|
||||
void quitRequested();
|
||||
};
|
||||
|
||||
#endif // SIGNALHANDLER_H
|
||||
Loading…
Add table
Add a link
Reference in a new issue