• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 }