Initial import from the monolithic Qt.
[profile/ivi/qtdeclarative.git] / src / declarative / debugger / qpacketprotocol.cpp
1 /****************************************************************************
2 **
3 ** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
4 ** All rights reserved.
5 ** Contact: Nokia Corporation (qt-info@nokia.com)
6 **
7 ** This file is part of the QtDeclarative module of the Qt Toolkit.
8 **
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
14 ** this package.
15 **
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.
23 **
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.
27 **
28 ** If you have questions regarding the use of this file, please contact
29 ** Nokia at qt-info@nokia.com.
30 **
31 **
32 **
33 **
34 **
35 **
36 **
37 **
38 ** $QT_END_LICENSE$
39 **
40 ****************************************************************************/
41
42 #include "private/qpacketprotocol_p.h"
43
44 #include <QBuffer>
45
46 QT_BEGIN_NAMESPACE
47
48 #define MAX_PACKET_SIZE 0x7FFFFFFF
49
50 /*!
51   \class QPacketProtocol
52   \internal
53
54   \brief The QPacketProtocol class encapsulates communicating discrete packets
55   across fragmented IO channels, such as TCP sockets.
56
57   QPacketProtocol makes it simple to send arbitrary sized data "packets" across 
58   fragmented transports such as TCP and UDP.
59
60   As transmission boundaries are not respected, sending packets over protocols
61   like TCP frequently involves "stitching" them back together at the receiver.
62   QPacketProtocol makes this easier by performing this task for you.  Packet
63   data sent using QPacketProtocol is prepended with a 4-byte size header
64   allowing the receiving QPacketProtocol to buffer the packet internally until
65   it has all been received.  QPacketProtocol does not perform any sanity
66   checking on the size or on the data, so this class should only be used in
67   prototyping or trusted situations where DOS attacks are unlikely.
68
69   QPacketProtocol does not perform any communications itself.  Instead it can
70   operate on any QIODevice that supports the QIODevice::readyRead() signal.  A
71   logical "packet" is encapsulated by the companion QPacket class.  The
72   following example shows two ways to send data using QPacketProtocol.  The
73   transmitted data is equivalent in both.
74
75   \code
76   QTcpSocket socket;
77   // ... connect socket ...
78
79   QPacketProtocol protocol(&socket);
80
81   // Send packet the quick way
82   protocol.send() << "Hello world" << 123;
83
84   // Send packet the longer way
85   QPacket packet;
86   packet << "Hello world" << 123;
87   protocol.send(packet);
88   \endcode
89
90   Likewise, the following shows how to read data from QPacketProtocol, assuming
91   that the QPacketProtocol::readyRead() signal has been emitted.
92
93   \code
94   // ... QPacketProtocol::readyRead() is emitted ...
95
96   int a;
97   QByteArray b;
98
99   // Receive packet the quick way
100   protocol.read() >> a >> b;
101
102   // Receive packet the longer way
103   QPacket packet = protocol.read();
104   p >> a >> b;
105   \endcode
106
107   \ingroup io
108   \sa QPacket
109 */
110
111 class QPacketProtocolPrivate : public QObject
112 {
113 Q_OBJECT
114 public:
115     QPacketProtocolPrivate(QPacketProtocol * parent, QIODevice * _dev)
116     : QObject(parent), inProgressSize(-1), maxPacketSize(MAX_PACKET_SIZE),
117       dev(_dev)
118     {
119         Q_ASSERT(4 == sizeof(qint32));
120
121         QObject::connect(this, SIGNAL(readyRead()),
122                          parent, SIGNAL(readyRead()));
123         QObject::connect(this, SIGNAL(packetWritten()),
124                          parent, SIGNAL(packetWritten()));
125         QObject::connect(this, SIGNAL(invalidPacket()),
126                          parent, SIGNAL(invalidPacket()));
127         QObject::connect(dev, SIGNAL(readyRead()),
128                          this, SLOT(readyToRead()), Qt::QueuedConnection);
129         QObject::connect(dev, SIGNAL(aboutToClose()),
130                          this, SLOT(aboutToClose()));
131         QObject::connect(dev, SIGNAL(bytesWritten(qint64)),
132                          this, SLOT(bytesWritten(qint64)));
133     }
134
135 Q_SIGNALS:
136     void readyRead();
137     void packetWritten();
138     void invalidPacket();
139
140 public Q_SLOTS:
141     void aboutToClose()
142     {
143         inProgress.clear();
144         sendingPackets.clear();
145         inProgressSize = -1;
146     }
147
148     void bytesWritten(qint64 bytes)
149     {
150         Q_ASSERT(!sendingPackets.isEmpty());
151
152         while(bytes) {
153             if(sendingPackets.at(0) > bytes) {
154                 sendingPackets[0] -= bytes;
155                 bytes = 0;
156             } else {
157                 bytes -= sendingPackets.at(0);
158                 sendingPackets.removeFirst();
159                 emit packetWritten();
160             }
161         }
162     }
163
164     void readyToRead()
165     {
166         if(-1 == inProgressSize) {
167             // We need a size header of sizeof(qint32)
168             if(sizeof(qint32) > (uint)dev->bytesAvailable())
169                 return;
170
171             // Read size header
172             int read = dev->read((char *)&inProgressSize, sizeof(qint32));
173             Q_ASSERT(read == sizeof(qint32));
174             Q_UNUSED(read);
175
176             // Check sizing constraints
177             if(inProgressSize > maxPacketSize) {
178                 QObject::disconnect(dev, SIGNAL(readyRead()),
179                                     this, SLOT(readyToRead()));
180                 QObject::disconnect(dev, SIGNAL(aboutToClose()),
181                                     this, SLOT(aboutToClose()));
182                 QObject::disconnect(dev, SIGNAL(bytesWritten(qint64)),
183                                     this, SLOT(bytesWritten(qint64)));
184                 dev = 0;
185                 emit invalidPacket();
186                 return;
187             }
188
189             inProgressSize -= sizeof(qint32);
190
191             // Need to get trailing data
192             readyToRead();
193         } else {
194             inProgress.append(dev->read(inProgressSize - inProgress.size()));
195
196             if(inProgressSize == inProgress.size()) {
197                 // Packet has arrived!
198                 packets.append(inProgress);
199                 inProgressSize = -1;
200                 inProgress.clear();
201
202                 emit readyRead();
203
204                 // Need to get trailing data
205                 readyToRead();
206             }
207         }
208     }
209
210 public:
211     QList<qint64> sendingPackets;
212     QList<QByteArray> packets;
213     QByteArray inProgress;
214     qint32 inProgressSize;
215     qint32 maxPacketSize;
216     QIODevice * dev;
217 };
218
219 /*!
220   Construct a QPacketProtocol instance that works on \a dev with the
221   specified \a parent.
222  */
223 QPacketProtocol::QPacketProtocol(QIODevice * dev, QObject * parent)
224 : QObject(parent), d(new QPacketProtocolPrivate(this, dev))
225 {
226     Q_ASSERT(dev);
227 }
228
229 /*!
230   Destroys the QPacketProtocol instance.
231  */
232 QPacketProtocol::~QPacketProtocol()
233 {
234 }
235
236 /*!
237   Returns the maximum packet size allowed.  By default this is
238   2,147,483,647 bytes.  
239   
240   If a packet claiming to be larger than the maximum packet size is received,
241   the QPacketProtocol::invalidPacket() signal is emitted.
242
243   \sa QPacketProtocol::setMaximumPacketSize()
244  */
245 qint32 QPacketProtocol::maximumPacketSize() const
246 {
247     return d->maxPacketSize;
248 }
249
250 /*!
251   Sets the maximum allowable packet size to \a max.
252
253   \sa QPacketProtocol::maximumPacketSize()
254  */
255 qint32 QPacketProtocol::setMaximumPacketSize(qint32 max)
256 {
257     if(max > (signed)sizeof(qint32))
258         d->maxPacketSize = max;
259     return d->maxPacketSize;
260 }
261
262 /*!
263   Returns a streamable object that is transmitted on destruction.  For example
264
265   \code
266   protocol.send() << "Hello world" << 123;
267   \endcode
268
269   will send a packet containing "Hello world" and 123.  To construct more 
270   complex packets, explicitly construct a QPacket instance.
271  */
272 QPacketAutoSend QPacketProtocol::send()
273 {
274     return QPacketAutoSend(this);
275 }
276
277 /*!
278   \fn void QPacketProtocol::send(const QPacket & packet)
279
280   Transmit the \a packet.
281  */
282 void QPacketProtocol::send(const QPacket & p)
283 {
284     if(p.b.isEmpty())
285         return; // We don't send empty packets
286
287     qint64 sendSize = p.b.size() + sizeof(qint32);
288
289     d->sendingPackets.append(sendSize);
290     qint32 sendSize32 = sendSize;
291     qint64 writeBytes = d->dev->write((char *)&sendSize32, sizeof(qint32));
292     Q_ASSERT(writeBytes == sizeof(qint32));
293     writeBytes = d->dev->write(p.b);
294     Q_ASSERT(writeBytes == p.b.size());
295 }
296
297 /*!
298   Returns the number of received packets yet to be read.
299   */
300 qint64 QPacketProtocol::packetsAvailable() const
301 {
302     return d->packets.count();
303 }
304
305 /*!
306   Discard any unread packets.
307   */
308 void QPacketProtocol::clear()
309 {
310     d->packets.clear();
311 }
312
313 /*!
314   Return the next unread packet, or an invalid QPacket instance if no packets
315   are available.  This method does NOT block.
316   */
317 QPacket QPacketProtocol::read()
318 {
319     if(0 == d->packets.count())
320         return QPacket();
321
322     QPacket rv(d->packets.at(0));
323     d->packets.removeFirst();
324     return rv;
325 }
326
327 /*!
328   Return the QIODevice passed to the QPacketProtocol constructor.
329 */
330 QIODevice * QPacketProtocol::device()
331 {
332     return d->dev;
333 }
334
335 /*!
336   \fn void QPacketProtocol::readyRead()
337
338   Emitted whenever a new packet is received.  Applications may use
339   QPacketProtocol::read() to retrieve this packet.
340  */
341
342 /*!
343   \fn void QPacketProtocol::invalidPacket()
344
345   A packet larger than the maximum allowable packet size was received.  The
346   packet will be discarded and, as it indicates corruption in the protocol, no
347   further packets will be received.
348  */
349
350 /*!
351   \fn void QPacketProtocol::packetWritten()
352
353   Emitted each time a packet is completing written to the device.  This signal
354   may be used for communications flow control.
355  */
356
357 /*!
358   \class QPacket
359   \internal
360
361   \brief The QPacket class encapsulates an unfragmentable packet of data to be
362   transmitted by QPacketProtocol.
363
364   The QPacket class works together with QPacketProtocol to make it simple to
365   send arbitrary sized data "packets" across fragmented transports such as TCP
366   and UDP.
367
368   QPacket provides a QDataStream interface to an unfragmentable packet.
369   Applications should construct a QPacket, propagate it with data and then
370   transmit it over a QPacketProtocol instance.  For example:
371   \code
372   QPacketProtocol protocol(...);
373
374   QPacket myPacket;
375   myPacket << "Hello world!" << 123;
376   protocol.send(myPacket);
377   \endcode
378
379   As long as both ends of the connection are using the QPacketProtocol class,
380   the data within this packet will be delivered unfragmented at the other end,
381   ready for extraction.
382
383   \code
384   QByteArray greeting;
385   int count;
386
387   QPacket myPacket = protocol.read();
388
389   myPacket >> greeting >> count;
390   \endcode
391
392   Only packets returned from QPacketProtocol::read() may be read from.  QPacket
393   instances constructed by directly by applications are for transmission only 
394   and are considered "write only".  Attempting to read data from them will 
395   result in undefined behavior.
396
397   \ingroup io
398   \sa QPacketProtocol
399  */
400
401 /*!
402   Constructs an empty write-only packet.
403   */
404 QPacket::QPacket()
405 : QDataStream(), buf(0)
406 {
407     buf = new QBuffer(&b);
408     buf->open(QIODevice::WriteOnly);
409     setDevice(buf);
410     setVersion(QDataStream::Qt_4_7);
411 }
412
413 /*!
414   Destroys the QPacket instance.
415   */
416 QPacket::~QPacket()
417 {
418     if(buf) {
419         delete buf;
420         buf = 0;
421     }
422 }
423
424 /*!
425   Creates a copy of \a other.  The initial stream positions are shared, but the
426   two packets are otherwise independent.
427  */
428 QPacket::QPacket(const QPacket & other)
429 : QDataStream(), b(other.b), buf(0)
430 {
431     buf = new QBuffer(&b);
432     buf->open(other.buf->openMode());
433     setDevice(buf);
434 }
435
436 /*!
437   \internal
438   */
439 QPacket::QPacket(const QByteArray & ba)
440 : QDataStream(), b(ba), buf(0)
441 {
442     buf = new QBuffer(&b);
443     buf->open(QIODevice::ReadOnly);
444     setDevice(buf);
445 }
446
447 /*!
448   Returns true if this packet is empty - that is, contains no data.
449   */
450 bool QPacket::isEmpty() const
451 {
452     return b.isEmpty();
453 }
454
455 /*!
456   Returns raw packet data.
457   */
458 QByteArray QPacket::data() const
459 {
460     return b;
461 }
462
463 /*!
464   Clears data in the packet.  This is useful for reusing one writable packet.
465   For example
466   \code
467   QPacketProtocol protocol(...);
468
469   QPacket packet;
470
471   packet << "Hello world!" << 123;
472   protocol.send(packet);
473
474   packet.clear();
475   packet << "Goodbyte world!" << 789;
476   protocol.send(packet);
477   \endcode
478  */
479 void QPacket::clear()
480 {
481     QBuffer::OpenMode oldMode = buf->openMode();
482     buf->close();
483     b.clear();
484     buf->setBuffer(&b); // reset QBuffer internals with new size of b.
485     buf->open(oldMode);
486 }
487
488 /*!
489   \class QPacketAutoSend
490   \internal
491
492   \internal
493   */
494 QPacketAutoSend::QPacketAutoSend(QPacketProtocol * _p)
495 : QPacket(), p(_p)
496 {
497 }
498
499 QPacketAutoSend::~QPacketAutoSend()
500 {
501     if(!b.isEmpty())
502         p->send(*this);
503 }
504
505 QT_END_NAMESPACE
506
507 #include <qpacketprotocol.moc>