26#if QT_VERSION >= QT_VERSION_CHECK(6,5,0)
27#include <QtSystemDetection>
29#include <QCoreApplication>
30#include <QHostAddress>
33#include <QNetworkInterface>
34#include <QNetworkAddressEntry>
43#define LOC QString("PortChecker::%1(): ").arg(__func__)
65 LOG(VB_GENERAL, LOG_DEBUG,
LOC + QString(
"host %1 port %2 timeLimit %3")
66 .arg(host).arg(port).arg(timeLimit.count()));
72 bool isIPAddress = addr.setAddress(host);
74 && addr.protocol() == QAbstractSocket::IPv6Protocol
75 && addr.isInSubnet(QHostAddress::parseSubnet(
"fe80::/10")))
82 socket.connectToHost(host, port);
84 QAbstractSocket::SocketState state = QAbstractSocket::UnconnectedState;
85 while (state != QAbstractSocket::ConnectedState
86 && (timer.
elapsed() < timeLimit)
90 static constexpr std::chrono::milliseconds k_poll_interval {1ms};
91 QCoreApplication::processEvents(QEventLoop::AllEvents, k_poll_interval.count());
92 std::this_thread::sleep_for(1ns);
93 state = socket.state();
95 state = socket.state();
96 LOG(VB_GENERAL, LOG_DEBUG,
LOC +
97 QString(
"host %1 port %2 socket state %3, attempt time: %4")
98 .arg(host, QString::number(port), QString::number(state),
99 QString::number(timer.
elapsed().count())
102 return (state == QAbstractSocket::ConnectedState);
147 LOG(VB_GENERAL, LOG_DEBUG,
LOC + QString(
"host %1 port %2 timeLimit %3")
148 .arg(host).arg(port).arg(timeLimit.count()));
151 bool isIPAddress = addr.setAddress(host);
153 && addr.protocol() == QAbstractSocket::IPv6Protocol
154 && addr.isInSubnet(QHostAddress::parseSubnet(
"fe80::/10")))
159 host = addr.toString();
167 QList<QNetworkInterface> cards = QNetworkInterface::allInterfaces();
168 auto iCard = cards.cbegin();
170 QAbstractSocket::SocketState state = QAbstractSocket::UnconnectedState;
172 while (state != QAbstractSocket::ConnectedState
173 && (timer.
elapsed() < timeLimit)
178 addr.setScopeId(QString());
179 while (addr.scopeId().isEmpty())
182 if (iCard != cards.cend())
184 unsigned int flags = iCard->flags();
185 if (!(flags & QNetworkInterface::IsLoopBack)
186 && (flags & QNetworkInterface::IsRunning))
189 QList<QNetworkAddressEntry> addresses = iCard->addressEntries();
190 for (
const auto& ae : std::as_const(addresses))
192 if (ae.ip().protocol() == QAbstractSocket::IPv6Protocol)
194 addr.setScopeId(iCard->name());
206 LOG(VB_GENERAL, LOG_ERR,
LOC +
207 QString(
"There is no IPV6 compatible interface for %1").arg(host)
213 cards = QNetworkInterface::allInterfaces();
214 iCard = cards.cbegin();
217 LOG(VB_GENERAL, LOG_DEBUG, QString(
"Checking host %1 port %2")
218 .arg(addr.toString(), QString::number(port))
221 socket.connectToHost(addr.toString(), port);
222 std::chrono::milliseconds attempt_time_limit
223 {std::min(3s + timer.
elapsed(), timeLimit)};
224 while (state != QAbstractSocket::ConnectedState
226 && timer.
elapsed() < attempt_time_limit
229 static constexpr std::chrono::milliseconds k_poll_interval {1ms};
230 QCoreApplication::processEvents(QEventLoop::AllEvents, k_poll_interval.count());
231 std::this_thread::sleep_for(1ns);
232 state = socket.state();
234 state = socket.state();
235 LOG(VB_GENERAL, LOG_DEBUG,
LOC +
236 QString(
"host %1 port %2 socket state %3, attempt time: %4")
237 .arg(host, QString::number(port), QString::number(state),
238 QString::number(timer.
elapsed().count())
242 if (state == QAbstractSocket::ConnectedState && !addr.scopeId().isEmpty())
245 host = addr.toString();
247 return (state == QAbstractSocket::ConnectedState);
260 LOG(VB_GENERAL, LOG_DEBUG,
LOC + QString(
"Aborting port check"));
void SetScopeForAddress(const QHostAddress &addr)
Record the scope Id of the given IP address.
bool GetScopeForAddress(QHostAddress &addr) const
Return the cached scope Id for the given address.
A QElapsedTimer based timer to replace use of QTime as a timer.
std::chrono::milliseconds elapsed(void)
Returns milliseconds elapsed since last start() or restart()
bool resolveLinkLocal(QString &host, int port, std::chrono::milliseconds timeLimit=30s)
Convenience method to resolve link-local address.
void cancelPortCheck(void)
Cancel the checkPort operation currently in progress.
bool checkPort(const QString &host, int port, std::chrono::milliseconds timeLimit=30s)
Check if a port is open.
MythCoreContext * gCoreContext
This global variable contains the MythCoreContext instance for the app.
#define LOG(_MASK_, _LEVEL_, _QSTRING_)