10
10
// Qt includes
11
11
#include < QResource>
12
12
#include < QDateTime>
13
+ #include < QCryptographicHash>
14
+ #include < QHostInfo>
13
15
14
16
// hyperion util includes
15
17
#include < hyperion/ImageProcessorFactory.h>
@@ -27,6 +29,7 @@ JsonClientConnection::JsonClientConnection(QTcpSocket *socket, Hyperion * hyperi
27
29
_hyperion(hyperion),
28
30
_receiveBuffer()
29
31
{
32
+ _webSocketHandshakeDone = false ;
30
33
// connect internal signals and slots
31
34
connect (_socket, SIGNAL (disconnected ()), this , SLOT (socketClosed ()));
32
35
connect (_socket, SIGNAL (readyRead ()), this , SLOT (readData ()));
@@ -41,7 +44,126 @@ JsonClientConnection::~JsonClientConnection()
41
44
void JsonClientConnection::readData ()
42
45
{
43
46
_receiveBuffer += _socket->readAll ();
44
-
47
+
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 (int 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 (int 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
148
+ int bytes = _receiveBuffer.indexOf (' \n ' ) + 1 ;
149
+ while (bytes > 0 )
150
+ {
151
+ // create message string
152
+ std::string message (_receiveBuffer.data (), bytes);
153
+
154
+ // remove message data from buffer
155
+ _receiveBuffer = _receiveBuffer.mid (bytes);
156
+
157
+ // handle message
158
+ handleMessage (message);
159
+
160
+ // try too look up '\n' again
161
+ bytes = _receiveBuffer.indexOf (' \n ' ) + 1 ;
162
+ }
163
+ }
164
+ }
165
+
166
+ /*
45
167
int bytes = _receiveBuffer.indexOf('\n') + 1;
46
168
while(bytes > 0)
47
169
{
@@ -57,10 +179,12 @@ void JsonClientConnection::readData()
57
179
// try too look up '\n' again
58
180
bytes = _receiveBuffer.indexOf('\n') + 1;
59
181
}
182
+ */
60
183
}
61
184
62
185
void JsonClientConnection::socketClosed ()
63
186
{
187
+ _webSocketHandshakeDone = false ;
64
188
emit connectionClosed (this );
65
189
}
66
190
@@ -205,6 +329,9 @@ void JsonClientConnection::handleServerInfoCommand(const Json::Value &)
205
329
Json::Value result;
206
330
result[" success" ] = true ;
207
331
Json::Value & info = result[" info" ];
332
+
333
+ // add host name for remote clients
334
+ info[" hostname" ] = QHostInfo::localHostName ().toStdString ();
208
335
209
336
// collect priority information
210
337
Json::Value & priorities = info[" priorities" ] = Json::Value (Json::arrayValue);
@@ -362,7 +489,28 @@ void JsonClientConnection::sendMessage(const Json::Value &message)
362
489
{
363
490
Json::FastWriter writer;
364
491
std::string serializedReply = writer.write (message);
365
- _socket->write (serializedReply.data (), serializedReply.length ());
492
+
493
+ if (!_webSocketHandshakeDone) { // raw tcp socket mode
494
+ _socket->write (serializedReply.data (), serializedReply.length ());
495
+ } else { // websocket mode
496
+ quint32 size = serializedReply.length ();
497
+
498
+ // prepare data frame
499
+ QByteArray response;
500
+ response.append (0x81 );
501
+ if (size > 125 ) {
502
+ response.append (0x7E );
503
+ response.append ((size >> 8 ) & 0xFF );
504
+ response.append (size & 0xFF );
505
+ } else {
506
+ response.append (size);
507
+ }
508
+
509
+ QByteArray data (serializedReply.c_str (), serializedReply.length ());
510
+ response.append (data);
511
+
512
+ _socket->write (response.data (), response.length ());
513
+ }
366
514
}
367
515
368
516
void JsonClientConnection::sendSuccessReply ()
0 commit comments