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 for (
const auto & str : std::as_const(addrstr))
486 addrs << QHostAddress(str);
487 return listen(addrs, port, requireall, servertype);
500 for (
const auto & qha : std::as_const(addrs))
504 if (qha.protocol() == QAbstractSocket::IPv4Protocol
509 if (qha.protocol() == QAbstractSocket::IPv6Protocol
513 QNetworkAddressEntry host;
514 QNetworkAddressEntry wildcard;
516 if (qha.protocol() == QAbstractSocket::IPv6Protocol)
518 for (
const auto& iae : std::as_const(
naList_6))
525 if (iae.ip() == QHostAddress::AnyIPv6)
531 for (
const auto& iae : std::as_const(
naList_4))
538 if (iae.ip() == QHostAddress::AnyIPv4)
543 if (host.ip().isNull())
545 if (wildcard.ip().isNull())
547 LOG(VB_GENERAL, LOG_ERR,
548 QString(
"Failed to find local address to use for destination %1:%2.")
553 LOG(VB_GENERAL, LOG_DEBUG,
554 QString(
"Failed to find local address to use for destination %1:%2. Using wildcard.")
561 if (socket->bind(qha, port))
563 LOG(VB_GENERAL, LOG_INFO, QString(
"Binding to UDP %1:%2")
566 connect(socket, &QIODevice::readyRead,
571 LOG(VB_GENERAL, LOG_ERR,
572 QString(
"Failed binding to UDP %1:%2 - Error %3: %4")
575 .arg(socket->error())
576 .arg(socket->errorString()));
577 socket->disconnect();
578 socket->deleteLater();
580 if (socket->error() == QAbstractSocket::SocketAddressNotAvailableError)
582 LOG(VB_GENERAL, LOG_ERR,
583 QString(
"Address %1 no longer exists - ignoring")
605 QList<QHostAddress> addrs;
606 for (
const auto & str : std::as_const(addrstr))
607 addrs << QHostAddress(str);
608 return bind(addrs, port, requireall);
617 const QHostAddress &addr, quint16 port)
621 LOG(VB_GENERAL, LOG_ERR,
"Trying to write datagram to disconnected "
622 "ServerPool instance.");
630 QList<PrivUdpSocket*>::iterator it;
644 LOG(VB_GENERAL, LOG_DEBUG,
645 QString(
"No exact socket match for %1:%2. Searching for wildcard.")
649 if ((addr.protocol() == QAbstractSocket::IPv6Protocol &&
650 val->host().ip() == QHostAddress::AnyIPv6) ||
651 (val->host().ip() == QHostAddress::AnyIPv4))
660 LOG(VB_GENERAL, LOG_DEBUG, QString(
"No m_lastUdpSocket"));
667 LOG(VB_GENERAL, LOG_DEBUG, QString(
"Error = %1 : %2")
674 const QHostAddress &addr, quint16 port)
676 return writeDatagram(datagram.data(), datagram.size(), addr, port);
683 auto *server = qobject_cast<PrivTcpServer *>(QObject::sender());
684 if (!server || server->GetServerType() ==
kSSLServer)
687 auto *qsock =
new QTcpSocket(
this);
688 if (qsock->setSocketDescriptor(socket)
701 auto *socket = qobject_cast<QUdpSocket*>(sender());
703 while (socket->state() == QAbstractSocket::BoundState &&
704 socket->hasPendingDatagrams())
707 buffer.resize(socket->pendingDatagramSize());
709 quint16 senderPort = 0;
711 socket->readDatagram(buffer.data(), buffer.size(),
712 &sender, &senderPort);
735 while (port < baseport + range)
744 if (port >= baseport + range)
768 while (port < baseport + range)
777 if (port >= baseport + range)
801 int range,
bool *isipv6)
806 while (port < baseport + range)
810 if (server->listen(QHostAddress::AnyIPv6, port))
816 QAbstractSocket::SocketError err = server->serverError();
817 if (err == QAbstractSocket::UnsupportedSocketOperationError)
824 if (server->listen(QHostAddress::Any, port))
837 if (port >= baseport + range)
843 port = server->serverPort();
865 int range,
bool *isipv6)
870 while (port < baseport + range)
874 if (socket->bind(QHostAddress::AnyIPv6, port))
880 QAbstractSocket::SocketError err = socket->error();
881 if (err == QAbstractSocket::UnsupportedSocketOperationError)
888 if (socket->bind(QHostAddress::Any, port))
901 if (port >= baseport + range)
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
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