@@ -27,9 +27,9 @@ JsonClientConnection::JsonClientConnection(QTcpSocket *socket, Hyperion * hyperi
2727 _socket(socket),
2828 _imageProcessor(ImageProcessorFactory::getInstance().newImageProcessor()),
2929 _hyperion(hyperion),
30- _receiveBuffer()
30+ _receiveBuffer(),
31+ _webSocketHandshakeDone(false )
3132{
32- _webSocketHandshakeDone = false ;
3333 // connect internal signals and slots
3434 connect (_socket, SIGNAL (disconnected ()), this , SLOT (socketClosed ()));
3535 connect (_socket, SIGNAL (readyRead ()), this , SLOT (readData ()));
@@ -45,106 +45,19 @@ void JsonClientConnection::readData()
4545{
4646 _receiveBuffer += _socket->readAll ();
4747
48- if (_webSocketHandshakeDone) { // websocket mode, data frame
49- quint8 opCode = 0 ;
50- quint64 payloadLength = 0 ;
51- bool isMasked = false ;
52- quint32 index = 0 ;
53- quint8 maskKey[4 ];
54-
55- if ((_receiveBuffer.at (0 ) & 0x80 ) == 0x80 ) { // final bit
56- opCode = _receiveBuffer.at (0 ) & 0x0F ;
57- isMasked = (_receiveBuffer.at (1 ) & 0x80 ) == 0x80 ;
58- payloadLength = _receiveBuffer.at (1 ) & 0x7F ;
59- index = 2 ;
60-
61- switch (payloadLength) {
62- case 126 :
63- payloadLength = ((_receiveBuffer.at (2 ) << 8 ) & 0xFF00 ) | (_receiveBuffer.at (3 ) & 0xFF );
64- index += 2 ;
65- break ;
66- case 127 : {
67- payloadLength = 0 ;
68- for (uint i=0 ; i < 8 ; i++) {
69- payloadLength |= ((quint64)(_receiveBuffer.at (index+i) & 0xFF )) << (8 *(7 -i));
70- }
71- index += 8 ;
72- }
73- break ;
74- default :
75- break ;
76- }
77-
78- if (isMasked) { // if the data is masked we need to get the key for unmasking
79- for (uint i=0 ; i < 4 ; i++) {
80- maskKey[i] = _receiveBuffer.at (index + i);
81- }
82- index += 4 ;
83- }
84-
85- // check the type of data frame
86- switch (opCode) {
87- case 0x01 : { // text
88- QByteArray result = _receiveBuffer.mid (index, payloadLength);
89- _receiveBuffer.clear ();
90-
91- // unmask data if necessary
92- if (isMasked) {
93- for (uint i=0 ; i < payloadLength; i++) {
94- result[i] = (result[i] ^ maskKey[i % 4 ]);
95- }
96- }
97-
98- handleMessage (QString (result).toStdString ());
99- }
100- break ;
101- case 0x08 : { // close
102- quint8 close[]={0x88 , 0 };
103- _socket->write ((const char *)close, 2 );
104- _socket->flush ();
105- _socket->close ();
106- }
107- break ;
108- case 0x09 : { // ping, send pong
109- quint8 close[]={0x0A , 0 };
110- _socket->write ((const char *)close, 2 );
111- _socket->flush ();
112- }
113- break ;
114- }
115- } else {
116- std::cout << " Someone is sending very big messages over several frames... it's not supported yet" << std::endl;
117- quint8 close[]={0x88 , 0 };
118- _socket->write ((const char *)close, 2 );
119- _socket->flush ();
120- _socket->close ();
121- }
122- } else { // might be a handshake request or raw socket data
123- if (_receiveBuffer.contains (" Upgrade: websocket" )){ // http header, might not be a very reliable check...
124- std::cout << " Websocket handshake" << std::endl;
125-
126- // get the key to tprepare an answer
127- int start = _receiveBuffer.indexOf (" Sec-WebSocket-Key" ) + 19 ;
128- std::string value (_receiveBuffer.mid (start, _receiveBuffer.indexOf (" \r\n " , start) - start).data ());
129- _receiveBuffer.clear ();
130-
131- // must be always appended
132- value += " 258EAFA5-E914-47DA-95CA-C5AB0DC85B11" ;
133-
134- // generate sha1 hash
135- QByteArray hash = QCryptographicHash::hash (value.c_str (), QCryptographicHash::Sha1);
136-
137- // prepare an answer
138- std::ostringstream h;
139- h << " HTTP/1.1 101 Switching Protocols\r\n " <<
140- " Upgrade: websocket\r\n " <<
141- " Connection: Upgrade\r\n " <<
142- " Sec-WebSocket-Accept: " << QString (hash.toBase64 ()).toStdString () << " \r\n\r\n " ;
143-
144- _socket->write (h.str ().c_str ());
145- _socket->flush ();
146- _webSocketHandshakeDone = true ; // we are in WebSocket mode, data frames should follow next
147- } else { // raw socket data, handling as usual
48+ if (_webSocketHandshakeDone)
49+ {
50+ // websocket mode, data frame
51+ handleWebSocketFrame ();
52+ } else
53+ {
54+ // might be a handshake request or raw socket data
55+ if (_receiveBuffer.contains (" Upgrade: websocket" ))
56+ {
57+ doWebSocketHandshake ();
58+ } else
59+ {
60+ // raw socket data, handling as usual
14861 int bytes = _receiveBuffer.indexOf (' \n ' ) + 1 ;
14962 while (bytes > 0 )
15063 {
@@ -164,6 +77,128 @@ void JsonClientConnection::readData()
16477 }
16578}
16679
80+ void JsonClientConnection::handleWebSocketFrame ()
81+ {
82+ if ((_receiveBuffer.at (0 ) & 0x80 ) == 0x80 )
83+ {
84+ // final bit found, frame complete
85+ quint8 * maskKey = NULL ;
86+ quint8 opCode = _receiveBuffer.at (0 ) & 0x0F ;
87+ bool isMasked = (_receiveBuffer.at (1 ) & 0x80 ) == 0x80 ;
88+ quint64 payloadLength = _receiveBuffer.at (1 ) & 0x7F ;
89+ quint32 index = 2 ;
90+
91+ switch (payloadLength)
92+ {
93+ case 126 :
94+ payloadLength = ((_receiveBuffer.at (2 ) << 8 ) & 0xFF00 ) | (_receiveBuffer.at (3 ) & 0xFF );
95+ index += 2 ;
96+ break ;
97+ case 127 :
98+ payloadLength = 0 ;
99+ for (uint i=0 ; i < 8 ; i++) {
100+ payloadLength |= ((quint64)(_receiveBuffer.at (index+i) & 0xFF )) << (8 *(7 -i));
101+ }
102+ index += 8 ;
103+ break ;
104+ default :
105+ break ;
106+ }
107+
108+ if (isMasked)
109+ {
110+ // if the data is masked we need to get the key for unmasking
111+ maskKey = new quint8[4 ];
112+ for (uint i=0 ; i < 4 ; i++)
113+ {
114+ maskKey[i] = _receiveBuffer.at (index + i);
115+ }
116+ index += 4 ;
117+ }
118+
119+ // check the type of data frame
120+ switch (opCode)
121+ {
122+ case 0x01 :
123+ {
124+ // frame contains text, extract it
125+ QByteArray result = _receiveBuffer.mid (index, payloadLength);
126+ _receiveBuffer.clear ();
127+
128+ // unmask data if necessary
129+ if (isMasked)
130+ {
131+ for (uint i=0 ; i < payloadLength; i++)
132+ {
133+ result[i] = (result[i] ^ maskKey[i % 4 ]);
134+ }
135+ if (maskKey != NULL )
136+ {
137+ delete[] maskKey;
138+ maskKey = NULL ;
139+ }
140+ }
141+
142+ handleMessage (QString (result).toStdString ());
143+ }
144+ break ;
145+ case 0x08 :
146+ {
147+ // close request, confirm
148+ quint8 close[] = {0x88 , 0 };
149+ _socket->write ((const char *)close, 2 );
150+ _socket->flush ();
151+ _socket->close ();
152+ }
153+ break ;
154+ case 0x09 :
155+ {
156+ // ping received, send pong
157+ quint8 pong[] = {0x0A , 0 };
158+ _socket->write ((const char *)pong, 2 );
159+ _socket->flush ();
160+ }
161+ break ;
162+ }
163+ } else
164+ {
165+ std::cout << " Someone is sending very big messages over several frames... it's not supported yet" << std::endl;
166+ quint8 close[] = {0x88 , 0 };
167+ _socket->write ((const char *)close, 2 );
168+ _socket->flush ();
169+ _socket->close ();
170+ }
171+ }
172+
173+ void JsonClientConnection::doWebSocketHandshake ()
174+ {
175+ // http header, might not be a very reliable check...
176+ std::cout << " Websocket handshake" << std::endl;
177+
178+ // get the key to prepare an answer
179+ int start = _receiveBuffer.indexOf (" Sec-WebSocket-Key" ) + 19 ;
180+ std::string value (_receiveBuffer.mid (start, _receiveBuffer.indexOf (" \r\n " , start) - start).data ());
181+ _receiveBuffer.clear ();
182+
183+ // must be always appended
184+ value += " 258EAFA5-E914-47DA-95CA-C5AB0DC85B11" ;
185+
186+ // generate sha1 hash
187+ QByteArray hash = QCryptographicHash::hash (value.c_str (), QCryptographicHash::Sha1);
188+
189+ // prepare an answer
190+ std::ostringstream h;
191+ h << " HTTP/1.1 101 Switching Protocols\r\n " <<
192+ " Upgrade: websocket\r\n " <<
193+ " Connection: Upgrade\r\n " <<
194+ " Sec-WebSocket-Accept: " << QString (hash.toBase64 ()).toStdString () << " \r\n\r\n " ;
195+
196+ _socket->write (h.str ().c_str ());
197+ _socket->flush ();
198+ // we are in WebSocket mode, data frames should follow next
199+ _webSocketHandshakeDone = true ;
200+ }
201+
167202void JsonClientConnection::socketClosed ()
168203{
169204 _webSocketHandshakeDone = false ;
@@ -472,24 +507,28 @@ void JsonClientConnection::sendMessage(const Json::Value &message)
472507 Json::FastWriter writer;
473508 std::string serializedReply = writer.write (message);
474509
475- if (!_webSocketHandshakeDone) { // raw tcp socket mode
510+ if (!_webSocketHandshakeDone)
511+ {
512+ // raw tcp socket mode
476513 _socket->write (serializedReply.data (), serializedReply.length ());
477- } else { // websocket mode
514+ } else
515+ {
516+ // websocket mode
478517 quint32 size = serializedReply.length ();
479518
480519 // prepare data frame
481520 QByteArray response;
482521 response.append (0x81 );
483- if (size > 125 ) {
522+ if (size > 125 )
523+ {
484524 response.append (0x7E );
485525 response.append ((size >> 8 ) & 0xFF );
486526 response.append (size & 0xFF );
487527 } else {
488528 response.append (size);
489529 }
490530
491- QByteArray data (serializedReply.c_str (), serializedReply.length ());
492- response.append (data);
531+ response.append (serializedReply.c_str (), serializedReply.length ());
493532
494533 _socket->write (response.data (), response.length ());
495534 }
0 commit comments