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)" : "",
417  PRETTYIP_(qha), QString::number(port)));
418  if ((servertype == kTCPServer) || (servertype == kSSLServer))
419  m_tcpServers.append(server);
420  if (m_port == 0)
421  m_port = server->serverPort();
422  }
423  else
424  {
425  LOG(VB_GENERAL, LOG_ERR,
426  QString("Failed listening on TCP %1:%2 - Error %3: %4")
427  .arg(PRETTYIP_(qha))
428  .arg(port)
429  .arg(server->serverError())
430  .arg(server->errorString()));
431  server->disconnect();
432  server->deleteLater();
433 
434  if (server->serverError() == QAbstractSocket::HostNotFoundError ||
435  server->serverError() == QAbstractSocket::SocketAddressNotAvailableError)
436  {
437  LOG(VB_GENERAL, LOG_ERR,
438  QString("Address %1 no longer exists - ignoring")
439  .arg(PRETTYIP_(qha)));
440  continue;
441  }
442 
443  if (server->serverError() == QAbstractSocket::UnsupportedSocketOperationError
444  && qha.protocol() == QAbstractSocket::IPv4Protocol)
445  {
446  LOG(VB_GENERAL, LOG_INFO,
447  QString("IPv4 support failed for this port."));
448  continue;
449  }
450 
451  if (server->serverError() == QAbstractSocket::UnsupportedSocketOperationError
452  && qha.protocol() == QAbstractSocket::IPv6Protocol)
453  {
454  LOG(VB_GENERAL, LOG_INFO,
455  QString("IPv6 support failed for this port."));
456  continue;
457  }
458 
459  if (requireall)
460  {
461  close();
462  return false;
463  }
464  }
465  }
466 
467  if (m_tcpServers.empty())
468  return false;
469 
470  m_listening = true;
471  return true;
472 }
473 
474 bool ServerPool::listen(QStringList addrstr, quint16 port, bool requireall,
475  PoolServerType servertype)
476 {
477  QList<QHostAddress> addrs;
478  for (const auto & str : qAsConst(addrstr))
479  addrs << QHostAddress(str);
480  return listen(addrs, port, requireall, servertype);
481 }
482 
483 bool ServerPool::listen(quint16 port, bool requireall,
484  PoolServerType servertype)
485 {
486  return listen(DefaultListen(), port, requireall, servertype);
487 }
488 
489 bool ServerPool::bind(QList<QHostAddress> addrs, quint16 port,
490  bool requireall)
491 {
492  m_port = port;
493  for (const auto & qha : qAsConst(addrs))
494  {
495  // If IPV4 support is disabled and this is an IPV4 address,
496  // bypass this address
497  if (qha.protocol() == QAbstractSocket::IPv4Protocol
498  && ! gCoreContext->GetBoolSetting("IPv4Support",true))
499  continue;
500  // If IPV6 support is disabled and this is an IPV6 address,
501  // bypass this address
502  if (qha.protocol() == QAbstractSocket::IPv6Protocol
503  && ! gCoreContext->GetBoolSetting("IPv6Support",true))
504  continue;
505 
506  QNetworkAddressEntry host;
507  QNetworkAddressEntry wildcard;
508 
509  if (qha.protocol() == QAbstractSocket::IPv6Protocol)
510  {
511  for (const auto& iae : qAsConst(naList_6))
512  {
513  if (PrivUdpSocket::contains(iae, qha))
514  {
515  host = iae;
516  break;
517  }
518  if (iae.ip() == QHostAddress::AnyIPv6)
519  wildcard = iae;
520  }
521  }
522  else
523  {
524  for (const auto& iae : qAsConst(naList_4))
525  {
526  if (PrivUdpSocket::contains(iae, qha))
527  {
528  host = iae;
529  break;
530  }
531  if (iae.ip() == QHostAddress::AnyIPv4)
532  wildcard = iae;
533  }
534  }
535 
536  if (host.ip().isNull())
537  {
538  if (wildcard.ip().isNull())
539  {
540  LOG(VB_GENERAL, LOG_ERR,
541  QString("Failed to find local address to use for destination %1:%2.")
542  .arg(PRETTYIP_(qha)).arg(port));
543  continue;
544  }
545 
546  LOG(VB_GENERAL, LOG_DEBUG,
547  QString("Failed to find local address to use for destination %1:%2. Using wildcard.")
548  .arg(PRETTYIP_(qha)).arg(port));
549  host = wildcard;
550  }
551 
552  auto *socket = new PrivUdpSocket(this, host);
553 
554  if (socket->bind(qha, port))
555  {
556  LOG(VB_GENERAL, LOG_INFO, QString("Binding to UDP %1:%2")
557  .arg(PRETTYIP_(qha)).arg(port));
558  m_udpSockets.append(socket);
559  connect(socket, &QIODevice::readyRead,
561  }
562  else
563  {
564  LOG(VB_GENERAL, LOG_ERR,
565  QString("Failed binding to UDP %1:%2 - Error %3: %4")
566  .arg(PRETTYIP_(qha))
567  .arg(port)
568  .arg(socket->error())
569  .arg(socket->errorString()));
570  socket->disconnect();
571  socket->deleteLater();
572 
573  if (socket->error() == QAbstractSocket::SocketAddressNotAvailableError)
574  {
575  LOG(VB_GENERAL, LOG_ERR,
576  QString("Address %1 no longer exists - ignoring")
577  .arg(PRETTYIP_(qha)));
578  continue;
579  }
580 
581  if (requireall)
582  {
583  close();
584  return false;
585  }
586  }
587  }
588 
589  if (m_udpSockets.empty())
590  return false;
591 
592  m_listening = true;
593  return true;
594 }
595 
596 bool ServerPool::bind(QStringList addrstr, quint16 port, bool requireall)
597 {
598  QList<QHostAddress> addrs;
599  for (const auto & str : qAsConst(addrstr))
600  addrs << QHostAddress(str);
601  return bind(addrs, port, requireall);
602 }
603 
604 bool ServerPool::bind(quint16 port, bool requireall)
605 {
606  return bind(DefaultListen(), port, requireall);
607 }
608 
609 qint64 ServerPool::writeDatagram(const char * data, qint64 size,
610  const QHostAddress &addr, quint16 port)
611 {
612  if (!m_listening || m_udpSockets.empty())
613  {
614  LOG(VB_GENERAL, LOG_ERR, "Trying to write datagram to disconnected "
615  "ServerPool instance.");
616  return -1;
617  }
618 
619  // check if can re-use the last one, so there's no need for a linear search
620  if (!m_lastUdpSocket || !m_lastUdpSocket->contains(addr))
621  {
622  // find the right socket to use
623  QList<PrivUdpSocket*>::iterator it;
624  for (it = m_udpSockets.begin(); it != m_udpSockets.end(); ++it)
625  {
626  PrivUdpSocket *val = *it;
627  if (val->contains(addr))
628  {
629  m_lastUdpSocket = val;
630  break;
631  }
632  }
633  }
634  if (!m_lastUdpSocket)
635  {
636  // Couldn't find an exact socket. See is there is a wildcard one.
637  LOG(VB_GENERAL, LOG_DEBUG,
638  QString("No exact socket match for %1:%2. Searching for wildcard.")
639  .arg(PRETTYIP_(addr)).arg(port));
640  for (auto *val : qAsConst(m_udpSockets))
641  {
642  if ((addr.protocol() == QAbstractSocket::IPv6Protocol &&
643  val->host().ip() == QHostAddress::AnyIPv6) ||
644  (val->host().ip() == QHostAddress::AnyIPv4))
645  {
646  m_lastUdpSocket = val;
647  break;
648  }
649  }
650  }
651  if (!m_lastUdpSocket)
652  {
653  LOG(VB_GENERAL, LOG_DEBUG, QString("No m_lastUdpSocket"));
654  return -1;
655  }
656 
657  qint64 ret = m_lastUdpSocket->writeDatagram(data, size, addr, port);
658  if (ret != size)
659  {
660  LOG(VB_GENERAL, LOG_DEBUG, QString("Error = %1 : %2")
661  .arg(ret).arg(m_lastUdpSocket->error()));
662  }
663  return ret;
664 }
665 
666 qint64 ServerPool::writeDatagram(const QByteArray &datagram,
667  const QHostAddress &addr, quint16 port)
668 {
669  return writeDatagram(datagram.data(), datagram.size(), addr, port);
670 }
671 
673 {
674  // Ignore connections from an SSL server for now, these are only handled
675  // by HttpServer which overrides newTcpConnection
676  auto *server = qobject_cast<PrivTcpServer *>(QObject::sender());
677  if (!server || server->GetServerType() == kSSLServer)
678  return;
679 
680  auto *qsock = new QTcpSocket(this);
681  if (qsock->setSocketDescriptor(socket)
682  && gCoreContext->CheckSubnet(qsock))
683  {
684  emit newConnection(qsock);
685  }
686  else
687  delete qsock;
688 }
689 
691 {
692  auto *socket = qobject_cast<QUdpSocket*>(sender());
693 
694  while (socket->state() == QAbstractSocket::BoundState &&
695  socket->hasPendingDatagrams())
696  {
697  QByteArray buffer;
698  buffer.resize(socket->pendingDatagramSize());
699  QHostAddress sender;
700  quint16 senderPort = 0;
701 
702  socket->readDatagram(buffer.data(), buffer.size(),
703  &sender, &senderPort);
704  if (gCoreContext->CheckSubnet(sender))
705  emit newDatagram(buffer, sender, senderPort);
706  }
707 }
708 
722 int ServerPool::tryListeningPort(int baseport, int range)
723 {
724  // try a few ports in case the first is in use
725  int port = baseport;
726  while (port < baseport + range)
727  {
728  if (listen(port))
729  {
730  break;
731  }
732  port++;
733  }
734 
735  if (port >= baseport + range)
736  {
737  return -1;
738  }
739  return port;
740 }
741 
755 int ServerPool::tryBindingPort(int baseport, int range)
756 {
757  // try a few ports in case the first is in use
758  int port = baseport;
759  while (port < baseport + range)
760  {
761  if (bind(port))
762  {
763  break;
764  }
765  port++;
766  }
767 
768  if (port >= baseport + range)
769  {
770  return -1;
771  }
772  return port;
773 }
774 
791 int ServerPool::tryListeningPort(QTcpServer *server, int baseport,
792  int range, bool *isipv6)
793 {
794  bool ipv6 = true;
795  // try a few ports in case the first is in use
796  int port = baseport;
797  while (port < baseport + range)
798  {
799  if (ipv6)
800  {
801  if (server->listen(QHostAddress::AnyIPv6, port))
802  {
803  break;
804  }
805 
806  // did we fail because IPv6 isn't available?
807  QAbstractSocket::SocketError err = server->serverError();
808  if (err == QAbstractSocket::UnsupportedSocketOperationError)
809  {
810  ipv6 = false;
811  }
812  }
813  if (!ipv6)
814  {
815  if (server->listen(QHostAddress::Any, port))
816  {
817  break;
818  }
819  }
820  port++;
821  }
822 
823  if (isipv6)
824  {
825  *isipv6 = ipv6;
826  }
827 
828  if (port >= baseport + range)
829  {
830  return -1;
831  }
832  if (port == 0)
833  {
834  port = server->serverPort();
835  }
836  return port;
837 }
838 
855 int ServerPool::tryBindingPort(QUdpSocket *socket, int baseport,
856  int range, bool *isipv6)
857 {
858  bool ipv6 = true;
859  // try a few ports in case the first is in use
860  int port = baseport;
861  while (port < baseport + range)
862  {
863  if (ipv6)
864  {
865  if (socket->bind(QHostAddress::AnyIPv6, port))
866  {
867  break;
868  }
869 
870  // did we fail because IPv6 isn't available?
871  QAbstractSocket::SocketError err = socket->error();
872  if (err == QAbstractSocket::UnsupportedSocketOperationError)
873  {
874  ipv6 = false;
875  }
876  }
877  if (!ipv6)
878  {
879  if (socket->bind(QHostAddress::Any, port))
880  {
881  break;
882  }
883  }
884  port++;
885  }
886 
887  if (isipv6)
888  {
889  *isipv6 = ipv6;
890  }
891 
892  if (port >= baseport + range)
893  {
894  return -1;
895  }
896  return port;
897 }
naList_4
static QList< QNetworkAddressEntry > naList_4
Definition: serverpool.cpp:21
force
bool force
Definition: mythtv/programs/mythcommflag/main.cpp:72
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:1175
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:755
PrivTcpServer::PrivTcpServer
PrivTcpServer(QObject *parent=nullptr, PoolServerType type=kTCPServer)
Definition: serverpool.cpp:58
ServerPool::DefaultListenIPv4
static QList< QHostAddress > DefaultListenIPv4(void)
Definition: serverpool.cpp:307
ServerPool::tryListeningPort
int tryListeningPort(int baseport, int range=1)
tryListeningPort
Definition: serverpool.cpp:722
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:609
ServerPool::m_proxy
QNetworkProxy m_proxy
Definition: serverpool.h:124
mythlogging.h
ServerPool::newUdpDatagram
virtual void newUdpDatagram(void)
Definition: serverpool.cpp:690
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:672
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:489
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:930
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:1280
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