Update ping and monitor handling
This commit is contained in:
parent
abb656016d
commit
341a07cd85
@ -89,7 +89,7 @@ NetworkDeviceDiscoveryImpl::NetworkDeviceDiscoveryImpl(QObject *parent) :
|
||||
|
||||
// Timer for updating the monitors
|
||||
m_monitorTimer = new QTimer(this);
|
||||
m_monitorTimer->setInterval(5000);
|
||||
m_monitorTimer->setInterval(10000);
|
||||
m_monitorTimer->setSingleShot(false);
|
||||
connect(m_monitorTimer, &QTimer::timeout, this, &NetworkDeviceDiscoveryImpl::evaluateMonitors);
|
||||
|
||||
@ -218,58 +218,6 @@ bool NetworkDeviceDiscoveryImpl::running() const
|
||||
return m_running;
|
||||
}
|
||||
|
||||
// NetworkDeviceMonitor *NetworkDeviceDiscoveryImpl::registerMonitor(const MacAddress &macAddress)
|
||||
// {
|
||||
// if (macAddress.isNull()) {
|
||||
// qCWarning(dcNetworkDeviceDiscovery()) << "Could not register monitor for invalid" << macAddress;
|
||||
// return nullptr;
|
||||
// }
|
||||
|
||||
// // Make sure we create only one monitor per MAC and keep track how many user
|
||||
// // have access to this monitor otherwise an unregister could cause a crash in
|
||||
// // an other plugin plugin which might still need it
|
||||
// if (m_monitors.contains(macAddress)) {
|
||||
// m_monitorsReferenceCount[macAddress] += 1;
|
||||
// qCInfo(dcNetworkDeviceDiscovery()) << "Register network device monitor for" << macAddress << "which already exists. Returning existing monitor having now" << m_monitorsReferenceCount[macAddress] << "references.";
|
||||
// return m_monitors.value(macAddress);
|
||||
// }
|
||||
|
||||
// qCInfo(dcNetworkDeviceDiscovery()) << "Register new network device monitor for" << macAddress;
|
||||
|
||||
// // Fill in cached information
|
||||
// NetworkDeviceInfo info;
|
||||
// if (m_networkInfoCache.contains(macAddress)) {
|
||||
// info = m_networkInfoCache.value(macAddress);
|
||||
// } else {
|
||||
// info.setMacAddress(macAddress.toString());
|
||||
// }
|
||||
|
||||
// NetworkDeviceMonitorImpl *monitor = new NetworkDeviceMonitorImpl(macAddress, this);
|
||||
// monitor->setNetworkDeviceInfo(info);
|
||||
// monitor->setLastSeen(m_lastSeen.value(macAddress, QDateTime()));
|
||||
// m_monitors.insert(macAddress, monitor);
|
||||
// m_monitorsReferenceCount[macAddress] = 1;
|
||||
|
||||
// if (!available()) {
|
||||
// qCWarning(dcNetworkDeviceDiscovery()) << "Registered monitor but the hardware resource is not available. The monitor will not work as expected" << monitor;
|
||||
// return monitor;
|
||||
// }
|
||||
|
||||
// // Restart the monitor timer since we evaluate this one now
|
||||
// m_monitorTimer->start();
|
||||
|
||||
// if (!monitor->networkDeviceInfo().isValid()) {
|
||||
// qCDebug(dcNetworkDeviceDiscovery()) << "Adding network device monitor for unresolved mac address. Starting a discovery...";
|
||||
// NetworkDeviceDiscoveryReply *reply = discover();
|
||||
// connect(reply, &NetworkDeviceDiscoveryReply::finished, reply, &NetworkDeviceDiscoveryReply::deleteLater);
|
||||
// } else {
|
||||
// evaluateMonitor(monitor);
|
||||
// }
|
||||
|
||||
// qCDebug(dcNetworkDeviceDiscovery()) << "Registered successfully" << monitor;
|
||||
// return monitor;
|
||||
// }
|
||||
|
||||
NetworkDeviceMonitor *NetworkDeviceDiscoveryImpl::registerMonitor(Thing *thing)
|
||||
{
|
||||
if (!thing->thingClass().interfaces().contains("networkdevice")) {
|
||||
@ -308,11 +256,14 @@ NetworkDeviceMonitor *NetworkDeviceDiscoveryImpl::registerMonitor(Thing *thing)
|
||||
}
|
||||
}
|
||||
|
||||
bool newMonitor = true;
|
||||
if (internalMonitor) {
|
||||
qCDebug(dcNetworkDeviceDiscovery()) << "Already have an internal monitor for this network device" << internalMonitor;
|
||||
newMonitor = false;
|
||||
} else {
|
||||
// Create a new monitor for the internal use
|
||||
internalMonitor = new NetworkDeviceMonitorImpl(macAddress, hostName, address, this);
|
||||
m_monitors.insert(internalMonitor, QVector<NetworkDeviceMonitorImpl*>());
|
||||
}
|
||||
|
||||
internalMonitor->setMonitorMode(mode);
|
||||
@ -354,7 +305,13 @@ NetworkDeviceMonitor *NetworkDeviceDiscoveryImpl::registerMonitor(Thing *thing)
|
||||
|
||||
// Create a new plugin monitor object we are going to return...
|
||||
NetworkDeviceMonitorImpl *pluginMonitor = createPluginMonitor(internalMonitor);
|
||||
m_monitors[internalMonitor].append(pluginMonitor);
|
||||
qCDebug(dcNetworkDeviceDiscovery()) << "Registered successfully" << pluginMonitor;
|
||||
|
||||
// In case this is a new monitor, let's evaluate it right the way so know asap if the device is reachable or not
|
||||
if (newMonitor)
|
||||
evaluateMonitor(internalMonitor);
|
||||
|
||||
return pluginMonitor;
|
||||
}
|
||||
|
||||
@ -374,6 +331,14 @@ PingReply *NetworkDeviceDiscoveryImpl::ping(const QHostAddress &address, uint re
|
||||
return reply;
|
||||
}
|
||||
|
||||
PingReply *NetworkDeviceDiscoveryImpl::ping(const QString &hostName, uint retries)
|
||||
{
|
||||
PingReply *reply = m_ping->ping(hostName, retries);
|
||||
// Note: we use any ping used trough this method also for the monitor evaluation
|
||||
watchPingReply(reply);
|
||||
return reply;
|
||||
}
|
||||
|
||||
PingReply *NetworkDeviceDiscoveryImpl::ping(const QHostAddress &address, bool lookupHost, uint retries)
|
||||
{
|
||||
PingReply *reply = m_ping->ping(address, lookupHost, retries);
|
||||
@ -521,7 +486,35 @@ void NetworkDeviceDiscoveryImpl::processMonitorPingResult(PingReply *reply, Netw
|
||||
// Save the last time we tried to communicate
|
||||
if (reply->error() == PingReply::ErrorNoError) {
|
||||
qCDebug(dcNetworkDeviceDiscovery()) << "Ping response from" << monitor << reply->duration() << "ms";
|
||||
monitor->setLastSeen(QDateTime::currentDateTime());
|
||||
|
||||
QDateTime currentDateTime = QDateTime::currentDateTime();
|
||||
m_lastSeen[reply->targetHostAddress()] = currentDateTime;
|
||||
|
||||
for (int i = 0; i < m_networkInfoCache.count(); i++) {
|
||||
|
||||
if (monitor->monitorMode() == NetworkDeviceInfo::MonitorModeHostName) {
|
||||
if (m_networkInfoCache.at(i).hostName() == monitor->hostName() && m_networkInfoCache.at(i).address() != reply->targetHostAddress()) {
|
||||
QHostAddress oldAddress = m_networkInfoCache.at(i).address();
|
||||
qCDebug(dcNetworkDeviceDiscovery()) << "Hostname" << monitor->hostName() << "changed the IP address from"
|
||||
<< oldAddress.toString()
|
||||
<< "-->"
|
||||
<< reply->targetHostAddress().toString();
|
||||
|
||||
removeFromNetworkDeviceCache(oldAddress);
|
||||
|
||||
NetworkDeviceInfo info = m_networkInfoCache.at(i);
|
||||
info.setAddress(reply->targetHostAddress());
|
||||
|
||||
monitor->setNetworkDeviceInfo(info);
|
||||
m_networkInfoCache[i] = info;
|
||||
m_networkInfoCache.sortNetworkDevices();
|
||||
saveNetworkDeviceCache(info);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
monitor->setLastSeen(currentDateTime);
|
||||
monitor->setReachable(true);
|
||||
} else {
|
||||
qCDebug(dcNetworkDeviceDiscovery()) << "Failed to ping device from" << monitor << "retrying" << reply->retries() << "times:" << reply->error();
|
||||
@ -531,29 +524,25 @@ void NetworkDeviceDiscoveryImpl::processMonitorPingResult(PingReply *reply, Netw
|
||||
|
||||
void NetworkDeviceDiscoveryImpl::watchPingReply(PingReply *reply)
|
||||
{
|
||||
connect(reply, &PingReply::finished, this, [=](){
|
||||
// Search cache for mac address and update last seen
|
||||
connect(reply, &PingReply::finished, this, [this, reply](){
|
||||
if (reply->error() == PingReply::ErrorNoError) {
|
||||
|
||||
// FIXME
|
||||
// if (reply->error() == PingReply::ErrorNoError) {
|
||||
// foreach (const NetworkDeviceInfo &info, m_networkInfoCache) {
|
||||
// if (info.address() == reply->targetHostAddress()) {
|
||||
// // Found info for this ip, update the cache
|
||||
// MacAddress macAddress(info.macAddress());
|
||||
// if (!macAddress.isNull() && m_networkInfoCache.contains(macAddress)) {
|
||||
// m_lastSeen[macAddress] = QDateTime::currentDateTime();
|
||||
// saveNetworkDeviceCache(m_networkInfoCache.value(macAddress));
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
int index = m_networkInfoCache.indexFromHostAddress(reply->targetHostAddress());
|
||||
if (index < 0)
|
||||
return;
|
||||
|
||||
// Update any monitor
|
||||
// foreach (NetworkDeviceMonitorImpl *monitor, m_monitors.values()) {
|
||||
// if (monitor->networkDeviceInfo().address() == reply->targetHostAddress()) {
|
||||
// processMonitorPingResult(reply, monitor);
|
||||
// }
|
||||
// }
|
||||
m_lastSeen[reply->targetHostAddress()] = QDateTime::currentDateTime();
|
||||
saveNetworkDeviceCache(m_networkInfoCache.at(index));
|
||||
}
|
||||
|
||||
// Update any relevant monitor
|
||||
foreach (NetworkDeviceMonitorImpl *monitor, m_monitors.keys()) {
|
||||
if ((monitor->monitorMode() == NetworkDeviceInfo::MonitorModeIp && reply->targetHostAddress() == monitor->address()) ||
|
||||
(monitor->monitorMode() == NetworkDeviceInfo::MonitorModeHostName && reply->hostName() == monitor->hostName()) ||
|
||||
(monitor->monitorMode() == NetworkDeviceInfo::MonitorModeMac && reply->targetHostAddress() == monitor->networkDeviceInfo().address())) {
|
||||
processMonitorPingResult(reply, monitor);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@ -562,7 +551,7 @@ void NetworkDeviceDiscoveryImpl::loadNetworkDeviceCache()
|
||||
qCInfo(dcNetworkDeviceDiscovery()) << "Loading cached network device information from" << m_cacheSettings->fileName();
|
||||
|
||||
m_networkInfoCache.clear();
|
||||
QDateTime now = QDateTime::currentDateTime();
|
||||
QDateTime currentDateTime = QDateTime::currentDateTime();
|
||||
|
||||
uint cacheVersion = m_cacheSettings->value("version", 0).toUInt();
|
||||
|
||||
@ -579,7 +568,7 @@ void NetworkDeviceDiscoveryImpl::loadNetworkDeviceCache()
|
||||
QDateTime lastSeen = QDateTime::fromMSecsSinceEpoch(m_cacheSettings->value("lastSeen").toLongLong());
|
||||
|
||||
// Remove the info from the cache if not seen fo the last 30 days...
|
||||
if (lastSeen.date().addDays(m_cacheCleanupPeriod) < now.date()) {
|
||||
if (lastSeen.date().addDays(m_cacheCleanupPeriod) < currentDateTime.date()) {
|
||||
qCDebug(dcNetworkDeviceDiscovery()) << "Removing network device cache entry since it did not show up within the last" << m_cacheCleanupPeriod << "days" << address.toString();
|
||||
m_cacheSettings->remove("");
|
||||
m_cacheSettings->endGroup(); // mac address
|
||||
@ -624,21 +613,6 @@ void NetworkDeviceDiscoveryImpl::loadNetworkDeviceCache()
|
||||
m_lastCacheHousekeeping = QDateTime::currentDateTime();
|
||||
}
|
||||
|
||||
void NetworkDeviceDiscoveryImpl::removeFromNetworkDeviceCache(const MacAddress &macAddress)
|
||||
{
|
||||
if (macAddress.isNull())
|
||||
return;
|
||||
|
||||
// m_networkInfoCache.remove(macAddress);
|
||||
// m_lastSeen.remove(macAddress);
|
||||
// m_cacheSettings->beginGroup("NetworkDeviceInfos");
|
||||
// m_cacheSettings->beginGroup(macAddress.toString());
|
||||
// m_cacheSettings->remove("");
|
||||
// m_cacheSettings->endGroup(); // mac address
|
||||
// m_cacheSettings->endGroup(); // NetworkDeviceInfos
|
||||
// m_cacheSettings->sync();
|
||||
}
|
||||
|
||||
void NetworkDeviceDiscoveryImpl::removeFromNetworkDeviceCache(const QHostAddress &address)
|
||||
{
|
||||
if (address.isNull())
|
||||
@ -707,17 +681,23 @@ void NetworkDeviceDiscoveryImpl::updateCache(const NetworkDeviceInfo &deviceInfo
|
||||
|
||||
void NetworkDeviceDiscoveryImpl::evaluateMonitor(NetworkDeviceMonitorImpl *monitor)
|
||||
{
|
||||
// if (!monitor->networkDeviceInfo().isValid())
|
||||
// return;
|
||||
|
||||
|
||||
if (monitor->currentPingReply())
|
||||
if (monitor->currentPingReply()) {
|
||||
qCDebug(dcNetworkDeviceDiscovery()) << "Monitor has still a ping reply pending:" << monitor;
|
||||
return;
|
||||
}
|
||||
|
||||
qCDebug(dcNetworkDeviceDiscovery()) << "Evaluate monitor" << monitor;
|
||||
|
||||
// Start action if we have not seen the device for gracePeriod seconds
|
||||
QDateTime currentDateTime = QDateTime::currentDateTime();
|
||||
|
||||
bool requiresRefresh = false;
|
||||
|
||||
if (!monitor->networkDeviceInfo().isValid()) {
|
||||
qCDebug(dcNetworkDeviceDiscovery()) << "Network device info not valid for" << monitor;
|
||||
requiresRefresh = true;
|
||||
}
|
||||
|
||||
if (monitor->lastSeen().isNull()) {
|
||||
qCDebug(dcNetworkDeviceDiscovery()) << monitor << "requires refresh. Not seen since application start.";
|
||||
requiresRefresh = true;
|
||||
@ -744,57 +724,85 @@ void NetworkDeviceDiscoveryImpl::evaluateMonitor(NetworkDeviceMonitorImpl *monit
|
||||
if (!requiresRefresh)
|
||||
return;
|
||||
|
||||
// Try to ping first
|
||||
qCDebug(dcNetworkDeviceDiscovery()) << monitor << "try to ping" << monitor->networkDeviceInfo().address().toString();
|
||||
PingReply *reply = m_ping->ping(monitor->networkDeviceInfo().address(), monitor->pingRetries());
|
||||
// Try to ping first.
|
||||
|
||||
// IMPORTANT: use the ping methods from this object, so the result will automatically
|
||||
// be evaluated for the monitors and cache
|
||||
PingReply *reply = nullptr;
|
||||
if (monitor->monitorMode() == NetworkDeviceInfo::MonitorModeHostName) {
|
||||
qCDebug(dcNetworkDeviceDiscovery()) << monitor << "try to ping" << monitor->hostName();
|
||||
reply = ping(monitor->hostName(), monitor->pingRetries());
|
||||
} else {
|
||||
qCDebug(dcNetworkDeviceDiscovery()) << monitor << "try to ping" << monitor->networkDeviceInfo().address().toString();
|
||||
reply = ping(monitor->networkDeviceInfo().address(), monitor->pingRetries());
|
||||
}
|
||||
|
||||
monitor->setCurrentPingReply(reply);
|
||||
monitor->setLastConnectionAttempt(currentDateTime);
|
||||
|
||||
connect(reply, &PingReply::retry, monitor, [=](PingReply::Error error, uint retryCount){
|
||||
connect(reply, &PingReply::retry, monitor, [monitor](PingReply::Error error, uint retryCount){
|
||||
Q_UNUSED(error)
|
||||
Q_UNUSED(retryCount)
|
||||
monitor->setLastConnectionAttempt(QDateTime::currentDateTime());
|
||||
});
|
||||
|
||||
connect(reply, &PingReply::destroyed, monitor, [=](){
|
||||
monitor->setCurrentPingReply(nullptr);
|
||||
connect(reply, &PingReply::destroyed, monitor, [monitor, reply](){
|
||||
if (monitor->currentPingReply() == reply) {
|
||||
monitor->setCurrentPingReply(nullptr);
|
||||
}
|
||||
});
|
||||
|
||||
connect(reply, &PingReply::finished, monitor, [=](){
|
||||
processMonitorPingResult(reply, monitor);
|
||||
connect(reply, &PingReply::finished, monitor, [monitor, reply](){
|
||||
if (monitor->currentPingReply() == reply) {
|
||||
monitor->setCurrentPingReply(nullptr);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
void NetworkDeviceDiscoveryImpl::processArpTraffic(const QNetworkInterface &interface, const QHostAddress &address, const MacAddress &macAddress)
|
||||
{
|
||||
QDateTime now = QDateTime::currentDateTime();
|
||||
// m_lastSeen[macAddress] = now;
|
||||
QDateTime currentDateTime = QDateTime::currentDateTime();
|
||||
m_lastSeen[address] = currentDateTime;
|
||||
|
||||
// FIXME
|
||||
// Update monitors and cache
|
||||
for (int i = 0; i < m_networkInfoCache.count(); i++) {
|
||||
switch (m_networkInfoCache.at(i).monitorMode()) {
|
||||
case NetworkDeviceInfo::MonitorModeMac:
|
||||
if (m_networkInfoCache.at(i).macAddressInfos().hasMacAddress(macAddress) &&
|
||||
m_networkInfoCache.at(i).address() != address) {
|
||||
|
||||
// if (m_networkInfoCache.hasMacAddress(macAddress)) {
|
||||
// if (m_networkInfoCache.value(macAddress).address() != address) {
|
||||
// m_networkInfoCache[macAddress].setAddress(address);
|
||||
// saveNetworkDeviceCache(m_networkInfoCache.value(macAddress));
|
||||
// }
|
||||
// }
|
||||
QHostAddress oldAddress = m_networkInfoCache.at(i).address();
|
||||
qCDebug(dcNetworkDeviceDiscovery()) << "Host" << macAddress.toString() << "changed the IP address from"
|
||||
<< oldAddress.toString()
|
||||
<< "-->"
|
||||
<< address.toString();
|
||||
|
||||
// Update the monitors
|
||||
// NetworkDeviceMonitorImpl *monitor = m_monitors.value(macAddress);
|
||||
// if (monitor) {
|
||||
// monitor->setLastSeen(now);
|
||||
// if (monitor->networkDeviceInfo().address() != address) {
|
||||
// NetworkDeviceInfo info = monitor->networkDeviceInfo();
|
||||
// info.setAddress(address);
|
||||
// monitor->setNetworkDeviceInfo(info);
|
||||
// qCDebug(dcNetworkDeviceDiscovery()) << "NetworkDeviceMonitor" << monitor << "ip address changed";
|
||||
// emit monitor->networkDeviceInfoChanged(monitor->networkDeviceInfo());
|
||||
// }
|
||||
removeFromNetworkDeviceCache(oldAddress);
|
||||
|
||||
// if (monitor->networkDeviceInfo().isComplete()) {
|
||||
// monitor->setReachable(true);
|
||||
// }
|
||||
// }
|
||||
NetworkDeviceInfo info = m_networkInfoCache.at(i);
|
||||
info.setAddress(address);
|
||||
|
||||
m_networkInfoCache[i] = info;
|
||||
m_networkInfoCache.sortNetworkDevices();
|
||||
saveNetworkDeviceCache(info);
|
||||
|
||||
foreach (NetworkDeviceMonitorImpl *monitor, m_monitors.keys()) {
|
||||
if (monitor->macAddress() == macAddress) {
|
||||
monitor->setNetworkDeviceInfo(info);
|
||||
monitor->setLastSeen(currentDateTime);
|
||||
monitor->setReachable(true);
|
||||
break;
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
break;
|
||||
case NetworkDeviceInfo::MonitorModeHostName:
|
||||
case NetworkDeviceInfo::MonitorModeIp:
|
||||
saveNetworkDeviceCache(m_networkInfoCache.at(i));
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// Check if we have currently reply running
|
||||
if (!m_currentDiscoveryReply)
|
||||
@ -910,6 +918,7 @@ void NetworkDeviceDiscoveryImpl::cleanupPluginMonitor(NetworkDeviceMonitorImpl *
|
||||
foreach (NetworkDeviceMonitorImpl *internalMonitor, m_monitors.keys()) {
|
||||
if (m_monitors.value(internalMonitor).contains(pluginMonitor)) {
|
||||
m_monitors[internalMonitor].removeAll(pluginMonitor);
|
||||
pluginMonitor->deleteLater();
|
||||
|
||||
if (m_monitors.value(internalMonitor).isEmpty()) {
|
||||
qCDebug(dcNetworkDeviceDiscovery()) << "No monitor registered for this network device any more. Unregister internal monitor" << internalMonitor;
|
||||
@ -952,7 +961,7 @@ void NetworkDeviceDiscoveryImpl::evaluateMonitors()
|
||||
evaluateMonitor(monitor);
|
||||
|
||||
// Check if there is any monitor which has not be seen since
|
||||
if (!monitor->reachable() /*&& monitor->lastConnectionAttempt().isValid()*/ && longerAgoThan(monitor->lastSeen(), m_monitorInterval)) {
|
||||
if (!monitor->reachable() && monitor->lastConnectionAttempt().isValid() && longerAgoThan(monitor->lastSeen(), m_monitorInterval)) {
|
||||
monitorRequiresRediscovery = true;
|
||||
}
|
||||
}
|
||||
@ -967,7 +976,7 @@ void NetworkDeviceDiscoveryImpl::evaluateMonitors()
|
||||
// // Do some cache housekeeping if required
|
||||
// if (m_lastCacheHousekeeping.addDays(1) < QDateTime::currentDateTime()) {
|
||||
// qCInfo(dcNetworkDeviceDiscovery()) << "Starting cache housekeeping since it is more than one day since the last clanup...";
|
||||
// QDateTime now = QDateTime::currentDateTime();
|
||||
// QDateTime currentDateTime = QDateTime::currentDateTime();
|
||||
// foreach (const MacAddress &mac, m_lastSeen.keys()) {
|
||||
// // Remove the info from the cache if not seen fo the last 30 days...
|
||||
// if (m_lastSeen.value(mac).date().addDays(m_cacheCleanupPeriod) < QDateTime::currentDateTime().date()) {
|
||||
@ -975,7 +984,7 @@ void NetworkDeviceDiscoveryImpl::evaluateMonitors()
|
||||
// removeFromNetworkDeviceCache(mac);
|
||||
// }
|
||||
// }
|
||||
// m_lastCacheHousekeeping = now;
|
||||
// m_lastCacheHousekeeping = currentDateTime;
|
||||
// }
|
||||
}
|
||||
|
||||
|
||||
@ -71,6 +71,7 @@ public:
|
||||
void unregisterMonitor(NetworkDeviceMonitor *networkDeviceMonitor) override;
|
||||
|
||||
PingReply *ping(const QHostAddress &address, uint retries = 3) override;
|
||||
PingReply *ping(const QString &hostName, uint retries = 3) override;
|
||||
PingReply *ping(const QHostAddress &address, bool lookupHost, uint retries = 3);
|
||||
|
||||
MacAddressDatabaseReply *lookupMacAddress(const QString &macAddress) override;
|
||||
@ -138,6 +139,8 @@ private:
|
||||
|
||||
void processArpTraffic(const QNetworkInterface &interface, const QHostAddress &address, const MacAddress &macAddress);
|
||||
|
||||
void testPingMonitor(NetworkDeviceMonitorImpl *monitor);
|
||||
|
||||
// Time helpers
|
||||
bool longerAgoThan(const QDateTime &dateTime, uint minutes);
|
||||
QDateTime convertMinuteBased(const QDateTime &dateTime = QDateTime());
|
||||
|
||||
@ -61,6 +61,7 @@ public:
|
||||
virtual void unregisterMonitor(NetworkDeviceMonitor *networkDeviceMonitor) = 0;
|
||||
|
||||
virtual PingReply *ping(const QHostAddress &address, uint retries = 3) = 0;
|
||||
virtual PingReply *ping(const QString &hostName, uint retries = 3) = 0;
|
||||
|
||||
virtual MacAddressDatabaseReply *lookupMacAddress(const QString &macAddress) = 0;
|
||||
virtual MacAddressDatabaseReply *lookupMacAddress(const MacAddress &macAddress) = 0;
|
||||
|
||||
@ -56,6 +56,17 @@ int NetworkDeviceInfos::indexFromHostAddress(const QHostAddress &address)
|
||||
return -1;
|
||||
}
|
||||
|
||||
int NetworkDeviceInfos::indexFromHostName(const QString &hostName)
|
||||
{
|
||||
for (int i = 0; i < this->size(); i++) {
|
||||
if (at(i).hostName() == hostName) {
|
||||
return i;
|
||||
}
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
QList<int> NetworkDeviceInfos::indexFromMacAddress(const QString &macAddress)
|
||||
{
|
||||
return indexFromMacAddress(MacAddress(macAddress));
|
||||
|
||||
@ -44,6 +44,7 @@ public:
|
||||
NetworkDeviceInfos(const QVector<NetworkDeviceInfo> &other);
|
||||
|
||||
int indexFromHostAddress(const QHostAddress &address);
|
||||
int indexFromHostName(const QString &hostName);
|
||||
QList<int> indexFromMacAddress(const QString &macAddress);
|
||||
QList<int> indexFromMacAddress(const MacAddress &macAddress);
|
||||
|
||||
|
||||
@ -141,6 +141,18 @@ PingReply *Ping::ping(const QHostAddress &hostAddress, bool lookupHost, uint ret
|
||||
return reply;
|
||||
}
|
||||
|
||||
PingReply *Ping::ping(const QString &hostName, uint retries)
|
||||
{
|
||||
// Make first the host lookup, then the ping the first address and save it in the reply
|
||||
PingReply *reply = createReply(hostName);
|
||||
reply->m_retries = retries;
|
||||
|
||||
// Note: due to a Qt bug < 5.9 we need to use old SLOT style and cannot make use of lambda here
|
||||
int lookupId = QHostInfo::lookupHost(hostName, this, SLOT(onHostLookupFinished(QHostInfo)));
|
||||
m_pendingHostAddressLookups.insert(lookupId, reply);
|
||||
return reply;
|
||||
}
|
||||
|
||||
void Ping::sendNextReply()
|
||||
{
|
||||
if (m_queueTimer->isActive())
|
||||
@ -150,7 +162,7 @@ void Ping::sendNextReply()
|
||||
return;
|
||||
|
||||
m_currentReply = m_replyQueue.dequeue();
|
||||
qCDebug(dcPing()) << "Send next reply " << m_currentReply->targetHostAddress().toString() << QString("0x%1").arg(m_currentReply->requestId(), 4, 16, QChar('0')) << ", " << m_replyQueue.count() << "left in queue";
|
||||
qCDebug(dcPing()).nospace().noquote() << "Send next reply " << m_currentReply->targetHostAddress().toString() << " ID: " << QString("0x%1").arg(m_currentReply->requestId(), 4, 16, QChar('0')) << ", " << m_replyQueue.count() << "left in queue";
|
||||
m_queueTimer->start();
|
||||
QTimer::singleShot(0, this, [=]() {
|
||||
if (!m_currentReply)
|
||||
@ -209,8 +221,8 @@ void Ping::performPing(PingReply *reply)
|
||||
}
|
||||
|
||||
qCDebug(dcPingTraffic()) << "Send ICMP echo request" << reply->targetHostAddress().toString() << ICMP_PACKET_SIZE << "[Bytes]"
|
||||
<< "ID:" << QString("0x%1").arg(reply->requestId(), 4, 16, QChar('0'))
|
||||
<< "Sequence:" << reply->sequenceNumber();
|
||||
<< "ID:" << QString("0x%1").arg(reply->requestId(), 4, 16, QChar('0'))
|
||||
<< "Sequence:" << reply->sequenceNumber();
|
||||
|
||||
// Send packet to the target ip
|
||||
int bytesSent = sendto(m_socketDescriptor, &requestPacket, sizeof(requestPacket), 0, (struct sockaddr *)&pingAddress, sizeof(pingAddress));
|
||||
@ -329,14 +341,43 @@ PingReply *Ping::createReply(const QHostAddress &hostAddress)
|
||||
return reply;
|
||||
}
|
||||
|
||||
PingReply *Ping::createReply(const QString &hostName)
|
||||
{
|
||||
PingReply *reply = new PingReply(this);
|
||||
reply->m_hostName = hostName;
|
||||
|
||||
connect(reply, &PingReply::timeout, this, [=](){
|
||||
// Note: this is not the ICMP timeout, here we actually got nothing from anybody...
|
||||
finishReply(reply, PingReply::ErrorTimeout);
|
||||
});
|
||||
|
||||
connect(reply, &PingReply::aborted, this, [=](){
|
||||
finishReply(reply, PingReply::ErrorAborted);
|
||||
});
|
||||
|
||||
connect(reply, &PingReply::finished, this, [=](){
|
||||
cleanUpReply(reply);
|
||||
reply->deleteLater();
|
||||
});
|
||||
|
||||
// Just in case the reply get's deleted before beeing able to finish ...
|
||||
connect(reply, &PingReply::destroyed, this, [this, reply](){
|
||||
cleanUpReply(reply);
|
||||
});
|
||||
|
||||
return reply;
|
||||
}
|
||||
|
||||
void Ping::finishReply(PingReply *reply, PingReply::Error error)
|
||||
{
|
||||
// Check if we should retry
|
||||
if (reply->m_retryCount >= reply->m_retries ||
|
||||
error == PingReply::ErrorNoError ||
|
||||
error == PingReply::ErrorAborted ||
|
||||
error == PingReply::ErrorInvalidHostAddress ||
|
||||
error == PingReply::ErrorPermissionDenied) {
|
||||
error == PingReply::ErrorNoError ||
|
||||
error == PingReply::ErrorAborted ||
|
||||
error == PingReply::ErrorInvalidHostAddress ||
|
||||
error == PingReply::ErrorPermissionDenied||
|
||||
error == PingReply::ErrorHostNameLookupFailed ||
|
||||
error == PingReply::ErrorHostNameNotFound) {
|
||||
// No retry, we are done
|
||||
reply->m_error = error;
|
||||
reply->m_timer->stop();
|
||||
@ -374,11 +415,11 @@ void Ping::cleanUpReply(PingReply *reply)
|
||||
m_pendingReplies.remove(reply->requestId());
|
||||
m_replyQueue.removeAll(reply);
|
||||
|
||||
if (m_pendingHostLookups.values().contains(reply)) {
|
||||
if (m_pendingHostNameLookups.values().contains(reply)) {
|
||||
// Abort any pending host lookups, the reply has been finished
|
||||
int lookupId = m_pendingHostLookups.key(reply);
|
||||
int lookupId = m_pendingHostNameLookups.key(reply);
|
||||
QHostInfo::abortHostLookup(lookupId);
|
||||
m_pendingHostLookups.remove(lookupId);
|
||||
m_pendingHostNameLookups.remove(lookupId);
|
||||
}
|
||||
}
|
||||
|
||||
@ -404,19 +445,19 @@ void Ping::onSocketReadyRead(int socketDescriptor)
|
||||
QHostAddress destinationAddress(qFromBigEndian(ipHeader->daddr));
|
||||
|
||||
qCDebug(dcPingTraffic()) << "IP header: Lenght" << ipHeaderLength
|
||||
<< "Sender:" << senderAddress.toString()
|
||||
<< "Destination:" << destinationAddress.toString()
|
||||
<< "Size:" << htons(ipHeader->tot_len) << "B"
|
||||
<< "TTL" << ipHeader->ttl;
|
||||
<< "Sender:" << senderAddress.toString()
|
||||
<< "Destination:" << destinationAddress.toString()
|
||||
<< "Size:" << htons(ipHeader->tot_len) << "B"
|
||||
<< "TTL" << ipHeader->ttl;
|
||||
|
||||
struct icmp *responsePacket = reinterpret_cast<struct icmp *>(receiveBuffer + ipHeaderLength);
|
||||
quint16 icmpId = htons(responsePacket->icmp_id);
|
||||
quint16 icmpSequnceNumber = htons(responsePacket->icmp_seq);
|
||||
qCDebug(dcPingTraffic()) << "ICMP packt (Size:" << icmpPacketSize << "Bytes):"
|
||||
<< "Type" << responsePacket->icmp_type
|
||||
<< "Code:" << responsePacket->icmp_code
|
||||
<< "ID:" << QString("0x%1").arg(icmpId, 4, 16, QChar('0'))
|
||||
<< "Sequence:" << icmpSequnceNumber;
|
||||
<< "Type" << responsePacket->icmp_type
|
||||
<< "Code:" << responsePacket->icmp_code
|
||||
<< "ID:" << QString("0x%1").arg(icmpId, 4, 16, QChar('0'))
|
||||
<< "Sequence:" << icmpSequnceNumber;
|
||||
|
||||
if (responsePacket->icmp_type == ICMP_ECHOREPLY) {
|
||||
|
||||
@ -447,14 +488,14 @@ void Ping::onSocketReadyRead(int socketDescriptor)
|
||||
reply->m_duration = qRound((receiveTimeValue.tv_sec * 1000 + (double)receiveTimeValue.tv_usec / 1000) * 100) / 100.0;
|
||||
|
||||
qCDebug(dcPing()) << "Received ICMP response" << reply->targetHostAddress().toString() << ICMP_PACKET_SIZE << "[Bytes]"
|
||||
<< "ID:" << QString("0x%1").arg(icmpId, 4, 16, QChar('0'))
|
||||
<< "Sequence:" << icmpSequnceNumber
|
||||
<< "Time:" << reply->duration() << "[ms]";
|
||||
<< "ID:" << QString("0x%1").arg(icmpId, 4, 16, QChar('0'))
|
||||
<< "Sequence:" << icmpSequnceNumber
|
||||
<< "Time:" << reply->duration() << "[ms]";
|
||||
|
||||
if (reply->doHostLookup()) {
|
||||
// Note: due to a Qt bug < 5.9 we need to use old SLOT style and cannot make use of lambda here
|
||||
int lookupId = QHostInfo::lookupHost(senderAddress.toString(), this, SLOT(onHostLookupFinished(QHostInfo)));
|
||||
m_pendingHostLookups.insert(lookupId, reply);
|
||||
m_pendingHostNameLookups.insert(lookupId, reply);
|
||||
// Finish the reply after the host lookup has finished
|
||||
} else {
|
||||
finishReply(reply, PingReply::ErrorNoError);
|
||||
@ -472,20 +513,20 @@ void Ping::onSocketReadyRead(int socketDescriptor)
|
||||
QHostAddress nestedDestinationAddress(qFromBigEndian(nestedIpHeader->daddr));
|
||||
|
||||
qCDebug(dcPingTraffic()) << "++ IP header: Lenght" << nestedIpHeaderLength
|
||||
<< "Sender:" << nestedSenderAddress.toString()
|
||||
<< "Destination:" << nestedDestinationAddress.toString()
|
||||
<< "Size:" << htons(nestedIpHeader->tot_len) << "B"
|
||||
<< "TTL" << ipHeader->ttl;
|
||||
<< "Sender:" << nestedSenderAddress.toString()
|
||||
<< "Destination:" << nestedDestinationAddress.toString()
|
||||
<< "Size:" << htons(nestedIpHeader->tot_len) << "B"
|
||||
<< "TTL" << ipHeader->ttl;
|
||||
|
||||
struct icmp *nestedResponsePacket = reinterpret_cast<struct icmp *>(receiveBuffer + messageOffset + nestedIpHeaderLength);
|
||||
icmpId = htons(nestedResponsePacket->icmp_id);
|
||||
icmpSequnceNumber = htons(nestedResponsePacket->icmp_seq);
|
||||
|
||||
qCDebug(dcPingTraffic()) << "++ ICMP packt (Size:" << nestedIcmpPacketSize << "Bytes):"
|
||||
<< "Type" << nestedResponsePacket->icmp_type
|
||||
<< "Code:" << nestedResponsePacket->icmp_code
|
||||
<< "ID:" << QString("0x%1").arg(icmpId, 4, 16, QChar('0'))
|
||||
<< "Sequence:" << icmpSequnceNumber;
|
||||
<< "Type" << nestedResponsePacket->icmp_type
|
||||
<< "Code:" << nestedResponsePacket->icmp_code
|
||||
<< "ID:" << QString("0x%1").arg(icmpId, 4, 16, QChar('0'))
|
||||
<< "Sequence:" << icmpSequnceNumber;
|
||||
|
||||
qCDebug(dcPing()) << "ICMP destination unreachable" << nestedDestinationAddress.toString()
|
||||
<< "Code:" << nestedResponsePacket->icmp_code
|
||||
@ -495,9 +536,9 @@ void Ping::onSocketReadyRead(int socketDescriptor)
|
||||
PingReply *reply = m_pendingReplies.value(icmpId);
|
||||
if (!reply) {
|
||||
qCDebug(dcPingTraffic()) << "No pending reply for ping echo response unreachable with ID"
|
||||
<< QString("0x%1").arg(icmpId, 4, 16, QChar('0'))
|
||||
<< "Sequence:" << icmpSequnceNumber
|
||||
<< "from" << nestedSenderAddress.toString() << "to" << nestedDestinationAddress.toString();
|
||||
<< QString("0x%1").arg(icmpId, 4, 16, QChar('0'))
|
||||
<< "Sequence:" << icmpSequnceNumber
|
||||
<< "from" << nestedSenderAddress.toString() << "to" << nestedDestinationAddress.toString();
|
||||
return;
|
||||
}
|
||||
|
||||
@ -508,20 +549,74 @@ void Ping::onSocketReadyRead(int socketDescriptor)
|
||||
|
||||
void Ping::onHostLookupFinished(const QHostInfo &info)
|
||||
{
|
||||
PingReply *reply = m_pendingHostLookups.value(info.lookupId());
|
||||
if (!reply) {
|
||||
qCWarning(dcPing()) << "Could not find reply after host lookup.";
|
||||
return;
|
||||
}
|
||||
if (m_pendingHostNameLookups.contains(info.lookupId())) {
|
||||
|
||||
if (info.error() != QHostInfo::NoError) {
|
||||
qCWarning(dcPing()) << "Failed to look up hostname after successfull ping" << reply->targetHostAddress().toString() << info.error();
|
||||
} else {
|
||||
qCDebug(dcPing()) << "Looked up hostname after successfull ping" << reply->targetHostAddress().toString() << info.hostName();
|
||||
if (info.hostName() != reply->targetHostAddress().toString()) {
|
||||
reply->m_hostName = info.hostName();
|
||||
PingReply *reply = m_pendingHostNameLookups.take(info.lookupId());
|
||||
if (!reply) {
|
||||
qCWarning(dcPing()) << "Could not find ping reply after finished host lookup" << info.hostName() << info.addresses() << info.errorString();
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
finishReply(reply, PingReply::ErrorNoError);
|
||||
PingReply::Error pingError = PingReply::ErrorNoError;
|
||||
switch(info.error()) {
|
||||
case QHostInfo::NoError:
|
||||
qCDebug(dcPing()) << "Looked up hostname after successfull ping" << reply->targetHostAddress().toString() << info.hostName();
|
||||
if (info.hostName() != reply->targetHostAddress().toString())
|
||||
reply->m_hostName = info.hostName();
|
||||
|
||||
break;
|
||||
case QHostInfo::HostNotFound:
|
||||
qCWarning(dcPing()) << "Unable to find hostname:" << reply->hostName() << info.errorString();
|
||||
pingError = PingReply::ErrorHostNameNotFound;
|
||||
break;
|
||||
default:
|
||||
qCWarning(dcPing()) << "Failed to lookup hostname" << (reply->targetHostAddress().isNull() ? reply->hostName() : reply->targetHostAddress().toString()) << info.errorString();
|
||||
pingError = PingReply::ErrorHostNameLookupFailed;
|
||||
break;
|
||||
}
|
||||
|
||||
finishReply(reply, pingError);
|
||||
|
||||
} else if (m_pendingHostAddressLookups.contains(info.lookupId())) {
|
||||
|
||||
PingReply *reply = m_pendingHostAddressLookups.take(info.lookupId());
|
||||
if (!reply) {
|
||||
qCWarning(dcPing()) << "Could not find ping reply after finished host lookup" << info.hostName() << info.addresses() << info.errorString();
|
||||
return;
|
||||
}
|
||||
|
||||
PingReply::Error pingError = PingReply::ErrorNoError;
|
||||
switch(info.error()) {
|
||||
case QHostInfo::NoError:
|
||||
qCDebug(dcPing()) << "Looked up address for hostname finished successfully" << info.hostName() << info.addresses();
|
||||
if (info.addresses().isEmpty()) {
|
||||
qCWarning(dcPing()) << "Looked up address finished succesfully but there are no addresses available for" << info.hostName();
|
||||
pingError = PingReply::ErrorHostNameNotFound;
|
||||
} else {
|
||||
reply->m_targetHostAddress = info.addresses().first();
|
||||
reply->m_networkInterface = NetworkUtils::getInterfaceForHostaddress(reply->targetHostAddress());
|
||||
pingError = PingReply::ErrorNoError;
|
||||
}
|
||||
break;
|
||||
case QHostInfo::HostNotFound:
|
||||
qCDebug(dcPing()) << "Unable to find hostname:" << reply->hostName() << info.errorString();
|
||||
pingError = PingReply::ErrorHostNameNotFound;
|
||||
break;
|
||||
default:
|
||||
qCWarning(dcPing()) << "Failed to lookup hostname" << (reply->targetHostAddress().isNull() ? reply->hostName() : reply->targetHostAddress().toString()) << info.errorString();
|
||||
pingError = PingReply::ErrorHostNameLookupFailed;
|
||||
break;
|
||||
}
|
||||
|
||||
if (pingError != PingReply::ErrorNoError) {
|
||||
// Host lookup failed, we cannot continue, nothing to ping
|
||||
finishReply(reply, pingError);
|
||||
} else {
|
||||
// Ping the resolved host address
|
||||
m_replyQueue.enqueue(reply);
|
||||
sendNextReply();
|
||||
}
|
||||
} else {
|
||||
qCWarning(dcPing()) << "Host name lookup finished but we have no ping reply for it. Ignoring looked up information" << info.hostName() << info.addresses() << info.error();
|
||||
}
|
||||
}
|
||||
|
||||
@ -67,6 +67,8 @@ public:
|
||||
PingReply *ping(const QHostAddress &hostAddress, uint retries = 3);
|
||||
PingReply *ping(const QHostAddress &hostAddress, bool lookupHost, uint retries = 3);
|
||||
|
||||
PingReply *ping(const QString &hostName, uint retries = 3);
|
||||
|
||||
signals:
|
||||
void availableChanged(bool available);
|
||||
|
||||
@ -91,7 +93,8 @@ private:
|
||||
QTimer *m_queueTimer = nullptr;
|
||||
PingReply *m_currentReply = nullptr;
|
||||
void sendNextReply();
|
||||
QHash<int, PingReply *> m_pendingHostLookups;
|
||||
QHash<int, PingReply *> m_pendingHostNameLookups;
|
||||
QHash<int, PingReply *> m_pendingHostAddressLookups;
|
||||
|
||||
//Error performPing(const QString &address);
|
||||
void performPing(PingReply *reply);
|
||||
@ -104,13 +107,13 @@ private:
|
||||
quint16 calculateRequestId();
|
||||
|
||||
PingReply *createReply(const QHostAddress &hostAddress);
|
||||
PingReply *createReply(const QString &hostName);
|
||||
void finishReply(PingReply *reply, PingReply::Error error);
|
||||
void cleanUpReply(PingReply *reply);
|
||||
|
||||
private slots:
|
||||
void onSocketReadyRead(int socketDescriptor);
|
||||
void onHostLookupFinished(const QHostInfo &info);
|
||||
|
||||
};
|
||||
|
||||
#endif // PING_H
|
||||
|
||||
@ -59,7 +59,9 @@ public:
|
||||
ErrorSocketError,
|
||||
ErrorTimeout,
|
||||
ErrorHostUnreachable,
|
||||
ErrorInvalidHostAddress
|
||||
ErrorInvalidHostAddress,
|
||||
ErrorHostNameLookupFailed,
|
||||
ErrorHostNameNotFound
|
||||
};
|
||||
Q_ENUM(Error)
|
||||
|
||||
|
||||
Reference in New Issue
Block a user