refs #478, CUrl class and moved network utils

* moved network utils into network folder
* CUrl / CUrlList as DBus/JSON compliant class for locations
* Added support for selsigned certificates in network utils
This commit is contained in:
Klaus Basan
2015-10-14 01:37:23 +02:00
committed by Mathew Sutcliffe
parent dff7ed5a90
commit 19df8a5d71
14 changed files with 840 additions and 277 deletions

View File

@@ -14,7 +14,7 @@
/*!
* \namespace BlackMisc::Network
* \brief Classes related to the traffic network and swift DB, such as VATSIM user etc.
* \brief Classes related to the traffic network, swift DB, such as VATSIM user, utilities, URL etc.
*/
#include "blackmisc/network/user.h"

View File

@@ -0,0 +1,185 @@
/* Copyright (C) 2013 VATSIM Community / authors
* 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 "networkutils.h"
#include <QtNetwork/QNetworkInterface>
#include <QtNetwork/QTcpSocket>
#include <QCoreApplication>
#include <QHostAddress>
#include <QAbstractSocket>
#include <QUrl>
#include <QSslConfiguration>
using namespace BlackMisc::Network;
namespace BlackMisc
{
namespace Network
{
bool CNetworkUtils::hasConnectedInterface(bool withDebugOutput)
{
// http://stackoverflow.com/questions/2475266/verfiying-the-network-connection-using-qt-4-4
QList<QNetworkInterface> interfaces = QNetworkInterface::allInterfaces();
bool result = false;
for (int i = 0; i < interfaces.count(); i++)
{
QNetworkInterface iface = interfaces.at(i);
// details of connection
if (withDebugOutput) qDebug() << "name:" << iface.name() << endl << "ip addresses:" << endl << "mac:" << iface.hardwareAddress() << endl;
if (iface.flags().testFlag(QNetworkInterface::IsUp) && !iface.flags().testFlag(QNetworkInterface::IsLoopBack))
{
// this loop is important
for (int j = 0; j < iface.addressEntries().count(); j++)
{
if (withDebugOutput) qDebug() << iface.addressEntries().at(j).ip().toString() << " / " << iface.addressEntries().at(j).netmask().toString() << endl;
// we have an interface that is up, and has an ip address, therefore the link is present
// we will only enable this check on first positive, all later results are incorrect
if (!result)
{
result = true;
break;
}
}
}
}
return result;
}
QStringList CNetworkUtils::getKnownIpAddresses()
{
QStringList ips;
if (!CNetworkUtils::hasConnectedInterface(false)) return ips;
foreach(const QHostAddress & address, QNetworkInterface::allAddresses())
{
if (address.isLoopback() || address.isNull()) continue;
if (address.protocol() == QAbstractSocket::IPv4Protocol && address != QHostAddress(QHostAddress::LocalHost))
{
QString a = address.toString();
if (CNetworkUtils::isValidIPv4Address(a)) ips.append(a);
}
}
return ips;
}
/*
* Can connect to IP/port?
*/
bool CNetworkUtils::canConnect(const QString &hostAddress, int port, QString &message, int timeoutMs)
{
if (!CNetworkUtils::hasConnectedInterface(false))
{
message = QObject::tr("No connected network interface", "BlackMisc");
return false;
}
// http://qt-project.org/forums/viewthread/9346
QTcpSocket socket;
bool connected = false;
socket.connectToHost(hostAddress, static_cast<quint16>(port));
if (!socket.waitForConnected(timeoutMs))
{
message = QObject::tr("Connection failed : %1", "BlackMisc").arg(socket.errorString());
connected = false;
}
else
{
message = QObject::tr("OK, connected", "BlackMisc");
connected = true;
}
socket.close();
return connected;
}
bool CNetworkUtils::canConnect(const Network::CServer &server, QString &message, int timeoutMs)
{
return CNetworkUtils::canConnect(server.getAddress(), server.getPort(), message, timeoutMs);
}
bool CNetworkUtils::canConnect(const QString &url, QString &message, int timeoutMs)
{
if (url.isEmpty())
{
message = QObject::tr("Missing URL", "BlackMisc");
return false;
}
return canConnect(QUrl(url), message, timeoutMs);
}
bool CNetworkUtils::canConnect(const QUrl &url, QString &message, int timeoutMs)
{
if (!url.isValid())
{
message = QObject::tr("Invalid URL: %1", "BlackMisc").arg(url.toString());
return false;
}
if (url.isRelative())
{
message = QObject::tr("Relative URL cannot be tested: %1", "BlackMisc").arg(url.toString());
return false;
}
QString host(url.host());
QString scheme(url.scheme().toLower());
int p = url.port();
if (p < 0)
{
p = scheme.contains("https") ? 443 : 80;
}
return canConnect(host, p, message, timeoutMs);
}
bool CNetworkUtils::canConnect(const CUrl &location, QString &message, int timeoutMs)
{
return canConnect(location.getHost(), location.getPort(), message, timeoutMs);
}
bool CNetworkUtils::isValidIPv4Address(const QString &candidate)
{
QHostAddress address(candidate);
return (QAbstractSocket::IPv4Protocol == address.protocol());
}
bool CNetworkUtils::isValidIPv6Address(const QString &candidate)
{
QHostAddress address(candidate);
return (QAbstractSocket::IPv6Protocol == address.protocol());
}
bool CNetworkUtils::isValidPort(const QString &port)
{
bool success;
int p = port.toInt(&success);
if (!success) return false;
return (p >= 1 && p <= 65535);
}
QString CNetworkUtils::buildUrl(const QString &protocol, const QString &server, const QString &baseUrl, const QString &serviceUrl)
{
Q_ASSERT_X(protocol.length() > 3, Q_FUNC_INFO, "worng protocol");
Q_ASSERT_X(!server.isEmpty(), Q_FUNC_INFO, "missing server");
Q_ASSERT_X(!serviceUrl.isEmpty(), Q_FUNC_INFO, "missing service URL");
QString url(server);
if (!baseUrl.isEmpty())
{
url.append("/").append(baseUrl);
}
url.append("/").append(serviceUrl);
url.replace("//", "/");
return protocol + "://" + url;
}
void CNetworkUtils::ignoreSslVerification(QNetworkRequest &request)
{
QSslConfiguration conf = request.sslConfiguration();
conf.setPeerVerifyMode(QSslSocket::VerifyNone);
request.setSslConfiguration(conf);
}
} // namespace
} // namespacee

