2#include <QNetworkAddressEntry>
3#include <QReadWriteLock>
15 if (x.protocol() == QAbstractSocket::IPv6Protocol)
16 return "[" + x.toString().toLower() +
"]";
17 return x.toString().toLower();
21#define LOC QString("ServerPool: ")
29 QHostAddress::parseSubnet(
"169.254.0.0/16");
31 QHostAddress::parseSubnet(
"fe80::/10");
39 QNetworkAddressEntry
host()
47 static bool contains(
const QNetworkAddressEntry&
host,
const QHostAddress& addr)
49 if (addr.protocol() == QAbstractSocket::IPv6Protocol &&
51 host.ip().scopeId() != addr.scopeId())
55 return addr.isInSubnet(
host.ip(),
host.prefixLength());
62 : QTcpServer(parent), m_serverType(
type)
80 QReadLocker rlock(&
naLock);
86 QWriteLocker wlock(&
naLock);
92 QNetworkAddressEntry entry;
93 entry.setIp(QHostAddress(QHostAddress::AnyIPv4));
95 entry.setIp(QHostAddress(QHostAddress::AnyIPv6));
105 bool v4IsSet = config_v4.isNull();
110 bool v6IsSet = config_v6.isNull();
114 QList<QNetworkInterface> IFs = QNetworkInterface::allInterfaces();
115 for (
const auto & qni : std::as_const(IFs))
117 if ((qni.flags() & QNetworkInterface::IsRunning) == 0)
120 QList<QNetworkAddressEntry> IPs = qni.addressEntries();
124 for (
auto qnai = IPs.begin(); qnai != IPs.end(); ++qnai)
126 QHostAddress ip = qnai->ip();
127 if (ip.protocol() == QAbstractSocket::IPv4Protocol)
133 if (!config_v4.isNull() && (ip == config_v4))
136 LOG(VB_GENERAL, LOG_DEBUG,
137 QString(
"Adding BackendServerIP to address list."));
143 else if (ip == QHostAddress::LocalHost)
146 LOG(VB_GENERAL, LOG_DEBUG,
147 QString(
"Adding IPv4 loopback to address list."));
149 if (!v4IsSet && (config_v4 == ip))
153 else if (ip.isInSubnet(
kLinkLocal) && allowLinkLocal)
158 LOG(VB_GENERAL, LOG_DEBUG,
159 QString(
"Adding link-local '%1' to address list.")
164 else if (config_v4.isNull())
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");
175 if (ip.isInSubnet(s_privNet1) || ip.isInSubnet(s_privNet2) ||
176 ip.isInSubnet(s_privNet3))
178 LOG(VB_GENERAL, LOG_DEBUG,
179 QString(
"Adding '%1' to address list.")
185 LOG(VB_GENERAL, LOG_DEBUG,
186 QString(
"Adding link-local '%1' to address list.")
192 LOG(VB_GENERAL, LOG_DEBUG, QString(
"Skipping "
193 "non-private address during IPv4 autoselection: %1")
200 LOG(VB_GENERAL, LOG_DEBUG, QString(
"Skipping address: %1")
210 ip.setScopeId(qni.name());
218 if ((!config_v6.isNull()) && (ip == config_v6))
221 LOG(VB_GENERAL, LOG_DEBUG,
222 QString(
"Adding BackendServerIP6 to address list."));
227 else if (ip == QHostAddress::LocalHostIPv6)
230 LOG(VB_GENERAL, LOG_DEBUG,
231 QString(
"Adding IPv6 loopback to address list."));
233 if (!v6IsSet && (config_v6 == ip))
237 else if (ip.isInSubnet(
kLinkLocal6) && allowLinkLocal)
242 LOG(VB_GENERAL, LOG_DEBUG,
243 QString(
"Adding link-local '%1' to address list.")
244 .arg(ip.toString()));
248 else if (config_v6.isNull())
252 LOG(VB_GENERAL, LOG_DEBUG,
253 QString(
"Adding link-local '%1' to address list.")
258 LOG(VB_GENERAL, LOG_DEBUG,
259 QString(
"Adding '%1' to address list.")
268 LOG(VB_GENERAL, LOG_DEBUG, QString(
"Skipping address: %1")
275 if (!v4IsSet && (config_v4 != QHostAddress::LocalHost)
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()));
283 if (!v6IsSet && (config_v6 != QHostAddress::LocalHostIPv6)
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)));
308 QList<QHostAddress> alist;
317 QReadLocker rlock(&
naLock);
319 QList<QHostAddress> alist;
320 for (
const auto & nae : std::as_const(
naList_4))
321 if (!alist.contains(nae.ip()))
330 QReadLocker rlock(&
naLock);
332 QList<QHostAddress> alist;
333 for (
const auto & nae : std::as_const(
naList_6))
334 if (!alist.contains(nae.ip()))
342 QList<QHostAddress> blist;
354 QReadLocker rlock(&
naLock);
356 QList<QHostAddress> blist;
357 for (
const auto & nae : std::as_const(
naList_4))
359 if (!blist.contains(nae.broadcast()) && (nae.prefixLength() != 32) &&
360 (nae.ip() != QHostAddress::LocalHost))
361 blist << nae.broadcast();
369 QList<QHostAddress> blist;
370 blist << QHostAddress(
"FF02::1");
380 server->disconnect();
382 server->deleteLater();
388 socket->disconnect();
390 socket->deleteLater();
400 for (
const auto & qha : std::as_const(addrs))
404 if (qha.protocol() == QAbstractSocket::IPv4Protocol
409 if (qha.protocol() == QAbstractSocket::IPv6Protocol
420 if (server->listen(qha,
m_port))
422 LOG(VB_GENERAL, LOG_INFO, QString(
"Listening on TCP%1 %2:%3")
423 .arg(servertype ==
kSSLServer ?
" (SSL)" :
"",
424 prettyip(qha), QString::number(port)));
428 m_port = server->serverPort();
432 LOG(VB_GENERAL, LOG_ERR,
433 QString(
"Failed listening on TCP %1:%2 - Error %3: %4")
436 .arg(server->serverError())
437 .arg(server->errorString()));
438 server->disconnect();
439 server->deleteLater();
441 if (server->serverError() == QAbstractSocket::HostNotFoundError ||
442 server->serverError() == QAbstractSocket::SocketAddressNotAvailableError)
444 LOG(VB_GENERAL, LOG_ERR,
445 QString(
"Address %1 no longer exists - ignoring")
450 if (server->serverError() == QAbstractSocket::UnsupportedSocketOperationError
451 && qha.protocol() == QAbstractSocket::IPv4Protocol)
453 LOG(VB_GENERAL, LOG_INFO,
454 QString(
"IPv4 support failed for this port."));
458 if (server->serverError() == QAbstractSocket::UnsupportedSocketOperationError
459 && qha.protocol() == QAbstractSocket::IPv6Protocol)
461 LOG(VB_GENERAL, LOG_INFO,
462 QString(
"IPv6 support failed for this port."));
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);
501 for (
const auto & qha : std::as_const(addrs))
505 if (qha.protocol() == QAbstractSocket::IPv4Protocol
510 if (qha.protocol() == QAbstractSocket::IPv6Protocol
514 QNetworkAddressEntry host;
515 QNetworkAddressEntry wildcard;
517 if (qha.protocol() == QAbstractSocket::IPv6Protocol)
519 for (
const auto& iae : std::as_const(
naList_6))
526 if (iae.ip() == QHostAddress::AnyIPv6)
532 for (
const auto& iae : std::as_const(
naList_4))
539 if (iae.ip() == QHostAddress::AnyIPv4)
544 if (host.ip().isNull())
546 if (wildcard.ip().isNull())
548 LOG(VB_GENERAL, LOG_ERR,
549 QString(
"Failed to find local address to use for destination %1:%2.")
554 LOG(VB_GENERAL, LOG_DEBUG,
555 QString(
"Failed to find local address to use for destination %1:%2. Using wildcard.")
562 if (socket->bind(qha, port))
564 LOG(VB_GENERAL, LOG_INFO, QString(
"Binding to UDP %1:%2")
567 connect(socket, &QIODevice::readyRead,
572 LOG(VB_GENERAL, LOG_ERR,
573 QString(
"Failed binding to UDP %1:%2 - Error %3: %4")
576 .arg(socket->error())
577 .arg(socket->errorString()));
578 socket->disconnect();
579 socket->deleteLater();
581 if (socket->error() == QAbstractSocket::SocketAddressNotAvailableError)
583 LOG(VB_GENERAL, LOG_ERR,
584 QString(
"Address %1 no longer exists - ignoring")
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);
619 const QHostAddress &addr, quint16 port)
623 LOG(VB_GENERAL, LOG_ERR,
"Trying to write datagram to disconnected "
624 "ServerPool instance.");
632 QList<PrivUdpSocket*>::iterator it;
646 LOG(VB_GENERAL, LOG_DEBUG,
647 QString(
"No exact socket match for %1:%2. Searching for wildcard.")
651 if ((addr.protocol() == QAbstractSocket::IPv6Protocol &&
652 val->host().ip() == QHostAddress::AnyIPv6) ||
653 (val->host().ip() == QHostAddress::AnyIPv4))
662 LOG(VB_GENERAL, LOG_DEBUG, QString(
"No m_lastUdpSocket"));
669 LOG(VB_GENERAL, LOG_DEBUG, QString(
"Error = %1 : %2")
676 const QHostAddress &addr, quint16 port)
678 return writeDatagram(datagram.data(), datagram.size(), addr, port);
685 auto *server = qobject_cast<PrivTcpServer *>(QObject::sender());
686 if (!server || server->GetServerType() ==
kSSLServer)
689 auto *qsock =
new QTcpSocket(
this);
690 if (qsock->setSocketDescriptor(socket)
703 auto *socket = qobject_cast<QUdpSocket*>(sender());
705 while (socket->state() == QAbstractSocket::BoundState &&
706 socket->hasPendingDatagrams())
709 buffer.resize(socket->pendingDatagramSize());
711 quint16 senderPort = 0;
713 socket->readDatagram(buffer.data(), buffer.size(),
714 &sender, &senderPort);
737 while (port < baseport + range)
746 if (port >= baseport + range)
770 while (port < baseport + range)
779 if (port >= baseport + range)
803 int range,
bool *isipv6)
808 while (port < baseport + range)
812 if (server->listen(QHostAddress::AnyIPv6, port))
818 QAbstractSocket::SocketError err = server->serverError();
819 if (err == QAbstractSocket::UnsupportedSocketOperationError)
826 if (server->listen(QHostAddress::Any, port))
839 if (port >= baseport + range)
845 port = server->serverPort();
867 int range,
bool *isipv6)
872 while (port < baseport + range)
876 if (socket->bind(QHostAddress::AnyIPv6, port))
882 QAbstractSocket::SocketError err = socket->error();
883 if (err == QAbstractSocket::UnsupportedSocketOperationError)
890 if (socket->bind(QHostAddress::Any, port))
903 if (port >= baseport + range)
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
PrivTcpServer(QObject *parent=nullptr, PoolServerType type=kTCPServer)
void newConnection(qintptr socket)
QNetworkAddressEntry m_host
QNetworkAddressEntry host()
PrivUdpSocket(QObject *parent, const QNetworkAddressEntry &host)
~PrivUdpSocket() override=default
static bool contains(const QNetworkAddressEntry &host, const QHostAddress &addr)
bool contains(const QHostAddress &addr)
bool bind(QList< QHostAddress > addrs, quint16 port, bool requireall=true)
static QList< QHostAddress > DefaultListenIPv4(void)
void newDatagram(QByteArray, QHostAddress, quint16)
static QList< QHostAddress > DefaultListen(void)
bool listen(QList< QHostAddress > addrs, quint16 port, bool requireall=true, PoolServerType type=kTCPServer)
int tryListeningPort(int baseport, int range=1)
tryListeningPort
int tryBindingPort(int baseport, int range=1)
tryBindingPort
QList< PrivUdpSocket * > m_udpSockets
~ServerPool(void) override
PrivUdpSocket * m_lastUdpSocket
static QList< QHostAddress > DefaultBroadcast(void)
virtual void newTcpConnection(qintptr socket)
static QList< QHostAddress > DefaultListenIPv6(void)
QList< PrivTcpServer * > m_tcpServers
static QList< QHostAddress > DefaultBroadcastIPv6(void)
void newConnection(QTcpSocket *)
virtual void newUdpDatagram(void)
qint64 writeDatagram(const char *data, qint64 size, const QHostAddress &addr, quint16 port)
static void SelectDefaultListen(bool force=false)
static QList< QHostAddress > DefaultBroadcastIPv4(void)
static void RefreshDefaultListen(void)
MythCoreContext * gCoreContext
This global variable contains the MythCoreContext instance for the app.
#define LOG(_MASK_, _LEVEL_, _QSTRING_)
static QPair< QHostAddress, int > kLinkLocal6
static QString prettyip(const QHostAddress &x)
static QReadWriteLock naLock
static QList< QNetworkAddressEntry > naList_6
static QList< QNetworkAddressEntry > naList_4
static QPair< QHostAddress, int > kLinkLocal