• 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 <atomic>
17 #include <thread>
18 #include "CommandLineInterface.h"
19 #include "PreviewerEngineLog.h"
20 #include "WebSocketServer.h"
21 
22 lws* WebSocketServer::webSocket = nullptr;
23 std::atomic<bool> WebSocketServer::interrupted = false;
24 WebSocketServer::WebSocketState WebSocketServer::webSocketWritable = WebSocketState::INIT;
25 uint8_t* WebSocketServer::firstImageBuffer = nullptr;
26 uint64_t WebSocketServer::firstImagebufferSize = 0;
27 
WebSocketServer()28 WebSocketServer::WebSocketServer() : serverThread(nullptr), serverPort(0)
29 {
30     protocols[0] = {"ws", WebSocketServer::ProtocolCallback, 0, MAX_PAYLOAD_SIZE};
31     protocols[1] = {NULL, NULL, 0, 0};
32 }
33 
~WebSocketServer()34 WebSocketServer::~WebSocketServer() {}
35 
GetInstance()36 WebSocketServer& WebSocketServer::GetInstance()
37 {
38     static WebSocketServer server;
39     return server;
40 }
41 
SetServerPort(int port)42 void WebSocketServer::SetServerPort(int port)
43 {
44     serverPort = port;
45 }
46 
SetSid(const std::string curSid)47 void WebSocketServer::SetSid(const std::string curSid)
48 {
49     sid = curSid;
50 }
51 
CheckSid(struct lws * wsi)52 bool WebSocketServer::CheckSid(struct lws* wsi)
53 {
54     if (WebSocketServer::GetInstance().sid.empty()) {
55         return true;
56     }
57     std::string uri(WebSocketServer::sidMaxLength, '\0');
58     int uriLength = lws_hdr_copy(wsi, &uri[0], uri.size(), WSI_TOKEN_GET_URI);
59     if (uriLength <= 0) {
60         return false;
61     }
62     uri.resize(uriLength);
63     if (uri.empty()) {
64         return false;
65     }
66     const std::string::size_type start = uri.find_last_of('/');
67     if (start == std::string::npos) {
68         return false;
69     }
70     std::string curSid = uri.substr(start + 1); // add 1 to next index
71     if (curSid == WebSocketServer::GetInstance().sid) {
72         ILOG("Websocket path validation passed.");
73         return true;
74     } else {
75         ELOG("Websocket path validation failed.");
76         return false;
77     }
78 }
79 
ProtocolCallback(struct lws * wsi,enum lws_callback_reasons reason,void * user,void * in,size_t len)80 int WebSocketServer::ProtocolCallback(struct lws* wsi, enum lws_callback_reasons reason,
81     void* user, void* in, size_t len)
82 {
83     switch (reason) {
84         case LWS_CALLBACK_FILTER_PROTOCOL_CONNECTION:
85             if (!CheckSid(wsi)) {
86                 return 1; // 1 is connection denied
87             }
88             break;
89         case LWS_CALLBACK_PROTOCOL_INIT:
90             ILOG("Engine Websocket protocol init");
91             break;
92         case LWS_CALLBACK_ESTABLISHED:
93             ILOG("Websocket client connect");
94             webSocket = wsi;
95             lws_callback_on_writable(wsi);
96             break;
97         case LWS_CALLBACK_RECEIVE:
98             break;
99         case LWS_CALLBACK_SERVER_WRITEABLE:
100             ILOG("Engine websocket server writeable");
101             if (firstImagebufferSize > 0 && webSocketWritable == WebSocketState::UNWRITEABLE) {
102                 ILOG("Send last image after websocket reconnected");
103                 std::lock_guard<std::mutex> guard(WebSocketServer::GetInstance().mutex);
104                 lws_write(wsi,
105                           firstImageBuffer + LWS_PRE,
106                           firstImagebufferSize,
107                           LWS_WRITE_BINARY);
108             }
109             webSocketWritable = WebSocketState::WRITEABLE;
110             break;
111         case LWS_CALLBACK_CLOSED:
112             ILOG("Websocket client connection closed");
113             webSocketWritable = WebSocketState::UNWRITEABLE;
114             break;
115         default:
116             break;
117     }
118     return 0;
119 }
120 
SignalHandler(int sig)121 void WebSocketServer::SignalHandler(int sig)
122 {
123     interrupted = true;
124 }
125 
StartWebsocketListening()126 void WebSocketServer::StartWebsocketListening()
127 {
128     const auto sig = signal(SIGINT, SignalHandler);
129     if (sig == SIG_ERR) {
130         ELOG("StartWebsocketListening failed");
131         return;
132     }
133     ILOG("Begin to start websocket listening!");
134     struct lws_context_creation_info contextInfo = {0};
135     contextInfo.port = serverPort;
136     contextInfo.iface = serverHostname;
137     contextInfo.protocols = protocols;
138     contextInfo.ip_limit_wsi = websocketMaxConn;
139     contextInfo.options  = LWS_SERVER_OPTION_VALIDATE_UTF8;
140     struct lws_context* context = lws_create_context(&contextInfo);
141     if (context == nullptr) {
142         ELOG("WebSocketServer::StartWebsocketListening context memory allocation failed");
143         return;
144     }
145     while (!interrupted) {
146         if (lws_service(context, WEBSOCKET_SERVER_TIMEOUT)) {
147             interrupted = true;
148         }
149     }
150     lws_context_destroy(context);
151 }
152 
Run()153 void WebSocketServer::Run()
154 {
155     serverThread = std::make_unique<std::thread>([this]() {
156         this->StartWebsocketListening();
157     });
158     if (serverThread == nullptr) {
159         ELOG("WebSocketServer::Start serverThread memory allocation failed");
160     }
161     serverThread->detach();
162 }
163 
WriteData(unsigned char * data,size_t length)164 size_t WebSocketServer::WriteData(unsigned char* data, size_t length)
165 {
166     while (webSocketWritable != WebSocketState::WRITEABLE) {
167         std::this_thread::sleep_for(std::chrono::milliseconds(1));
168     }
169     if (webSocket != nullptr && webSocketWritable == WebSocketState::WRITEABLE) {
170         return lws_write(webSocket, data, length, LWS_WRITE_BINARY);
171     }
172     return 0;
173 }
174