View File

@@ -0,0 +1,86 @@
/* Copyright (C) 2013
* swift Project Community / Contributors
*
* This file is part of swift project. It is subject to the license terms in the LICENSE file found in the top-level
* directory of this distribution and at http://www.swift-project.org/license.html. No part of swift project,
* including this file, may be copied, modified, propagated, or distributed except according to the terms
* contained in the LICENSE file.
*/
//! \file
#ifndef BLACKMISC_NETWORKUTILS_H
#define BLACKMISC_NETWORKUTILS_H
#include "blackmisc/blackmiscexport.h"
#include "blackmisc/network/server.h"
#include "blackmisc/network/url.h"
#include <QUrl>
#include <QStringList>
#include <QNetworkRequest>
namespace BlackMisc
{
namespace Network
{
//! Utilities, e.g. checking whether a network connection can be established
class BLACKMISC_EXPORT CNetworkUtils
{
public:
//! Is a connected interface available?
//! \param withDebugOutput enables some debugging output
//! \return
static bool hasConnectedInterface(bool withDebugOutput = false);
//! Can connect?
//! \param hostAddress 130.4.20.3, or myserver.com
//! \param port 80, 1234
//! \param timeoutMs
//! \param message human readable message
//! \return
static bool canConnect(const QString &hostAddress, int port, QString &message, int timeoutMs = 1500);
//! Can connect to server?
//! \param server
//! \param message human readable message
//! \param timeoutMs
//! \return
static bool canConnect(const BlackMisc::Network::CServer &server, QString &message, int timeoutMs = 1500);
//! Can connect to URL?
static bool canConnect(const QString &url, QString &message, int timeoutMs = 1500);
//! Can connect to URL?
static bool canConnect(const QUrl &url, QString &message, int timeoutMs = 1500);
//! Can connect to URL?
static bool canConnect(const BlackMisc::Network::CUrl &location, QString &message, int timeoutMs = 1500);
//! Find out my IPv4 address, empty if not possible
static QStringList getKnownIpAddresses();
//! Valid IPv4 address
static bool isValidIPv4Address(const QString &candidate);
//! Valid IPv6 address
static bool isValidIPv6Address(const QString &candidate);
//! Valid port
static bool isValidPort(const QString &port);
//! Build / concatenate an URL
static QString buildUrl(const QString &protocol, const QString &server, const QString &baseUrl, const QString &serviceUrl);
//! Ignore SSL verification such as self signed certificates
static void ignoreSslVerification(QNetworkRequest &request);
private:
//! Deleted constructor
CNetworkUtils() {}
};
} // namespace
} // namespace
#endif // guard

