36 QPair<QHostAddress,int>
gIPv4LinkLocal = QHostAddress::parseSubnet(QStringLiteral(
"169.254.0.0/16"));
37 QPair<QHostAddress,int>
gIPv4PrivateA = QHostAddress::parseSubnet(QStringLiteral(
"10.0.0.0/8"));
38 QPair<QHostAddress,int>
gIPv4PrivateB = QHostAddress::parseSubnet(QStringLiteral(
"172.16.0.0/12"));
39 QPair<QHostAddress,int>
gIPv4PrivateC = QHostAddress::parseSubnet(QStringLiteral(
"192.168.0.0/16"));
41 QPair<QHostAddress,int>
gIPv6LinkLocal = QHostAddress::parseSubnet(QStringLiteral(
"fe80::/10"));
42 QPair<QHostAddress,int>
gIPv6SiteLocal = QHostAddress::parseSubnet(QStringLiteral(
"fec0::/10"));
43 QPair<QHostAddress,int>
gIPv6UniqueLocal = QHostAddress::parseSubnet(QStringLiteral(
"fc00::/7"));
44 QPair<QHostAddress,int>
gIPv6Global = QHostAddress::parseSubnet(QStringLiteral(
"2000::/3"));
50 return gNetwork ? gNetwork->
IsOnline() :
false;
96 if (!Request || !Parent)
101 LOG(VB_GENERAL, LOG_ERR, QStringLiteral(
"Cannot queue asynchronous request for streamed buffer"));
105 if (Parent->metaObject()->indexOfMethod(QMetaObject::normalizedSignature(
"RequestReady(TorcNetworkRequest*)")) < 0)
107 LOG(VB_GENERAL, LOG_ERR, QStringLiteral(
"Request's parent does not have RequestReady method"));
133 bool changed =
false;
140 LOG(VB_GENERAL, LOG_WARNING, QStringLiteral(
"Number of host names > 10 - ignoring new name '%1' (%2)").arg(Host,
gNetworkHostNames.join(
',')));
144 LOG(VB_GENERAL, LOG_INFO, QStringLiteral(
"New host name '%1'").arg(Host));
161 bool changed =
false;
168 LOG(VB_GENERAL, LOG_INFO, QStringLiteral(
"Removed host name '%1'").arg(Host));
187 result.removeDuplicates();
200 if (UseLocalhost && Address.isLoopback())
202 result = QStringLiteral(
"localhost");
204 else if (Address.protocol() == QAbstractSocket::IPv4Protocol)
206 result = Address.toString();
210 QHostAddress address(Address);
211 address.setScopeId(QStringLiteral(
""));
212 result =
"[" + address.toString() +
"]";
216 result +=
":" + QString::number(Port);
224 if (Address.isNull() || Address.isLoopback())
231 if (Address.isNull())
240 if (Address.isNull())
243 if (Address.protocol() == QAbstractSocket::IPv4Protocol)
244 if (Address.isInSubnet(gIPv4PrivateA) || Address.isInSubnet(gIPv4PrivateB) || Address.isInSubnet(gIPv4PrivateC))
249 if (Address.isInSubnet(gIPv6UniqueLocal) || Address.isInSubnet(gIPv6SiteLocal))
299 case QNetworkConfiguration::InternetAccessPoint:
return QStringLiteral(
"InternetAccessPoint");
300 case QNetworkConfiguration::ServiceNetwork:
return QStringLiteral(
"ServiceNetwork");
301 case QNetworkConfiguration::UserChoice:
return QStringLiteral(
"UserDefined");
302 case QNetworkConfiguration::Invalid:
return QStringLiteral(
"Invalid");
305 return QStringLiteral();
314 : QNetworkAccessManager(),
321 m_asynchronousRequests()
323 LOG(VB_GENERAL, LOG_INFO, QStringLiteral(
"Opening network access manager"));
324 LOG(VB_GENERAL, LOG_INFO, QStringLiteral(
"SSL support is %1available").arg(QSslSocket::supportsSsl() ? QStringLiteral(
"") : QStringLiteral(
"not ")));
349 LOG(VB_GENERAL, LOG_INFO, QStringLiteral(
"Closing network access manager"));
359 return QNetworkInterface::allAddresses().contains(Address);
364 if (Request && m_online)
371 QNetworkReply* reply =
nullptr;
373 if (Request->
m_type == QNetworkAccessManager::GetOperation)
375 else if (Request->
m_type == QNetworkAccessManager::HeadOperation)
377 else if (Request->
m_type == QNetworkAccessManager::PostOperation)
383 LOG(VB_GENERAL, LOG_ERR, QStringLiteral(
"Unknown request type"));
391 connect(reply,
static_cast<void (QNetworkReply::*)(QNetworkReply::NetworkError)
>(&QNetworkReply::error),
this, &
TorcNetwork::Error);
394 m_requests.insert(reply, Request);
395 m_reverseRequests.insert(Request, reply);
401 if (m_reverseRequests.contains(Request))
403 QNetworkReply* reply = m_reverseRequests.take(Request);
405 m_requests.remove(reply);
406 if (reply->isFinished())
407 LOG(VB_NETWORK, LOG_DEBUG, QStringLiteral(
"Deleting finished request '%1'").arg(reply->request().url().toString()));
409 LOG(VB_GENERAL, LOG_INFO, QStringLiteral(
"Cancelling '%1'").arg(reply->request().url().toString()));
411 reply->deleteLater();
414 if (m_asynchronousRequests.contains(Request))
416 QObject *parent = m_asynchronousRequests.take(Request);
417 if (!QMetaObject::invokeMethod(parent,
"RequestReady", Qt::AutoConnection, Q_ARG(
TorcNetworkRequest*, Request)))
418 LOG(VB_GENERAL, LOG_ERR, QStringLiteral(
"Error sending RequestReady"));
423 LOG(VB_GENERAL, LOG_ERR, QStringLiteral(
"Trying to cancel unknown network request"));
429 if (m_reverseRequests.contains(Request))
430 Request->
Write(m_reverseRequests.value(Request));
435 if (!Request || !Parent)
438 if (m_asynchronousRequests.contains(Request))
440 LOG(VB_GENERAL, LOG_ERR, QStringLiteral(
"Asynchronous request is already queued - ignoring"));
446 m_asynchronousRequests.insert(Request, Parent);
482 if (!Request || !Reply)
485 QVariant status = Reply->attribute(QNetworkRequest::HttpStatusCodeAttribute);
486 if (!status.isValid())
489 int httpstatus = status.toInt();
490 int contentlength = 0;
493 QVariant length = Reply->header(QNetworkRequest::ContentLengthHeader);
494 if (length.isValid())
496 int size = length.toInt();
498 contentlength = size;
502 QVariant contenttype = Reply->header(QNetworkRequest::ContentTypeHeader);
504 if (Request->
m_type == QNetworkAccessManager::HeadOperation)
516 m_reverseRequests.remove(Request);
517 m_requests.remove(Reply);
518 Request->
m_request.setUrl(Reply->request().url());
519 Request->
m_type = QNetworkAccessManager::GetOperation;
522 Reply->deleteLater();
531 Request->
m_contentType = contenttype.isValid() ? contenttype.toString().toLower() : QStringLiteral();
532 Request->
m_byteServingAvailable = Reply->rawHeader(
"Accept-Ranges").toLower().contains(
"bytes") && contentlength > 0;
538 if (!Request || !Reply)
541 QUrl newurl = Reply->attribute(QNetworkRequest::RedirectionTargetAttribute).toUrl();
544 if (!newurl.isEmpty() && newurl != oldurl)
547 if (newurl.isRelative())
548 newurl = oldurl.resolved(newurl);
550 LOG(VB_GENERAL, LOG_INFO, QStringLiteral(
"Redirected from '%1' to '%2'").arg(oldurl.toString(), newurl.toString()));
554 m_reverseRequests.remove(Request);
555 m_requests.remove(Reply);
557 Reply->deleteLater();
565 LOG(VB_GENERAL, LOG_WARNING, QStringLiteral(
"Max redirections exceeded"));
574 QNetworkReply *reply =
dynamic_cast<QNetworkReply*
>(sender());
577 if (reply && m_requests.contains(reply) && (request = m_requests.value(reply)))
593 LOG(VB_GENERAL, LOG_INFO, QStringLiteral(
"Download started"));
597 request->
Write(reply);
603 QNetworkReply *reply =
dynamic_cast<QNetworkReply*
>(sender());
606 if (reply && m_requests.contains(reply) && (request = m_requests.value(reply)))
608 if (request->
m_type == QNetworkAccessManager::HeadOperation)
618 else if (request->
m_type == QNetworkAccessManager::PostOperation)
628 if (m_asynchronousRequests.contains(request))
635 QNetworkReply *reply =
dynamic_cast<QNetworkReply*
>(sender());
638 if (reply && m_requests.contains(reply) && (request = m_requests.value(reply)) && (Code != QNetworkReply::OperationCanceledError))
641 LOG(VB_GENERAL, LOG_ERR, QStringLiteral(
"Network error '%1'").arg(reply->errorString()));
647 bool selfsigned =
false;
648 bool mismatched =
false;
651 QList<QSslError> allowed;
652 foreach (
const QSslError &error, Errors)
654 if (error.error() == QSslError::SelfSignedCertificate)
656 LOG(VB_GENERAL, LOG_INFO, QStringLiteral(
"Allowing self signed certificate"));
660 else if (error.error() == QSslError::HostNameMismatch)
667 LOG(VB_GENERAL, LOG_INFO, QStringLiteral(
"Ssl Error: %1").arg(error.errorString()));
675 LOG(VB_GENERAL, LOG_INFO, QStringLiteral(
"Allowing host name mismatch for self signed certfificate"));
680 LOG(VB_GENERAL, LOG_INFO, QStringLiteral(
"Ssl Error: %1").arg(mismatch.errorString()));
689 QNetworkReply *reply =
dynamic_cast<QNetworkReply*
>(sender());
693 if (!allowed.isEmpty())
700 QNetworkReply *reply =
dynamic_cast<QNetworkReply*
>(sender());
703 if (reply && m_requests.contains(reply) && (request = m_requests.value(reply)))
711 LOG(VB_GENERAL, LOG_INFO, QStringLiteral(
"Authentication required"));
717 if (!Info.hostName().isEmpty())
719 m_hostNames.append(Info.hostName());
737 if (!m_requests.isEmpty())
738 LOG(VB_GENERAL, LOG_WARNING, QStringLiteral(
"%1 outstanding network requests").arg(m_requests.size()));
740 while (!m_requests.isEmpty())
741 CancelSafe(*m_requests.begin());
744 m_reverseRequests.clear();
745 m_asynchronousRequests.clear();
750 QNetworkConfiguration configuration = m_manager.defaultConfiguration();
751 bool wasonline = m_online;
752 bool changed =
false;
754 if (configuration != m_configuration || Creating)
757 m_configuration = configuration;
759 if (m_configuration.isValid())
761 LOG(VB_GENERAL, LOG_INFO, QStringLiteral(
"Network interface: %1 Bearer: %2").arg(configuration.name(), configuration.bearerTypeName()));
766 LOG(VB_GENERAL, LOG_INFO, QStringLiteral(
"No valid network connection"));
771 if (m_online && !wasonline)
775 QStringList addresses;
776 QList<QHostAddress> entries = QNetworkInterface::allAddresses();
777 foreach (
const QHostAddress &entry, entries)
779 QString address = entry.toString();
780 addresses << address;
781 QHostInfo::lookupHost(address,
this, SLOT(
NewHostName(QHostInfo)));
784 LOG(VB_GENERAL, LOG_INFO, QStringLiteral(
"Network up (%1)").arg(addresses.join(QStringLiteral(
", "))));
786 else if (wasonline && !m_online)
788 LOG(VB_GENERAL, LOG_INFO, QStringLiteral(
"Network down"));
792 foreach (QString host, m_hostNames)
794 m_hostNames = QStringList();
798 LOG(VB_GENERAL, LOG_INFO, QStringLiteral(
"Network configuration changed"));
812 qRegisterMetaType<TorcNetworkRequest*>();
813 qRegisterMetaType<QNetworkReply*>();
#define DEFAULT_USER_AGENT
void ConfigurationChanged(const QNetworkConfiguration &Config)
void NewAsyncRequest(TorcNetworkRequest *Request, QObject *Parent)
void CancelRequest(TorcNetworkRequest *Request)
static void Setup(bool Create)
TorcLocalContext * gLocalContext
void SetReplyError(QNetworkReply::NetworkError Error)
void UpdateConfiguration(bool Creating=false)
A factory class for automatically running objects outside of the main loop.
A wrapper around QNetworkRequest.
static bool GetAsynchronous(TorcNetworkRequest *Request, QObject *Parent)
Queue an asynchronous HTTP request.
void ConfigurationRemoved(const QNetworkConfiguration &Config)
static QStringList GetHostNames(void)
Retrieve the list of currently identified host names.
static bool IsGlobal(const QHostAddress &Address)
QNetworkAccessManager::Operation m_type
static QString IPAddressToLiteral(const QHostAddress &Address, int Port, bool UseLocalhost=true)
Convert an IP address to a string literal.
void UpdateCompleted(void)
#define TORC_ADMIN_CRIT_PRIORITY
static bool IsAvailable(void)
virtual bool DownRef(void)
bool IsOwnAddressPriv(const QHostAddress &Address)
QPair< QHostAddress, int > gIPv4PrivateA
const QByteArray m_postData
static void NotifyEvent(int Event)
QPair< QHostAddress, int > gIPv6Global
void ConfigurationAdded(const QNetworkConfiguration &Config)
static QList< QSslError > AllowableSslErrors(const QList< QSslError > &Errors)
static void AddHostName(const QString &Host)
Register a known host name for this application.
QPair< QHostAddress, int > gIPv6LinkLocal
bool m_byteServingAvailable
void PokeRequest(TorcNetworkRequest *Request)
bool Redirected(TorcNetworkRequest *Request, QNetworkReply *Reply)
QStringList gNetworkHostNames
static bool IsLinkLocal(const QHostAddress &Address)
QPair< QHostAddress, int > gIPv6UniqueLocal
void Authenticate(QNetworkReply *Reply, QAuthenticator *Authenticator)
#define DEFAULT_MAX_REDIRECTIONS
void DownloadProgress(qint64 Received, qint64 Total)
QList< QNetworkReply::RawHeaderPair > m_rawHeaders
QPair< QHostAddress, int > gIPv4PrivateB
QNetworkRequest m_request
QString ConfigurationTypeToString(QNetworkConfiguration::Type Type)
void DownloadProgress(qint64 Received, qint64 Total)
void Write(QNetworkReply *Reply)
static bool IsExternal(const QHostAddress &Address)
Returns true if the address is accessible from other devices.
friend class TorcNetworkObject
void NewRequest(TorcNetworkRequest *Request)
void SSLErrors(const QList< QSslError > &Errors)
bool CheckHeaders(TorcNetworkRequest *Request, QNetworkReply *Reply)
static void Poke(TorcNetworkRequest *Request)
QReadWriteLock * gNetworkHostNamesLock
#define LOG(_MASK_, _LEVEL_, _STRING_)
void Error(QNetworkReply::NetworkError Code)
Subclass of QNetworkAccessManager for sending network requests and monitoring the network state...
QPair< QHostAddress, int > gIPv4PrivateC
static void Cancel(TorcNetworkRequest *Request)
static bool Get(TorcNetworkRequest *Request)
static bool IsOwnAddress(const QHostAddress &Address)
void CloseConnections(void)
Cancel all current network requests.
static void RemoveHostName(const QString &Host)
Remove a host name from the known list of host names.
void OnlineStateChanged(bool Online)
QPair< QHostAddress, int > gIPv4LinkLocal
QPair< QHostAddress, int > gIPv6SiteLocal
A static class used to create the TorcNetwork singleton in the admin thread.
void NewHostName(const QHostInfo &Info)
Receives host name updates from QHostInfo.
void SetRange(int Start, int End=0)
static bool IsLocal(const QHostAddress &Address)