• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 2022 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_exec.h"
17 
18 #include <memory>
19 #include <queue>
20 #include <thread>
21 
22 #include "constant.h"
23 #include "netstack_common_utils.h"
24 #include "netstack_log.h"
25 #include "napi_utils.h"
26 #include "securec.h"
27 
28 static constexpr const char *PATH_START = "/";
29 
30 static constexpr const char *NAME_END = ":";
31 
32 static constexpr const char *STATUS_LINE_SEP = " ";
33 
34 static constexpr const size_t STATUS_LINE_ELEM_NUM = 2;
35 
36 static constexpr const char *PREFIX_HTTPS = "https";
37 
38 static constexpr const char *PREFIX_WSS = "wss";
39 
40 static constexpr const int MAX_URI_LENGTH = 1024;
41 
42 static constexpr const int MAX_HDR_LENGTH = 1024;
43 
44 static constexpr const int FD_LIMIT_PER_THREAD = 1 + 1 + 1;
45 
46 static constexpr const int COMMON_ERROR_CODE = 200;
47 
48 static constexpr const char *EVENT_KEY_CODE = "code";
49 
50 static constexpr const char *EVENT_KEY_STATUS = "status";
51 
52 static constexpr const char *EVENT_KEY_REASON = "reason";
53 
54 static constexpr const char *EVENT_KEY_MESSAGE = "message";
55 
56 namespace OHOS::NetStack {
57 static const lws_protocols LWS_PROTOCOLS[] = {
58     {"lws-minimal-client", WebSocketExec::LwsCallback, 0, 0},
59     {nullptr, nullptr, 0, 0}, // this line is needed
60 };
61 
62 static const lws_retry_bo_t RETRY = {
63     .secs_since_valid_ping = 0,
64     .secs_since_valid_hangup = 10,
65     .jitter_percent = 20,
66 };
67 
68 struct CallbackDispatcher {
69     lws_callback_reasons reason;
70     int (*callback)(lws *wsi, lws_callback_reasons reason, void *user, void *in, size_t len);
71 };
72 
73 struct OnOpenClosePara {
OnOpenCloseParaOHOS::NetStack::OnOpenClosePara74     OnOpenClosePara() : status(0) {}
75     uint32_t status;
76     std::string message;
77 };
78 
79 struct OnMessagePara {
OnMessageParaOHOS::NetStack::OnMessagePara80     OnMessagePara() : data(nullptr), length(0), isBinary(false) {}
~OnMessageParaOHOS::NetStack::OnMessagePara81     ~OnMessagePara()
82     {
83         if (data != nullptr) {
84             free(data);
85         }
86     }
87     void *data;
88     size_t length;
89     bool isBinary;
90 };
91 
92 class UserData {
93 public:
94     struct SendData {
SendDataOHOS::NetStack::UserData::SendData95         SendData(void *paraData, size_t paraLength, lws_write_protocol paraProtocol)
96             : data(paraData), length(paraLength), protocol(paraProtocol)
97         {
98         }
99 
100         SendData() = delete;
101 
102         ~SendData() = default;
103 
104         void *data;
105         size_t length;
106         lws_write_protocol protocol;
107     };
108 
UserData(lws_context * context)109     explicit UserData(lws_context *context)
110         : closeStatus(LWS_CLOSE_STATUS_NOSTATUS), openStatus(0), closed_(false), context_(context)
111     {
112     }
113 
IsClosed()114     bool IsClosed()
115     {
116         std::lock_guard<std::mutex> lock(mutex_);
117         return closed_;
118     }
119 
Close(lws_close_status status,const std::string & reason)120     void Close(lws_close_status status, const std::string &reason)
121     {
122         std::lock_guard<std::mutex> lock(mutex_);
123         closeStatus = status;
124         closeReason = reason;
125         closed_ = true;
126     }
127 
Push(void * data,size_t length,lws_write_protocol protocol)128     void Push(void *data, size_t length, lws_write_protocol protocol)
129     {
130         std::lock_guard<std::mutex> lock(mutex_);
131         dataQueue_.push(SendData(data, length, protocol));
132     }
133 
Pop()134     SendData Pop()
135     {
136         std::lock_guard<std::mutex> lock(mutex_);
137         if (dataQueue_.empty()) {
138             return {nullptr, 0, LWS_WRITE_TEXT};
139         }
140         SendData data = dataQueue_.front();
141         dataQueue_.pop();
142         return data;
143     }
144 
SetContext(lws_context * context)145     void SetContext(lws_context *context)
146     {
147         context_ = context;
148     }
149 
GetContext()150     lws_context *GetContext()
151     {
152         return context_;
153     }
154 
155     std::map<std::string, std::string> header;
156 
157     lws_close_status closeStatus;
158 
159     std::string closeReason;
160 
161     uint32_t openStatus;
162 
163     std::string openMessage;
164 
165 private:
166     volatile bool closed_;
167 
168     std::mutex mutex_;
169 
170     lws_context *context_;
171 
172     std::queue<SendData> dataQueue_;
173 };
174 
CallbackTemplate(uv_work_t * work,int status)175 template <napi_value (*MakeJsValue)(napi_env, void *)> static void CallbackTemplate(uv_work_t *work, int status)
176 {
177     (void)status;
178 
179     auto workWrapper = static_cast<UvWorkWrapper *>(work->data);
180     napi_env env = workWrapper->env;
181     auto closeScope = [env](napi_handle_scope scope) { NapiUtils::CloseScope(env, scope); };
182     std::unique_ptr<napi_handle_scope__, decltype(closeScope)> scope(NapiUtils::OpenScope(env), closeScope);
183 
184     napi_value obj = MakeJsValue(env, workWrapper->data);
185 
186     std::pair<napi_value, napi_value> arg = {NapiUtils::GetUndefined(workWrapper->env), obj};
187     workWrapper->manager->Emit(workWrapper->type, arg);
188 
189     delete workWrapper;
190     delete work;
191 }
192 
ParseUrl(ConnectContext * context,char * prefix,size_t prefixLen,char * address,size_t addressLen,char * path,size_t pathLen,int * port)193 bool WebSocketExec::ParseUrl(ConnectContext *context,
194                              char *prefix,
195                              size_t prefixLen,
196                              char *address,
197                              size_t addressLen,
198                              char *path,
199                              size_t pathLen,
200                              int *port)
201 {
202     char uri[MAX_URI_LENGTH] = {0};
203     if (strcpy_s(uri, MAX_URI_LENGTH, context->url.c_str()) < 0) {
204         NETSTACK_LOGE("strcpy_s failed");
205         return false;
206     }
207     const char *tempPrefix = nullptr;
208     const char *tempAddress = nullptr;
209     const char *tempPath = nullptr;
210     (void)lws_parse_uri(uri, &tempPrefix, &tempAddress, port, &tempPath);
211     if (strcpy_s(prefix, prefixLen, tempPrefix) < 0) {
212         NETSTACK_LOGE("strcpy_s failed");
213         return false;
214     }
215     if (strcpy_s(address, addressLen, tempAddress) < 0) {
216         NETSTACK_LOGE("strcpy_s failed");
217         return false;
218     }
219     if (strcpy_s(path, pathLen, tempPath) < 0) {
220         NETSTACK_LOGE("strcpy_s failed");
221         return false;
222     }
223     return true;
224 }
225 
RunService(EventManager * manager)226 void WebSocketExec::RunService(EventManager *manager)
227 {
228     NETSTACK_LOGI("start service");
229     if (manager == nullptr || manager->GetData() == nullptr) {
230         NETSTACK_LOGE("RunService para error");
231         return;
232     }
233     auto userData = reinterpret_cast<UserData *>(manager->GetData());
234     lws_context *context = userData->GetContext();
235     if (context == nullptr) {
236         NETSTACK_LOGE("context is null");
237         return;
238     }
239     while (lws_service(context, 0) >= 0) {
240     }
241     lws_context_destroy(context);
242     userData->SetContext(nullptr);
243     delete userData;
244     manager->SetData(nullptr);
245     NETSTACK_LOGI("websocket end run service");
246 }
247 
RaiseError(EventManager * manager)248 int WebSocketExec::RaiseError(EventManager *manager)
249 {
250     OnError(manager, COMMON_ERROR_CODE);
251     return -1;
252 }
253 
HttpDummy(lws * wsi,lws_callback_reasons reason,void * user,void * in,size_t len)254 int WebSocketExec::HttpDummy(lws *wsi, lws_callback_reasons reason, void *user, void *in, size_t len)
255 {
256     int ret = lws_callback_http_dummy(wsi, reason, user, in, len);
257     if (ret < 0) {
258         OnError(reinterpret_cast<EventManager *>(user), COMMON_ERROR_CODE);
259     }
260     return ret;
261 }
262 
LwsCallbackClientAppendHandshakeHeader(lws * wsi,lws_callback_reasons reason,void * user,void * in,size_t len)263 int WebSocketExec::LwsCallbackClientAppendHandshakeHeader(lws *wsi,
264                                                           lws_callback_reasons reason,
265                                                           void *user,
266                                                           void *in,
267                                                           size_t len)
268 {
269     NETSTACK_LOGI("LwsCallbackClientAppendHandshakeHeader");
270     auto manager = reinterpret_cast<EventManager *>(user);
271     if (manager->GetData() == nullptr) {
272         NETSTACK_LOGE("user data is null");
273         return RaiseError(manager);
274     }
275     auto userData = reinterpret_cast<UserData *>(manager->GetData());
276 
277     auto payload = reinterpret_cast<unsigned char **>(in);
278     if (payload == nullptr || (*payload) == nullptr || len == 0) {
279         NETSTACK_LOGE("header payload is null, do not append header");
280         return RaiseError(manager);
281     }
282     auto payloadEnd = (*payload) + len;
283     for (const auto &pair : userData->header) {
284         std::string name = pair.first + NAME_END;
285         if (lws_add_http_header_by_name(wsi, reinterpret_cast<const unsigned char *>(name.c_str()),
286                                         reinterpret_cast<const unsigned char *>(pair.second.c_str()),
287                                         static_cast<int>(strlen(pair.second.c_str())), payload, payloadEnd)) {
288             NETSTACK_LOGE("add header failed");
289             return RaiseError(manager);
290         }
291     }
292     NETSTACK_LOGI("add header OK");
293     return HttpDummy(wsi, reason, user, in, len);
294 }
295 
LwsCallbackWsPeerInitiatedClose(lws * wsi,lws_callback_reasons reason,void * user,void * in,size_t len)296 int WebSocketExec::LwsCallbackWsPeerInitiatedClose(lws *wsi,
297                                                    lws_callback_reasons reason,
298                                                    void *user,
299                                                    void *in,
300                                                    size_t len)
301 {
302     NETSTACK_LOGI("LwsCallbackWsPeerInitiatedClose");
303     auto manager = reinterpret_cast<EventManager *>(user);
304     if (manager->GetData() == nullptr) {
305         NETSTACK_LOGE("user data is null");
306         return RaiseError(manager);
307     }
308     auto userData = reinterpret_cast<UserData *>(manager->GetData());
309 
310     if (in == nullptr || len < sizeof(uint16_t)) {
311         NETSTACK_LOGI("No close reason");
312         userData->Close(LWS_CLOSE_STATUS_NORMAL, "");
313         return HttpDummy(wsi, reason, user, in, len);
314     }
315 
316     uint16_t closeStatus = ntohs(*reinterpret_cast<uint16_t *>(in));
317     std::string closeReason;
318     closeReason.append(reinterpret_cast<char *>(in) + sizeof(uint16_t), len - sizeof(uint16_t));
319     userData->Close(static_cast<lws_close_status>(closeStatus), closeReason);
320     return HttpDummy(wsi, reason, user, in, len);
321 }
322 
LwsCallbackClientWritable(lws * wsi,lws_callback_reasons reason,void * user,void * in,size_t len)323 int WebSocketExec::LwsCallbackClientWritable(lws *wsi, lws_callback_reasons reason, void *user, void *in, size_t len)
324 {
325     auto manager = reinterpret_cast<EventManager *>(user);
326     if (manager->GetData() == nullptr) {
327         NETSTACK_LOGE("user data is null");
328         return RaiseError(manager);
329     }
330     auto userData = reinterpret_cast<UserData *>(manager->GetData());
331     if (userData->IsClosed()) {
332         NETSTACK_LOGI("need to close");
333         lws_close_reason(wsi, userData->closeStatus,
334                          reinterpret_cast<unsigned char *>(const_cast<char *>(userData->closeReason.c_str())),
335                          strlen(userData->closeReason.c_str()));
336         // here do not emit error, because we close it
337         return -1;
338     }
339 
340     auto sendData = userData->Pop();
341     if (sendData.data == nullptr || sendData.length == 0) {
342         return HttpDummy(wsi, reason, user, in, len);
343     }
344     int sendLength = lws_write(wsi, reinterpret_cast<unsigned char *>(sendData.data) + LWS_SEND_BUFFER_PRE_PADDING,
345                                sendData.length, sendData.protocol);
346     free(sendData.data);
347     NETSTACK_LOGI("send data length = %{public}d", sendLength);
348     return HttpDummy(wsi, reason, user, in, len);
349 }
350 
LwsCallbackClientConnectionError(lws * wsi,lws_callback_reasons reason,void * user,void * in,size_t len)351 int WebSocketExec::LwsCallbackClientConnectionError(lws *wsi,
352                                                     lws_callback_reasons reason,
353                                                     void *user,
354                                                     void *in,
355                                                     size_t len)
356 {
357     NETSTACK_LOGI("LwsCallbackClientConnectionError %{public}s",
358                   (in == nullptr) ? "null" : reinterpret_cast<char *>(in));
359     return HttpDummy(wsi, reason, user, in, len);
360 }
361 
LwsCallbackClientReceive(lws * wsi,lws_callback_reasons reason,void * user,void * in,size_t len)362 int WebSocketExec::LwsCallbackClientReceive(lws *wsi, lws_callback_reasons reason, void *user, void *in, size_t len)
363 {
364     NETSTACK_LOGI("LwsCallbackClientReceive");
365     OnMessage(reinterpret_cast<EventManager *>(user), in, len, lws_frame_is_binary(wsi));
366     return HttpDummy(wsi, reason, user, in, len);
367 }
368 
LwsCallbackClientFilterPreEstablish(lws * wsi,lws_callback_reasons reason,void * user,void * in,size_t len)369 int WebSocketExec::LwsCallbackClientFilterPreEstablish(lws *wsi,
370                                                        lws_callback_reasons reason,
371                                                        void *user,
372                                                        void *in,
373                                                        size_t len)
374 {
375     NETSTACK_LOGI("LwsCallbackClientFilterPreEstablish");
376     auto manager = reinterpret_cast<EventManager *>(user);
377     if (manager->GetData() == nullptr) {
378         NETSTACK_LOGE("user data is null");
379         return RaiseError(manager);
380     }
381     auto userData = reinterpret_cast<UserData *>(manager->GetData());
382 
383     userData->openStatus = lws_http_client_http_response(wsi);
384     char statusLine[MAX_HDR_LENGTH] = {0};
385     if (lws_hdr_copy(wsi, statusLine, MAX_HDR_LENGTH, WSI_TOKEN_HTTP) || strlen(statusLine) == 0) {
386         return HttpDummy(wsi, reason, user, in, len);
387     }
388 
389     auto vec = CommonUtils::Split(statusLine, STATUS_LINE_SEP, STATUS_LINE_ELEM_NUM);
390     if (vec.size() >= FUNCTION_PARAM_TWO) {
391         userData->openMessage = vec[1];
392     }
393 
394     return HttpDummy(wsi, reason, user, in, len);
395 }
396 
LwsCallbackClientEstablished(lws * wsi,lws_callback_reasons reason,void * user,void * in,size_t len)397 int WebSocketExec::LwsCallbackClientEstablished(lws *wsi, lws_callback_reasons reason, void *user, void *in, size_t len)
398 {
399     NETSTACK_LOGI("LwsCallbackClientEstablished");
400     auto manager = reinterpret_cast<EventManager *>(user);
401     if (manager->GetData() == nullptr) {
402         NETSTACK_LOGE("user data is null");
403         return RaiseError(manager);
404     }
405     auto userData = reinterpret_cast<UserData *>(manager->GetData());
406 
407     OnOpen(reinterpret_cast<EventManager *>(user), userData->openStatus, userData->openMessage);
408     return HttpDummy(wsi, reason, user, in, len);
409 }
410 
LwsCallbackClientClosed(lws * wsi,lws_callback_reasons reason,void * user,void * in,size_t len)411 int WebSocketExec::LwsCallbackClientClosed(lws *wsi, lws_callback_reasons reason, void *user, void *in, size_t len)
412 {
413     NETSTACK_LOGI("LwsCallbackClientClosed");
414     auto manager = reinterpret_cast<EventManager *>(user);
415     if (manager->GetData() == nullptr) {
416         NETSTACK_LOGE("user data is null");
417         return RaiseError(manager);
418     }
419     auto userData = reinterpret_cast<UserData *>(manager->GetData());
420 
421     OnClose(reinterpret_cast<EventManager *>(user), userData->closeStatus, userData->closeReason);
422     return HttpDummy(wsi, reason, user, in, len);
423 }
424 
LwsCallbackWsiDestroy(lws * wsi,lws_callback_reasons reason,void * user,void * in,size_t len)425 int WebSocketExec::LwsCallbackWsiDestroy(lws *wsi, lws_callback_reasons reason, void *user, void *in, size_t len)
426 {
427     NETSTACK_LOGI("LwsCallbackWsiDestroy");
428     return HttpDummy(wsi, reason, user, in, len);
429 }
430 
LwsCallbackProtocolDestroy(lws * wsi,lws_callback_reasons reason,void * user,void * in,size_t len)431 int WebSocketExec::LwsCallbackProtocolDestroy(lws *wsi, lws_callback_reasons reason, void *user, void *in, size_t len)
432 {
433     NETSTACK_LOGI("LwsCallbackProtocolDestroy");
434     return HttpDummy(wsi, reason, user, in, len);
435 }
436 
LwsCallback(lws * wsi,lws_callback_reasons reason,void * user,void * in,size_t len)437 int WebSocketExec::LwsCallback(lws *wsi, lws_callback_reasons reason, void *user, void *in, size_t len)
438 {
439     CallbackDispatcher dispatchers[] = {
440         {LWS_CALLBACK_CLIENT_APPEND_HANDSHAKE_HEADER, LwsCallbackClientAppendHandshakeHeader},
441         {LWS_CALLBACK_WS_PEER_INITIATED_CLOSE, LwsCallbackWsPeerInitiatedClose},
442         {LWS_CALLBACK_CLIENT_WRITEABLE, LwsCallbackClientWritable},
443         {LWS_CALLBACK_CLIENT_CONNECTION_ERROR, LwsCallbackClientConnectionError},
444         {LWS_CALLBACK_CLIENT_RECEIVE, LwsCallbackClientReceive},
445         {LWS_CALLBACK_CLIENT_FILTER_PRE_ESTABLISH, LwsCallbackClientFilterPreEstablish},
446         {LWS_CALLBACK_CLIENT_ESTABLISHED, LwsCallbackClientEstablished},
447         {LWS_CALLBACK_CLIENT_CLOSED, LwsCallbackClientClosed},
448         {LWS_CALLBACK_WSI_DESTROY, LwsCallbackWsiDestroy},
449         {LWS_CALLBACK_PROTOCOL_DESTROY, LwsCallbackProtocolDestroy},
450     };
451 
452     for (const auto dispatcher : dispatchers) {
453         if (dispatcher.reason == reason) {
454             return dispatcher.callback(wsi, reason, user, in, len);
455         }
456     }
457 
458     return HttpDummy(wsi, reason, user, in, len);
459 }
460 
FillContextInfo(lws_context_creation_info & info)461 static inline void FillContextInfo(lws_context_creation_info &info)
462 {
463     info.options = LWS_SERVER_OPTION_DO_SSL_GLOBAL_INIT;
464     info.port = CONTEXT_PORT_NO_LISTEN;
465     info.protocols = LWS_PROTOCOLS;
466     info.fd_limit_per_thread = FD_LIMIT_PER_THREAD;
467 }
468 
ExecConnect(ConnectContext * context)469 bool WebSocketExec::ExecConnect(ConnectContext *context)
470 {
471     if (context == nullptr) {
472         NETSTACK_LOGE("context is nullptr");
473         return false;
474     }
475     if (!CommonUtils::HasInternetPermission()) {
476         context->SetPermissionDenied(true);
477         return false;
478     }
479 
480     NETSTACK_LOGI("begin connect, parse url");
481     if (context->GetManager() == nullptr) {
482         return false;
483     }
484     char prefix[MAX_URI_LENGTH] = {0};
485     char address[MAX_URI_LENGTH] = {0};
486     char pathWithoutStart[MAX_URI_LENGTH] = {0};
487     int port = 0;
488     if (!ParseUrl(context, prefix, MAX_URI_LENGTH, address, MAX_URI_LENGTH, pathWithoutStart, MAX_URI_LENGTH, &port)) {
489         NETSTACK_LOGE("ParseUrl failed");
490         return false;
491     }
492     std::string path = PATH_START + std::string(pathWithoutStart);
493 
494     lws_context_creation_info info = {0};
495     FillContextInfo(info);
496     lws_context *lwsContext = lws_create_context(&info);
497     if (lwsContext == nullptr) {
498         NETSTACK_LOGE("no memory");
499         return false;
500     }
501 
502     lws_client_connect_info connectInfo = {nullptr};
503     connectInfo.context = lwsContext;
504     connectInfo.port = port;
505     connectInfo.address = address;
506     connectInfo.path = path.c_str();
507     connectInfo.host = address;
508     connectInfo.origin = address;
509     if (strcmp(prefix, PREFIX_HTTPS) == 0 || strcmp(prefix, PREFIX_WSS) == 0) {
510         connectInfo.ssl_connection =
511             LCCSCF_USE_SSL | LCCSCF_SKIP_SERVER_CERT_HOSTNAME_CHECK | LCCSCF_ALLOW_INSECURE | LCCSCF_ALLOW_SELFSIGNED;
512     }
513     lws *wsi = nullptr;
514     connectInfo.pwsi = &wsi;
515     connectInfo.retry_and_idle_policy = &RETRY;
516     auto manager = context->GetManager();
517     if (manager != nullptr && manager->GetData() == nullptr) {
518         auto userData = new UserData(lwsContext);
519         userData->header = context->header;
520         manager->SetData(userData);
521     }
522     connectInfo.userdata = reinterpret_cast<void *>(manager);
523     if (lws_client_connect_via_info(&connectInfo) == nullptr) {
524         NETSTACK_LOGI("ExecConnect websocket connect failed");
525         context->SetErrorCode(-1);
526         // here return true, means that connection failed but no error happened during exec
527         lws_context_destroy(lwsContext);
528         return true;
529     }
530 
531     std::thread serviceThread(RunService, manager);
532     serviceThread.detach();
533     return true;
534 }
535 
ConnectCallback(ConnectContext * context)536 napi_value WebSocketExec::ConnectCallback(ConnectContext *context)
537 {
538     if (context->GetErrorCode() < 0) {
539         NETSTACK_LOGI("ConnectCallback connect failed");
540         return NapiUtils::GetBoolean(context->GetEnv(), false);
541     }
542     NETSTACK_LOGI("ConnectCallback connect success");
543     return NapiUtils::GetBoolean(context->GetEnv(), true);
544 }
545 
ExecSend(SendContext * context)546 bool WebSocketExec::ExecSend(SendContext *context)
547 {
548     if (context == nullptr) {
549         NETSTACK_LOGE("context is nullptr");
550         return false;
551     }
552     if (!CommonUtils::HasInternetPermission()) {
553         context->SetPermissionDenied(true);
554         return false;
555     }
556 
557     if (context->GetManager() == nullptr) {
558         NETSTACK_LOGE("context is null");
559         return false;
560     }
561 
562     auto manager = context->GetManager();
563     auto userData = reinterpret_cast<UserData *>(manager->GetData());
564     if (userData == nullptr) {
565         NETSTACK_LOGE("user data is null");
566         return false;
567     }
568 
569     userData->Push(context->data, context->length, context->protocol);
570     NETSTACK_LOGI("ExecSend OK");
571     return true;
572 }
573 
SendCallback(SendContext * context)574 napi_value WebSocketExec::SendCallback(SendContext *context)
575 {
576     NETSTACK_LOGI("SendCallback success");
577     return NapiUtils::GetBoolean(context->GetEnv(), true);
578 }
579 
ExecClose(CloseContext * context)580 bool WebSocketExec::ExecClose(CloseContext *context)
581 {
582     if (context == nullptr) {
583         NETSTACK_LOGE("context is nullptr");
584         return false;
585     }
586     if (!CommonUtils::HasInternetPermission()) {
587         context->SetPermissionDenied(true);
588         return false;
589     }
590 
591     if (context->GetManager() == nullptr) {
592         NETSTACK_LOGE("context is null");
593         return false;
594     }
595 
596     auto manager = context->GetManager();
597     auto userData = reinterpret_cast<UserData *>(manager->GetData());
598     if (userData == nullptr) {
599         NETSTACK_LOGE("user data is null");
600         return false;
601     }
602 
603     userData->Close(static_cast<lws_close_status>(context->code), context->reason);
604     NETSTACK_LOGI("ExecClose OK");
605     return true;
606 }
607 
CloseCallback(CloseContext * context)608 napi_value WebSocketExec::CloseCallback(CloseContext *context)
609 {
610     NETSTACK_LOGI("CloseCallback success");
611     return NapiUtils::GetBoolean(context->GetEnv(), true);
612 }
613 
CreateError(napi_env env,void * callbackPara)614 static napi_value CreateError(napi_env env, void *callbackPara)
615 {
616     auto code = reinterpret_cast<int32_t *>(callbackPara);
617     auto deleter = [](const int32_t *p) { delete p; };
618     std::unique_ptr<int32_t, decltype(deleter)> handler(code, deleter);
619     napi_value err = NapiUtils::CreateObject(env);
620     if (NapiUtils::GetValueType(env, err) != napi_object) {
621         return NapiUtils::GetUndefined(env);
622     }
623     NapiUtils::SetInt32Property(env, err, EVENT_KEY_CODE, *code);
624     return err;
625 }
626 
CreateOpenPara(napi_env env,void * callbackPara)627 static napi_value CreateOpenPara(napi_env env, void *callbackPara)
628 {
629     auto para = reinterpret_cast<OnOpenClosePara *>(callbackPara);
630     auto deleter = [](const OnOpenClosePara *p) { delete p; };
631     std::unique_ptr<OnOpenClosePara, decltype(deleter)> handler(para, deleter);
632     napi_value obj = NapiUtils::CreateObject(env);
633     if (NapiUtils::GetValueType(env, obj) != napi_object) {
634         return NapiUtils::GetUndefined(env);
635     }
636     NapiUtils::SetUint32Property(env, obj, EVENT_KEY_STATUS, para->status);
637     NapiUtils::SetStringPropertyUtf8(env, obj, EVENT_KEY_MESSAGE, para->message);
638     return obj;
639 }
640 
CreateClosePara(napi_env env,void * callbackPara)641 static napi_value CreateClosePara(napi_env env, void *callbackPara)
642 {
643     auto para = reinterpret_cast<OnOpenClosePara *>(callbackPara);
644     auto deleter = [](const OnOpenClosePara *p) { delete p; };
645     std::unique_ptr<OnOpenClosePara, decltype(deleter)> handler(para, deleter);
646     napi_value obj = NapiUtils::CreateObject(env);
647     if (NapiUtils::GetValueType(env, obj) != napi_object) {
648         return NapiUtils::GetUndefined(env);
649     }
650     NapiUtils::SetUint32Property(env, obj, EVENT_KEY_CODE, para->status);
651     NapiUtils::SetStringPropertyUtf8(env, obj, EVENT_KEY_REASON, para->message);
652     return obj;
653 }
654 
CreateMessagePara(napi_env env,void * callbackPara)655 static napi_value CreateMessagePara(napi_env env, void *callbackPara)
656 {
657     auto para = reinterpret_cast<OnMessagePara *>(callbackPara);
658     auto deleter = [](const OnMessagePara *p) { delete p; };
659     std::unique_ptr<OnMessagePara, decltype(deleter)> handler(para, deleter);
660     if (!para->isBinary) {
661         std::string str;
662         str.append(reinterpret_cast<char *>(para->data), para->length);
663         return NapiUtils::CreateStringUtf8(env, str);
664     }
665 
666     void *data = nullptr;
667     napi_value arrayBuffer = NapiUtils::CreateArrayBuffer(env, para->length, &data);
668     if (data != nullptr && NapiUtils::ValueIsArrayBuffer(env, arrayBuffer) &&
669         memcpy_s(data, para->length, para->data, para->length) >= 0) {
670         return arrayBuffer;
671     }
672     return NapiUtils::GetUndefined(env);
673 }
674 
OnError(EventManager * manager,int32_t code)675 void WebSocketExec::OnError(EventManager *manager, int32_t code)
676 {
677     NETSTACK_LOGI("OnError %{public}d", code);
678     if (manager == nullptr) {
679         NETSTACK_LOGE("manager is null");
680         return;
681     }
682     if (!manager->HasEventListener(EventName::EVENT_ERROR)) {
683         NETSTACK_LOGI("no event listener: %{public}s", EventName::EVENT_ERROR);
684         return;
685     }
686     manager->EmitByUv(EventName::EVENT_ERROR, new int32_t(code), CallbackTemplate<CreateError>);
687 }
688 
OnOpen(EventManager * manager,uint32_t status,const std::string & message)689 void WebSocketExec::OnOpen(EventManager *manager, uint32_t status, const std::string &message)
690 {
691     NETSTACK_LOGI("OnOpen %{public}u %{public}s", status, message.c_str());
692     if (manager == nullptr) {
693         NETSTACK_LOGE("manager is null");
694         return;
695     }
696     if (!manager->HasEventListener(EventName::EVENT_OPEN)) {
697         NETSTACK_LOGI("no event listener: %{public}s", EventName::EVENT_OPEN);
698         return;
699     }
700     auto para = new OnOpenClosePara;
701     para->status = status;
702     para->message = message;
703     manager->EmitByUv(EventName::EVENT_OPEN, para, CallbackTemplate<CreateOpenPara>);
704 }
705 
OnClose(EventManager * manager,lws_close_status closeStatus,const std::string & closeReason)706 void WebSocketExec::OnClose(EventManager *manager, lws_close_status closeStatus, const std::string &closeReason)
707 {
708     NETSTACK_LOGI("OnClose %{public}u %{public}s", closeStatus, closeReason.c_str());
709     if (manager == nullptr) {
710         NETSTACK_LOGE("manager is null");
711         return;
712     }
713     if (!manager->HasEventListener(EventName::EVENT_CLOSE)) {
714         NETSTACK_LOGI("no event listener: %{public}s", EventName::EVENT_CLOSE);
715         return;
716     }
717     auto para = new OnOpenClosePara;
718     para->status = closeStatus;
719     para->message = closeReason;
720     manager->EmitByUv(EventName::EVENT_CLOSE, para, CallbackTemplate<CreateClosePara>);
721 }
722 
OnMessage(EventManager * manager,void * data,size_t length,bool isBinary)723 void WebSocketExec::OnMessage(EventManager *manager, void *data, size_t length, bool isBinary)
724 {
725     NETSTACK_LOGI("OnMessage %{public}d", isBinary);
726     if (manager == nullptr) {
727         NETSTACK_LOGE("manager is null");
728         return;
729     }
730     if (!manager->HasEventListener(EventName::EVENT_MESSAGE)) {
731         NETSTACK_LOGI("no event listener: %{public}s", EventName::EVENT_MESSAGE);
732         return;
733     }
734     if (length > INT32_MAX) {
735         NETSTACK_LOGE("data length too long");
736         return;
737     }
738     auto para = new OnMessagePara;
739     // para->data will free on OnMessagePara destructor, so there is no memory leak problem.
740     para->data = malloc(length);
741     if (para->data == nullptr) {
742         delete para;
743         NETSTACK_LOGE("no memory");
744         return;
745     }
746     if (memcpy_s(para->data, length, data, length) < 0) {
747         delete para;
748         NETSTACK_LOGE("mem copy failed");
749         return;
750     }
751     para->length = length;
752     para->isBinary = isBinary;
753     manager->EmitByUv(EventName::EVENT_MESSAGE, para, CallbackTemplate<CreateMessagePara>);
754 }
755 } // namespace OHOS::NetStack
756