View File

@@ -0,0 +1,242 @@
/* Copyright (C) 2015
* swift project Community / Contributors
*
* This file is part of swift project. It is subject to the license terms in the LICENSE file found in the top-level
* directory of this distribution and at http://www.swift-project.org/license.html. No part of swift project,
* including this file, may be copied, modified, propagated, or distributed except according to the terms
* contained in the LICENSE file.
*/
#include "blackmisc/network/url.h"
#include "blackmisc/blackmiscfreefunctions.h"
#include "blackmisc/network/networkutils.h"
#include "blackmisc/propertyindex.h"
namespace BlackMisc
{
namespace Network
{
CUrl::CUrl(const QString &fullUrl)
{
if (!fullUrl.isEmpty())
{
setFullUrl(fullUrl);
}
}
CUrl::CUrl(const QUrl &url)
{
this->setQUrl(url);
}
CUrl::CUrl(const QString &address, int port) :
CUrl("", address, port, "")
{ }
CUrl::CUrl(const QString &scheme, const QString &address, int port, const QString &path)
: m_host(address.trimmed()), m_port(port), m_path(path.trimmed())
{
this->setScheme(scheme);
}
void CUrl::setScheme(const QString &protocol)
{
m_scheme = protocol.trimmed().toLower().replace("://", "");
}
void CUrl::setPath(const QString &path)
{
m_path = path.simplified();
}
QString CUrl::appendPath(const QString &pathToAppend)
{
QString p(getPath());
p = p.append("/").append(pathToAppend.trimmed()).replace("//", "/");
this->setPath(p);
return m_path;
}
bool CUrl::hasPort() const
{
return m_port >= 0;
}
bool CUrl::isEmpty() const
{
return m_host.isEmpty();
}
bool CUrl::hasDefaultPort() const
{
return isDefaultPort(m_scheme, m_port);
}
void CUrl::setQuery(const QString &query)
{
QString q(stripQueryString(query));
m_query = q;
}
bool CUrl::hasQuery() const
{
return !m_query.isEmpty();
}
QString CUrl::appendQuery(const QString &queryToAppend)
{
QString q(stripQueryString(queryToAppend));
if (q.isEmpty()) { return m_query; }
if (!hasQuery())
{
this->setQuery(q);
}
else
{
m_query = m_query + "&" + q;
}
return m_query;
}
QString CUrl::getFullUrl() const
{
Q_ASSERT_X(!m_host.isEmpty(), Q_FUNC_INFO, "missing address");
if (m_host.isEmpty()) { return ""; }
QString qn(m_host);
if (!hasDefaultPort() && hasPort()) { qn = qn.append(":").append(QString::number(m_port)); }
if (hasPath()) { qn = qn.append("/").append(m_path).replace("//", "/"); }
if (hasQuery()) { qn = qn.append("?").append(m_query); }
if (hasScheme()) { qn = QString(this->getScheme()).append("://").append(qn); }
return qn;
}
void CUrl::setFullUrl(const QString &fullUrl)
{
setQUrl(QUrl(fullUrl));
}
QUrl CUrl::toQUrl() const
{
return QUrl(getFullUrl());
}
void CUrl::setQUrl(const QUrl &url)
{
this->setPort(url.port());
this->setHost(url.host());
this->setScheme(url.scheme());
this->setPath(url.path());
this->setQuery(url.query());
}
CUrl CUrl::withAppendedPath(const QString &path) const
{
if (path.isEmpty()) { return *this; }
CUrl url(*this);
url.appendPath(path);
return url;
}
CUrl CUrl::withAppendedQuery(const QString &query) const
{
if (query.isEmpty()) { return *this; }
CUrl url(*this);
url.appendQuery(query);
return url;
}
QString CUrl::convertToQString(bool i18n) const
{
Q_UNUSED(i18n);
return getFullUrl();
}
QJsonObject CUrl::toJson() const
{
QPair<QString, QJsonValue> v("url", getFullUrl());
QJsonObject json({ v });
return json;
}
void CUrl::convertFromJson(const QJsonObject &json)
{
QString url(json.value("url").toString());
this->setFullUrl(url);
}
int CUrl::protocolToDefaultPort(const QString &protocol)
{
const QString p(protocol.trimmed().toLower());
if (p == "ftp") return 20;
if (p == "https") return 443;
if (p == "http") return 80;
return -1;
}
bool CUrl::isDefaultPort(const QString &protocol, int port)
{
int p = protocolToDefaultPort(protocol);
if (p < 0) { return false; }
return port == p;
}
QString CUrl::stripQueryString(const QString query)
{
QString q(query.trimmed());
if (q.startsWith("?") || q.startsWith("&"))
{
q = q.mid(1);
}
if (q.endsWith("?") || q.endsWith("&"))
{
q = q.left(q.size() - 1);
}
return q;
}
CVariant CUrl::propertyByIndex(const BlackMisc::CPropertyIndex &index) const
{
if (index.isMyself()) { return CVariant::from(*this); }
ColumnIndex i = index.frontCasted<ColumnIndex>();
switch (i)
{
case IndexHost:
return CVariant::fromValue(this->m_host);
case IndexPort:
return CVariant::fromValue(this->m_port);
case IndexScheme:
return CVariant::fromValue(this->m_scheme);
case IndexPath:
return CVariant::fromValue(this->m_path);
default:
return CValueObject::propertyByIndex(index);
}
}
void CUrl::setPropertyByIndex(const CVariant &variant, const BlackMisc::CPropertyIndex &index)
{
if (index.isMyself()) { (*this) = variant.to<CUrl>(); return; }
ColumnIndex i = index.frontCasted<ColumnIndex>();
switch (i)
{
case IndexHost:
this->setHost(variant.value<QString>());
break;
case IndexPort:
this->setPort(variant.value<qint32>());
break;
case IndexPath:
this->setPath(variant.value<QString>());
break;
case IndexScheme:
this->setScheme(variant.value<QString>());
break;
default:
CValueObject::setPropertyByIndex(variant, index);
break;
}
}
} // namespace
} // namespace

