|
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> |