From 7bb9c69c08390a4ee57d6bdf577f58c4e685bced Mon Sep 17 00:00:00 2001 From: sledgehammer999 Date: Sun, 13 Aug 2017 00:58:22 +0300 Subject: [PATCH] Fix connection problems when a specific interface/ip is configured. Closes #7235. Bug related to #7099 and Qt. --- src/base/bittorrent/session.cpp | 71 +++++++++++++++++++++++++++++++-- 1 file changed, 68 insertions(+), 3 deletions(-) diff --git a/src/base/bittorrent/session.cpp b/src/base/bittorrent/session.cpp index 0dd14f650..a68461c61 100644 --- a/src/base/bittorrent/session.cpp +++ b/src/base/bittorrent/session.cpp @@ -41,6 +41,7 @@ #include #include #include +#include #include #include @@ -92,6 +93,14 @@ #include "tracker.h" #include "trackerentry.h" +#ifdef Q_OS_WIN +#include +#endif + +#if _WIN32_WINNT < 0x0600 +using NETIO_STATUS = LONG; +#endif + static const char PEER_ID[] = "qB"; static const char RESUME_FOLDER[] = "BT_backup"; static const char USER_AGENT[] = "qBittorrent/" QBT_VERSION_2; @@ -109,6 +118,10 @@ namespace void torrentQueuePositionTop(const libt::torrent_handle &handle); void torrentQueuePositionBottom(const libt::torrent_handle &handle); +#ifdef Q_OS_WIN + QString convertIfaceNameToGuid(const QString &name); +#endif + inline SettingsStorage *settings() { return SettingsStorage::instance(); } QStringMap map_cast(const QVariantMap &map) @@ -1103,6 +1116,10 @@ void Session::configure(libtorrent::settings_pack &settingsPack) { Logger* const logger = Logger::instance(); +#ifdef Q_OS_WIN + QString chosenIP; +#endif + if (m_listenInterfaceChanged) { const ushort port = this->port(); std::pair ports(port, port); @@ -1132,11 +1149,31 @@ void Session::configure(libtorrent::settings_pack &settingsPack) .arg(ip).arg(port) , Log::INFO); settingsPack.set_str(libt::settings_pack::listen_interfaces, interfacesStr); +#ifdef Q_OS_WIN + chosenIP = ip; +#endif break; } } +#ifdef Q_OS_WIN + // On Vista+ versions and after Qt 5.5 QNetworkInterface::name() returns + // the interface's Luid and not the GUID. + // Libtorrent expects GUIDs for the 'outgoing_interfaces' setting. + if (!networkInterface().isEmpty()) { + QString guid = convertIfaceNameToGuid(networkInterface()); + if (!guid.isEmpty()) { + settingsPack.set_str(libt::settings_pack::outgoing_interfaces, guid.toStdString()); + } + else { + settingsPack.set_str(libt::settings_pack::outgoing_interfaces, chosenIP.toStdString()); + LogMsg(tr("Could not get GUID of configured network interface. Binding to IP %1").arg(chosenIP) + , Log::WARNING); + } + } +#else settingsPack.set_str(libt::settings_pack::outgoing_interfaces, networkInterface().toStdString()); +#endif m_listenInterfaceChanged = false; } @@ -2510,10 +2547,10 @@ QString Session::networkInterface() const return m_networkInterface; } -void Session::setNetworkInterface(const QString &interface) +void Session::setNetworkInterface(const QString &iface) { - if (interface != networkInterface()) { - m_networkInterface = interface; + if (iface != networkInterface()) { + m_networkInterface = iface; configureListeningInterface(); } } @@ -4104,4 +4141,32 @@ namespace qDebug() << Q_FUNC_INFO << " fails: " << exc.what(); } } + +#ifdef Q_OS_WIN + QString convertIfaceNameToGuid(const QString &name) + { + // Under Windows XP or on Qt version <= 5.5 'name' will be a GUID already. + QUuid uuid(name); + if (!uuid.isNull()) + return uuid.toString().toUpper(); // Libtorrent expects the GUID in uppercase + + using PCONVERTIFACENAMETOLUID = NETIO_STATUS (WINAPI *)(const WCHAR *, PNET_LUID); + PCONVERTIFACENAMETOLUID ConvertIfaceNameToLuid = reinterpret_cast(::GetProcAddress(::GetModuleHandleW(L"Iphlpapi.dll"), "ConvertInterfaceNameToLuidW")); + if (!ConvertIfaceNameToLuid) return QString(); + + using PCONVERTIFACELUIDTOGUID = NETIO_STATUS (WINAPI *)(const NET_LUID *, GUID *); + PCONVERTIFACELUIDTOGUID ConvertIfaceLuidToGuid = reinterpret_cast(::GetProcAddress(::GetModuleHandleW(L"Iphlpapi.dll"), "ConvertInterfaceLuidToGuid")); + if (!ConvertIfaceLuidToGuid) return QString(); + + NET_LUID luid; + LONG res = ConvertIfaceNameToLuid(name.toStdWString().c_str(), &luid); + if (res == 0) { + GUID guid; + if (ConvertIfaceLuidToGuid(&luid, &guid) == 0) + return QUuid(guid).toString().toUpper(); + } + + return QString(); + } +#endif }