162
src/blackmisc/network/url.h Normal file
View File

@@ -0,0 +1,162 @@
/* Copyright (C) 2015
* swift project Community / Contributors
*
* This file is part of swift project. It is subject to the license terms in the LICENSE file found in the top-level
* directory of this distribution and at http://www.swift-project.org/license.html. No part of swift project,
* including this file, may be copied, modified, propagated, or distributed except according to the terms
* contained in the LICENSE file.
*/
//! \file
#ifndef BLACKMISC_NETWORK_NETWORKLOCATION_H
#define BLACKMISC_NETWORK_NETWORKLOCATION_H
#include "blackmisc/blackmiscexport.h"
#include "blackmisc/valueobject.h"
#include <QUrl>
namespace BlackMisc
{
namespace Network
{
//! Value object encapsulating information of a location,
//! kind of simplied CValueObject compliant version of QUrl
class BLACKMISC_EXPORT CUrl : public CValueObject<CUrl>
{
public:
//! Properties by index
enum ColumnIndex
{
IndexScheme = BlackMisc::CPropertyIndex::GlobalIndexCUrl,
IndexHost,
IndexPort,
IndexPath,
IndexQuery
};
//! Default constructor.
CUrl(const QString &fullUrl = QString());
//! By QUrl.
CUrl(const QUrl &url);
//! Constructor.
CUrl(const QString &address, int port);
//! Constructor.
CUrl(const QString &scheme, const QString &address, int port, const QString &path);
//! Get host.
const QString &getHost() const { return m_host; }
//! Set address (e.g. myserver.foo.com)
void setHost(const QString &address) { m_host = address.trimmed(); }
//! Get protocl
const QString &getScheme() const { return m_scheme; }
//! Set protocol
void setScheme(const QString &protocol);
//! Protocol
bool hasScheme() const { return !m_scheme.isEmpty(); }
//! Get path
const QString &getPath() const { return m_path; }
//! Set path
void setPath(const QString &path);
//! Append path
QString appendPath(const QString &pathToAppend);
//! Has path?
bool hasPath() const { return !m_path.isEmpty(); }
//! Get port
int getPort() const { return m_port; }
//! Set port
void setPort(int port) { m_port = port; }
//! Port?
bool hasPort() const;
//! Default port
bool hasDefaultPort() const;
//! Get query part
QString getQuery() const { return m_query; }
//! Set query
void setQuery(const QString &query);
//! Query string?
bool hasQuery() const;
//! Append query
QString appendQuery(const QString &queryToAppend);
//! Empty
bool isEmpty() const;
//! Qualified name
QString getFullUrl() const;
//! Set full URL
void setFullUrl(const QString &fullUrl);
//! To QUrl
QUrl toQUrl() const;
//! To QUrl
void setQUrl(const QUrl &url);
//! Append path
CUrl withAppendedPath(const QString &path) const;
//! Append path
CUrl withAppendedQuery(const QString &query) const;
//! \copydoc CValueObject::propertyByIndex
CVariant propertyByIndex(const BlackMisc::CPropertyIndex &index) const;
//! \copydoc CValueObject::setPropertyByIndex
void setPropertyByIndex(const CVariant &variant, const BlackMisc::CPropertyIndex &index);
//! \copydoc CValueObject::convertToQString()
QString convertToQString(bool i18n = false) const;
//! \copydoc BlackMisc::Mixin::JsonByTuple::toJson
QJsonObject toJson() const;
//! \copydoc BlackMisc::Mixin::JsonByTuple::convertFromJson
void convertFromJson(const QJsonObject &json);
//! Protocol to default port
static int protocolToDefaultPort(const QString &protocol);
//! Default port for given protocol
static bool isDefaultPort(const QString &protocol, int port);
//! Convert to QUrl
operator QUrl() const { return this->toQUrl(); }
private:
BLACK_ENABLE_TUPLE_CONVERSION(CUrl)
QString m_scheme;
QString m_host;
int m_port = -1;
QString m_path;
QString m_query;
static QString stripQueryString(const QString query);
};
} // namespace
} // namespace
BLACK_DECLARE_TUPLE_CONVERSION(BlackMisc::Network::CUrl, (o.m_scheme, o.m_host, o.m_port, o.m_path, o.m_query))
Q_DECLARE_METATYPE(BlackMisc::Network::CUrl)
#endif // guard

