Torc  0.1
torcnetwork.cpp
Go to the documentation of this file.
1 /* Class TorcNetwork
2 *
3 * This file is part of the Torc project.
4 *
5 * Copyright (C) Mark Kendall 2012-18
6 *
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation; either version 2 of the License, or
10 * (at your option) any later version.
11 *
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
16 *
17 * You should have received a copy of the GNU General Public License
18 * along with this program; if not, write to the Free Software
19 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301,
20 * USA.
21 */
22 
23 // Torc
24 #include "torclocalcontext.h"
25 #include "torclogging.h"
26 #include "torcadminthread.h"
27 #include "http/torchttprequest.h"
28 #include "torcnetwork.h"
29 #include "torccoreutils.h"
30 
31 TorcNetwork* gNetwork = nullptr;
32 QMutex* gNetworkLock = new QMutex(QMutex::Recursive);
33 QStringList gNetworkHostNames;
34 QReadWriteLock* gNetworkHostNamesLock = new QReadWriteLock();
35 
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"));
40 
41 QPair<QHostAddress,int> gIPv6LinkLocal = QHostAddress::parseSubnet(QStringLiteral("fe80::/10"));
42 QPair<QHostAddress,int> gIPv6SiteLocal = QHostAddress::parseSubnet(QStringLiteral("fec0::/10")); // deprecated
43 QPair<QHostAddress,int> gIPv6UniqueLocal = QHostAddress::parseSubnet(QStringLiteral("fc00::/7"));
44 QPair<QHostAddress,int> gIPv6Global = QHostAddress::parseSubnet(QStringLiteral("2000::/3"));
45 
47 {
48  QMutexLocker locker(gNetworkLock);
49 
50  return gNetwork ? gNetwork->IsOnline() : false;
51 }
52 
53 bool TorcNetwork::IsOwnAddress(const QHostAddress &Address)
54 {
55  QMutexLocker locker(gNetworkLock);
56 
57  return gNetwork ? gNetwork->IsOwnAddressPriv(Address) : false;
58 }
59 
61 {
62  QMutexLocker locker(gNetworkLock);
63 
64  if (gNetwork->IsOnline())
65  {
66  emit gNetwork->NewRequest(Request);
67  return true;
68  }
69 
70  return false;
71 }
72 
74 {
75  QMutexLocker locker(gNetworkLock);
76  if (gNetwork)
77  emit gNetwork->CancelRequest(Request);
78 }
79 
81 {
82  QMutexLocker locker(gNetworkLock);
83 
84  if (gNetwork)
85  emit gNetwork->PokeRequest(Request);
86 }
87 
94 bool TorcNetwork::GetAsynchronous(TorcNetworkRequest *Request, QObject *Parent)
95 {
96  if (!Request || !Parent)
97  return false;
98 
99  if (Request->m_bufferSize)
100  {
101  LOG(VB_GENERAL, LOG_ERR, QStringLiteral("Cannot queue asynchronous request for streamed buffer"));
102  return false;
103  }
104 
105  if (Parent->metaObject()->indexOfMethod(QMetaObject::normalizedSignature("RequestReady(TorcNetworkRequest*)")) < 0)
106  {
107  LOG(VB_GENERAL, LOG_ERR, QStringLiteral("Request's parent does not have RequestReady method"));
108  return false;
109  }
110 
111  QMutexLocker locker(gNetworkLock);
112 
113  if (gNetwork->IsOnline())
114  {
115  emit gNetwork->NewAsyncRequest(Request, Parent);
116  return true;
117  }
118 
119  return false;
120 }
121 
131 void TorcNetwork::AddHostName(const QString &Host)
132 {
133  bool changed = false;
134 
135  {
136  QWriteLocker locker(gNetworkHostNamesLock);
137 
138  if (gNetworkHostNames.size() > 10)
139  {
140  LOG(VB_GENERAL, LOG_WARNING, QStringLiteral("Number of host names > 10 - ignoring new name '%1' (%2)").arg(Host, gNetworkHostNames.join(',')));
141  }
142  else if (!gNetworkHostNames.contains(Host))
143  {
144  LOG(VB_GENERAL, LOG_INFO, QStringLiteral("New host name '%1'").arg(Host));
145  gNetworkHostNames.append(Host);
146  changed = true;
147  }
148  }
149 
150  if (changed && gLocalContext)
152 }
153 
159 void TorcNetwork::RemoveHostName(const QString &Host)
160 {
161  bool changed = false;
162 
163  {
164  QWriteLocker locker(gNetworkHostNamesLock);
165 
166  if (gNetworkHostNames.contains(Host))
167  {
168  LOG(VB_GENERAL, LOG_INFO, QStringLiteral("Removed host name '%1'").arg(Host));
169  gNetworkHostNames.removeAll(Host);
170  changed = true;
171  }
172  }
173 
174  if (changed && gLocalContext)
176 }
177 
183 QStringList TorcNetwork::GetHostNames(void)
184 {
185  QReadLocker locker(gNetworkHostNamesLock);
186  QStringList result = gNetworkHostNames;
187  result.removeDuplicates();
188  return result;
189 }
190 
196 QString TorcNetwork::IPAddressToLiteral(const QHostAddress &Address, int Port, bool UseLocalhost /* = true*/)
197 {
198  QString result;
199 
200  if (UseLocalhost && Address.isLoopback())
201  {
202  result = QStringLiteral("localhost");
203  }
204  else if (Address.protocol() == QAbstractSocket::IPv4Protocol)
205  {
206  result = Address.toString();
207  }
208  else
209  {
210  QHostAddress address(Address);
211  address.setScopeId(QStringLiteral(""));
212  result = "[" + address.toString() +"]";
213  }
214 
215  if (Port)
216  result += ":" + QString::number(Port);
217 
218  return result;
219 }
220 
222 bool TorcNetwork::IsExternal(const QHostAddress &Address)
223 {
224  if (Address.isNull() || Address.isLoopback())
225  return false;
226  return true;
227 }
228 
229 bool TorcNetwork::IsLinkLocal(const QHostAddress &Address)
230 {
231  if (Address.isNull())
232  return false;
233  if (Address.isInSubnet(Address.protocol() == QAbstractSocket::IPv4Protocol ? gIPv4LinkLocal : gIPv6LinkLocal))
234  return true;
235  return false;
236 }
237 
238 bool TorcNetwork::IsLocal(const QHostAddress &Address)
239 {
240  if (Address.isNull())
241  return false;
242 
243  if (Address.protocol() == QAbstractSocket::IPv4Protocol)
244  if (Address.isInSubnet(gIPv4PrivateA) || Address.isInSubnet(gIPv4PrivateB) || Address.isInSubnet(gIPv4PrivateC))
245  return true;
246 
247  // IPv6 - work in progress!
248  // use a whitelist approach
249  if (Address.isInSubnet(gIPv6UniqueLocal) || Address.isInSubnet(gIPv6SiteLocal))
250  return true;
251 
252  return false;
253 }
254 
255 /* \brief Returns true if the address is globally accessible (i.e. exposed to the real world!)
256  * \TODO make this ipv6 aware
257 */
258 bool TorcNetwork::IsGlobal(const QHostAddress &Address)
259 {
260  // internal/loopback and link local
261  if (!IsExternal(Address))
262  return false;
263 
264  // private
265  if (IsLocal(Address))
266  return false;
267 
268  return true;
269 }
270 
271 void TorcNetwork::Setup(bool Create)
272 {
273  QMutexLocker locker(gNetworkLock);
274 
275  if (gNetwork)
276  {
277  if (Create)
278  return;
279 
280  delete gNetwork;
281  gNetwork = nullptr;
282  return;
283  }
284 
285  if (Create)
286  {
287  gNetwork = new TorcNetwork();
288  return;
289  }
290 
291  delete gNetwork;
292  gNetwork = nullptr;
293 }
294 
295 QString ConfigurationTypeToString(QNetworkConfiguration::Type Type)
296 {
297  switch (Type)
298  {
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");
303  }
304 
305  return QStringLiteral();
306 }
307 
314  : QNetworkAccessManager(),
315  m_online(false),
316  m_manager(this),
317  m_configuration(),
318  m_hostNames(),
319  m_requests(),
320  m_reverseRequests(),
321  m_asynchronousRequests()
322 {
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 ")));
325 
326  connect(&m_manager, &QNetworkConfigurationManager::configurationAdded, this, &TorcNetwork::ConfigurationAdded);
327  connect(&m_manager, &QNetworkConfigurationManager::configurationChanged, this, &TorcNetwork::ConfigurationChanged);
328  connect(&m_manager, &QNetworkConfigurationManager::configurationRemoved, this, &TorcNetwork::ConfigurationRemoved);
329  connect(&m_manager, &QNetworkConfigurationManager::onlineStateChanged, this, &TorcNetwork::OnlineStateChanged);
330  connect(&m_manager, &QNetworkConfigurationManager::updateCompleted, this, &TorcNetwork::UpdateCompleted);
331 
332  connect(this, &TorcNetwork::NewRequest, this, &TorcNetwork::GetSafe);
333  connect(this, &TorcNetwork::CancelRequest, this, &TorcNetwork::CancelSafe);
334  connect(this, &TorcNetwork::PokeRequest, this, &TorcNetwork::PokeSafe);
335  connect(this, &TorcNetwork::NewAsyncRequest, this, &TorcNetwork::GetAsynchronousSafe);
336 
337  // direct connection for authentication requests
338  connect(this, &TorcNetwork::authenticationRequired, this, &TorcNetwork::Authenticate, Qt::DirectConnection);
339 
340  // set initial state
341  UpdateConfiguration(true);
342 }
343 
345 {
346  // release any outstanding requests
348 
349  LOG(VB_GENERAL, LOG_INFO, QStringLiteral("Closing network access manager"));
350 }
351 
353 {
354  return m_online;
355 }
356 
357 bool TorcNetwork::IsOwnAddressPriv(const QHostAddress &Address)
358 {
359  return QNetworkInterface::allAddresses().contains(Address);
360 }
361 
362 void TorcNetwork::GetSafe(TorcNetworkRequest* Request)
363 {
364  if (Request && m_online)
365  {
366  Request->UpRef();
367 
368  // some servers require a recognised user agent...
369  Request->m_request.setRawHeader("User-Agent", DEFAULT_USER_AGENT);
370 
371  QNetworkReply* reply = nullptr;
372 
373  if (Request->m_type == QNetworkAccessManager::GetOperation)
374  reply = get(Request->m_request);
375  else if (Request->m_type == QNetworkAccessManager::HeadOperation)
376  reply = head(Request->m_request);
377  else if (Request->m_type == QNetworkAccessManager::PostOperation)
378  reply = post(Request->m_request, Request->m_postData);
379 
380  if (!reply)
381  {
382  Request->DownRef();
383  LOG(VB_GENERAL, LOG_ERR, QStringLiteral("Unknown request type"));
384  return;
385  }
386 
387  // join the dots
388  connect(reply, &QNetworkReply::readyRead, this, &TorcNetwork::ReadyRead);
389  connect(reply, &QNetworkReply::finished, this, &TorcNetwork::Finished);
390  connect(reply, &QNetworkReply::downloadProgress, this, &TorcNetwork::DownloadProgress);
391  connect(reply, static_cast<void (QNetworkReply::*)(QNetworkReply::NetworkError)>(&QNetworkReply::error), this, &TorcNetwork::Error);
392  connect(reply, &QNetworkReply::sslErrors, this, &TorcNetwork::SSLErrors);
393 
394  m_requests.insert(reply, Request);
395  m_reverseRequests.insert(Request, reply);
396  }
397 }
398 
399 void TorcNetwork::CancelSafe(TorcNetworkRequest *Request)
400 {
401  if (m_reverseRequests.contains(Request))
402  {
403  QNetworkReply* reply = m_reverseRequests.take(Request);
404  Request->m_rawHeaders = reply->rawHeaderPairs();
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()));
408  else
409  LOG(VB_GENERAL, LOG_INFO, QStringLiteral("Cancelling '%1'").arg(reply->request().url().toString()));
410  reply->abort();
411  reply->deleteLater();
412  Request->DownRef();
413 
414  if (m_asynchronousRequests.contains(Request))
415  {
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"));
419  }
420  }
421  else
422  {
423  LOG(VB_GENERAL, LOG_ERR, QStringLiteral("Trying to cancel unknown network request"));
424  }
425 }
426 
427 void TorcNetwork::PokeSafe(TorcNetworkRequest *Request)
428 {
429  if (m_reverseRequests.contains(Request))
430  Request->Write(m_reverseRequests.value(Request));
431 }
432 
433 void TorcNetwork::GetAsynchronousSafe(TorcNetworkRequest *Request, QObject *Parent)
434 {
435  if (!Request || !Parent)
436  return;
437 
438  if (m_asynchronousRequests.contains(Request))
439  {
440  LOG(VB_GENERAL, LOG_ERR, QStringLiteral("Asynchronous request is already queued - ignoring"));
441  return;
442  }
443 
444  if (m_online)
445  {
446  m_asynchronousRequests.insert(Request, Parent);
447  GetSafe(Request);
448  }
449 }
450 
451 void TorcNetwork::ConfigurationAdded(const QNetworkConfiguration &Config)
452 {
453  (void)Config;
455 }
456 
457 void TorcNetwork::ConfigurationChanged(const QNetworkConfiguration &Config)
458 {
459  (void)Config;
461 }
462 
463 void TorcNetwork::ConfigurationRemoved(const QNetworkConfiguration &Config)
464 {
465  (void)Config;
467 }
468 
470 {
471  (void)Online;
473 }
474 
476 {
478 }
479 
480 bool TorcNetwork::CheckHeaders(TorcNetworkRequest *Request, QNetworkReply *Reply)
481 {
482  if (!Request || !Reply)
483  return false;
484 
485  QVariant status = Reply->attribute(QNetworkRequest::HttpStatusCodeAttribute);
486  if (!status.isValid())
487  return true;
488 
489  int httpstatus = status.toInt();
490  int contentlength = 0;
491 
492  // content length
493  QVariant length = Reply->header(QNetworkRequest::ContentLengthHeader);
494  if (length.isValid())
495  {
496  int size = length.toInt();
497  if (size > 0)
498  contentlength = size;
499  }
500 
501  // content type
502  QVariant contenttype = Reply->header(QNetworkRequest::ContentTypeHeader);
503 
504  if (Request->m_type == QNetworkAccessManager::HeadOperation)
505  {
506  // NB the following assumes the head request is checking for byte serving support
507 
508  // some servers (yes - I'm talking to you Dropbox) don't allow HEAD requests for
509  // some files (secure redirections?). Furthermore they don't return a valid Allow list
510  // in the response, or in response to an OPTIONS request. We could go around in circles
511  // trying to check support in a number of ways, but just cut to the chase and issue
512  // a test range request (as they do actually support range requests)
513  if (httpstatus == HTTP_MethodNotAllowed)
514  {
515  // delete the reply and try again as a GET request with range
516  m_reverseRequests.remove(Request);
517  m_requests.remove(Reply);
518  Request->m_request.setUrl(Reply->request().url());
519  Request->m_type = QNetworkAccessManager::GetOperation;
520  Request->SetRange(0, 10);
521  Reply->abort();
522  Reply->deleteLater();
523  GetSafe(Request);
524  Request->DownRef();
525  return false;
526  }
527  }
528 
529  Request->m_httpStatus = httpstatus;
530  Request->m_contentLength = contentlength;
531  Request->m_contentType = contenttype.isValid() ? contenttype.toString().toLower() : QStringLiteral();
532  Request->m_byteServingAvailable = Reply->rawHeader("Accept-Ranges").toLower().contains("bytes") && contentlength > 0;
533  return true;
534 }
535 
536 bool TorcNetwork::Redirected(TorcNetworkRequest *Request, QNetworkReply *Reply)
537 {
538  if (!Request || !Reply)
539  return false;
540 
541  QUrl newurl = Reply->attribute(QNetworkRequest::RedirectionTargetAttribute).toUrl();
542  QUrl oldurl = Request->m_request.url();
543 
544  if (!newurl.isEmpty() && newurl != oldurl)
545  {
546  // redirected
547  if (newurl.isRelative())
548  newurl = oldurl.resolved(newurl);
549 
550  LOG(VB_GENERAL, LOG_INFO, QStringLiteral("Redirected from '%1' to '%2'").arg(oldurl.toString(), newurl.toString()));
552  {
553  // delete the reply and create a new one
554  m_reverseRequests.remove(Request);
555  m_requests.remove(Reply);
556  Reply->abort();
557  Reply->deleteLater();
558  Request->m_request.setUrl(newurl);
559  GetSafe(Request);
560  Request->DownRef();
561  return true;
562  }
563  else
564  {
565  LOG(VB_GENERAL, LOG_WARNING, QStringLiteral("Max redirections exceeded"));
566  }
567  }
568 
569  return false;
570 }
571 
573 {
574  QNetworkReply *reply = dynamic_cast<QNetworkReply*>(sender());
575 
576  TorcNetworkRequest* request = nullptr;
577  if (reply && m_requests.contains(reply) && (request = m_requests.value(reply)))
578  {
579  if (!request->m_started)
580  {
581  // check for redirection
582  if (Redirected(request, reply))
583  return;
584 
585  // no need to check return value for GET requests
586  (void)CheckHeaders(request, reply);
587 
588  // we need to set the buffer size after the download has started as Qt will ignore
589  // the set value if it doesn't yet know the expected size. Not ideal...
590  if (request->m_bufferSize)
591  reply->setReadBufferSize(request->m_bufferSize);
592 
593  LOG(VB_GENERAL, LOG_INFO, QStringLiteral("Download started"));
594  request->m_started = true;
595  }
596 
597  request->Write(reply);
598  }
599 }
600 
602 {
603  QNetworkReply *reply = dynamic_cast<QNetworkReply*>(sender());
604 
605  TorcNetworkRequest *request = nullptr;
606  if (reply && m_requests.contains(reply) && (request = m_requests.value(reply)))
607  {
608  if (request->m_type == QNetworkAccessManager::HeadOperation)
609  {
610  // head requests never trigger a read request (no content), so check redirection on completion
611  if (Redirected(request, reply))
612  return;
613 
614  // a false return value indicates the request has been resent (perhaps in another form)
615  if (!CheckHeaders(request, reply))
616  return;
617  }
618  else if (request->m_type == QNetworkAccessManager::PostOperation)
619  {
620  // as for head, Post ops responses may have no content and hence ReadyRead is never triggered
621  // so check headers now (to set status etc)
622  (void)CheckHeaders(request, reply);
623  }
624 
625  request->m_replyFinished = true;
626 
627  // we need to manage async requests
628  if (m_asynchronousRequests.contains(request))
629  CancelSafe(request);
630  }
631 }
632 
633 void TorcNetwork::Error(QNetworkReply::NetworkError Code)
634 {
635  QNetworkReply *reply = dynamic_cast<QNetworkReply*>(sender());
636 
637  TorcNetworkRequest *request = nullptr;
638  if (reply && m_requests.contains(reply) && (request = m_requests.value(reply)) && (Code != QNetworkReply::OperationCanceledError))
639  {
640  request->SetReplyError(Code);
641  LOG(VB_GENERAL, LOG_ERR, QStringLiteral("Network error '%1'").arg(reply->errorString()));
642  }
643 }
644 
645 QList<QSslError> TorcNetwork::AllowableSslErrors(const QList<QSslError> &Errors)
646 {
647  bool selfsigned = false;
648  bool mismatched = false;
649  QSslError mismatch;
650 
651  QList<QSslError> allowed;
652  foreach (const QSslError &error, Errors)
653  {
654  if (error.error() == QSslError::SelfSignedCertificate)
655  {
656  LOG(VB_GENERAL, LOG_INFO, QStringLiteral("Allowing self signed certificate"));
657  allowed << error;
658  selfsigned = true;
659  }
660  else if (error.error() == QSslError::HostNameMismatch)
661  {
662  mismatched = true;
663  mismatch = error;
664  }
665  else
666  {
667  LOG(VB_GENERAL, LOG_INFO, QStringLiteral("Ssl Error: %1").arg(error.errorString()));
668  }
669  }
670 
671  if (mismatched)
672  {
673  if (selfsigned)
674  {
675  LOG(VB_GENERAL, LOG_INFO, QStringLiteral("Allowing host name mismatch for self signed certfificate"));
676  allowed << mismatch;
677  }
678  else
679  {
680  LOG(VB_GENERAL, LOG_INFO, QStringLiteral("Ssl Error: %1").arg(mismatch.errorString()));
681  }
682  }
683 
684  return allowed;
685 }
686 
687 void TorcNetwork::SSLErrors(const QList<QSslError> &Errors)
688 {
689  QNetworkReply *reply = dynamic_cast<QNetworkReply*>(sender());
690  if (reply)
691  {
692  QList<QSslError> allowed = TorcNetwork::AllowableSslErrors(Errors);
693  if (!allowed.isEmpty())
694  reply->ignoreSslErrors(TorcNetwork::AllowableSslErrors(Errors));
695  }
696 }
697 
698 void TorcNetwork::DownloadProgress(qint64 Received, qint64 Total)
699 {
700  QNetworkReply *reply = dynamic_cast<QNetworkReply*>(sender());
701 
702  TorcNetworkRequest *request = nullptr;
703  if (reply && m_requests.contains(reply) && (request = m_requests.value(reply)))
704  request->DownloadProgress(Received, Total);
705 }
706 
707 void TorcNetwork::Authenticate(QNetworkReply *Reply, QAuthenticator *Authenticator)
708 {
709  (void)Reply;
710  (void)Authenticator;
711  LOG(VB_GENERAL, LOG_INFO, QStringLiteral("Authentication required"));
712 }
713 
715 void TorcNetwork::NewHostName(const QHostInfo &Info)
716 {
717  if (!Info.hostName().isEmpty())
718  {
719  m_hostNames.append(Info.hostName());
720  AddHostName(Info.hostName());
721  }
722 }
723 
736 {
737  if (!m_requests.isEmpty())
738  LOG(VB_GENERAL, LOG_WARNING, QStringLiteral("%1 outstanding network requests").arg(m_requests.size()));
739 
740  while (!m_requests.isEmpty())
741  CancelSafe(*m_requests.begin());
742 
743  m_requests.clear();
744  m_reverseRequests.clear();
745  m_asynchronousRequests.clear();
746 }
747 
749 {
750  QNetworkConfiguration configuration = m_manager.defaultConfiguration();
751  bool wasonline = m_online;
752  bool changed = false;
753 
754  if (configuration != m_configuration || Creating)
755  {
756  changed = true;
757  m_configuration = configuration;
758 
759  if (m_configuration.isValid())
760  {
761  LOG(VB_GENERAL, LOG_INFO, QStringLiteral("Network interface: %1 Bearer: %2").arg(configuration.name(), configuration.bearerTypeName()));
762  m_online = true;
763  }
764  else
765  {
766  LOG(VB_GENERAL, LOG_INFO, QStringLiteral("No valid network connection"));
767  m_online = false;
768  }
769  }
770 
771  if (m_online && !wasonline)
772  {
774 
775  QStringList addresses;
776  QList<QHostAddress> entries = QNetworkInterface::allAddresses();
777  foreach (const QHostAddress &entry, entries)
778  {
779  QString address = entry.toString();
780  addresses << address;
781  QHostInfo::lookupHost(address, this, SLOT(NewHostName(QHostInfo)));
782  }
783 
784  LOG(VB_GENERAL, LOG_INFO, QStringLiteral("Network up (%1)").arg(addresses.join(QStringLiteral(", "))));
785  }
786  else if (wasonline && !m_online)
787  {
788  LOG(VB_GENERAL, LOG_INFO, QStringLiteral("Network down"));
791 
792  foreach (QString host, m_hostNames)
793  RemoveHostName(host);
794  m_hostNames = QStringList();
795  }
796  else if (changed)
797  {
798  LOG(VB_GENERAL, LOG_INFO, QStringLiteral("Network configuration changed"));
800  }
801 }
802 
807 {
808  public:
811  {
812  qRegisterMetaType<TorcNetworkRequest*>();
813  qRegisterMetaType<QNetworkReply*>();
814  }
815 
816  void Create(void)
817  {
818  // always create the network object to at least monitor network state.
819  // if access is disallowed, it will be made inaccessible.
820  TorcNetwork::Setup(true);
821  }
822 
823  void Destroy(void)
824  {
825  TorcNetwork::Setup(false);
826  }
828 
829 
#define DEFAULT_USER_AGENT
Definition: torcnetwork.h:18
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)
TorcNetwork * gNetwork
Definition: torcnetwork.cpp:31
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.
Definition: torcnetwork.cpp:94
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)
Definition: torcnetwork.cpp:46
virtual bool DownRef(void)
bool IsOwnAddressPriv(const QHostAddress &Address)
QPair< QHostAddress, int > gIPv4PrivateA
Definition: torcnetwork.cpp:37
const QByteArray m_postData
static void NotifyEvent(int Event)
QPair< QHostAddress, int > gIPv6Global
Definition: torcnetwork.cpp:44
bool IsOnline(void)
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
Definition: torcnetwork.cpp:41
void Destroy(void)
void PokeRequest(TorcNetworkRequest *Request)
bool Redirected(TorcNetworkRequest *Request, QNetworkReply *Reply)
QStringList gNetworkHostNames
Definition: torcnetwork.cpp:33
static bool IsLinkLocal(const QHostAddress &Address)
QPair< QHostAddress, int > gIPv6UniqueLocal
Definition: torcnetwork.cpp:43
void Authenticate(QNetworkReply *Reply, QAuthenticator *Authenticator)
#define DEFAULT_MAX_REDIRECTIONS
Definition: torcnetwork.h:17
void DownloadProgress(qint64 Received, qint64 Total)
void ReadyRead(void)
virtual ~TorcNetwork()
QList< QNetworkReply::RawHeaderPair > m_rawHeaders
QPair< QHostAddress, int > gIPv4PrivateB
Definition: torcnetwork.cpp:38
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
Definition: torcnetwork.h:24
void NewRequest(TorcNetworkRequest *Request)
void SSLErrors(const QList< QSslError > &Errors)
bool CheckHeaders(TorcNetworkRequest *Request, QNetworkReply *Reply)
static void Poke(TorcNetworkRequest *Request)
Definition: torcnetwork.cpp:80
QReadWriteLock * gNetworkHostNamesLock
Definition: torcnetwork.cpp:34
#define LOG(_MASK_, _LEVEL_, _STRING_)
Definition: torclogging.h:20
void Error(QNetworkReply::NetworkError Code)
Subclass of QNetworkAccessManager for sending network requests and monitoring the network state...
Definition: torcnetwork.h:22
QPair< QHostAddress, int > gIPv4PrivateC
Definition: torcnetwork.cpp:39
static void Cancel(TorcNetworkRequest *Request)
Definition: torcnetwork.cpp:73
void Finished(void)
static bool Get(TorcNetworkRequest *Request)
Definition: torcnetwork.cpp:60
static bool IsOwnAddress(const QHostAddress &Address)
Definition: torcnetwork.cpp:53
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
Definition: torcnetwork.cpp:36
QPair< QHostAddress, int > gIPv6SiteLocal
Definition: torcnetwork.cpp:42
QMutex * gNetworkLock
Definition: torcnetwork.cpp:32
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)