1 /***************************************************************************
2 * Copyright (C) 2005-2013 by the Quassel Project *
3 * devel@quassel-irc.org *
5 * This program is free software; you can redistribute it and/or modify *
6 * it under the terms of the GNU General Public License as published by *
7 * the Free Software Foundation; either version 2 of the License, or *
8 * (at your option) version 3. *
10 * This program is distributed in the hope that it will be useful, *
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of *
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
13 * GNU General Public License for more details. *
15 * You should have received a copy of the GNU General Public License *
16 * along with this program; if not, write to the *
17 * Free Software Foundation, Inc., *
18 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. *
19 ***************************************************************************/
21 #include "legacypeer.h"
23 using namespace Protocol;
25 LegacyPeer::LegacyPeer(QTcpSocket *socket, QObject *parent)
26 : RemotePeer(socket, parent),
28 _useCompression(false)
30 _stream.setDevice(socket);
31 _stream.setVersion(QDataStream::Qt_4_2);
33 connect(socket, SIGNAL(readyRead()), SLOT(socketDataAvailable()));
37 void LegacyPeer::setSignalProxy(::SignalProxy *proxy)
39 RemotePeer::setSignalProxy(proxy);
42 // enable compression now if requested - the initial handshake is uncompressed in the legacy protocol!
43 _useCompression = socket()->property("UseCompression").toBool();
49 void LegacyPeer::socketDataAvailable()
52 while (readSocketData(item)) {
53 // if no sigproxy is set, we're in handshake mode and let the data be handled elsewhere
55 emit dataReceived(item);
57 handlePackedFunc(item);
62 bool LegacyPeer::readSocketData(QVariant &item)
64 if (_blockSize == 0) {
65 if (socket()->bytesAvailable() < 4)
67 _stream >> _blockSize;
70 if (_blockSize > 1 << 22) {
71 close("Peer tried to send package larger than max package size!");
75 if (_blockSize == 0) {
76 close("Peer tried to send 0 byte package!");
80 if (socket()->bytesAvailable() < _blockSize) {
81 emit transferProgress(socket()->bytesAvailable(), _blockSize);
85 emit transferProgress(_blockSize, _blockSize);
89 if (_useCompression) {
93 int nbytes = rawItem.size();
95 const char *data = rawItem.constData();
96 if (nbytes < 4 || (data[0] != 0 || data[1] != 0 || data[2] != 0 || data[3] != 0)) {
97 close("Peer sent corrupted compressed data!");
102 rawItem = qUncompress(rawItem);
104 QDataStream itemStream(&rawItem, QIODevice::ReadOnly);
105 itemStream.setVersion(QDataStream::Qt_4_2);
112 if (!item.isValid()) {
113 close("Peer sent corrupt data: unable to load QVariant!");
121 void LegacyPeer::writeSocketData(const QVariant &item)
123 if (!socket()->isOpen()) {
124 qWarning() << Q_FUNC_INFO << "Can't write to a closed socket!";
129 QDataStream out(&block, QIODevice::WriteOnly);
130 out.setVersion(QDataStream::Qt_4_2);
132 if (_useCompression) {
134 QDataStream itemStream(&rawItem, QIODevice::WriteOnly);
135 itemStream.setVersion(QDataStream::Qt_4_2);
138 rawItem = qCompress(rawItem);
146 _stream << block; // also writes the length as part of the serialization format
150 void LegacyPeer::handlePackedFunc(const QVariant &packedFunc)
152 QVariantList params(packedFunc.toList());
154 if (params.isEmpty()) {
155 qWarning() << Q_FUNC_INFO << "Received incompatible data:" << packedFunc;
159 RequestType requestType = (RequestType)params.takeFirst().value<int>();
160 switch (requestType) {
162 if (params.count() < 3) {
163 qWarning() << Q_FUNC_INFO << "Received invalid sync call:" << params;
166 QByteArray className = params.takeFirst().toByteArray();
167 QString objectName = params.takeFirst().toString();
168 QByteArray slotName = params.takeFirst().toByteArray();
169 handle(Protocol::SyncMessage(className, objectName, slotName, params));
173 if (params.empty()) {
174 qWarning() << Q_FUNC_INFO << "Received empty RPC call!";
177 QByteArray slotName = params.takeFirst().toByteArray();
178 handle(Protocol::RpcCall(slotName, params));
182 if (params.count() != 2) {
183 qWarning() << Q_FUNC_INFO << "Received invalid InitRequest:" << params;
186 QByteArray className = params[0].toByteArray();
187 QString objectName = params[1].toString();
188 handle(Protocol::InitRequest(className, objectName));
192 if (params.count() != 3) {
193 qWarning() << Q_FUNC_INFO << "Received invalid InitData:" << params;
196 QByteArray className = params[0].toByteArray();
197 QString objectName = params[1].toString();
198 QVariantMap initData = params[2].toMap();
199 handle(Protocol::InitData(className, objectName, initData));
203 if (params.count() != 1) {
204 qWarning() << Q_FUNC_INFO << "Received invalid HeartBeat:" << params;
207 // The legacy protocol would only send a QTime, no QDateTime
208 // so we assume it's sent today, which works in exactly the same cases as it did in the old implementation
209 QDateTime dateTime = QDateTime::currentDateTimeUtc();
210 dateTime.setTime(params[0].toTime());
211 handle(Protocol::HeartBeat(dateTime));
214 case HeartBeatReply: {
215 if (params.count() != 1) {
216 qWarning() << Q_FUNC_INFO << "Received invalid HeartBeat:" << params;
219 // The legacy protocol would only send a QTime, no QDateTime
220 // so we assume it's sent today, which works in exactly the same cases as it did in the old implementation
221 QDateTime dateTime = QDateTime::currentDateTimeUtc();
222 dateTime.setTime(params[0].toTime());
223 handle(Protocol::HeartBeatReply(dateTime));
231 void LegacyPeer::dispatch(const Protocol::SyncMessage &msg)
233 dispatchPackedFunc(QVariantList() << (qint16)Sync << msg.className() << msg.objectName() << msg.slotName() << msg.params());
237 void LegacyPeer::dispatch(const Protocol::RpcCall &msg)
239 dispatchPackedFunc(QVariantList() << (qint16)RpcCall << msg.slotName() << msg.params());
243 void LegacyPeer::dispatch(const Protocol::InitRequest &msg)
245 dispatchPackedFunc(QVariantList() << (qint16)InitRequest << msg.className() << msg.objectName());
249 void LegacyPeer::dispatch(const Protocol::InitData &msg)
251 dispatchPackedFunc(QVariantList() << (qint16)InitData << msg.className() << msg.objectName() << msg.initData());
255 void LegacyPeer::dispatch(const Protocol::HeartBeat &msg)
257 dispatchPackedFunc(QVariantList() << (qint16)HeartBeat << msg.timestamp().time());
261 void LegacyPeer::dispatch(const Protocol::HeartBeatReply &msg)
263 dispatchPackedFunc(QVariantList() << (qint16)HeartBeatReply << msg.timestamp().time());
267 void LegacyPeer::dispatchPackedFunc(const QVariantList &packedFunc)
269 writeSocketData(QVariant(packedFunc));