MythTV  master
serverpool.cpp
Go to the documentation of this file.
1 #include <QNetworkAddressEntry>
2 #include <QReadWriteLock>
3 #include <QWriteLocker>
4 #include <QReadLocker>
5 #include <QTcpSocket>
6 
7 #include "mythcorecontext.h"
8 #include "mythlogging.h"
9 #include "serverpool.h"
10 
11 static inline
12 QString prettyip(const QHostAddress& x)
13 {
14  if (x.protocol() == QAbstractSocket::IPv6Protocol)
15  return "[" + x.toString().toLower() + "]";
16  return x.toString().toLower();
17 }
18 
19 
20 #define LOC QString("ServerPool: ")
21 
22 // Lists of IP address this machine is listening to.
23 static QList<QNetworkAddressEntry> naList_4;
24 static QList<QNetworkAddressEntry> naList_6;
25 static QReadWriteLock naLock;
26 
27 static QPair<QHostAddress, int> kLinkLocal =
28  QHostAddress::parseSubnet("169.254.0.0/16");
29 static QPair<QHostAddress, int> kLinkLocal6 =
30  QHostAddress::parseSubnet("fe80::/10");
31 
32 class PrivUdpSocket : public QUdpSocket
33 {
34 public:
35  PrivUdpSocket(QObject *parent, const QNetworkAddressEntry& host) :
36  QUdpSocket(parent), m_host(host) { };
37  ~PrivUdpSocket() override = default;
38  QNetworkAddressEntry host()
39  {
40  return m_host;
41  };
42  bool contains(const QHostAddress& addr)
43  {
44  return contains(m_host, addr);
45  };
46  static bool contains(const QNetworkAddressEntry& host, const QHostAddress& addr)
47  {
48  if (addr.protocol() == QAbstractSocket::IPv6Protocol &&
49  addr.isInSubnet(kLinkLocal6) &&
50  host.ip().scopeId() != addr.scopeId())
51  {
52  return false;
53  }
54  return addr.isInSubnet(host.ip(), host.prefixLength());
55  }
56 private:
57  QNetworkAddressEntry m_host;
58 };
59 
61  : QTcpServer(parent), m_serverType(type)
62 {
63 }
64 
66 {
67  emit newConnection(socket);
68 }
69 
71 {
72  close();
73 }
74 
76 {
77  if (!force)
78  {
79  QReadLocker rlock(&naLock);
80  if (!naList_4.isEmpty() || !naList_6.isEmpty())
81  // lists are already populated, do nothing
82  return;
83  }
84 
85  QWriteLocker wlock(&naLock);
86  naList_4.clear();
87  naList_6.clear();
88 
89  if (gCoreContext->GetBoolSetting("ListenOnAllIps",true))
90  {
91  QNetworkAddressEntry entry;
92  entry.setIp(QHostAddress(QHostAddress::AnyIPv4));
93  naList_4.append(entry);
94  entry.setIp(QHostAddress(QHostAddress::AnyIPv6));
95  naList_6.append(entry);
96  return;
97  }
98 
99  // populate stored IPv4 and IPv6 addresses
100  QHostAddress config_v4(gCoreContext->resolveSettingAddress(
101  "BackendServerIP",
102  QString(),
104  bool v4IsSet = config_v4.isNull();
105  QHostAddress config_v6(gCoreContext->resolveSettingAddress(
106  "BackendServerIP6",
107  QString(),
109  bool v6IsSet = config_v6.isNull();
110  bool allowLinkLocal = gCoreContext->GetBoolSetting("AllowLinkLocal", true);
111 
112  // loop through all available interfaces
113  QList<QNetworkInterface> IFs = QNetworkInterface::allInterfaces();
114  for (const auto & qni : std::as_const(IFs))
115  {
116  if ((qni.flags() & QNetworkInterface::IsRunning) == 0)
117  continue;
118 
119  QList<QNetworkAddressEntry> IPs = qni.addressEntries();
120  // C+11 range-for should only be used on const Qt lists, and
121  // this next loop modifies the list items.
122  // NOLINTNEXTLINE(modernize-loop-convert)
123  for (auto qnai = IPs.begin(); qnai != IPs.end(); ++qnai)
124  {
125  QHostAddress ip = qnai->ip();
126  if (ip.protocol() == QAbstractSocket::IPv4Protocol)
127  {
128  if (naList_4.contains(*qnai))
129  // already defined, skip
130  continue;
131 
132  if (!config_v4.isNull() && (ip == config_v4))
133  {
134  // IPv4 address is defined, add it
135  LOG(VB_GENERAL, LOG_DEBUG,
136  QString("Adding BackendServerIP to address list."));
137  naList_4.append(*qnai);
138  v4IsSet = true;
139 
140  }
141 
142  else if (ip == QHostAddress::LocalHost)
143  {
144  // always listen on LocalHost
145  LOG(VB_GENERAL, LOG_DEBUG,
146  QString("Adding IPv4 loopback to address list."));
147  naList_4.append(*qnai);
148  if (!v4IsSet && (config_v4 == ip))
149  v4IsSet = true;
150  }
151 
152  else if (ip.isInSubnet(kLinkLocal) && allowLinkLocal)
153  {
154  // optionally listen on linklocal
155  // the next clause will enable it anyway if no IP address
156  // has been set
157  LOG(VB_GENERAL, LOG_DEBUG,
158  QString("Adding link-local '%1' to address list.")
159  .arg(prettyip(ip)));
160  naList_4.append(*qnai);
161  }
162 
163  else if (config_v4.isNull())
164  {
165  // IPv4 address is not defined, populate one
166  // restrict autoconfiguration to RFC1918 private networks
167  static QPair<QHostAddress, int>
168  s_privNet1 = QHostAddress::parseSubnet("10.0.0.0/8");
169  static QPair<QHostAddress, int>
170  s_privNet2 = QHostAddress::parseSubnet("172.16.0.0/12");
171  static QPair<QHostAddress, int>
172  s_privNet3 = QHostAddress::parseSubnet("192.168.0.0/16");
173 
174  if (ip.isInSubnet(s_privNet1) || ip.isInSubnet(s_privNet2) ||
175  ip.isInSubnet(s_privNet3))
176  {
177  LOG(VB_GENERAL, LOG_DEBUG,
178  QString("Adding '%1' to address list.")
179  .arg(prettyip(ip)));
180  naList_4.append(*qnai);
181  }
182  else if (ip.isInSubnet(kLinkLocal))
183  {
184  LOG(VB_GENERAL, LOG_DEBUG,
185  QString("Adding link-local '%1' to address list.")
186  .arg(prettyip(ip)));
187  naList_4.append(*qnai);
188  }
189  else
190  {
191  LOG(VB_GENERAL, LOG_DEBUG, QString("Skipping "
192  "non-private address during IPv4 autoselection: %1")
193  .arg(prettyip(ip)));
194  }
195  }
196 
197  else
198  LOG(VB_GENERAL, LOG_DEBUG, QString("Skipping address: %1")
199  .arg(prettyip(ip)));
200 
201  }
202  else
203  {
204  if (ip.isInSubnet(kLinkLocal6))
205  {
206  // set scope id for link local address
207  ip.setScopeId(qni.name());
208  qnai->setIp(ip);
209  }
210 
211  if (naList_6.contains(*qnai))
212  // already defined, skip
213  continue;
214 
215  if ((!config_v6.isNull()) && (ip == config_v6))
216  {
217  // IPv6 address is defined, add it
218  LOG(VB_GENERAL, LOG_DEBUG,
219  QString("Adding BackendServerIP6 to address list."));
220  naList_6.append(*qnai);
221  v6IsSet = true;
222  }
223 
224  else if (ip == QHostAddress::LocalHostIPv6)
225  {
226  // always listen on LocalHost
227  LOG(VB_GENERAL, LOG_DEBUG,
228  QString("Adding IPv6 loopback to address list."));
229  naList_6.append(*qnai);
230  if (!v6IsSet && (config_v6 == ip))
231  v6IsSet = true;
232  }
233 
234  else if (ip.isInSubnet(kLinkLocal6) && allowLinkLocal)
235  {
236  // optionally listen on linklocal
237  // the next clause will enable it anyway if no IP address
238  // has been set
239  LOG(VB_GENERAL, LOG_DEBUG,
240  QString("Adding link-local '%1' to address list.")
241  .arg(ip.toString()));
242  naList_6.append(*qnai);
243  }
244 
245  else if (config_v6.isNull())
246  {
247  if (ip.isInSubnet(kLinkLocal6))
248  {
249  LOG(VB_GENERAL, LOG_DEBUG,
250  QString("Adding link-local '%1' to address list.")
251  .arg(prettyip(ip)));
252  }
253  else
254  {
255  LOG(VB_GENERAL, LOG_DEBUG,
256  QString("Adding '%1' to address list.")
257  .arg(prettyip(ip)));
258  }
259 
260  naList_6.append(*qnai);
261  }
262 
263  else
264  LOG(VB_GENERAL, LOG_DEBUG, QString("Skipping address: %1")
265  .arg(prettyip(ip)));
266  }
267  }
268  }
269 
270  if (!v4IsSet && (config_v4 != QHostAddress::LocalHost)
271  && !naList_4.isEmpty())
272  {
273  LOG(VB_GENERAL, LOG_CRIT, LOC + QString("Host is configured to listen "
274  "on %1, but address is not used on any local network "
275  "interfaces.").arg(config_v4.toString()));
276  }
277 
278  if (!v6IsSet && (config_v6 != QHostAddress::LocalHostIPv6)
279  && !naList_6.isEmpty())
280  {
281  LOG(VB_GENERAL, LOG_CRIT, LOC + QString("Host is configured to listen "
282  "on %1, but address is not used on any local network "
283  "interfaces.").arg(prettyip(config_v6)));
284  }
285 
286  // NOTE: there is no warning for the case where both defined addresses
287  // are localhost, and neither are found. however this would also
288  // mean there is no configured network at all, and should be
289  // sufficiently rare a case as to not worry about it.
290 }
291 
293 {
294  SelectDefaultListen(true);
295  // TODO:
296  // send signal for any running servers to cycle their addresses
297  // will allow address configuration to be modified without a server
298  // reset for use with the migration to the mythtv-setup replacement
299 }
300 
301 QList<QHostAddress> ServerPool::DefaultListen(void)
302 {
303  QList<QHostAddress> alist;
304  alist << DefaultListenIPv4()
305  << DefaultListenIPv6();
306  return alist;
307 }
308 
309 QList<QHostAddress> ServerPool::DefaultListenIPv4(void)
310 {
312  QReadLocker rlock(&naLock);
313 
314  QList<QHostAddress> alist;
315  for (const auto & nae : std::as_const(naList_4))
316  if (!alist.contains(nae.ip()))
317  alist << nae.ip();
318 
319  return alist;
320 }
321 
322 QList<QHostAddress> ServerPool::DefaultListenIPv6(void)
323 {
325  QReadLocker rlock(&naLock);
326 
327  QList<QHostAddress> alist;
328  for (const auto & nae : std::as_const(naList_6))
329  if (!alist.contains(nae.ip()))
330  alist << nae.ip();
331 
332  return alist;
333 }
334 
335 QList<QHostAddress> ServerPool::DefaultBroadcast(void)
336 {
337  QList<QHostAddress> blist;
338  if (!gCoreContext->GetBoolSetting("ListenOnAllIps",true))
339  {
340  blist << DefaultBroadcastIPv4();
341  blist << DefaultBroadcastIPv6();
342  }
343  return blist;
344 }
345 
346 QList<QHostAddress> ServerPool::DefaultBroadcastIPv4(void)
347 {
349  QReadLocker rlock(&naLock);
350 
351  QList<QHostAddress> blist;
352  for (const auto & nae : std::as_const(naList_4))
353  {
354  if (!blist.contains(nae.broadcast()) && (nae.prefixLength() != 32) &&
355  (nae.ip() != QHostAddress::LocalHost))
356  blist << nae.broadcast();
357  }
358 
359  return blist;
360 }
361 
362 QList<QHostAddress> ServerPool::DefaultBroadcastIPv6(void)
363 {
364  QList<QHostAddress> blist;
365  blist << QHostAddress("FF02::1");
366  return blist;
367 }
368 
369 
371 {
372  while (!m_tcpServers.isEmpty())
373  {
374  PrivTcpServer *server = m_tcpServers.takeLast();
375  server->disconnect();
376  server->close();
377  server->deleteLater();
378  }
379 
380  while (!m_udpSockets.isEmpty())
381  {
382  PrivUdpSocket *socket = m_udpSockets.takeLast();
383  socket->disconnect();
384  socket->close();
385  socket->deleteLater();
386  }
387  m_lastUdpSocket = nullptr;
388  m_listening = false;
389 }
390 
391 bool ServerPool::listen(QList<QHostAddress> addrs, quint16 port,
392  bool requireall, PoolServerType servertype)
393 {
394  m_port = port;
395  for (const auto & qha : std::as_const(addrs))
396  {
397  // If IPV4 support is disabled and this is an IPV4 address,
398  // bypass this address
399  if (qha.protocol() == QAbstractSocket::IPv4Protocol
400  && ! gCoreContext->GetBoolSetting("IPv4Support",true))
401  continue;
402  // If IPV6 support is disabled and this is an IPV6 address,
403  // bypass this address
404  if (qha.protocol() == QAbstractSocket::IPv6Protocol
405  && ! gCoreContext->GetBoolSetting("IPv6Support",true))
406  continue;
407 
408  auto *server = new PrivTcpServer(this, servertype);
409  connect(server, &PrivTcpServer::newConnection,
411 
412  server->setProxy(m_proxy);
413  server->setMaxPendingConnections(m_maxPendingConn);
414 
415  if (server->listen(qha, m_port))
416  {
417  LOG(VB_GENERAL, LOG_INFO, QString("Listening on TCP%1 %2:%3")
418  .arg(servertype == kSSLServer ? " (SSL)" : "",
419  prettyip(qha), QString::number(port)));
420  if ((servertype == kTCPServer) || (servertype == kSSLServer))
421  m_tcpServers.append(server);
422  if (m_port == 0)
423  m_port = server->serverPort();
424  }
425  else
426  {
427  LOG(VB_GENERAL, LOG_ERR,
428  QString("Failed listening on TCP %1:%2 - Error %3: %4")
429  .arg(prettyip(qha))
430  .arg(port)
431  .arg(server->serverError())
432  .arg(server->errorString()));
433  server->disconnect();
434  server->deleteLater();
435 
436  if (server->serverError() == QAbstractSocket::HostNotFoundError ||
437  server->serverError() == QAbstractSocket::SocketAddressNotAvailableError)
438  {
439  LOG(VB_GENERAL, LOG_ERR,
440  QString("Address %1 no longer exists - ignoring")
441  .arg(prettyip(qha)));
442  continue;
443  }
444 
445  if (server->serverError() == QAbstractSocket::UnsupportedSocketOperationError
446  && qha.protocol() == QAbstractSocket::IPv4Protocol)
447  {
448  LOG(VB_GENERAL, LOG_INFO,
449  QString("IPv4 support failed for this port."));
450  continue;
451  }
452 
453  if (server->serverError() == QAbstractSocket::UnsupportedSocketOperationError
454  && qha.protocol() == QAbstractSocket::IPv6Protocol)
455  {
456  LOG(VB_GENERAL, LOG_INFO,
457  QString("IPv6 support failed for this port."));
458  continue;
459  }
460 
461  if (requireall)
462  {
463  close();
464  return false;
465  }
466  }
467  }
468 
469  if (m_tcpServers.empty())
470  return false;
471 
472  m_listening = true;
473  return true;
474 }
475 
476 bool ServerPool::listen(QStringList addrstr, quint16 port, bool requireall,
477  PoolServerType servertype)
478 {
479  QList<QHostAddress> addrs;
480  for (const auto & str : std::as_const(addrstr))
481  addrs << QHostAddress(str);
482  return listen(addrs, port, requireall, servertype);
483 }
484 
485 bool ServerPool::listen(quint16 port, bool requireall,
486  PoolServerType servertype)
487 {
488  return listen(DefaultListen(), port, requireall, servertype);
489 }
490 
491 bool ServerPool::bind(QList<QHostAddress> addrs, quint16 port,
492  bool requireall)
493 {
494  m_port = port;
495  for (const auto & qha : std::as_const(addrs))
496  {
497  // If IPV4 support is disabled and this is an IPV4 address,
498  // bypass this address
499  if (qha.protocol() == QAbstractSocket::IPv4Protocol
500  && ! gCoreContext->GetBoolSetting("IPv4Support",true))
501  continue;
502  // If IPV6 support is disabled and this is an IPV6 address,
503  // bypass this address
504  if (qha.protocol() == QAbstractSocket::IPv6Protocol
505  && ! gCoreContext->GetBoolSetting("IPv6Support",true))
506  continue;
507 
508  QNetworkAddressEntry host;
509  QNetworkAddressEntry wildcard;
510 
511  if (qha.protocol() == QAbstractSocket::IPv6Protocol)
512  {
513  for (const auto& iae : std::as_const(naList_6))
514  {
515  if (PrivUdpSocket::contains(iae, qha))
516  {
517  host = iae;
518  break;
519  }
520  if (iae.ip() == QHostAddress::AnyIPv6)
521  wildcard = iae;
522  }
523  }
524  else
525  {
526  for (const auto& iae : std::as_const(naList_4))
527  {
528  if (PrivUdpSocket::contains(iae, qha))
529  {
530  host = iae;
531  break;
532  }
533  if (iae.ip() == QHostAddress::AnyIPv4)
534  wildcard = iae;
535  }
536  }
537 
538  if (host.ip().isNull())
539  {
540  if (wildcard.ip().isNull())
541  {
542  LOG(VB_GENERAL, LOG_ERR,
543  QString("Failed to find local address to use for destination %1:%2.")
544  .arg(prettyip(qha)).arg(port));
545  continue;
546  }
547 
548  LOG(VB_GENERAL, LOG_DEBUG,
549  QString("Failed to find local address to use for destination %1:%2. Using wildcard.")
550  .arg(prettyip(qha)).arg(port));
551  host = wildcard;
552  }
553 
554  auto *socket = new PrivUdpSocket(this, host);
555 
556  if (socket->bind(qha, port))
557  {
558  LOG(VB_GENERAL, LOG_INFO, QString("Binding to UDP %1:%2")
559  .arg(prettyip(qha)).arg(port));
560  m_udpSockets.append(socket);
561  connect(socket, &QIODevice::readyRead,
563  }
564  else
565  {
566  LOG(VB_GENERAL, LOG_ERR,
567  QString("Failed binding to UDP %1:%2 - Error %3: %4")
568  .arg(prettyip(qha))
569  .arg(port)
570  .arg(socket->error())
571  .arg(socket->errorString()));
572  socket->disconnect();
573  socket->deleteLater();
574 
575  if (socket->error() == QAbstractSocket::SocketAddressNotAvailableError)
576  {
577  LOG(VB_GENERAL, LOG_ERR,
578  QString("Address %1 no longer exists - ignoring")
579  .arg(prettyip(qha)));
580  continue;
581  }
582 
583  if (requireall)
584  {
585  close();
586  return false;
587  }
588  }
589  }
590 
591  if (m_udpSockets.empty())
592  return false;
593 
594  m_listening = true;
595  return true;
596 }
597 
598 bool ServerPool::bind(QStringList addrstr, quint16 port, bool requireall)
599 {
600  QList<QHostAddress> addrs;
601  for (const auto & str : std::as_const(addrstr))
602  addrs << QHostAddress(str);
603  return bind(addrs, port, requireall);
604 }
605 
606 bool ServerPool::bind(quint16 port, bool requireall)
607 {
608  return bind(DefaultListen(), port, requireall);
609 }
610 
611 qint64 ServerPool::writeDatagram(const char * data, qint64 size,
612  const QHostAddress &addr, quint16 port)
613 {
614  if (!m_listening || m_udpSockets.empty())
615  {
616  LOG(VB_GENERAL, LOG_ERR, "Trying to write datagram to disconnected "
617  "ServerPool instance.");
618  return -1;
619  }
620 
621  // check if can re-use the last one, so there's no need for a linear search
622  if (!m_lastUdpSocket || !m_lastUdpSocket->contains(addr))
623  {
624  // find the right socket to use
625  QList<PrivUdpSocket*>::iterator it;
626  for (it = m_udpSockets.begin(); it != m_udpSockets.end(); ++it)
627  {
628  PrivUdpSocket *val = *it;
629  if (val->contains(addr))
630  {
631  m_lastUdpSocket = val;
632  break;
633  }
634  }
635  }
636  if (!m_lastUdpSocket)
637  {
638  // Couldn't find an exact socket. See is there is a wildcard one.
639  LOG(VB_GENERAL, LOG_DEBUG,
640  QString("No exact socket match for %1:%2. Searching for wildcard.")
641  .arg(prettyip(addr)).arg(port));
642  for (auto *val : std::as_const(m_udpSockets))
643  {
644  if ((addr.protocol() == QAbstractSocket::IPv6Protocol &&
645  val->host().ip() == QHostAddress::AnyIPv6) ||
646  (val->host().ip() == QHostAddress::AnyIPv4))
647  {
648  m_lastUdpSocket = val;
649  break;
650  }
651  }
652  }
653  if (!m_lastUdpSocket)
654  {
655  LOG(VB_GENERAL, LOG_DEBUG, QString("No m_lastUdpSocket"));
656  return -1;
657  }
658 
659  qint64 ret = m_lastUdpSocket->writeDatagram(data, size, addr, port);
660  if (ret != size)
661  {
662  LOG(VB_GENERAL, LOG_DEBUG, QString("Error = %1 : %2")
663  .arg(ret).arg(m_lastUdpSocket->error()));
664  }
665  return ret;
666 }
667 
668 qint64 ServerPool::writeDatagram(const QByteArray &datagram,
669  const QHostAddress &addr, quint16 port)
670 {
671  return writeDatagram(datagram.data(), datagram.size(), addr, port);
672 }
673 
674 void ServerPool::newTcpConnection(qintptr socket)
675 {
676  // Ignore connections from an SSL server for now, these are only handled
677  // by HttpServer which overrides newTcpConnection
678  auto *server = qobject_cast<PrivTcpServer *>(QObject::sender());
679  if (!server || server->GetServerType() == kSSLServer)
680  return;
681 
682  auto *qsock = new QTcpSocket(this);
683  if (qsock->setSocketDescriptor(socket)
684  && gCoreContext->CheckSubnet(qsock))
685  {
686  emit newConnection(qsock);
687  }
688  else
689  delete qsock;
690 }
691 
693 {
694  auto *socket = qobject_cast<QUdpSocket*>(sender());
695 
696  while (socket->state() == QAbstractSocket::BoundState &&
697  socket->hasPendingDatagrams())
698  {
699  QByteArray buffer;
700  buffer.resize(socket->pendingDatagramSize());
701  QHostAddress sender;
702  quint16 senderPort = 0;
703 
704  socket->readDatagram(buffer.data(), buffer.size(),
705  &sender, &senderPort);
706  if (gCoreContext->CheckSubnet(sender))
707  emit newDatagram(buffer, sender, senderPort);
708  }
709 }
710 
724 int ServerPool::tryListeningPort(int baseport, int range)
725 {
726  // try a few ports in case the first is in use
727  int port = baseport;
728  while (port < baseport + range)
729  {
730  if (listen(port))
731  {
732  break;
733  }
734  port++;
735  }
736 
737  if (port >= baseport + range)
738  {
739  return -1;
740  }
741  return port;
742 }
743 
757 int ServerPool::tryBindingPort(int baseport, int range)
758 {
759  // try a few ports in case the first is in use
760  int port = baseport;
761  while (port < baseport + range)
762  {
763  if (bind(port))
764  {
765  break;
766  }
767  port++;
768  }
769 
770  if (port >= baseport + range)
771  {
772  return -1;
773  }
774  return port;
775 }
776 
793 int ServerPool::tryListeningPort(QTcpServer *server, int baseport,
794  int range, bool *isipv6)
795 {
796  bool ipv6 = true;
797  // try a few ports in case the first is in use
798  int port = baseport;
799  while (port < baseport + range)
800  {
801  if (ipv6)
802  {
803  if (server->listen(QHostAddress::AnyIPv6, port))
804  {
805  break;
806  }
807 
808  // did we fail because IPv6 isn't available?
809  QAbstractSocket::SocketError err = server->serverError();
810  if (err == QAbstractSocket::UnsupportedSocketOperationError)
811  {
812  ipv6 = false;
813  }
814  }
815  if (!ipv6)
816  {
817  if (server->listen(QHostAddress::Any, port))
818  {
819  break;
820  }
821  }
822  port++;
823  }
824 
825  if (isipv6)
826  {
827  *isipv6 = ipv6;
828  }
829 
830  if (port >= baseport + range)
831  {
832  return -1;
833  }
834  if (port == 0)
835  {
836  port = server->serverPort();
837  }
838  return port;
839 }
840 
857 int ServerPool::tryBindingPort(QUdpSocket *socket, int baseport,
858  int range, bool *isipv6)
859 {
860  bool ipv6 = true;
861  // try a few ports in case the first is in use
862  int port = baseport;
863  while (port < baseport + range)
864  {
865  if (ipv6)
866  {
867  if (socket->bind(QHostAddress::AnyIPv6, port))
868  {
869  break;
870  }
871 
872  // did we fail because IPv6 isn't available?
873  QAbstractSocket::SocketError err = socket->error();
874  if (err == QAbstractSocket::UnsupportedSocketOperationError)
875  {
876  ipv6 = false;
877  }
878  }
879  if (!ipv6)
880  {
881  if (socket->bind(QHostAddress::Any, port))
882  {
883  break;
884  }
885  }
886  port++;
887  }
888 
889  if (isipv6)
890  {
891  *isipv6 = ipv6;
892  }
893 
894  if (port >= baseport + range)
895  {
896  return -1;
897  }
898  return port;
899 }
naList_4
static QList< QNetworkAddressEntry > naList_4
Definition: serverpool.cpp:23
MythCoreContext::resolveSettingAddress
QString resolveSettingAddress(const QString &name, const QString &host=QString(), ResolveType type=ResolveAny, bool keepscope=false)
Retrieve IP setting "name" for "host".
Definition: mythcorecontext.cpp:1163
PrivUdpSocket::contains
bool contains(const QHostAddress &addr)
Definition: serverpool.cpp:42
kSSLServer
@ kSSLServer
Definition: serverpool.h:33
ServerPool::~ServerPool
~ServerPool(void) override
Definition: serverpool.cpp:70
kLinkLocal6
static QPair< QHostAddress, int > kLinkLocal6
Definition: serverpool.cpp:29
ServerPool::newDatagram
void newDatagram(QByteArray, QHostAddress, quint16)
ServerPool::close
void close(void)
Definition: serverpool.cpp:370
naList_6
static QList< QNetworkAddressEntry > naList_6
Definition: serverpool.cpp:24
PrivUdpSocket::PrivUdpSocket
PrivUdpSocket(QObject *parent, const QNetworkAddressEntry &host)
Definition: serverpool.cpp:35
ServerPool::m_lastUdpSocket
PrivUdpSocket * m_lastUdpSocket
Definition: serverpool.h:128
PrivUdpSocket
Definition: serverpool.cpp:32
ServerPool::tryBindingPort
int tryBindingPort(int baseport, int range=1)
tryBindingPort
Definition: serverpool.cpp:757
PrivTcpServer::PrivTcpServer
PrivTcpServer(QObject *parent=nullptr, PoolServerType type=kTCPServer)
Definition: serverpool.cpp:60
ServerPool::DefaultListenIPv4
static QList< QHostAddress > DefaultListenIPv4(void)
Definition: serverpool.cpp:309
ServerPool::tryListeningPort
int tryListeningPort(int baseport, int range=1)
tryListeningPort
Definition: serverpool.cpp:724
ServerPool::m_udpSockets
QList< PrivUdpSocket * > m_udpSockets
Definition: serverpool.h:127
ServerPool::DefaultBroadcastIPv6
static QList< QHostAddress > DefaultBroadcastIPv6(void)
Definition: serverpool.cpp:362
LOG
#define LOG(_MASK_, _LEVEL_, _QSTRING_)
Definition: mythlogging.h:39
force
bool force
Definition: mythcommflag.cpp:70
ServerPool::DefaultBroadcastIPv4
static QList< QHostAddress > DefaultBroadcastIPv4(void)
Definition: serverpool.cpp:346
ServerPool::newConnection
void newConnection(QTcpSocket *)
PrivUdpSocket::~PrivUdpSocket
~PrivUdpSocket() override=default
prettyip
static QString prettyip(const QHostAddress &x)
Definition: serverpool.cpp:12
ServerPool::writeDatagram
qint64 writeDatagram(const char *data, qint64 size, const QHostAddress &addr, quint16 port)
Definition: serverpool.cpp:611
ServerPool::m_proxy
QNetworkProxy m_proxy
Definition: serverpool.h:124
mythlogging.h
ServerPool::newUdpDatagram
virtual void newUdpDatagram(void)
Definition: serverpool.cpp:692
PrivUdpSocket::contains
static bool contains(const QNetworkAddressEntry &host, const QHostAddress &addr)
Definition: serverpool.cpp:46
PrivTcpServer
Definition: serverpool.h:39
PrivTcpServer::newConnection
void newConnection(qintptr socket)
PoolServerType
PoolServerType
Definition: serverpool.h:29
PrivUdpSocket::host
QNetworkAddressEntry host()
Definition: serverpool.cpp:38
ServerPool::RefreshDefaultListen
static void RefreshDefaultListen(void)
Definition: serverpool.cpp:292
ServerPool::DefaultListen
static QList< QHostAddress > DefaultListen(void)
Definition: serverpool.cpp:301
ServerPool::newTcpConnection
virtual void newTcpConnection(qintptr socket)
Definition: serverpool.cpp:674
ServerPool::m_maxPendingConn
int m_maxPendingConn
Definition: serverpool.h:122
gCoreContext
MythCoreContext * gCoreContext
This global variable contains the MythCoreContext instance for the app.
Definition: mythcorecontext.cpp:55
ServerPool::bind
bool bind(QList< QHostAddress > addrs, quint16 port, bool requireall=true)
Definition: serverpool.cpp:491
ServerPool::SelectDefaultListen
static void SelectDefaultListen(bool force=false)
Definition: serverpool.cpp:75
MythCoreContext::ResolveIPv6
@ ResolveIPv6
Definition: mythcorecontext.h:211
MythCoreContext::GetBoolSetting
bool GetBoolSetting(const QString &key, bool defaultval=false)
Definition: mythcorecontext.cpp:906
ServerPool::m_tcpServers
QList< PrivTcpServer * > m_tcpServers
Definition: serverpool.h:126
MythCoreContext::ResolveIPv4
@ ResolveIPv4
Definition: mythcorecontext.h:211
mythcorecontext.h
naLock
static QReadWriteLock naLock
Definition: serverpool.cpp:25
LOC
#define LOC
Definition: serverpool.cpp:20
kLinkLocal
static QPair< QHostAddress, int > kLinkLocal
Definition: serverpool.cpp:27
serverpool.h
ServerPool::m_port
quint16 m_port
Definition: serverpool.h:123
ServerPool::m_listening
bool m_listening
Definition: serverpool.h:121
ServerPool::listen
bool listen(QList< QHostAddress > addrs, quint16 port, bool requireall=true, PoolServerType type=kTCPServer)
Definition: serverpool.cpp:391
PrivTcpServer::incomingConnection
void incomingConnection(qintptr socket) override
Definition: serverpool.cpp:65
ServerPool::DefaultBroadcast
static QList< QHostAddress > DefaultBroadcast(void)
Definition: serverpool.cpp:335
ServerPool::DefaultListenIPv6
static QList< QHostAddress > DefaultListenIPv6(void)
Definition: serverpool.cpp:322
MythCoreContext::CheckSubnet
bool CheckSubnet(const QAbstractSocket *socket)
Check if a socket is connected to an approved peer.
Definition: mythcorecontext.cpp:1268
kTCPServer
@ kTCPServer
Definition: serverpool.h:31
PrivUdpSocket::m_host
QNetworkAddressEntry m_host
Definition: serverpool.cpp:57