• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 2023 Huawei Device Co., Ltd.
3  * Licensed under the Apache License, Version 2.0 (the "License");
4  * you may not use this file except in compliance with the License.
5  * You may obtain a copy of the License at
6  *
7  *     http://www.apache.org/licenses/LICENSE-2.0
8  *
9  * Unless required by applicable law or agreed to in writing, software
10  * distributed under the License is distributed on an "AS IS" BASIS,
11  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12  * See the License for the specific language governing permissions and
13  * limitations under the License.
14  */
15 
16 #include <thread>
17 #include "CommandLineInterface.h"
18 #include "PreviewerEngineLog.h"
19 #include "WebSocketServer.h"
20 using namespace std;
21 
22 lws* WebSocketServer::webSocket = nullptr;
23 volatile sig_atomic_t WebSocketServer::interrupted = 0;
24 WebSocketServer::WebSocketState WebSocketServer::webSocketWritable = WebSocketState::INIT;
25 uint8_t* WebSocketServer::firstImageBuffer = nullptr;
26 uint64_t WebSocketServer::firstImagebufferSize = 0;
27 int8_t* WebSocketServer::receivedMessage = nullptr;
28 
WebSocketServer()29 WebSocketServer::WebSocketServer() : serverThread(nullptr), serverPort(0)
30 {
31     protocols[0] = {"ws", WebSocketServer::ProtocolCallback, 0, MAX_PAYLOAD_SIZE};
32     protocols[1] = {NULL, NULL, 0, 0};
33 }
34 
~WebSocketServer()35 WebSocketServer::~WebSocketServer() {}
36 
GetInstance()37 WebSocketServer& WebSocketServer::GetInstance()
38 {
39     static WebSocketServer server;
40     return server;
41 }
42 
SetServerPort(int port)43 void WebSocketServer::SetServerPort(int port)
44 {
45     serverPort = port;
46 }
47 
SetSid(const std::string curSid)48 void WebSocketServer::SetSid(const std::string curSid)
49 {
50     sid = curSid;
51 }
52 
CheckSid(struct lws * wsi)53 bool WebSocketServer::CheckSid(struct lws* wsi)
54 {
55     if (WebSocketServer::GetInstance().sid.empty()) {
56         return true;
57     }
58     std::string uri(WebSocketServer::sidMaxLength, '\0');
59     int uriLength = lws_hdr_copy(wsi, &uri[0], uri.size(), WSI_TOKEN_GET_URI);
60     if (uriLength <= 0) {
61         return false;
62     }
63     uri.resize(uriLength);
64     if (uri.empty()) {
65         return false;
66     }
67     const std::string::size_type start = uri.find_last_of('/');
68     if (start == std::string::npos) {
69         return false;
70     }
71     std::string curSid = uri.substr(start + 1); // add 1 to next index
72     if (curSid == WebSocketServer::GetInstance().sid) {
73         ILOG("Websocket path validation passed.");
74         return true;
75     } else {
76         ELOG("Websocket path validation failed.");
77         return false;
78     }
79 }
80 
ProtocolCallback(struct lws * wsi,enum lws_callback_reasons reason,void * user,void * in,size_t len)81 int WebSocketServer::ProtocolCallback(struct lws* wsi, enum lws_callback_reasons reason,
82     void* user, void* in, size_t len)
83 {
84     switch (reason) {
85         case LWS_CALLBACK_FILTER_PROTOCOL_CONNECTION:
86             if (!CheckSid(wsi)) {
87                 return 1; // 1 is connection denied
88             }
89             break;
90         case LWS_CALLBACK_PROTOCOL_INIT:
91             ILOG("Engine Websocket protocol init");
92             break;
93         case LWS_CALLBACK_ESTABLISHED:
94             ILOG("Websocket client connect");
95             webSocket = wsi;
96             lws_callback_on_writable(wsi);
97             break;
98         case LWS_CALLBACK_RECEIVE:
99             break;
100         case LWS_CALLBACK_SERVER_WRITEABLE:
101             ILOG("Engine websocket server writeable");
102             if (firstImagebufferSize > 0 && webSocketWritable == WebSocketState::UNWRITEABLE) {
103                 ILOG("Send last image after websocket reconnected");
104                 std::lock_guard<std::mutex> guard(WebSocketServer::GetInstance().mutex);
105                 lws_write(wsi,
106                           firstImageBuffer + LWS_PRE,
107                           firstImagebufferSize,
108                           LWS_WRITE_BINARY);
109             }
110             webSocketWritable = WebSocketState::WRITEABLE;
111             break;
112         case LWS_CALLBACK_CLOSED:
113             ILOG("Websocket client connection closed");
114             webSocketWritable = WebSocketState::UNWRITEABLE;
115             break;
116         default:
117             break;
118     }
119     return 0;
120 }
121 
SignalHandler(int sig)122 void WebSocketServer::SignalHandler(int sig)
123 {
124     interrupted = 1;
125 }
126 
StartWebsocketListening()127 void WebSocketServer::StartWebsocketListening()
128 {
129     const auto sig = signal(SIGINT, SignalHandler);
130     if (sig == SIG_ERR) {
131         ELOG("StartWebsocketListening failed");
132         return;
133     }
134     ILOG("Begin to start websocket listening!");
135     struct lws_context_creation_info contextInfo = {0};
136     contextInfo.port = serverPort;
137     contextInfo.iface = serverHostname;
138     contextInfo.protocols = protocols;
139     contextInfo.ip_limit_wsi = websocketMaxConn;
140     contextInfo.options  = LWS_SERVER_OPTION_VALIDATE_UTF8;
141     struct lws_context* context = lws_create_context(&contextInfo);
142     if (context == nullptr) {
143         ELOG("WebSocketServer::StartWebsocketListening context memory allocation failed");
144         return;
145     }
146     while (interrupted == 0) {
147         if (lws_service(context, WEBSOCKET_SERVER_TIMEOUT)) {
148             interrupted = 1;
149         }
150     }
151     lws_context_destroy(context);
152 }
153 
Run()154 void WebSocketServer::Run()
155 {
156     serverThread = std::make_unique<std::thread>([this]() {
157         this->StartWebsocketListening();
158     });
159     if (serverThread == nullptr) {
160         ELOG("WebSocketServer::Start serverThread memory allocation failed");
161     }
162     serverThread->detach();
163 }
164 
WriteData(unsigned char * data,size_t length)165 size_t WebSocketServer::WriteData(unsigned char* data, size_t length)
166 {
167     while (webSocketWritable != WebSocketState::WRITEABLE) {
168         this_thread::sleep_for(chrono::milliseconds(1));
169     }
170     if (webSocket != nullptr && webSocketWritable == WebSocketState::WRITEABLE) {
171         return lws_write(webSocket, data, length, LWS_WRITE_BINARY);
172     }
173     return 0;
174 }
175