KWin
Loading...
Searching...
No Matches
client_machine.cpp
Go to the documentation of this file.
1/*
2 KWin - the KDE window manager
3 This file is part of the KDE project.
4
5 SPDX-FileCopyrightText: 2013 Martin Gräßlin <mgraesslin@kde.org>
6
7 SPDX-License-Identifier: GPL-2.0-or-later
8*/
9// own
10#include "client_machine.h"
11#include "effect/xcb.h"
12#include "main.h"
13#include "utils/common.h"
14// KF5
15#include <NETWM>
16// Qt
17#include <QFutureWatcher>
18#include <QtConcurrentRun>
19// system
20#include <netdb.h>
21#include <sys/socket.h>
22#include <sys/types.h>
23#include <unistd.h>
24
25namespace KWin
26{
27
28static QString getHostName()
29{
30#ifdef HOST_NAME_MAX
31 char hostnamebuf[HOST_NAME_MAX];
32#else
33 char hostnamebuf[256];
34#endif
35 if (gethostname(hostnamebuf, sizeof hostnamebuf) >= 0) {
36 hostnamebuf[sizeof(hostnamebuf) - 1] = 0;
37 return QString::fromLocal8Bit(hostnamebuf);
38 }
39 return QString();
40}
41
42GetAddrInfo::GetAddrInfo(const QString &hostName, QObject *parent)
43 : QObject(parent)
44 , m_resolving(false)
45 , m_resolved(false)
46 , m_ownResolved(false)
47 , m_hostName(hostName)
48 , m_addressHints(std::make_unique<addrinfo>())
49 , m_address(nullptr)
50 , m_ownAddress(nullptr)
51 , m_watcher(std::make_unique<QFutureWatcher<int>>())
52 , m_ownAddressWatcher(std::make_unique<QFutureWatcher<int>>())
53{
54 // watcher will be deleted together with the GetAddrInfo once the future
55 // got canceled or finished
56 connect(m_watcher.get(), &QFutureWatcher<int>::canceled, this, &GetAddrInfo::deleteLater);
57 connect(m_watcher.get(), &QFutureWatcher<int>::finished, this, &GetAddrInfo::slotResolved);
58 connect(m_ownAddressWatcher.get(), &QFutureWatcher<int>::canceled, this, &GetAddrInfo::deleteLater);
59 connect(m_ownAddressWatcher.get(), &QFutureWatcher<int>::finished, this, &GetAddrInfo::slotOwnAddressResolved);
60}
61
63{
64 if (m_watcher && m_watcher->isRunning()) {
65 m_watcher->cancel();
66 m_watcher->waitForFinished();
67 }
68 if (m_ownAddressWatcher && m_ownAddressWatcher->isRunning()) {
69 m_ownAddressWatcher->cancel();
70 m_ownAddressWatcher->waitForFinished();
71 }
72 if (m_address) {
73 freeaddrinfo(m_address);
74 }
75 if (m_ownAddress) {
76 freeaddrinfo(m_ownAddress);
77 }
78}
79
81{
82 if (m_resolving) {
83 return;
84 }
85 m_resolving = true;
86 *m_addressHints = {};
87 m_addressHints->ai_family = PF_UNSPEC;
88 m_addressHints->ai_socktype = SOCK_STREAM;
89 m_addressHints->ai_flags |= AI_CANONNAME;
90
91 m_watcher->setFuture(QtConcurrent::run([this]() {
92 return getaddrinfo(m_hostName.toLocal8Bit().constData(), nullptr, m_addressHints.get(), &m_address);
93 }));
94 m_ownAddressWatcher->setFuture(QtConcurrent::run([this] {
95 // needs to be performed in a lambda as getHostName() returns a temporary value which would
96 // get destroyed in the main thread before the getaddrinfo thread is able to read it
97 return getaddrinfo(getHostName().toLocal8Bit().constData(), nullptr, m_addressHints.get(), &m_ownAddress);
98 }));
99}
100
101void GetAddrInfo::slotResolved()
102{
103 if (resolved(m_watcher.get())) {
104 m_resolved = true;
105 compare();
106 }
107}
108
109void GetAddrInfo::slotOwnAddressResolved()
110{
111 if (resolved(m_ownAddressWatcher.get())) {
112 m_ownResolved = true;
113 compare();
114 }
115}
116
117bool GetAddrInfo::resolved(QFutureWatcher<int> *watcher)
118{
119 if (!watcher->isFinished()) {
120 return false;
121 }
122 if (watcher->result() != 0) {
123 qCDebug(KWIN_CORE) << "getaddrinfo failed with error:" << gai_strerror(watcher->result());
124 // call failed;
125 deleteLater();
126 return false;
127 }
128 return true;
129}
130
131void GetAddrInfo::compare()
132{
133 if (!m_resolved || !m_ownResolved) {
134 return;
135 }
136 addrinfo *address = m_address;
137 while (address) {
138 if (address->ai_canonname && m_hostName == QByteArray(address->ai_canonname).toLower()) {
139 addrinfo *ownAddress = m_ownAddress;
140 bool localFound = false;
141 while (ownAddress) {
142 if (ownAddress->ai_canonname && QByteArray(ownAddress->ai_canonname).toLower() == m_hostName) {
143 localFound = true;
144 break;
145 }
146 ownAddress = ownAddress->ai_next;
147 }
148 if (localFound) {
149 Q_EMIT local();
150 break;
151 }
152 }
153 address = address->ai_next;
154 }
155 deleteLater();
156}
157
159 : QObject(parent)
160 , m_localhost(false)
161 , m_resolved(false)
162 , m_resolving(false)
163{
164}
165
169
170void ClientMachine::resolve(xcb_window_t window, xcb_window_t clientLeader)
171{
172 if (m_resolved) {
173 return;
174 }
175 QString name = NETWinInfo(connection(), window, rootWindow(), NET::Properties(), NET::WM2ClientMachine).clientMachine();
176 if (name.isEmpty() && clientLeader && clientLeader != window) {
177 name = NETWinInfo(connection(), clientLeader, rootWindow(), NET::Properties(), NET::WM2ClientMachine).clientMachine();
178 }
179 if (name.isEmpty()) {
180 name = localhost();
181 }
182 if (name == localhost()) {
183 setLocal();
184 }
185 m_hostName = name;
186 checkForLocalhost();
187 m_resolved = true;
188}
189
190void ClientMachine::checkForLocalhost()
191{
192 if (isLocal()) {
193 // nothing to do
194 return;
195 }
196 QString host = getHostName();
197
198 if (!host.isEmpty()) {
199 host = host.toLower();
200 const QString lowerHostName(m_hostName.toLower());
201 if (host == lowerHostName) {
202 setLocal();
203 return;
204 }
205 if (int index = host.indexOf('.'); index != -1) {
206 if (QStringView(host).left(index) == lowerHostName) {
207 setLocal();
208 return;
209 }
210 } else {
211 m_resolving = true;
212 // check using information from get addr info
213 // GetAddrInfo gets automatically destroyed once it finished or not
214 GetAddrInfo *info = new GetAddrInfo(lowerHostName, this);
215 connect(info, &GetAddrInfo::local, this, &ClientMachine::setLocal);
216 connect(info, &GetAddrInfo::destroyed, this, &ClientMachine::resolveFinished);
217 info->resolve();
218 }
219 }
220}
221
222void ClientMachine::setLocal()
223{
224 m_localhost = true;
225 Q_EMIT localhostChanged();
226}
227
228void ClientMachine::resolveFinished()
229{
230 m_resolving = false;
231}
232
233} // namespace
234
235#include "moc_client_machine.cpp"
void resolve(xcb_window_t window, xcb_window_t clientLeader)
ClientMachine(QObject *parent=nullptr)
static QString localhost()
GetAddrInfo(const QString &hostName, QObject *parent=nullptr)
KWIN_EXPORT xcb_window_t rootWindow()
Definition xcb.h:24
KWIN_EXPORT xcb_connection_t * connection()
Definition xcb.h:19