1 /****************************************************************************
3 ** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
4 ** All rights reserved.
5 ** Contact: Nokia Corporation (qt-info@nokia.com)
7 ** This file is part of the QtDeclarative module of the Qt Toolkit.
9 ** $QT_BEGIN_LICENSE:LGPL$
10 ** No Commercial Usage
11 ** This file contains pre-release code and may not be distributed.
12 ** You may use this file in accordance with the terms and conditions
13 ** contained in the Technology Preview License Agreement accompanying
16 ** GNU Lesser General Public License Usage
17 ** Alternatively, this file may be used under the terms of the GNU Lesser
18 ** General Public License version 2.1 as published by the Free Software
19 ** Foundation and appearing in the file LICENSE.LGPL included in the
20 ** packaging of this file. Please review the following information to
21 ** ensure the GNU Lesser General Public License version 2.1 requirements
22 ** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
24 ** In addition, as a special exception, Nokia gives you certain additional
25 ** rights. These rights are described in the Nokia Qt LGPL Exception
26 ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
28 ** If you have questions regarding the use of this file, please contact
29 ** Nokia at qt-info@nokia.com.
40 ****************************************************************************/
42 #include "private/qdeclarativedebugserver_p.h"
43 #include "private/qdeclarativedebugservice_p.h"
44 #include "private/qdeclarativedebugservice_p_p.h"
45 #include "private/qdeclarativeengine_p.h"
47 #include "private/qpacketprotocol_p.h"
49 #include <QtCore/QStringList>
51 #include <QtNetwork/qtcpserver.h>
52 #include <QtNetwork/qtcpsocket.h>
54 #include <private/qobject_p.h>
55 #include <private/qapplication_p.h>
60 QDeclarativeDebug Protocol (Version 1):
64 "QDeclarativeDebugServer" 0 version pluginNames
65 version: an int representing the highest protocol version the client knows
66 pluginNames: plugins available on client side
68 "QDeclarativeDebugClient" 0 version pluginNames
69 version: an int representing the highest protocol version the client & server know
70 pluginNames: plugins available on server side. plugins both in the client and server message are enabled.
71 client plugin advertisement
73 "QDeclarativeDebugServer" 1 pluginNames
74 server plugin advertisement
76 "QDeclarativeDebugClient" 1 pluginNames
78 Everything send with a header different to "QDeclarativeDebugServer" is sent to the appropriate plugin.
81 const int protocolVersion = 1;
84 class QDeclarativeDebugServerPrivate : public QObjectPrivate
86 Q_DECLARE_PUBLIC(QDeclarativeDebugServer)
88 QDeclarativeDebugServerPrivate();
90 void advertisePlugins();
93 QTcpSocket *connection;
94 QPacketProtocol *protocol;
95 QHash<QString, QDeclarativeDebugService *> plugins;
96 QStringList clientPlugins;
97 QTcpServer *tcpServer;
101 QDeclarativeDebugServerPrivate::QDeclarativeDebugServerPrivate()
102 : connection(0), protocol(0), gotHello(false)
106 void QDeclarativeDebugServerPrivate::advertisePlugins()
109 || connection->state() != QTcpSocket::ConnectedState
114 pack << QString(QLatin1String("QDeclarativeDebugClient")) << 1 << plugins.keys();
115 protocol->send(pack);
119 void QDeclarativeDebugServer::listen()
121 Q_D(QDeclarativeDebugServer);
123 d->tcpServer = new QTcpServer(this);
124 QObject::connect(d->tcpServer, SIGNAL(newConnection()), this, SLOT(newConnection()));
125 if (d->tcpServer->listen(QHostAddress::Any, d->port))
126 qWarning("QDeclarativeDebugServer: Waiting for connection on port %d...", d->port);
128 qWarning("QDeclarativeDebugServer: Unable to listen on port %d", d->port);
131 void QDeclarativeDebugServer::waitForConnection()
133 Q_D(QDeclarativeDebugServer);
134 d->tcpServer->waitForNewConnection(-1);
137 void QDeclarativeDebugServer::newConnection()
139 Q_D(QDeclarativeDebugServer);
142 qWarning("QDeclarativeDebugServer error: another client is already connected");
143 QTcpSocket *faultyConnection = d->tcpServer->nextPendingConnection();
144 delete faultyConnection;
148 d->connection = d->tcpServer->nextPendingConnection();
149 d->connection->setParent(this);
150 d->protocol = new QPacketProtocol(d->connection, this);
151 QObject::connect(d->protocol, SIGNAL(readyRead()), this, SLOT(readyRead()));
154 bool QDeclarativeDebugServer::hasDebuggingClient() const
156 Q_D(const QDeclarativeDebugServer);
158 && (d->connection->state() == QTcpSocket::ConnectedState)
162 QDeclarativeDebugServer *QDeclarativeDebugServer::instance()
164 static bool commandLineTested = false;
165 static QDeclarativeDebugServer *server = 0;
167 if (!commandLineTested) {
168 commandLineTested = true;
170 #ifndef QDECLARATIVE_NO_DEBUG_PROTOCOL
171 QApplicationPrivate *appD = static_cast<QApplicationPrivate*>(QObjectPrivate::get(qApp));
172 // ### remove port definition when protocol is changed
177 // format: qmljsdebugger=port:3768[,block]
178 if (!appD->qmljsDebugArgumentsString().isEmpty()) {
179 if (!QDeclarativeEnginePrivate::qml_debugging_enabled) {
180 const QString message =
181 QString::fromAscii("QDeclarativeDebugServer: Ignoring \"-qmljsdebugger=%1\". "
182 "Debugging has not been enabled.").arg(
183 appD->qmljsDebugArgumentsString());
184 qWarning("%s", qPrintable(message));
188 if (appD->qmljsDebugArgumentsString().indexOf(QLatin1String("port:")) == 0) {
189 int separatorIndex = appD->qmljsDebugArgumentsString().indexOf(QLatin1Char(','));
190 port = appD->qmljsDebugArgumentsString().mid(5, separatorIndex - 5).toInt(&ok);
192 block = appD->qmljsDebugArgumentsString().contains(QLatin1String("block"));
195 server = new QDeclarativeDebugServer(port);
198 server->waitForConnection();
201 qWarning(QString::fromAscii("QDeclarativeDebugServer: Ignoring \"-qmljsdebugger=%1\". "
202 "Format is -qmljsdebugger=port:<port>[,block]").arg(
203 appD->qmljsDebugArgumentsString()).toAscii().constData());
212 QDeclarativeDebugServer::QDeclarativeDebugServer(int port)
213 : QObject(*(new QDeclarativeDebugServerPrivate))
215 Q_D(QDeclarativeDebugServer);
219 void QDeclarativeDebugServer::readyRead()
221 Q_D(QDeclarativeDebugServer);
224 QPacket hello = d->protocol->read();
230 if (name != QLatin1String("QDeclarativeDebugServer")
232 qWarning("QDeclarativeDebugServer: Invalid hello message");
233 QObject::disconnect(d->protocol, SIGNAL(readyRead()), this, SLOT(readyRead()));
234 d->protocol->deleteLater();
236 d->connection->deleteLater();
242 hello >> version >> d->clientPlugins;
244 QHash<QString, QDeclarativeDebugService*>::Iterator iter = d->plugins.begin();
245 for (; iter != d->plugins.end(); ++iter) {
246 QDeclarativeDebugService::Status newStatus = QDeclarativeDebugService::Unavailable;
247 if (d->clientPlugins.contains(iter.key()))
248 newStatus = QDeclarativeDebugService::Enabled;
249 iter.value()->d_func()->status = newStatus;
250 iter.value()->statusChanged(newStatus);
254 helloAnswer << QString(QLatin1String("QDeclarativeDebugClient")) << 0 << protocolVersion << d->plugins.keys();
255 d->protocol->send(helloAnswer);
256 d->connection->flush();
259 qWarning("QDeclarativeDebugServer: Connection established");
262 QString debugServer(QLatin1String("QDeclarativeDebugServer"));
264 while (d->protocol->packetsAvailable()) {
265 QPacket pack = d->protocol->read();
270 if (name == debugServer) {
276 QStringList oldClientPlugins = d->clientPlugins;
277 pack >> d->clientPlugins;
279 QHash<QString, QDeclarativeDebugService*>::Iterator iter = d->plugins.begin();
280 for (; iter != d->plugins.end(); ++iter) {
281 const QString pluginName = iter.key();
282 QDeclarativeDebugService::Status newStatus = QDeclarativeDebugService::Unavailable;
283 if (d->clientPlugins.contains(pluginName))
284 newStatus = QDeclarativeDebugService::Enabled;
286 if (oldClientPlugins.contains(pluginName)
287 != d->clientPlugins.contains(pluginName)) {
288 iter.value()->d_func()->status = newStatus;
289 iter.value()->statusChanged(newStatus);
293 qWarning("QDeclarativeDebugServer: Invalid control message %d", op);
299 QHash<QString, QDeclarativeDebugService *>::Iterator iter =
300 d->plugins.find(name);
301 if (iter == d->plugins.end()) {
302 qWarning() << "QDeclarativeDebugServer: Message received for missing plugin" << name;
304 (*iter)->messageReceived(message);
311 QList<QDeclarativeDebugService*> QDeclarativeDebugServer::services() const
313 const Q_D(QDeclarativeDebugServer);
314 return d->plugins.values();
317 QStringList QDeclarativeDebugServer::serviceNames() const
319 const Q_D(QDeclarativeDebugServer);
320 return d->plugins.keys();
323 bool QDeclarativeDebugServer::addService(QDeclarativeDebugService *service)
325 Q_D(QDeclarativeDebugServer);
326 if (!service || d->plugins.contains(service->name()))
329 d->plugins.insert(service->name(), service);
330 d->advertisePlugins();
332 QDeclarativeDebugService::Status newStatus = QDeclarativeDebugService::Unavailable;
333 if (d->clientPlugins.contains(service->name()))
334 newStatus = QDeclarativeDebugService::Enabled;
335 service->d_func()->status = newStatus;
336 service->statusChanged(newStatus);
340 bool QDeclarativeDebugServer::removeService(QDeclarativeDebugService *service)
342 Q_D(QDeclarativeDebugServer);
343 if (!service || !d->plugins.contains(service->name()))
346 d->plugins.remove(service->name());
347 d->advertisePlugins();
349 QDeclarativeDebugService::Status newStatus = QDeclarativeDebugService::NotConnected;
350 service->d_func()->server = 0;
351 service->d_func()->status = newStatus;
352 service->statusChanged(newStatus);
356 void QDeclarativeDebugServer::sendMessage(QDeclarativeDebugService *service,
357 const QByteArray &message)
359 Q_D(QDeclarativeDebugServer);
361 pack << service->name() << message;
362 d->protocol->send(pack);
363 d->connection->flush();