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