Warning, file /plasma/kwin/src/client_machine.cpp was not indexed or was modified since last indexation (in which case cross-reference links may be missing, inaccurate or erroneous).
0001 /* 0002 KWin - the KDE window manager 0003 This file is part of the KDE project. 0004 0005 SPDX-FileCopyrightText: 2013 Martin Gräßlin <mgraesslin@kde.org> 0006 0007 SPDX-License-Identifier: GPL-2.0-or-later 0008 */ 0009 // own 0010 #include "client_machine.h" 0011 #include "main.h" 0012 #include "utils/common.h" 0013 // KF5 0014 #include <NETWM> 0015 // Qt 0016 #include <QFutureWatcher> 0017 #include <QtConcurrentRun> 0018 // system 0019 #include <netdb.h> 0020 #include <sys/socket.h> 0021 #include <sys/types.h> 0022 #include <unistd.h> 0023 0024 namespace KWin 0025 { 0026 0027 static QString getHostName() 0028 { 0029 #ifdef HOST_NAME_MAX 0030 char hostnamebuf[HOST_NAME_MAX]; 0031 #else 0032 char hostnamebuf[256]; 0033 #endif 0034 if (gethostname(hostnamebuf, sizeof hostnamebuf) >= 0) { 0035 hostnamebuf[sizeof(hostnamebuf) - 1] = 0; 0036 return QString::fromLocal8Bit(hostnamebuf); 0037 } 0038 return QString(); 0039 } 0040 0041 GetAddrInfo::GetAddrInfo(const QString &hostName, QObject *parent) 0042 : QObject(parent) 0043 , m_resolving(false) 0044 , m_resolved(false) 0045 , m_ownResolved(false) 0046 , m_hostName(hostName) 0047 , m_addressHints(std::make_unique<addrinfo>()) 0048 , m_address(nullptr) 0049 , m_ownAddress(nullptr) 0050 , m_watcher(std::make_unique<QFutureWatcher<int>>()) 0051 , m_ownAddressWatcher(std::make_unique<QFutureWatcher<int>>()) 0052 { 0053 // watcher will be deleted together with the GetAddrInfo once the future 0054 // got canceled or finished 0055 connect(m_watcher.get(), &QFutureWatcher<int>::canceled, this, &GetAddrInfo::deleteLater); 0056 connect(m_watcher.get(), &QFutureWatcher<int>::finished, this, &GetAddrInfo::slotResolved); 0057 connect(m_ownAddressWatcher.get(), &QFutureWatcher<int>::canceled, this, &GetAddrInfo::deleteLater); 0058 connect(m_ownAddressWatcher.get(), &QFutureWatcher<int>::finished, this, &GetAddrInfo::slotOwnAddressResolved); 0059 } 0060 0061 GetAddrInfo::~GetAddrInfo() 0062 { 0063 if (m_watcher && m_watcher->isRunning()) { 0064 m_watcher->cancel(); 0065 m_watcher->waitForFinished(); 0066 } 0067 if (m_ownAddressWatcher && m_ownAddressWatcher->isRunning()) { 0068 m_ownAddressWatcher->cancel(); 0069 m_ownAddressWatcher->waitForFinished(); 0070 } 0071 if (m_address) { 0072 freeaddrinfo(m_address); 0073 } 0074 if (m_ownAddress) { 0075 freeaddrinfo(m_ownAddress); 0076 } 0077 } 0078 0079 void GetAddrInfo::resolve() 0080 { 0081 if (m_resolving) { 0082 return; 0083 } 0084 m_resolving = true; 0085 *m_addressHints = {}; 0086 m_addressHints->ai_family = PF_UNSPEC; 0087 m_addressHints->ai_socktype = SOCK_STREAM; 0088 m_addressHints->ai_flags |= AI_CANONNAME; 0089 0090 m_watcher->setFuture(QtConcurrent::run([this]() { 0091 return getaddrinfo(m_hostName.toLocal8Bit().constData(), nullptr, m_addressHints.get(), &m_address); 0092 })); 0093 m_ownAddressWatcher->setFuture(QtConcurrent::run([this] { 0094 // needs to be performed in a lambda as getHostName() returns a temporary value which would 0095 // get destroyed in the main thread before the getaddrinfo thread is able to read it 0096 return getaddrinfo(getHostName().toLocal8Bit().constData(), nullptr, m_addressHints.get(), &m_ownAddress); 0097 })); 0098 } 0099 0100 void GetAddrInfo::slotResolved() 0101 { 0102 if (resolved(m_watcher.get())) { 0103 m_resolved = true; 0104 compare(); 0105 } 0106 } 0107 0108 void GetAddrInfo::slotOwnAddressResolved() 0109 { 0110 if (resolved(m_ownAddressWatcher.get())) { 0111 m_ownResolved = true; 0112 compare(); 0113 } 0114 } 0115 0116 bool GetAddrInfo::resolved(QFutureWatcher<int> *watcher) 0117 { 0118 if (!watcher->isFinished()) { 0119 return false; 0120 } 0121 if (watcher->result() != 0) { 0122 qCDebug(KWIN_CORE) << "getaddrinfo failed with error:" << gai_strerror(watcher->result()); 0123 // call failed; 0124 deleteLater(); 0125 return false; 0126 } 0127 return true; 0128 } 0129 0130 void GetAddrInfo::compare() 0131 { 0132 if (!m_resolved || !m_ownResolved) { 0133 return; 0134 } 0135 addrinfo *address = m_address; 0136 while (address) { 0137 if (address->ai_canonname && m_hostName == QByteArray(address->ai_canonname).toLower()) { 0138 addrinfo *ownAddress = m_ownAddress; 0139 bool localFound = false; 0140 while (ownAddress) { 0141 if (ownAddress->ai_canonname && QByteArray(ownAddress->ai_canonname).toLower() == m_hostName) { 0142 localFound = true; 0143 break; 0144 } 0145 ownAddress = ownAddress->ai_next; 0146 } 0147 if (localFound) { 0148 Q_EMIT local(); 0149 break; 0150 } 0151 } 0152 address = address->ai_next; 0153 } 0154 deleteLater(); 0155 } 0156 0157 ClientMachine::ClientMachine(QObject *parent) 0158 : QObject(parent) 0159 , m_localhost(false) 0160 , m_resolved(false) 0161 , m_resolving(false) 0162 { 0163 } 0164 0165 ClientMachine::~ClientMachine() 0166 { 0167 } 0168 0169 void ClientMachine::resolve(xcb_window_t window, xcb_window_t clientLeader) 0170 { 0171 if (m_resolved) { 0172 return; 0173 } 0174 QString name = NETWinInfo(connection(), window, rootWindow(), NET::Properties(), NET::WM2ClientMachine).clientMachine(); 0175 if (name.isEmpty() && clientLeader && clientLeader != window) { 0176 name = NETWinInfo(connection(), clientLeader, rootWindow(), NET::Properties(), NET::WM2ClientMachine).clientMachine(); 0177 } 0178 if (name.isEmpty()) { 0179 name = localhost(); 0180 } 0181 if (name == localhost()) { 0182 setLocal(); 0183 } 0184 m_hostName = name; 0185 checkForLocalhost(); 0186 m_resolved = true; 0187 } 0188 0189 void ClientMachine::checkForLocalhost() 0190 { 0191 if (isLocal()) { 0192 // nothing to do 0193 return; 0194 } 0195 QString host = getHostName(); 0196 0197 if (!host.isEmpty()) { 0198 host = host.toLower(); 0199 const QString lowerHostName(m_hostName.toLower()); 0200 if (host == lowerHostName) { 0201 setLocal(); 0202 return; 0203 } 0204 if (int index = host.indexOf('.'); index != -1) { 0205 if (QStringView(host).left(index) == lowerHostName) { 0206 setLocal(); 0207 return; 0208 } 0209 } else { 0210 m_resolving = true; 0211 // check using information from get addr info 0212 // GetAddrInfo gets automatically destroyed once it finished or not 0213 GetAddrInfo *info = new GetAddrInfo(lowerHostName, this); 0214 connect(info, &GetAddrInfo::local, this, &ClientMachine::setLocal); 0215 connect(info, &GetAddrInfo::destroyed, this, &ClientMachine::resolveFinished); 0216 info->resolve(); 0217 } 0218 } 0219 } 0220 0221 void ClientMachine::setLocal() 0222 { 0223 m_localhost = true; 0224 Q_EMIT localhostChanged(); 0225 } 0226 0227 void ClientMachine::resolveFinished() 0228 { 0229 m_resolving = false; 0230 } 0231 0232 } // namespace