View File

@@ -0,0 +1,91 @@
/* Copyright (C) 2015
* swift project Community / Contributors
*
* This file is part of swift project. It is subject to the license terms in the LICENSE file found in the top-level
* directory of this distribution and at http://www.swift-project.org/license.html. No part of swift project,
* including this file, may be copied, modified, propagated, or distributed except according to the terms
* contained in the LICENSE file.
*/
#include "blackmisc/network/urllist.h"
#include "blackmisc/math/mathutils.h"
using namespace BlackMisc::Math;
namespace BlackMisc
{
namespace Network
{
CUrlList::CUrlList() { }
CUrlList::CUrlList(const QStringList &listOfUrls)
{
for (const QString &url : listOfUrls)
{
this->push_back(CUrl(url));
}
}
CUrlList::CUrlList(const CSequence<CUrl> &other) :
CSequence<CUrl>(other)
{ }
CUrl CUrlList::getRandomUrl() const
{
if (this->isEmpty()) { return CUrl(); }
if (this->size() == 1) { return this->front();}
int i = CMathUtils::randomInteger(0, this->size() - 1);
return (*this)[i];
}
CUrl CUrlList::getRandomWithout(const CUrlList &exclude) const
{
CUrlList copy(*this);
copy.removeIfIn(exclude);
if (copy.isEmpty()) { return CUrl(); }
return copy.getRandomUrl();
}
CUrl CUrlList::getNextUrl(bool randomStart) const
{
if (this->isEmpty()) { return CUrl(); }
if (this->size() == 1) { return this->front();}
if (m_currentIndexDistributedLoad < 0)
{
// random start point
m_currentIndexDistributedLoad = randomStart ?
CMathUtils::randomInteger(0, this->size() - 1) :
0;
}
else
{
m_currentIndexDistributedLoad++;
if (m_currentIndexDistributedLoad >= this->size())
{
m_currentIndexDistributedLoad = 0;
}
}
return (*this)[m_currentIndexDistributedLoad];
}
CUrl CUrlList::getNextUrlWithout(const CUrlList &exclude, bool randomStart) const
{
CUrlList copy(*this);
copy.removeIfIn(exclude);
if (copy.isEmpty()) { return CUrl(); }
return copy.getNextUrl(randomStart);
}
CUrlList CUrlList::appendPath(const QString &path) const
{
if (path.isEmpty() || this->isEmpty()) { return (*this); }
CUrlList urls;
for (const CUrl &url : (*this))
{
urls.push_back(url.withAppendedPath(path));
}
return urls;
}
} // namespace
} // namespace

