mirror of
https://github.com/swift-project/pilotclient.git
synced 2026-04-04 16:56:53 +08:00
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:
committed by
Mathew Sutcliffe
parent
dff7ed5a90
commit
19df8a5d71
@@ -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"
|
||||
|
||||
185
src/blackmisc/network/networkutils.cpp
Normal file
185
src/blackmisc/network/networkutils.cpp
Normal 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
|
||||
86
src/blackmisc/network/networkutils.h
Normal file
86
src/blackmisc/network/networkutils.h
Normal 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
|
||||
|
||||
242
src/blackmisc/network/url.cpp
Normal file
242
src/blackmisc/network/url.cpp
Normal 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
162
src/blackmisc/network/url.h
Normal 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
|
||||
91
src/blackmisc/network/urllist.cpp
Normal file
91
src/blackmisc/network/urllist.cpp
Normal 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
|
||||
66
src/blackmisc/network/urllist.h
Normal file
66
src/blackmisc/network/urllist.h
Normal 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
|
||||
@@ -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
|
||||
@@ -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
|
||||
|
||||
Reference in New Issue
Block a user