1010// Qt includes
1111#include < QResource>
1212#include < QDateTime>
13+ #include < QCryptographicHash>
14+ #include < QHostInfo>
1315
1416// hyperion util includes
1517#include < hyperion/ImageProcessorFactory.h>
@@ -25,7 +27,8 @@ JsonClientConnection::JsonClientConnection(QTcpSocket *socket, Hyperion * hyperi
2527 _socket(socket),
2628 _imageProcessor(ImageProcessorFactory::getInstance().newImageProcessor()),
2729 _hyperion(hyperion),
28- _receiveBuffer()
30+ _receiveBuffer(),
31+ _webSocketHandshakeDone(false )
2932{
3033 // connect internal signals and slots
3134 connect (_socket, SIGNAL (disconnected ()), this , SLOT (socketClosed ()));
@@ -41,26 +44,164 @@ JsonClientConnection::~JsonClientConnection()
4144void JsonClientConnection::readData ()
4245{
4346 _receiveBuffer += _socket->readAll ();
44-
45- int bytes = _receiveBuffer.indexOf (' \n ' ) + 1 ;
46- while (bytes > 0 )
47+
48+ if (_webSocketHandshakeDone)
4749 {
48- // create message string
49- std::string message (_receiveBuffer.data (), bytes);
50-
51- // remove message data from buffer
52- _receiveBuffer = _receiveBuffer.mid (bytes);
53-
54- // handle message
55- handleMessage (message);
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
61+ int bytes = _receiveBuffer.indexOf (' \n ' ) + 1 ;
62+ while (bytes > 0 )
63+ {
64+ // create message string
65+ std::string message (_receiveBuffer.data (), bytes);
66+
67+ // remove message data from buffer
68+ _receiveBuffer = _receiveBuffer.mid (bytes);
69+
70+ // handle message
71+ handleMessage (message);
72+
73+ // try too look up '\n' again
74+ bytes = _receiveBuffer.indexOf (' \n ' ) + 1 ;
75+ }
76+ }
77+ }
78+ }
5679
57- // try too look up '\n' again
58- bytes = _receiveBuffer.indexOf (' \n ' ) + 1 ;
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 ();
59170 }
60171}
61172
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+
62202void JsonClientConnection::socketClosed ()
63203{
204+ _webSocketHandshakeDone = false ;
64205 emit connectionClosed (this );
65206}
66207
@@ -205,6 +346,9 @@ void JsonClientConnection::handleServerInfoCommand(const Json::Value &)
205346 Json::Value result;
206347 result[" success" ] = true ;
207348 Json::Value & info = result[" info" ];
349+
350+ // add host name for remote clients
351+ info[" hostname" ] = QHostInfo::localHostName ().toStdString ();
208352
209353 // collect priority information
210354 Json::Value & priorities = info[" priorities" ] = Json::Value (Json::arrayValue);
@@ -362,7 +506,32 @@ void JsonClientConnection::sendMessage(const Json::Value &message)
362506{
363507 Json::FastWriter writer;
364508 std::string serializedReply = writer.write (message);
365- _socket->write (serializedReply.data (), serializedReply.length ());
509+
510+ if (!_webSocketHandshakeDone)
511+ {
512+ // raw tcp socket mode
513+ _socket->write (serializedReply.data (), serializedReply.length ());
514+ } else
515+ {
516+ // websocket mode
517+ quint32 size = serializedReply.length ();
518+
519+ // prepare data frame
520+ QByteArray response;
521+ response.append (0x81 );
522+ if (size > 125 )
523+ {
524+ response.append (0x7E );
525+ response.append ((size >> 8 ) & 0xFF );
526+ response.append (size & 0xFF );
527+ } else {
528+ response.append (size);
529+ }
530+
531+ response.append (serializedReply.c_str (), serializedReply.length ());
532+
533+ _socket->write (response.data (), response.length ());
534+ }
366535}
367536
368537void JsonClientConnection::sendSuccessReply ()
0 commit comments