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