• 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 
CreateConnectError(napi_env env,void * callbackPara)351 static napi_value CreateConnectError(napi_env env, void *callbackPara)
352 {
353     auto code = reinterpret_cast<int32_t *>(callbackPara);
354     auto deleter = [](const int32_t *p) { delete p; };
355     std::unique_ptr<int32_t, decltype(deleter)> handler(code, deleter);
356     napi_value err = NapiUtils::CreateObject(env);
357     if (NapiUtils::GetValueType(env, err) != napi_object) {
358         return NapiUtils::GetUndefined(env);
359     }
360     NapiUtils::SetInt32Property(env, err, EVENT_KEY_CODE, *code);
361     return err;
362 }
363 
OnConnectError(EventManager * manager,int32_t code)364 void OnConnectError(EventManager *manager, int32_t code)
365 {
366     NETSTACK_LOGI("OnError %{public}d", code);
367     if (manager == nullptr) {
368         NETSTACK_LOGE("manager is null");
369         return;
370     }
371     if (!manager->HasEventListener(EventName::EVENT_ERROR)) {
372         NETSTACK_LOGI("no event listener: %{public}s", EventName::EVENT_ERROR);
373         return;
374     }
375     manager->EmitByUv(EventName::EVENT_ERROR, new int32_t(code), CallbackTemplate<CreateConnectError>);
376 }
377 
LwsCallbackClientConnectionError(lws * wsi,lws_callback_reasons reason,void * user,void * in,size_t len)378 int WebSocketExec::LwsCallbackClientConnectionError(lws *wsi,
379                                                     lws_callback_reasons reason,
380                                                     void *user,
381                                                     void *in,
382                                                     size_t len)
383 {
384     NETSTACK_LOGI("LwsCallbackClientConnectionError %{public}s",
385                   (in == nullptr) ? "null" : reinterpret_cast<char *>(in));
386     // 200 means connect failed
387     OnConnectError(reinterpret_cast<EventManager *>(user), COMMON_ERROR_CODE);
388     return HttpDummy(wsi, reason, user, in, len);
389 }
390 
LwsCallbackClientReceive(lws * wsi,lws_callback_reasons reason,void * user,void * in,size_t len)391 int WebSocketExec::LwsCallbackClientReceive(lws *wsi, lws_callback_reasons reason, void *user, void *in, size_t len)
392 {
393     NETSTACK_LOGI("LwsCallbackClientReceive");
394     OnMessage(reinterpret_cast<EventManager *>(user), in, len, lws_frame_is_binary(wsi));
395     return HttpDummy(wsi, reason, user, in, len);
396 }
397 
LwsCallbackClientFilterPreEstablish(lws * wsi,lws_callback_reasons reason,void * user,void * in,size_t len)398 int WebSocketExec::LwsCallbackClientFilterPreEstablish(lws *wsi,
399                                                        lws_callback_reasons reason,
400                                                        void *user,
401                                                        void *in,
402                                                        size_t len)
403 {
404     NETSTACK_LOGI("LwsCallbackClientFilterPreEstablish");
405     auto manager = reinterpret_cast<EventManager *>(user);
406     if (manager->GetData() == nullptr) {
407         NETSTACK_LOGE("user data is null");
408         return RaiseError(manager);
409     }
410     auto userData = reinterpret_cast<UserData *>(manager->GetData());
411 
412     userData->openStatus = lws_http_client_http_response(wsi);
413     char statusLine[MAX_HDR_LENGTH] = {0};
414     if (lws_hdr_copy(wsi, statusLine, MAX_HDR_LENGTH, WSI_TOKEN_HTTP) || strlen(statusLine) == 0) {
415         return HttpDummy(wsi, reason, user, in, len);
416     }
417 
418     auto vec = CommonUtils::Split(statusLine, STATUS_LINE_SEP, STATUS_LINE_ELEM_NUM);
419     if (vec.size() >= FUNCTION_PARAM_TWO) {
420         userData->openMessage = vec[1];
421     }
422 
423     return HttpDummy(wsi, reason, user, in, len);
424 }
425 
LwsCallbackClientEstablished(lws * wsi,lws_callback_reasons reason,void * user,void * in,size_t len)426 int WebSocketExec::LwsCallbackClientEstablished(lws *wsi, lws_callback_reasons reason, void *user, void *in, size_t len)
427 {
428     NETSTACK_LOGI("LwsCallbackClientEstablished");
429     auto manager = reinterpret_cast<EventManager *>(user);
430     if (manager->GetData() == nullptr) {
431         NETSTACK_LOGE("user data is null");
432         return RaiseError(manager);
433     }
434     auto userData = reinterpret_cast<UserData *>(manager->GetData());
435 
436     OnOpen(reinterpret_cast<EventManager *>(user), userData->openStatus, userData->openMessage);
437     return HttpDummy(wsi, reason, user, in, len);
438 }
439 
LwsCallbackClientClosed(lws * wsi,lws_callback_reasons reason,void * user,void * in,size_t len)440 int WebSocketExec::LwsCallbackClientClosed(lws *wsi, lws_callback_reasons reason, void *user, void *in, size_t len)
441 {
442     NETSTACK_LOGI("LwsCallbackClientClosed");
443     auto manager = reinterpret_cast<EventManager *>(user);
444     if (manager->GetData() == nullptr) {
445         NETSTACK_LOGE("user data is null");
446         return RaiseError(manager);
447     }
448     auto userData = reinterpret_cast<UserData *>(manager->GetData());
449 
450     OnClose(reinterpret_cast<EventManager *>(user), userData->closeStatus, userData->closeReason);
451     return HttpDummy(wsi, reason, user, in, len);
452 }
453 
LwsCallbackWsiDestroy(lws * wsi,lws_callback_reasons reason,void * user,void * in,size_t len)454 int WebSocketExec::LwsCallbackWsiDestroy(lws *wsi, lws_callback_reasons reason, void *user, void *in, size_t len)
455 {
456     NETSTACK_LOGI("LwsCallbackWsiDestroy");
457     return HttpDummy(wsi, reason, user, in, len);
458 }
459 
LwsCallbackProtocolDestroy(lws * wsi,lws_callback_reasons reason,void * user,void * in,size_t len)460 int WebSocketExec::LwsCallbackProtocolDestroy(lws *wsi, lws_callback_reasons reason, void *user, void *in, size_t len)
461 {
462     NETSTACK_LOGI("LwsCallbackProtocolDestroy");
463     return HttpDummy(wsi, reason, user, in, len);
464 }
465 
LwsCallback(lws * wsi,lws_callback_reasons reason,void * user,void * in,size_t len)466 int WebSocketExec::LwsCallback(lws *wsi, lws_callback_reasons reason, void *user, void *in, size_t len)
467 {
468     CallbackDispatcher dispatchers[] = {
469         {LWS_CALLBACK_CLIENT_APPEND_HANDSHAKE_HEADER, LwsCallbackClientAppendHandshakeHeader},
470         {LWS_CALLBACK_WS_PEER_INITIATED_CLOSE, LwsCallbackWsPeerInitiatedClose},
471         {LWS_CALLBACK_CLIENT_WRITEABLE, LwsCallbackClientWritable},
472         {LWS_CALLBACK_CLIENT_CONNECTION_ERROR, LwsCallbackClientConnectionError},
473         {LWS_CALLBACK_CLIENT_RECEIVE, LwsCallbackClientReceive},
474         {LWS_CALLBACK_CLIENT_FILTER_PRE_ESTABLISH, LwsCallbackClientFilterPreEstablish},
475         {LWS_CALLBACK_CLIENT_ESTABLISHED, LwsCallbackClientEstablished},
476         {LWS_CALLBACK_CLIENT_CLOSED, LwsCallbackClientClosed},
477         {LWS_CALLBACK_WSI_DESTROY, LwsCallbackWsiDestroy},
478         {LWS_CALLBACK_PROTOCOL_DESTROY, LwsCallbackProtocolDestroy},
479     };
480 
481     for (const auto dispatcher : dispatchers) {
482         if (dispatcher.reason == reason) {
483             return dispatcher.callback(wsi, reason, user, in, len);
484         }
485     }
486 
487     return HttpDummy(wsi, reason, user, in, len);
488 }
489 
FillContextInfo(lws_context_creation_info & info)490 static inline void FillContextInfo(lws_context_creation_info &info)
491 {
492     info.options = LWS_SERVER_OPTION_DO_SSL_GLOBAL_INIT;
493     info.port = CONTEXT_PORT_NO_LISTEN;
494     info.protocols = LWS_PROTOCOLS;
495     info.fd_limit_per_thread = FD_LIMIT_PER_THREAD;
496 }
497 
ExecConnect(ConnectContext * context)498 bool WebSocketExec::ExecConnect(ConnectContext *context)
499 {
500     if (!CommonUtils::HasInternetPermission()) {
501         context->SetPermissionDenied(true);
502         return false;
503     }
504     if (context == nullptr) {
505         NETSTACK_LOGE("context is nullptr");
506         return false;
507     }
508     NETSTACK_LOGI("begin connect, parse url");
509     if (context->GetManager() == nullptr) {
510         return false;
511     }
512     char prefix[MAX_URI_LENGTH] = {0};
513     char address[MAX_URI_LENGTH] = {0};
514     char pathWithoutStart[MAX_URI_LENGTH] = {0};
515     int port = 0;
516     if (!ParseUrl(context, prefix, MAX_URI_LENGTH, address, MAX_URI_LENGTH, pathWithoutStart, MAX_URI_LENGTH, &port)) {
517         NETSTACK_LOGE("ParseUrl failed");
518         return false;
519     }
520     std::string path = PATH_START + std::string(pathWithoutStart);
521 
522     lws_context_creation_info info = {0};
523     FillContextInfo(info);
524     lws_context *lwsContext = lws_create_context(&info);
525     if (lwsContext == nullptr) {
526         NETSTACK_LOGE("no memory");
527         return false;
528     }
529 
530     lws_client_connect_info connectInfo = {nullptr};
531     connectInfo.context = lwsContext;
532     connectInfo.port = port;
533     connectInfo.address = address;
534     connectInfo.path = path.c_str();
535     connectInfo.host = address;
536     connectInfo.origin = address;
537     if (strcmp(prefix, PREFIX_HTTPS) == 0 || strcmp(prefix, PREFIX_WSS) == 0) {
538         connectInfo.ssl_connection =
539             LCCSCF_USE_SSL | LCCSCF_SKIP_SERVER_CERT_HOSTNAME_CHECK | LCCSCF_ALLOW_INSECURE | LCCSCF_ALLOW_SELFSIGNED;
540     }
541     lws *wsi = nullptr;
542     connectInfo.pwsi = &wsi;
543     connectInfo.retry_and_idle_policy = &RETRY;
544     auto manager = context->GetManager();
545     if (manager != nullptr && manager->GetData() == nullptr) {
546         auto userData = new UserData(lwsContext);
547         userData->header = context->header;
548         manager->SetData(userData);
549     }
550     connectInfo.userdata = reinterpret_cast<void *>(manager);
551     if (lws_client_connect_via_info(&connectInfo) == nullptr) {
552         NETSTACK_LOGI("ExecConnect websocket connect failed");
553         context->SetErrorCode(-1);
554         lws_context_destroy(lwsContext);
555         return false;
556     }
557 
558     std::thread serviceThread(RunService, manager);
559     serviceThread.detach();
560     return true;
561 }
562 
ConnectCallback(ConnectContext * context)563 napi_value WebSocketExec::ConnectCallback(ConnectContext *context)
564 {
565     if (context->GetErrorCode() < 0) {
566         NETSTACK_LOGI("ConnectCallback connect failed");
567         return NapiUtils::GetBoolean(context->GetEnv(), false);
568     }
569     NETSTACK_LOGI("ConnectCallback connect success");
570     return NapiUtils::GetBoolean(context->GetEnv(), true);
571 }
572 
ExecSend(SendContext * context)573 bool WebSocketExec::ExecSend(SendContext *context)
574 {
575     if (!CommonUtils::HasInternetPermission()) {
576         context->SetPermissionDenied(true);
577         return false;
578     }
579     if (context == nullptr) {
580         NETSTACK_LOGE("context is nullptr");
581         return false;
582     }
583     if (context->GetManager() == nullptr) {
584         NETSTACK_LOGE("context is null");
585         return false;
586     }
587 
588     auto manager = context->GetManager();
589     auto userData = reinterpret_cast<UserData *>(manager->GetData());
590     if (userData == nullptr) {
591         NETSTACK_LOGE("user data is null");
592         return false;
593     }
594 
595     userData->Push(context->data, context->length, context->protocol);
596     NETSTACK_LOGI("ExecSend OK");
597     return true;
598 }
599 
SendCallback(SendContext * context)600 napi_value WebSocketExec::SendCallback(SendContext *context)
601 {
602     NETSTACK_LOGI("SendCallback success");
603     return NapiUtils::GetBoolean(context->GetEnv(), true);
604 }
605 
ExecClose(CloseContext * context)606 bool WebSocketExec::ExecClose(CloseContext *context)
607 {
608     if (!CommonUtils::HasInternetPermission()) {
609         context->SetPermissionDenied(true);
610         return false;
611     }
612     if (context == nullptr) {
613         NETSTACK_LOGE("context is nullptr");
614         return false;
615     }
616 
617     if (context->GetManager() == nullptr) {
618         NETSTACK_LOGE("context is null");
619         return false;
620     }
621 
622     auto manager = context->GetManager();
623     auto userData = reinterpret_cast<UserData *>(manager->GetData());
624     if (userData == nullptr) {
625         NETSTACK_LOGE("user data is null");
626         return false;
627     }
628 
629     userData->Close(static_cast<lws_close_status>(context->code), context->reason);
630     NETSTACK_LOGI("ExecClose OK");
631     return true;
632 }
633 
CloseCallback(CloseContext * context)634 napi_value WebSocketExec::CloseCallback(CloseContext *context)
635 {
636     NETSTACK_LOGI("CloseCallback success");
637     return NapiUtils::GetBoolean(context->GetEnv(), true);
638 }
639 
CreateError(napi_env env,void * callbackPara)640 static napi_value CreateError(napi_env env, void *callbackPara)
641 {
642     auto code = reinterpret_cast<int32_t *>(callbackPara);
643     auto deleter = [](const int32_t *p) { delete p; };
644     std::unique_ptr<int32_t, decltype(deleter)> handler(code, deleter);
645     napi_value err = NapiUtils::CreateObject(env);
646     if (NapiUtils::GetValueType(env, err) != napi_object) {
647         return NapiUtils::GetUndefined(env);
648     }
649     NapiUtils::SetInt32Property(env, err, EVENT_KEY_CODE, *code);
650     return err;
651 }
652 
CreateOpenPara(napi_env env,void * callbackPara)653 static napi_value CreateOpenPara(napi_env env, void *callbackPara)
654 {
655     auto para = reinterpret_cast<OnOpenClosePara *>(callbackPara);
656     auto deleter = [](const OnOpenClosePara *p) { delete p; };
657     std::unique_ptr<OnOpenClosePara, decltype(deleter)> handler(para, deleter);
658     napi_value obj = NapiUtils::CreateObject(env);
659     if (NapiUtils::GetValueType(env, obj) != napi_object) {
660         return NapiUtils::GetUndefined(env);
661     }
662     NapiUtils::SetUint32Property(env, obj, EVENT_KEY_STATUS, para->status);
663     NapiUtils::SetStringPropertyUtf8(env, obj, EVENT_KEY_MESSAGE, para->message);
664     return obj;
665 }
666 
CreateClosePara(napi_env env,void * callbackPara)667 static napi_value CreateClosePara(napi_env env, void *callbackPara)
668 {
669     auto para = reinterpret_cast<OnOpenClosePara *>(callbackPara);
670     auto deleter = [](const OnOpenClosePara *p) { delete p; };
671     std::unique_ptr<OnOpenClosePara, decltype(deleter)> handler(para, deleter);
672     napi_value obj = NapiUtils::CreateObject(env);
673     if (NapiUtils::GetValueType(env, obj) != napi_object) {
674         return NapiUtils::GetUndefined(env);
675     }
676     NapiUtils::SetUint32Property(env, obj, EVENT_KEY_CODE, para->status);
677     NapiUtils::SetStringPropertyUtf8(env, obj, EVENT_KEY_REASON, para->message);
678     return obj;
679 }
680 
CreateMessagePara(napi_env env,void * callbackPara)681 static napi_value CreateMessagePara(napi_env env, void *callbackPara)
682 {
683     auto para = reinterpret_cast<OnMessagePara *>(callbackPara);
684     auto deleter = [](const OnMessagePara *p) { delete p; };
685     std::unique_ptr<OnMessagePara, decltype(deleter)> handler(para, deleter);
686     if (!para->isBinary) {
687         std::string str;
688         str.append(reinterpret_cast<char *>(para->data), para->length);
689         return NapiUtils::CreateStringUtf8(env, str);
690     }
691 
692     void *data = nullptr;
693     napi_value arrayBuffer = NapiUtils::CreateArrayBuffer(env, para->length, &data);
694     if (data != nullptr && NapiUtils::ValueIsArrayBuffer(env, arrayBuffer) &&
695         memcpy_s(data, para->length, para->data, para->length) >= 0) {
696         return arrayBuffer;
697     }
698     return NapiUtils::GetUndefined(env);
699 }
700 
OnError(EventManager * manager,int32_t code)701 void WebSocketExec::OnError(EventManager *manager, int32_t code)
702 {
703     NETSTACK_LOGI("OnError %{public}d", code);
704     if (manager == nullptr) {
705         NETSTACK_LOGE("manager is null");
706         return;
707     }
708     if (!manager->HasEventListener(EventName::EVENT_ERROR)) {
709         NETSTACK_LOGI("no event listener: %{public}s", EventName::EVENT_ERROR);
710         return;
711     }
712     manager->EmitByUv(EventName::EVENT_ERROR, new int32_t(code), CallbackTemplate<CreateError>);
713 }
714 
OnOpen(EventManager * manager,uint32_t status,const std::string & message)715 void WebSocketExec::OnOpen(EventManager *manager, uint32_t status, const std::string &message)
716 {
717     NETSTACK_LOGI("OnOpen %{public}u %{public}s", status, message.c_str());
718     if (manager == nullptr) {
719         NETSTACK_LOGE("manager is null");
720         return;
721     }
722     if (!manager->HasEventListener(EventName::EVENT_OPEN)) {
723         NETSTACK_LOGI("no event listener: %{public}s", EventName::EVENT_OPEN);
724         return;
725     }
726     auto para = new OnOpenClosePara;
727     para->status = status;
728     para->message = message;
729     manager->EmitByUv(EventName::EVENT_OPEN, para, CallbackTemplate<CreateOpenPara>);
730 }
731 
OnClose(EventManager * manager,lws_close_status closeStatus,const std::string & closeReason)732 void WebSocketExec::OnClose(EventManager *manager, lws_close_status closeStatus, const std::string &closeReason)
733 {
734     NETSTACK_LOGI("OnClose %{public}u %{public}s", closeStatus, closeReason.c_str());
735     if (manager == nullptr) {
736         NETSTACK_LOGE("manager is null");
737         return;
738     }
739     if (!manager->HasEventListener(EventName::EVENT_CLOSE)) {
740         NETSTACK_LOGI("no event listener: %{public}s", EventName::EVENT_CLOSE);
741         return;
742     }
743     auto para = new OnOpenClosePara;
744     para->status = closeStatus;
745     para->message = closeReason;
746     manager->EmitByUv(EventName::EVENT_CLOSE, para, CallbackTemplate<CreateClosePara>);
747 }
748 
OnMessage(EventManager * manager,void * data,size_t length,bool isBinary)749 void WebSocketExec::OnMessage(EventManager *manager, void *data, size_t length, bool isBinary)
750 {
751     NETSTACK_LOGI("OnMessage %{public}d", isBinary);
752     if (manager == nullptr) {
753         NETSTACK_LOGE("manager is null");
754         return;
755     }
756     if (!manager->HasEventListener(EventName::EVENT_MESSAGE)) {
757         NETSTACK_LOGI("no event listener: %{public}s", EventName::EVENT_MESSAGE);
758         return;
759     }
760     if (length > INT32_MAX) {
761         NETSTACK_LOGE("data length too long");
762         return;
763     }
764     auto para = new OnMessagePara;
765     // para->data will free on OnMessagePara destructor, so there is no memory leak problem.
766     para->data = malloc(length);
767     if (para->data == nullptr) {
768         delete para;
769         NETSTACK_LOGE("no memory");
770         return;
771     }
772     if (memcpy_s(para->data, length, data, length) < 0) {
773         delete para;
774         NETSTACK_LOGE("mem copy failed");
775         return;
776     }
777     para->length = length;
778     para->isBinary = isBinary;
779     manager->EmitByUv(EventName::EVENT_MESSAGE, para, CallbackTemplate<CreateMessagePara>);
780 }
781 } // namespace OHOS::NetStack
782