summaryrefslogtreecommitdiff
path: root/src/websockets/qwebsocket.cpp
blob: 6e60230d2743233cb0a70abc3428b23d1e16febe (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
/****************************************************************************
**
** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies).
** Contact: http://www.qt-project.org/legal
**
** This file is part of the QtWebSockets module of the Qt Toolkit.
**
** $QT_BEGIN_LICENSE:LGPL$
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and Digia.  For licensing terms and
** conditions see http://qt.digia.com/licensing.  For further information
** use the contact form at http://qt.digia.com/contact-us.
**
** GNU Lesser General Public License Usage
** Alternatively, this file may be used under the terms of the GNU Lesser
** General Public License version 2.1 as published by the Free Software
** Foundation and appearing in the file LICENSE.LGPL included in the
** packaging of this file.  Please review the following information to
** ensure the GNU Lesser General Public License version 2.1 requirements
** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
**
** In addition, as a special exception, Digia gives you certain additional
** rights.  These rights are described in the Digia Qt LGPL Exception
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
**
** GNU General Public License Usage
** Alternatively, this file may be used under the terms of the GNU
** General Public License version 3.0 as published by the Free Software
** Foundation and appearing in the file LICENSE.GPL included in the
** packaging of this file.  Please review the following information to
** ensure the GNU General Public License version 3.0 requirements will be
** met: http://www.gnu.org/copyleft/gpl.html.
**
**
** $QT_END_LICENSE$
**
****************************************************************************/

/*!
    \class QWebSocket

    \inmodule QtWebSockets
    \brief Implements a TCP socket that talks the websocket protocol.

    WebSockets is a web technology providing full-duplex communications channels over
    a single TCP connection.
    The WebSocket protocol was standardized by the IETF as
    \l {http://tools.ietf.org/html/rfc6455} {RFC 6455} in 2011.
    QWebSocket can both be used in a client application and server application.

    This class was modeled after QAbstractSocket.

    QWebSocket currently does not support
    \l {http://tools.ietf.org/html/rfc6455#page-39} {extensions} and
    \l {http://tools.ietf.org/html/rfc6455#page-12} {subprotocols}.

    QWebSocket only supports version 13 of the WebSocket protocol, as outlined in RFC 6455.

    \sa QAbstractSocket, QTcpSocket

    \sa {QWebSocket client example}
*/

/*!
    \page echoclient.html example
    \title QWebSocket client example
    \brief A sample websocket client that sends a message and displays the message that
    it receives back.

    \section1 Description
    The EchoClient example implements a web socket client that sends a message to a websocket server
    and dumps the answer that it gets back.
    This example should ideally be used with the EchoServer example.
    \section1 Code
    We start by connecting to the `connected()` signal.
    \snippet echoclient/echoclient.cpp constructor
    After the connection, we open the socket to the given \a url.

    \snippet echoclient/echoclient.cpp onConnected
    When the client is connected successfully, we connect to the `onTextMessageReceived()` signal,
    and send out "Hello, world!".
    If connected with the EchoServer, we will receive the same message back.

    \snippet echoclient/echoclient.cpp onTextMessageReceived
    Whenever a message is received, we write it out.
*/

/*!
  \fn void QWebSocket::connected()
  \brief Emitted when a connection is successfully established.
  A connection is successfully established when the socket is connected
  and the handshake was successful.
  \sa open(), disconnected()
*/
/*!
  \fn void QWebSocket::disconnected()
  \brief Emitted when the socket is disconnected.
  \sa close(), connected()
*/
/*!
    \fn void QWebSocket::aboutToClose()

    This signal is emitted when the socket is about to close.
    Connect this signal if you have operations that need to be performed before the socket closes
    (e.g., if you have data in a separate buffer that needs to be written to the device).

    \sa close()
 */
/*!
\fn void QWebSocket::proxyAuthenticationRequired(const QNetworkProxy &proxy, QAuthenticator *authenticator)

This signal can be emitted when a \a proxy that requires
authentication is used. The \a authenticator object can then be
filled in with the required details to allow authentication and
continue the connection.

\note It is not possible to use a QueuedConnection to connect to
this signal, as the connection will fail if the authenticator has
not been filled in with new information when the signal returns.

\sa QAuthenticator, QNetworkProxy
*/
/*!
    \fn void QWebSocket::stateChanged(QAbstractSocket::SocketState state);

    This signal is emitted whenever QWebSocket's state changes.
    The \a state parameter is the new state.

    \note QAbstractSocket::ConnectedState is emitted after the handshake has
    with the server has succeeded.

    QAbstractSocket::SocketState is not a registered metatype, so for queued
    connections, you will have to register it with Q_REGISTER_METATYPE() and
    qRegisterMetaType().

    \sa state()
*/
/*!
    \fn void QWebSocket::readChannelFinished()

    This signal is emitted when the input (reading) stream is closed in this device.
    It is emitted as soon as the closing is detected.

    \sa close()
*/
/*!
    \fn void QWebSocket::bytesWritten(qint64 bytes)

    This signal is emitted every time a payload of data has been written to the socket.
    The \a bytes argument is set to the number of bytes that were written in this payload.

    \note This signal has the same meaning both for secure and non-secure websockets.
    As opposed to QSslSocket, bytesWritten() is only emitted when encrypted data is effectively
    written (see QSslSocket:encryptedBytesWritten()).
    \sa close()
*/

/*!
    \fn void QWebSocket::textFrameReceived(const QString &frame, bool isLastFrame);

    This signal is emitted whenever a text frame is received. The \a frame contains the data and
    \a isLastFrame indicates whether this is the last frame of the complete message.

    This signal can be used to process large messages frame by frame, instead of waiting for the
    complete message to arrive.

    \sa binaryFrameReceived()
*/
/*!
    \fn void QWebSocket::binaryFrameReceived(const QByteArray &frame, bool isLastFrame);

    This signal is emitted whenever a binary frame is received. The \a frame contains the data and
    \a isLastFrame indicates whether this is the last frame of the complete message.

    This signal can be used to process large messages frame by frame, instead of waiting for the
    complete message to arrive.

    \sa textFrameReceived()
*/
/*!
    \fn void QWebSocket::textMessageReceived(const QString &message);

    This signal is emitted whenever a text message is received. The \a message contains the
    received text.

    \sa binaryMessageReceived()
*/
/*!
    \fn void QWebSocket::binaryMessageReceived(const QByteArray &message);

    This signal is emitted whenever a binary message is received. The \a message contains the
    received bytes.

    \sa textMessageReceived()
*/
/*!
    \fn void QWebSocket::error(QAbstractSocket::SocketError error);

    This signal is emitted after an error occurred. The \a error
    parameter describes the type of error that occurred.

    QAbstractSocket::SocketError is not a registered metatype, so for queued
    connections, you will have to register it with Q_DECLARE_METATYPE() and
    qRegisterMetaType().

    \sa error(), errorString()
*/
/*!
    \fn void QWebSocket::sslErrors(const QList<QSslError> &errors)
    QWebSocket emits this signal after the SSL handshake to indicate that one or more errors have
    occurred while establishing the identity of the peer.
    The errors are usually an indication that QWebSocket is unable to securely identify the peer.
    Unless any action is taken, the connection will be dropped after this signal has been emitted.
    If you want to continue connecting despite the errors that have occurred, you must call
    QWebSocket::ignoreSslErrors() from inside a slot connected to this signal.
    If you need to access the error list at a later point, you can call sslErrors()
    (without arguments).

    \a errors contains one or more errors that prevent QWebSocket from verifying the identity of
    the peer.

    \note You cannot use Qt::QueuedConnection when connecting to this signal, or calling
    QWebSocket::ignoreSslErrors() will have no effect.
*/
/*!
    \fn void QWebSocket::pong(quint64 elapsedTime, const QByteArray &payload)

    Emitted when a pong message is received in reply to a previous ping.
    \a elapsedTime contains the roundtrip time in milliseconds and \a payload contains an optional
    payload that was sent with the ping.

    \sa ping()
  */
#include "qwebsocket.h"
#include "qwebsocket_p.h"

#include <QtCore/QUrl>
#include <QtNetwork/QTcpSocket>
#include <QtCore/QByteArray>
#include <QtNetwork/QHostAddress>

#include <QtCore/QDebug>

#include <limits>

QT_BEGIN_NAMESPACE

/*!
 * \brief Creates a new QWebSocket with the given \a origin,
 * the \a version of the protocol to use and \a parent.
 *
 * The \a origin of the client is as specified \l {http://tools.ietf.org/html/rfc6454}{RFC 6454}.
 * (The \a origin is not required for non-web browser clients
 * (see \l {http://tools.ietf.org/html/rfc6455}{RFC 6455})).
 * \note Currently only V13 (\l {http://tools.ietf.org/html/rfc6455} {RFC 6455}) is supported
 */
QWebSocket::QWebSocket(const QString &origin,
                       QWebSocketProtocol::Version version,
                       QObject *parent) :
    QObject(*(new QWebSocketPrivate(origin, version, this)), parent)
{
    Q_D(QWebSocket);
    d->init();
}

/*!
 * \brief Destroys the QWebSocket. Closes the socket if it is still open,
 * and releases any used resources.
 */
QWebSocket::~QWebSocket()
{
}

/*!
 * \brief Aborts the current socket and resets the socket.
 * Unlike close(), this function immediately closes the socket,
 * discarding any pending data in the write buffer.
 */
void QWebSocket::abort()
{
    Q_D(QWebSocket);
    d->abort();
}

/*!
 * Returns the type of error that last occurred
 * \sa errorString()
 */
QAbstractSocket::SocketError QWebSocket::error() const
{
    Q_D(const QWebSocket);
    return d->error();
}

//only called by QWebSocketPrivate::upgradeFrom
/*!
  \internal
 */
QWebSocket::QWebSocket(QTcpSocket *pTcpSocket,
                       QWebSocketProtocol::Version version, QObject *parent) :
    QObject(*(new QWebSocketPrivate(pTcpSocket, version, this)), parent)
{
    Q_D(QWebSocket);
    d->init();
}

/*!
 * Returns a human-readable description of the last error that occurred
 *
 * \sa error()
 */
QString QWebSocket::errorString() const
{
    Q_D(const QWebSocket);
    return d->errorString();
}

/*!
    This function writes as much as possible from the internal write buffer
    to the underlying network socket, without blocking.
    If any data was written, this function returns true; otherwise false is returned.
    Call this function if you need QWebSocket to start sending buffered data immediately.
    The number of bytes successfully written depends on the operating system.
    In most cases, you do not need to call this function,
    because QWebSocket will start sending data automatically
    once control goes back to the event loop.
*/
bool QWebSocket::flush()
{
    Q_D(QWebSocket);
    return d->flush();
}

/*!
    \brief Sends the given \a message over the socket as a text message and
    returns the number of bytes actually sent.

    \sa sendBinaryMessage()
 */
qint64 QWebSocket::sendTextMessage(const QString &message)
{
    Q_D(QWebSocket);
    return d->sendTextMessage(message);
}

/*!
    \brief Sends the given \a data over the socket as a binary message and
    returns the number of bytes actually sent.

    \sa sendTextMessage()
 */
qint64 QWebSocket::sendBinaryMessage(const QByteArray &data)
{
    Q_D(QWebSocket);
    return d->sendBinaryMessage(data);
}

/*!
    \brief Gracefully closes the socket with the given \a closeCode and \a reason.

    Any data in the write buffer is flushed before the socket is closed.
    The \a closeCode is a QWebSocketProtocol::CloseCode indicating the reason to close, and
    \a reason describes the reason of the closure more in detail
 */
void QWebSocket::close(QWebSocketProtocol::CloseCode closeCode, const QString &reason)
{
    Q_D(QWebSocket);
    d->close(closeCode, reason);
}

/*!
    \brief Opens a websocket connection using the given \a url.
    If \a mask is true, all frames will be masked; this is only necessary for client side sockets;
    servers should never mask.
    \note A client socket must *always* mask its frames; servers may *never* mask its frames.
 */
void QWebSocket::open(const QUrl &url, bool mask)
{
    Q_D(QWebSocket);
    d->open(url, mask);
}

/*!
    \brief Pings the server to indicate that the connection is still alive.
    Additional \a payload can be sent along the ping message.

    The size of the \a payload cannot be bigger than 125.
    If it is larger, the \a payload is clipped to 125 bytes.

    \sa pong()
 */
void QWebSocket::ping(const QByteArray &payload)
{
    Q_D(QWebSocket);
    d->ping(payload);
}

#ifndef QT_NO_SSL
/*!
    This slot tells QWebSocket to ignore errors during QWebSocket's
    handshake phase and continue connecting. If you want to continue
    with the connection even if errors occur during the handshake
    phase, then you must call this slot, either from a slot connected
    to sslErrors(), or before the handshake phase. If you don't call
    this slot, either in response to errors or before the handshake,
    the connection will be dropped after the sslErrors() signal has
    been emitted.

    \warning Be sure to always let the user inspect the errors
    reported by the sslErrors() signal, and only call this method
    upon confirmation from the user that proceeding is ok.
    If there are unexpected errors, the connection should be aborted.
    Calling this method without inspecting the actual errors will
    most likely pose a security risk for your application. Use it
    with great care!

    \sa sslErrors(), QSslSocket::ignoreSslErrors(), QNetworkReply::ignoreSslErrors()
*/
void QWebSocket::ignoreSslErrors()
{
    Q_D(QWebSocket);
    d->ignoreSslErrors();
}

/*!
    \overload

    This method tells QWebSocket to ignore the errors given in \a errors.

    Note that you can set the expected certificate in the SSL error:
    If, for instance, you want to connect to a server that uses
    a self-signed certificate, consider the following snippet:

    \snippet src_websockets_ssl_qwebsocket.cpp 6

    Multiple calls to this function will replace the list of errors that
    were passed in previous calls.
    You can clear the list of errors you want to ignore by calling this
    function with an empty list.

    \sa sslErrors()
*/
void QWebSocket::ignoreSslErrors(const QList<QSslError> &errors)
{
    Q_D(QWebSocket);
    d->ignoreSslErrors(errors);
}

/*!
    Sets the socket's SSL configuration to be the contents of \a sslConfiguration.

    This function sets the local certificate, the ciphers, the private key and
    the CA certificates to those stored in \a sslConfiguration.
    It is not possible to set the SSL-state related fields.
    \sa sslConfiguration()
 */
void QWebSocket::setSslConfiguration(const QSslConfiguration &sslConfiguration)
{
    Q_D(QWebSocket);
    d->setSslConfiguration(sslConfiguration);
}

/*!
    Returns the socket's SSL configuration state.
    The default SSL configuration of a socket is to use the default ciphers,
    default CA certificates, no local private key or certificate.
    The SSL configuration also contains fields that can change with time without notice.

    \sa setSslConfiguration()
 */
QSslConfiguration QWebSocket::sslConfiguration() const
{
    Q_D(const QWebSocket);
    return d->sslConfiguration();
}

#endif  //not QT_NO_SSL

/*!
    \brief Returns the version the socket is currently using
 */
QWebSocketProtocol::Version QWebSocket::version() const
{
    Q_D(const QWebSocket);
    return d->version();
}

/*!
    \brief Returns the name of the resource currently accessed.
 */
QString QWebSocket::resourceName() const
{
    Q_D(const QWebSocket);
    return d->resourceName();
}

/*!
    \brief Returns the url the socket is connected to or will connect to.
 */
QUrl QWebSocket::requestUrl() const
{
    Q_D(const QWebSocket);
    return d->requestUrl();
}

/*!
    \brief Returns the current origin
 */
QString QWebSocket::origin() const
{
    Q_D(const QWebSocket);
    return d->origin();
}

/*!
    \brief Returns the code indicating why the socket was closed.
    \sa QWebSocketProtocol::CloseCode, closeReason()
 */
QWebSocketProtocol::CloseCode QWebSocket::closeCode() const
{
    Q_D(const QWebSocket);
    return d->closeCode();
}

/*!
    \brief Returns the reason why the socket was closed.
    \sa closeCode()
 */
QString QWebSocket::closeReason() const
{
    Q_D(const QWebSocket);
    return d->closeReason();
}

/*!
    \brief Returns the current state of the socket
 */
QAbstractSocket::SocketState QWebSocket::state() const
{
    Q_D(const QWebSocket);
    return d->state();
}

/*!
    Returns the local address
 */
QHostAddress QWebSocket::localAddress() const
{
    Q_D(const QWebSocket);
    return d->localAddress();
}

/*!
    Returns the local port
 */
quint16 QWebSocket::localPort() const
{
    Q_D(const QWebSocket);
    return d->localPort();
}

/*!
    Returns the pause mode of this socket
 */
QAbstractSocket::PauseModes QWebSocket::pauseMode() const
{
    Q_D(const QWebSocket);
    return d->pauseMode();
}

/*!
    Returns the peer address
 */
QHostAddress QWebSocket::peerAddress() const
{
    Q_D(const QWebSocket);
    return d->peerAddress();
}

/*!
    Returns the peerName
 */
QString QWebSocket::peerName() const
{
    Q_D(const QWebSocket);
    return d->peerName();
}

/*!
    Returns the peerport
 */
quint16 QWebSocket::peerPort() const
{
    Q_D(const QWebSocket);
    return d->peerPort();
}

#ifndef QT_NO_NETWORKPROXY
/*!
    Returns the currently configured proxy
 */
QNetworkProxy QWebSocket::proxy() const
{
    Q_D(const QWebSocket);
    return d->proxy();
}

/*!
    Sets the proxy to \a networkProxy
 */
void QWebSocket::setProxy(const QNetworkProxy &networkProxy)
{
    Q_D(QWebSocket);
    d->setProxy(networkProxy);
}
#endif

/*!
    Returns the size in bytes of the readbuffer that is used by the socket.
 */
qint64 QWebSocket::readBufferSize() const
{
    Q_D(const QWebSocket);
    return d->readBufferSize();
}

/*!
    Continues data transfer on the socket. This method should only be used after the socket
    has been set to pause upon notifications and a notification has been received.
    The only notification currently supported is sslErrors().
    Calling this method if the socket is not paused results in undefined behavior.

    \sa pauseMode(), setPauseMode()
 */
void QWebSocket::resume()
{
    Q_D(QWebSocket);
    d->resume();
}

/*!
    Controls whether to pause upon receiving a notification. The \a pauseMode parameter specifies
    the conditions in which the socket should be paused.

    The only notification currently supported is sslErrors().
    If set to PauseOnSslErrors, data transfer on the socket will be paused
    and needs to be enabled explicitly again by calling resume().
    By default, this option is set to PauseNever. This option must be called
    before connecting to the server, otherwise it will result in undefined behavior.

    \sa pauseMode(), resume()
 */
void QWebSocket::setPauseMode(QAbstractSocket::PauseModes pauseMode)
{
    Q_D(QWebSocket);
    d->setPauseMode(pauseMode);
}

/*!
    Sets the size of QWebSocket's internal read buffer to be \a size bytes.

    If the buffer size is limited to a certain size, QWebSocket won't buffer more than
    this size of data.
    Exceptionally, a buffer size of 0 means that the read buffer is unlimited and
    all incoming data is buffered. This is the default.
    This option is useful if you only read the data at certain points in time
    (e.g., in a real-time streaming application) or if you want to protect your socket against
    receiving too much data, which may eventually cause your application to run out of memory.

    \sa readBufferSize()
*/
void QWebSocket::setReadBufferSize(qint64 size)
{
    Q_D(QWebSocket);
    d->setReadBufferSize(size);
}

/*!
    Returns \c true if the socket is ready for reading and writing; otherwise
    returns \c false.
 */
bool QWebSocket::isValid() const
{
    Q_D(const QWebSocket);
    return d->isValid();
}

QT_END_NAMESPACE