src/declarative/debugger/qpacketprotocol.cpp
changeset 30 5dc02b23752f
child 37 758a864f9613
equal deleted inserted replaced
29:b72c6db6890b 30:5dc02b23752f
       
     1 /****************************************************************************
       
     2 **
       
     3 ** Copyright (C) 2010 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()));
       
   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 }
       
   411 
       
   412 /*!
       
   413   Destroys the QPacket instance.
       
   414   */
       
   415 QPacket::~QPacket()
       
   416 {
       
   417     if(buf) {
       
   418         delete buf;
       
   419         buf = 0;
       
   420     }
       
   421 }
       
   422 
       
   423 /*!
       
   424   Creates a copy of \a other.  The initial stream positions are shared, but the
       
   425   two packets are otherwise independant.
       
   426  */
       
   427 QPacket::QPacket(const QPacket & other)
       
   428 : QDataStream(), b(other.b), buf(0)
       
   429 {
       
   430     buf = new QBuffer(&b);
       
   431     buf->open(other.buf->openMode());
       
   432     setDevice(buf);
       
   433 }
       
   434 
       
   435 /*!
       
   436   \internal
       
   437   */
       
   438 QPacket::QPacket(const QByteArray & ba)
       
   439 : QDataStream(), b(ba), buf(0)
       
   440 {
       
   441     buf = new QBuffer(&b);
       
   442     buf->open(QIODevice::ReadOnly);
       
   443     setDevice(buf);
       
   444 }
       
   445 
       
   446 /*!
       
   447   Returns true if this packet is empty - that is, contains no data.
       
   448   */
       
   449 bool QPacket::isEmpty() const
       
   450 {
       
   451     return b.isEmpty();
       
   452 }
       
   453 
       
   454 /*!
       
   455   Clears data in the packet.  This is useful for reusing one writable packet.
       
   456   For example
       
   457   \code
       
   458   QPacketProtocol protocol(...);
       
   459 
       
   460   QPacket packet;
       
   461 
       
   462   packet << "Hello world!" << 123;
       
   463   protocol.send(packet);
       
   464 
       
   465   packet.clear();
       
   466   packet << "Goodbyte world!" << 789;
       
   467   protocol.send(packet);
       
   468   \endcode
       
   469  */
       
   470 void QPacket::clear()
       
   471 {
       
   472     QBuffer::OpenMode oldMode = buf->openMode();
       
   473     buf->close();
       
   474     b.clear();
       
   475     buf->setBuffer(&b); // reset QBuffer internals with new size of b.
       
   476     buf->open(oldMode);
       
   477 }
       
   478 
       
   479 /*!
       
   480   \class QPacketAutoSend
       
   481   \internal
       
   482 
       
   483   \internal
       
   484   */
       
   485 QPacketAutoSend::QPacketAutoSend(QPacketProtocol * _p)
       
   486 : QPacket(), p(_p)
       
   487 {
       
   488 }
       
   489 
       
   490 QPacketAutoSend::~QPacketAutoSend()
       
   491 {
       
   492     if(!b.isEmpty())
       
   493         p->send(*this);
       
   494 }
       
   495 
       
   496 QT_END_NAMESPACE
       
   497 
       
   498 #include <qpacketprotocol.moc>