mirror of
https://github.com/moonlight-stream/moonlight-qt
synced 2024-12-13 12:52:27 +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();
|
||||
}
|
||||
|
||||
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()
|
||||
{
|
||||
QWriteLocker lock(&m_Lock);
|
||||
|
@ -234,8 +270,8 @@ void ComputerManager::startPolling()
|
|||
qInfo() << "Discovered mDNS host:" << service.hostname();
|
||||
|
||||
MdnsPendingComputer* pendingComputer = new MdnsPendingComputer(&m_MdnsServer, &m_MdnsCache, service);
|
||||
connect(pendingComputer, SIGNAL(resolvedv4(MdnsPendingComputer*,QHostAddress)),
|
||||
this, SLOT(handleMdnsServiceResolved(MdnsPendingComputer*,QHostAddress)));
|
||||
connect(pendingComputer, &MdnsPendingComputer::resolvedHost,
|
||||
this, &ComputerManager::handleMdnsServiceResolved);
|
||||
m_PendingResolution.append(pendingComputer);
|
||||
});
|
||||
}
|
||||
|
@ -277,11 +313,39 @@ void ComputerManager::startPollingComputer(NvComputer* 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);
|
||||
computer->deleteLater();
|
||||
|
@ -508,9 +572,10 @@ class PendingAddTask : public QObject, public QRunnable
|
|||
Q_OBJECT
|
||||
|
||||
public:
|
||||
PendingAddTask(ComputerManager* computerManager, QString address, bool mdns)
|
||||
PendingAddTask(ComputerManager* computerManager, QString address, QHostAddress mdnsIpv6Address, bool mdns)
|
||||
: m_ComputerManager(computerManager),
|
||||
m_Address(address),
|
||||
m_MdnsIpv6Address(mdnsIpv6Address),
|
||||
m_Mdns(mdns)
|
||||
{
|
||||
connect(this, &PendingAddTask::computerAddCompleted,
|
||||
|
@ -560,7 +625,7 @@ private:
|
|||
{
|
||||
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
|
||||
QString serverInfo = fetchServerInfo(http);
|
||||
|
@ -606,6 +671,11 @@ private:
|
|||
else {
|
||||
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 {
|
||||
newComputer->manualAddress = m_Address;
|
||||
|
@ -657,14 +727,15 @@ private:
|
|||
|
||||
ComputerManager* m_ComputerManager;
|
||||
QString m_Address;
|
||||
QHostAddress m_MdnsIpv6Address;
|
||||
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
|
||||
// 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);
|
||||
}
|
||||
|
||||
|
|
|
@ -13,6 +13,7 @@
|
|||
#include <QReadWriteLock>
|
||||
#include <QSettings>
|
||||
#include <QRunnable>
|
||||
#include <QTimer>
|
||||
|
||||
class MdnsPendingComputer : public QObject
|
||||
{
|
||||
|
@ -25,8 +26,8 @@ public:
|
|||
: m_Hostname(service.hostname()),
|
||||
m_Resolver(server, m_Hostname, cache)
|
||||
{
|
||||
connect(&m_Resolver, SIGNAL(resolved(QHostAddress)),
|
||||
this, SLOT(handleResolved(QHostAddress)));
|
||||
connect(&m_Resolver, &QMdnsEngine::Resolver::resolved,
|
||||
this, &MdnsPendingComputer::handleResolvedAddress);
|
||||
}
|
||||
|
||||
QString hostname()
|
||||
|
@ -35,20 +36,31 @@ public:
|
|||
}
|
||||
|
||||
private slots:
|
||||
void handleResolved(const QHostAddress& address)
|
||||
void handleResolvedTimeout()
|
||||
{
|
||||
if (address.protocol() == QAbstractSocket::IPv4Protocol) {
|
||||
m_Resolver.disconnect();
|
||||
emit resolvedv4(this, address);
|
||||
Q_ASSERT(!m_Addresses.isEmpty());
|
||||
emit resolvedHost(this, m_Addresses);
|
||||
}
|
||||
|
||||
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:
|
||||
void resolvedv4(MdnsPendingComputer*, const QHostAddress&);
|
||||
void resolvedHost(MdnsPendingComputer*,QVector<QHostAddress>&);
|
||||
|
||||
private:
|
||||
QByteArray m_Hostname;
|
||||
QMdnsEngine::Resolver m_Resolver;
|
||||
QVector<QHostAddress> m_Addresses;
|
||||
};
|
||||
|
||||
class ComputerPollingEntry
|
||||
|
@ -140,7 +152,7 @@ public:
|
|||
|
||||
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);
|
||||
|
||||
|
@ -165,11 +177,13 @@ private slots:
|
|||
|
||||
void handleComputerStateChanged(NvComputer* computer);
|
||||
|
||||
void handleMdnsServiceResolved(MdnsPendingComputer* computer, const QHostAddress& address);
|
||||
void handleMdnsServiceResolved(MdnsPendingComputer* computer, QVector<QHostAddress>& addresses);
|
||||
|
||||
private:
|
||||
void saveHosts();
|
||||
|
||||
QHostAddress getBestGlobalAddressV6(QVector<QHostAddress>& addresses);
|
||||
|
||||
void startPollingComputer(NvComputer* computer);
|
||||
|
||||
int m_PollingRef;
|
||||
|
|
|
@ -39,11 +39,18 @@ void ComputerSeeker::onComputerUpdated(NvComputer *computer)
|
|||
bool ComputerSeeker::matchComputer(NvComputer *computer) const
|
||||
{
|
||||
QString value = m_ComputerName.toLower();
|
||||
return computer->name.toLower() == value ||
|
||||
computer->localAddress.toLower() == value ||
|
||||
computer->remoteAddress.toLower() == value ||
|
||||
computer->manualAddress.toLower() == value ||
|
||||
computer->uuid.toLower() == value;
|
||||
|
||||
if (computer->name.toLower() == value || computer->uuid.toLower() == value) {
|
||||
return true;
|
||||
}
|
||||
|
||||
for (const QString& addr : computer->uniqueAddresses()) {
|
||||
if (addr.toLower() == value) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool ComputerSeeker::isOnline(NvComputer *computer) const
|
||||
|
|
|
@ -10,6 +10,7 @@
|
|||
#define SER_LOCALADDR "localaddress"
|
||||
#define SER_REMOTEADDR "remoteaddress"
|
||||
#define SER_MANUALADDR "manualaddress"
|
||||
#define SER_IPV6ADDR "ipv6address"
|
||||
#define SER_APPLIST "apps"
|
||||
#define SER_SRVCERT "srvcert"
|
||||
|
||||
|
@ -24,6 +25,7 @@ NvComputer::NvComputer(QSettings& settings)
|
|||
this->macAddress = settings.value(SER_MAC).toByteArray();
|
||||
this->localAddress = settings.value(SER_LOCALADDR).toString();
|
||||
this->remoteAddress = settings.value(SER_REMOTEADDR).toString();
|
||||
this->ipv6Address = settings.value(SER_IPV6ADDR).toString();
|
||||
this->manualAddress = settings.value(SER_MANUALADDR).toString();
|
||||
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_LOCALADDR, localAddress);
|
||||
settings.setValue(SER_REMOTEADDR, remoteAddress);
|
||||
settings.setValue(SER_IPV6ADDR, ipv6Address);
|
||||
settings.setValue(SER_MANUALADDR, manualAddress);
|
||||
settings.setValue(SER_SRVCERT, serverCert.toPem());
|
||||
|
||||
|
@ -237,6 +240,7 @@ QVector<QString> NvComputer::uniqueAddresses()
|
|||
uniqueAddressList.append(activeAddress);
|
||||
uniqueAddressList.append(localAddress);
|
||||
uniqueAddressList.append(remoteAddress);
|
||||
uniqueAddressList.append(ipv6Address);
|
||||
uniqueAddressList.append(manualAddress);
|
||||
|
||||
// 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(localAddress);
|
||||
ASSIGN_IF_CHANGED_AND_NONEMPTY(remoteAddress);
|
||||
ASSIGN_IF_CHANGED_AND_NONEMPTY(ipv6Address);
|
||||
ASSIGN_IF_CHANGED_AND_NONEMPTY(manualAddress);
|
||||
ASSIGN_IF_CHANGED(pairState);
|
||||
ASSIGN_IF_CHANGED(serverCodecModeSupport);
|
||||
|
|
|
@ -64,6 +64,7 @@ public:
|
|||
// Persisted traits
|
||||
QString localAddress;
|
||||
QString remoteAddress;
|
||||
QString ipv6Address;
|
||||
QString manualAddress;
|
||||
QByteArray macAddress;
|
||||
QString name;
|
||||
|
|
|
@ -1 +1 @@
|
|||
Subproject commit 40646208d0599044ce9e47fd3d212e5f942d9303
|
||||
Subproject commit 4cd72bc39a9a02fb447c2876f216a3e266681bdc
|
Loading…
Reference in a new issue