Qt
Internal/Contributor docs for the Qt SDK. <b>Note:</b> These are NOT official API docs; those are found <a href='https://doc.qt.io/'>here</a>.
Loading...
Searching...
No Matches
qqmldebugconnection.cpp
Go to the documentation of this file.
1// Copyright (C) 2016 The Qt Company Ltd.
2// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
3
5#include "qqmldebugclient_p.h"
6
7#include <private/qpacketprotocol_p.h>
8#include <private/qpacket_p.h>
9#include <private/qobject_p.h>
10
11#include <QtCore/qeventloop.h>
12#include <QtCore/qtimer.h>
13#include <QtCore/QHash>
14#include <QtCore/qdatastream.h>
15#include <QtNetwork/qlocalserver.h>
16#include <QtNetwork/qlocalsocket.h>
17#include <QtNetwork/qtcpsocket.h>
18
20
21static const int protocolVersion = 1;
22static const QString serverId = QLatin1String("QDeclarativeDebugServer");
23static const QString clientId = QLatin1String("QDeclarativeDebugClient");
24
26{
27 Q_DECLARE_PUBLIC(QQmlDebugConnection)
28
29public:
32 QIODevice *device = nullptr;
33 QLocalServer *server = nullptr;
36
37 bool gotHello = false;
38 int currentDataStreamVersion = QDataStream::Qt_4_7;
39 int maximumDataStreamVersion = QDataStream::Qt_DefaultCompiledVersion;
40 QHash <QString, float> serverPlugins;
41 QHash<QString, QQmlDebugClient *> plugins;
43
44 void advertisePlugins();
45 void createProtocol();
46 void flush();
47};
48
54
56{
58 if (!q->isConnected())
59 return;
60
62 pack << serverId << 1 << plugins.keys();
63 protocol->send(pack.data());
64 flush();
65}
66
67void QQmlDebugConnection::socketConnected()
68{
70 QPacket pack(d->currentDataStreamVersion);
71 pack << serverId << 0 << protocolVersion << d->plugins.keys() << d->maximumDataStreamVersion
72 << true; // We accept multiple messages per packet
73 d->protocol->send(pack.data());
74 d->flush();
75}
76
77void QQmlDebugConnection::socketDisconnected()
78{
80 d->gotHello = false;
82}
83
84void QQmlDebugConnection::protocolReadyRead()
85{
87 if (!d->gotHello) {
88 QPacket pack(d->currentDataStreamVersion, d->protocol->read());
90
91 pack >> name;
92
93 bool validHello = false;
94 if (name == clientId) {
95 int op = -1;
96 pack >> op;
97 if (op == 0) {
98 int version = -1;
99 pack >> version;
100 if (version == protocolVersion) {
101 QStringList pluginNames;
102 QList<float> pluginVersions;
103 pack >> pluginNames;
104 if (!pack.atEnd())
105 pack >> pluginVersions;
106
107 const int pluginNamesSize = pluginNames.size();
108 const int pluginVersionsSize = pluginVersions.size();
109 for (int i = 0; i < pluginNamesSize; ++i) {
110 float pluginVersion = 1.0;
111 if (i < pluginVersionsSize)
112 pluginVersion = pluginVersions.at(i);
113 d->serverPlugins.insert(pluginNames.at(i), pluginVersion);
114 }
115
116 pack >> d->currentDataStreamVersion;
117 validHello = true;
118 }
119 }
120 }
121
122 if (!validHello) {
123 qWarning("QQmlDebugConnection: Invalid hello message");
124 close();
125 return;
126 }
127 d->gotHello = true;
128 emit connected();
129
131 for (; iter != d->plugins.end(); ++iter) {
133 if (d->serverPlugins.contains(iter.key()))
135 iter.value()->stateChanged(newState);
136 }
137
138 d->handshakeTimer.stop();
139 d->handshakeEventLoop.quit();
140 }
141
142 while (d->protocol->packetsAvailable()) {
143 QPacket pack(d->currentDataStreamVersion, d->protocol->read());
145 pack >> name;
146
147 if (name == clientId) {
148 int op = -1;
149 pack >> op;
150
151 if (op == 1) {
152 // Service Discovery
153 QHash<QString, float> oldServerPlugins = d->serverPlugins;
154 d->serverPlugins.clear();
155
156 QStringList pluginNames;
157 QList<float> pluginVersions;
158 pack >> pluginNames;
159 if (!pack.atEnd())
160 pack >> pluginVersions;
161
162 const int pluginNamesSize = pluginNames.size();
163 const int pluginVersionsSize = pluginVersions.size();
164 for (int i = 0; i < pluginNamesSize; ++i) {
165 float pluginVersion = 1.0;
166 if (i < pluginVersionsSize)
167 pluginVersion = pluginVersions.at(i);
168 d->serverPlugins.insert(pluginNames.at(i), pluginVersion);
169 }
170
172 for (; iter != d->plugins.end(); ++iter) {
173 const QString &pluginName = iter.key();
175 if (d->serverPlugins.contains(pluginName))
177
178 if (oldServerPlugins.contains(pluginName)
179 != d->serverPlugins.contains(pluginName)) {
180 iter.value()->stateChanged(newState);
181 }
182 }
183 } else {
184 qWarning() << "QQmlDebugConnection: Unknown control message id" << op;
185 }
186 } else {
188 if (iter == d->plugins.end()) {
189 // We can get more messages for plugins we have removed because it takes time to
190 // send the advertisement message but the removal is instant locally.
191 if (!d->removedPlugins.contains(name)) {
192 qWarning() << "QQmlDebugConnection: Message received for missing plugin"
193 << name;
194 }
195 } else {
198 while (!pack.atEnd()) {
199 pack >> message;
201 }
202 }
203 }
204 }
205}
206
207void QQmlDebugConnection::handshakeTimeout()
208{
210 if (!d->gotHello) {
211 qWarning() << "QQmlDebugConnection: Did not get handshake answer in time";
212 d->handshakeEventLoop.quit();
213 }
214}
215
217 QObject(*(new QQmlDebugConnectionPrivate), parent)
218{
220 connect(&d->handshakeTimer, &QTimer::timeout, this, &QQmlDebugConnection::handshakeTimeout);
221}
222
224{
227 for (; iter != d->plugins.end(); ++iter)
228 emit iter.value()->stateChanged(QQmlDebugClient::NotConnected);
229}
230
232{
233 Q_D(const QQmlDebugConnection);
234 return d->currentDataStreamVersion;
235}
236
238{
240 d->maximumDataStreamVersion = maximumVersion;
241}
242
244{
245 Q_D(const QQmlDebugConnection);
246 return d->gotHello;
247}
248
250{
251 Q_D(const QQmlDebugConnection);
252 return !d->gotHello && d->device;
253}
254
256{
258 if (d->gotHello) {
259 d->gotHello = false;
260 d->device->close();
261
263 for (; iter != d->plugins.end(); ++iter)
264 emit iter.value()->stateChanged(QQmlDebugClient::NotConnected);
265 }
266
267 if (d->device) {
268 d->device->deleteLater();
269 d->device = nullptr;
270 }
271}
272
274{
276 auto socket = qobject_cast<QAbstractSocket*>(d->device);
277 if (!socket) {
278 if (!d->server || (!d->server->hasPendingConnections() &&
279 !d->server->waitForNewConnection(msecs)))
280 return false;
281 } else if (!socket->waitForConnected(msecs)) {
282 return false;
283 }
284 // wait for handshake
285 d->handshakeTimer.start();
286 d->handshakeEventLoop.exec();
287 return d->gotHello;
288}
289
291{
292 Q_D(const QQmlDebugConnection);
293 return d->plugins.value(name, nullptr);
294}
295
297{
299 if (d->plugins.contains(name))
300 return false;
301 d->removedPlugins.removeAll(name);
302 d->plugins.insert(name, client);
303 d->advertisePlugins();
304 return true;
305}
306
308{
310 if (!d->plugins.contains(name))
311 return false;
312 d->plugins.remove(name);
313 d->removedPlugins.append(name);
314 d->advertisePlugins();
315 return true;
316}
317
318float QQmlDebugConnection::serviceVersion(const QString &serviceName) const
319{
320 Q_D(const QQmlDebugConnection);
321 return d->serverPlugins.value(serviceName, -1);
322}
323
325{
327 if (!isConnected() || !d->serverPlugins.contains(name))
328 return false;
329
330 QPacket pack(d->currentDataStreamVersion);
331 pack << name << message;
332 d->protocol->send(pack.data());
333 d->flush();
334
335 return true;
336}
337
339{
340 if (auto socket = qobject_cast<QAbstractSocket *>(device))
341 socket->flush();
342 else if (auto socket = qobject_cast<QLocalSocket *>(device))
343 socket->flush();
344}
345
347{
349 if (d->gotHello)
350 close();
351 auto socket = new QTcpSocket(this);
352 d->device = socket;
353 d->createProtocol();
354 connect(socket, &QAbstractSocket::disconnected, this, &QQmlDebugConnection::socketDisconnected);
355 connect(socket, &QAbstractSocket::connected, this, &QQmlDebugConnection::socketConnected);
359 socket->connectToHost(hostName, port);
360}
361
363{
365 if (d->gotHello)
366 close();
367 if (d->server)
368 d->server->deleteLater();
369 d->server = new QLocalServer(this);
370 // QueuedConnection so that waitForNewConnection() returns true.
372 this, &QQmlDebugConnection::newConnection, Qt::QueuedConnection);
373 d->server->listen(fileName);
374}
375
401
402void QQmlDebugConnection::newConnection()
403{
405 delete d->device;
406 QLocalSocket *socket = d->server->nextPendingConnection();
407 d->server->close();
408 d->device = socket;
409 d->createProtocol();
410 connect(socket, &QLocalSocket::disconnected, this, &QQmlDebugConnection::socketDisconnected);
411 auto translator = new LocalSocketSignalTranslator(socket);
412
417 socketConnected();
418}
419
421{
423 delete protocol;
426 q, &QQmlDebugConnection::protocolReadyRead);
427}
428
430
431#include <qqmldebugconnection.moc>
432
433#include "moc_qqmldebugconnection_p.cpp"
void socketStateChanged(QAbstractSocket::SocketState)
LocalSocketSignalTranslator(QLocalSocket *parent)
void onError(QLocalSocket::LocalSocketError error)
void onStateChanged(QLocalSocket::LocalSocketState state)
void socketError(QAbstractSocket::SocketError)
The QAbstractSocket class provides the base functionality common to all socket types.
SocketState
This enum describes the different states in which a socket can be.
bool flush()
This function writes as much as possible from the internal write buffer to the underlying network soc...
void stateChanged(QAbstractSocket::SocketState)
This signal is emitted whenever QAbstractSocket's state changes.
void errorOccurred(QAbstractSocket::SocketError)
void connected()
This signal is emitted after connectToHost() has been called and a connection has been successfully e...
virtual bool waitForConnected(int msecs=30000)
Waits until the socket is connected, up to msecs milliseconds.
void close() override
Closes the I/O device for the socket and calls disconnectFromHost() to close the socket's connection.
SocketError
This enum describes the socket errors that can occur.
virtual void connectToHost(const QString &hostName, quint16 port, OpenMode mode=ReadWrite, NetworkLayerProtocol protocol=AnyIPProtocol)
Attempts to make a connection to hostName on the given port.
void disconnected()
This signal is emitted when the socket has been disconnected.
\inmodule QtCore
Definition qbytearray.h:57
\inmodule QtCore
Definition qeventloop.h:16
\inmodule QtCore
Definition qhash.h:1103
QList< Key > keys() const
Returns a list containing all the keys in the hash, in an arbitrary order.
Definition qhash.h:1086
\inmodule QtCore \reentrant
Definition qiodevice.h:34
The QLocalServer class provides a local socket based server.
void newConnection()
This signal is emitted every time a new connection is available.
The QLocalSocket class provides a local socket.
void disconnected()
This signal is emitted when the socket has been disconnected.
LocalSocketState
This enum describes the different states in which a socket can be.
void stateChanged(QLocalSocket::LocalSocketState socketState)
This signal is emitted whenever QLocalSocket's state changes.
LocalSocketError
The LocalServerError enumeration represents the errors that can occur.
void errorOccurred(QLocalSocket::LocalSocketError socketError)
\inmodule QtCore
Definition qobject.h:103
QObject * parent() const
Returns a pointer to the parent object.
Definition qobject.h:346
static QMetaObject::Connection connect(const QObject *sender, const char *signal, const QObject *receiver, const char *member, Qt::ConnectionType=Qt::AutoConnection)
\threadsafe
Definition qobject.cpp:2960
void deleteLater()
\threadsafe
Definition qobject.cpp:2435
The QPacketProtocol class encapsulates communicating discrete packets across fragmented IO channels,...
void send(const QByteArray &data)
Transmit the packet.
void readyRead()
Emitted whenever a new packet is received.
The QPacket class encapsulates an unfragmentable packet of data to be transmitted by QPacketProtocol.
Definition qpacket_p.h:24
const QByteArray & data() const
Returns a reference to the raw packet data.
Definition qpacket.cpp:77
virtual void messageReceived(const QByteArray &message)
QHash< QString, float > serverPlugins
QHash< QString, QQmlDebugClient * > plugins
QQmlDebugConnection(QObject *parent=nullptr)
bool addClient(const QString &name, QQmlDebugClient *client)
void socketError(QAbstractSocket::SocketError socketError)
void setMaximumDataStreamVersion(int maximumVersion)
bool sendMessage(const QString &name, const QByteArray &message)
bool removeClient(const QString &name)
QQmlDebugClient * client(const QString &name) const
float serviceVersion(const QString &serviceName) const
void socketStateChanged(QAbstractSocket::SocketState socketState)
bool waitForConnected(int msecs=30000)
void startLocalServer(const QString &fileName)
void connectToHost(const QString &hostName, quint16 port)
\inmodule QtCore
\macro QT_RESTRICTED_CAST_FROM_ASCII
Definition qstring.h:129
void clear()
Clears the contents of the string and makes it null.
Definition qstring.h:1252
The QTcpSocket class provides a TCP socket.
Definition qtcpsocket.h:18
\inmodule QtCore
Definition qtimer.h:20
void setSingleShot(bool singleShot)
Definition qtimer.cpp:552
void setInterval(int msec)
Definition qtimer.cpp:579
void timeout(QPrivateSignal)
This signal is emitted when the timer times out.
else opt state
[0]
void newState(QList< State > &states, const char *token, const char *lexem, bool pre)
Combined button and popup list for selecting options.
@ QueuedConnection
DBusConnection const char DBusError DBusBusType DBusError return DBusConnection DBusHandleMessageFunction void DBusFreeFunction return DBusConnection return DBusConnection return const char DBusError return DBusConnection DBusMessage dbus_uint32_t return DBusConnection dbus_bool_t DBusConnection DBusAddWatchFunction DBusRemoveWatchFunction DBusWatchToggledFunction void DBusFreeFunction return DBusConnection DBusDispatchStatusFunction void DBusFreeFunction DBusTimeout return DBusTimeout return DBusWatch return DBusWatch unsigned int return DBusError const DBusError return const DBusMessage return DBusMessage return DBusMessage return DBusMessage return DBusMessage return DBusMessage return DBusMessageIter * iter
DBusConnection const char DBusError * error
EGLOutputPortEXT port
#define qWarning
Definition qlogging.h:166
GLuint GLsizei const GLchar * message
GLuint name
GLdouble GLdouble GLdouble GLdouble q
Definition qopenglext.h:259
static const QString serverId
static QT_BEGIN_NAMESPACE const int protocolVersion
static const QString clientId
QT_BEGIN_NAMESPACE const int protocolVersion
QLatin1StringView QLatin1String
Definition qstringfwd.h:31
#define Q_OBJECT
#define signals
#define emit
unsigned short quint16
Definition qtypes.h:48
QTcpSocket * socket
[1]