code refactoring

Former-commit-id: 157f424e83c58fca4ed1e3283899cbbdfadcffe1
This commit is contained in:
Gamadril 2014-11-08 21:01:46 +01:00
parent 6a9e75243d
commit 9168ee5098
2 changed files with 156 additions and 107 deletions

View File

@ -27,9 +27,9 @@ JsonClientConnection::JsonClientConnection(QTcpSocket *socket, Hyperion * hyperi
_socket(socket), _socket(socket),
_imageProcessor(ImageProcessorFactory::getInstance().newImageProcessor()), _imageProcessor(ImageProcessorFactory::getInstance().newImageProcessor()),
_hyperion(hyperion), _hyperion(hyperion),
_receiveBuffer() _receiveBuffer(),
_webSocketHandshakeDone(false)
{ {
_webSocketHandshakeDone = false;
// connect internal signals and slots // connect internal signals and slots
connect(_socket, SIGNAL(disconnected()), this, SLOT(socketClosed())); connect(_socket, SIGNAL(disconnected()), this, SLOT(socketClosed()));
connect(_socket, SIGNAL(readyRead()), this, SLOT(readData())); connect(_socket, SIGNAL(readyRead()), this, SLOT(readData()));
@ -45,85 +45,137 @@ void JsonClientConnection::readData()
{ {
_receiveBuffer += _socket->readAll(); _receiveBuffer += _socket->readAll();
if (_webSocketHandshakeDone) { // websocket mode, data frame if (_webSocketHandshakeDone)
quint8 opCode = 0; {
quint64 payloadLength = 0; // websocket mode, data frame
bool isMasked = false; handleWebSocketFrame();
quint32 index = 0; } else
quint8 maskKey[4]; {
// might be a handshake request or raw socket data
if(_receiveBuffer.contains("Upgrade: websocket"))
{
doWebSocketHandshake();
} else
{
// raw socket data, handling as usual
int bytes = _receiveBuffer.indexOf('\n') + 1;
while(bytes > 0)
{
// create message string
std::string message(_receiveBuffer.data(), bytes);
if ((_receiveBuffer.at(0) & 0x80) == 0x80) { // final bit // remove message data from buffer
opCode = _receiveBuffer.at(0) & 0x0F; _receiveBuffer = _receiveBuffer.mid(bytes);
isMasked = (_receiveBuffer.at(1) & 0x80) == 0x80;
payloadLength = _receiveBuffer.at(1) & 0x7F;
index = 2;
switch (payloadLength) { // handle message
handleMessage(message);
// try too look up '\n' again
bytes = _receiveBuffer.indexOf('\n') + 1;
}
}
}
}
void JsonClientConnection::handleWebSocketFrame()
{
if ((_receiveBuffer.at(0) & 0x80) == 0x80)
{
// final bit found, frame complete
quint8 * maskKey = NULL;
quint8 opCode = _receiveBuffer.at(0) & 0x0F;
bool isMasked = (_receiveBuffer.at(1) & 0x80) == 0x80;
quint64 payloadLength = _receiveBuffer.at(1) & 0x7F;
quint32 index = 2;
switch (payloadLength)
{
case 126: case 126:
payloadLength = ((_receiveBuffer.at(2) << 8) & 0xFF00) | (_receiveBuffer.at(3) & 0xFF); payloadLength = ((_receiveBuffer.at(2) << 8) & 0xFF00) | (_receiveBuffer.at(3) & 0xFF);
index += 2; index += 2;
break; break;
case 127: { case 127:
payloadLength = 0; payloadLength = 0;
for (uint i=0; i < 8; i++) { for (uint i=0; i < 8; i++) {
payloadLength |= ((quint64)(_receiveBuffer.at(index+i) & 0xFF)) << (8*(7-i)); payloadLength |= ((quint64)(_receiveBuffer.at(index+i) & 0xFF)) << (8*(7-i));
} }
index += 8; index += 8;
}
break; break;
default: default:
break; break;
} }
if (isMasked) { // if the data is masked we need to get the key for unmasking if (isMasked)
for (uint i=0; i < 4; i++) { {
// if the data is masked we need to get the key for unmasking
maskKey = new quint8[4];
for (uint i=0; i < 4; i++)
{
maskKey[i] = _receiveBuffer.at(index + i); maskKey[i] = _receiveBuffer.at(index + i);
} }
index += 4; index += 4;
} }
// check the type of data frame // check the type of data frame
switch (opCode) { switch (opCode)
case 0x01: { // text {
case 0x01:
{
// frame contains text, extract it
QByteArray result = _receiveBuffer.mid(index, payloadLength); QByteArray result = _receiveBuffer.mid(index, payloadLength);
_receiveBuffer.clear(); _receiveBuffer.clear();
// unmask data if necessary // unmask data if necessary
if (isMasked) { if (isMasked)
for (uint i=0 ; i < payloadLength; i++) { {
for (uint i=0; i < payloadLength; i++)
{
result[i] = (result[i] ^ maskKey[i % 4]); result[i] = (result[i] ^ maskKey[i % 4]);
} }
if (maskKey != NULL)
{
delete[] maskKey;
maskKey = NULL;
}
} }
handleMessage(QString(result).toStdString()); handleMessage(QString(result).toStdString());
} }
break; break;
case 0x08: { // close case 0x08:
quint8 close[]={0x88, 0}; {
// close request, confirm
quint8 close[] = {0x88, 0};
_socket->write((const char*)close, 2); _socket->write((const char*)close, 2);
_socket->flush(); _socket->flush();
_socket->close(); _socket->close();
} }
break; break;
case 0x09: { // ping, send pong case 0x09:
quint8 close[]={0x0A, 0}; {
_socket->write((const char*)close, 2); // ping received, send pong
quint8 pong[] = {0x0A, 0};
_socket->write((const char*)pong, 2);
_socket->flush(); _socket->flush();
} }
break; break;
} }
} else { } else
{
std::cout << "Someone is sending very big messages over several frames... it's not supported yet" << std::endl; std::cout << "Someone is sending very big messages over several frames... it's not supported yet" << std::endl;
quint8 close[]={0x88, 0}; quint8 close[] = {0x88, 0};
_socket->write((const char*)close, 2); _socket->write((const char*)close, 2);
_socket->flush(); _socket->flush();
_socket->close(); _socket->close();
} }
} else { // might be a handshake request or raw socket data }
if(_receiveBuffer.contains("Upgrade: websocket")){ // http header, might not be a very reliable check...
void JsonClientConnection::doWebSocketHandshake()
{
// http header, might not be a very reliable check...
std::cout << "Websocket handshake" << std::endl; std::cout << "Websocket handshake" << std::endl;
// get the key to tprepare an answer // get the key to prepare an answer
int start = _receiveBuffer.indexOf("Sec-WebSocket-Key") + 19; int start = _receiveBuffer.indexOf("Sec-WebSocket-Key") + 19;
std::string value(_receiveBuffer.mid(start, _receiveBuffer.indexOf("\r\n", start) - start).data()); std::string value(_receiveBuffer.mid(start, _receiveBuffer.indexOf("\r\n", start) - start).data());
_receiveBuffer.clear(); _receiveBuffer.clear();
@ -143,25 +195,8 @@ void JsonClientConnection::readData()
_socket->write(h.str().c_str()); _socket->write(h.str().c_str());
_socket->flush(); _socket->flush();
_webSocketHandshakeDone = true; // we are in WebSocket mode, data frames should follow next // we are in WebSocket mode, data frames should follow next
} else { // raw socket data, handling as usual _webSocketHandshakeDone = true;
int bytes = _receiveBuffer.indexOf('\n') + 1;
while(bytes > 0)
{
// create message string
std::string message(_receiveBuffer.data(), bytes);
// remove message data from buffer
_receiveBuffer = _receiveBuffer.mid(bytes);
// handle message
handleMessage(message);
// try too look up '\n' again
bytes = _receiveBuffer.indexOf('\n') + 1;
}
}
}
} }
void JsonClientConnection::socketClosed() void JsonClientConnection::socketClosed()
@ -472,15 +507,20 @@ void JsonClientConnection::sendMessage(const Json::Value &message)
Json::FastWriter writer; Json::FastWriter writer;
std::string serializedReply = writer.write(message); std::string serializedReply = writer.write(message);
if (!_webSocketHandshakeDone) { // raw tcp socket mode if (!_webSocketHandshakeDone)
{
// raw tcp socket mode
_socket->write(serializedReply.data(), serializedReply.length()); _socket->write(serializedReply.data(), serializedReply.length());
} else { // websocket mode } else
{
// websocket mode
quint32 size = serializedReply.length(); quint32 size = serializedReply.length();
// prepare data frame // prepare data frame
QByteArray response; QByteArray response;
response.append(0x81); response.append(0x81);
if (size > 125) { if (size > 125)
{
response.append(0x7E); response.append(0x7E);
response.append((size >> 8) & 0xFF); response.append((size >> 8) & 0xFF);
response.append(size & 0xFF); response.append(size & 0xFF);
@ -488,8 +528,7 @@ void JsonClientConnection::sendMessage(const Json::Value &message)
response.append(size); response.append(size);
} }
QByteArray data(serializedReply.c_str(), serializedReply.length()); response.append(serializedReply.c_str(), serializedReply.length());
response.append(data);
_socket->write(response.data(), response.length()); _socket->write(response.data(), response.length());
} }

View File

@ -137,6 +137,16 @@ private:
/// ///
void sendErrorReply(const std::string & error); void sendErrorReply(const std::string & error);
///
/// Do handshake for a websocket connection
///
void doWebSocketHandshake();
///
/// Handle incoming websocket data frame
///
void handleWebSocketFrame();
private: private:
/// ///
/// Check if a JSON messag is valid according to a given JSON schema /// Check if a JSON messag is valid according to a given JSON schema