1 /*
2 * Copyright (c) 2025 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 "net_websocket_exec.h"
17
18 #include <atomic>
19 #include <memory>
20 #include <queue>
21 #include <thread>
22 #include <unistd.h>
23
24 #include "libwebsockets.h"
25 #include "net_websocket_base_context.h"
26 #include "net_websocket_impl.h"
27 #include "securec.h"
28 #include "net_websocket_utils.h"
29 #include "netstack_common_utils.h"
30 #include "netstack_log.h"
31
32 #ifdef HAS_NETMANAGER_BASE
33 #include "http_proxy.h"
34 #include "net_conn_client.h"
35 #endif
36
37 static constexpr const char *PROTOCOL_DELIMITER = "//";
38 static constexpr const char *NAME_END = ":";
39 static constexpr const char *STATUS_LINE_SEP = " ";
40 static constexpr const size_t STATUS_LINE_ELEM_NUM = 2;
41 static constexpr const char *PREFIX_HTTPS = "https";
42 static constexpr const char *PREFIX_WSS = "wss";
43 static constexpr const char *PREFIX_WS = "ws";
44 static constexpr const int MAX_URI_LENGTH = 1024;
45 static constexpr const int MAX_HDR_LENGTH = 1024;
46 static constexpr const int MAX_PROTOCOL_LENGTH = 1024;
47 static constexpr const int MAX_ADDRESS_LENGTH = 1024;
48 static constexpr const int FD_LIMIT_PER_THREAD = 1 + 1 + 1;
49 static constexpr const int COMMON_ERROR_CODE = 200;
50 static constexpr const char *LINK_DOWN = "The link is down";
51 static constexpr const int32_t UID_TRANSFORM_DIVISOR = 200000;
52 static constexpr const char *BASE_PATH = "/data/certificates/user_cacerts/";
53 static constexpr const char *WEBSOCKET_SYSTEM_PREPARE_CA_PATH = "/etc/security/certificates";
54 static constexpr const int FUNCTION_PARAM_TWO = 2;
55 static constexpr const char *WEBSOCKET_CLIENT_THREAD_RUN = "OS_NET_WSJsCli";
56
57 static const std::vector<std::string> WS_PREFIX = {PREFIX_WSS, PREFIX_WS};
58
59 namespace OHOS::NetStack::NetWebSocket {
60 static const lws_protocols WEBSOCKET_PROTOCOLS[] = {
61 {"lws-minimal-client-cj", NetWebSocketExec::LwsCallback, 0, 0},
62 {nullptr, nullptr, 0, 0}, // this line is needed
63 };
64
65 static const lws_retry_bo_t RETRY = {
66 .secs_since_valid_ping = 30, /* force PINGs after secs idle */
67 .secs_since_valid_hangup = 60, /* hangup after secs idle */
68 .jitter_percent = 20,
69 };
70
71 struct CallbackDispatcher {
72 lws_callback_reasons reason;
73 int (*callback)(lws *wsi, lws_callback_reasons reason, void *user, void *in, size_t len);
74 };
75
76
77 class WebSocketContext {
78 public:
79 struct SendData {
SendDataOHOS::NetStack::NetWebSocket::WebSocketContext::SendData80 SendData(void *paraData, size_t paraLength, lws_write_protocol paraProtocol)
81 : data(paraData), length(paraLength), protocol(paraProtocol)
82 {
83 }
84
85 SendData() = delete;
86
87 ~SendData() = default;
88
89 void *data;
90 size_t length;
91 lws_write_protocol protocol;
92 };
93
WebSocketContext(lws_context * context)94 explicit WebSocketContext(lws_context *context)
95 : closeStatus(LWS_CLOSE_STATUS_NOSTATUS), openStatus(0), closed_(false), threadStop_(false), context_(context)
96 {
97 }
98
IsClosed()99 bool IsClosed()
100 {
101 std::lock_guard<std::mutex> lock(mutex_);
102 return closed_;
103 }
104
IsThreadStop()105 bool IsThreadStop()
106 {
107 return threadStop_.load();
108 }
109
SetThreadStop(bool threadStop)110 void SetThreadStop(bool threadStop)
111 {
112 threadStop_.store(threadStop);
113 }
114
Close(lws_close_status status,const std::string & reason)115 void Close(lws_close_status status, const std::string &reason)
116 {
117 std::lock_guard<std::mutex> lock(mutex_);
118 closeStatus = status;
119 closeReason = reason;
120 closed_ = true;
121 }
122
Push(void * data,size_t length,lws_write_protocol protocol)123 void Push(void *data, size_t length, lws_write_protocol protocol)
124 {
125 std::lock_guard<std::mutex> lock(mutex_);
126 dataQueue_.emplace(data, length, protocol);
127 }
128
Pop()129 SendData Pop()
130 {
131 std::lock_guard<std::mutex> lock(mutex_);
132 if (dataQueue_.empty()) {
133 return {nullptr, 0, LWS_WRITE_TEXT};
134 }
135 SendData data = dataQueue_.front();
136 dataQueue_.pop();
137 return data;
138 }
139
SetContext(lws_context * context)140 void SetContext(lws_context *context)
141 {
142 context_ = context;
143 }
144
GetContext()145 lws_context *GetContext()
146 {
147 return context_;
148 }
149
IsEmpty()150 bool IsEmpty()
151 {
152 std::lock_guard<std::mutex> lock(mutex_);
153 if (dataQueue_.empty()) {
154 return true;
155 }
156 return false;
157 }
158
SetLws(lws * wsi)159 void SetLws(lws *wsi)
160 {
161 std::lock_guard<std::mutex> lock(mutexForLws_);
162 if (wsi == nullptr) {
163 NETSTACK_LOGD("set wsi nullptr");
164 }
165 wsi_ = wsi;
166 }
167
TriggerWritable()168 void TriggerWritable()
169 {
170 std::lock_guard<std::mutex> lock(mutexForLws_);
171 if (wsi_ == nullptr) {
172 NETSTACK_LOGE("wsi is nullptr, can not trigger");
173 return;
174 }
175 lws_callback_on_writable(wsi_);
176 }
177
178 std::map<std::string, std::string> header;
179
180 lws_close_status closeStatus;
181
182 std::string closeReason;
183
184 uint32_t openStatus;
185
186 std::string openMessage;
187
188 private:
189 volatile bool closed_;
190
191 std::atomic_bool threadStop_;
192
193 std::mutex mutex_;
194
195 std::mutex mutexForLws_;
196
197 lws_context *context_;
198
199 std::queue<SendData> dataQueue_;
200
201 lws *wsi_ = nullptr;
202 };
203
CreateOpenPara(uint32_t status,const std::string & message)204 static uint8_t* CreateOpenPara(uint32_t status, const std::string &message)
205 {
206 COpenResponse* res = new COpenResponse;
207 res->status = status;
208 res->message = MallocCString(message);
209 return reinterpret_cast<uint8_t*>(res);
210 }
211
CreateClosePara(uint32_t code,const std::string & reason)212 static uint8_t* CreateClosePara(uint32_t code, const std::string &reason)
213 {
214 CCloseResponse* res = new CCloseResponse;
215 res->code = code;
216 res->reason = MallocCString(reason);
217 return reinterpret_cast<uint8_t*>(res);
218 }
219
CreateMessagePara(CJWebsocketProxy * websocketProxy,bool isBinary)220 static uint8_t* CreateMessagePara(CJWebsocketProxy *websocketProxy, bool isBinary)
221 {
222 CMessageResponse* res = new CMessageResponse;
223 res->resultType = isBinary ? ARRAY_BUFFER : STRING;
224 auto msg = reinterpret_cast<std::string *>(websocketProxy->GetQueueData());
225 if (!msg) {
226 NETSTACK_LOGE("msg is nullptr");
227 delete res;
228 return nullptr;
229 }
230 CArrUI8 body;
231 body.head = reinterpret_cast<uint8_t*>(MallocCString(*msg));
232 body.size = static_cast<int64_t>(msg->size());
233 res->result = body;
234 return reinterpret_cast<uint8_t*>(res);
235 }
236
CreateResponseHeader(const std::map<std::string,std::string> & headers)237 static uint8_t* CreateResponseHeader(const std::map<std::string, std::string> &headers)
238 {
239 CReceiveResponse* res = new CReceiveResponse;
240 if (headers.empty()) {
241 res->headerType = UNDEFINED;
242 res->header.head = nullptr;
243 res->header.size = 0;
244 }
245 res->headerType = MAP;
246 res->header = Map2CArrString(headers);
247 return reinterpret_cast<uint8_t*>(res);
248 }
249
CreateError(int32_t code,uint32_t httpResponse)250 static uint8_t* CreateError(int32_t code, uint32_t httpResponse)
251 {
252 CErrorResponse* res = new CErrorResponse;
253 res->code = code;
254 res->httpResponse = httpResponse;
255 return reinterpret_cast<uint8_t*>(res);
256 }
257
OnConnectError(CJWebsocketProxy * websocketProxy,int32_t code,uint32_t httpResponse)258 void OnConnectError(CJWebsocketProxy *websocketProxy, int32_t code, uint32_t httpResponse)
259 {
260 NETSTACK_LOGI("OnConnectError code is %{public}d, httpResponse is %{public}d", code, httpResponse);
261 if (websocketProxy == nullptr) {
262 NETSTACK_LOGE("websocketProxy is null");
263 return;
264 }
265 if (auto webSocketContext = websocketProxy->GetWebSocketContext(); webSocketContext != nullptr) {
266 NETSTACK_LOGI("OnConnectError SetThreadStop");
267 webSocketContext->SetThreadStop(true);
268 }
269 if (websocketProxy->FindCallback(EVENT_OPEN) == std::nullopt) {
270 NETSTACK_LOGI("no event listener: ERROR");
271 return;
272 }
273 CWebSocketCallbackData* para = new CWebSocketCallbackData;
274 para->code = ERR_OK;
275 para->typeId = EVENT_ERROR;
276 para->data = CreateError(code, httpResponse);
277 para->dataLen = sizeof(CErrorResponse);
278 websocketProxy->EmitCallBack(para);
279 delete reinterpret_cast<CErrorResponse*>(para->data);
280 delete para;
281 }
282
CreatConnectInfo(WebSocketConnectContext * context,lws_context * lwsContext,CJWebsocketProxy * websocketProxy)283 bool NetWebSocketExec::CreatConnectInfo(WebSocketConnectContext *context,
284 lws_context *lwsContext, CJWebsocketProxy *websocketProxy)
285 {
286 lws_client_connect_info connectInfo = {};
287 char protocol[MAX_URI_LENGTH] = {0};
288 char address[MAX_URI_LENGTH] = {0};
289 char path[MAX_URI_LENGTH] = {0};
290 char customizedProtocol[MAX_PROTOCOL_LENGTH] = {0};
291 int port = 0;
292
293 if (!ParseUrl(context, protocol, MAX_URI_LENGTH, address, MAX_URI_LENGTH, path, MAX_URI_LENGTH, &port)) {
294 NETSTACK_LOGE("ParseUrl failed");
295 context->SetErrorCode(WEBSOCKET_ERROR_CODE_URL_ERROR);
296 return false;
297 }
298 if (lwsContext == nullptr) {
299 NETSTACK_LOGE("no memory");
300 return false;
301 }
302 std::string tempHost = std::string(address) + NAME_END + std::to_string(port);
303 std::string tempOrigin = std::string(protocol) + NAME_END + PROTOCOL_DELIMITER + tempHost;
304 NETSTACK_LOGD("tempOrigin = %{private}s", tempOrigin.c_str());
305 if (strcpy_s(customizedProtocol, context->GetProtocol().length() + 1, context->GetProtocol().c_str()) != ERR_OK) {
306 NETSTACK_LOGE("memory copy failed");
307 }
308
309 connectInfo.context = lwsContext;
310 connectInfo.port = port;
311 connectInfo.address = address;
312 connectInfo.path = path;
313 connectInfo.host = address;
314 connectInfo.origin = address;
315 connectInfo.protocol = customizedProtocol;
316
317 if (strcmp(protocol, PREFIX_HTTPS) == 0 || strcmp(protocol, PREFIX_WSS) == 0) {
318 connectInfo.ssl_connection = LCCSCF_USE_SSL | LCCSCF_SKIP_SERVER_CERT_HOSTNAME_CHECK | LCCSCF_ALLOW_SELFSIGNED;
319 }
320 lws *wsi = nullptr;
321 connectInfo.pwsi = &wsi;
322 connectInfo.retry_and_idle_policy = &RETRY;
323 connectInfo.userdata = websocketProxy;
324 if (lws_client_connect_via_info(&connectInfo) == nullptr) {
325 NETSTACK_LOGI("ExecConnect websocket connect failed");
326 context->SetErrorCode(-1);
327 OnConnectError(websocketProxy, COMMON_ERROR_CODE, 0);
328 return false;
329 }
330 return true;
331 }
332
RunService(std::shared_ptr<WebSocketContext> webSocketContext,CJWebsocketProxy * websocketProxy)333 void RunService(std::shared_ptr<WebSocketContext> webSocketContext, CJWebsocketProxy* websocketProxy)
334 {
335 NETSTACK_LOGI("websocket run service start");
336 int res = 0;
337 lws_context *context = webSocketContext->GetContext();
338 if (context == nullptr) {
339 NETSTACK_LOGE("context is null");
340 return;
341 }
342 while (res >= 0 && !webSocketContext->IsThreadStop()) {
343 res = lws_service(context, 0);
344 }
345 lws_context_destroy(context);
346 webSocketContext->SetContext(nullptr);
347 websocketProxy->SetWebSocketContext(nullptr);
348 NETSTACK_LOGI("websocket run service end");
349 }
350
351
ExecConnect(WebSocketConnectContext * context)352 bool NetWebSocketExec::ExecConnect(WebSocketConnectContext *context)
353 {
354 NETSTACK_LOGD("websocket Connect exec");
355 if (context == nullptr) {
356 NETSTACK_LOGE("context is nullptr");
357 return false;
358 }
359 if (!CommonUtils::HasInternetPermission()) {
360 context->SetPermissionDenied(true);
361 return false;
362 }
363
364 auto websocketProxy = context->GetWebsocketProxy();
365 if (websocketProxy == nullptr) {
366 return false;
367 }
368 lws_context_creation_info info = {};
369 char proxyAds[MAX_ADDRESS_LENGTH] = {0};
370 FillContextInfo(context, info, proxyAds);
371 if (!FillCaPath(context, info)) {
372 return false;
373 }
374 lws_context *lwsContext = nullptr;
375 std::shared_ptr<WebSocketContext> webSocketContext;
376 if (websocketProxy->GetWebSocketContext() == nullptr) {
377 lwsContext = lws_create_context(&info);
378 webSocketContext = std::make_shared<WebSocketContext>(lwsContext);
379 webSocketContext->header = context->header;
380 websocketProxy->SetWebSocketContext(webSocketContext);
381 } else {
382 NETSTACK_LOGE("Websocket connect already exist");
383 context->SetErrorCode(WEBSOCKET_ERROR_CODE_CONNECT_AlREADY_EXIST);
384 return false;
385 }
386 if (!CreatConnectInfo(context, lwsContext, websocketProxy)) {
387 webSocketContext->SetContext(nullptr);
388 lws_context_destroy(lwsContext);
389 websocketProxy->SetWebSocketContext(nullptr);
390 return false;
391 }
392 std::thread serviceThread(RunService, webSocketContext, websocketProxy);
393
394 #if defined(MAC_PLATFORM) || defined(IOS_PLATFORM)
395 pthread_setname_np(WEBSOCKET_CLIENT_THREAD_RUN);
396 #else
397 pthread_setname_np(serviceThread.native_handle(), WEBSOCKET_CLIENT_THREAD_RUN);
398 #endif
399 serviceThread.detach();
400 return true;
401 }
402
ExecSend(WebSocketSendContext * context)403 bool NetWebSocketExec::ExecSend(WebSocketSendContext *context)
404 {
405 if (context == nullptr) {
406 NETSTACK_LOGE("context is nullptr");
407 return false;
408 }
409 if (!CommonUtils::HasInternetPermission()) {
410 context->SetPermissionDenied(true);
411 return false;
412 }
413 auto websocketProxy = context->GetWebsocketProxy();
414 if (websocketProxy == nullptr) {
415 NETSTACK_LOGE("context is null");
416 return false;
417 }
418 auto webSocketContext = websocketProxy->GetWebSocketContext();
419 if (webSocketContext == nullptr) {
420 NETSTACK_LOGE("user data is nullptr");
421 return false;
422 }
423 if (webSocketContext->IsClosed() || webSocketContext->IsThreadStop()) {
424 NETSTACK_LOGE("session is closed or stopped");
425 return false;
426 }
427 webSocketContext->Push(context->data, context->length, context->protocol);
428 webSocketContext->TriggerWritable();
429 NETSTACK_LOGD("lws ts send success");
430 return true;
431 }
432
ExecClose(WebSocketCloseContext * context)433 bool NetWebSocketExec::ExecClose(WebSocketCloseContext *context)
434 {
435 if (context == nullptr) {
436 NETSTACK_LOGE("context is nullptr");
437 return false;
438 }
439 if (!CommonUtils::HasInternetPermission()) {
440 context->SetPermissionDenied(true);
441 return false;
442 }
443 if (context->GetWebsocketProxy() == nullptr) {
444 NETSTACK_LOGE("context is null");
445 return false;
446 }
447
448 auto websocketProxy = context->GetWebsocketProxy();
449 auto webSocketContext = websocketProxy->GetWebSocketContext();
450 if (webSocketContext == nullptr) {
451 NETSTACK_LOGE("user data is nullptr");
452 return false;
453 }
454
455 if (webSocketContext->IsClosed()) {
456 NETSTACK_LOGE("connection has been closed");
457 return false;
458 }
459 webSocketContext->Close(static_cast<lws_close_status>(context->code), context->reason);
460 webSocketContext->TriggerWritable();
461 NETSTACK_LOGI("ExecClose OK");
462 return true;
463 }
464
ParseUrl(WebSocketConnectContext * context,char * protocol,size_t protocolLen,char * address,size_t addressLen,char * path,size_t pathLen,int * port)465 bool NetWebSocketExec::ParseUrl(WebSocketConnectContext *context, char *protocol, size_t protocolLen, char *address,
466 size_t addressLen, char *path, size_t pathLen, int *port)
467 {
468 char uri[MAX_URI_LENGTH] = {0};
469 if (strcpy_s(uri, MAX_URI_LENGTH, context->url.c_str()) < 0) {
470 NETSTACK_LOGE("strcpy_s failed");
471 return false;
472 }
473 const char *tempProt = nullptr;
474 const char *tempAddress = nullptr;
475 const char *tempPath = nullptr;
476 (void)lws_parse_uri(uri, &tempProt, &tempAddress, port, &tempPath);
477 if (strcpy_s(protocol, protocolLen, tempProt) < 0) {
478 NETSTACK_LOGE("strcpy_s failed");
479 return false;
480 }
481 if (std::find(WS_PREFIX.begin(), WS_PREFIX.end(), protocol) == WS_PREFIX.end()) {
482 NETSTACK_LOGE("protocol failed");
483 return false;
484 }
485 if (strcpy_s(address, addressLen, tempAddress) < 0) {
486 NETSTACK_LOGE("strcpy_s failed");
487 return false;
488 }
489 if (strcpy_s(path, pathLen, tempPath) < 0) {
490 NETSTACK_LOGE("strcpy_s failed");
491 return false;
492 }
493 return true;
494 }
495
RaiseError(CJWebsocketProxy * websocketProxy,uint32_t httpResponse)496 int NetWebSocketExec::RaiseError(CJWebsocketProxy *websocketProxy, uint32_t httpResponse)
497 {
498 OnError(websocketProxy, COMMON_ERROR_CODE, httpResponse);
499 return -1;
500 }
501
LwsCallback(lws * wsi,lws_callback_reasons reason,void * user,void * in,size_t len)502 int NetWebSocketExec::LwsCallback(lws *wsi, lws_callback_reasons reason, void *user, void *in, size_t len)
503 {
504 NETSTACK_LOGI("lws callback reason is %{public}d", reason);
505 CallbackDispatcher dispatchers[] = {
506 {LWS_CALLBACK_CLIENT_APPEND_HANDSHAKE_HEADER, LwsCallbackClientAppendHandshakeHeader},
507 {LWS_CALLBACK_WS_PEER_INITIATED_CLOSE, LwsCallbackWsPeerInitiatedClose},
508 {LWS_CALLBACK_CLIENT_WRITEABLE, LwsCallbackClientWritable},
509 {LWS_CALLBACK_CLIENT_CONNECTION_ERROR, LwsCallbackClientConnectionError},
510 {LWS_CALLBACK_CLIENT_RECEIVE, LwsCallbackClientReceive},
511 {LWS_CALLBACK_CLIENT_FILTER_PRE_ESTABLISH, LwsCallbackClientFilterPreEstablish},
512 {LWS_CALLBACK_CLIENT_ESTABLISHED, LwsCallbackClientEstablished},
513 {LWS_CALLBACK_CLIENT_CLOSED, LwsCallbackClientClosed},
514 {LWS_CALLBACK_WSI_DESTROY, LwsCallbackWsiDestroy},
515 {LWS_CALLBACK_PROTOCOL_DESTROY, LwsCallbackProtocolDestroy},
516 {LWS_CALLBACK_VHOST_CERT_AGING, LwsCallbackVhostCertAging},
517 };
518
519 for (const auto dispatcher : dispatchers) {
520 if (dispatcher.reason == reason) {
521 return dispatcher.callback(wsi, reason, user, in, len);
522 }
523 }
524
525 return HttpDummy(wsi, reason, user, in, len);
526 }
527
HttpDummy(lws * wsi,lws_callback_reasons reason,void * user,void * in,size_t len)528 int NetWebSocketExec::HttpDummy(lws *wsi, lws_callback_reasons reason, void *user, void *in, size_t len)
529 {
530 int ret = lws_callback_http_dummy(wsi, reason, user, in, len);
531 if (ret < 0) {
532 OnError(reinterpret_cast<CJWebsocketProxy *>(user), COMMON_ERROR_CODE, GetHttpResponseFromWsi(wsi));
533 }
534 return 0;
535 }
536
LwsCallbackClientAppendHandshakeHeader(lws * wsi,lws_callback_reasons reason,void * user,void * in,size_t len)537 int NetWebSocketExec::LwsCallbackClientAppendHandshakeHeader(lws *wsi, lws_callback_reasons reason,
538 void *user, void *in, size_t len)
539 {
540 NETSTACK_LOGD("lws callback client append handshake header");
541 auto websocketProxy = reinterpret_cast<CJWebsocketProxy *>(user);
542 auto webSocketContext = websocketProxy->GetWebSocketContext();
543 if (webSocketContext == nullptr) {
544 NETSTACK_LOGE("user data is null");
545 return RaiseError(websocketProxy, GetHttpResponseFromWsi(wsi));
546 }
547
548 auto payload = reinterpret_cast<unsigned char **>(in);
549 if (payload == nullptr || (*payload) == nullptr || len == 0) {
550 NETSTACK_LOGE("header payload is null, do not append header");
551 return RaiseError(websocketProxy, GetHttpResponseFromWsi(wsi));
552 }
553 auto payloadEnd = (*payload) + len;
554 for (const auto &pair : webSocketContext->header) {
555 std::string name = pair.first + NAME_END;
556 if (lws_add_http_header_by_name(wsi, reinterpret_cast<const unsigned char *>(name.c_str()),
557 reinterpret_cast<const unsigned char *>(pair.second.c_str()),
558 static_cast<int>(strlen(pair.second.c_str())), payload, payloadEnd)) {
559 NETSTACK_LOGE("add header failed");
560 return RaiseError(websocketProxy, GetHttpResponseFromWsi(wsi));
561 }
562 }
563 NETSTACK_LOGI("add header OK");
564 return HttpDummy(wsi, reason, user, in, len);
565 }
566
LwsCallbackWsPeerInitiatedClose(lws * wsi,lws_callback_reasons reason,void * user,void * in,size_t len)567 int NetWebSocketExec::LwsCallbackWsPeerInitiatedClose(lws *wsi, lws_callback_reasons reason,
568 void *user, void *in, size_t len)
569 {
570 NETSTACK_LOGD("lws callback ws peer initiated close");
571 auto websocketProxy = reinterpret_cast<CJWebsocketProxy *>(user);
572 auto webSocketContext = websocketProxy->GetWebSocketContext();
573 if (webSocketContext == nullptr) {
574 NETSTACK_LOGE("user data is null");
575 return RaiseError(websocketProxy, GetHttpResponseFromWsi(wsi));
576 }
577
578 if (in == nullptr || len < sizeof(uint16_t)) {
579 NETSTACK_LOGI("No close reason");
580 webSocketContext->Close(LWS_CLOSE_STATUS_NORMAL, "");
581 return HttpDummy(wsi, reason, user, in, len);
582 }
583
584 uint16_t closeStatus = ntohs(*reinterpret_cast<uint16_t *>(in));
585 std::string closeReason;
586 closeReason.append(reinterpret_cast<char *>(in) + sizeof(uint16_t), len - sizeof(uint16_t));
587 webSocketContext->Close(static_cast<lws_close_status>(closeStatus), closeReason);
588 return HttpDummy(wsi, reason, user, in, len);
589 }
590
LwsCallbackClientWritable(lws * wsi,lws_callback_reasons reason,void * user,void * in,size_t len)591 int NetWebSocketExec::LwsCallbackClientWritable(lws *wsi, lws_callback_reasons reason, void *user, void *in, size_t len)
592 {
593 NETSTACK_LOGD("lws callback client writable");
594 auto websocketProxy = reinterpret_cast<CJWebsocketProxy *>(user);
595 auto webSocketContext = websocketProxy->GetWebSocketContext();
596 if (webSocketContext == nullptr) {
597 NETSTACK_LOGE("user data is null");
598 return RaiseError(websocketProxy, GetHttpResponseFromWsi(wsi));
599 }
600 if (webSocketContext->IsClosed()) {
601 NETSTACK_LOGI("need to close");
602 lws_close_reason(wsi, webSocketContext->closeStatus,
603 reinterpret_cast<unsigned char *>(const_cast<char *>(webSocketContext->closeReason.c_str())),
604 strlen(webSocketContext->closeReason.c_str()));
605 // here do not emit error, because we close it
606 return -1;
607 }
608 auto sendData = webSocketContext->Pop();
609 if (sendData.data == nullptr || sendData.length == 0) {
610 return HttpDummy(wsi, reason, user, in, len);
611 }
612 int sendLength = lws_write(wsi, reinterpret_cast<unsigned char *>(sendData.data) + LWS_SEND_BUFFER_PRE_PADDING,
613 sendData.length, sendData.protocol);
614 free(sendData.data);
615 NETSTACK_LOGD("lws send data length is %{public}d", sendLength);
616 if (!webSocketContext->IsEmpty()) {
617 lws_callback_on_writable(wsi);
618 }
619 return HttpDummy(wsi, reason, user, in, len);
620 }
621
LwsCallbackClientConnectionError(lws * wsi,lws_callback_reasons reason,void * user,void * in,size_t len)622 int NetWebSocketExec::LwsCallbackClientConnectionError(lws *wsi, lws_callback_reasons reason,
623 void *user, void *in, size_t len)
624 {
625 NETSTACK_LOGD("lws callback client connection error");
626 NETSTACK_LOGI("Lws client connection error %{public}s", (in == nullptr) ? "null" : reinterpret_cast<char *>(in));
627 // 200 means connect failed
628 OnConnectError(reinterpret_cast<CJWebsocketProxy *>(user), COMMON_ERROR_CODE, GetHttpResponseFromWsi(wsi));
629 return HttpDummy(wsi, reason, user, in, len);
630 }
631
LwsCallbackClientReceive(lws * wsi,lws_callback_reasons reason,void * user,void * in,size_t len)632 int NetWebSocketExec::LwsCallbackClientReceive(lws *wsi, lws_callback_reasons reason,
633 void *user, void *in, size_t len)
634 {
635 NETSTACK_LOGD("lws callback client receive");
636 auto websocketProxy = reinterpret_cast<CJWebsocketProxy *>(user);
637 auto isFinal = lws_is_final_fragment(wsi);
638 OnMessage(websocketProxy, in, len, lws_frame_is_binary(wsi), isFinal);
639 return HttpDummy(wsi, reason, user, in, len);
640 }
641
LwsCallbackClientFilterPreEstablish(lws * wsi,lws_callback_reasons reason,void * user,void * in,size_t len)642 int NetWebSocketExec::LwsCallbackClientFilterPreEstablish(lws *wsi, lws_callback_reasons reason,
643 void *user, void *in, size_t len)
644 {
645 NETSTACK_LOGD("lws callback client filter preEstablish");
646 auto websocketProxy = reinterpret_cast<CJWebsocketProxy *>(user);
647 auto webSocketContext = websocketProxy->GetWebSocketContext();
648 if (webSocketContext == nullptr) {
649 NETSTACK_LOGE("user data is null");
650 return RaiseError(websocketProxy, GetHttpResponseFromWsi(wsi));
651 }
652
653 webSocketContext->openStatus = GetHttpResponseFromWsi(wsi);
654 char statusLine[MAX_HDR_LENGTH] = {0};
655 if (lws_hdr_copy(wsi, statusLine, MAX_HDR_LENGTH, WSI_TOKEN_HTTP) < 0 || strlen(statusLine) == 0) {
656 return HttpDummy(wsi, reason, user, in, len);
657 }
658
659 auto vec = CommonUtils::Split(statusLine, STATUS_LINE_SEP, STATUS_LINE_ELEM_NUM);
660 if (vec.size() >= FUNCTION_PARAM_TWO) {
661 webSocketContext->openMessage = vec[1];
662 }
663
664 char buffer[MAX_HDR_LENGTH] = {};
665 std::map<std::string, std::string> responseHeader;
666 for (int i = 0; i < WSI_TOKEN_COUNT; i++) {
667 if (lws_hdr_total_length(wsi, static_cast<lws_token_indexes>(i)) > 0) {
668 lws_hdr_copy(wsi, buffer, sizeof(buffer), static_cast<lws_token_indexes>(i));
669 std::string str;
670 if (lws_token_to_string(static_cast<lws_token_indexes>(i))) {
671 str =
672 std::string(reinterpret_cast<const char *>(lws_token_to_string(static_cast<lws_token_indexes>(i))));
673 }
674 if (!str.empty() && str.back() == ':') {
675 responseHeader.emplace(str.substr(0, str.size() - 1), std::string(buffer));
676 }
677 }
678 }
679 lws_hdr_custom_name_foreach(
680 wsi,
681 [](const char *name, int nlen, void *opaque) -> void {
682 auto header = static_cast<std::map<std::string, std::string> *>(opaque);
683 if (header == nullptr) {
684 return;
685 }
686 header->emplace(std::string(name).substr(0, nlen - 1), std::string(name).substr(nlen));
687 },
688 &responseHeader);
689 OnHeaderReceive(websocketProxy, responseHeader);
690 return HttpDummy(wsi, reason, user, in, len);
691 }
692
LwsCallbackClientEstablished(lws * wsi,lws_callback_reasons reason,void * user,void * in,size_t len)693 int NetWebSocketExec::LwsCallbackClientEstablished(lws *wsi, lws_callback_reasons reason,
694 void *user, void *in, size_t len)
695 {
696 NETSTACK_LOGD("lws callback client established");
697 auto websocketProxy = reinterpret_cast<CJWebsocketProxy *>(user);
698 auto webSocketContext = websocketProxy->GetWebSocketContext();
699 if (webSocketContext == nullptr) {
700 NETSTACK_LOGE("user data is null");
701 return RaiseError(websocketProxy, GetHttpResponseFromWsi(wsi));
702 }
703 lws_callback_on_writable(wsi);
704 webSocketContext->SetLws(wsi);
705 OnOpen(reinterpret_cast<CJWebsocketProxy *>(user), webSocketContext->openStatus, webSocketContext->openMessage);
706 return HttpDummy(wsi, reason, user, in, len);
707 }
708
LwsCallbackClientClosed(lws * wsi,lws_callback_reasons reason,void * user,void * in,size_t len)709 int NetWebSocketExec::LwsCallbackClientClosed(lws *wsi, lws_callback_reasons reason, void *user, void *in, size_t len)
710 {
711 NETSTACK_LOGD("lws callback client closed");
712 auto websocketProxy = reinterpret_cast<CJWebsocketProxy *>(user);
713 auto webSocketContext = websocketProxy->GetWebSocketContext();
714 if (webSocketContext == nullptr) {
715 NETSTACK_LOGE("user data is null");
716 return RaiseError(websocketProxy, GetHttpResponseFromWsi(wsi));
717 }
718 webSocketContext->SetThreadStop(true);
719 if ((webSocketContext->closeReason).empty()) {
720 webSocketContext->Close(webSocketContext->closeStatus, LINK_DOWN);
721 }
722 if (webSocketContext->closeStatus == LWS_CLOSE_STATUS_NOSTATUS) {
723 NETSTACK_LOGE("The link is down, onError");
724 OnError(websocketProxy, COMMON_ERROR_CODE, GetHttpResponseFromWsi(wsi));
725 }
726 OnClose(reinterpret_cast<CJWebsocketProxy *>(user), webSocketContext->closeStatus, webSocketContext->closeReason);
727 return HttpDummy(wsi, reason, user, in, len);
728 }
729
LwsCallbackWsiDestroy(lws * wsi,lws_callback_reasons reason,void * user,void * in,size_t len)730 int NetWebSocketExec::LwsCallbackWsiDestroy(lws *wsi, lws_callback_reasons reason, void *user, void *in, size_t len)
731 {
732 NETSTACK_LOGD("lws callback wsi destroy");
733 auto websocketProxy = reinterpret_cast<CJWebsocketProxy *>(user);
734 if (websocketProxy == nullptr) {
735 NETSTACK_LOGE("websocketProxy is null");
736 return RaiseError(websocketProxy, GetHttpResponseFromWsi(wsi));
737 }
738 auto webSocketContext = websocketProxy->GetWebSocketContext();
739 if (webSocketContext == nullptr) {
740 NETSTACK_LOGE("user data is null");
741 return RaiseError(websocketProxy, GetHttpResponseFromWsi(wsi));
742 }
743 webSocketContext->SetLws(nullptr);
744 return HttpDummy(wsi, reason, user, in, len);
745 }
746
LwsCallbackProtocolDestroy(lws * wsi,lws_callback_reasons reason,void * user,void * in,size_t len)747 int NetWebSocketExec::LwsCallbackProtocolDestroy(lws *wsi, lws_callback_reasons reason,
748 void *user, void *in, size_t len)
749 {
750 NETSTACK_LOGD("lws callback protocol destroy");
751 return HttpDummy(wsi, reason, user, in, len);
752 }
753
LwsCallbackVhostCertAging(lws * wsi,lws_callback_reasons reason,void * user,void * in,size_t len)754 int NetWebSocketExec::LwsCallbackVhostCertAging(lws *wsi, lws_callback_reasons reason, void *user, void *in, size_t len)
755 {
756 NETSTACK_LOGI("lws callback vhost cert aging. len: %{public}zu", len);
757 return HttpDummy(wsi, reason, user, in, len);
758 }
759
FillContextInfo(WebSocketConnectContext * context,lws_context_creation_info & info,char * proxyAds)760 void NetWebSocketExec::FillContextInfo(WebSocketConnectContext *context,
761 lws_context_creation_info &info, char *proxyAds)
762 {
763 info.options = LWS_SERVER_OPTION_DO_SSL_GLOBAL_INIT;
764 info.port = CONTEXT_PORT_NO_LISTEN;
765 info.protocols = WEBSOCKET_PROTOCOLS;
766 info.fd_limit_per_thread = FD_LIMIT_PER_THREAD;
767
768 char tempUri[MAX_URI_LENGTH] = {0};
769 const char *tempProtocol = nullptr;
770 const char *tempAddress = nullptr;
771 const char *tempPath = nullptr;
772 int32_t tempPort = 0;
773
774 std::string host;
775 uint32_t port = 0;
776 std::string exclusions;
777
778 if (strcpy_s(tempUri, MAX_URI_LENGTH, context->url.c_str()) < 0) {
779 NETSTACK_LOGE("strcpy_s failed");
780 return;
781 }
782 if (lws_parse_uri(tempUri, &tempProtocol, &tempAddress, &tempPort, &tempPath) != 0) {
783 NETSTACK_LOGE("get websocket hostname failed");
784 return;
785 }
786 GetWebsocketProxyInfo(context, host, port, exclusions);
787 if (!host.empty() && !CommonUtils::IsHostNameExcluded(tempAddress, exclusions, ",")) {
788 if (strcpy_s(proxyAds, host.length() + 1, host.c_str()) != ERR_OK) {
789 NETSTACK_LOGE("memory copy failed");
790 }
791 info.http_proxy_address = proxyAds;
792 info.http_proxy_port = port;
793 }
794 }
795
CheckFilePath(std::string & path)796 static bool CheckFilePath(std::string &path)
797 {
798 char tmpPath[PATH_MAX] = {0};
799 if (!realpath(static_cast<const char *>(path.c_str()), tmpPath)) {
800 NETSTACK_LOGE("path is error");
801 return false;
802 }
803 path = tmpPath;
804 return true;
805 }
806
FillCaPath(WebSocketConnectContext * context,lws_context_creation_info & info)807 bool NetWebSocketExec::FillCaPath(WebSocketConnectContext *context, lws_context_creation_info &info)
808 {
809 if (!context->caPath_.empty()) {
810 if (!CheckFilePath(context->caPath_)) {
811 NETSTACK_LOGE("ca not exist");
812 context->SetErrorCode(WEBSOCKET_ERROR_CODE_FILE_NOT_EXIST);
813 return false;
814 }
815 info.client_ssl_ca_filepath = context->caPath_.c_str();
816 NETSTACK_LOGD("load customize CA: %{public}s", info.client_ssl_ca_filepath);
817 } else {
818 info.client_ssl_ca_dirs[0] = WEBSOCKET_SYSTEM_PREPARE_CA_PATH;
819 #ifdef HAS_NETMANAGER_BASE
820 if (NetManagerStandard::NetConnClient::GetInstance().TrustUserCa()) {
821 context->userCertPath_ = BASE_PATH + std::to_string(getuid() / UID_TRANSFORM_DIVISOR);
822 info.client_ssl_ca_dirs[1] = context->userCertPath_.c_str();
823 }
824 #endif
825 NETSTACK_LOGD("load system CA");
826 }
827 if (!context->clientCert_.empty()) {
828 char realKeyPath[PATH_MAX] = {0};
829 if (!CheckFilePath(context->clientCert_) || !realpath(context->clientKey_.Data(), realKeyPath)) {
830 NETSTACK_LOGE("client cert not exist");
831 context->SetErrorCode(WEBSOCKET_ERROR_CODE_FILE_NOT_EXIST);
832 return false;
833 }
834 context->clientKey_ = SecureChar(realKeyPath);
835 info.client_ssl_cert_filepath = context->clientCert_.c_str();
836 info.client_ssl_private_key_filepath = context->clientKey_.Data();
837 info.client_ssl_private_key_password = context->keyPassword_.Data();
838 }
839 return true;
840 }
841
GetWebsocketProxyInfo(WebSocketConnectContext * context,std::string & host,uint32_t & port,std::string & exclusions)842 void NetWebSocketExec::GetWebsocketProxyInfo(WebSocketConnectContext *context, std::string &host,
843 uint32_t &port, std::string &exclusions)
844 {
845 if (context->GetUsingWebsocketProxyType() == WebsocketProxyType::USE_SYSTEM) {
846 #ifdef HAS_NETMANAGER_BASE
847 using namespace NetManagerStandard;
848 HttpProxy websocketProxy;
849 NetConnClient::GetInstance().GetDefaultHttpProxy(websocketProxy);
850 host = websocketProxy.GetHost();
851 port = websocketProxy.GetPort();
852 exclusions = CommonUtils::ToString(websocketProxy.GetExclusionList());
853 #endif
854 } else if (context->GetUsingWebsocketProxyType() == WebsocketProxyType::USE_SPECIFIED) {
855 context->GetSpecifiedWebsocketProxy(host, port, exclusions);
856 }
857 }
858
GetHttpResponseFromWsi(lws * wsi)859 uint32_t NetWebSocketExec::GetHttpResponseFromWsi(lws *wsi)
860 {
861 if (wsi == nullptr) {
862 return 0;
863 }
864 return lws_http_client_http_response(wsi);
865 }
866
OnOpen(CJWebsocketProxy * websocketProxy,uint32_t status,const std::string & message)867 void NetWebSocketExec::OnOpen(CJWebsocketProxy *websocketProxy, uint32_t status, const std::string &message)
868 {
869 NETSTACK_LOGI("OnOpen %{public}u %{public}s", status, message.c_str());
870 if (websocketProxy == nullptr) {
871 NETSTACK_LOGE("websocketProxy is null");
872 return;
873 }
874 if (websocketProxy->FindCallback(EVENT_OPEN) == std::nullopt) {
875 NETSTACK_LOGI("no event listener: OPEN");
876 return;
877 }
878
879 CWebSocketCallbackData* para = new CWebSocketCallbackData;
880 para->code = ERR_OK;
881 para->typeId = EVENT_OPEN;
882 para->data = CreateOpenPara(status, message);
883 para->dataLen = sizeof(COpenResponse);
884 websocketProxy->EmitCallBack(para);
885 auto openResponse = reinterpret_cast<COpenResponse*>(para->data);
886 free(openResponse->message);
887 delete openResponse;
888 delete para;
889 }
890
OnError(CJWebsocketProxy * websocketProxy,int32_t code,uint32_t httpResponse)891 void NetWebSocketExec::OnError(CJWebsocketProxy *websocketProxy, int32_t code, uint32_t httpResponse)
892 {
893 NETSTACK_LOGI("OnError code is %{public}d, httpResponse is %{public}d", code, httpResponse);
894 if (websocketProxy == nullptr) {
895 NETSTACK_LOGE("websocketProxy is null");
896 return;
897 }
898 if (websocketProxy->FindCallback(EVENT_OPEN) == std::nullopt) {
899 NETSTACK_LOGI("no event listener: ERROR");
900 return;
901 }
902
903 CWebSocketCallbackData* para = new CWebSocketCallbackData;
904 para->code = ERR_OK;
905 para->typeId = EVENT_ERROR;
906 para->data = CreateError(code, httpResponse);
907 para->dataLen = sizeof(CErrorResponse);
908 websocketProxy->EmitCallBack(para);
909 delete reinterpret_cast<CErrorResponse*>(para->data);
910 delete para;
911 }
912
OnMessage(CJWebsocketProxy * websocketProxy,void * data,size_t length,bool isBinary,bool isFinal)913 void NetWebSocketExec::OnMessage(CJWebsocketProxy *websocketProxy, void *data,
914 size_t length, bool isBinary, bool isFinal)
915 {
916 NETSTACK_LOGD("OnMessage %{public}d", isBinary);
917 if (websocketProxy == nullptr) {
918 NETSTACK_LOGE("websocketProxy is null");
919 return;
920 }
921 if (websocketProxy->FindCallback(EVENT_OPEN) == std::nullopt) {
922 NETSTACK_LOGI("no event listener: MESSAGE");
923 return;
924 }
925 if (length > INT32_MAX) {
926 NETSTACK_LOGE("data length too long");
927 return;
928 }
929 HandleRcvMessage(websocketProxy, data, length, isBinary, isFinal);
930 }
931
OnClose(CJWebsocketProxy * websocketProxy,lws_close_status closeStatus,const std::string & closeReason)932 void NetWebSocketExec::OnClose(CJWebsocketProxy *websocketProxy,
933 lws_close_status closeStatus, const std::string &closeReason)
934 {
935 NETSTACK_LOGI("OnClose %{public}u %{public}s", closeStatus, closeReason.c_str());
936 if (websocketProxy == nullptr) {
937 NETSTACK_LOGE("websocketProxy is null");
938 return;
939 }
940 if (websocketProxy->FindCallback(EVENT_CLOSE) == std::nullopt) {
941 NETSTACK_LOGI("no event listener: CLOSE");
942 return;
943 }
944
945 CWebSocketCallbackData* para = new CWebSocketCallbackData;
946 para->code = ERR_OK;
947 para->typeId = EVENT_CLOSE;
948 para->data = CreateClosePara(closeStatus, closeReason);
949 para->dataLen = sizeof(CCloseResponse);
950 websocketProxy->EmitCallBack(para);
951 auto closeResponse = reinterpret_cast<CCloseResponse*>(para->data);
952 free(closeResponse->reason);
953 delete closeResponse;
954 delete para;
955 }
956
OnDataEnd(CJWebsocketProxy * websocketProxy)957 void NetWebSocketExec::OnDataEnd(CJWebsocketProxy *websocketProxy)
958 {
959 if (websocketProxy == nullptr) {
960 NETSTACK_LOGE("websocketProxy is null");
961 return;
962 }
963 if (websocketProxy->FindCallback(EVENT_DATA_END) == std::nullopt) {
964 NETSTACK_LOGI("no event listener: EVENT_DATA_END");
965 return;
966 }
967 CWebSocketCallbackData* para = new CWebSocketCallbackData;
968 para->code = ERR_OK;
969 para->typeId = EVENT_DATA_END;
970 websocketProxy->EmitCallBack(para);
971 delete para;
972 }
973
OnHeaderReceive(CJWebsocketProxy * websocketProxy,const std::map<std::string,std::string> & headers)974 void NetWebSocketExec::OnHeaderReceive(CJWebsocketProxy *websocketProxy,
975 const std::map<std::string, std::string> &headers)
976 {
977 if (websocketProxy == nullptr) {
978 NETSTACK_LOGE("websocketProxy is null");
979 return;
980 }
981 if (websocketProxy->FindCallback(EVENT_HEADER_RECEIVE) == std::nullopt) {
982 NETSTACK_LOGI("no event listener: EVENT_HEADER_RECEIVE");
983 return;
984 }
985
986 CWebSocketCallbackData* para = new CWebSocketCallbackData;
987 para->code = ERR_OK;
988 para->typeId = EVENT_HEADER_RECEIVE;
989 para->data = CreateResponseHeader(headers);
990 para->dataLen = sizeof(CReceiveResponse);
991 websocketProxy->EmitCallBack(para);
992 auto receiveResponse = reinterpret_cast<CReceiveResponse*>(para->data);
993 FreeCArrString(receiveResponse->header);
994 delete receiveResponse;
995 delete para;
996 }
997
HandleRcvMessage(CJWebsocketProxy * websocketProxy,void * data,size_t length,bool isBinary,bool isFinal)998 void NetWebSocketExec::HandleRcvMessage(CJWebsocketProxy *websocketProxy,
999 void *data, size_t length, bool isBinary, bool isFinal)
1000 {
1001 if (isBinary) {
1002 websocketProxy->AppendWebSocketBinaryData(data, length);
1003 if (isFinal) {
1004 const std::string &msgFromManager = websocketProxy->GetWebSocketBinaryData();
1005 auto msg = new std::string;
1006 msg->append(msgFromManager.data(), msgFromManager.size());
1007 websocketProxy->SetQueueData(msg);
1008 CWebSocketCallbackData* para = new CWebSocketCallbackData;
1009 para->code = ERR_OK;
1010 para->typeId = EVENT_MESSAGE;
1011 para->data = CreateMessagePara(websocketProxy, isBinary);
1012 para->dataLen = sizeof(CMessageResponse);
1013 websocketProxy->EmitCallBack(para);
1014 if (para->data) {
1015 auto msgResponse = reinterpret_cast<CMessageResponse*>(para->data);
1016 free(msgResponse->result.head);
1017 delete msgResponse;
1018 }
1019 delete para;
1020 websocketProxy->ClearWebSocketTextData();
1021 OnDataEnd(websocketProxy);
1022 }
1023 } else {
1024 websocketProxy->AppendWebSocketTextData(data, length);
1025 if (isFinal) {
1026 const std::string &msgFromManager = websocketProxy->GetWebSocketTextData();
1027 auto msg = new (std::nothrow) std::string;
1028 if (msg == nullptr) {
1029 return;
1030 }
1031 msg->append(msgFromManager.data(), msgFromManager.size());
1032 websocketProxy->SetQueueData(msg);
1033 CWebSocketCallbackData* para = new CWebSocketCallbackData;
1034 para->code = ERR_OK;
1035 para->typeId = EVENT_MESSAGE;
1036 para->data = CreateMessagePara(websocketProxy, isBinary);
1037 para->dataLen = sizeof(CMessageResponse);
1038 websocketProxy->EmitCallBack(para);
1039 if (para->data) {
1040 auto msgResponse = reinterpret_cast<CMessageResponse*>(para->data);
1041 free(msgResponse->result.head);
1042 delete msgResponse;
1043 }
1044 delete para;
1045 websocketProxy->ClearWebSocketTextData();
1046 OnDataEnd(websocketProxy);
1047 }
1048 }
1049 }
1050 } // namespace OHOS::NetStack::NetWebSocket