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  {
199  LOG(VB_GENERAL, LOG_DEBUG, QString("Skipping address: %1")
200  .arg(prettyip(ip)));
201  }
202 
203  }
204  else
205  {
206  if (ip.isInSubnet(kLinkLocal6))
207  {
208  // set scope id for link local address
209  ip.setScopeId(qni.name());
210  qnai->setIp(ip);
211  }
212 
213  if (naList_6.contains(*qnai))
214  // already defined, skip
215  continue;
216 
217  if ((!config_v6.isNull()) && (ip == config_v6))
218  {
219  // IPv6 address is defined, add it
220  LOG(VB_GENERAL, LOG_DEBUG,
221  QString("Adding BackendServerIP6 to address list."));
222  naList_6.append(*qnai);
223  v6IsSet = true;
224  }
225 
226  else if (ip == QHostAddress::LocalHostIPv6)
227  {
228  // always listen on LocalHost
229  LOG(VB_GENERAL, LOG_DEBUG,
230  QString("Adding IPv6 loopback to address list."));
231  naList_6.append(*qnai);
232  if (!v6IsSet && (config_v6 == ip))
233  v6IsSet = true;
234  }
235 
236  else if (ip.isInSubnet(kLinkLocal6) && allowLinkLocal)
237  {
238  // optionally listen on linklocal
239  // the next clause will enable it anyway if no IP address
240  // has been set
241  LOG(VB_GENERAL, LOG_DEBUG,
242  QString("Adding link-local '%1' to address list.")
243  .arg(ip.toString()));
244  naList_6.append(*qnai);
245  }
246 
247  else if (config_v6.isNull())
248  {
249  if (ip.isInSubnet(kLinkLocal6))
250  {
251  LOG(VB_GENERAL, LOG_DEBUG,
252  QString("Adding link-local '%1' to address list.")
253  .arg(prettyip(ip)));
254  }
255  else
256  {
257  LOG(VB_GENERAL, LOG_DEBUG,
258  QString("Adding '%1' to address list.")
259  .arg(prettyip(ip)));
260  }
261 
262  naList_6.append(*qnai);
263  }
264 
265  else
266  {
267  LOG(VB_GENERAL, LOG_DEBUG, QString("Skipping address: %1")
268  .arg(prettyip(ip)));
269  }
270  }
271  }
272  }
273 
274  if (!v4IsSet && (config_v4 != QHostAddress::LocalHost)
275  && !naList_4.isEmpty())
276  {
277  LOG(VB_GENERAL, LOG_CRIT, LOC + QString("Host is configured to listen "
278  "on %1, but address is not used on any local network "
279  "interfaces.").arg(config_v4.toString()));
280  }
281 
282  if (!v6IsSet && (config_v6 != QHostAddress::LocalHostIPv6)
283  && !naList_6.isEmpty())
284  {
285  LOG(VB_GENERAL, LOG_CRIT, LOC + QString("Host is configured to listen "
286  "on %1, but address is not used on any local network "
287  "interfaces.").arg(prettyip(config_v6)));
288  }
289 
290  // NOTE: there is no warning for the case where both defined addresses
291  // are localhost, and neither are found. however this would also
292  // mean there is no configured network at all, and should be
293  // sufficiently rare a case as to not worry about it.
294 }
295 
297 {
298  SelectDefaultListen(true);
299  // TODO:
300  // send signal for any running servers to cycle their addresses
301  // will allow address configuration to be modified without a server
302  // reset for use with the migration to the mythtv-setup replacement
303 }
304 
305 QList<QHostAddress> ServerPool::DefaultListen(void)
306 {
307  QList<QHostAddress> alist;
308  alist << DefaultListenIPv4()
309  << DefaultListenIPv6();
310  return alist;
311 }
312 
313 QList<QHostAddress> ServerPool::DefaultListenIPv4(void)
314 {
316  QReadLocker rlock(&naLock);
317 
318  QList<QHostAddress> alist;
319  for (const auto & nae : std::as_const(naList_4))
320  if (!alist.contains(nae.ip()))
321  alist << nae.ip();
322 
323  return alist;
324 }
325 
326 QList<QHostAddress> ServerPool::DefaultListenIPv6(void)
327 {
329  QReadLocker rlock(&naLock);
330 
331  QList<QHostAddress> alist;
332  for (const auto & nae : std::as_const(naList_6))
333  if (!alist.contains(nae.ip()))
334  alist << nae.ip();
335 
336  return alist;
337 }
338 
339 QList<QHostAddress> ServerPool::DefaultBroadcast(void)
340 {
341  QList<QHostAddress> blist;
342  if (!gCoreContext->GetBoolSetting("ListenOnAllIps",true))
343  {
344  blist << DefaultBroadcastIPv4();
345  blist << DefaultBroadcastIPv6();
346  }
347  return blist;
348 }
349 
350 QList<QHostAddress> ServerPool::DefaultBroadcastIPv4(void)
351 {
353  QReadLocker rlock(&naLock);
354 
355  QList<QHostAddress> blist;
356  for (const auto & nae : std::as_const(naList_4))
357  {
358  if (!blist.contains(nae.broadcast()) && (nae.prefixLength() != 32) &&
359  (nae.ip() != QHostAddress::LocalHost))
360  blist << nae.broadcast();
361  }
362 
363  return blist;
364 }
365 
366 QList<QHostAddress> ServerPool::DefaultBroadcastIPv6(void)
367 {
368  QList<QHostAddress> blist;
369  blist << QHostAddress("FF02::1");
370  return blist;
371 }
372 
373 
375 {
376  while (!m_tcpServers.isEmpty())
377  {
378  PrivTcpServer *server = m_tcpServers.takeLast();
379  server->disconnect();
380  server->close();
381  server->deleteLater();
382  }
383 
384  while (!m_udpSockets.isEmpty())
385  {
386  PrivUdpSocket *socket = m_udpSockets.takeLast();
387  socket->disconnect();
388  socket->close();
389  socket->deleteLater();
390  }
391  m_lastUdpSocket = nullptr;
392  m_listening = false;
393 }
394 
395 bool ServerPool::listen(QList<QHostAddress> addrs, quint16 port,
396  bool requireall, PoolServerType servertype)
397 {
398  m_port = port;
399  for (const auto & qha : std::as_const(addrs))
400  {
401  // If IPV4 support is disabled and this is an IPV4 address,
402  // bypass this address
403  if (qha.protocol() == QAbstractSocket::IPv4Protocol
404  && ! gCoreContext->GetBoolSetting("IPv4Support",true))
405  continue;
406  // If IPV6 support is disabled and this is an IPV6 address,
407  // bypass this address
408  if (qha.protocol() == QAbstractSocket::IPv6Protocol
409  && ! gCoreContext->GetBoolSetting("IPv6Support",true))
410  continue;
411 
412  auto *server = new PrivTcpServer(this, servertype);
413  connect(server, &PrivTcpServer::newConnection,
415 
416  server->setProxy(m_proxy);
417  server->setMaxPendingConnections(m_maxPendingConn);
418 
419  if (server->listen(qha, m_port))
420  {
421  LOG(VB_GENERAL, LOG_INFO, QString("Listening on TCP%1 %2:%3")
422  .arg(servertype == kSSLServer ? " (SSL)" : "",
423  prettyip(qha), QString::number(port)));
424  if ((servertype == kTCPServer) || (servertype == kSSLServer))
425  m_tcpServers.append(server);
426  if (m_port == 0)
427  m_port = server->serverPort();
428  }
429  else
430  {
431  LOG(VB_GENERAL, LOG_ERR,
432  QString("Failed listening on TCP %1:%2 - Error %3: %4")
433  .arg(prettyip(qha))
434  .arg(port)
435  .arg(server->serverError())
436  .arg(server->errorString()));
437  server->disconnect();
438  server->deleteLater();
439 
440  if (server->serverError() == QAbstractSocket::HostNotFoundError ||
441  server->serverError() == QAbstractSocket::SocketAddressNotAvailableError)
442  {
443  LOG(VB_GENERAL, LOG_ERR,
444  QString("Address %1 no longer exists - ignoring")
445  .arg(prettyip(qha)));
446  continue;
447  }
448 
449  if (server->serverError() == QAbstractSocket::UnsupportedSocketOperationError
450  && qha.protocol() == QAbstractSocket::IPv4Protocol)
451  {
452  LOG(VB_GENERAL, LOG_INFO,
453  QString("IPv4 support failed for this port."));
454  continue;
455  }
456 
457  if (server->serverError() == QAbstractSocket::UnsupportedSocketOperationError
458  && qha.protocol() == QAbstractSocket::IPv6Protocol)
459  {
460  LOG(VB_GENERAL, LOG_INFO,
461  QString("IPv6 support failed for this port."));
462  continue;
463  }
464 
465  if (requireall)
466  {
467  close();
468  return false;
469  }
470  }
471  }
472 
473  if (m_tcpServers.empty())
474  return false;
475 
476  m_listening = true;
477  return true;
478 }
479 
480 bool ServerPool::listen(QStringList addrstr, quint16 port, bool requireall,
481  PoolServerType servertype)
482 {
483  QList<QHostAddress> addrs;
484  for (const auto & str : std::as_const(addrstr))
485  addrs << QHostAddress(str);
486  return listen(addrs, port, requireall, servertype);
487 }
488 
489 bool ServerPool::listen(quint16 port, bool requireall,
490  PoolServerType servertype)
491 {
492  return listen(DefaultListen(), port, requireall, servertype);
493 }
494 
495 bool ServerPool::bind(QList<QHostAddress> addrs, quint16 port,
496  bool requireall)
497 {
498  m_port = port;
499  for (const auto & qha : std::as_const(addrs))
500  {
501  // If IPV4 support is disabled and this is an IPV4 address,
502  // bypass this address
503  if (qha.protocol() == QAbstractSocket::IPv4Protocol
504  && ! gCoreContext->GetBoolSetting("IPv4Support",true))
505  continue;
506  // If IPV6 support is disabled and this is an IPV6 address,
507  // bypass this address
508  if (qha.protocol() == QAbstractSocket::IPv6Protocol
509  && ! gCoreContext->GetBoolSetting("IPv6Support",true))
510  continue;
511 
512  QNetworkAddressEntry host;
513  QNetworkAddressEntry wildcard;
514 
515  if (qha.protocol() == QAbstractSocket::IPv6Protocol)
516  {
517  for (const auto& iae : std::as_const(naList_6))
518  {
519  if (PrivUdpSocket::contains(iae, qha))
520  {
521  host = iae;
522  break;
523  }
524  if (iae.ip() == QHostAddress::AnyIPv6)
525  wildcard = iae;
526  }
527  }
528  else
529  {
530  for (const auto& iae : std::as_const(naList_4))
531  {
532  if (PrivUdpSocket::contains(iae, qha))
533  {
534  host = iae;
535  break;
536  }
537  if (iae.ip() == QHostAddress::AnyIPv4)
538  wildcard = iae;
539  }
540  }
541 
542  if (host.ip().isNull())
543  {
544  if (wildcard.ip().isNull())
545  {
546  LOG(VB_GENERAL, LOG_ERR,
547  QString("Failed to find local address to use for destination %1:%2.")
548  .arg(prettyip(qha)).arg(port));
549  continue;
550  }
551 
552  LOG(VB_GENERAL, LOG_DEBUG,
553  QString("Failed to find local address to use for destination %1:%2. Using wildcard.")
554  .arg(prettyip(qha)).arg(port));
555  host = wildcard;
556  }
557 
558  auto *socket = new PrivUdpSocket(this, host);
559 
560  if (socket->bind(qha, port))
561  {
562  LOG(VB_GENERAL, LOG_INFO, QString("Binding to UDP %1:%2")
563  .arg(prettyip(qha)).arg(port));
564  m_udpSockets.append(socket);
565  connect(socket, &QIODevice::readyRead,
567  }
568  else
569  {
570  LOG(VB_GENERAL, LOG_ERR,
571  QString("Failed binding to UDP %1:%2 - Error %3: %4")
572  .arg(prettyip(qha))
573  .arg(port)
574  .arg(socket->error())
575  .arg(socket->errorString()));
576  socket->disconnect();
577  socket->deleteLater();
578 
579  if (socket->error() == QAbstractSocket::SocketAddressNotAvailableError)
580  {
581  LOG(VB_GENERAL, LOG_ERR,
582  QString("Address %1 no longer exists - ignoring")
583  .arg(prettyip(qha)));
584  continue;
585  }
586 
587  if (requireall)
588  {
589  close();
590  return false;
591  }
592  }
593  }
594 
595  if (m_udpSockets.empty())
596  return false;
597 
598  m_listening = true;
599  return true;
600 }
601 
602 bool ServerPool::bind(QStringList addrstr, quint16 port, bool requireall)
603 {
604  QList<QHostAddress> addrs;
605  for (const auto & str : std::as_const(addrstr))
606  addrs << QHostAddress(str);
607  return bind(addrs, port, requireall);
608 }
609 
610 bool ServerPool::bind(quint16 port, bool requireall)
611 {
612  return bind(DefaultListen(), port, requireall);
613 }
614 
615 qint64 ServerPool::writeDatagram(const char * data, qint64 size,
616  const QHostAddress &addr, quint16 port)
617 {
618  if (!m_listening || m_udpSockets.empty())
619  {
620  LOG(VB_GENERAL, LOG_ERR, "Trying to write datagram to disconnected "
621  "ServerPool instance.");
622  return -1;
623  }
624 
625  // check if can re-use the last one, so there's no need for a linear search
626  if (!m_lastUdpSocket || !m_lastUdpSocket->contains(addr))
627  {
628  // find the right socket to use
629  QList<PrivUdpSocket*>::iterator it;
630  for (it = m_udpSockets.begin(); it != m_udpSockets.end(); ++it)
631  {
632  PrivUdpSocket *val = *it;
633  if (val->contains(addr))
634  {
635  m_lastUdpSocket = val;
636  break;
637  }
638  }
639  }
640  if (!m_lastUdpSocket)
641  {
642  // Couldn't find an exact socket. See is there is a wildcard one.
643  LOG(VB_GENERAL, LOG_DEBUG,
644  QString("No exact socket match for %1:%2. Searching for wildcard.")
645  .arg(prettyip(addr)).arg(port));
646  for (auto *val : std::as_const(m_udpSockets))
647  {
648  if ((addr.protocol() == QAbstractSocket::IPv6Protocol &&
649  val->host().ip() == QHostAddress::AnyIPv6) ||
650  (val->host().ip() == QHostAddress::AnyIPv4))
651  {
652  m_lastUdpSocket = val;
653  break;
654  }
655  }
656  }
657  if (!m_lastUdpSocket)
658  {
659  LOG(VB_GENERAL, LOG_DEBUG, QString("No m_lastUdpSocket"));
660  return -1;
661  }
662 
663  qint64 ret = m_lastUdpSocket->writeDatagram(data, size, addr, port);
664  if (ret != size)
665  {
666  LOG(VB_GENERAL, LOG_DEBUG, QString("Error = %1 : %2")
667  .arg(ret).arg(m_lastUdpSocket->error()));
668  }
669  return ret;
670 }
671 
672 qint64 ServerPool::writeDatagram(const QByteArray &datagram,
673  const QHostAddress &addr, quint16 port)
674 {
675  return writeDatagram(datagram.data(), datagram.size(), addr, port);
676 }
677 
678 void ServerPool::newTcpConnection(qintptr socket)
679 {
680  // Ignore connections from an SSL server for now, these are only handled
681  // by HttpServer which overrides newTcpConnection
682  auto *server = qobject_cast<PrivTcpServer *>(QObject::sender());
683  if (!server || server->GetServerType() == kSSLServer)
684  return;
685 
686  auto *qsock = new QTcpSocket(this);
687  if (qsock->setSocketDescriptor(socket)
688  && gCoreContext->CheckSubnet(qsock))
689  {
690  emit newConnection(qsock);
691  }
692  else
693  {
694  delete qsock;
695  }
696 }
697 
699 {
700  auto *socket = qobject_cast<QUdpSocket*>(sender());
701 
702  while (socket->state() == QAbstractSocket::BoundState &&
703  socket->hasPendingDatagrams())
704  {
705  QByteArray buffer;
706  buffer.resize(socket->pendingDatagramSize());
707  QHostAddress sender;
708  quint16 senderPort = 0;
709 
710  socket->readDatagram(buffer.data(), buffer.size(),
711  &sender, &senderPort);
712  if (gCoreContext->CheckSubnet(sender))
713  emit newDatagram(buffer, sender, senderPort);
714  }
715 }
716 
730 int ServerPool::tryListeningPort(int baseport, int range)
731 {
732  // try a few ports in case the first is in use
733  int port = baseport;
734  while (port < baseport + range)
735  {
736  if (listen(port))
737  {
738  break;
739  }
740  port++;
741  }
742 
743  if (port >= baseport + range)
744  {
745  return -1;
746  }
747  return port;
748 }
749 
763 int ServerPool::tryBindingPort(int baseport, int range)
764 {
765  // try a few ports in case the first is in use
766  int port = baseport;
767  while (port < baseport + range)
768  {
769  if (bind(port))
770  {
771  break;
772  }
773  port++;
774  }
775 
776  if (port >= baseport + range)
777  {
778  return -1;
779  }
780  return port;
781 }
782 
799 int ServerPool::tryListeningPort(QTcpServer *server, int baseport,
800  int range, bool *isipv6)
801 {
802  bool ipv6 = true;
803  // try a few ports in case the first is in use
804  int port = baseport;
805  while (port < baseport + range)
806  {
807  if (ipv6)
808  {
809  if (server->listen(QHostAddress::AnyIPv6, port))
810  {
811  break;
812  }
813 
814  // did we fail because IPv6 isn't available?
815  QAbstractSocket::SocketError err = server->serverError();
816  if (err == QAbstractSocket::UnsupportedSocketOperationError)
817  {
818  ipv6 = false;
819  }
820  }
821  if (!ipv6)
822  {
823  if (server->listen(QHostAddress::Any, port))
824  {
825  break;
826  }
827  }
828  port++;
829  }
830 
831  if (isipv6)
832  {
833  *isipv6 = ipv6;
834  }
835 
836  if (port >= baseport + range)
837  {
838  return -1;
839  }
840  if (port == 0)
841  {
842  port = server->serverPort();
843  }
844  return port;
845 }
846 
863 int ServerPool::tryBindingPort(QUdpSocket *socket, int baseport,
864  int range, bool *isipv6)
865 {
866  bool ipv6 = true;
867  // try a few ports in case the first is in use
868  int port = baseport;
869  while (port < baseport + range)
870  {
871  if (ipv6)
872  {
873  if (socket->bind(QHostAddress::AnyIPv6, port))
874  {
875  break;
876  }
877 
878  // did we fail because IPv6 isn't available?
879  QAbstractSocket::SocketError err = socket->error();
880  if (err == QAbstractSocket::UnsupportedSocketOperationError)
881  {
882  ipv6 = false;
883  }
884  }
885  if (!ipv6)
886  {
887  if (socket->bind(QHostAddress::Any, port))
888  {
889  break;
890  }
891  }
892  port++;
893  }
894 
895  if (isipv6)
896  {
897  *isipv6 = ipv6;
898  }
899 
900  if (port >= baseport + range)
901  {
902  return -1;
903  }
904  return port;
905 }
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:1167
PrivUdpSocket::contains
bool contains(const QHostAddress &addr)
Definition: serverpool.cpp:42
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:374
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:763
PrivTcpServer::PrivTcpServer
PrivTcpServer(QObject *parent=nullptr, PoolServerType type=kTCPServer)
Definition: serverpool.cpp:60
ServerPool::DefaultListenIPv4
static QList< QHostAddress > DefaultListenIPv4(void)
Definition: serverpool.cpp:313
ServerPool::tryListeningPort
int tryListeningPort(int baseport, int range=1)
tryListeningPort
Definition: serverpool.cpp:730
ServerPool::m_udpSockets
QList< PrivUdpSocket * > m_udpSockets
Definition: serverpool.h:127
ServerPool::DefaultBroadcastIPv6
static QList< QHostAddress > DefaultBroadcastIPv6(void)
Definition: serverpool.cpp:366
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:350
ServerPool::newConnection
void newConnection(QTcpSocket *)
PrivUdpSocket::~PrivUdpSocket
~PrivUdpSocket() override=default
kSSLServer
@ kSSLServer
Definition: serverpool.h:33
prettyip
static QString prettyip(const QHostAddress &x)
Definition: serverpool.cpp:12
PoolServerType
PoolServerType
Definition: serverpool.h:29
ServerPool::writeDatagram
qint64 writeDatagram(const char *data, qint64 size, const QHostAddress &addr, quint16 port)
Definition: serverpool.cpp:615
ServerPool::m_proxy
QNetworkProxy m_proxy
Definition: serverpool.h:124
mythlogging.h
ServerPool::newUdpDatagram
virtual void newUdpDatagram(void)
Definition: serverpool.cpp:698
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)
PrivUdpSocket::host
QNetworkAddressEntry host()
Definition: serverpool.cpp:38
kTCPServer
@ kTCPServer
Definition: serverpool.h:31
ServerPool::RefreshDefaultListen
static void RefreshDefaultListen(void)
Definition: serverpool.cpp:296
ServerPool::DefaultListen
static QList< QHostAddress > DefaultListen(void)
Definition: serverpool.cpp:305
MythCoreContext::ResolveIPv6
@ ResolveIPv6
Definition: mythcorecontext.h:211
ServerPool::newTcpConnection
virtual void newTcpConnection(qintptr socket)
Definition: serverpool.cpp:678
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:495
ServerPool::SelectDefaultListen
static void SelectDefaultListen(bool force=false)
Definition: serverpool.cpp:75
MythCoreContext::GetBoolSetting
bool GetBoolSetting(const QString &key, bool defaultval=false)
Definition: mythcorecontext.cpp:910
ServerPool::m_tcpServers
QList< PrivTcpServer * > m_tcpServers
Definition: serverpool.h:126
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
MythCoreContext::ResolveIPv4
@ ResolveIPv4
Definition: mythcorecontext.h:211
ServerPool::listen
bool listen(QList< QHostAddress > addrs, quint16 port, bool requireall=true, PoolServerType type=kTCPServer)
Definition: serverpool.cpp:395
PrivTcpServer::incomingConnection
void incomingConnection(qintptr socket) override
Definition: serverpool.cpp:65
ServerPool::DefaultBroadcast
static QList< QHostAddress > DefaultBroadcast(void)
Definition: serverpool.cpp:339
ServerPool::DefaultListenIPv6
static QList< QHostAddress > DefaultListenIPv6(void)
Definition: serverpool.cpp:326
MythCoreContext::CheckSubnet
bool CheckSubnet(const QAbstractSocket *socket)
Check if a socket is connected to an approved peer.
Definition: mythcorecontext.cpp:1276
PrivUdpSocket::m_host
QNetworkAddressEntry m_host
Definition: serverpool.cpp:57