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