View File

@@ -0,0 +1,66 @@
/* Copyright (C) 2015
* swift project Community / Contributors
*
* This file is part of swift project. It is subject to the license terms in the LICENSE file found in the top-level
* directory of this distribution and at http://www.swift-project.org/license.html. No part of swift project,
* including this file, may be copied, modified, propagated, or distributed except according to the terms
* contained in the LICENSE file.
*/
//! \file
#ifndef BLACKMISC_NETWORK_NETWORKLOCATIONLIST_H
#define BLACKMISC_NETWORK_NETWORKLOCATIONLIST_H
#include "blackmisc/blackmiscexport.h"
#include "blackmisc/network/url.h"
#include "blackmisc/collection.h"
#include "blackmisc/sequence.h"
namespace BlackMisc
{
namespace Network
{
//! Value object encapsulating a list of servers.
class BLACKMISC_EXPORT CUrlList :
public CSequence<CUrl>,
public BlackMisc::Mixin::MetaType<CUrlList>
{
public:
BLACKMISC_DECLARE_USING_MIXIN_METATYPE(CUrlList)
//! Default constructor.
CUrlList();
//! By list of URLs
explicit CUrlList(const QStringList &listOfUrls);
//! Construct from a base class object.
CUrlList(const CSequence<CUrl> &other);
//! Random location for distributed load
CUrl getRandomUrl() const;
//! Random location for distributed load
CUrl getRandomWithout(const CUrlList &exclude) const;
//! Round robin with random start point
CUrl getNextUrl(bool randomStart = true) const;
//! Round robin with random start point
CUrl getNextUrlWithout(const CUrlList &exclude, bool randomStart = true) const;
//! Append path to all URLs
CUrlList appendPath(const QString &path) const;
private:
mutable int m_currentIndexDistributedLoad = -1;
};
} //namespace
} // namespace
Q_DECLARE_METATYPE(BlackMisc::Network::CUrlList)
Q_DECLARE_METATYPE(BlackMisc::CCollection<BlackMisc::Network::CUrl>)
Q_DECLARE_METATYPE(BlackMisc::CSequence<BlackMisc::Network::CUrl>)
#endif //guard

