class Fragment
{
public:
- Fragment();
- Fragment(const Fragment &other);
+ Fragment();
+ Fragment(const Fragment &other);
- const Fragment &operator =(const Fragment &other);
+ const Fragment &operator =(const Fragment &other);
- WebSocketProtocol::CloseCode getCloseCode() const;
- QString getCloseReason() const;
- bool isFinalFragment() const;
- bool isControlFragment() const;
- bool isDataFragment() const;
- bool isContinuationFragment() const;
- bool hasMask() const;
- quint32 getMask() const; //returns 0 if no mask
- int getRsv1() const;
- int getRsv2() const;
- int getRsv3() const;
- WebSocketProtocol::OpCode getOpCode() const;
- QByteArray getPayload() const;
+ WebSocketProtocol::CloseCode getCloseCode() const;
+ QString getCloseReason() const;
+ bool isFinalFragment() const;
+ bool isControlFragment() const;
+ bool isDataFragment() const;
+ bool isContinuationFragment() const;
+ bool hasMask() const;
+ quint32 getMask() const; //returns 0 if no mask
+ int getRsv1() const;
+ int getRsv2() const;
+ int getRsv3() const;
+ WebSocketProtocol::OpCode getOpCode() const;
+ QByteArray getPayload() const;
- void clear(); //resets all member variables, and invalidates the object
+ void clear(); //resets all member variables, and invalidates the object
- bool isValid() const;
+ bool isValid() const;
- static Fragment readFragment(QTcpSocket *pSocket);
+ static Fragment readFragment(QTcpSocket *pSocket);
private:
- //header
- WebSocketProtocol::CloseCode m_closeCode;
- QString m_closeReason;
- bool m_isFinalFragment;
- quint32 m_mask;
- int m_rsv1; //reserved field 1
- int m_rsv2; //reserved field 2
- int m_rsv3; //reserved field 3
- WebSocketProtocol::OpCode m_opCode;
-
- quint8 m_length; //length field as read from the header; this is 1 byte, which when 126 or 127, indicates a large payload
- QByteArray m_payload;
-
- bool m_isValid;
-
- enum ProcessingState
- {
- PS_READ_HEADER,
- PS_READ_PAYLOAD_LENGTH,
- PS_READ_BIG_PAYLOAD_LENGTH,
- PS_READ_MASK,
- PS_READ_PAYLOAD,
- PS_DISPATCH_RESULT,
- PS_WAIT_FOR_MORE_DATA
- };
-
- void setError(WebSocketProtocol::CloseCode code, QString closeReason);
- bool checkValidity();
+ //header
+ WebSocketProtocol::CloseCode m_closeCode;
+ QString m_closeReason;
+ bool m_isFinalFragment;
+ quint32 m_mask;
+ int m_rsv1; //reserved field 1
+ int m_rsv2; //reserved field 2
+ int m_rsv3; //reserved field 3
+ WebSocketProtocol::OpCode m_opCode;
+
+ quint8 m_length; //length field as read from the header; this is 1 byte, which when 126 or 127, indicates a large payload
+ QByteArray m_payload;
+
+ bool m_isValid;
+
+ enum ProcessingState
+ {
+ PS_READ_HEADER,
+ PS_READ_PAYLOAD_LENGTH,
+ PS_READ_BIG_PAYLOAD_LENGTH,
+ PS_READ_MASK,
+ PS_READ_PAYLOAD,
+ PS_DISPATCH_RESULT,
+ PS_WAIT_FOR_MORE_DATA
+ };
+
+ void setError(WebSocketProtocol::CloseCode code, QString closeReason);
+ bool checkValidity();
};
Fragment::Fragment() :
- m_closeCode(WebSocketProtocol::CC_NORMAL),
- m_closeReason(),
- m_isFinalFragment(true),
- m_mask(0),
- m_rsv1(0),
- m_rsv2(0),
- m_rsv3(0),
- m_opCode(WebSocketProtocol::OC_RESERVED_V),
- m_length(0),
- m_payload(),
- m_isValid(false)
+ m_closeCode(WebSocketProtocol::CC_NORMAL),
+ m_closeReason(),
+ m_isFinalFragment(true),
+ m_mask(0),
+ m_rsv1(0),
+ m_rsv2(0),
+ m_rsv3(0),
+ m_opCode(WebSocketProtocol::OC_RESERVED_V),
+ m_length(0),
+ m_payload(),
+ m_isValid(false)
{
}
Fragment::Fragment(const Fragment &other) :
- m_closeCode(other.m_closeCode),
- m_closeReason(other.m_closeReason),
- m_isFinalFragment(other.m_isFinalFragment),
- m_mask(other.m_mask),
- m_rsv1(other.m_rsv1),
- m_rsv2(other.m_rsv2),
- m_rsv3(other.m_rsv3),
- m_opCode(other.m_opCode),
- m_length(other.m_length),
- m_payload(other.m_payload),
- m_isValid(other.m_isValid)
+ m_closeCode(other.m_closeCode),
+ m_closeReason(other.m_closeReason),
+ m_isFinalFragment(other.m_isFinalFragment),
+ m_mask(other.m_mask),
+ m_rsv1(other.m_rsv1),
+ m_rsv2(other.m_rsv2),
+ m_rsv3(other.m_rsv3),
+ m_opCode(other.m_opCode),
+ m_length(other.m_length),
+ m_payload(other.m_payload),
+ m_isValid(other.m_isValid)
{
}
const Fragment &Fragment::operator =(const Fragment &other)
{
- m_closeCode = other.m_closeCode;
- m_closeReason = other.m_closeReason;
- m_isFinalFragment = other.m_isFinalFragment;
- m_mask = other.m_mask;
- m_rsv1 = other.m_rsv1;
- m_rsv2 = other.m_rsv2;
- m_rsv3 = other.m_rsv2;
- m_opCode = other.m_opCode;
- m_length = other.m_length;
- m_payload = other.m_payload;
- m_isValid = other.m_isValid;
-
- return *this;
+ m_closeCode = other.m_closeCode;
+ m_closeReason = other.m_closeReason;
+ m_isFinalFragment = other.m_isFinalFragment;
+ m_mask = other.m_mask;
+ m_rsv1 = other.m_rsv1;
+ m_rsv2 = other.m_rsv2;
+ m_rsv3 = other.m_rsv2;
+ m_opCode = other.m_opCode;
+ m_length = other.m_length;
+ m_payload = other.m_payload;
+ m_isValid = other.m_isValid;
+
+ return *this;
}
WebSocketProtocol::CloseCode Fragment::getCloseCode() const
{
- return m_closeCode;
+ return m_closeCode;
}
QString Fragment::getCloseReason() const
{
- return m_closeReason;
+ return m_closeReason;
}
bool Fragment::isFinalFragment() const
{
- return m_isFinalFragment;
+ return m_isFinalFragment;
}
bool Fragment::isControlFragment() const
{
- return (m_opCode & 0x08) == 0x08;
+ return (m_opCode & 0x08) == 0x08;
}
bool Fragment::isDataFragment() const
{
- return !isControlFragment();
+ return !isControlFragment();
}
bool Fragment::isContinuationFragment() const
{
- return isDataFragment() && (m_opCode == WebSocketProtocol::OC_CONTINUE);
+ return isDataFragment() && (m_opCode == WebSocketProtocol::OC_CONTINUE);
}
bool Fragment::hasMask() const
{
- return m_mask != 0;
+ return m_mask != 0;
}
quint32 Fragment::getMask() const
{
- return m_mask;
+ return m_mask;
}
int Fragment::getRsv1() const
{
- return m_rsv1;
+ return m_rsv1;
}
int Fragment::getRsv2() const
{
- return m_rsv2;
+ return m_rsv2;
}
int Fragment::getRsv3() const
{
- return m_rsv3;
+ return m_rsv3;
}
WebSocketProtocol::OpCode Fragment::getOpCode() const
{
- return m_opCode;
+ return m_opCode;
}
QByteArray Fragment::getPayload() const
{
- return m_payload;
+ return m_payload;
}
void Fragment::clear()
{
- m_closeCode = WebSocketProtocol::CC_NORMAL;
- m_closeReason.clear();
- m_isFinalFragment = true;
- m_mask = 0;
- m_rsv1 = 0;
- m_rsv2 =0;
- m_rsv3 = 0;
- m_opCode = WebSocketProtocol::OC_RESERVED_V;
- m_length = 0;
- m_payload.clear();
- m_isValid = false;
+ m_closeCode = WebSocketProtocol::CC_NORMAL;
+ m_closeReason.clear();
+ m_isFinalFragment = true;
+ m_mask = 0;
+ m_rsv1 = 0;
+ m_rsv2 =0;
+ m_rsv3 = 0;
+ m_opCode = WebSocketProtocol::OC_RESERVED_V;
+ m_length = 0;
+ m_payload.clear();
+ m_isValid = false;
}
bool Fragment::isValid() const
{
- return m_isValid;
+ return m_isValid;
}
#define WAIT_FOR_MORE_DATA(dataSizeInBytes) { returnState = processingState; processingState = PS_WAIT_FOR_MORE_DATA; dataWaitSize = dataSizeInBytes; }
Fragment Fragment::readFragment(QTcpSocket *pSocket)
{
- bool isDone = false;
- qint64 bytesRead = 0;
- Fragment fragment;
- ProcessingState processingState = PS_READ_HEADER;
- ProcessingState returnState = PS_READ_HEADER;
- quint64 dataWaitSize = 0;
- bool hasMask = false;
- quint64 payloadLength = 0;
-
- while (!isDone)
- {
- switch (processingState)
- {
- case PS_WAIT_FOR_MORE_DATA:
- {
- bool result = pSocket->waitForReadyRead(1000);
- if (!result) //timeout
- {
- qDebug() << "Timeout" << dataWaitSize << "bytesAvail" << pSocket->bytesAvailable();
- fragment.setError(WebSocketProtocol::CC_GOING_AWAY, "Timeout when reading data from socket.");
- isDone = true;
- }
- else
- {
- processingState = returnState;
- }
- break;
- }
- case PS_READ_HEADER:
- {
- if (pSocket->bytesAvailable() >= 2)
- {
- //FIN, RSV1-3, Opcode
- char header[2] = {0};
- bytesRead = pSocket->read(header, 2);
- fragment.m_isFinalFragment = (header[0] & 0x80) != 0;
- fragment.m_rsv1 = (header[0] & 0x40);
- fragment.m_rsv2 = (header[0] & 0x20);
- fragment.m_rsv3 = (header[0] & 0x10);
- fragment.m_opCode = static_cast<WebSocketProtocol::OpCode>(header[0] & 0x0F);
-
- //Mask, PayloadLength
- hasMask = (header[1] & 0x80) != 0;
- fragment.m_length = (header[1] & 0x7F);
-
- switch (fragment.m_length)
- {
- case 126:
- {
- processingState = PS_READ_PAYLOAD_LENGTH;
- break;
- }
- case 127:
- {
- processingState = PS_READ_BIG_PAYLOAD_LENGTH;
- break;
- }
- default:
- {
- payloadLength = fragment.m_length;
- processingState = hasMask ? PS_READ_MASK : PS_READ_PAYLOAD;
- break;
- }
- }
- if (!fragment.checkValidity())
- {
- isDone = true;
- }
- }
- else
- {
- WAIT_FOR_MORE_DATA(2);
- }
- break;
- }
-
- case PS_READ_PAYLOAD_LENGTH:
- {
- if (pSocket->bytesAvailable() >= 2)
- {
- uchar length[2] = {0};
- //TODO: Handle return value
- bytesRead = pSocket->read(reinterpret_cast<char *>(length), 2);
- payloadLength = qFromBigEndian<quint16>(reinterpret_cast<const uchar *>(length));
- processingState = hasMask ? PS_READ_MASK : PS_READ_PAYLOAD;
- }
- else
- {
- WAIT_FOR_MORE_DATA(2);
- }
- break;
- }
-
- case PS_READ_BIG_PAYLOAD_LENGTH:
- {
- if (pSocket->bytesAvailable() >= 8)
- {
- uchar length[8] = {0};
- //TODO: Handle return value
- bytesRead = pSocket->read(reinterpret_cast<char *>(length), 8);
- //Most significant bit must be set to 0 as per http://tools.ietf.org/html/rfc6455#section-5.2
- //TODO: Do we check for that?
- payloadLength = qFromBigEndian<quint64>(length) & ~(1ULL << 63);
- processingState = hasMask ? PS_READ_MASK : PS_READ_PAYLOAD;
- }
- else
- {
- WAIT_FOR_MORE_DATA(8);
- }
-
- break;
- }
-
- case PS_READ_MASK:
- {
- if (pSocket->bytesAvailable() >= 4)
- {
- //TODO: Handle return value
- bytesRead = pSocket->read(reinterpret_cast<char *>(&fragment.m_mask), sizeof(fragment.m_mask));
- processingState = PS_READ_PAYLOAD;
- }
- else
- {
- WAIT_FOR_MORE_DATA(4);
- }
- break;
- }
-
- case PS_READ_PAYLOAD:
- {
- // TODO: Handle large payloads
- if (!payloadLength)
- {
- processingState = PS_DISPATCH_RESULT;
- }
- else
- {
- qint64 bytesAvailable = pSocket->bytesAvailable();
- if (bytesAvailable >= payloadLength)
- {
- //QByteArray payload = pSocket->read(bytesLeftToRead);
- fragment.m_payload = pSocket->read(payloadLength);
- if (hasMask)
- {
- WebSocketProtocol::mask(&fragment.m_payload, fragment.m_mask);
- }
- processingState = PS_DISPATCH_RESULT;
- }
- else
- {
- WAIT_FOR_MORE_DATA(payloadLength);
- }
- }
- break;
- }
-
- case PS_DISPATCH_RESULT:
- {
- processingState = PS_READ_HEADER;
- isDone = true;
- break;
- }
-
- default:
- {
- //should not come here
- qDebug() << "DataProcessor::process: Found invalid state. This should not happen!";
- fragment.clear();
- isDone = true;
- break;
- }
- } //end switch
- }
-
- return fragment;
-}
-
-void Fragment::setError(WebSocketProtocol::CloseCode code, QString closeReason)
-{
- clear();
- m_closeCode = code;
- m_closeReason = closeReason;
- m_isValid = false;
-}
-
-bool Fragment::checkValidity()
-{
- if (!isValid())
- {
- if (m_rsv1 || m_rsv2 || m_rsv3)
- {
- setError(WebSocketProtocol::CC_PROTOCOL_ERROR, "Rsv field is non-zero");
- }
- else if (WebSocketProtocol::isOpCodeReserved(m_opCode))
- {
- setError(WebSocketProtocol::CC_PROTOCOL_ERROR, "Used reserved opcode");
- }
- else if (isControlFragment())
- {
- if (m_length > 125)
- {
- setError(WebSocketProtocol::CC_PROTOCOL_ERROR, "Controle frame is larger than 125 bytes");
- }
- else if (!m_isFinalFragment)
- {
- setError(WebSocketProtocol::CC_PROTOCOL_ERROR, "Controle frames cannot be fragmented");
- }
- else
- {
- m_isValid = true;
- }
- }
- else
- {
- m_isValid = true;
- }
- }
- return m_isValid;
-}
-
-DataProcessor::DataProcessor(QObject *parent) :
- QObject(parent),
- m_processingState(PS_READ_HEADER),
- m_isFinalFragment(false),
- m_isFragmented(false),
- m_opCode(WebSocketProtocol::OC_CLOSE),
- m_isControlFrame(false),
- m_hasMask(false),
- m_mask(0),
- m_frame(),
- m_payloadLength(0)
-{
-}
-
-DataProcessor::~DataProcessor()
-{
-}
-
-#if 1
-
-void DataProcessor::process(QTcpSocket *pSocket)
-{
- bool isDone = false;
-
- while (!isDone)
- {
- Fragment fragment = Fragment::readFragment(pSocket);
- if (fragment.isValid())
- {
- if (fragment.isControlFragment())
- {
- Q_EMIT frameReceived(fragment.getOpCode(), fragment.getPayload(), true);
- isDone = true; //exit the loop after a control frame, so we can get a chance to close the socket if necessary
- }
- else //we have a dataframe
- {
- if (!m_isFragmented && fragment.isContinuationFragment())
- {
- clear();
- Q_EMIT errorEncountered(WebSocketProtocol::CC_PROTOCOL_ERROR, "Received Continuation frame /*with FIN=true*/, while there is nothing to continue.");
- return;
- }
- if (m_isFragmented && fragment.isDataFragment() && !fragment.isContinuationFragment())
- {
- clear();
- Q_EMIT errorEncountered(WebSocketProtocol::CC_PROTOCOL_ERROR, "All data frames after the initial data frame must have opcode 0");
- return;
- }
- if (!fragment.isContinuationFragment())
- {
- m_opCode = fragment.getOpCode();
- m_isFragmented = !fragment.isFinalFragment();
- }
- m_frame.append(fragment.getPayload());
- if (fragment.isFinalFragment())
- {
- Q_EMIT frameReceived(m_opCode, m_frame, m_isFinalFragment);
- clear();
- isDone = true;
- }
- }
- }
- else
- {
- Q_EMIT errorEncountered(fragment.getCloseCode(), fragment.getCloseReason());
- clear();
- isDone = true;
- }
- }
-}
-#else
-void DataProcessor::process(QTcpSocket *pSocket)
-{
+ bool isDone = false;
qint64 bytesRead = 0;
- Q_UNUSED(bytesRead); //TODO: to make gcc happy; in the future we will use the bytesRead to handle errors
- bool isDone = false;
- quint64 currentFrameLength = 0;
+ Fragment fragment;
+ ProcessingState processingState = PS_READ_HEADER;
+ ProcessingState returnState = PS_READ_HEADER;
+ quint64 dataWaitSize = 0;
+ bool hasMask = false;
+ quint64 payloadLength = 0;
while (!isDone)
{
- switch (m_processingState)
+ switch (processingState)
{
+ case PS_WAIT_FOR_MORE_DATA:
+ {
+ bool result = pSocket->waitForReadyRead(1000);
+ if (!result) //timeout
+ {
+ qDebug() << "Timeout" << dataWaitSize << "bytesAvail" << pSocket->bytesAvailable();
+ fragment.setError(WebSocketProtocol::CC_GOING_AWAY, "Timeout when reading data from socket.");
+ isDone = true;
+ }
+ else
+ {
+ processingState = returnState;
+ }
+ break;
+ }
case PS_READ_HEADER:
{
- currentFrameLength = m_frame.size();
- if (pSocket->bytesAvailable() >= 2)
+ if (pSocket->bytesAvailable() >= 2)
{
//FIN, RSV1-3, Opcode
- char header[2];
+ char header[2] = {0};
bytesRead = pSocket->read(header, 2);
- m_isFinalFragment = (header[0] & 0x80) != 0;
- int rsv1 = (header[0] & 0x40);
- int rsv2 = (header[0] & 0x20);
- int rsv3 = (header[0] & 0x10);
- if (rsv1 || rsv2 || rsv3)
- {
- clear();
- Q_EMIT errorEncountered(WebSocketProtocol::CC_PROTOCOL_ERROR, "Rsv field is non-zero");
- return;
- }
- WebSocketProtocol::OpCode opCode = static_cast<WebSocketProtocol::OpCode>(header[0] & 0x0F);
- m_isControlFrame = (opCode & 0x08) == 0x08;
- if (WebSocketProtocol::isOpCodeReserved(opCode))
- {
- clear();
- qDebug() << "Invalid opcode";
- Q_EMIT errorEncountered(WebSocketProtocol::CC_PROTOCOL_ERROR, "Used reserved opcode");
- return;
- }
- if ((opCode == WebSocketProtocol::OC_CONTINUE) && !m_isFragmented)
- {
- clear();
- qDebug() << "Continuation frame while not fragmented.";
- Q_EMIT errorEncountered(WebSocketProtocol::CC_PROTOCOL_ERROR, "Received Continuation frame /*with FIN=true*/, while there is nothing to continue.");
- return;
- }
- if (!m_isControlFrame && m_isFragmented && (opCode != WebSocketProtocol::OC_CONTINUE))
- {
- clear();
- qDebug() << "Continuation frame with invalid opcode.";
- Q_EMIT errorEncountered(WebSocketProtocol::CC_PROTOCOL_ERROR, "All data frames after the initial data frame must have opcode 0");
- return;
- }
- if (opCode != WebSocketProtocol::OC_CONTINUE)
- {
- m_opCode = opCode;
- }
- if (!m_isControlFrame && (opCode != WebSocketProtocol::OC_CONTINUE))
- {
- m_isFragmented = !m_isFinalFragment;
- }
+ fragment.m_isFinalFragment = (header[0] & 0x80) != 0;
+ fragment.m_rsv1 = (header[0] & 0x40);
+ fragment.m_rsv2 = (header[0] & 0x20);
+ fragment.m_rsv3 = (header[0] & 0x10);
+ fragment.m_opCode = static_cast<WebSocketProtocol::OpCode>(header[0] & 0x0F);
//Mask, PayloadLength
- m_hasMask = (header[1] & 0x80) != 0;
- quint8 length = (header[1] & 0x7F);
-
- if (m_isControlFrame)
- {
- if (length > 125)
- {
- qDebug() << "Control frame larger than 125 bytes.";
- Q_EMIT errorEncountered(WebSocketProtocol::CC_PROTOCOL_ERROR, "Controle frame is larger than 125 bytes");
- return;
- }
-
- if (!m_isFinalFragment)
- {
- qDebug() << "Control frames cannot be fragmented.";
- Q_EMIT errorEncountered(WebSocketProtocol::CC_PROTOCOL_ERROR, "Controle frames cannot be fragmented");
- return;
- }
- }
-
- switch (length)
+ hasMask = (header[1] & 0x80) != 0;
+ fragment.m_length = (header[1] & 0x7F);
+
+ switch (fragment.m_length)
{
case 126:
{
- m_processingState = PS_READ_PAYLOAD_LENGTH;
+ processingState = PS_READ_PAYLOAD_LENGTH;
break;
}
case 127:
{
- m_processingState = PS_READ_BIG_PAYLOAD_LENGTH;
+ processingState = PS_READ_BIG_PAYLOAD_LENGTH;
break;
}
default:
{
- m_payloadLength = length;
- m_processingState = m_hasMask ? PS_READ_MASK : PS_READ_PAYLOAD;
+ payloadLength = fragment.m_length;
+ processingState = hasMask ? PS_READ_MASK : PS_READ_PAYLOAD;
break;
}
}
+ if (!fragment.checkValidity())
+ {
+ isDone = true;
+ }
}
else
{
- isDone = true;
+ WAIT_FOR_MORE_DATA(2);
}
break;
}
case PS_READ_PAYLOAD_LENGTH:
{
- if (pSocket->bytesAvailable() >= 2)
+ if (pSocket->bytesAvailable() >= 2)
{
- uchar length[2];
+ uchar length[2] = {0};
//TODO: Handle return value
bytesRead = pSocket->read(reinterpret_cast<char *>(length), 2);
- m_payloadLength = qFromBigEndian<quint16>(reinterpret_cast<const uchar *>(length));
- m_processingState = m_hasMask ? PS_READ_MASK : PS_READ_PAYLOAD;
+ payloadLength = qFromBigEndian<quint16>(reinterpret_cast<const uchar *>(length));
+ processingState = hasMask ? PS_READ_MASK : PS_READ_PAYLOAD;
}
else
{
- isDone = true;
+ WAIT_FOR_MORE_DATA(2);
}
break;
}
case PS_READ_BIG_PAYLOAD_LENGTH:
{
- if (pSocket->bytesAvailable() >= 8)
+ if (pSocket->bytesAvailable() >= 8)
{
- uchar length[8];
+ uchar length[8] = {0};
//TODO: Handle return value
bytesRead = pSocket->read(reinterpret_cast<char *>(length), 8);
//Most significant bit must be set to 0 as per http://tools.ietf.org/html/rfc6455#section-5.2
//TODO: Do we check for that?
- m_payloadLength = qFromBigEndian<quint64>(length) & ~(1ULL << 63);
- m_processingState = m_hasMask ? PS_READ_MASK : PS_READ_PAYLOAD;
+ payloadLength = qFromBigEndian<quint64>(length) & ~(1ULL << 63);
+ processingState = hasMask ? PS_READ_MASK : PS_READ_PAYLOAD;
}
else
{
- isDone = true;
+ WAIT_FOR_MORE_DATA(8);
}
break;
case PS_READ_MASK:
{
- if (pSocket->bytesAvailable() >= 4)
+ if (pSocket->bytesAvailable() >= 4)
{
//TODO: Handle return value
- bytesRead = pSocket->read(reinterpret_cast<char *>(&m_mask), sizeof(m_mask));
- m_processingState = PS_READ_PAYLOAD;
+ bytesRead = pSocket->read(reinterpret_cast<char *>(&fragment.m_mask), sizeof(fragment.m_mask));
+ processingState = PS_READ_PAYLOAD;
}
else
{
- isDone = true;
+ WAIT_FOR_MORE_DATA(4);
}
break;
}
case PS_READ_PAYLOAD:
{
- // TODO: Handle large payloads
- //if (pSocket->bytesAvailable() >= static_cast<qint32>(m_payloadLength))
- qint64 bytesAvailable = pSocket->bytesAvailable();
- //qint64 bytesLeftToRead = qMin(m_payloadLength - (quint64)m_frame.size() - currentFrameLength, (quint64)bytesAvailable);
- //qint64 bytesLeftToRead = qMin(m_payloadLength, (quint64)bytesAvailable);
- //if (bytesLeftToRead > 0)
- if (bytesAvailable >= m_payloadLength)
+ // TODO: Handle large payloads
+ if (!payloadLength)
+ {
+ processingState = PS_DISPATCH_RESULT;
+ }
+ else
{
- //QByteArray payload = pSocket->read(bytesLeftToRead);
- QByteArray payload = pSocket->read(m_payloadLength);
- if (m_hasMask)
+ quint64 bytesAvailable = static_cast<quint64>(pSocket->bytesAvailable());
+ if (bytesAvailable >= payloadLength)
{
- WebSocketProtocol::mask(&payload, m_mask);
+ //QByteArray payload = pSocket->read(bytesLeftToRead);
+ fragment.m_payload = pSocket->read(payloadLength);
+ if (hasMask)
+ {
+ WebSocketProtocol::mask(&fragment.m_payload, fragment.m_mask);
+ }
+ processingState = PS_DISPATCH_RESULT;
+ }
+ else
+ {
+ WAIT_FOR_MORE_DATA(payloadLength);
}
- m_frame.append(payload);
- }
- else if (m_payloadLength > 0)
- {
- //qDebug() << "Waiting for ready read";
- pSocket->waitForReadyRead(1000);
- //qDebug() << "Waited for ready read" << m_frame.size();
- //isDone = true; //wait for more to be read
- break;
- }
- if (m_frame.size() == (m_payloadLength + currentFrameLength))
- {
- m_processingState = m_isFinalFragment ? PS_DISPATCH_RESULT : PS_READ_HEADER;
- }
- else
- {
- isDone = true; //more to read
}
- /*if ((m_frame.size() % (64 * 1000)) == 0)
- {
- qDebug() << "framesize=" << m_frame.size() << pSocket->bytesAvailable();
- }*/
break;
}
case PS_DISPATCH_RESULT:
{
- Q_EMIT frameReceived(m_opCode, m_frame, m_isFinalFragment);
- m_processingState = PS_READ_HEADER;
- m_frame.clear();
+ processingState = PS_READ_HEADER;
+ isDone = true;
break;
}
{
//should not come here
qDebug() << "DataProcessor::process: Found invalid state. This should not happen!";
+ fragment.clear();
isDone = true;
break;
}
} //end switch
- } //end while
+ }
+
+ return fragment;
+}
+
+void Fragment::setError(WebSocketProtocol::CloseCode code, QString closeReason)
+{
+ clear();
+ m_closeCode = code;
+ m_closeReason = closeReason;
+ m_isValid = false;
+}
+
+bool Fragment::checkValidity()
+{
+ if (!isValid())
+ {
+ if (m_rsv1 || m_rsv2 || m_rsv3)
+ {
+ setError(WebSocketProtocol::CC_PROTOCOL_ERROR, "Rsv field is non-zero");
+ }
+ else if (WebSocketProtocol::isOpCodeReserved(m_opCode))
+ {
+ setError(WebSocketProtocol::CC_PROTOCOL_ERROR, "Used reserved opcode");
+ }
+ else if (isControlFragment())
+ {
+ if (m_length > 125)
+ {
+ setError(WebSocketProtocol::CC_PROTOCOL_ERROR, "Controle frame is larger than 125 bytes");
+ }
+ else if (!m_isFinalFragment)
+ {
+ setError(WebSocketProtocol::CC_PROTOCOL_ERROR, "Controle frames cannot be fragmented");
+ }
+ else
+ {
+ m_isValid = true;
+ }
+ }
+ else
+ {
+ m_isValid = true;
+ }
+ }
+ return m_isValid;
+}
+
+DataProcessor::DataProcessor(QObject *parent) :
+ QObject(parent),
+ m_processingState(PS_READ_HEADER),
+ m_isFinalFragment(false),
+ m_isFragmented(false),
+ m_opCode(WebSocketProtocol::OC_CLOSE),
+ m_isControlFrame(false),
+ m_hasMask(false),
+ m_mask(0),
+ m_frame(),
+ m_payloadLength(0)
+{
+}
+
+DataProcessor::~DataProcessor()
+{
}
-#endif
+
+void DataProcessor::process(QTcpSocket *pSocket)
+{
+ bool isDone = false;
+
+ while (!isDone)
+ {
+ Fragment fragment = Fragment::readFragment(pSocket);
+ if (fragment.isValid())
+ {
+ if (fragment.isControlFragment())
+ {
+ Q_EMIT frameReceived(fragment.getOpCode(), fragment.getPayload(), true);
+ isDone = true; //exit the loop after a control frame, so we can get a chance to close the socket if necessary
+ }
+ else //we have a dataframe
+ {
+ if (!m_isFragmented && fragment.isContinuationFragment())
+ {
+ clear();
+ Q_EMIT errorEncountered(WebSocketProtocol::CC_PROTOCOL_ERROR, "Received Continuation frame /*with FIN=true*/, while there is nothing to continue.");
+ return;
+ }
+ if (m_isFragmented && fragment.isDataFragment() && !fragment.isContinuationFragment())
+ {
+ clear();
+ Q_EMIT errorEncountered(WebSocketProtocol::CC_PROTOCOL_ERROR, "All data frames after the initial data frame must have opcode 0");
+ return;
+ }
+ if (!fragment.isContinuationFragment())
+ {
+ m_opCode = fragment.getOpCode();
+ m_isFragmented = !fragment.isFinalFragment();
+ }
+ m_frame.append(fragment.getPayload());
+ if (fragment.isFinalFragment())
+ {
+ Q_EMIT frameReceived(m_opCode, m_frame, m_isFinalFragment);
+ clear();
+ isDone = true;
+ }
+ }
+ }
+ else
+ {
+ Q_EMIT errorEncountered(fragment.getCloseCode(), fragment.getCloseReason());
+ clear();
+ isDone = true;
+ }
+ }
+}
+
void DataProcessor::clear()
{
m_processingState = PS_READ_HEADER;
m_isFinalFragment = false;
- m_isFragmented = false;
+ m_isFragmented = false;
m_opCode = WebSocketProtocol::OC_CLOSE;
m_hasMask = false;
m_mask = 0;
#include "handshakeresponse.h"
#include <QUrl>
#include <QTcpSocket>
-#include <QSharedData>
#include <QByteArray>
#include <QtEndian>
#include <QCryptographicHash>
void WebSocket::close(WebSocketProtocol::CloseCode closeCode, QString reason)
{
- if (!m_isClosingHandshakeSent)
+ if (!m_isClosingHandshakeSent)
{
- quint32 maskingKey = 0;
- if (m_mustMask)
- {
- maskingKey = generateMaskingKey();
- }
- quint16 code = qToBigEndian<quint16>(closeCode);
- QByteArray payload;
- payload.append(static_cast<const char *>(static_cast<const void *>(&code)), 2);
- if (!reason.isEmpty())
+ quint32 maskingKey = 0;
+ if (m_mustMask)
+ {
+ maskingKey = generateMaskingKey();
+ }
+ quint16 code = qToBigEndian<quint16>(closeCode);
+ QByteArray payload;
+ payload.append(static_cast<const char *>(static_cast<const void *>(&code)), 2);
+ if (!reason.isEmpty())
+ {
+ payload.append(reason.toUtf8());
+ }
+ if (m_mustMask)
{
- payload.append(reason.toUtf8());
+ WebSocketProtocol::mask(payload.data(), payload.size(), maskingKey);
}
- if (m_mustMask)
- {
- WebSocketProtocol::mask(payload.data(), payload.size(), maskingKey);
- }
- QByteArray frame = getFrameHeader(WebSocketProtocol::OC_CLOSE, payload.size(), maskingKey, true);
- frame.append(payload);
- m_pSocket->write(frame);
+ QByteArray frame = getFrameHeader(WebSocketProtocol::OC_CLOSE, payload.size(), maskingKey, true);
+ frame.append(payload);
+ m_pSocket->write(frame);
m_isClosingHandshakeSent = true;
- //qDebug() << "Sent closing handshake";
+ //qDebug() << "Sent closing handshake";
setSocketState(QAbstractSocket::ClosingState);
- //Q_EMIT aboutToClose();
+ //Q_EMIT aboutToClose();
}
- //if (m_isClosingHandshakeSent && m_isClosingHandshakeReceived)
+ //if (m_isClosingHandshakeSent && m_isClosingHandshakeReceived)
{
- //qDebug() << "Closing tcp socket";
+ //qDebug() << "Closing tcp socket";
setSocketState(QAbstractSocket::UnconnectedState);
- m_pSocket->flush();
+ m_pSocket->flush();
m_pSocket->close();
- Q_EMIT disconnected();
- }
+ Q_EMIT disconnected();
+ }
}
void WebSocket::open(const QUrl &url, bool mask)
{
m_dataProcessor.clear();
- m_isClosingHandshakeReceived = false;
- m_isClosingHandshakeSent = false;
+ m_isClosingHandshakeReceived = false;
+ m_isClosingHandshakeSent = false;
setRequestUrl(url);
//resourcename cannot contain the scheme, host and port for socket.io
connect(pTcpSocket, SIGNAL(readyRead()), this, SLOT(processData()));
connect(&m_dataProcessor, SIGNAL(frameReceived(WebSocketProtocol::OpCode, QByteArray, bool)), this, SLOT(processFrame(WebSocketProtocol::OpCode, QByteArray, bool)));
- connect(&m_dataProcessor, SIGNAL(errorEncountered(WebSocketProtocol::CloseCode,QString)), this, SLOT(close(WebSocketProtocol::CloseCode,QString)));
+ connect(&m_dataProcessor, SIGNAL(errorEncountered(WebSocketProtocol::CloseCode,QString)), this, SLOT(close(WebSocketProtocol::CloseCode,QString)));
}
void WebSocket::releaseConnections(const QTcpSocket *pTcpSocket)
const WebSocketProtocol::OpCode firstOpCode = isBinary ? WebSocketProtocol::OC_BINARY : WebSocketProtocol::OC_TEXT;
int numFrames = data.size() / MAX_FRAME_SIZE_IN_BYTES;
- QByteArray tmpData(data);
- tmpData.detach();
- char *payload = tmpData.data();
- quint64 sizeLeft = static_cast<quint64>(data.size()) % MAX_FRAME_SIZE_IN_BYTES;
+ QByteArray tmpData(data);
+ tmpData.detach();
+ char *payload = tmpData.data();
+ quint64 sizeLeft = static_cast<quint64>(data.size()) % MAX_FRAME_SIZE_IN_BYTES;
if (sizeLeft)
{
++numFrames;
}
- if (numFrames == 0) //catch the case where the payload is zero bytes; in that case, we still need to send a frame
- {
- //qDebug() << "No data to send";
- numFrames = 1;
- }
+ if (numFrames == 0) //catch the case where the payload is zero bytes; in that case, we still need to send a frame
+ {
+ //qDebug() << "No data to send";
+ numFrames = 1;
+ }
quint64 currentPosition = 0;
qint64 bytesWritten = 0;
- qint64 payloadWritten = 0;
- quint64 bytesLeft = data.size();
+ qint64 payloadWritten = 0;
+ quint64 bytesLeft = data.size();
for (int i = 0; i < numFrames; ++i)
{
bool isLastFrame = (i == (numFrames - 1));
bool isFirstFrame = (i == 0);
- //quint64 size = isLastFrame ? sizeLeft : MAX_FRAME_SIZE_IN_BYTES;
- quint64 size = qMin(bytesLeft, MAX_FRAME_SIZE_IN_BYTES);
+ //quint64 size = isLastFrame ? sizeLeft : MAX_FRAME_SIZE_IN_BYTES;
+ quint64 size = qMin(bytesLeft, MAX_FRAME_SIZE_IN_BYTES);
WebSocketProtocol::OpCode opcode = isFirstFrame ? firstOpCode : WebSocketProtocol::OC_CONTINUE;
//write header
bytesWritten += m_pSocket->write(getFrameHeader(opcode, size, maskingKey, isLastFrame));
//write payload
- if (size > 0)
- {
- char *currentData = payload + currentPosition;
- if (m_mustMask)
- {
- //WARNING: currentData is written over
- WebSocketProtocol::mask(currentData, size, maskingKey);
- }
- qint64 written = m_pSocket->write(currentData, static_cast<qint64>(size));
- if (written > 0)
- {
- bytesWritten += written;
- payloadWritten += written;
- }
- else
- {
- qDebug() << "WebSocket::doWriteFrames: Error writing bytes to socket:" << m_pSocket->errorString();
- m_pSocket->flush();
- break;
- }
- }
+ if (size > 0)
+ {
+ char *currentData = payload + currentPosition;
+ if (m_mustMask)
+ {
+ //WARNING: currentData is written over
+ WebSocketProtocol::mask(currentData, size, maskingKey);
+ }
+ qint64 written = m_pSocket->write(currentData, static_cast<qint64>(size));
+ if (written > 0)
+ {
+ bytesWritten += written;
+ payloadWritten += written;
+ }
+ else
+ {
+ qDebug() << "WebSocket::doWriteFrames: Error writing bytes to socket:" << m_pSocket->errorString();
+ m_pSocket->flush();
+ break;
+ }
+ }
currentPosition += size;
- bytesLeft -= size;
+ bytesLeft -= size;
+ }
+ if (payloadWritten != data.size())
+ {
+ qDebug() << "Bytes written" << payloadWritten << "!=" << "data size:" << data.size();
}
- if (payloadWritten != data.size())
- {
- qDebug() << "Bytes written" << payloadWritten << "!=" << "data size:" << data.size();
- }
- //return bytesWritten;
- return payloadWritten;
+ //return bytesWritten;
+ return payloadWritten;
}
quint32 WebSocket::generateRandomNumber() const
QString readLine(QTcpSocket *pSocket)
{
- QString line;
- char c;
- while (pSocket->getChar(&c))
- {
- if (c == '\r')
- {
- pSocket->getChar(&c);
- break;
- }
- else
- {
- line.append(QChar(c));
- }
- }
- return line;
+ QString line;
+ char c;
+ while (pSocket->getChar(&c))
+ {
+ if (c == '\r')
+ {
+ pSocket->getChar(&c);
+ break;
+ }
+ else
+ {
+ line.append(QChar(c));
+ }
+ }
+ return line;
}
//called for a server handshake response
return;
}
- bool ok = false;
- const QString regExpStatusLine("^(HTTP/1.1)\\s([0-9]+)\\s(.*)");
- const QRegExp regExp(regExpStatusLine);
- //QString statusLine = textStream.readLine();
- QString statusLine = readLine(pSocket);
- QString httpProtocol;
- int httpStatusCode;
- QString httpStatusMessage;
- if (regExp.indexIn(statusLine) != -1)
- {
- QStringList tokens = regExp.capturedTexts();
- tokens.removeFirst(); //remove the search string
- if (tokens.length() == 3)
- {
- httpProtocol = tokens[0];
- httpStatusCode = tokens[1].toInt();
- httpStatusMessage = tokens[2].trimmed();
- ok = true;
- }
- }
- if (!ok)
- {
- qDebug() << "WebSocket::processHandshake: Invalid statusline in response:" << statusLine;
- }
- else
- {
- //QString headerLine = textStream.readLine();
- QString headerLine = readLine(pSocket);
- QMap<QString, QString> headers;
- while (!headerLine.isEmpty())
- {
- QStringList headerField = headerLine.split(QString(": "), QString::SkipEmptyParts);
- headers.insertMulti(headerField[0], headerField[1]);
- headerLine = readLine(pSocket);
- }
-
- QString acceptKey = headers.value("Sec-WebSocket-Accept", "");
- QString upgrade = headers.value("Upgrade", "");
- QString connection = headers.value("Connection", "");
- QString extensions = headers.value("Sec-WebSocket-Extensions", "");
- QString protocol = headers.value("Sec-WebSocket-Protocol", "");
- QString version = headers.value("Sec-WebSocket-Version", "");
-
- if (httpStatusCode == 101) //HTTP/1.1 101 Switching Protocols
- {
- //do not check the httpStatusText right now
- ok = !(acceptKey.isEmpty() ||
- (httpProtocol.toLower() != "http/1.1") ||
- (upgrade.toLower() != "websocket") ||
- (connection.toLower() != "upgrade"));
- if (ok)
- {
- QString accept = calculateAcceptKey(m_key);
- ok = (accept == acceptKey);
- if (!ok)
- {
- qDebug() << "WebSocket::processHandshake: Accept-Key received from server" << qPrintable(acceptKey) << "does not match the client key" << qPrintable(accept);
- }
- }
- else
- {
- qDebug() << "WebSocket::processHandshake: Invalid statusline in response:" << statusLine;
- }
- }
- else if (httpStatusCode == 400) //HTTP/1.1 400 Bad Request
- {
- if (!version.isEmpty())
- {
- QStringList versions = version.split(", ", QString::SkipEmptyParts);
- if (!versions.contains("13"))
- {
- //if needed to switch protocols, then we are finished here
- //because we cannot handle other protocols than the RFC one (v13)
- qDebug() << "WebSocket::processHandshake: Server requests a version that we don't support:" << versions;
- ok = false;
- }
- else
- {
- //we tried v13, but something different went wrong
- qDebug() << "WebSocket::processHandshake: Unknown error condition encountered. Aborting connection.";
- ok = false;
- }
- }
- }
- else
- {
- qDebug() << "WebSocket::processHandshake: Unhandled http status code" << httpStatusCode;
- ok = false;
- }
+ bool ok = false;
+ const QString regExpStatusLine("^(HTTP/1.1)\\s([0-9]+)\\s(.*)");
+ const QRegExp regExp(regExpStatusLine);
+ //QString statusLine = textStream.readLine();
+ QString statusLine = readLine(pSocket);
+ QString httpProtocol;
+ int httpStatusCode;
+ QString httpStatusMessage;
+ if (regExp.indexIn(statusLine) != -1)
+ {
+ QStringList tokens = regExp.capturedTexts();
+ tokens.removeFirst(); //remove the search string
+ if (tokens.length() == 3)
+ {
+ httpProtocol = tokens[0];
+ httpStatusCode = tokens[1].toInt();
+ httpStatusMessage = tokens[2].trimmed();
+ ok = true;
+ }
+ }
+ if (!ok)
+ {
+ qDebug() << "WebSocket::processHandshake: Invalid statusline in response:" << statusLine;
+ }
+ else
+ {
+ //QString headerLine = textStream.readLine();
+ QString headerLine = readLine(pSocket);
+ QMap<QString, QString> headers;
+ while (!headerLine.isEmpty())
+ {
+ QStringList headerField = headerLine.split(QString(": "), QString::SkipEmptyParts);
+ headers.insertMulti(headerField[0], headerField[1]);
+ headerLine = readLine(pSocket);
+ }
+
+ QString acceptKey = headers.value("Sec-WebSocket-Accept", "");
+ QString upgrade = headers.value("Upgrade", "");
+ QString connection = headers.value("Connection", "");
+ QString extensions = headers.value("Sec-WebSocket-Extensions", "");
+ QString protocol = headers.value("Sec-WebSocket-Protocol", "");
+ QString version = headers.value("Sec-WebSocket-Version", "");
+
+ if (httpStatusCode == 101) //HTTP/1.1 101 Switching Protocols
+ {
+ //do not check the httpStatusText right now
+ ok = !(acceptKey.isEmpty() ||
+ (httpProtocol.toLower() != "http/1.1") ||
+ (upgrade.toLower() != "websocket") ||
+ (connection.toLower() != "upgrade"));
+ if (ok)
+ {
+ QString accept = calculateAcceptKey(m_key);
+ ok = (accept == acceptKey);
+ if (!ok)
+ {
+ qDebug() << "WebSocket::processHandshake: Accept-Key received from server" << qPrintable(acceptKey) << "does not match the client key" << qPrintable(accept);
+ }
+ }
+ else
+ {
+ qDebug() << "WebSocket::processHandshake: Invalid statusline in response:" << statusLine;
+ }
+ }
+ else if (httpStatusCode == 400) //HTTP/1.1 400 Bad Request
+ {
+ if (!version.isEmpty())
+ {
+ QStringList versions = version.split(", ", QString::SkipEmptyParts);
+ if (!versions.contains("13"))
+ {
+ //if needed to switch protocols, then we are finished here
+ //because we cannot handle other protocols than the RFC one (v13)
+ qDebug() << "WebSocket::processHandshake: Server requests a version that we don't support:" << versions;
+ ok = false;
+ }
+ else
+ {
+ //we tried v13, but something different went wrong
+ qDebug() << "WebSocket::processHandshake: Unknown error condition encountered. Aborting connection.";
+ ok = false;
+ }
+ }
+ }
+ else
+ {
+ qDebug() << "WebSocket::processHandshake: Unhandled http status code" << httpStatusCode;
+ ok = false;
+ }
if (!ok)
{
void WebSocket::processStateChanged(QAbstractSocket::SocketState socketState)
{
QAbstractSocket::SocketState webSocketState = this->state();
- //qDebug() << "State changed to:" << webSocketState << "tpcsocketstate:" << socketState;
+ //qDebug() << "State changed to:" << webSocketState << "tpcsocketstate:" << socketState;
switch (socketState)
{
case QAbstractSocket::ConnectedState:
if (webSocketState == QAbstractSocket::ConnectingState)
{
m_key = generateKey();
- QString handshake = createHandShakeRequest(m_resourceName, m_requestUrl.host() + ":" + QString::number(m_requestUrl.port(80)), getOrigin(), "", "", m_key);
+ QString handshake = createHandShakeRequest(m_resourceName, m_requestUrl.host() + ":" + QString::number(m_requestUrl.port(80)), getOrigin(), "", "", m_key);
m_pSocket->write(handshake.toLatin1());
}
break;
{
if (webSocketState == QAbstractSocket::ConnectedState)
{
- close(WebSocketProtocol::CC_GOING_AWAY);
+ close(WebSocketProtocol::CC_GOING_AWAY);
setSocketState(QAbstractSocket::ClosingState);
- //Q_EMIT aboutToClose();
+ //Q_EMIT aboutToClose();
}
break;
}
//if our socket was already upgraded, then we need to process websocket data
void WebSocket::processData()
{
- while (m_pSocket->bytesAvailable())
- {
- if (state() == QAbstractSocket::ConnectingState)
- {
- processHandshake(m_pSocket);
- }
- else
- {
- m_dataProcessor.process(m_pSocket);
- }
- }
+ while (m_pSocket->bytesAvailable())
+ {
+ if (state() == QAbstractSocket::ConnectingState)
+ {
+ processHandshake(m_pSocket);
+ }
+ else
+ {
+ m_dataProcessor.process(m_pSocket);
+ }
+ }
}
void WebSocket::processFrame(WebSocketProtocol::OpCode opCode, QByteArray frame, bool isLastFrame)
{
- //qDebug() << "Processing frame:" << frame << "opcode:" << opCode;
- switch (opCode)
+ //qDebug() << "Processing frame:" << frame << "opcode:" << opCode;
+ switch (opCode)
{
case WebSocketProtocol::OC_BINARY:
{
- Q_EMIT binaryFrameReceived(frame, isLastFrame);
+ Q_EMIT binaryFrameReceived(frame, isLastFrame);
break;
}
case WebSocketProtocol::OC_TEXT:
- {
- //qDebug() << "Processing text frame:" << frame << "opcode:" << opCode;
- Q_EMIT textFrameReceived(QString::fromLatin1(frame), isLastFrame);
+ {
+ //qDebug() << "Processing text frame:" << frame << "opcode:" << opCode;
+ Q_EMIT textFrameReceived(QString::fromLatin1(frame), isLastFrame);
break;
}
case WebSocketProtocol::OC_PING:
{
- //qDebug() << "Processing ping frame:" << frame;
- quint32 maskingKey = 0;
- if (m_mustMask)
- {
- maskingKey = generateMaskingKey();
- }
- m_pSocket->write(getFrameHeader(WebSocketProtocol::OC_PONG, frame.size(), maskingKey, true));
- if (frame.size() > 0)
- {
- if (m_mustMask)
- {
- WebSocketProtocol::mask(&frame, maskingKey);
- }
- m_pSocket->write(frame);
- }
+ //qDebug() << "Processing ping frame:" << frame;
+ quint32 maskingKey = 0;
+ if (m_mustMask)
+ {
+ maskingKey = generateMaskingKey();
+ }
+ m_pSocket->write(getFrameHeader(WebSocketProtocol::OC_PONG, frame.size(), maskingKey, true));
+ if (frame.size() > 0)
+ {
+ if (m_mustMask)
+ {
+ WebSocketProtocol::mask(&frame, maskingKey);
+ }
+ m_pSocket->write(frame);
+ }
break;
}
case WebSocketProtocol::OC_PONG:
}
case WebSocketProtocol::OC_CLOSE:
{
- quint16 closeCode = WebSocketProtocol::CC_NORMAL;
- QString closeReason;
- if (frame.size() > 0) //close frame can have no close code nor reason
- {
- closeCode = qFromBigEndian<quint16>(reinterpret_cast<const uchar *>(frame.constData()));
- closeReason = QString::fromUtf8(frame.remove(0, 2));
- //qDebug() << "Received closing handshake with code" << closeCode;
- if (!WebSocketProtocol::isCloseCodeValid(closeCode))
- {
- closeCode = WebSocketProtocol::CC_PROTOCOL_ERROR;
- }
- m_isClosingHandshakeReceived = true;
- }
- close(static_cast<WebSocketProtocol::CloseCode>(closeCode), closeReason);
+ quint16 closeCode = WebSocketProtocol::CC_NORMAL;
+ QString closeReason;
+ if (frame.size() > 0) //close frame can have no close code nor reason
+ {
+ closeCode = qFromBigEndian<quint16>(reinterpret_cast<const uchar *>(frame.constData()));
+ closeReason = QString::fromUtf8(frame.remove(0, 2));
+ //qDebug() << "Received closing handshake with code" << closeCode;
+ if (!WebSocketProtocol::isCloseCodeValid(closeCode))
+ {
+ closeCode = WebSocketProtocol::CC_PROTOCOL_ERROR;
+ }
+ m_isClosingHandshakeReceived = true;
+ }
+ close(static_cast<WebSocketProtocol::CloseCode>(closeCode), closeReason);
break;
}
case WebSocketProtocol::OC_CONTINUE:
QAbstractSocket::SocketState WebSocket::state() const
{
- return m_socketState;
+ return m_socketState;
}
bool WebSocket::waitForConnected(int msecs)
{
- bool retVal = false;
- if (m_pSocket)
- {
- retVal = m_pSocket->waitForConnected(msecs);
- }
- return retVal;
+ bool retVal = false;
+ if (m_pSocket)
+ {
+ retVal = m_pSocket->waitForConnected(msecs);
+ }
+ return retVal;
}
bool WebSocket::waitForDisconnected(int msecs)
{
- bool retVal = true;
- if (m_pSocket)
- {
- retVal = m_pSocket->waitForDisconnected(msecs);
- }
- return retVal;
+ bool retVal = true;
+ if (m_pSocket)
+ {
+ retVal = m_pSocket->waitForDisconnected(msecs);
+ }
+ return retVal;
}
void WebSocket::setSocketState(QAbstractSocket::SocketState state)
QHostAddress WebSocket::localAddress() const
{
- QHostAddress address;
- if (m_pSocket)
- {
- address = m_pSocket->localAddress();
- }
- return address;
+ QHostAddress address;
+ if (m_pSocket)
+ {
+ address = m_pSocket->localAddress();
+ }
+ return address;
}
quint16 WebSocket::localPort() const
{
- quint16 port = 0;
- if (m_pSocket)
- {
- port = m_pSocket->localPort();
- }
- return port;
+ quint16 port = 0;
+ if (m_pSocket)
+ {
+ port = m_pSocket->localPort();
+ }
+ return port;
}
QHostAddress WebSocket::peerAddress() const
{
- QHostAddress peer;
- if (m_pSocket)
- {
- peer = m_pSocket->peerAddress();
- }
- return peer;
+ QHostAddress peer;
+ if (m_pSocket)
+ {
+ peer = m_pSocket->peerAddress();
+ }
+ return peer;
}
QString WebSocket::peerName() const
{
- QString name;
- if (m_pSocket)
- {
- name = m_pSocket->peerName();
- }
- return name;
+ QString name;
+ if (m_pSocket)
+ {
+ name = m_pSocket->peerName();
+ }
+ return name;
}
quint16 WebSocket::peerPort() const
{
- quint16 port = 0;
- if (m_pSocket)
- {
- port = m_pSocket->peerPort();
- }
- return port;
+ quint16 port = 0;
+ if (m_pSocket)
+ {
+ port = m_pSocket->peerPort();
+ }
+ return port;
}
QNetworkProxy WebSocket::proxy() const
{
- QNetworkProxy proxy;
- if (m_pSocket)
- {
- proxy = m_pSocket->proxy();
- }
- return proxy;
+ QNetworkProxy proxy;
+ if (m_pSocket)
+ {
+ proxy = m_pSocket->proxy();
+ }
+ return proxy;
}
qint64 WebSocket::readBufferSize() const
{
- qint64 readBuffer = 0;
- if (m_pSocket)
- {
- readBuffer = m_pSocket->readBufferSize();
- }
- return readBuffer;
+ qint64 readBuffer = 0;
+ if (m_pSocket)
+ {
+ readBuffer = m_pSocket->readBufferSize();
+ }
+ return readBuffer;
}
void WebSocket::setProxy(const QNetworkProxy &networkProxy)
{
- if (m_pSocket)
- {
- m_pSocket->setProxy(networkProxy);
- }
+ if (m_pSocket)
+ {
+ m_pSocket->setProxy(networkProxy);
+ }
}
bool WebSocket::isValid()
{
- bool valid = false;
- if (m_pSocket)
- {
- valid = m_pSocket->isValid();
- }
- return valid;
+ bool valid = false;
+ if (m_pSocket)
+ {
+ valid = m_pSocket->isValid();
+ }
+ return valid;
}