mirror of
https://github.com/moonlight-stream/moonlight-qt
synced 2024-12-13 21:02:28 +00:00
Add support for zero configuration IPv6 streaming
This commit is contained in:
parent
bcbd1a5b4b
commit
6f9c3fbc38
6 changed files with 122 additions and 24 deletions
|
@ -216,6 +216,42 @@ void ComputerManager::saveHosts()
|
||||||
settings.endArray();
|
settings.endArray();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
QHostAddress ComputerManager::getBestGlobalAddressV6(QVector<QHostAddress> &addresses)
|
||||||
|
{
|
||||||
|
for (const QHostAddress& address : addresses) {
|
||||||
|
if (address.protocol() == QAbstractSocket::IPv6Protocol) {
|
||||||
|
if (address.isInSubnet(QHostAddress("fe80::"), 10)) {
|
||||||
|
// Link-local
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (address.isInSubnet(QHostAddress("fec0::"), 10)) {
|
||||||
|
qInfo() << "Ignoring site-local address:" << address;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (address.isInSubnet(QHostAddress("fc00::"), 7)) {
|
||||||
|
qInfo() << "Ignoring ULA:" << address;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (address.isInSubnet(QHostAddress("2002::"), 16)) {
|
||||||
|
qInfo() << "Ignoring 6to4 address:" << address;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (address.isInSubnet(QHostAddress("2001::"), 32)) {
|
||||||
|
qInfo() << "Ignoring Teredo address:" << address;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
return address;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return QHostAddress();
|
||||||
|
}
|
||||||
|
|
||||||
void ComputerManager::startPolling()
|
void ComputerManager::startPolling()
|
||||||
{
|
{
|
||||||
QWriteLocker lock(&m_Lock);
|
QWriteLocker lock(&m_Lock);
|
||||||
|
@ -234,8 +270,8 @@ void ComputerManager::startPolling()
|
||||||
qInfo() << "Discovered mDNS host:" << service.hostname();
|
qInfo() << "Discovered mDNS host:" << service.hostname();
|
||||||
|
|
||||||
MdnsPendingComputer* pendingComputer = new MdnsPendingComputer(&m_MdnsServer, &m_MdnsCache, service);
|
MdnsPendingComputer* pendingComputer = new MdnsPendingComputer(&m_MdnsServer, &m_MdnsCache, service);
|
||||||
connect(pendingComputer, SIGNAL(resolvedv4(MdnsPendingComputer*,QHostAddress)),
|
connect(pendingComputer, &MdnsPendingComputer::resolvedHost,
|
||||||
this, SLOT(handleMdnsServiceResolved(MdnsPendingComputer*,QHostAddress)));
|
this, &ComputerManager::handleMdnsServiceResolved);
|
||||||
m_PendingResolution.append(pendingComputer);
|
m_PendingResolution.append(pendingComputer);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
@ -277,11 +313,39 @@ void ComputerManager::startPollingComputer(NvComputer* computer)
|
||||||
}
|
}
|
||||||
|
|
||||||
void ComputerManager::handleMdnsServiceResolved(MdnsPendingComputer* computer,
|
void ComputerManager::handleMdnsServiceResolved(MdnsPendingComputer* computer,
|
||||||
const QHostAddress& address)
|
QVector<QHostAddress>& addresses)
|
||||||
{
|
{
|
||||||
qInfo() << "Resolved" << computer->hostname() << "to" << address.toString();
|
QHostAddress v6Global = getBestGlobalAddressV6(addresses);
|
||||||
|
bool added = false;
|
||||||
|
|
||||||
addNewHost(address.toString(), true);
|
// Add the host using the IPv4 address
|
||||||
|
for (const QHostAddress& address : addresses) {
|
||||||
|
if (address.protocol() == QAbstractSocket::IPv4Protocol) {
|
||||||
|
// NB: We don't just call addNewHost() here with v6Global because the IPv6
|
||||||
|
// address may not be reachable (if the user hasn't installed the IPv6 helper yet
|
||||||
|
// or if this host lacks outbound IPv6 capability). We want to add IPv6 even if
|
||||||
|
// it's not currently reachable.
|
||||||
|
addNewHost(address.toString(), true, v6Global);
|
||||||
|
added = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!added) {
|
||||||
|
// If we get here, there wasn't an IPv4 address so we'll do it v6-only
|
||||||
|
for (const QHostAddress& address : addresses) {
|
||||||
|
if (address.protocol() == QAbstractSocket::IPv6Protocol) {
|
||||||
|
// Use a link-local or site-local address for the "local address"
|
||||||
|
if (address.isInSubnet(QHostAddress("fe80::"), 10) ||
|
||||||
|
address.isInSubnet(QHostAddress("fec0::"), 10) ||
|
||||||
|
address.isInSubnet(QHostAddress("fc00::"), 7)) {
|
||||||
|
addNewHost(address.toString(), true, v6Global);
|
||||||
|
added = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
m_PendingResolution.removeOne(computer);
|
m_PendingResolution.removeOne(computer);
|
||||||
computer->deleteLater();
|
computer->deleteLater();
|
||||||
|
@ -508,9 +572,10 @@ class PendingAddTask : public QObject, public QRunnable
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
|
|
||||||
public:
|
public:
|
||||||
PendingAddTask(ComputerManager* computerManager, QString address, bool mdns)
|
PendingAddTask(ComputerManager* computerManager, QString address, QHostAddress mdnsIpv6Address, bool mdns)
|
||||||
: m_ComputerManager(computerManager),
|
: m_ComputerManager(computerManager),
|
||||||
m_Address(address),
|
m_Address(address),
|
||||||
|
m_MdnsIpv6Address(mdnsIpv6Address),
|
||||||
m_Mdns(mdns)
|
m_Mdns(mdns)
|
||||||
{
|
{
|
||||||
connect(this, &PendingAddTask::computerAddCompleted,
|
connect(this, &PendingAddTask::computerAddCompleted,
|
||||||
|
@ -560,7 +625,7 @@ private:
|
||||||
{
|
{
|
||||||
NvHTTP http(m_Address, QSslCertificate());
|
NvHTTP http(m_Address, QSslCertificate());
|
||||||
|
|
||||||
qInfo() << "Processing new PC at" << m_Address << "from" << (m_Mdns ? "mDNS" : "user");
|
qInfo() << "Processing new PC at" << m_Address << "from" << (m_Mdns ? "mDNS" : "user") << m_MdnsIpv6Address;
|
||||||
|
|
||||||
// Perform initial serverinfo fetch over HTTP since we don't know which cert to use
|
// Perform initial serverinfo fetch over HTTP since we don't know which cert to use
|
||||||
QString serverInfo = fetchServerInfo(http);
|
QString serverInfo = fetchServerInfo(http);
|
||||||
|
@ -606,6 +671,11 @@ private:
|
||||||
else {
|
else {
|
||||||
qWarning() << "STUN failed to get WAN address:" << err;
|
qWarning() << "STUN failed to get WAN address:" << err;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!m_MdnsIpv6Address.isNull()) {
|
||||||
|
Q_ASSERT(m_MdnsIpv6Address.protocol() == QAbstractSocket::IPv6Protocol);
|
||||||
|
newComputer->ipv6Address = m_MdnsIpv6Address.toString();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
newComputer->manualAddress = m_Address;
|
newComputer->manualAddress = m_Address;
|
||||||
|
@ -657,14 +727,15 @@ private:
|
||||||
|
|
||||||
ComputerManager* m_ComputerManager;
|
ComputerManager* m_ComputerManager;
|
||||||
QString m_Address;
|
QString m_Address;
|
||||||
|
QHostAddress m_MdnsIpv6Address;
|
||||||
bool m_Mdns;
|
bool m_Mdns;
|
||||||
};
|
};
|
||||||
|
|
||||||
void ComputerManager::addNewHost(QString address, bool mdns)
|
void ComputerManager::addNewHost(QString address, bool mdns, QHostAddress mdnsIpv6Address)
|
||||||
{
|
{
|
||||||
// Punt to a worker thread to avoid stalling the
|
// Punt to a worker thread to avoid stalling the
|
||||||
// UI while waiting for serverinfo query to complete
|
// UI while waiting for serverinfo query to complete
|
||||||
PendingAddTask* addTask = new PendingAddTask(this, address, mdns);
|
PendingAddTask* addTask = new PendingAddTask(this, address, mdnsIpv6Address, mdns);
|
||||||
QThreadPool::globalInstance()->start(addTask);
|
QThreadPool::globalInstance()->start(addTask);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -13,6 +13,7 @@
|
||||||
#include <QReadWriteLock>
|
#include <QReadWriteLock>
|
||||||
#include <QSettings>
|
#include <QSettings>
|
||||||
#include <QRunnable>
|
#include <QRunnable>
|
||||||
|
#include <QTimer>
|
||||||
|
|
||||||
class MdnsPendingComputer : public QObject
|
class MdnsPendingComputer : public QObject
|
||||||
{
|
{
|
||||||
|
@ -25,8 +26,8 @@ public:
|
||||||
: m_Hostname(service.hostname()),
|
: m_Hostname(service.hostname()),
|
||||||
m_Resolver(server, m_Hostname, cache)
|
m_Resolver(server, m_Hostname, cache)
|
||||||
{
|
{
|
||||||
connect(&m_Resolver, SIGNAL(resolved(QHostAddress)),
|
connect(&m_Resolver, &QMdnsEngine::Resolver::resolved,
|
||||||
this, SLOT(handleResolved(QHostAddress)));
|
this, &MdnsPendingComputer::handleResolvedAddress);
|
||||||
}
|
}
|
||||||
|
|
||||||
QString hostname()
|
QString hostname()
|
||||||
|
@ -35,20 +36,31 @@ public:
|
||||||
}
|
}
|
||||||
|
|
||||||
private slots:
|
private slots:
|
||||||
void handleResolved(const QHostAddress& address)
|
void handleResolvedTimeout()
|
||||||
{
|
{
|
||||||
if (address.protocol() == QAbstractSocket::IPv4Protocol) {
|
Q_ASSERT(!m_Addresses.isEmpty());
|
||||||
m_Resolver.disconnect();
|
emit resolvedHost(this, m_Addresses);
|
||||||
emit resolvedv4(this, address);
|
}
|
||||||
|
|
||||||
|
void handleResolvedAddress(const QHostAddress& address)
|
||||||
|
{
|
||||||
|
qInfo() << "Resolved" << hostname() << "to" << address;
|
||||||
|
m_Addresses.push_back(address);
|
||||||
|
|
||||||
|
// Now that we got an address, start a timer to wait for more
|
||||||
|
// addresses to come in before reporting them
|
||||||
|
if (m_Addresses.count() == 1) {
|
||||||
|
QTimer::singleShot(1000, this, SLOT(handleResolvedTimeout()));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
signals:
|
signals:
|
||||||
void resolvedv4(MdnsPendingComputer*, const QHostAddress&);
|
void resolvedHost(MdnsPendingComputer*,QVector<QHostAddress>&);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
QByteArray m_Hostname;
|
QByteArray m_Hostname;
|
||||||
QMdnsEngine::Resolver m_Resolver;
|
QMdnsEngine::Resolver m_Resolver;
|
||||||
|
QVector<QHostAddress> m_Addresses;
|
||||||
};
|
};
|
||||||
|
|
||||||
class ComputerPollingEntry
|
class ComputerPollingEntry
|
||||||
|
@ -140,7 +152,7 @@ public:
|
||||||
|
|
||||||
Q_INVOKABLE void stopPollingAsync();
|
Q_INVOKABLE void stopPollingAsync();
|
||||||
|
|
||||||
Q_INVOKABLE void addNewHost(QString address, bool mdns);
|
Q_INVOKABLE void addNewHost(QString address, bool mdns, QHostAddress mdnsIpv6Address = QHostAddress());
|
||||||
|
|
||||||
void pairHost(NvComputer* computer, QString pin);
|
void pairHost(NvComputer* computer, QString pin);
|
||||||
|
|
||||||
|
@ -165,11 +177,13 @@ private slots:
|
||||||
|
|
||||||
void handleComputerStateChanged(NvComputer* computer);
|
void handleComputerStateChanged(NvComputer* computer);
|
||||||
|
|
||||||
void handleMdnsServiceResolved(MdnsPendingComputer* computer, const QHostAddress& address);
|
void handleMdnsServiceResolved(MdnsPendingComputer* computer, QVector<QHostAddress>& addresses);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void saveHosts();
|
void saveHosts();
|
||||||
|
|
||||||
|
QHostAddress getBestGlobalAddressV6(QVector<QHostAddress>& addresses);
|
||||||
|
|
||||||
void startPollingComputer(NvComputer* computer);
|
void startPollingComputer(NvComputer* computer);
|
||||||
|
|
||||||
int m_PollingRef;
|
int m_PollingRef;
|
||||||
|
|
|
@ -39,11 +39,18 @@ void ComputerSeeker::onComputerUpdated(NvComputer *computer)
|
||||||
bool ComputerSeeker::matchComputer(NvComputer *computer) const
|
bool ComputerSeeker::matchComputer(NvComputer *computer) const
|
||||||
{
|
{
|
||||||
QString value = m_ComputerName.toLower();
|
QString value = m_ComputerName.toLower();
|
||||||
return computer->name.toLower() == value ||
|
|
||||||
computer->localAddress.toLower() == value ||
|
if (computer->name.toLower() == value || computer->uuid.toLower() == value) {
|
||||||
computer->remoteAddress.toLower() == value ||
|
return true;
|
||||||
computer->manualAddress.toLower() == value ||
|
}
|
||||||
computer->uuid.toLower() == value;
|
|
||||||
|
for (const QString& addr : computer->uniqueAddresses()) {
|
||||||
|
if (addr.toLower() == value) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool ComputerSeeker::isOnline(NvComputer *computer) const
|
bool ComputerSeeker::isOnline(NvComputer *computer) const
|
||||||
|
|
|
@ -10,6 +10,7 @@
|
||||||
#define SER_LOCALADDR "localaddress"
|
#define SER_LOCALADDR "localaddress"
|
||||||
#define SER_REMOTEADDR "remoteaddress"
|
#define SER_REMOTEADDR "remoteaddress"
|
||||||
#define SER_MANUALADDR "manualaddress"
|
#define SER_MANUALADDR "manualaddress"
|
||||||
|
#define SER_IPV6ADDR "ipv6address"
|
||||||
#define SER_APPLIST "apps"
|
#define SER_APPLIST "apps"
|
||||||
#define SER_SRVCERT "srvcert"
|
#define SER_SRVCERT "srvcert"
|
||||||
|
|
||||||
|
@ -24,6 +25,7 @@ NvComputer::NvComputer(QSettings& settings)
|
||||||
this->macAddress = settings.value(SER_MAC).toByteArray();
|
this->macAddress = settings.value(SER_MAC).toByteArray();
|
||||||
this->localAddress = settings.value(SER_LOCALADDR).toString();
|
this->localAddress = settings.value(SER_LOCALADDR).toString();
|
||||||
this->remoteAddress = settings.value(SER_REMOTEADDR).toString();
|
this->remoteAddress = settings.value(SER_REMOTEADDR).toString();
|
||||||
|
this->ipv6Address = settings.value(SER_IPV6ADDR).toString();
|
||||||
this->manualAddress = settings.value(SER_MANUALADDR).toString();
|
this->manualAddress = settings.value(SER_MANUALADDR).toString();
|
||||||
this->serverCert = QSslCertificate(settings.value(SER_SRVCERT).toByteArray());
|
this->serverCert = QSslCertificate(settings.value(SER_SRVCERT).toByteArray());
|
||||||
|
|
||||||
|
@ -63,6 +65,7 @@ void NvComputer::serialize(QSettings& settings)
|
||||||
settings.setValue(SER_MAC, macAddress);
|
settings.setValue(SER_MAC, macAddress);
|
||||||
settings.setValue(SER_LOCALADDR, localAddress);
|
settings.setValue(SER_LOCALADDR, localAddress);
|
||||||
settings.setValue(SER_REMOTEADDR, remoteAddress);
|
settings.setValue(SER_REMOTEADDR, remoteAddress);
|
||||||
|
settings.setValue(SER_IPV6ADDR, ipv6Address);
|
||||||
settings.setValue(SER_MANUALADDR, manualAddress);
|
settings.setValue(SER_MANUALADDR, manualAddress);
|
||||||
settings.setValue(SER_SRVCERT, serverCert.toPem());
|
settings.setValue(SER_SRVCERT, serverCert.toPem());
|
||||||
|
|
||||||
|
@ -237,6 +240,7 @@ QVector<QString> NvComputer::uniqueAddresses()
|
||||||
uniqueAddressList.append(activeAddress);
|
uniqueAddressList.append(activeAddress);
|
||||||
uniqueAddressList.append(localAddress);
|
uniqueAddressList.append(localAddress);
|
||||||
uniqueAddressList.append(remoteAddress);
|
uniqueAddressList.append(remoteAddress);
|
||||||
|
uniqueAddressList.append(ipv6Address);
|
||||||
uniqueAddressList.append(manualAddress);
|
uniqueAddressList.append(manualAddress);
|
||||||
|
|
||||||
// Prune duplicates (always giving precedence to the first)
|
// Prune duplicates (always giving precedence to the first)
|
||||||
|
@ -296,6 +300,7 @@ bool NvComputer::update(NvComputer& that)
|
||||||
ASSIGN_IF_CHANGED_AND_NONEMPTY(macAddress);
|
ASSIGN_IF_CHANGED_AND_NONEMPTY(macAddress);
|
||||||
ASSIGN_IF_CHANGED_AND_NONEMPTY(localAddress);
|
ASSIGN_IF_CHANGED_AND_NONEMPTY(localAddress);
|
||||||
ASSIGN_IF_CHANGED_AND_NONEMPTY(remoteAddress);
|
ASSIGN_IF_CHANGED_AND_NONEMPTY(remoteAddress);
|
||||||
|
ASSIGN_IF_CHANGED_AND_NONEMPTY(ipv6Address);
|
||||||
ASSIGN_IF_CHANGED_AND_NONEMPTY(manualAddress);
|
ASSIGN_IF_CHANGED_AND_NONEMPTY(manualAddress);
|
||||||
ASSIGN_IF_CHANGED(pairState);
|
ASSIGN_IF_CHANGED(pairState);
|
||||||
ASSIGN_IF_CHANGED(serverCodecModeSupport);
|
ASSIGN_IF_CHANGED(serverCodecModeSupport);
|
||||||
|
|
|
@ -64,6 +64,7 @@ public:
|
||||||
// Persisted traits
|
// Persisted traits
|
||||||
QString localAddress;
|
QString localAddress;
|
||||||
QString remoteAddress;
|
QString remoteAddress;
|
||||||
|
QString ipv6Address;
|
||||||
QString manualAddress;
|
QString manualAddress;
|
||||||
QByteArray macAddress;
|
QByteArray macAddress;
|
||||||
QString name;
|
QString name;
|
||||||
|
|
|
@ -1 +1 @@
|
||||||
Subproject commit 40646208d0599044ce9e47fd3d212e5f942d9303
|
Subproject commit 4cd72bc39a9a02fb447c2876f216a3e266681bdc
|
Loading…
Reference in a new issue