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