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