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