RDK Documentation (Open Sourced RDK Components)
qt_websocketproxy.cpp
1 /*
2  * If not stated otherwise in this file or this component's Licenses.txt file the
3  * following copyright and licenses apply:
4  *
5  * Copyright 2016 RDK Management
6  *
7  * Licensed under the Apache License, Version 2.0 (the "License");
8  * you may not use this file except in compliance with the License.
9  * You may obtain a copy of the License at
10  *
11  * http://www.apache.org/licenses/LICENSE-2.0
12  *
13  * Unless required by applicable law or agreed to in writing, software
14  * distributed under the License is distributed on an "AS IS" BASIS,
15  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16  * See the License for the specific language governing permissions and
17  * limitations under the License.
18 */
19 
20 
21 /**
22 * @defgroup trm
23 * @{
24 * @defgroup wsproxy
25 * @{
26 **/
27 
28 
29 #include <sys/types.h>
30 #include <sys/stat.h>
31 #include <unistd.h>
32 #include <fcntl.h>
33 #include <linux/reboot.h>
34 #include <sys/reboot.h>
35 
36 #include <iostream>
37 #include <QStringList>
38 #include <QtCore/QTimer>
39 #include <QtWebSockets/QWebSocketServer>
40 #include <QtWebSockets/QWebSocket>
41 
42 #include <QtCore/QFile>
43 #include <QtNetwork/QSslCertificate>
44 #include <QtNetwork/QSslKey>
45 #include <QSslCipher>
46 #include <QSettings>
47 #include "safec_lib.h"
48 #include "rfcapi.h"
49 
50 #define DYNAMIC_PASSCODE_UTILITY "/usr/bin/rdkssacli"
51 #define STATIC_PASSCODE_UTILITY "/usr/bin/GetConfigFile"
52 #define DYNAMIC_PASSCODE_ARG "\"{STOR=GET,SRC=kquhqtoczcbx,DST=/dev/stdout}\""
53 #define STATIC_PASSCODE_ARG_FILE "/tmp/.cfgStaticxpki"
54 
55 
56 const char* trmPropertiesPath ="/etc/trmProxySetup.properties";
57 const char* caKeyTagName = "CA_CHAIN_CERTIFICATE";
58 const char* privateKeyTagName = "CA_SERVER_PRIVATE_KEY";
59 const char* publicKeyTagName = "CA_SERVER_PUBLIC_CERTIFICATE";
60 const char* xpkiDynamicCertificate = "CA_SERVER_XPKI_DYNAMIC_CERTIFICATE";
61 const char* xpkiStaticCertificate = "CA_SERVER_XPKI_STATIC_CERTIFICATE";
62 
63 
64 #include "qt_websocketproxy.h"
65 
66 #include "tcpOpensslProxyServer.h"
67 extern int begin_request_callback(void *conn);
68 extern void end_request_callback(void *conn, int reply_status_code);
69 extern int websocket_connect_callback(void *conn);
70 extern int websocket_disconnect_callback(void *conn);
71 extern void websocket_ready_callback(void *conn) ;
72 extern int log_message_callback(const void *conn, const char *message) ;
73 extern int websocket_data_callback(void *conn, int flags, char *trm_data, size_t trm_data_length) ;
74 extern int websocket_data_callback_with_clientId(int connection_id, int flags, char *trm_data, size_t trm_data_length);
75 static void onWebsocketMessageReceivedSSL(int clientId, char* message, size_t len);
76 static void onPongSSL(int clientId, long long unsigned int ticks, QByteArray &qmsg);
77 
78 static WebSocketProxy *m_proxy = NULL;
79 
80 QT_USE_NAMESPACE
81 
82 PingPongTask::PingPongTask(QWebSocket* wssocket)
83  : wssocket(wssocket), stopped(false)
84 {
85  m_clientId = -1;
86  m_sslProxyServer = NULL;
87  __TIMESTAMP();
88  std::cout << "Ping-Pong created for socket " << (void *)wssocket << std::endl;
89  connect(&timer, SIGNAL(timeout()), this, SLOT(onTimeout()));
90  connect(wssocket, SIGNAL(pong(quint64, QByteArray)), this, SLOT(onPong(quint64, QByteArray)));
91  retry = 0;
92 }
93 
94 PingPongTask::PingPongTask(tcpOpensslProxyServer *sslProxyServer, int clientId)
95  : m_sslProxyServer(sslProxyServer), m_clientId(clientId), stopped(false)
96 {
97  wssocket = NULL;
98  __TIMESTAMP();
99  std::cout << "Ping-Pong created for socket " << (void *)wssocket << " m_sslProxyServer "<< m_sslProxyServer <<std::endl;
100  connect(&timer, SIGNAL(timeout()), this, SLOT(onTimeout()));
101  //On pong signal handle is implemented during new connection
102  retry = 0;
103 }
104 
105 PingPongTask::~PingPongTask(void)
106 {
107  if (!stopped) {
108  __TIMESTAMP();
109  std::cout << " Assert: PING-PONG not stopped before deleting\r\n";
110  }
111 }
112 
113 void PingPongTask::start(void)
114 {
115  if (!stopped) {
116  //__TIMESTAMP(); std::cout << "Ping-Pong started for socket " << (void *)&wssocket << " m_sslProxyServer "<< m_sslProxyServer << " m_clientId " << m_clientId <<std::endl;
117  if (NULL != wssocket) {
118  wssocket->ping();
119  }
120  if (NULL != m_sslProxyServer) {
121  m_sslProxyServer->ping (m_clientId);
122  }
123  timer.setInterval(5000);
124  timer.setSingleShot(true);
125  timer.start();
126  }
127 }
128 
129 void PingPongTask::stop(void)
130 {
131  __TIMESTAMP();
132  std::cout << "Ping-Pong stopped for socket " << (void *)wssocket << " m_sslProxyServer "<< m_sslProxyServer <<std::endl;
133  timer.stop();
134  stopped = true;
135 }
136 
137 void PingPongTask::onTimeout(void)
138 {
139  /* Retry on timeout, or close the connection */
140  //__TIMESTAMP(); std::cout << "Ping-Pong Timeout " << retry << "times for socket " << (void *)&wssocket << std::endl;
141  retry++;
142  if (retry < 3) {
143  start();
144  }
145  else {
146  if (retry < 5) {
147  __TIMESTAMP();
148  std::cout << "Ping-Pong Would have closed socket " << (void *)wssocket << " m_sslProxyServer "<< m_sslProxyServer <<std::endl;
149  start();
150  }
151  else {
152  __TIMESTAMP();
153  std::cout << "Ping-Pong Timeout closing socket " << (void *)wssocket << " m_sslProxyServer "<< m_sslProxyServer << " m_clientId " << m_clientId << std::endl;
154  if (NULL != wssocket) {
155  wssocket->close();
156  }
157  if (NULL != m_sslProxyServer) {
158  m_sslProxyServer->closeClient (m_clientId);
159  }
160  }
161  }
162 }
163 
164 void PingPongTask::onPong(quint64 elapsedTime, QByteArray)
165 {
166  /* reset on PONG */
167  if (elapsedTime > 10000) {
168  __TIMESTAMP();
169  std::cout << "Ping-Pong Slow: pong received for socket " << (void *)wssocket << " m_sslProxyServer "<< m_sslProxyServer <<std::endl;
170  std::cout << " At [" << QTime::currentTime().toString().toUtf8().data();
171  std::cout << " ] PONG received epapsedTime = " << elapsedTime << std::endl;
172  }
173  retry = 0;
174 }
175 
176 
177 /* Function to execute system command */
178 static int exec_sys_command(char* cmd)
179 {
180  char buff[128];
181  FILE *syscmd = popen(cmd, "re");
182  if(!syscmd) {
183  std::cout <<"popen failed with error code"<< syscmd <<"to execute system command: "<< cmd;
184  return -1;
185  }
186  memset(buff, 0, 128);
187  std::cout << "Executing system command " << cmd << std::endl;
188 
189  while(fgets(buff, sizeof(buff), syscmd) != 0) {
190  std::cout << "read syscmd buff : " << buff << std::endl;
191  }
192  pclose(syscmd);
193  return 0;
194 }
195 
196 #define TRM_USE_RFC 1
197 static bool rfc_get_trmssl_status()
198 {
199  bool isTRMSSLEnabled = true;
200 #ifdef TRM_USE_RFC
201  int sysRet = system(". /lib/rdk/isFeatureEnabled.sh NOTRMSSL");
202  if((WEXITSTATUS(sysRet) == true) && (WIFEXITED(sysRet) == true))
203  {
204  std::cout << "RFC NOTRMSSL feature Enabled "<<std::endl;
205  isTRMSSLEnabled = false;
206  }
207 #else
208  isTRMSSLEnabled = true;
209 #endif
210 
211  std::cout << "RFC TRMSSL feature status:"<< isTRMSSLEnabled<<std::endl;
212  return isTRMSSLEnabled;
213 }
214 
215 typedef enum {
216  RFC_PARM_mTLS = 0,
217  RFC_PARM_qtPort,
218 }TRM_RFC_PARAM_TYPE;
219 
220 static bool is_TRM_RFC_param_enable (TRM_RFC_PARAM_TYPE type)
221 {
222  bool ret = false;
223  RFC_ParamData_t param;
224  WDMP_STATUS status = WDMP_ERR_INVALID_PARAMETER_NAME;
225  std::string parmName = std::string ("invalid");
226  switch (type) {
227  case RFC_PARM_mTLS:
228  status = getRFCParameter((const char*)"WSPROXY", (const char*)"Device.DeviceInfo.X_RDKCENTRAL-COM_RFC.Feature.TRM.EnableMTLS", &param);
229  parmName = std::string ("mTLS");
230  break;
231  case RFC_PARM_qtPort:
232  status = getRFCParameter((const char*)"WSPROXY", (const char*)"Device.DeviceInfo.X_RDKCENTRAL-COM_RFC.Feature.TRMQtSecurePort.Enable", &param);
233  parmName = std::string ("qtPort");
234  break;
235  }
236  if (status == WDMP_SUCCESS) {
237  printf ("name = %s, type = %d, value = %s\n", param.name, param.type, param.value);
238 
239  if (!strncmp(param.value, "true", strlen("true"))) {
240  printf ("TRM %s is enabled.\n", parmName.c_str());
241  ret = true;
242  }
243  else {
244  printf ("TRM %s is disabled.\n", parmName.c_str());
245  }
246  }
247  else {
248  printf ("getRFCParameter Failed : %s\n", getRFCErrorString(status));
249  if (RFC_PARM_qtPort == type){
250  //TRMQtSecurePort default value is enabled.
251  ret = true;
252  }
253  }
254  return ret;
255 }
256 
257 static void delete_file (QString &fileName)
258 {
259  char cmd[256];
260  sprintf(cmd, "%s %s", "rm", fileName.toLatin1().data());
261  exec_sys_command(cmd);
262 }
263 
264 static void executeCommand (std::string command, std::string &output){
265  FILE *fp;
266  int i = 0;
267  int maxResult = 1024;
268  char result[maxResult] = {'\0'};
269  fp = popen(command.c_str(), "r");
270  if (fp == NULL) {
271  printf("\n%s:%d Failed to run command: %s\n", __FUNCTION__, __LINE__, command.c_str());
272  return;
273  }
274 
275  i = 0;
276  /* Read the output a line at a time - output it. */
277  while (fgets(result, sizeof(result), fp) != NULL) {
278  if (i++ > maxResult) {
279  break;
280  }
281  }
282  if (maxResult <=i){
283  printf("\n%s:%d command %s . running in endless loop\n", __FUNCTION__, __LINE__, command.c_str());
284  }
285 
286  output = result;
287  /* close */
288  pclose(fp);
289  return;
290 
291 }
292 
293 static bool selectPk12KeyAndPass (std::string dynKeyFilePath, std::string staticKeyFilePath,
294  std::string &outputKeyFilePath, std::string &pass)
295 {
296  bool eRet = true;
297  if (!(access(dynKeyFilePath.c_str(), F_OK) == 0)) {
298  //dynamic pk12 certificate not exists
299  printf("\n%s:%d dynamic pk12 certificate:%s not exists. Pass key wont be generated\n", __FUNCTION__, __LINE__, dynKeyFilePath.c_str());
300  eRet = false;
301  } else {
302  if (!(access(DYNAMIC_PASSCODE_UTILITY, F_OK) == 0)) {
303  //dynamic pk12 pass key generator exists
304  printf("\n%s:%d dynamic pk12 pass key generator not exists\n", __FUNCTION__, __LINE__);
305  eRet = false;
306  }
307 
308  pass="";
309  if (true == eRet) {
310  std::string command = DYNAMIC_PASSCODE_UTILITY;
311  command.append (" ");
312  command.append (DYNAMIC_PASSCODE_ARG);
313  executeCommand (command, pass);
314  //Remove new line if present in the password
315  pass.erase(std::remove(pass.begin(), pass.end(), '\n'), pass.end());
316  }
317 
318  outputKeyFilePath = "";
319  if (!pass.empty()) {
320  outputKeyFilePath = dynKeyFilePath;
321  printf("\n%s:%d using dynamic pk12 certificate\n", __FUNCTION__, __LINE__);
322  eRet = true;
323  return eRet;
324  } else {
325  printf("\n%s:%d dynamic pk12 pass key null\n", __FUNCTION__, __LINE__);
326  }
327  }
328  printf("\n%s:%d dynamic pk12 certificate check failed\n", __FUNCTION__, __LINE__);
329 
330  outputKeyFilePath = ""; pass="";
331  //Not able to setup dynamic key set static key
332  if (!(access(staticKeyFilePath.c_str(), F_OK) == 0)) {
333  //static pk12 certificate not exists
334  printf("\n%s:%d static pk12 certificate:%s not exists\n", __FUNCTION__, __LINE__, staticKeyFilePath.c_str());
335  eRet = false;
336  return eRet;
337  }
338  if (!(access(STATIC_PASSCODE_UTILITY, F_OK) == 0)) {
339  //static pk12 pass key generator exists
340  printf("\n%s:%d static pk12 pass key generator not exists\n", __FUNCTION__, __LINE__);
341  eRet = false;
342  return eRet;
343  }
344 
345  pass="";
346  std::string command = STATIC_PASSCODE_UTILITY;
347  command.append (" ");
348  command.append (STATIC_PASSCODE_ARG_FILE);
349  executeCommand (command, pass);
350  if (!(access(STATIC_PASSCODE_ARG_FILE, F_OK) == 0)) {
351  printf("\n%s:%d static config file generation failed\n", __FUNCTION__, __LINE__);
352  eRet = false;
353  return eRet;
354  }
355 
356  pass="";
357  command = "cat ";
358  command.append (STATIC_PASSCODE_ARG_FILE);
359  executeCommand (command, pass);
360  //Remove new line if present in the password
361  pass.erase(std::remove(pass.begin(), pass.end(), '\n'), pass.end());
362 
363  outputKeyFilePath = "";
364  if (!pass.empty()) {
365  outputKeyFilePath = staticKeyFilePath;
366  printf("\n%s:%d using static pk12 certificate\n", __FUNCTION__, __LINE__);
367  eRet = true;
368  return eRet;
369  } else {
370  printf("\n%s:%d static pk12 pass key null\n", __FUNCTION__, __LINE__);
371  }
372 
373  printf("\n%s:%d dynamic and static pk12 certificate check failed\n", __FUNCTION__, __LINE__);
374  //Not expecting to reach here
375  return false;
376 }
377 
378 WebSocketProxy::WebSocketProxy(const QStringList &boundIPs, quint16 port, QObject *parent) :
379  QObject(parent), proxyServers(), connections()
380 {
381 #ifdef TRM_USE_SSL
382  if(rfc_get_trmssl_status() == true)
383  {
384  //Reading TRM configuration file
385  QSettings trmSetting( trmPropertiesPath, QSettings::IniFormat );
386  QString caChainFile = trmSetting.value( caKeyTagName ).toString();
387  QString keyFileName = trmSetting.value( privateKeyTagName ).toString();
388  QString certFileName = trmSetting.value( publicKeyTagName ).toString();
389  QString xpkiDynFilePath = trmSetting.value( xpkiDynamicCertificate ).toString();
390  QString xpkiStaticFilePath = trmSetting.value( xpkiStaticCertificate ).toString();
391 
392  if(caChainFile.isNull() || keyFileName.isNull() || certFileName.isNull())
393 
394  {
395  std::cout << "Missing TRM configuration information";
396  }
397  else
398  {
399  QStringList::const_iterator it = boundIPs.constBegin();
400  while (it != boundIPs.constEnd())
401  {
402  if (proxyServers.constFind(*it) == proxyServers.constEnd())
403  {
404 
405  if(is_TRM_RFC_param_enable(RFC_PARM_qtPort)) {
406  //If xPKI RFC enabled use xPKI certificates.
407  std::cout <<"QT secure port enabled"<<std::endl;
408 
409  QFile certFile(certFileName);
410  QFile keyFile(keyFileName);
411  if(!keyFile.exists())
412  {
413  std::cout << "Server private key not exist. Don't start the server ";
414  break;
415  }
416  certFile.open(QIODevice::ReadOnly);
417  keyFile.open(QIODevice::ReadOnly);
418  QSslCertificate certificate(&certFile, QSsl::Pem);
419  QSslKey sslKey(&keyFile, QSsl::Rsa, QSsl::Pem,QSsl::PrivateKey,QByteArray(""));
420  certFile.close();
421  keyFile.close();
422  QSslConfiguration sslConfiguration;
423 
424  if (true == is_TRM_RFC_param_enable(RFC_PARM_mTLS))
425  {
426  std::cout << "QSslSocket peerVerifyMode is QSslSocket::VerifyPeer. " << std::endl;
427  sslConfiguration.setPeerVerifyMode(QSslSocket::VerifyPeer);
428  }
429  else
430  {
431  std::cout << "QSslSocket peerVerifyMode is QSslSocket::QueryPeer. " << std::endl;
432  sslConfiguration.setPeerVerifyMode(QSslSocket::QueryPeer);
433  }
434 
435  sslConfiguration.setLocalCertificate(certificate);
436  sslConfiguration.setPrivateKey(sslKey);
437  sslConfiguration.setProtocol(QSsl::TlsV1_2);
438  sslConfiguration.setPeerVerifyDepth(2);
439 
440  QList<QSslCertificate> caCerts = QSslCertificate::fromPath(caChainFile);
441 
442  sslConfiguration.setCaCertificates(caCerts);
443  QWebSocketServer *proxyServer = new QWebSocketServer(QString("TRM SecureMode WebsocketServer IP: ") + *it , QWebSocketServer::SecureMode, this);
444 
445  proxyServer->setSslConfiguration(sslConfiguration);
446 
447  std::cout << "TRM WebsocketProxy starting server on ip: " <<(*it).toUtf8().data()
448  <<" SecureMode: "<<proxyServer->secureMode()<< std::endl;
449  if (proxyServer->listen(QHostAddress(*it), port))
450  {
451  connect(proxyServer, SIGNAL(newConnection()), this,
452  SLOT(onNewConnection()));
453  connect(proxyServer,&QWebSocketServer::sslErrors ,this,
454  &WebSocketProxy::onSslErrors);
455  connect(proxyServer, &QWebSocketServer::acceptError, this,
456  &WebSocketProxy::onAcceptError);
457  connect(proxyServer, &QWebSocketServer::peerVerifyError, this,
458  &WebSocketProxy::onPeerVerifyError);
459  proxyServers[*it] = proxyServer;
460  }
461  else
462  {
463  std::cout << "TRM WebsocketProxy Failed to listen" << std::endl;
464  }
465  }
466 
467  std::string pk12keyFilePath = "";
468  std::string pk12pass = "";
469  bool isPk12CertAvailable = selectPk12KeyAndPass (xpkiDynFilePath.toStdString(), xpkiStaticFilePath.toStdString(), pk12keyFilePath, pk12pass);
470  if (isPk12CertAvailable) {
471  std::cout << "Opening tcpOpensslProxyServer with ip"<<(*it).toStdString().c_str() << std::endl;
472  tcpOpensslProxyServer *sslProxyServer = new tcpOpensslProxyServer();
473  sslProxyServer->onMessageReceivedCallBack = onWebsocketMessageReceivedSSL;
474  sslProxyServer->onPongCallBack = onPongSSL;
475 
476  //Need to specify ip also here. Use port 9990 here using port old secure port 9988
477  //Will have connection issue with old client boxes since QT auth is not compatible.
478  int ret = sslProxyServer->setUpServer(
479  (*it).toStdString().c_str(), 9990,
480  caChainFile.toStdString().c_str(),
481  pk12keyFilePath.c_str(),
482  pk12pass.c_str());
483  if (0==ret){
484  connect(sslProxyServer, SIGNAL(newConnection (int, tcpOpensslProxyServer*)), this,
485  SLOT(onNewConnectionSSl(int, tcpOpensslProxyServer*)));
486  connect(sslProxyServer,SIGNAL(sslErrors (QString)) ,this,
487  SLOT(onSslErrorsSSL(QString)));
488  connect(sslProxyServer, SIGNAL(acceptError (QString)), this,
489  SLOT(onAcceptErrorSSL(QString)));
490  connect(sslProxyServer, SIGNAL(peerVerifyError (QString)), this,
491  SLOT(onPeerVerifyErrorSSL(QString)));
492 
493  connect(sslProxyServer, SIGNAL(connected (int, QString)), this,
494  SLOT(onWebsocketConnectSSL(int, QString)));
495  connect(sslProxyServer, SIGNAL(disconnected (int)), this,
496  SLOT(onWebsocketDisconnectedSSL(int)));
497  connect(sslProxyServer, SIGNAL(socketError (QString)), this,
498  SLOT(onWebsocketErrorSSL(QString)));
499  sslProxyServers[*it] = sslProxyServer;
500  } else {
501  std::cout << "TRM WebsocketProxy Failed to listen" << std::endl;
502  }
503  } else {
504  std::cout << "TRM WebsocketProxy pk12 certificates depenedncies not available" << std::endl;
505  }
506  }
507  else
508  {
509  __TIMESTAMP();
510  std::cout << "TRM WebsocketProxy already listen on "
511  << (*it).toUtf8().data() << ":" << port << std::endl;
512  }
513 
514  ++it;
515  }
516  delete_file (keyFileName);
517  }
518  }
519 #endif
520  ///non secure connection on port 9988
521  port--;
522 
523  // Temp Code added to support non secure TRM connection. This should be removed once all XI device updated
524  // with secure connection capability.
525  QStringList::const_iterator itr = boundIPs.constBegin();
526  while (itr != boundIPs.constEnd()) {
527  QWebSocketServer *proxyServer = new QWebSocketServer(
528  QString("TRM NonSecureMode WebsocketServer IP: ") + *itr,
529  QWebSocketServer::NonSecureMode, this);
530  std::cout << "TRM WebsocketProxy starting server on ip: " <<(*itr).toUtf8().data()
531  <<" SecureMode: "<<proxyServer->secureMode()<< std::endl;
532  if (proxyServer->listen(QHostAddress(*itr), port)) {
533  connect(proxyServer, SIGNAL(newConnection()), this,
534  SLOT(onNewConnection()));
535  proxyServers[*itr] = proxyServer;
536  }
537  else
538  {
539  std::cout << "TRM WebsocketProxy Failed to listen" << std::endl;
540  }
541 
542  ++itr;
543  }
544 
545  m_proxy = this;
546 }
547 
548 #ifdef TRM_USE_SSL
549 void WebSocketProxy::onSslErrorsSSL(QString err){
550  std::cout << "onSslErrorsSSL:" << err.toStdString()<<endl;
551 }
552 void WebSocketProxy::onAcceptErrorSSL(QString err) {
553  std::cout<<"onAcceptErrorSSL occured:"<<err.toStdString()<<endl;
554 }
555 void WebSocketProxy::onPeerVerifyErrorSSL(QString err) {
556  std::cout<<"onPeerVerifyErrorSSL :"<<err.toStdString()<<endl;
557 }
558 
559 void WebSocketProxy::onWebsocketConnectSSL(int clientId, QString msg)
560 {
561  __TIMESTAMP();
562  std::cout << "TRM WebsocketProxy onWebsocketConnectSSL" << std::endl;
563  if (sslProxyPingPongTasks.find(clientId) != sslProxyPingPongTasks.end()){
564  PingPongTask* pp = sslProxyPingPongTasks [clientId];
565  pp->start();
566  }
567 }
568 
569 static void onWebsocketMessageReceivedSSL(int clientId, char* message, size_t len)
570 {
571  __TIMESTAMP();
572  std::cout << "TRM WebsocketProxy onWebsocketMessageReceivedSSL msg:" << message << std::endl;
573  websocket_data_callback_with_clientId (clientId, 0, message, len);
574 }
575 
576 static void onPongSSL(int clientId, uint64_t ticks, QByteArray &qmsg)
577 {
578  __TIMESTAMP();
579  //std::cout << "TRM WebsocketProxy onPongSSL clientId:" << clientId << std::endl;
580  if (m_proxy->sslProxyPingPongTasks.find(clientId) != m_proxy->sslProxyPingPongTasks.end()){
581  //send to curresponding pingpong object
582  m_proxy->sslProxyPingPongTasks[clientId]->onPong (ticks, qmsg);
583  }
584 
585 }
586 
587 void WebSocketProxy::onWebsocketDisconnectedSSL(int clientId) {
588  __TIMESTAMP();
589  std::cout << "TRM WebsocketProxy onWebsocketDisconnectedSSL clientId:"<< clientId << std::endl;
590  if (sslProxyMap.find(clientId) != sslProxyMap.end()){
591  sslProxyMap.erase (clientId);
592  }
593  if (sslProxyPingPongTasks.find(clientId) != sslProxyPingPongTasks.end()){
594  //if existing client mapping present remove it;
595  PingPongTask* oldPp = sslProxyPingPongTasks [clientId];
596  sslProxyPingPongTasks.erase(clientId);
597  oldPp->stop();
598  oldPp->deleteLater();
599  }
600 }
601 
602 void WebSocketProxy::onWebsocketErrorSSL(QString err)
603 {
604  __TIMESTAMP();
605  std::cout << "TRM WebsocketProxy onWebsocketErrorSSL = " << err.toStdString()<<endl;
606 }
607 
608 
609 
610 void WebSocketProxy::onSslErrors(const QList<QSslError> &sslError)
611 {
612  qDebug() << "onSslErrors :" << sslError;
613 }
614 
615 void WebSocketProxy::onAcceptError(QAbstractSocket::SocketError socketError)
616 {
617  std::cout<<" onAcceptError occured:"<<socketError<<std::endl;
618 }
619 void WebSocketProxy::onPeerVerifyError(const QSslError &error)
620 {
621  qDebug() << "onPeerVerifyError :" << error;
622 }
623 #endif
624 
625 
626 void WebSocketProxy::onNewConnectionSSl(int clientId, tcpOpensslProxyServer *ss){
627  std::cout<<" WebSocketProxy::onNewConnectionSSl:"<<std::endl;
628  {
629 
630  static const char *has_livestream_client_flag_filename ="/tmp/mnt/diska3/persistent/.has_livestream_client";
631  struct stat st;
632 
633  int ret = ::lstat(has_livestream_client_flag_filename, &st);
634  }
635  sslProxyMap [clientId] = ss;
636  PingPongTask* ppTask = new PingPongTask(ss, clientId);
637  if (sslProxyPingPongTasks.find(clientId) != sslProxyPingPongTasks.end()){
638  //if existing client mapping present remove it;
639  PingPongTask* oldPP = sslProxyPingPongTasks [clientId];
640  sslProxyPingPongTasks.erase(clientId);
641  oldPP->stop();
642  oldPP->deleteLater();
643  }
644  sslProxyPingPongTasks [clientId] = ppTask;
645 }
646 
647 void WebSocketProxy::onNewConnection()
648 {
649 
650  {
651 
652  static const char *has_livestream_client_flag_filename ="/tmp/mnt/diska3/persistent/.has_livestream_client";
653  struct stat st;
654 
655  int ret = ::lstat(has_livestream_client_flag_filename, &st);
656 #define USE_DELIA_GATEWAY
657 #ifndef USE_DELIA_GATEWAY
658  if (ret >= 0) {
659  /* Already has flag set */
660  }
661  else {
662  int fd = ::open(has_livestream_client_flag_filename, O_WRONLY|O_CREAT, 0666);
663  if (fd >= 0) {
664  /* Reboot */
665  __TIMESTAMP();
666  std::cout << "Rebooting STB on the initial xi3 connection \r\n" << std::endl;
667  close(fd);
668  ::sync();
669  ::system( "sh /rebootNow.sh -s websocketproxyinit" );
670  return;
671  }
672  }
673 #endif //USE_DELIA_GATEWAY
674 
675  }
676 
677  QWebSocketServer *proxyServer = qobject_cast<QWebSocketServer *>(sender());
678  __TIMESTAMP();
679  std::cout << "TRM WebsocketProxy connection from server " << (void *)proxyServer << " of name:" << proxyServer->serverName().toUtf8().data() << std::endl;
680 
681  QWebSocket *wssocket = proxyServer->nextPendingConnection();
682  websocket_connect_callback((void *)wssocket);
683  __TIMESTAMP();
684  std::cout << "TRM WebsocketProxy peerAddress: " << qPrintable(wssocket->peerAddress().toString()) << " Port: "<< wssocket->peerPort();
685  __TIMESTAMP();
686  std::cout << "TRM WebsocketProxy accept connection " << (void *)wssocket << std::endl;
687 
688  // The QtWebSocket version we use doesn't support connected() signal. Instead the
689  // newConnection() signal already indicates the completion of ws handshake
690  websocket_ready_callback((void *)wssocket);
691  connections << wssocket;
692  pingPongTasks.insert(wssocket, new PingPongTask(wssocket));
693 
694  /* Connect() signaled when socket is connected and the handshake was successful */
695  connect(wssocket, SIGNAL(connected()), this, SLOT(onWebsocketConnect()));
696  /* binaryMessageReceived() when there is raw payload on websocket */
697  connect(wssocket, SIGNAL(binaryMessageReceived(QByteArray)), this, SLOT(onWebsocketBinaryMessageReceived(QByteArray)));
698  connect(wssocket, SIGNAL(textMessageReceived(QString)), this, SLOT(onWebsocketTextMessageReceived(QString)));
699  /* write callback */
700  /*5.x*///connect(wssocket, SIGNAL(bytesWritten(qint64)), this, SLOT(onWebsocketBytesWritten(qint64)));
701  /* disconnected() when the socket is disconnected. */
702  connect(wssocket, SIGNAL(disconnected()), this, SLOT(onWebsocketDisconnected()));
703  connect(wssocket, SIGNAL(error(QAbstractSocket::SocketError)), this, SLOT(onWebsocketError(QAbstractSocket::SocketError)));
704 
705 #if 1
706  connect(wssocket, SIGNAL(stateChanged(QAbstractSocket::SocketState)), this, SLOT(onWebsocketStateChanged(QAbstractSocket::SocketState)));
707 #else
708  connect(wssocket, SIGNAL(aboutToClose()), this, SLOT(onWebSocketAboutClose()));
709 #endif
710  ((pingPongTasks.find(wssocket)).value())->start();
711 
712 }
713 
714 void WebSocketProxy::onWebsocketConnect(void)
715 {
716  __TIMESTAMP();
717  std::cout << "TRM WebsocketProxy onWebsocketConnect" << std::endl;
718 }
719 
720 void WebSocketProxy::onWebsocketBinaryMessageReceived(QByteArray byteArray)
721 {
722  __TIMESTAMP();
723  std::cout << "TRM WebsocketProxy onWebsocketBinaryMessageReceived" << std::endl;
724  QWebSocket *wssocket = qobject_cast<QWebSocket *>(sender());
725  websocket_data_callback((void *)wssocket, 0, byteArray.data(), byteArray.size());
726 }
727 
728 void WebSocketProxy::onWebsocketTextMessageReceived(QString message)
729 {
730  __TIMESTAMP();
731  std::cout << "TRM WebsocketProxy onWebsocketTextMessageReceived" << std::endl;
732  QWebSocket *wssocket = qobject_cast<QWebSocket *>(sender());
733  websocket_data_callback((void *)wssocket, 0, message.toUtf8().data(), message.size());
734 }
735 
736 void WebSocketProxy::onWebsocketBytesWritten(qint64)
737 {
738 }
739 
740 void WebSocketProxy::onWebsocketDisconnected(void)
741 {
742  QWebSocket *wssocket = qobject_cast<QWebSocket *>(sender());
743  __TIMESTAMP();
744  std::cout << "TRM WebsocketProxy onWebsocketDisconnected " << (void *)wssocket << std::endl;
745  if (wssocket && connections.contains(wssocket)) {
746  //wssocket->close();
747  wssocket->deleteLater();
748 
749  connections.removeAll(wssocket);
750  websocket_disconnect_callback((void *)wssocket);
751  /* Delete pingpong before deleting socket */
752  ((pingPongTasks.find(wssocket)).value())->stop();
753  ((pingPongTasks.find(wssocket)).value())->deleteLater();
754  pingPongTasks.remove(wssocket);
755  }
756 }
757 
758 void WebSocketProxy::onWebsocketStateChanged(QAbstractSocket::SocketState state)
759 {
760  static const char *states_name[] = {
761  "UnconnectedState",
762  "HostLookupState",
763  "ConnectingState",
764  "ConnectedState",
765  "BoundState",
766  "ListeningState",
767  "ClosingState",
768  };
769  QWebSocket *wssocket = qobject_cast<QWebSocket *>(sender());
770  __TIMESTAMP();
771  std::cout << "TRM WebsocketProxy onWebsocketStateChanged " << (void *)wssocket << " New State =" << states_name[state] << std::endl;
772 }
773 
774 void WebSocketProxy::onWebSocketAboutClose(void)
775 {
776 }
777 
778 void WebSocketProxy::onWebsocketError(QAbstractSocket::SocketError error)
779 {
780  __TIMESTAMP();
781  std::cout << "TRM WebsocketProxy onWebsocketError = " << error << std::endl;
782  QWebSocket *wssocket = qobject_cast<QWebSocket *>(sender());
783  if (wssocket) {
784  // cannot do socket close here. do so after disconnect
785  // wssocket->close();
786  }
787 }
788 
789 int WebSocketProxy::onWebsocketHasDataToWriteSSL(int clientId, char* data, int len)
790 {
791  if (sslProxyMap.find(clientId) != sslProxyMap.end()){
792  tcpOpensslProxyServer *ss = sslProxyMap[clientId];
793  printf ("WebSocketProxy::%s:%d data: masked len:%d\n", __FUNCTION__, __LINE__, len);
794  ss->sendTextMessage (clientId, data, len);
795  return len;
796  } else {
797  return 0;
798  }
799 }
800 
801 void WebSocketProxy::onWebsocketHasDataToWrite(void *conn, void *data)
802 {
803  /* This is thread safe as the caller of mg_websocket_write() already ensure
804  * that the connection is still valid.
805  */
806 
807  QWebSocket *wssocket = (QWebSocket *)conn;
808  QByteArray *byteArray= (QByteArray *)data;
809  if (connections.contains(wssocket)) {
810  wssocket->sendTextMessage(QString(byteArray->constData()));
811  }
812  delete byteArray;
813 
814 }
815 
816 void WebSocketProxy::onRemoveConnection(void *conn)
817 {
818  /* This is thread safe as the caller of mg_websocket_write() already ensure
819  * that the connection is still valid.
820  */
821  __TIMESTAMP();
822  std::cout << "onRemoveConnection" << std::endl;
823 
824  QWebSocket *wssocket = (QWebSocket *)conn;
825  if (connections.contains(wssocket)) {
826  emit wssocket->close();
827  }
828 }
829 
830 void WebSocketProxy::onRemoveAllOpenSslConnections() {
831  QMap<QString, tcpOpensslProxyServer *>::iterator iter;
832  for (iter = sslProxyServers.begin(); iter != sslProxyServers.end(); ++iter) {
833  tcpOpensslProxyServer * sslProxyServer = iter.value();
834  sslProxyServer->closeAllClients();
835  }
836 }
837 
838 int mg_websocket_write_ssl(int clientId, char *data, int data_len)
839 {
840  int ret = 0;
841  printf ("%s:%d data masked data_len:%d\n", __FUNCTION__, __LINE__, data_len);
842  if (NULL != m_proxy) {
843  ret = m_proxy->onWebsocketHasDataToWriteSSL (clientId, data, data_len);
844  }
845  return ret;
846 }
847 
848 int mg_websocket_write(void * conn, const char *data, size_t data_len)
849 {
850  QWebSocket *wssocket = (QWebSocket *)(conn);
851  //Want to NULL terminate the message
852  QByteArray *byteArray = new QByteArray(data, data_len);
853  byteArray->append('\0');
854  QMetaObject::invokeMethod(m_proxy, "onWebsocketHasDataToWrite", Qt::QueuedConnection, Q_ARG(void *, wssocket), Q_ARG(void *, byteArray));
855 
856  return data_len;
857 }
858 
859 int mg_websocket_close_all_ssl()
860 {
861  printf ("%s:%d \n", __FUNCTION__, __LINE__);
862  if (NULL != m_proxy) {
863  m_proxy->onRemoveAllOpenSslConnections();
864  }
865  return 0;
866 }
867 
868 int mg_websocket_close(void * conn)
869 {
870  __TIMESTAMP();
871  std::cout << "mg_websocket_close" << std::endl;
872  __TIMESTAMP();
873  printf("[%s] THREAD SELF is %p\r\n", __FUNCTION__, (void *)pthread_self());
874 
875  QWebSocket *wssocket = (QWebSocket *)(conn);
876  //Want to NULL terminate the message
877  QMetaObject::invokeMethod(m_proxy, "onRemoveConnection", Qt::QueuedConnection, Q_ARG(void *, wssocket));
878 
879  return 0;
880 }
881 
882 
883 /** @} */
884 /** @} */
tcpOpensslProxyServer
Definition: tcpOpensslProxyServer.h:15
PingPongTask
Definition: qt_websocketproxy.h:103
WebSocketProxy
Definition: qt_websocketproxy.h:56