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