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 addrs.reserve(addrstr.size());
486 for (const auto & str : std::as_const(addrstr))
487 addrs << QHostAddress(str);
488 return listen(addrs, port, requireall, servertype);
489}
490
491bool ServerPool::listen(quint16 port, bool requireall,
492 PoolServerType servertype)
493{
494 return listen(DefaultListen(), port, requireall, servertype);
495}
496
497bool ServerPool::bind(QList<QHostAddress> addrs, quint16 port,
498 bool requireall)
499{
500 m_port = port;
501 for (const auto & qha : std::as_const(addrs))
502 {
503 // If IPV4 support is disabled and this is an IPV4 address,
504 // bypass this address
505 if (qha.protocol() == QAbstractSocket::IPv4Protocol
506 && ! gCoreContext->GetBoolSetting("IPv4Support",true))
507 continue;
508 // If IPV6 support is disabled and this is an IPV6 address,
509 // bypass this address
510 if (qha.protocol() == QAbstractSocket::IPv6Protocol
511 && ! gCoreContext->GetBoolSetting("IPv6Support",true))
512 continue;
513
514 QNetworkAddressEntry host;
515 QNetworkAddressEntry wildcard;
516
517 if (qha.protocol() == QAbstractSocket::IPv6Protocol)
518 {
519 for (const auto& iae : std::as_const(naList_6))
520 {
521 if (PrivUdpSocket::contains(iae, qha))
522 {
523 host = iae;
524 break;
525 }
526 if (iae.ip() == QHostAddress::AnyIPv6)
527 wildcard = iae;
528 }
529 }
530 else
531 {
532 for (const auto& iae : std::as_const(naList_4))
533 {
534 if (PrivUdpSocket::contains(iae, qha))
535 {
536 host = iae;
537 break;
538 }
539 if (iae.ip() == QHostAddress::AnyIPv4)
540 wildcard = iae;
541 }
542 }
543
544 if (host.ip().isNull())
545 {
546 if (wildcard.ip().isNull())
547 {
548 LOG(VB_GENERAL, LOG_ERR,
549 QString("Failed to find local address to use for destination %1:%2.")
550 .arg(prettyip(qha)).arg(port));
551 continue;
552 }
553
554 LOG(VB_GENERAL, LOG_DEBUG,
555 QString("Failed to find local address to use for destination %1:%2. Using wildcard.")
556 .arg(prettyip(qha)).arg(port));
557 host = wildcard;
558 }
559
560 auto *socket = new PrivUdpSocket(this, host);
561
562 if (socket->bind(qha, port))
563 {
564 LOG(VB_GENERAL, LOG_INFO, QString("Binding to UDP %1:%2")
565 .arg(prettyip(qha)).arg(port));
566 m_udpSockets.append(socket);
567 connect(socket, &QIODevice::readyRead,
569 }
570 else
571 {
572 LOG(VB_GENERAL, LOG_ERR,
573 QString("Failed binding to UDP %1:%2 - Error %3: %4")
574 .arg(prettyip(qha))
575 .arg(port)
576 .arg(socket->error())
577 .arg(socket->errorString()));
578 socket->disconnect();
579 socket->deleteLater();
580
581 if (socket->error() == QAbstractSocket::SocketAddressNotAvailableError)
582 {
583 LOG(VB_GENERAL, LOG_ERR,
584 QString("Address %1 no longer exists - ignoring")
585 .arg(prettyip(qha)));
586 continue;
587 }
588
589 if (requireall)
590 {
591 close();
592 return false;
593 }
594 }
595 }
596
597 if (m_udpSockets.empty())
598 return false;
599
600 m_listening = true;
601 return true;
602}
603
604bool ServerPool::bind(QStringList addrstr, quint16 port, bool requireall)
605{
606 QList<QHostAddress> addrs;
607 addrs.reserve(addrstr.size());
608 for (const auto & str : std::as_const(addrstr))
609 addrs << QHostAddress(str);
610 return bind(addrs, port, requireall);
611}
612
613bool ServerPool::bind(quint16 port, bool requireall)
614{
615 return bind(DefaultListen(), port, requireall);
616}
617
618qint64 ServerPool::writeDatagram(const char * data, qint64 size,
619 const QHostAddress &addr, quint16 port)
620{
621 if (!m_listening || m_udpSockets.empty())
622 {
623 LOG(VB_GENERAL, LOG_ERR, "Trying to write datagram to disconnected "
624 "ServerPool instance.");
625 return -1;
626 }
627
628 // check if can re-use the last one, so there's no need for a linear search
630 {
631 // find the right socket to use
632 QList<PrivUdpSocket*>::iterator it;
633 for (it = m_udpSockets.begin(); it != m_udpSockets.end(); ++it)
634 {
635 PrivUdpSocket *val = *it;
636 if (val->contains(addr))
637 {
638 m_lastUdpSocket = val;
639 break;
640 }
641 }
642 }
643 if (!m_lastUdpSocket)
644 {
645 // Couldn't find an exact socket. See is there is a wildcard one.
646 LOG(VB_GENERAL, LOG_DEBUG,
647 QString("No exact socket match for %1:%2. Searching for wildcard.")
648 .arg(prettyip(addr)).arg(port));
649 for (auto *val : std::as_const(m_udpSockets))
650 {
651 if ((addr.protocol() == QAbstractSocket::IPv6Protocol &&
652 val->host().ip() == QHostAddress::AnyIPv6) ||
653 (val->host().ip() == QHostAddress::AnyIPv4))
654 {
655 m_lastUdpSocket = val;
656 break;
657 }
658 }
659 }
660 if (!m_lastUdpSocket)
661 {
662 LOG(VB_GENERAL, LOG_DEBUG, QString("No m_lastUdpSocket"));
663 return -1;
664 }
665
666 qint64 ret = m_lastUdpSocket->writeDatagram(data, size, addr, port);
667 if (ret != size)
668 {
669 LOG(VB_GENERAL, LOG_DEBUG, QString("Error = %1 : %2")
670 .arg(ret).arg(m_lastUdpSocket->error()));
671 }
672 return ret;
673}
674
675qint64 ServerPool::writeDatagram(const QByteArray &datagram,
676 const QHostAddress &addr, quint16 port)
677{
678 return writeDatagram(datagram.data(), datagram.size(), addr, port);
679}
680
682{
683 // Ignore connections from an SSL server for now, these are only handled
684 // by HttpServer which overrides newTcpConnection
685 auto *server = qobject_cast<PrivTcpServer *>(QObject::sender());
686 if (!server || server->GetServerType() == kSSLServer)
687 return;
688
689 auto *qsock = new QTcpSocket(this);
690 if (qsock->setSocketDescriptor(socket)
691 && gCoreContext->CheckSubnet(qsock))
692 {
693 emit newConnection(qsock);
694 }
695 else
696 {
697 delete qsock;
698 }
699}
700
702{
703 auto *socket = qobject_cast<QUdpSocket*>(sender());
704
705 while (socket->state() == QAbstractSocket::BoundState &&
706 socket->hasPendingDatagrams())
707 {
708 QByteArray buffer;
709 buffer.resize(socket->pendingDatagramSize());
710 QHostAddress sender;
711 quint16 senderPort = 0;
712
713 socket->readDatagram(buffer.data(), buffer.size(),
714 &sender, &senderPort);
715 if (gCoreContext->CheckSubnet(sender))
716 emit newDatagram(buffer, sender, senderPort);
717 }
718}
719
733int ServerPool::tryListeningPort(int baseport, int range)
734{
735 // try a few ports in case the first is in use
736 int port = baseport;
737 while (port < baseport + range)
738 {
739 if (listen(port))
740 {
741 break;
742 }
743 port++;
744 }
745
746 if (port >= baseport + range)
747 {
748 return -1;
749 }
750 return port;
751}
752
766int ServerPool::tryBindingPort(int baseport, int range)
767{
768 // try a few ports in case the first is in use
769 int port = baseport;
770 while (port < baseport + range)
771 {
772 if (bind(port))
773 {
774 break;
775 }
776 port++;
777 }
778
779 if (port >= baseport + range)
780 {
781 return -1;
782 }
783 return port;
784}
785
802int ServerPool::tryListeningPort(QTcpServer *server, int baseport,
803 int range, bool *isipv6)
804{
805 bool ipv6 = true;
806 // try a few ports in case the first is in use
807 int port = baseport;
808 while (port < baseport + range)
809 {
810 if (ipv6)
811 {
812 if (server->listen(QHostAddress::AnyIPv6, port))
813 {
814 break;
815 }
816
817 // did we fail because IPv6 isn't available?
818 QAbstractSocket::SocketError err = server->serverError();
819 if (err == QAbstractSocket::UnsupportedSocketOperationError)
820 {
821 ipv6 = false;
822 }
823 }
824 if (!ipv6)
825 {
826 if (server->listen(QHostAddress::Any, port))
827 {
828 break;
829 }
830 }
831 port++;
832 }
833
834 if (isipv6)
835 {
836 *isipv6 = ipv6;
837 }
838
839 if (port >= baseport + range)
840 {
841 return -1;
842 }
843 if (port == 0)
844 {
845 port = server->serverPort();
846 }
847 return port;
848}
849
866int ServerPool::tryBindingPort(QUdpSocket *socket, int baseport,
867 int range, bool *isipv6)
868{
869 bool ipv6 = true;
870 // try a few ports in case the first is in use
871 int port = baseport;
872 while (port < baseport + range)
873 {
874 if (ipv6)
875 {
876 if (socket->bind(QHostAddress::AnyIPv6, port))
877 {
878 break;
879 }
880
881 // did we fail because IPv6 isn't available?
882 QAbstractSocket::SocketError err = socket->error();
883 if (err == QAbstractSocket::UnsupportedSocketOperationError)
884 {
885 ipv6 = false;
886 }
887 }
888 if (!ipv6)
889 {
890 if (socket->bind(QHostAddress::Any, port))
891 {
892 break;
893 }
894 }
895 port++;
896 }
897
898 if (isipv6)
899 {
900 *isipv6 = ipv6;
901 }
902
903 if (port >= baseport + range)
904 {
905 return -1;
906 }
907 return port;
908}
909
910#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:497
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:733
int tryBindingPort(int baseport, int range=1)
tryBindingPort
Definition: serverpool.cpp:766
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:681
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:701
qint64 writeDatagram(const char *data, qint64 size, const QHostAddress &addr, quint16 port)
Definition: serverpool.cpp:618
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