View File

@@ -1,192 +0,0 @@
/* Copyright (C) 2013 VATSIM Community / authors
* 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 "networkutils.h"
#include <QtNetwork/QNetworkInterface>
#include <QtNetwork/QTcpSocket>
#include <QCoreApplication>
#include <QHostAddress>
#include <QAbstractSocket>
#include <QUrl>
namespace BlackMisc
{
/*
* Connected interface?
*/
bool CNetworkUtils::hasConnectedInterface(bool withDebugOutput)
{
// http://stackoverflow.com/questions/2475266/verfiying-the-network-connection-using-qt-4-4
QList<QNetworkInterface> interfaces = QNetworkInterface::allInterfaces();
bool result = false;
for (int i = 0; i < interfaces.count(); i++)
{
QNetworkInterface iface = interfaces.at(i);
// details of connection
if (withDebugOutput) qDebug() << "name:" << iface.name() << endl << "ip addresses:" << endl << "mac:" << iface.hardwareAddress() << endl;
if (iface.flags().testFlag(QNetworkInterface::IsUp) && !iface.flags().testFlag(QNetworkInterface::IsLoopBack))
{
// this loop is important
for (int j = 0; j < iface.addressEntries().count(); j++)
{
if (withDebugOutput) qDebug() << iface.addressEntries().at(j).ip().toString() << " / " << iface.addressEntries().at(j).netmask().toString() << endl;
// we have an interface that is up, and has an ip address, therefore the link is present
// we will only enable this check on first positive, all later results are incorrect
if (!result)
{
result = true;
break;
}
}
}
}
return result;
}
/*
* My IP
*/
QStringList CNetworkUtils::getKnownIpAddresses()
{
QStringList ips;
if (!CNetworkUtils::hasConnectedInterface(false)) return ips;
foreach(const QHostAddress & address, QNetworkInterface::allAddresses())
{
if (address.isLoopback() || address.isNull()) continue;
if (address.protocol() == QAbstractSocket::IPv4Protocol && address != QHostAddress(QHostAddress::LocalHost))
{
QString a = address.toString();
if (CNetworkUtils::isValidIPv4Address(a)) ips.append(a);
}
}
return ips;
}
/*
* Can connect to IP/port?
*/
bool CNetworkUtils::canConnect(const QString &hostAddress, int port, QString &message, int timeoutMs)
{
if (!CNetworkUtils::hasConnectedInterface(false))
{
message = QObject::tr("No connected network interface", "BlackMisc");
return false;
}
// http://qt-project.org/forums/viewthread/9346
QTcpSocket socket;
bool connected = false;
socket.connectToHost(hostAddress, static_cast<quint16>(port));
if (!socket.waitForConnected(timeoutMs))
{
message = QObject::tr("Connection failed : %1", "BlackMisc").arg(socket.errorString());
connected = false;
}
else
{
message = QObject::tr("OK, connected", "BlackMisc");
connected = true;
}
socket.close();
return connected;
}
/*
* Can connect server?
*/
bool CNetworkUtils::canConnect(const Network::CServer &server, QString &message, int timeoutMs)
{
return CNetworkUtils::canConnect(server.getAddress(), server.getPort(), message, timeoutMs);
}
/*
* Can connect url?
*/
bool CNetworkUtils::canConnect(const QString &url, QString &message, int timeoutMs)
{
if (url.isEmpty())
{
message = QObject::tr("Missing URL", "BlackMisc");
return false;
}
return canConnect(QUrl(url), message, timeoutMs);
}
/*
* Can connect url?
*/
bool CNetworkUtils::canConnect(const QUrl &url, QString &message, int timeoutMs)
{
if (!url.isValid())
{
message = QObject::tr("Invalid URL: %1", "BlackMisc").arg(url.toString());
return false;
}
if (url.isRelative())
{
message = QObject::tr("Relative URL cannot be tested: %1", "BlackMisc").arg(url.toString());
return false;
}
QString scheme(url.scheme().toLower());
int p = scheme.contains("https") ? 443 : 80;
p = url.port(80);
QString host(url.host());
return canConnect(host, p, message, timeoutMs);
}
/*
* Valid IPv4 address
*/
bool CNetworkUtils::isValidIPv4Address(const QString &candidate)
{
QHostAddress address(candidate);
return (QAbstractSocket::IPv4Protocol == address.protocol());
}
/*
* Valid IPv6 address
*/
bool CNetworkUtils::isValidIPv6Address(const QString &candidate)
{
QHostAddress address(candidate);
return (QAbstractSocket::IPv6Protocol == address.protocol());
}
/*
* Valid port?
*/
bool CNetworkUtils::isValidPort(const QString &port)
{
bool success;
int p = port.toInt(&success);
if (!success) return false;
return (p >= 1 && p <= 65535);
}
/*
* Build URL
*/
QString CNetworkUtils::buildUrl(const QString &protocol, const QString &server, const QString &baseUrl, const QString &serviceUrl)
{
Q_ASSERT_X(protocol.length() > 3, Q_FUNC_INFO, "worng protocol");
Q_ASSERT_X(!server.isEmpty(), Q_FUNC_INFO, "missing server");
Q_ASSERT_X(!serviceUrl.isEmpty(), Q_FUNC_INFO, "missing service URL");
QString url(server);
if (!baseUrl.isEmpty())
{
url.append("/").append(baseUrl);
}
url.append("/").append(serviceUrl);
url.replace("//", "/");
return protocol + "://" + url;
}
} // namespace

