summaryrefslogtreecommitdiffstats
path: root/src/declarative/debugger/qdeclarativedebugservice.cpp
diff options
context:
space:
mode:
authorKai Koehne <kai.koehne@nokia.com>2010-09-22 19:03:57 (GMT)
committerKai Koehne <kai.koehne@nokia.com>2010-09-28 05:55:32 (GMT)
commitfd9771c29d401d88779ab7c5d7715c9ca41dd723 (patch)
tree0e96e0871e8914f5747bfc1a1314d76a78620b6d /src/declarative/debugger/qdeclarativedebugservice.cpp
parent7b796b4dcdebfba55c4754d241edb334217fc550 (diff)
downloadQt-fd9771c29d401d88779ab7c5d7715c9ca41dd723.zip
Qt-fd9771c29d401d88779ab7c5d7715c9ca41dd723.tar.gz
Qt-fd9771c29d401d88779ab7c5d7715c9ca41dd723.tar.bz2
Make QmlDebug protocol more robust
The protocol so far was client->server only. That is, there was no sane way for a client to check whether a plugin on the server (service) was available or not. E.g. calling Client::setEnabled(true) 'succeeded', without a check whether there is actually a service to talk to. The new protocol replaces this shortcoming by a service discovery mechanism: Both client & service announce their available plugins at handshake time, and later on if there are changes. The status is reflected in Client::status() and Service::Status() , which are either NotConnected - no network connection, or not registered properly Unavailable - TCP/IP connection works, but no plugin with the same name on the other side Enabled - You can connect to plugin on other side The status changes happen automatically (no setEnabled() anymore). Furthermore a version ID was added to the handshake, so that we can extend the protocol further in the future :)
Diffstat (limited to 'src/declarative/debugger/qdeclarativedebugservice.cpp')
-rw-r--r--src/declarative/debugger/qdeclarativedebugservice.cpp126
1 files changed, 99 insertions, 27 deletions
diff --git a/src/declarative/debugger/qdeclarativedebugservice.cpp b/src/declarative/debugger/qdeclarativedebugservice.cpp
index 1f2bf4f..0fbc1e3 100644
--- a/src/declarative/debugger/qdeclarativedebugservice.cpp
+++ b/src/declarative/debugger/qdeclarativedebugservice.cpp
@@ -54,6 +54,30 @@
QT_BEGIN_NAMESPACE
+/*
+ QDeclarativeDebug Protocol (Version 1):
+
+ handshake:
+ 1. Client sends
+ "QDeclarativeDebugServer" 0 version pluginNames
+ version: an int representing the highest protocol version the client knows
+ pluginNames: plugins available on client side
+ 2. Server sends
+ "QDeclarativeDebugClient" 0 version pluginNames
+ version: an int representing the highest protocol version the client & server know
+ pluginNames: plugins available on server side. plugins both in the client and server message are enabled.
+ client plugin advertisement
+ 1. Client sends
+ "QDeclarativeDebugServer" 1 pluginNames
+ server plugin advertisement
+ 1. Server sends
+ "QDeclarativeDebugClient" 1 pluginNames
+ plugin communication:
+ Everything send with a header different to "QDeclarativeDebugServer" is sent to the appropriate plugin.
+ */
+
+const int protocolVersion = 1;
+
class QDeclarativeDebugServerPrivate;
class QDeclarativeDebugServer : public QObject
{
@@ -82,11 +106,13 @@ class QDeclarativeDebugServerPrivate : public QObjectPrivate
public:
QDeclarativeDebugServerPrivate();
+ void advertisePlugins();
+
int port;
QTcpSocket *connection;
QPacketProtocol *protocol;
QHash<QString, QDeclarativeDebugService *> plugins;
- QStringList enabledPlugins;
+ QStringList clientPlugins;
QTcpServer *tcpServer;
bool gotHello;
};
@@ -106,6 +132,18 @@ QDeclarativeDebugServerPrivate::QDeclarativeDebugServerPrivate()
{
}
+void QDeclarativeDebugServerPrivate::advertisePlugins()
+{
+ if (!connection
+ || connection->state() != QTcpSocket::ConnectedState
+ || !gotHello)
+ return;
+
+ QPacket pack;
+ pack << QString(QLatin1String("QDeclarativeDebugClient")) << 1 << plugins.keys();
+ protocol->send(pack);
+}
+
void QDeclarativeDebugServer::listen()
{
Q_D(QDeclarativeDebugServer);
@@ -202,9 +240,13 @@ void QDeclarativeDebugServer::readyRead()
if (!d->gotHello) {
QPacket hello = d->protocol->read();
- QString name;
- hello >> name >> d->enabledPlugins;
- if (name != QLatin1String("QDeclarativeDebugServer")) {
+
+ QString name;
+ int op;
+ hello >> name >> op;
+
+ if (name != QLatin1String("QDeclarativeDebugServer")
+ || op != 0) {
qWarning("QDeclarativeDebugServer: Invalid hello message");
QObject::disconnect(d->protocol, SIGNAL(readyRead()), this, SLOT(readyRead()));
d->protocol->deleteLater();
@@ -213,6 +255,23 @@ void QDeclarativeDebugServer::readyRead()
d->connection = 0;
return;
}
+
+ int version;
+ hello >> version >> d->clientPlugins;
+
+ QHash<QString, QDeclarativeDebugService*>::Iterator iter = d->plugins.begin();
+ for (; iter != d->plugins.end(); ++iter) {
+ QDeclarativeDebugService::Status newStatus = QDeclarativeDebugService::Unavailable;
+ if (d->clientPlugins.contains(iter.key()))
+ newStatus = QDeclarativeDebugService::Enabled;
+ iter.value()->statusChanged(newStatus);
+ }
+
+ QPacket helloAnswer;
+ helloAnswer << QString(QLatin1String("QDeclarativeDebugClient")) << 0 << protocolVersion << d->plugins.keys();
+ d->protocol->send(helloAnswer);
+ d->connection->flush();
+
d->gotHello = true;
qWarning("QDeclarativeDebugServer: Connection established");
}
@@ -226,32 +285,29 @@ void QDeclarativeDebugServer::readyRead()
pack >> name;
if (name == debugServer) {
- int op = -1; QString plugin;
- pack >> op >> plugin;
+ int op = -1;
+ pack >> op;
if (op == 1) {
- // Enable
- if (!d->enabledPlugins.contains(plugin)) {
- d->enabledPlugins.append(plugin);
- QHash<QString, QDeclarativeDebugService *>::Iterator iter =
- d->plugins.find(plugin);
- if (iter != d->plugins.end())
- (*iter)->enabledChanged(true);
- }
-
- } else if (op == 2) {
- // Disable
- if (d->enabledPlugins.contains(plugin)) {
- d->enabledPlugins.removeAll(plugin);
- QHash<QString, QDeclarativeDebugService *>::Iterator iter =
- d->plugins.find(plugin);
- if (iter != d->plugins.end())
- (*iter)->enabledChanged(false);
+ // Service Discovery
+ QStringList oldClientPlugins = d->clientPlugins;
+ pack >> d->clientPlugins;
+
+ QHash<QString, QDeclarativeDebugService*>::Iterator iter = d->plugins.begin();
+ for (; iter != d->plugins.end(); ++iter) {
+ const QString pluginName = iter.key();
+ QDeclarativeDebugService::Status newStatus = QDeclarativeDebugService::Unavailable;
+ if (d->clientPlugins.contains(pluginName))
+ newStatus = QDeclarativeDebugService::Enabled;
+
+ if (oldClientPlugins.contains(pluginName)
+ != d->clientPlugins.contains(pluginName)) {
+ iter.value()->statusChanged(newStatus);
+ }
}
} else {
qWarning("QDeclarativeDebugServer: Invalid control message %d", op);
}
-
} else {
QByteArray message;
pack >> message;
@@ -287,6 +343,16 @@ QDeclarativeDebugService::QDeclarativeDebugService(const QString &name, QObject
d->server = 0;
} else {
d->server->d_func()->plugins.insert(name, this);
+ d->server->d_func()->advertisePlugins();
+ }
+}
+
+QDeclarativeDebugService::~QDeclarativeDebugService()
+{
+ Q_D(const QDeclarativeDebugService);
+ if (d->server) {
+ d->server->d_func()->plugins.remove(d->name);
+ d->server->d_func()->advertisePlugins();
}
}
@@ -296,10 +362,16 @@ QString QDeclarativeDebugService::name() const
return d->name;
}
-bool QDeclarativeDebugService::isEnabled() const
+QDeclarativeDebugService::Status QDeclarativeDebugService::status() const
{
Q_D(const QDeclarativeDebugService);
- return (d->server && d->server->d_func()->enabledPlugins.contains(d->name));
+ if (!d->server
+ || !d->server->hasDebuggingClient())
+ return NotConnected;
+ if (d->server->d_func()->clientPlugins.contains(d->name))
+ return Enabled;
+
+ return Unavailable;
}
namespace {
@@ -422,7 +494,7 @@ void QDeclarativeDebugService::sendMessage(const QByteArray &message)
d->server->d_func()->connection->flush();
}
-void QDeclarativeDebugService::enabledChanged(bool)
+void QDeclarativeDebugService::statusChanged(Status)
{
}