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  s_privNet2 = QHostAddress::parseSubnet("172.16.0.0/12"),
166  s_privNet3 = QHostAddress::parseSubnet("192.168.0.0/16");
167 
168  if (ip.isInSubnet(s_privNet1) || ip.isInSubnet(s_privNet2) ||
169  ip.isInSubnet(s_privNet3))
170  {
171  LOG(VB_GENERAL, LOG_DEBUG,
172  QString("Adding '%1' to address list.")
173  .arg(PRETTYIP_(ip)));
174  naList_4.append(*qnai);
175  }
176  else if (ip.isInSubnet(kLinkLocal))
177  {
178  LOG(VB_GENERAL, LOG_DEBUG,
179  QString("Adding link-local '%1' to address list.")
180  .arg(PRETTYIP_(ip)));
181  naList_4.append(*qnai);
182  }
183  else
184  LOG(VB_GENERAL, LOG_DEBUG, QString("Skipping "
185  "non-private address during IPv4 autoselection: %1")
186  .arg(PRETTYIP_(ip)));
187  }
188 
189  else
190  LOG(VB_GENERAL, LOG_DEBUG, QString("Skipping address: %1")
191  .arg(PRETTYIP_(ip)));
192 
193  }
194  else
195  {
196  if (ip.isInSubnet(kLinkLocal6))
197  {
198  // set scope id for link local address
199  ip.setScopeId(qni->name());
200  qnai->setIp(ip);
201  }
202 
203  if (naList_6.contains(*qnai))
204  // already defined, skip
205  continue;
206 
207  if ((!config_v6.isNull()) && (ip == config_v6))
208  {
209  // IPv6 address is defined, add it
210  LOG(VB_GENERAL, LOG_DEBUG,
211  QString("Adding BackendServerIP6 to address list."));
212  naList_6.append(*qnai);
213  v6IsSet = true;
214  }
215 
216  else if (ip == QHostAddress::LocalHostIPv6)
217  {
218  // always listen on LocalHost
219  LOG(VB_GENERAL, LOG_DEBUG,
220  QString("Adding IPv6 loopback to address list."));
221  naList_6.append(*qnai);
222  if (!v6IsSet && (config_v6 == ip))
223  v6IsSet = true;
224  }
225 
226  else if (ip.isInSubnet(kLinkLocal6) && allowLinkLocal)
227  {
228  // optionally listen on linklocal
229  // the next clause will enable it anyway if no IP address
230  // has been set
231  LOG(VB_GENERAL, LOG_DEBUG,
232  QString("Adding link-local '%1' to address list.")
233  .arg(ip.toString()));
234  naList_6.append(*qnai);
235  }
236 
237  else if (config_v6.isNull())
238  {
239  if (ip.isInSubnet(kLinkLocal6))
240  LOG(VB_GENERAL, LOG_DEBUG,
241  QString("Adding link-local '%1' to address list.")
242  .arg(PRETTYIP_(ip)));
243  else
244  LOG(VB_GENERAL, LOG_DEBUG,
245  QString("Adding '%1' to address list.")
246  .arg(PRETTYIP_(ip)));
247 
248  naList_6.append(*qnai);
249  }
250 
251  else
252  LOG(VB_GENERAL, LOG_DEBUG, QString("Skipping address: %1")
253  .arg(PRETTYIP_(ip)));
254  }
255  }
256  }
257 
258  if (!v4IsSet && (config_v4 != QHostAddress::LocalHost)
259  && !naList_4.isEmpty())
260  {
261  LOG(VB_GENERAL, LOG_CRIT, LOC + QString("Host is configured to listen "
262  "on %1, but address is not used on any local network "
263  "interfaces.").arg(config_v4.toString()));
264  }
265 
266  if (!v6IsSet && (config_v6 != QHostAddress::LocalHostIPv6)
267  && !naList_6.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(PRETTYIP_(config_v6)));
272  }
273 
274  // NOTE: there is no warning for the case where both defined addresses
275  // are localhost, and neither are found. however this would also
276  // mean there is no configured network at all, and should be
277  // sufficiently rare a case as to not worry about it.
278 }
279 
281 {
282  SelectDefaultListen(true);
283  // TODO:
284  // send signal for any running servers to cycle their addresses
285  // will allow address configuration to be modified without a server
286  // reset for use with the migration to the mythtv-setup replacement
287 }
288 
289 QList<QHostAddress> ServerPool::DefaultListen(void)
290 {
291  QList<QHostAddress> alist;
292  alist << DefaultListenIPv4()
293  << DefaultListenIPv6();
294  return alist;
295 }
296 
297 QList<QHostAddress> ServerPool::DefaultListenIPv4(void)
298 {
300  QReadLocker rlock(&naLock);
301 
302  QList<QHostAddress> alist;
303  QList<QNetworkAddressEntry>::const_iterator it;
304  for (it = naList_4.begin(); it != naList_4.end(); ++it)
305  if (!alist.contains(it->ip()))
306  alist << it->ip();
307 
308  return alist;
309 }
310 
311 QList<QHostAddress> ServerPool::DefaultListenIPv6(void)
312 {
314  QReadLocker rlock(&naLock);
315 
316  QList<QHostAddress> alist;
317  QList<QNetworkAddressEntry>::const_iterator it;
318  for (it = naList_6.begin(); it != naList_6.end(); ++it)
319  if (!alist.contains(it->ip()))
320  alist << it->ip();
321 
322  return alist;
323 }
324 
325 QList<QHostAddress> ServerPool::DefaultBroadcast(void)
326 {
327  QList<QHostAddress> blist;
328  if (!gCoreContext->GetBoolSetting("ListenOnAllIps",true))
329  {
330  blist << DefaultBroadcastIPv4();
331  blist << DefaultBroadcastIPv6();
332  }
333  return blist;
334 }
335 
336 QList<QHostAddress> ServerPool::DefaultBroadcastIPv4(void)
337 {
339  QReadLocker rlock(&naLock);
340 
341  QList<QHostAddress> blist;
342  QList<QNetworkAddressEntry>::const_iterator it;
343  for (it = naList_4.begin(); it != naList_4.end(); ++it)
344  if (!blist.contains(it->broadcast()) && (it->prefixLength() != 32) &&
345  (it->ip() != QHostAddress::LocalHost))
346  blist << it->broadcast();
347 
348  return blist;
349 }
350 
351 QList<QHostAddress> ServerPool::DefaultBroadcastIPv6(void)
352 {
353  QList<QHostAddress> blist;
354  blist << QHostAddress("FF02::1");
355  return blist;
356 }
357 
358 
360 {
361  while (!m_tcpServers.isEmpty())
362  {
363  PrivTcpServer *server = m_tcpServers.takeLast();
364  server->disconnect();
365  server->close();
366  server->deleteLater();
367  }
368 
369  while (!m_udpSockets.isEmpty())
370  {
371  PrivUdpSocket *socket = m_udpSockets.takeLast();
372  socket->disconnect();
373  socket->close();
374  socket->deleteLater();
375  }
376  m_lastUdpSocket = nullptr;
377  m_listening = false;
378 }
379 
380 bool ServerPool::listen(QList<QHostAddress> addrs, quint16 port,
381  bool requireall, PoolServerType servertype)
382 {
383  m_port = port;
384  QList<QHostAddress>::const_iterator it;
385 
386  for (it = addrs.begin(); it != addrs.end(); ++it)
387  {
388  // If IPV4 support is disabled and this is an IPV4 address,
389  // bypass this address
390  if (it->protocol() == QAbstractSocket::IPv4Protocol
391  && ! gCoreContext->GetBoolSetting("IPv4Support",true))
392  continue;
393  // If IPV6 support is disabled and this is an IPV6 address,
394  // bypass this address
395  if (it->protocol() == QAbstractSocket::IPv6Protocol
396  && ! gCoreContext->GetBoolSetting("IPv6Support",true))
397  continue;
398 
399  auto *server = new PrivTcpServer(this, servertype);
400  connect(server, &PrivTcpServer::newConnection,
402 
403  server->setProxy(m_proxy);
404  server->setMaxPendingConnections(m_maxPendingConn);
405 
406  if (server->listen(*it, m_port))
407  {
408  LOG(VB_GENERAL, LOG_INFO, QString("Listening on TCP %1:%2")
409  .arg(PRETTYIP(it)).arg(port));
410  if (servertype == kTCPServer)
411  m_tcpServers.append(server);
412  if (m_port == 0)
413  m_port = server->serverPort();
414  }
415  else
416  {
417  LOG(VB_GENERAL, LOG_ERR,
418  QString("Failed listening on TCP %1:%2 - Error %3: %4")
419  .arg(PRETTYIP(it))
420  .arg(port)
421  .arg(server->serverError())
422  .arg(server->errorString()));
423  server->disconnect();
424  server->deleteLater();
425 
426  if (server->serverError() == QAbstractSocket::HostNotFoundError ||
427  server->serverError() == QAbstractSocket::SocketAddressNotAvailableError)
428  {
429  LOG(VB_GENERAL, LOG_ERR,
430  QString("Address %1 no longer exists - ignoring")
431  .arg(PRETTYIP(it)));
432  continue;
433  }
434 
435  if (server->serverError() == QAbstractSocket::UnsupportedSocketOperationError
436  && it->protocol() == QAbstractSocket::IPv4Protocol)
437  {
438  LOG(VB_GENERAL, LOG_INFO,
439  QString("IPv4 support failed for this port."));
440  continue;
441  }
442 
443  if (server->serverError() == QAbstractSocket::UnsupportedSocketOperationError
444  && it->protocol() == QAbstractSocket::IPv6Protocol)
445  {
446  LOG(VB_GENERAL, LOG_INFO,
447  QString("IPv6 support failed for this port."));
448  continue;
449  }
450 
451  if (requireall)
452  {
453  close();
454  return false;
455  }
456  }
457  }
458 
459  if (m_tcpServers.empty())
460  return false;
461 
462  m_listening = true;
463  return true;
464 }
465 
466 bool ServerPool::listen(QStringList addrstr, quint16 port, bool requireall,
467  PoolServerType servertype)
468 {
469  QList<QHostAddress> addrs;
470  QStringList::const_iterator it;
471  for (it = addrstr.begin(); it != addrstr.end(); ++it)
472  addrs << QHostAddress(*it);
473  return listen(addrs, port, requireall, servertype);
474 }
475 
476 bool ServerPool::listen(quint16 port, bool requireall,
477  PoolServerType servertype)
478 {
479  return listen(DefaultListen(), port, requireall, servertype);
480 }
481 
482 bool ServerPool::bind(QList<QHostAddress> addrs, quint16 port,
483  bool requireall)
484 {
485  m_port = port;
486  QList<QHostAddress>::const_iterator it;
487 
488  for (it = addrs.begin(); it != addrs.end(); ++it)
489  {
490  // If IPV4 support is disabled and this is an IPV4 address,
491  // bypass this address
492  if (it->protocol() == QAbstractSocket::IPv4Protocol
493  && ! gCoreContext->GetBoolSetting("IPv4Support",true))
494  continue;
495  // If IPV6 support is disabled and this is an IPV6 address,
496  // bypass this address
497  if (it->protocol() == QAbstractSocket::IPv6Protocol
498  && ! gCoreContext->GetBoolSetting("IPv6Support",true))
499  continue;
500 
501  QNetworkAddressEntry host;
502 
503  if (it->protocol() == QAbstractSocket::IPv6Protocol)
504  {
505  QList<QNetworkAddressEntry>::iterator iae;
506  for (iae = naList_6.begin(); iae != naList_6.end(); ++iae)
507  {
508  if (PrivUdpSocket::contains(*iae, *it))
509  {
510  host = *iae;
511  break;
512  }
513  }
514  }
515  else
516  {
517  QList<QNetworkAddressEntry>::iterator iae;
518  for (iae = naList_4.begin(); iae != naList_4.end(); ++iae)
519  {
520  if (PrivUdpSocket::contains(*iae, *it))
521  {
522  host = *iae;
523  break;
524  }
525  }
526  }
527 
528  auto *socket = new PrivUdpSocket(this, host);
529 
530  if (socket->bind(*it, port))
531  {
532  LOG(VB_GENERAL, LOG_INFO, QString("Binding to UDP %1:%2")
533  .arg(PRETTYIP(it)).arg(port));
534  m_udpSockets.append(socket);
535  connect(socket, SIGNAL(readyRead()),
536  this, SLOT(newUdpDatagram()));
537  }
538  else
539  {
540  LOG(VB_GENERAL, LOG_ERR,
541  QString("Failed binding to UDP %1:%2 - Error %3: %4")
542  .arg(PRETTYIP(it))
543  .arg(port)
544  .arg(socket->error())
545  .arg(socket->errorString()));
546  socket->disconnect();
547  socket->deleteLater();
548 
549  if (socket->error() == QAbstractSocket::SocketAddressNotAvailableError)
550  {
551  LOG(VB_GENERAL, LOG_ERR,
552  QString("Address %1 no longer exists - ignoring")
553  .arg(PRETTYIP(it)));
554  continue;
555  }
556 
557  if (requireall)
558  {
559  close();
560  return false;
561  }
562  }
563  }
564 
565  if (m_udpSockets.empty())
566  return false;
567 
568  m_listening = true;
569  return true;
570 }
571 
572 bool ServerPool::bind(QStringList addrstr, quint16 port, bool requireall)
573 {
574  QList<QHostAddress> addrs;
575  QStringList::const_iterator it;
576  for (it = addrstr.begin(); it != addrstr.end(); ++it)
577  addrs << QHostAddress(*it);
578  return bind(addrs, port, requireall);
579 }
580 
581 bool ServerPool::bind(quint16 port, bool requireall)
582 {
583  // cppcheck-suppress invalidFunctionArgBool
584  return bind(DefaultListen(), port, requireall);
585 }
586 
587 qint64 ServerPool::writeDatagram(const char * data, qint64 size,
588  const QHostAddress &addr, quint16 port)
589 {
590  if (!m_listening || m_udpSockets.empty())
591  {
592  LOG(VB_GENERAL, LOG_ERR, "Trying to write datagram to disconnected "
593  "ServerPool instance.");
594  return -1;
595  }
596 
597  // check if can re-use the last one, so there's no need for a linear search
598  if (!m_lastUdpSocket || !m_lastUdpSocket->contains(addr))
599  {
600  // find the right socket to use
601  QList<PrivUdpSocket*>::iterator it;
602  for (it = m_udpSockets.begin(); it != m_udpSockets.end(); ++it)
603  {
604  PrivUdpSocket *val = *it;
605  if (val->contains(addr))
606  {
607  m_lastUdpSocket = val;
608  break;
609  }
610  }
611  }
612  if (!m_lastUdpSocket)
613  return -1;
614 
615  qint64 ret = m_lastUdpSocket->writeDatagram(data, size, addr, port);
616  if (ret != size)
617  {
618  LOG(VB_GENERAL, LOG_DEBUG, QString("Error = %1 : %2")
619  .arg(ret).arg(m_lastUdpSocket->error()));
620  }
621  return ret;
622 }
623 
624 qint64 ServerPool::writeDatagram(const QByteArray &datagram,
625  const QHostAddress &addr, quint16 port)
626 {
627  return writeDatagram(datagram.data(), datagram.size(), addr, port);
628 }
629 
631 {
632  // Ignore connections from an SSL server for now, these are only handled
633  // by HttpServer which overrides newTcpConnection
634  auto *server = dynamic_cast<PrivTcpServer *>(QObject::sender());
635  if (!server || server->GetServerType() == kSSLServer)
636  return;
637 
638  auto *qsock = new QTcpSocket(this);
639  if (qsock->setSocketDescriptor(socket)
640  && gCoreContext->CheckSubnet(qsock))
641  {
642  emit newConnection(qsock);
643  }
644  else
645  delete qsock;
646 }
647 
649 {
650  auto *socket = dynamic_cast<QUdpSocket*>(sender());
651 
652  while (socket->state() == QAbstractSocket::BoundState &&
653  socket->hasPendingDatagrams())
654  {
655  QByteArray buffer;
656  buffer.resize(socket->pendingDatagramSize());
657  QHostAddress sender;
658  quint16 senderPort = 0;
659 
660  socket->readDatagram(buffer.data(), buffer.size(),
661  &sender, &senderPort);
662  if (gCoreContext->CheckSubnet(sender))
663  emit newDatagram(buffer, sender, senderPort);
664  }
665 }
666 
680 int ServerPool::tryListeningPort(int baseport, int range)
681 {
682  // try a few ports in case the first is in use
683  int port = baseport;
684  while (port < baseport + range)
685  {
686  if (listen(port))
687  {
688  break;
689  }
690  port++;
691  }
692 
693  if (port >= baseport + range)
694  {
695  return -1;
696  }
697  return port;
698 }
699 
713 int ServerPool::tryBindingPort(int baseport, int range)
714 {
715  // try a few ports in case the first is in use
716  int port = baseport;
717  while (port < baseport + range)
718  {
719  if (bind(port))
720  {
721  break;
722  }
723  port++;
724  }
725 
726  if (port >= baseport + range)
727  {
728  return -1;
729  }
730  return port;
731 }
732 
749 int ServerPool::tryListeningPort(QTcpServer *server, int baseport,
750  int range, bool *isipv6)
751 {
752  bool ipv6 = true;
753  // try a few ports in case the first is in use
754  int port = baseport;
755  while (port < baseport + range)
756  {
757  if (ipv6)
758  {
759  if (server->listen(QHostAddress::AnyIPv6, port))
760  {
761  break;
762  }
763 
764  // did we fail because IPv6 isn't available?
765  QAbstractSocket::SocketError err = server->serverError();
766  if (err == QAbstractSocket::UnsupportedSocketOperationError)
767  {
768  ipv6 = false;
769  }
770  }
771  if (!ipv6)
772  {
773  if (server->listen(QHostAddress::Any, port))
774  {
775  break;
776  }
777  }
778  port++;
779  }
780 
781  if (isipv6)
782  {
783  *isipv6 = ipv6;
784  }
785 
786  if (port >= baseport + range)
787  {
788  return -1;
789  }
790  if (port == 0)
791  {
792  port = server->serverPort();
793  }
794  return port;
795 }
796 
813 int ServerPool::tryBindingPort(QUdpSocket *socket, int baseport,
814  int range, bool *isipv6)
815 {
816  bool ipv6 = true;
817  // try a few ports in case the first is in use
818  int port = baseport;
819  while (port < baseport + range)
820  {
821  if (ipv6)
822  {
823  if (socket->bind(QHostAddress::AnyIPv6, port))
824  {
825  break;
826  }
827 
828  // did we fail because IPv6 isn't available?
829  QAbstractSocket::SocketError err = socket->error();
830  if (err == QAbstractSocket::UnsupportedSocketOperationError)
831  {
832  ipv6 = false;
833  }
834  }
835  if (!ipv6)
836  {
837  if (socket->bind(QHostAddress::Any, port))
838  {
839  break;
840  }
841  }
842  port++;
843  }
844 
845  if (isipv6)
846  {
847  *isipv6 = ipv6;
848  }
849 
850  if (port >= baseport + range)
851  {
852  return -1;
853  }
854  return port;
855 }
~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:380
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:482
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:311
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)
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:680
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:351
static QList< QHostAddress > DefaultBroadcast(void)
Definition: serverpool.cpp:325
~ServerPool(void)
Definition: serverpool.cpp:67
static QList< QHostAddress > DefaultBroadcastIPv4(void)
Definition: serverpool.cpp:336
#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:587
#define PRETTYIP_(x)
Definition: serverpool.cpp:14
void close(void)
Definition: serverpool.cpp:359
virtual void newUdpDatagram(void)
Definition: serverpool.cpp:648
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:713
virtual void newTcpConnection(qt_socket_fd_t socket)
Definition: serverpool.cpp:630
static QList< QHostAddress > DefaultListenIPv4(void)
Definition: serverpool.cpp:297
#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:289
static void RefreshDefaultListen(void)
Definition: serverpool.cpp:280
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.