View File

@@ -1,78 +0,0 @@
/* Copyright (C) 2013
* swift Project Community / Contributors
*
* This file is part of swift project. It is subject to the license terms in the LICENSE file found in the top-level
* directory of this distribution and at http://www.swift-project.org/license.html. No part of swift project,
* including this file, may be copied, modified, propagated, or distributed except according to the terms
* contained in the LICENSE file.
*/
//! \file
#ifndef BLACKMISC_NETWORKUTILS_H
#define BLACKMISC_NETWORKUTILS_H
#include "blackmiscexport.h"
#include "network/server.h"
#include <QUrl>
#include <QStringList>
namespace BlackMisc
{
//! Utilities, e.g. checking whether a network connection can be established
class BLACKMISC_EXPORT CNetworkUtils
{
public:
//!
//! Is a connected interface available?
//! \param withDebugOutput enables some debugging output
//! \return
static bool hasConnectedInterface(bool withDebugOutput = false);
//!
//! Can connect?
//! \param hostAddress 130.4.20.3, or myserver.com
//! \param port 80, 1234
//! \param timeoutMs
//! \param message human readable message
//! \return
static bool canConnect(const QString &hostAddress, int port, QString &message, int timeoutMs = 1500);
//!
//! Can connect to server?
//! \param server
//! \param message human readable message
//! \param timeoutMs
//! \return
static bool canConnect(const BlackMisc::Network::CServer &server, QString &message, int timeoutMs = 1500);
//! Can connect to URL?
static bool canConnect(const QString &url, QString &message, int timeoutMs = 1500);
//! Can connect to URL?
static bool canConnect(const QUrl &url, QString &message, int timeoutMs = 1500);
//! Find out my IPv4 address, empty if not possible
static QStringList getKnownIpAddresses();
//! Valid IPv4 address
static bool isValidIPv4Address(const QString &candidate);
//! Valid IPv6 address
static bool isValidIPv6Address(const QString &candidate);
//! Valid port
static bool isValidPort(const QString &port);
//! Build / concatenate an URL
static QString buildUrl(const QString &protocol, const QString &server, const QString &baseUrl, const QString &serviceUrl);
private:
//! Deleted constructor
CNetworkUtils() {}
};
} // namespace
#endif // guard