diff options
Diffstat (limited to 'src/websockets/qwebsocket.cpp')
-rw-r--r-- | src/websockets/qwebsocket.cpp | 592 |
1 files changed, 592 insertions, 0 deletions
diff --git a/src/websockets/qwebsocket.cpp b/src/websockets/qwebsocket.cpp new file mode 100644 index 0000000..b92b061 --- /dev/null +++ b/src/websockets/qwebsocket.cpp @@ -0,0 +1,592 @@ +/* +QWebSockets implements the WebSocket protocol as defined in RFC 6455. +Copyright (C) 2013 Kurt Pattyn (pattyn.kurt@gmail.com) + +This library is free software; you can redistribute it and/or +modify it under the terms of the GNU Lesser General Public +License as published by the Free Software Foundation; either +version 2.1 of the License, or (at your option) any later version. + +This library is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +Lesser General Public License for more details. + +You should have received a copy of the GNU Lesser General Public +License along with this library; if not, write to the Free Software +Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +/*! + \class QWebSocket + + \inmodule QWebSockets + \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 RFC 6455 in 2011 (see http://tools.ietf.org/html/rfc6455). + It can both be used in a client application and server application. + + This class was modeled after QAbstractSocket. + + \sa QAbstractSocket, QTcpSocket + + \sa echoclient.html +*/ + +/*! + \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.cpp constructor + After the connection, we open the socket to the given \a url. + + \snippet 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.cpp onTextMessageReceived + Whenever a message is received, we write it out. +*/ + +/*! + \fn void QWebSocket::connected() + \brief Emitted when a connection is successfully established. + \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. + + 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::textFrameReceived(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(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(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(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::pong(quint64 elapsedTime, 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 <QUrl> +#include <QTcpSocket> +#include <QByteArray> +#include <QHostAddress> + +#include <QDebug> + +#include <limits> + +QT_BEGIN_NAMESPACE + +const quint64 FRAME_SIZE_IN_BYTES = 512 * 512 * 2; //maximum size of a frame when sending a message + +/*! + * \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 in http://tools.ietf.org/html/rfc6454. + * (The \a origin is not required for non-web browser clients (see RFC 6455)). + * \note Currently only V13 (RFC 6455) is supported + */ +QWebSocket::QWebSocket(const QString &origin, QWebSocketProtocol::Version version, QObject *parent) : + QObject(parent), + d_ptr(new QWebSocketPrivate(origin, version, this, this)) +{ +} + +/*! + * \brief Destroys the QWebSocket. Closes the socket if it is still open, and releases any used resources. + */ +QWebSocket::~QWebSocket() +{ + delete d_ptr; + //d_ptr = 0; +} + +/*! + * \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(parent), + d_ptr(new QWebSocketPrivate(pTcpSocket, version, this, this)) +{ +} + +/*! + * 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. + In the absence of an event loop, call waitForBytesWritten() instead. +*/ +bool QWebSocket::flush() +{ + Q_D(QWebSocket); + return d->flush(); +} + +/*! + Sends the given \a message over the socket as a text message and returns the number of bytes actually sent. + \a message must be '\\0' terminated. + */ +qint64 QWebSocket::write(const char *message) +{ + Q_D(QWebSocket); + return d->write(message); +} + +/*! + Sends the most \a maxSize bytes of the given \a message over the socket as a text message and returns the number of bytes actually sent. + */ +qint64 QWebSocket::write(const char *message, qint64 maxSize) +{ + Q_D(QWebSocket); + return d->write(message, maxSize); +} + +/*! + \brief Sends the given \a message over the socket as a text message and returns the number of bytes actually sent. + */ +qint64 QWebSocket::write(const QString &message) +{ + Q_D(QWebSocket); + return d->write(message); +} + +/*! + \brief Sends the given \a data over the socket as a binary message and returns the number of bytes actually sent. + */ +qint64 QWebSocket::write(const QByteArray &data) +{ + Q_D(QWebSocket); + return d->write(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); + if (payload.length() > 125) + { + payload.left(125); + } + d->ping(payload); +} + +/*! + \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 currently used protocol. + */ +QString QWebSocket::protocol() const +{ + Q_D(const QWebSocket); + return d->protocol(); +} + +/*! + \brief Returns the currently used extension. + */ +QString QWebSocket::extension() const +{ + Q_D(const QWebSocket); + return d->extension(); +} + +/*! + \brief Returns the current state of the socket + */ +QAbstractSocket::SocketState QWebSocket::state() const +{ + Q_D(const QWebSocket); + return d->state(); +} + +/*! + \brief Waits until the socket is connected, up to \a msecs milliseconds. If the connection has been established, this function returns true; otherwise it returns false. In the case where it returns false, you can call error() to determine the cause of the error. + The following example waits up to one second for a connection to be established: + + ~~~{.cpp} + socket->open("ws://localhost:1234", false); + if (socket->waitForConnected(1000)) + { + qDebug("Connected!"); + } + ~~~ + + If \a msecs is -1, this function will not time out. + @note This function may wait slightly longer than msecs, depending on the time it takes to complete the host lookup. + @note Multiple calls to this functions do not accumulate the time. If the function times out, the connecting process will be aborted. + + \sa connected(), open(), state() + */ +bool QWebSocket::waitForConnected(int msecs) +{ + Q_D(QWebSocket); + return d->waitForConnected(msecs); +} + +/*! + Waits \a msecs for the socket to be disconnected. + If the socket was successfully disconnected within time, this method returns true. + Otherwise false is returned. + When \a msecs is -1, this function will block until the socket is disconnected. + + \sa close(), state() +*/ +bool QWebSocket::waitForDisconnected(int msecs) +{ + Q_D(QWebSocket); + return d->waitForDisconnected(msecs); +} + +/*! + 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); +} + +/*! + Sets the given \a option to the value described by \a value. + \sa socketOption() +*/ +void QWebSocket::setSocketOption(QAbstractSocket::SocketOption option, const QVariant &value) +{ + Q_D(QWebSocket); + d->setSocketOption(option, value); +} + +/*! + Returns the value of the option \a option. + \sa setSocketOption() +*/ +QVariant QWebSocket::socketOption(QAbstractSocket::SocketOption option) +{ + Q_D(QWebSocket); + return d->socketOption(option); +} + +/*! + Returns true if the QWebSocket is valid. + */ +bool QWebSocket::isValid() const +{ + Q_D(const QWebSocket); + return d->isValid(); +} + +QT_END_NAMESPACE |