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