1 /*
2 * Copyright (c) 2022-2024 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 "websocket_server_exec.h"
17 #include <atomic>
18 #include <memory>
19 #include <queue>
20 #include <thread>
21 #include <unistd.h>
22 #include <sstream>
23 #include <algorithm>
24 #include <shared_mutex>
25 #include "constant.h"
26 #include "napi_utils.h"
27 #include "netstack_common_utils.h"
28 #include "netstack_log.h"
29 #include "securec.h"
30 #define LWS_PLUGIN_STATIC
31
32 static constexpr const char *EVENT_KEY_CLIENT_PORT = "clientPort";
33
34 static constexpr const char *EVENT_KEY_CLIENT_IP = "clientIP";
35
36 static constexpr const char *EVENT_KEY_CONNECTION = "clientConnection";
37
38 static constexpr const char *EVENT_KEY_DATA = "data";
39
40 static constexpr const char *EVENT_KEY_CODE = "code";
41
42 static constexpr const char *EVENT_KEY_REASON = "closeReason";
43
44 static constexpr const char *WEBSOCKET_SERVER_THREAD_RUN = "OS_NET_WSJsSer";
45
46 static constexpr const char *LINK_DOWN = "The link is down";
47
48 static constexpr const uint32_t MAX_CONCURRENT_CLIENTS_NUMBER = 10;
49
50 static constexpr const uint32_t MAX_CONNECTIONS_FOR_ONE_CLIENT = 10;
51
52 static constexpr const uint64_t ONE_MINUTE_IN_SEC = 60;
53
54 static constexpr const int32_t MAX_CONNECTIONS_PER_MINUTE = 50;
55
56 static constexpr const int32_t COMMON_ERROR_CODE = 200;
57
58 static constexpr const int32_t ARRAY_LEN_TWO = 2;
59
60 namespace OHOS::NetStack::Websocket {
61
62 static std::shared_mutex wsMutex_;
63
64 static std::shared_mutex connListMutex_;
65
66 static std::shared_mutex banListMutex_;
67
68 static std::unordered_map<std::string, uint64_t> banList;
69
70 static std::unordered_map<std::string, ClientInfo> clientList;
71
72 static std::unordered_map<std::string, std::pair<lws *,
73 OHOS::NetStack::Websocket::WebSocketConnection>> webSocketConnection_;
74
75 static const lws_protocols LWS_SERVER_PROTOCOLS[] = {
76 {"lws_server", WebSocketServerExec::lwsServerCallback, 0, 0},
77 {NULL, NULL, 0, 0}, // this line is needed
78 };
79
80 struct CloseResult {
81 uint32_t code;
82 std::string reason;
83 };
84
85 struct ClientConnectionCloseCallback {
86 WebSocketConnection connection;
87 CloseResult closeResult;
88 };
89
90 struct CallbackDispatcher {
91 lws_callback_reasons reason;
92 int (*callback)(lws *wsi, lws_callback_reasons reason, void *user, void *in, size_t len);
93 };
94
95 static const lws_http_mount mount = {
96 NULL,
97 "/",
98 "./mount-origin",
99 "index.html",
100 NULL,
101 NULL,
102 NULL,
103 NULL,
104 0,
105 0,
106 0,
107 0,
108 0,
109 0,
110 LWSMPRO_FILE,
111 1,
112 NULL,
113 };
114
CallbackTemplate(uv_work_t * work,int status)115 template <napi_value (*MakeJsValue)(napi_env, void *)> static void CallbackTemplate(uv_work_t *work, int status)
116 {
117 (void)status;
118
119 auto workWrapper = static_cast<UvWorkWrapperShared *>(work->data);
120 napi_env env = workWrapper->env;
121 auto closeScope = [env](napi_handle_scope scope) { NapiUtils::CloseScope(env, scope); };
122 std::unique_ptr<napi_handle_scope__, decltype(closeScope)> scope(NapiUtils::OpenScope(env), closeScope);
123
124 napi_value obj = MakeJsValue(env, workWrapper->data);
125 auto undefined = NapiUtils::GetUndefined(workWrapper->env);
126 std::pair<napi_value, napi_value> arg = {undefined, obj};
127 if (workWrapper->manager) {
128 workWrapper->manager->Emit(workWrapper->type, arg);
129 if (workWrapper->type == EventName::EVENT_MESSAGE &&
130 workWrapper->manager->HasEventListener(EventName::EVENT_DATA_END)) {
131 workWrapper->manager->Emit(EventName::EVENT_DATA_END, {undefined, undefined});
132 }
133 }
134 delete workWrapper;
135 delete work;
136 }
137
CallbackTemplateWithTwoPara(uv_work_t * work,int status)138 template <napi_value (*MakeJsValue)(napi_env, void *)> static void CallbackTemplateWithTwoPara(uv_work_t *work,
139 int status)
140 {
141 (void)status;
142
143 auto workWrapper = static_cast<UvWorkWrapperShared *>(work->data);
144 napi_env env = workWrapper->env;
145 auto closeScope = [env](napi_handle_scope scope) { NapiUtils::CloseScope(env, scope); };
146 std::unique_ptr<napi_handle_scope__, decltype(closeScope)> scope(NapiUtils::OpenScope(env), closeScope);
147
148 napi_value obj = MakeJsValue(env, workWrapper->data);
149 auto undefined = NapiUtils::GetUndefined(workWrapper->env);
150 if (NapiUtils::GetArrayLength(env, obj) != ARRAY_LEN_TWO) {
151 NETSTACK_LOGE("array length is not 2");
152 delete workWrapper;
153 delete work;
154 return;
155 }
156
157 napi_value firstValue = NapiUtils::GetArrayElement(env, obj, 0);
158 napi_value secValue = NapiUtils::GetArrayElement(env, obj, 1);
159 std::tuple<napi_value, napi_value, napi_value> arg = {undefined, firstValue, secValue};
160
161 if (workWrapper->manager) {
162 workWrapper->manager->EmitWithTwoPara(workWrapper->type, arg);
163 }
164 delete workWrapper;
165 delete work;
166 }
167
RunServerService(std::shared_ptr<UserData> userData,std::shared_ptr<EventManager> manager)168 void RunServerService(std::shared_ptr<UserData> userData, std::shared_ptr<EventManager> manager)
169 {
170 NETSTACK_LOGI("websocket run service start");
171 int res = 0;
172 lws_context *context = userData->GetContext();
173 if (context == nullptr) {
174 NETSTACK_LOGE("context is null");
175 return;
176 }
177 while (res >= 0 && !userData->IsThreadStop()) {
178 res = lws_service(context, 0);
179 }
180 NETSTACK_LOGE("lws_service stop");
181 lws_context_destroy(context);
182 userData->SetContext(nullptr);
183 manager->SetWebSocketUserData(nullptr);
184 NETSTACK_LOGI("websocket run service end");
185 }
186
RaiseServerError(EventManager * manager)187 int WebSocketServerExec::RaiseServerError(EventManager *manager)
188 {
189 OnServerError(manager, COMMON_ERROR_CODE);
190 return -1;
191 }
192
HttpDummy(lws * wsi,lws_callback_reasons reason,void * user,void * in,size_t len)193 int WebSocketServerExec::HttpDummy(lws *wsi, lws_callback_reasons reason, void *user, void *in, size_t len)
194 {
195 int ret = lws_callback_http_dummy(wsi, reason, user, in, len);
196 if (ret < 0) {
197 OnServerError(reinterpret_cast<EventManager *>(user), COMMON_ERROR_CODE);
198 }
199 return 0;
200 }
201
lwsServerCallback(lws * wsi,lws_callback_reasons reason,void * user,void * in,size_t len)202 int WebSocketServerExec::lwsServerCallback(lws *wsi, lws_callback_reasons reason, void *user, void *in, size_t len)
203 {
204 NETSTACK_LOGI("lws server callback reason is %{public}d", reason);
205 CallbackDispatcher dispatchers[] = {
206 {LWS_CALLBACK_ESTABLISHED, LwsCallbackEstablished},
207 {LWS_CALLBACK_FILTER_PROTOCOL_CONNECTION, LwsCallbackFilterProtocolConnection},
208 {LWS_CALLBACK_RECEIVE, LwsCallbackReceive},
209 {LWS_CALLBACK_SERVER_WRITEABLE, LwsCallbackServerWriteable},
210 {LWS_CALLBACK_WS_PEER_INITIATED_CLOSE, LwsCallbackWsPeerInitiatedCloseServer},
211 {LWS_CALLBACK_CLOSED, LwsCallbackClosed},
212 {LWS_CALLBACK_WSI_DESTROY, LwsCallbackWsiDestroyServer},
213 {LWS_CALLBACK_PROTOCOL_DESTROY, LwsCallbackProtocolDestroyServer},
214 };
215 for (const auto dispatcher : dispatchers) {
216 if (dispatcher.reason == reason) {
217 return dispatcher.callback(wsi, reason, user, in, len);
218 }
219 }
220 return HttpDummy(wsi, reason, user, in, len);
221 }
222
LwsCallbackEstablished(lws * wsi,lws_callback_reasons reason,void * user,void * in,size_t len)223 int WebSocketServerExec::LwsCallbackEstablished(lws *wsi, lws_callback_reasons reason, void *user, void *in,
224 size_t len)
225 {
226 NETSTACK_LOGD("lws callback server established");
227 lws_context *context = lws_get_context(wsi);
228 EventManager *manager = static_cast<EventManager *>(lws_context_user(context));
229 if (manager == nullptr) {
230 NETSTACK_LOGE("manager is null");
231 return RaiseServerError(manager);
232 }
233 auto userData = manager->GetWebSocketUserData();
234 if (userData == nullptr) {
235 NETSTACK_LOGE("user data is null");
236 return RaiseServerError(manager);
237 }
238 // bind clientuserdata with wsi
239 lws_context *lwsContext = lws_get_context(wsi);
240 auto clientUserData = std::make_shared<UserData>(lwsContext);
241 lws_set_wsi_user(wsi, clientUserData.get());
242 manager->AddClientUserData(wsi, clientUserData);
243
244 std::string clientId;
245 WebSocketConnection connection;
246 bool ret = GetPeerConnMsg(wsi, manager, clientId, connection);
247 if (!ret) {
248 NETSTACK_LOGE("GetPeerConnMsg failed");
249 return RaiseServerError(manager);
250 }
251 AddConnections(clientId, wsi, userData, connection);
252 clientUserData->SetLws(wsi);
253 clientUserData->TriggerWritable();
254 OnConnect(wsi, manager);
255 return HttpDummy(wsi, reason, user, in, len);
256 }
257
GetPeerConnMsg(lws * wsi,EventManager * manager,std::string & clientId,WebSocketConnection & conn)258 bool WebSocketServerExec::GetPeerConnMsg(lws *wsi, EventManager *manager, std::string &clientId,
259 WebSocketConnection &conn)
260 {
261 struct sockaddr_storage addr{};
262 socklen_t addrLen = sizeof(addr);
263 int ret = getpeername(lws_get_socket_fd(wsi), reinterpret_cast<sockaddr *>(&addr), &addrLen);
264 if (ret != 0) {
265 NETSTACK_LOGE("getpeername failed");
266 return false;
267 }
268 char ipStr[INET6_ADDRSTRLEN] = {0};
269 if (addr.ss_family == AF_INET) {
270 NETSTACK_LOGI("family is ipv4");
271 auto *addrIn = reinterpret_cast<struct sockaddr_in *>(&addr);
272 inet_ntop(AF_INET, &addrIn->sin_addr, ipStr, sizeof(ipStr));
273 uint16_t port = ntohs(addrIn->sin_port);
274 conn.clientPort = static_cast<uint32_t>(port);
275 conn.clientIP = ipStr;
276 clientId = std::string(ipStr) + ":" + std::to_string(port);
277 } else if (addr.ss_family == AF_INET6) {
278 NETSTACK_LOGI("family is ipv6");
279 auto *addrIn6 = reinterpret_cast<struct sockaddr_in6 *>(&addr);
280 inet_ntop(AF_INET6, &addrIn6->sin6_addr, ipStr, sizeof(ipStr));
281 uint16_t port = ntohs(addrIn6->sin6_port);
282 conn.clientPort = static_cast<uint32_t>(port);
283 conn.clientIP = ipStr;
284 clientId = std::string(ipStr) + ":" + std::to_string(port);
285 } else {
286 NETSTACK_LOGE("getpeer Ipv4 or Ipv6 failed");
287 return false;
288 }
289 return true;
290 }
291
IsOverMaxClientConns(EventManager * manager,const std::string ip)292 bool WebSocketServerExec::IsOverMaxClientConns(EventManager *manager, const std::string ip)
293 {
294 std::vector<WebSocketConnection> connections = GetConnections();
295 if (IsOverMaxConcurrentClientsCnt(manager, connections, ip)) {
296 NETSTACK_LOGI("current client connections is over max concurrent number");
297 return true;
298 }
299 if (IsOverMaxCntForOneClient(manager, connections, ip)) {
300 NETSTACK_LOGI("current connections for one client is over max number");
301 return true;
302 }
303 return false;
304 }
305
AddConnections(const std::string & id,lws * wsi,std::shared_ptr<UserData> & userData,WebSocketConnection & conn)306 void WebSocketServerExec::AddConnections(const std::string &id, lws *wsi,
307 std::shared_ptr<UserData> &userData, WebSocketConnection &conn)
308 {
309 if (userData->IsClosed() || userData->IsThreadStop()) {
310 NETSTACK_LOGE("AddConnections failed: session %s", userData->IsClosed() ? "closed" : "thread stopped");
311 return;
312 }
313 {
314 std::unique_lock<std::shared_mutex> lock(wsMutex_);
315 webSocketConnection_[id].first = wsi;
316 webSocketConnection_[id].second = conn;
317 NETSTACK_LOGI("AddConnections success");
318 }
319 }
320
IsOverMaxConcurrentClientsCnt(EventManager * manager,const std::vector<WebSocketConnection> connections,const std::string ip)321 bool WebSocketServerExec::IsOverMaxConcurrentClientsCnt(EventManager *manager,
322 const std::vector<WebSocketConnection> connections, const std::string ip)
323 {
324 std::unordered_set<std::string> uniqueIp;
325 for (const auto &conn : connections) {
326 uniqueIp.insert(conn.clientIP);
327 }
328 if (uniqueIp.find(ip) != uniqueIp.end()) {
329 return uniqueIp.size() > manager->GetMaxConcurrentClientCnt();
330 } else {
331 return (uniqueIp.size() + 1) > manager->GetMaxConcurrentClientCnt();
332 }
333 }
334
IsOverMaxCntForOneClient(EventManager * manager,const std::vector<WebSocketConnection> connections,const std::string ip)335 bool WebSocketServerExec::IsOverMaxCntForOneClient(EventManager *manager,
336 const std::vector<WebSocketConnection> connections, const std::string ip)
337 {
338 uint32_t cnt = 0;
339 for (auto it = connections.begin(); it != connections.end(); ++it) {
340 if (ip == it->clientIP) {
341 ++cnt;
342 }
343 }
344 if (cnt + 1 > manager->GetMaxConnForOneClient()) {
345 return true;
346 }
347 return false;
348 }
349
LwsCallbackClosed(lws * wsi,lws_callback_reasons reason,void * user,void * in,size_t len)350 int WebSocketServerExec::LwsCallbackClosed(lws *wsi, lws_callback_reasons reason, void *user, void *in, size_t len)
351 {
352 NETSTACK_LOGD("lws callback server closed");
353 if (wsi == nullptr) {
354 NETSTACK_LOGE("wsi is null");
355 return -1;
356 }
357 lws_context *context = lws_get_context(wsi);
358 EventManager *manager = static_cast<EventManager *>(lws_context_user(context));
359 if (manager == nullptr) {
360 NETSTACK_LOGE("manager is null");
361 return RaiseServerError(manager);
362 }
363 auto userData = manager->GetWebSocketUserData();
364 if (userData == nullptr) {
365 NETSTACK_LOGE("user data is null");
366 return RaiseServerError(manager);
367 }
368 auto clientUserData = reinterpret_cast<UserData *>(lws_wsi_user(wsi));
369 if (clientUserData == nullptr) {
370 NETSTACK_LOGE("clientUserData is null");
371 return RaiseServerError(manager);
372 }
373 clientUserData->SetThreadStop(true);
374 if ((clientUserData->closeReason).empty()) {
375 clientUserData->Close(clientUserData->closeStatus, LINK_DOWN);
376 }
377 if (clientUserData->closeStatus == LWS_CLOSE_STATUS_NOSTATUS) {
378 NETSTACK_LOGE("The link is down, onError");
379 OnServerError(manager, COMMON_ERROR_CODE);
380 }
381 std::string clientId;
382 {
383 std::shared_lock<std::shared_mutex> lock(wsMutex_);
384 for (auto it = webSocketConnection_.begin(); it != webSocketConnection_.end(); ++it) {
385 if (it->second.first == wsi) {
386 clientId = it->first;
387 }
388 }
389 }
390 OnServerClose(wsi, manager, clientUserData->closeStatus, clientUserData->closeReason);
391 RemoveConnections(clientId, *clientUserData);
392 manager->RemoveClientUserData(wsi);
393 lws_set_wsi_user(wsi, nullptr);
394
395 if (userData->IsClosed() && !userData->IsThreadStop()) {
396 NETSTACK_LOGI("server service is stopped");
397 userData->SetThreadStop(true);
398 }
399 return HttpDummy(wsi, reason, user, in, len);
400 }
401
RemoveConnections(const std::string & id,UserData & userData)402 void WebSocketServerExec::RemoveConnections(const std::string &id, UserData &userData)
403 {
404 if (webSocketConnection_.empty()) {
405 NETSTACK_LOGE("connection list is empty");
406 return;
407 }
408 {
409 std::unique_lock<std::shared_mutex> lock(wsMutex_);
410 if (webSocketConnection_.find(id) == webSocketConnection_.end()) {
411 NETSTACK_LOGE("connection list find clientId failed");
412 return;
413 }
414 webSocketConnection_.erase(id);
415 NETSTACK_LOGI("connection erase success");
416 }
417 }
418
LwsCallbackWsiDestroyServer(lws * wsi,lws_callback_reasons reason,void * user,void * in,size_t len)419 int WebSocketServerExec::LwsCallbackWsiDestroyServer(lws *wsi, lws_callback_reasons reason, void *user, void *in,
420 size_t len)
421 {
422 NETSTACK_LOGD("lws server callback wsi destroy");
423 if (wsi == nullptr) {
424 NETSTACK_LOGE("wsi is null");
425 return -1;
426 }
427 lws_context *context = lws_get_context(wsi);
428 EventManager *manager = static_cast<EventManager *>(lws_context_user(context));
429 if (manager == nullptr) {
430 NETSTACK_LOGE("manager is null");
431 return RaiseServerError(manager);
432 }
433 auto userData = manager->GetWebSocketUserData();
434 if (userData == nullptr) {
435 NETSTACK_LOGE("user data is null");
436 return RaiseServerError(manager);
437 }
438 userData->SetLws(nullptr);
439 return HttpDummy(wsi, reason, user, in, len);
440 }
441
LwsCallbackProtocolDestroyServer(lws * wsi,lws_callback_reasons reason,void * user,void * in,size_t len)442 int WebSocketServerExec::LwsCallbackProtocolDestroyServer(lws *wsi, lws_callback_reasons reason, void *user, void *in,
443 size_t len)
444 {
445 NETSTACK_LOGD("lws server callback protocol destroy");
446 return HttpDummy(wsi, reason, user, in, len);
447 }
448
LwsCallbackServerWriteable(lws * wsi,lws_callback_reasons reason,void * user,void * in,size_t len)449 int WebSocketServerExec::LwsCallbackServerWriteable(lws *wsi, lws_callback_reasons reason, void *user, void *in,
450 size_t len)
451 {
452 NETSTACK_LOGD("lws callback Server writable");
453 lws_context *context = lws_get_context(wsi);
454 EventManager *manager = static_cast<EventManager *>(lws_context_user(context));
455 if (manager == nullptr || manager->innerMagic_.magicNumber != EVENT_MANAGER_MAGIC_NUMBER) {
456 NETSTACK_LOGE("manager is null");
457 return RaiseServerError(manager);
458 }
459 // server
460 auto userData = manager->GetWebSocketUserData();
461 if (userData == nullptr) {
462 NETSTACK_LOGE("user data is null");
463 return RaiseServerError(manager);
464 }
465 if (userData->IsThreadStop()) {
466 NETSTACK_LOGI("session is stopped");
467 return -1;
468 }
469 // client
470 auto *clientUserData = reinterpret_cast<UserData *>(lws_wsi_user(wsi));
471 if (clientUserData == nullptr) {
472 NETSTACK_LOGE("clientUserData is null");
473 return RaiseServerError(manager);
474 }
475 if (clientUserData->IsClosed()) {
476 NETSTACK_LOGI("client is closed, need to close");
477 lws_close_reason(wsi, clientUserData->closeStatus,
478 reinterpret_cast<unsigned char *>(const_cast<char *>(clientUserData->closeReason.c_str())),
479 strlen(clientUserData->closeReason.c_str()));
480 return -1;
481 }
482 auto sendData = clientUserData->Pop();
483 if (sendData.data == nullptr || sendData.length == 0) {
484 NETSTACK_LOGE("send data is empty");
485 return HttpDummy(wsi, reason, user, in, len);
486 }
487 int sendLength = lws_write(wsi, reinterpret_cast<unsigned char *>(sendData.data) + LWS_SEND_BUFFER_PRE_PADDING,
488 sendData.length, sendData.protocol);
489 free(sendData.data);
490 NETSTACK_LOGD("lws send data length is %{public}d", sendLength);
491 if (!userData->IsEmpty()) {
492 NETSTACK_LOGE("userData is not empty");
493 userData->TriggerWritable();
494 }
495 return HttpDummy(wsi, reason, user, in, len);
496 }
497
LwsCallbackWsPeerInitiatedCloseServer(lws * wsi,lws_callback_reasons reason,void * user,void * in,size_t len)498 int WebSocketServerExec::LwsCallbackWsPeerInitiatedCloseServer(lws *wsi, lws_callback_reasons reason,
499 void *user, void *in, size_t len)
500 {
501 NETSTACK_LOGD("lws server callback ws peer initiated close");
502 if (wsi == nullptr) {
503 NETSTACK_LOGE("wsi is null");
504 return -1;
505 }
506 lws_context *context = lws_get_context(wsi);
507 EventManager *manager = static_cast<EventManager *>(lws_context_user(context));
508 auto userData = manager->GetWebSocketUserData();
509 if (userData == nullptr) {
510 NETSTACK_LOGE("user data is null");
511 return RaiseServerError(manager);
512 }
513 if (in == nullptr || len < sizeof(uint16_t)) {
514 NETSTACK_LOGI("No close reason");
515 userData->Close(LWS_CLOSE_STATUS_NORMAL, "");
516 return HttpDummy(wsi, reason, user, in, len);
517 }
518 uint16_t closeStatus = ntohs(*reinterpret_cast<uint16_t *>(in));
519 std::string closeReason;
520 closeReason.append(reinterpret_cast<char *>(in) + sizeof(uint16_t), len - sizeof(uint16_t));
521 auto *clientUserData = reinterpret_cast<UserData *>(lws_wsi_user(wsi));
522 clientUserData->Close(static_cast<lws_close_status>(closeStatus), closeReason);
523 return HttpDummy(wsi, reason, user, in, len);
524 }
525
LwsCallbackFilterProtocolConnection(lws * wsi,lws_callback_reasons reason,void * user,void * in,size_t len)526 int WebSocketServerExec::LwsCallbackFilterProtocolConnection(lws *wsi, lws_callback_reasons reason,
527 void *user, void *in, size_t len)
528 {
529 NETSTACK_LOGD("lws server callback filter ProtocolConnection");
530 lws_context *context = lws_get_context(wsi);
531 EventManager *manager = static_cast<EventManager *>(lws_context_user(context));
532 if (manager == nullptr) {
533 NETSTACK_LOGE("manager is null");
534 return RaiseServerError(manager);
535 }
536 auto userData = manager->GetWebSocketUserData();
537 if (userData == nullptr) {
538 NETSTACK_LOGE("user data is null");
539 return RaiseServerError(manager);
540 }
541 if (userData->IsClosed() || userData->IsThreadStop()) {
542 NETSTACK_LOGE("session is closed or thread is stopped");
543 return RaiseServerError(manager);
544 }
545 std::string clientId;
546 WebSocketConnection connection;
547 bool ret = GetPeerConnMsg(wsi, manager, clientId, connection);
548 if (!ret) {
549 NETSTACK_LOGE("GetPeerConnMsg failed");
550 return RaiseServerError(manager);
551 }
552 /* 是否超过最大连接数 */
553 if (IsOverMaxClientConns(manager, connection.clientIP)) {
554 NETSTACK_LOGE("current connections count is more than limit, need to close");
555 return RaiseServerError(manager);
556 }
557 /* 添加防止恶意连接的业务逻辑 */
558 if (!IsAllowConnection(connection.clientIP)) {
559 NETSTACK_LOGE("Rejected malicious connection");
560 return RaiseServerError(manager);
561 }
562 return HttpDummy(wsi, reason, user, in, len);
563 }
564
IsAllowConnection(const std::string & ip)565 bool WebSocketServerExec::IsAllowConnection(const std::string &ip)
566 {
567 if (IsIpInBanList(ip)) {
568 NETSTACK_LOGE("client is in banlist");
569 return false;
570 }
571 if (IsHighFreqConnection(ip)) {
572 NETSTACK_LOGE("client reach high frequency connection");
573 AddBanList(ip);
574 return false;
575 }
576 UpdataClientList(ip);
577 return true;
578 }
579
UpdataClientList(const std::string & ip)580 void WebSocketServerExec::UpdataClientList(const std::string &ip)
581 {
582 std::shared_lock<std::shared_mutex> lock(connListMutex_);
583 auto it = clientList.find(ip);
584 if (it == clientList.end()) {
585 NETSTACK_LOGI("add clientid to clientlist");
586 clientList[ip] = {1, GetCurrentSecond()};
587 } else {
588 auto now = GetCurrentSecond() - it->second.lastConnectionTime;
589 if (now > ONE_MINUTE_IN_SEC) {
590 NETSTACK_LOGI("reset clientid connections cnt");
591 it->second = {1, GetCurrentSecond()};
592 } else {
593 it->second.cnt++;
594 }
595 }
596 }
597
AddBanList(const std::string & ip)598 void WebSocketServerExec::AddBanList(const std::string &ip)
599 {
600 std::shared_lock<std::shared_mutex> lock(banListMutex_);
601 banList[ip] = GetCurrentSecond() + ONE_MINUTE_IN_SEC;
602 }
603
IsIpInBanList(const std::string & ip)604 bool WebSocketServerExec::IsIpInBanList(const std::string &ip)
605 {
606 std::shared_lock<std::shared_mutex> lock(banListMutex_);
607 auto it = banList.find(ip);
608 if (it != banList.end()) {
609 auto now = GetCurrentSecond();
610 if (now < it->second) {
611 return true;
612 } else {
613 banList.erase(it);
614 }
615 }
616 return false;
617 }
618
GetCurrentSecond()619 uint64_t WebSocketServerExec::GetCurrentSecond()
620 {
621 return std::chrono::duration_cast<std::chrono::seconds>(std::chrono::system_clock::now().time_since_epoch())
622 .count();
623 }
624
IsHighFreqConnection(const std::string & ip)625 bool WebSocketServerExec::IsHighFreqConnection(const std::string &ip)
626 {
627 std::shared_lock<std::shared_mutex> lock(connListMutex_);
628 auto it = clientList.find(ip);
629 if (it != clientList.end()) {
630 auto duration = GetCurrentSecond() - it->second.lastConnectionTime;
631 if (duration <= ONE_MINUTE_IN_SEC) {
632 return it->second.cnt > MAX_CONNECTIONS_PER_MINUTE;
633 }
634 }
635 return false;
636 }
637
LwsCallbackReceive(lws * wsi,lws_callback_reasons reason,void * user,void * in,size_t len)638 int WebSocketServerExec::LwsCallbackReceive(lws *wsi, lws_callback_reasons reason, void *user, void *in,
639 size_t len)
640 {
641 NETSTACK_LOGD("lws callback server receive");
642 lws_context *context = lws_get_context(wsi);
643 EventManager *manager = static_cast<EventManager *>(lws_context_user(context));
644 auto isFinal = lws_is_final_fragment(wsi);
645 OnServerMessage(wsi, manager, in, len, lws_frame_is_binary(wsi), isFinal);
646 return HttpDummy(wsi, reason, user, in, len);
647 }
648
CreateServerClosePara(napi_env env,void * callbackPara)649 static napi_value CreateServerClosePara(napi_env env, void *callbackPara)
650 {
651 auto para = reinterpret_cast<ClientConnectionCloseCallback *>(callbackPara);
652 auto deleter = [](const ClientConnectionCloseCallback *p) { delete p; };
653 std::unique_ptr<ClientConnectionCloseCallback, decltype(deleter)> handler(para, deleter);
654 napi_value obj = NapiUtils::CreateArray(env, ARRAY_LEN_TWO);
655 if (NapiUtils::GetValueType(env, obj) != napi_object) {
656 return NapiUtils::GetUndefined(env);
657 }
658 napi_value jsConn = NapiUtils::CreateObject(env);
659 if (NapiUtils::GetValueType(env, jsConn) != napi_object) {
660 return NapiUtils::GetUndefined(env);
661 }
662 NapiUtils::SetStringPropertyUtf8(env, jsConn, EVENT_KEY_CLIENT_IP, para->connection.clientIP);
663 NapiUtils::SetUint32Property(env, jsConn, EVENT_KEY_CLIENT_PORT, para->connection.clientPort);
664 NapiUtils::SetArrayElement(env, obj, 0, jsConn);
665 napi_value jsRes = NapiUtils::CreateObject(env);
666 if (NapiUtils::GetValueType(env, jsRes) != napi_object) {
667 return NapiUtils::GetUndefined(env);
668 }
669 NapiUtils::SetUint32Property(env, jsRes, EVENT_KEY_CODE, para->closeResult.code);
670 NapiUtils::SetStringPropertyUtf8(env, jsRes, EVENT_KEY_REASON, para->closeResult.reason);
671 NapiUtils::SetArrayElement(env, obj, 1, jsRes);
672 return obj;
673 }
674
ConvertWsBinaryMessageToJs(napi_env env,const WebSocketMessage * msg)675 static napi_value ConvertWsBinaryMessageToJs(napi_env env, const WebSocketMessage *msg)
676 {
677 napi_value jsMsg = NapiUtils::CreateObject(env);
678 if (NapiUtils::GetValueType(env, jsMsg) != napi_object) {
679 return NapiUtils::GetUndefined(env);
680 }
681 void *data = nullptr;
682 napi_value arrayBuffer = NapiUtils::CreateArrayBuffer(env, msg->data.size(), &data);
683 if (data != nullptr && NapiUtils::ValueIsArrayBuffer(env, arrayBuffer) &&
684 memcpy_s(data, msg->data.size(), msg->data.c_str(), msg->data.size()) >= 0) {
685 NapiUtils::SetNamedProperty(env, jsMsg, "data", arrayBuffer);
686 napi_value jsConn = NapiUtils::CreateObject(env);
687 if (NapiUtils::GetValueType(env, jsConn) != napi_object) {
688 return NapiUtils::GetUndefined(env);
689 }
690 NapiUtils::SetStringPropertyUtf8(env, jsConn, EVENT_KEY_CLIENT_IP, msg->connection.clientIP);
691 NapiUtils::SetUint32Property(env, jsConn, EVENT_KEY_CLIENT_PORT, msg->connection.clientPort);
692 NapiUtils::SetNamedProperty(env, jsMsg, EVENT_KEY_CONNECTION, jsConn);
693 return jsMsg;
694 }
695 return NapiUtils::GetUndefined(env);
696 }
697
CreateServerBinaryMessagePara(napi_env env,void * callbackPara)698 static napi_value CreateServerBinaryMessagePara(napi_env env, void *callbackPara)
699 {
700 auto pair = reinterpret_cast<std::pair<lws *, EventManager *> *>(callbackPara);
701 if (pair == nullptr) {
702 NETSTACK_LOGE("pair is nullptr");
703 return NapiUtils::GetUndefined(env);
704 }
705 lws *wsi = pair->first;
706 if (wsi == nullptr) {
707 NETSTACK_LOGE("wsi is nullptr");
708 return NapiUtils::GetUndefined(env);
709 }
710 auto &manager = pair->second;
711 if (manager == nullptr || manager->innerMagic_.magicNumber != EVENT_MANAGER_MAGIC_NUMBER) {
712 NETSTACK_LOGE("manager is nullptr");
713 return NapiUtils::CreateStringUtf8(env, "");
714 }
715 auto msg = reinterpret_cast<WebSocketMessage *>(manager->GetServerQueueData(wsi));
716 if (!msg) {
717 NETSTACK_LOGE("msg is nullptr");
718 return NapiUtils::GetUndefined(env);
719 }
720 napi_value jsMsg = ConvertWsBinaryMessageToJs(env, msg);
721 if (NapiUtils::GetValueType(env, jsMsg) != napi_object) {
722 delete msg;
723 return NapiUtils::GetUndefined(env);
724 }
725 delete msg;
726 return jsMsg;
727 }
728
ConvertWsTextMessageToJs(napi_env env,const WebSocketMessage * msg)729 static napi_value ConvertWsTextMessageToJs(napi_env env, const WebSocketMessage *msg)
730 {
731 napi_value jsMsg = NapiUtils::CreateObject(env);
732 if (NapiUtils::GetValueType(env, jsMsg) != napi_object) {
733 return NapiUtils::GetUndefined(env);
734 }
735 NapiUtils::SetStringPropertyUtf8(env, jsMsg, EVENT_KEY_DATA, msg->data);
736 napi_value jsConn = NapiUtils::CreateObject(env);
737 if (NapiUtils::GetValueType(env, jsConn) != napi_object) {
738 return NapiUtils::GetUndefined(env);
739 }
740 NapiUtils::SetStringPropertyUtf8(env, jsConn, EVENT_KEY_CLIENT_IP, msg->connection.clientIP);
741 NapiUtils::SetUint32Property(env, jsConn, EVENT_KEY_CLIENT_PORT, msg->connection.clientPort);
742 NapiUtils::SetNamedProperty(env, jsMsg, EVENT_KEY_CONNECTION, jsConn);
743 return jsMsg;
744 }
745
CreateServerTextMessagePara(napi_env env,void * callbackPara)746 static napi_value CreateServerTextMessagePara(napi_env env, void *callbackPara)
747 {
748 auto pair = reinterpret_cast<std::pair<lws *, EventManager *> *>(callbackPara);
749 if (pair == nullptr) {
750 NETSTACK_LOGE("pair is nullptr");
751 return NapiUtils::GetUndefined(env);
752 }
753 lws *wsi = pair->first;
754 if (wsi == nullptr) {
755 NETSTACK_LOGE("wsi is nullptr");
756 return NapiUtils::GetUndefined(env);
757 }
758 auto &manager = pair->second;
759 if (manager == nullptr || manager->innerMagic_.magicNumber != EVENT_MANAGER_MAGIC_NUMBER) {
760 NETSTACK_LOGE("manager is nullptr");
761 return NapiUtils::CreateStringUtf8(env, "");
762 }
763 auto msg = reinterpret_cast<WebSocketMessage *>(manager->GetServerQueueData(wsi));
764 if (!msg) {
765 NETSTACK_LOGE("msg is nullptr");
766 return NapiUtils::GetUndefined(env);
767 }
768 napi_value jsMsg = ConvertWsTextMessageToJs(env, msg);
769 if (NapiUtils::GetValueType(env, jsMsg) != napi_object) {
770 NETSTACK_LOGE("jsMsg is not object");
771 delete msg;
772 return NapiUtils::GetUndefined(env);
773 }
774 delete msg;
775 return jsMsg;
776 }
777
CreateConnectPara(napi_env env,void * callbackPara)778 static napi_value CreateConnectPara(napi_env env, void *callbackPara)
779 {
780 auto para = reinterpret_cast<WebSocketConnection *>(callbackPara);
781 auto deleter = [](const WebSocketConnection *p) { delete p; };
782 std::unique_ptr<WebSocketConnection, decltype(deleter)> handler(para, deleter);
783 napi_value obj = NapiUtils::CreateObject(env);
784 if (NapiUtils::GetValueType(env, obj) != napi_object) {
785 NETSTACK_LOGE("napi_object not found");
786 return NapiUtils::GetUndefined(env);
787 }
788 NapiUtils::SetUint32Property(env, obj, EVENT_KEY_CLIENT_PORT, para->clientPort);
789 NapiUtils::SetStringPropertyUtf8(env, obj, EVENT_KEY_CLIENT_IP, para->clientIP);
790 return obj;
791 }
792
CreateServerError(napi_env env,void * callbackPara)793 static napi_value CreateServerError(napi_env env, void *callbackPara)
794 {
795 auto code = reinterpret_cast<int32_t *>(callbackPara);
796 auto deleter = [](int32_t *p) { delete p; };
797 std::unique_ptr<int32_t, decltype(deleter)> handler(code, deleter);
798 napi_value err = NapiUtils::CreateObject(env);
799 if (NapiUtils::GetValueType(env, err) != napi_object) {
800 return NapiUtils::GetUndefined(env);
801 }
802 NapiUtils::SetInt32Property(env, err, EVENT_KEY_CODE, *code);
803 return err;
804 }
805
OnServerError(EventManager * manager,int32_t code)806 void WebSocketServerExec::OnServerError(EventManager *manager, int32_t code)
807 {
808 NETSTACK_LOGI("OnServerError %{public}d", code);
809 if (manager == nullptr || manager->innerMagic_.magicNumber != EVENT_MANAGER_MAGIC_NUMBER) {
810 NETSTACK_LOGE("manager is null");
811 return;
812 }
813 bool hasServerEventListener = manager->HasEventListener(EventName::EVENT_SERVER_ERROR);
814 if (!hasServerEventListener) {
815 NETSTACK_LOGI("no event listener: %{public}s", EventName::EVENT_SERVER_ERROR);
816 return;
817 }
818 auto para = new int32_t(code);
819 manager->EmitByUvWithoutCheckShared(EventName::EVENT_SERVER_ERROR, para, CallbackTemplate<CreateServerError>);
820 }
821
OnConnect(lws * wsi,EventManager * manager)822 void WebSocketServerExec::OnConnect(lws *wsi, EventManager *manager)
823 {
824 NETSTACK_LOGI("OnConnect enter");
825 if (manager == nullptr || manager->innerMagic_.magicNumber != EVENT_MANAGER_MAGIC_NUMBER) {
826 NETSTACK_LOGE("manager is null");
827 return;
828 }
829 bool hasServerConnectListener = manager->HasEventListener(EventName::EVENT_SERVER_CONNECT);
830 if (!hasServerConnectListener) {
831 NETSTACK_LOGI("no event listener: %{public}s", EventName::EVENT_SERVER_CONNECT);
832 return;
833 }
834 {
835 std::shared_lock<std::shared_mutex> lock(wsMutex_);
836 for (auto [id, connPair] : webSocketConnection_) {
837 if (connPair.first == wsi) {
838 auto para = new WebSocketConnection;
839 para->clientIP = connPair.second.clientIP;
840 para->clientPort = connPair.second.clientPort;
841 NETSTACK_LOGI("connection find ok, clientId:%{public}s", id.c_str());
842 manager->EmitByUvWithoutCheckShared(EventName::EVENT_SERVER_CONNECT,
843 para, CallbackTemplate<CreateConnectPara>);
844 return;
845 }
846 }
847 }
848 NETSTACK_LOGE("not found client msg");
849 }
850
OnServerClose(lws * wsi,EventManager * manager,lws_close_status closeStatus,const std::string & closeReason)851 void WebSocketServerExec::OnServerClose(lws *wsi, EventManager *manager, lws_close_status closeStatus,
852 const std::string &closeReason)
853 {
854 NETSTACK_LOGI("OnServerClose %{public}u %{public}s", closeStatus, closeReason.c_str());
855 if (manager == nullptr || manager->innerMagic_.magicNumber != EVENT_MANAGER_MAGIC_NUMBER) {
856 NETSTACK_LOGE("manager is null");
857 return;
858 }
859 if (wsi == nullptr) {
860 NETSTACK_LOGE("wsi is nullptr");
861 return;
862 }
863 bool hasServerCloseListener = manager->HasEventListener(EventName::EVENT_SERVER_CLOSE);
864 if (!hasServerCloseListener) {
865 NETSTACK_LOGI("no event listener: %{public}s", EventName::EVENT_SERVER_CLOSE);
866 return;
867 }
868 {
869 std::shared_lock<std::shared_mutex> lock(wsMutex_);
870 for (auto [id, connPair] : webSocketConnection_) {
871 if (connPair.first == wsi) {
872 auto conn = new ClientConnectionCloseCallback;
873 if (conn == nullptr) {
874 return;
875 }
876 conn->closeResult.code = closeStatus;
877 conn->closeResult.reason = closeReason;
878 conn->connection = connPair.second;
879 NETSTACK_LOGI("clientId: %{public}s", id.c_str());
880 manager->EmitByUvWithoutCheckShared(EventName::EVENT_SERVER_CLOSE,
881 conn, CallbackTemplateWithTwoPara<CreateServerClosePara>);
882 return;
883 }
884 }
885 }
886 NETSTACK_LOGE("not found client msg");
887 }
888
OnServerMessage(lws * wsi,EventManager * manager,void * data,size_t length,bool isBinary,bool isFinal)889 void WebSocketServerExec::OnServerMessage(lws *wsi, EventManager *manager, void *data,
890 size_t length, bool isBinary, bool isFinal)
891 {
892 NETSTACK_LOGD("server OnMessage %{public}d", isBinary);
893 if (manager == nullptr || manager->innerMagic_.magicNumber != EVENT_MANAGER_MAGIC_NUMBER) {
894 NETSTACK_LOGE("manager is null");
895 return;
896 }
897 bool hasServerEventListener = manager->HasEventListener(EventName::EVENT_SERVER_MESSAGE_RECEIVE);
898 if (!hasServerEventListener) {
899 NETSTACK_LOGI("no event listener: %{public}s", EventName::EVENT_SERVER_MESSAGE_RECEIVE);
900 return;
901 }
902 if (length > INT32_MAX) {
903 NETSTACK_LOGE("data length too long");
904 return;
905 }
906 HandleServerRcvMessage(wsi, manager, data, length, isBinary, isFinal);
907 }
908
HandleServerRcvMessage(lws * wsi,EventManager * manager,void * data,size_t length,bool isBinary,bool isFinal)909 void WebSocketServerExec::HandleServerRcvMessage(lws *wsi, EventManager *manager, void *data,
910 size_t length, bool isBinary, bool isFinal)
911 {
912 if (manager == nullptr) {
913 NETSTACK_LOGE("manager is nullptr");
914 return;
915 }
916 if (isBinary) {
917 manager->AppendWsServerBinaryData(wsi, data, length);
918 if (isFinal) {
919 const std::string &msgFromManager = manager->GetWsServerBinaryData(wsi);
920 if (msgFromManager.empty()) {
921 NETSTACK_LOGE("msgFromManager is empty");
922 return;
923 }
924 auto msg = new WebSocketMessage;
925 if (msg == nullptr) {
926 return;
927 }
928 SetWebsocketMessage(wsi, manager, msgFromManager, msg);
929 manager->SetServerQueueData(wsi, msg);
930 auto callbackPara = new std::pair<lws *, EventManager *>(wsi, manager);
931 manager->EmitByUvWithoutCheckShared(EventName::EVENT_SERVER_MESSAGE_RECEIVE, callbackPara,
932 CallbackTemplate<CreateServerBinaryMessagePara>);
933 manager->ClearWsServerBinaryData(wsi);
934 }
935 } else {
936 manager->AppendWsServerTextData(wsi, data, length);
937 if (isFinal) {
938 const std::string &msgFromManager = manager->GetWsServerTextData(wsi);
939 if (msgFromManager.empty()) {
940 NETSTACK_LOGE("msgFromManager is empty");
941 return;
942 }
943 auto msg = new WebSocketMessage;
944 if (msg == nullptr) {
945 return;
946 }
947 SetWebsocketMessage(wsi, manager, msgFromManager, msg);
948 manager->SetServerQueueData(wsi, msg);
949 auto callbackPara = new std::pair<lws *, EventManager *>(wsi, manager);
950 manager->EmitByUvWithoutCheckShared(EventName::EVENT_SERVER_MESSAGE_RECEIVE, callbackPara,
951 CallbackTemplate<CreateServerTextMessagePara>);
952 manager->ClearWsServerTextData(wsi);
953 }
954 }
955 }
956
SetWebsocketMessage(lws * wsi,EventManager * manager,const std::string & msgFromManager,void * dataMsg)957 void WebSocketServerExec::SetWebsocketMessage(lws *wsi, EventManager *manager,
958 const std::string &msgFromManager, void *dataMsg)
959 {
960 NETSTACK_LOGD("SetWebsocketMessage enter");
961 if (manager == nullptr || manager->innerMagic_.magicNumber != EVENT_MANAGER_MAGIC_NUMBER) {
962 NETSTACK_LOGE("manager is null");
963 return;
964 }
965 if (wsi == nullptr) {
966 NETSTACK_LOGE("wsi is nullptr");
967 return;
968 }
969 auto webSocketMessage = static_cast<WebSocketMessage *>(dataMsg);
970 webSocketMessage->data = msgFromManager;
971
972 {
973 std::shared_lock<std::shared_mutex> lock(wsMutex_);
974 if (webSocketConnection_.empty()) {
975 NETSTACK_LOGE("webSocketConnection_ is empty");
976 return;
977 }
978 for (auto [_, connPair] : webSocketConnection_) {
979 if (connPair.first == wsi) {
980 webSocketMessage->connection = connPair.second;
981 return;
982 }
983 }
984 }
985 NETSTACK_LOGE("not found client msgFromManager");
986 }
987
ExecServerStart(ServerStartContext * context)988 bool WebSocketServerExec::ExecServerStart(ServerStartContext *context)
989 {
990 NETSTACK_LOGD("websocket server start exec");
991 if (context == nullptr) {
992 NETSTACK_LOGE("context is nullptr");
993 return false;
994 }
995 if (!CommonUtils::HasInternetPermission()) {
996 context->SetPermissionDenied(true);
997 return false;
998 }
999 if (!CommonUtils::IsValidIPV4(context->GetServerIP()) &&
1000 !CommonUtils::IsValidIPV6(context->GetServerIP())) {
1001 NETSTACK_LOGE("IPV4 and IPV6 are not valid");
1002 context->SetErrorCode(WEBSOCKET_ERROR_CODE_INVALID_NIC);
1003 return false;
1004 }
1005 if (!CommonUtils::IsValidPort(context->GetServerPort())) {
1006 context->SetErrorCode(WEBSOCKET_ERROR_CODE_INVALID_PORT);
1007 NETSTACK_LOGE("Port is not valid");
1008 return false;
1009 }
1010 if (context->GetMaxConcurrentClientsNumber() > MAX_CONCURRENT_CLIENTS_NUMBER) {
1011 NETSTACK_LOGE("max concurrent clients number is set over limit");
1012 return false;
1013 }
1014 auto manager = context->GetSharedManager();
1015 if (manager == nullptr) {
1016 return false;
1017 }
1018 manager->SetMaxConnClientCnt(context->GetMaxConcurrentClientsNumber());
1019 if (context->GetMaxConnectionsForOneClient() > MAX_CONNECTIONS_FOR_ONE_CLIENT) {
1020 NETSTACK_LOGE("max connection number for one client is set over limit");
1021 return false;
1022 }
1023 manager->SetMaxConnForOneClient(context->GetMaxConnectionsForOneClient());
1024 lws_context_creation_info info = {};
1025 FillServerContextInfo(context, manager, info);
1026 if (!FillServerCertPath(context, info)) {
1027 NETSTACK_LOGE("FillServerCertPath error");
1028 return false;
1029 }
1030 StartService(info, manager);
1031 return true;
1032 }
1033
StartService(lws_context_creation_info & info,std::shared_ptr<EventManager> & manager)1034 void WebSocketServerExec::StartService(lws_context_creation_info &info, std::shared_ptr<EventManager> &manager)
1035 {
1036 lws_context *lwsContext = nullptr;
1037 std::shared_ptr<UserData> userData;
1038 lwsContext = lws_create_context(&info);
1039 userData = std::make_shared<UserData>(lwsContext);
1040 manager->SetWebSocketUserData(userData);
1041 std::thread serviceThread(RunServerService, userData, manager);
1042 #if defined(MAC_PLATFORM) || defined(IOS_PLATFORM)
1043 pthread_setname_np(WEBSOCKET_SERVER_THREAD_RUN);
1044 #else
1045 pthread_setname_np(serviceThread.native_handle(), WEBSOCKET_SERVER_THREAD_RUN);
1046 #endif
1047 serviceThread.detach();
1048 }
1049
FillServerContextInfo(ServerStartContext * context,std::shared_ptr<EventManager> & manager,lws_context_creation_info & info)1050 void WebSocketServerExec::FillServerContextInfo(ServerStartContext *context, std::shared_ptr<EventManager> &manager,
1051 lws_context_creation_info &info)
1052 {
1053 info.options = LWS_SERVER_OPTION_HTTP_HEADERS_SECURITY_BEST_PRACTICES_ENFORCE;
1054 info.port = static_cast<int32_t>(context->GetServerPort());
1055 info.mounts = &mount;
1056 info.protocols = LWS_SERVER_PROTOCOLS;
1057 info.vhost_name = "localhost";
1058 info.user = manager.get();
1059 // maybe
1060 info.gid = -1;
1061 info.uid = -1;
1062 }
1063
CheckFilePath(std::string & path)1064 static bool CheckFilePath(std::string &path)
1065 {
1066 char tmpPath[PATH_MAX] = {0};
1067 if (!realpath(static_cast<const char *>(path.c_str()), tmpPath)) {
1068 NETSTACK_LOGE("path is error");
1069 return false;
1070 }
1071 path = tmpPath;
1072 return true;
1073 }
1074
FillServerCertPath(ServerStartContext * context,lws_context_creation_info & info)1075 bool WebSocketServerExec::FillServerCertPath(ServerStartContext *context, lws_context_creation_info &info)
1076 {
1077 if (!context->certPath_.empty()) {
1078 if (!CheckFilePath(context->certPath_) || !CheckFilePath(context->keyPath_)) {
1079 NETSTACK_LOGE("client cert not exist");
1080 context->SetErrorCode(WEBSOCKET_ERROR_CODE_FILE_NOT_EXIST);
1081 return false;
1082 }
1083 info.ssl_cert_filepath = context->certPath_.c_str();
1084 info.ssl_private_key_filepath = context->keyPath_.c_str();
1085 }
1086 return true;
1087 }
1088
ExecListAllConnections(ListAllConnectionsContext * context)1089 bool WebSocketServerExec::ExecListAllConnections(ListAllConnectionsContext *context)
1090 {
1091 NETSTACK_LOGD("ListAllConnections start exec");
1092 if (context == nullptr) {
1093 NETSTACK_LOGE("context is nullptr");
1094 return false;
1095 }
1096 if (!CommonUtils::HasInternetPermission()) {
1097 context->SetPermissionDenied(true);
1098 return false;
1099 }
1100 auto manager = context->GetSharedManager();
1101 if (manager == nullptr) {
1102 NETSTACK_LOGE("context is null");
1103 return false;
1104 }
1105 auto userData = manager->GetWebSocketUserData();
1106 if (userData == nullptr) {
1107 NETSTACK_LOGE("user data is nullptr");
1108 return false;
1109 }
1110 if (userData->IsClosed() || userData->IsThreadStop()) {
1111 NETSTACK_LOGE("session is closed or stopped");
1112 return false;
1113 }
1114 std::vector<WebSocketConnection> connection = GetConnections();
1115 context->SetAllConnections(connection);
1116 NETSTACK_LOGI("ExecListAllConnections OK");
1117 return true;
1118 }
1119
GetConnections()1120 std::vector<WebSocketConnection> WebSocketServerExec::GetConnections()
1121 {
1122 std::shared_lock<std::shared_mutex> lock(wsMutex_);
1123 std::vector<WebSocketConnection> conn;
1124 if (!webSocketConnection_.empty()) {
1125 for (auto [_, connPair] : webSocketConnection_) {
1126 conn.emplace_back(connPair.second);
1127 }
1128 }
1129 return conn;
1130 }
1131
ExecServerClose(ServerCloseContext * context)1132 bool WebSocketServerExec::ExecServerClose(ServerCloseContext *context)
1133 {
1134 if (context == nullptr) {
1135 NETSTACK_LOGE("context is nullptr");
1136 return false;
1137 }
1138 if (!CommonUtils::HasInternetPermission()) {
1139 context->SetPermissionDenied(true);
1140 return false;
1141 }
1142 if (context->GetSharedManager() == nullptr) {
1143 NETSTACK_LOGE("context is null");
1144 return false;
1145 }
1146 WebSocketConnection conn = context->GetConnection();
1147 if (conn.clientIP.empty()) {
1148 NETSTACK_LOGE("connection is empty");
1149 return false;
1150 }
1151 std::string clientId = conn.clientIP + ":" + std::to_string(conn.clientPort);
1152 NETSTACK_LOGI("ExecServerClose, clientID:%{public}s", clientId.c_str());
1153 auto wsi = GetClientWsi(clientId);
1154 if (wsi == nullptr) {
1155 context->SetErrorCode(WEBSOCKET_ERROR_CODE_CONNECTION_NOT_EXIST);
1156 NETSTACK_LOGE("clientId not found:%{public}s", clientId.c_str());
1157 return false;
1158 }
1159 auto *clientUserData = reinterpret_cast<UserData *>(lws_wsi_user(wsi));
1160 if (clientUserData == nullptr) {
1161 NETSTACK_LOGE("clientUser data is nullptr");
1162 return false;
1163 }
1164 if (clientUserData->IsClosed() || clientUserData->IsThreadStop()) {
1165 NETSTACK_LOGE("session is closed or stopped");
1166 return false;
1167 }
1168 clientUserData->Close(static_cast<lws_close_status>(context->code), context->reason);
1169 clientUserData->TriggerWritable();
1170 NETSTACK_LOGI("ExecServerClose OK");
1171 return true;
1172 }
1173
ExecServerSend(ServerSendContext * context)1174 bool WebSocketServerExec::ExecServerSend(ServerSendContext *context)
1175 {
1176 if (context == nullptr) {
1177 NETSTACK_LOGE("context is nullptr");
1178 return false;
1179 }
1180 if (!CommonUtils::HasInternetPermission()) {
1181 context->SetPermissionDenied(true);
1182 return false;
1183 }
1184 WebSocketConnection conn = context->GetConnection();
1185 if (conn.clientIP.empty()) {
1186 NETSTACK_LOGE("connection is empty");
1187 return false;
1188 }
1189 std::string clientId = conn.clientIP + ":" + std::to_string(conn.clientPort);
1190 NETSTACK_LOGI("connection clientid:%{public}s", clientId.c_str());
1191 auto wsi = GetClientWsi(clientId);
1192 if (wsi == nullptr) {
1193 context->SetErrorCode(WEBSOCKET_ERROR_CODE_CONNECTION_NOT_EXIST);
1194 NETSTACK_LOGE("clientId not found:%{public}s", clientId.c_str());
1195 return false;
1196 }
1197 auto *clientUserData = reinterpret_cast<UserData *>(lws_wsi_user(wsi));
1198 if (clientUserData == nullptr) {
1199 NETSTACK_LOGE("clientUser data is nullptr");
1200 return false;
1201 }
1202 if (clientUserData->IsClosed() || clientUserData->IsThreadStop()) {
1203 NETSTACK_LOGE("session is closed or stopped");
1204 return false;
1205 }
1206 clientUserData->Push(context->data, context->length, context->protocol);
1207 clientUserData->TriggerWritable();
1208 NETSTACK_LOGD("lws ts send success");
1209 return true;
1210 }
1211
GetClientWsi(const std::string clientId)1212 lws *WebSocketServerExec::GetClientWsi(const std::string clientId)
1213 {
1214 std::shared_lock<std::shared_mutex> lock(wsMutex_);
1215 if (webSocketConnection_.empty()) {
1216 NETSTACK_LOGE("webSocketConnection is empty");
1217 return nullptr;
1218 }
1219 auto it = webSocketConnection_.find(clientId);
1220 if (it == webSocketConnection_.end()) {
1221 NETSTACK_LOGE("can't find clientId");
1222 return nullptr;
1223 }
1224 return it->second.first;
1225 }
1226
ExecServerStop(ServerStopContext * context)1227 bool WebSocketServerExec::ExecServerStop(ServerStopContext *context)
1228 {
1229 if (context == nullptr) {
1230 NETSTACK_LOGE("context is nullptr");
1231 return false;
1232 }
1233 if (!CommonUtils::HasInternetPermission()) {
1234 context->SetPermissionDenied(true);
1235 return false;
1236 }
1237 auto manager = context->GetSharedManager();
1238 if (manager == nullptr) {
1239 NETSTACK_LOGE("context is null");
1240 return false;
1241 }
1242 auto userData = manager->GetWebSocketUserData();
1243 if (userData == nullptr) {
1244 NETSTACK_LOGE("user data is nullptr");
1245 return false;
1246 }
1247 if (userData->IsClosed() || userData->IsThreadStop()) {
1248 NETSTACK_LOGE("session is closed or stopped");
1249 return false;
1250 }
1251 CloseAllConnection(userData);
1252 userData->Close(LWS_CLOSE_STATUS_GOINGAWAY, "");
1253 NETSTACK_LOGI("ExecServerStop OK");
1254 return true;
1255 }
1256
CloseAllConnection(const std::shared_ptr<UserData> & userData)1257 void WebSocketServerExec::CloseAllConnection(const std::shared_ptr<UserData> &userData)
1258 {
1259 if (userData == nullptr) {
1260 NETSTACK_LOGE("user data is nullptr");
1261 return;
1262 }
1263 decltype(webSocketConnection_) connListTmp;
1264 {
1265 std::shared_lock<std::shared_mutex> lock(wsMutex_);
1266 if (webSocketConnection_.empty()) {
1267 NETSTACK_LOGE("webSocketConnection is empty");
1268 if (!userData->IsThreadStop()) {
1269 NETSTACK_LOGI("server service is stopped");
1270 userData->SetThreadStop(true);
1271 }
1272 return;
1273 }
1274 connListTmp = webSocketConnection_;
1275 }
1276 const char *closeReason = "server is going away";
1277 for (auto [id, connPair] : connListTmp) {
1278 if (connPair.first == nullptr) {
1279 NETSTACK_LOGE("clientId not found:%{public}s", id.c_str());
1280 continue;
1281 }
1282 auto *clientUserData = reinterpret_cast<UserData *>(lws_wsi_user(connPair.first));
1283 clientUserData->Close(LWS_CLOSE_STATUS_GOINGAWAY, closeReason);
1284 clientUserData->TriggerWritable();
1285 }
1286 NETSTACK_LOGI("CloseAllConnection OK");
1287 }
1288
ServerStartCallback(ServerStartContext * context)1289 napi_value WebSocketServerExec::ServerStartCallback(ServerStartContext *context)
1290 {
1291 return NapiUtils::GetBoolean(context->GetEnv(), true);
1292 }
1293
ListAllConnectionsCallback(ListAllConnectionsContext * context)1294 napi_value WebSocketServerExec::ListAllConnectionsCallback(ListAllConnectionsContext *context)
1295 {
1296 if (context == nullptr) {
1297 NETSTACK_LOGE("Context is null");
1298 return nullptr;
1299 }
1300 napi_value connectionsArray = NapiUtils::CreateArray(context->GetEnv(), 0);
1301 const std::vector<WebSocketConnection> connections = context->GetAllConnections();
1302 if (connections.empty()) {
1303 NETSTACK_LOGE("connections list is null");
1304 return connectionsArray;
1305 }
1306 uint32_t index = 0;
1307 for (const auto &conn : connections) {
1308 napi_value jsConn = NapiUtils::CreateObject(context->GetEnv());
1309 NapiUtils::SetUint32Property(context->GetEnv(), jsConn, EVENT_KEY_CLIENT_PORT, conn.clientPort);
1310 NapiUtils::SetStringPropertyUtf8(context->GetEnv(), jsConn, EVENT_KEY_CLIENT_IP, conn.clientIP);
1311 NapiUtils::SetArrayElement(context->GetEnv(), connectionsArray, index, jsConn);
1312 ++index;
1313 }
1314 return connectionsArray;
1315 }
1316
ServerSendCallback(ServerSendContext * context)1317 napi_value WebSocketServerExec::ServerSendCallback(ServerSendContext *context)
1318 {
1319 return NapiUtils::GetBoolean(context->GetEnv(), true);
1320 }
1321
ServerCloseCallback(ServerCloseContext * context)1322 napi_value WebSocketServerExec::ServerCloseCallback(ServerCloseContext *context)
1323 {
1324 return NapiUtils::GetBoolean(context->GetEnv(), true);
1325 }
1326
ServerStopCallback(ServerStopContext * context)1327 napi_value WebSocketServerExec::ServerStopCallback(ServerStopContext *context)
1328 {
1329 auto manager = context->GetSharedManager();
1330 if (manager != nullptr) {
1331 NETSTACK_LOGD("websocket close, delete js ref");
1332 manager->DeleteEventReference(context->GetEnv());
1333 }
1334 return NapiUtils::GetBoolean(context->GetEnv(), true);
1335 }
1336 }