1 /*
2  * Copyright (c) 2023 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 <cstring>
17 #include <iostream>
18 #include <securec.h>
19 #include <string>
20 
21 #include "netstack_log.h"
22 #include "websocket_client_innerapi.h"
23 
24 static constexpr const char *PATH_START = "/";
25 static constexpr const char *NAME_END = ":";
26 static constexpr const char *STATUS_LINE_SEP = " ";
27 static constexpr const size_t STATUS_LINE_ELEM_NUM = 2;
28 static constexpr const char *PREFIX_HTTPS = "https";
29 static constexpr const char *PREFIX_WSS = "wss";
30 static constexpr const int MAX_URI_LENGTH = 1024;
31 static constexpr const int MAX_HDR_LENGTH = 1024;
32 static constexpr const int MAX_HEADER_LENGTH = 8192;
33 static constexpr const size_t MAX_DATA_LENGTH = 4 * 1024 * 1024;
34 static constexpr const int FD_LIMIT_PER_THREAD = 1 + 1 + 1;
35 static constexpr const int CLOSE_RESULT_FROM_SERVER_CODE = 1001;
36 static constexpr const int CLOSE_RESULT_FROM_CLIENT_CODE = 1000;
37 static constexpr const char *LINK_DOWN = "The link is down";
38 static constexpr const char *CLOSE_REASON_FORM_SERVER = "websocket close from server";
39 static constexpr const int FUNCTION_PARAM_TWO = 2;
40 static constexpr const char *WEBSOCKET_CLIENT_THREAD_RUN = "OS_NET_WSCli";
41 static std::atomic<int> g_clientID(0);
42 namespace OHOS::NetStack::WebSocketClient {
43 static const lws_retry_bo_t RETRY = {
44     .secs_since_valid_ping = 0,    /* force PINGs after secs idle */
45     .secs_since_valid_hangup = 10, /* hangup after secs idle */
46     .jitter_percent = 20,
47 };
48 
WebSocketClient()49 WebSocketClient::WebSocketClient()
50 {
51     clientContext = new ClientContext();
52     clientContext->SetClientId(++g_clientID);
53 }
54 
~WebSocketClient()55 WebSocketClient::~WebSocketClient()
56 {
57     delete clientContext;
58     clientContext = nullptr;
59 }
60 
GetClientContext() const61 ClientContext *WebSocketClient::GetClientContext() const
62 {
63     return clientContext;
64 }
65 
RunService(WebSocketClient * Client)66 void RunService(WebSocketClient *Client)
67 {
68     if (Client->GetClientContext()->GetContext() == nullptr) {
69         return;
70     }
71     while (!Client->GetClientContext()->IsThreadStop()) {
72         lws_service(Client->GetClientContext()->GetContext(), 0);
73     }
74 }
75 
HttpDummy(lws * wsi,lws_callback_reasons reason,void * user,void * in,size_t len)76 int HttpDummy(lws *wsi, lws_callback_reasons reason, void *user, void *in, size_t len)
77 {
78     int ret = lws_callback_http_dummy(wsi, reason, user, in, len);
79     return ret;
80 }
81 
82 struct CallbackDispatcher {
83     lws_callback_reasons reason;
84     int (*callback)(lws *wsi, lws_callback_reasons reason, void *user, void *in, size_t len);
85 };
86 
LwsCallbackClientAppendHandshakeHeader(lws * wsi,lws_callback_reasons reason,void * user,void * in,size_t len)87 int LwsCallbackClientAppendHandshakeHeader(lws *wsi, lws_callback_reasons reason, void *user, void *in, size_t len)
88 {
89     WebSocketClient *client = static_cast<WebSocketClient *>(user);
90     if (client->GetClientContext() == nullptr) {
91         NETSTACK_LOGE("Callback ClientContext is nullptr");
92         return -1;
93     }
94     NETSTACK_LOGD("ClientId:%{public}d, Lws Callback AppendHandshakeHeader,",
95                   client->GetClientContext()->GetClientId());
96     auto payload = reinterpret_cast<unsigned char **>(in);
97     if (payload == nullptr || (*payload) == nullptr || len == 0) {
98         return -1;
99     }
100     auto payloadEnd = (*payload) + len;
101     for (const auto &pair : client->GetClientContext()->header) {
102         std::string name = pair.first + NAME_END;
103         if (lws_add_http_header_by_name(wsi, reinterpret_cast<const unsigned char *>(name.c_str()),
104                                         reinterpret_cast<const unsigned char *>(pair.second.c_str()),
105                                         static_cast<int>(strlen(pair.second.c_str())), payload, payloadEnd)) {
106             return -1;
107         }
108     }
109     return HttpDummy(wsi, reason, user, in, len);
110 }
111 
LwsCallbackWsPeerInitiatedClose(lws * wsi,lws_callback_reasons reason,void * user,void * in,size_t len)112 int LwsCallbackWsPeerInitiatedClose(lws *wsi, lws_callback_reasons reason, void *user, void *in, size_t len)
113 {
114     WebSocketClient *client = static_cast<WebSocketClient *>(user);
115     if (client->GetClientContext() == nullptr) {
116         NETSTACK_LOGE("Lws Callback ClientContext is nullptr");
117         return -1;
118     }
119     NETSTACK_LOGD("ClientId:%{public}d,Callback WsPeerInitiatedClose", client->GetClientContext()->GetClientId());
120     if (in == nullptr || len < sizeof(uint16_t)) {
121         NETSTACK_LOGE("Lws Callback WsPeerInitiatedClose");
122         client->GetClientContext()->Close(LWS_CLOSE_STATUS_NORMAL, "");
123         return HttpDummy(wsi, reason, user, in, len);
124     }
125     uint16_t closeStatus = ntohs(*reinterpret_cast<uint16_t *>(in));
126     std::string closeReason;
127     closeReason.append(reinterpret_cast<char *>(in) + sizeof(uint16_t), len - sizeof(uint16_t));
128     client->GetClientContext()->Close(static_cast<lws_close_status>(closeStatus), closeReason);
129     return HttpDummy(wsi, reason, user, in, len);
130 }
131 
LwsCallbackClientWritable(lws * wsi,lws_callback_reasons reason,void * user,void * in,size_t len)132 int LwsCallbackClientWritable(lws *wsi, lws_callback_reasons reason, void *user, void *in, size_t len)
133 {
134     WebSocketClient *client = static_cast<WebSocketClient *>(user);
135     if (client->GetClientContext() == nullptr) {
136         NETSTACK_LOGE("Lws Callback ClientContext is nullptr");
137         return -1;
138     }
139     NETSTACK_LOGD("ClientId:%{public}d,Callback CallbackClientWritable,",
140                   client->GetClientContext()->GetClientId());
141     if (client->GetClientContext()->IsClosed()) {
142         NETSTACK_LOGD("ClientId:%{public}d,Callback ClientWritable need to close",
143                       client->GetClientContext()->GetClientId());
144         lws_close_reason(
145             wsi, client->GetClientContext()->closeStatus,
146             reinterpret_cast<unsigned char *>(const_cast<char *>(client->GetClientContext()->closeReason.c_str())),
147             strlen(client->GetClientContext()->closeReason.c_str()));
148         // here do not emit error, because we close it
149         return -1;
150     }
151     SendData sendData = client->GetClientContext()->Pop();
152     if (sendData.data == nullptr || sendData.length == 0) {
153         return HttpDummy(wsi, reason, user, in, len);
154     }
155     const char *message = sendData.data;
156     size_t messageLen = sendData.length;
157     auto buffer = std::make_unique<unsigned char[]>(LWS_PRE + messageLen);
158     if (buffer == nullptr) {
159         return -1;
160     }
161     int result = memcpy_s(buffer.get() + LWS_PRE, LWS_PRE + messageLen, message, messageLen);
162     if (result != 0) {
163         return -1;
164     }
165     free(sendData.data);
166     int bytesSent = lws_write(wsi, buffer.get() + LWS_PRE, messageLen, sendData.protocol);
167     NETSTACK_LOGD("ClientId:%{public}d,Client Writable send data length = %{public}d",
168                   client->GetClientContext()->GetClientId(), bytesSent);
169     return HttpDummy(wsi, reason, user, in, len);
170 }
171 
LwsCallbackClientConnectionError(lws * wsi,lws_callback_reasons reason,void * user,void * in,size_t len)172 int LwsCallbackClientConnectionError(lws *wsi, lws_callback_reasons reason, void *user, void *in, size_t len)
173 {
174     WebSocketClient *client = static_cast<WebSocketClient *>(user);
175     NETSTACK_LOGE("ClientId:%{public}d,Callback ClientConnectionError", client->GetClientContext()->GetClientId());
176     std::string buf;
177     char *data = static_cast<char *>(in);
178     buf.assign(data, len);
179     ErrorResult errorResult;
180     errorResult.errorCode = WebSocketErrorCode::WEBSOCKET_CONNECTION_ERROR;
181     errorResult.errorMessage = data;
182     client->onErrorCallback_(client, errorResult);
183     return HttpDummy(wsi, reason, user, in, len);
184 }
185 
LwsCallbackClientReceive(lws * wsi,lws_callback_reasons reason,void * user,void * in,size_t len)186 int LwsCallbackClientReceive(lws *wsi, lws_callback_reasons reason, void *user, void *in, size_t len)
187 {
188     WebSocketClient *client = static_cast<WebSocketClient *>(user);
189     NETSTACK_LOGD("ClientId:%{public}d,Callback ClientReceive", client->GetClientContext()->GetClientId());
190     std::string buf;
191     char *data = static_cast<char *>(in);
192     buf.assign(data, len);
193     client->onMessageCallback_(client, data, len);
194     return HttpDummy(wsi, reason, user, in, len);
195 }
196 
Split(const std::string & str,const std::string & sep,size_t size)197 std::vector<std::string> Split(const std::string &str, const std::string &sep, size_t size)
198 {
199     std::string s = str;
200     std::vector<std::string> res;
201     while (!s.empty()) {
202         if (res.size() + 1 == size) {
203             res.emplace_back(s);
204             break;
205         }
206         auto pos = s.find(sep);
207         if (pos == std::string::npos) {
208             res.emplace_back(s);
209             break;
210         }
211         res.emplace_back(s.substr(0, pos));
212         s = s.substr(pos + sep.size());
213     }
214     return res;
215 }
216 
LwsCallbackClientFilterPreEstablish(lws * wsi,lws_callback_reasons reason,void * user,void * in,size_t len)217 int LwsCallbackClientFilterPreEstablish(lws *wsi, lws_callback_reasons reason, void *user, void *in, size_t len)
218 {
219     WebSocketClient *client = static_cast<WebSocketClient *>(user);
220     if (client->GetClientContext() == nullptr) {
221         NETSTACK_LOGE("Callback ClientContext is nullptr");
222         return -1;
223     }
224     client->GetClientContext()->openStatus = lws_http_client_http_response(wsi);
225     NETSTACK_LOGD("ClientId:%{public}d, libwebsockets Callback ClientFilterPreEstablish openStatus = %{public}d",
226                   client->GetClientContext()->GetClientId(), client->GetClientContext()->openStatus);
227     char statusLine[MAX_HDR_LENGTH] = {0};
228     if (lws_hdr_copy(wsi, statusLine, MAX_HDR_LENGTH, WSI_TOKEN_HTTP) < 0 || strlen(statusLine) == 0) {
229         return HttpDummy(wsi, reason, user, in, len);
230     }
231     auto vec = Split(statusLine, STATUS_LINE_SEP, STATUS_LINE_ELEM_NUM);
232     if (vec.size() >= FUNCTION_PARAM_TWO) {
233         client->GetClientContext()->openMessage = vec[1];
234     }
235     return HttpDummy(wsi, reason, user, in, len);
236 }
237 
LwsCallbackClientEstablished(lws * wsi,lws_callback_reasons reason,void * user,void * in,size_t len)238 int LwsCallbackClientEstablished(lws *wsi, lws_callback_reasons reason, void *user, void *in, size_t len)
239 {
240     WebSocketClient *client = static_cast<WebSocketClient *>(user);
241     if (client->GetClientContext() == nullptr) {
242         NETSTACK_LOGE("libwebsockets Callback ClientContext is nullptr");
243         return -1;
244     }
245     NETSTACK_LOGI("ClientId:%{public}d,Callback ClientEstablished", client->GetClientContext()->GetClientId());
246     OpenResult openResult;
247     openResult.status = client->GetClientContext()->openStatus;
248     openResult.message = client->GetClientContext()->openMessage.c_str();
249     client->onOpenCallback_(client, openResult);
250 
251     return HttpDummy(wsi, reason, user, in, len);
252 }
253 
LwsCallbackClientClosed(lws * wsi,lws_callback_reasons reason,void * user,void * in,size_t len)254 int LwsCallbackClientClosed(lws *wsi, lws_callback_reasons reason, void *user, void *in, size_t len)
255 {
256     WebSocketClient *client = static_cast<WebSocketClient *>(user);
257     if (client->GetClientContext() == nullptr) {
258         NETSTACK_LOGE("Callback ClientContext is nullptr");
259         return -1;
260     }
261     NETSTACK_LOGI("ClientId:%{public}d,Callback ClientClosed", client->GetClientContext()->GetClientId());
262     std::string buf;
263     char *data = static_cast<char *>(in);
264     buf.assign(data, len);
265     CloseResult closeResult;
266     closeResult.code = CLOSE_RESULT_FROM_SERVER_CODE;
267     closeResult.reason = CLOSE_REASON_FORM_SERVER;
268     client->onCloseCallback_(client, closeResult);
269     client->GetClientContext()->SetThreadStop(true);
270     if ((client->GetClientContext()->closeReason).empty()) {
271         client->GetClientContext()->Close(client->GetClientContext()->closeStatus, LINK_DOWN);
272     }
273     return HttpDummy(wsi, reason, user, in, len);
274 }
275 
LwsCallbackWsiDestroy(lws * wsi,lws_callback_reasons reason,void * user,void * in,size_t len)276 int LwsCallbackWsiDestroy(lws *wsi, lws_callback_reasons reason, void *user, void *in, size_t len)
277 {
278     WebSocketClient *client = static_cast<WebSocketClient *>(user);
279     if (client->GetClientContext() == nullptr) {
280         NETSTACK_LOGE("Callback ClientContext is nullptr");
281         return -1;
282     }
283     NETSTACK_LOGI("Lws Callback LwsCallbackWsiDestroy");
284     return HttpDummy(wsi, reason, user, in, len);
285 }
286 
LwsCallbackProtocolDestroy(lws * wsi,lws_callback_reasons reason,void * user,void * in,size_t len)287 int LwsCallbackProtocolDestroy(lws *wsi, lws_callback_reasons reason, void *user, void *in, size_t len)
288 {
289     NETSTACK_LOGI("Lws Callback ProtocolDestroy");
290     return HttpDummy(wsi, reason, user, in, len);
291 }
292 
LwsCallback(lws * wsi,lws_callback_reasons reason,void * user,void * in,size_t len)293 int LwsCallback(lws *wsi, lws_callback_reasons reason, void *user, void *in, size_t len)
294 {
295     constexpr CallbackDispatcher dispatchers[] = {
296         {LWS_CALLBACK_CLIENT_APPEND_HANDSHAKE_HEADER, LwsCallbackClientAppendHandshakeHeader},
297         {LWS_CALLBACK_WS_PEER_INITIATED_CLOSE, LwsCallbackWsPeerInitiatedClose},
298         {LWS_CALLBACK_CLIENT_WRITEABLE, LwsCallbackClientWritable},
299         {LWS_CALLBACK_CLIENT_CONNECTION_ERROR, LwsCallbackClientConnectionError},
300         {LWS_CALLBACK_CLIENT_RECEIVE, LwsCallbackClientReceive},
301         {LWS_CALLBACK_CLIENT_FILTER_PRE_ESTABLISH, LwsCallbackClientFilterPreEstablish},
302         {LWS_CALLBACK_CLIENT_ESTABLISHED, LwsCallbackClientEstablished},
303         {LWS_CALLBACK_CLIENT_CLOSED, LwsCallbackClientClosed},
304         {LWS_CALLBACK_WSI_DESTROY, LwsCallbackWsiDestroy},
305         {LWS_CALLBACK_PROTOCOL_DESTROY, LwsCallbackProtocolDestroy},
306     };
307     auto it = std::find_if(std::begin(dispatchers), std::end(dispatchers),
308         [&reason](const CallbackDispatcher &dispatcher) { return dispatcher.reason == reason; });
309     if (it != std::end(dispatchers)) {
310         return it->callback(wsi, reason, user, in, len);
311     }
312     return HttpDummy(wsi, reason, user, in, len);
313 }
314 
315 static struct lws_protocols protocols[] = {{"lws-minimal-client1", LwsCallback, 0, 0, 0, NULL, 0},
316                                            LWS_PROTOCOL_LIST_TERM};
317 
FillContextInfo(lws_context_creation_info & info)318 static void FillContextInfo(lws_context_creation_info &info)
319 {
320     info.options = LWS_SERVER_OPTION_DO_SSL_GLOBAL_INIT;
321     info.port = CONTEXT_PORT_NO_LISTEN;
322     info.protocols = protocols;
323     info.fd_limit_per_thread = FD_LIMIT_PER_THREAD;
324 }
325 
ParseUrl(const std::string url,char * prefix,char * address,char * path,int * port)326 bool ParseUrl(const std::string url, char *prefix, char *address, char *path, int *port)
327 {
328     char uri[MAX_URI_LENGTH] = {0};
329     if (strcpy_s(uri, MAX_URI_LENGTH, url.c_str()) < 0) {
330         NETSTACK_LOGE("strcpy_s failed");
331         return false;
332     }
333     const char *tempPrefix = nullptr;
334     const char *tempAddress = nullptr;
335     const char *tempPath = nullptr;
336     (void)lws_parse_uri(uri, &tempPrefix, &tempAddress, port, &tempPath);
337     if (strcpy_s(prefix, MAX_URI_LENGTH, tempPrefix) < 0) {
338         NETSTACK_LOGE("strcpy_s failed");
339         return false;
340     }
341     if (strcpy_s(address, MAX_URI_LENGTH, tempAddress) < 0) {
342         NETSTACK_LOGE("strcpy_s failed");
343         return false;
344     }
345     if (strcpy_s(path, MAX_URI_LENGTH, tempPath) < 0) {
346         NETSTACK_LOGE("strcpy_s failed");
347         return false;
348     }
349     return true;
350 }
351 
CreatConnectInfo(const std::string url,lws_context * lwsContext,WebSocketClient * client)352 int CreatConnectInfo(const std::string url, lws_context *lwsContext, WebSocketClient *client)
353 {
354     lws_client_connect_info connectInfo = {};
355     char prefix[MAX_URI_LENGTH] = {0};
356     char address[MAX_URI_LENGTH] = {0};
357     char pathWithoutStart[MAX_URI_LENGTH] = {0};
358     int port = 0;
359     if (!ParseUrl(url, prefix, address, pathWithoutStart, &port)) {
360         return WebSocketErrorCode::WEBSOCKET_CONNECTION_PARSEURL_ERROR;
361     }
362     std::string path = PATH_START + std::string(pathWithoutStart);
363 
364     connectInfo.context = lwsContext;
365     connectInfo.address = address;
366     connectInfo.port = port;
367     connectInfo.path = path.c_str();
368     connectInfo.host = address;
369     connectInfo.origin = address;
370 
371     connectInfo.local_protocol_name = "lws-minimal-client1";
372     connectInfo.retry_and_idle_policy = &RETRY;
373     if (strcmp(prefix, PREFIX_HTTPS) == 0 || strcmp(prefix, PREFIX_WSS) == 0) {
374         connectInfo.ssl_connection =
375             LCCSCF_USE_SSL | LCCSCF_SKIP_SERVER_CERT_HOSTNAME_CHECK | LCCSCF_ALLOW_INSECURE | LCCSCF_ALLOW_SELFSIGNED;
376     }
377     lws *wsi = nullptr;
378     connectInfo.pwsi = &wsi;
379     connectInfo.userdata = client;
380     if (lws_client_connect_via_info(&connectInfo) == nullptr) {
381         NETSTACK_LOGE("Connect lws_context_destroy");
382         return WebSocketErrorCode::WEBSOCKET_CONNECTION_TO_SERVER_FAIL;
383     }
384     return WebSocketErrorCode::WEBSOCKET_NONE_ERR;
385 }
386 
Connect(std::string url,struct OpenOptions options)387 int WebSocketClient::Connect(std::string url, struct OpenOptions options)
388 {
389     NETSTACK_LOGI("ClientId:%{public}d, Connect start", this->GetClientContext()->GetClientId());
390     if (!options.headers.empty()) {
391         if (options.headers.size() > MAX_HEADER_LENGTH) {
392             return WebSocketErrorCode::WEBSOCKET_ERROR_NO_HEADR_EXCEEDS;
393         }
394         for (const auto &item : options.headers) {
395             const std::string &key = item.first;
396             const std::string &value = item.second;
397             this->GetClientContext()->header[key] = value;
398         }
399     }
400     lws_context_creation_info info = {};
401     FillContextInfo(info);
402     lws_context *lwsContext = lws_create_context(&info);
403     if (lwsContext == nullptr) {
404         return WebSocketErrorCode::WEBSOCKET_CONNECTION_NO_MEMOERY;
405     }
406     this->GetClientContext()->SetContext(lwsContext);
407     int ret = CreatConnectInfo(url, lwsContext, this);
408     if (ret != WEBSOCKET_NONE_ERR) {
409         NETSTACK_LOGE("websocket CreatConnectInfo error");
410         GetClientContext()->SetContext(nullptr);
411         lws_context_destroy(lwsContext);
412         return ret;
413     }
414     std::thread serviceThread(RunService, this);
415 #if defined(MAC_PLATFORM) || defined(IOS_PLATFORM)
416     pthread_setname_np(WEBSOCKET_CLIENT_THREAD_RUN);
417 #else
418     pthread_setname_np(serviceThread.native_handle(), WEBSOCKET_CLIENT_THREAD_RUN);
419 #endif
420     serviceThread.detach();
421     return WebSocketErrorCode::WEBSOCKET_NONE_ERR;
422 }
423 
Send(char * data,size_t length)424 int WebSocketClient::Send(char *data, size_t length)
425 {
426     if (data == nullptr) {
427         return WebSocketErrorCode::WEBSOCKET_SEND_DATA_NULL;
428     }
429     if (length == 0) {
430         return WebSocketErrorCode::WEBSOCKET_NONE_ERR;
431     }
432     if (length > MAX_DATA_LENGTH) {
433         return WebSocketErrorCode::WEBSOCKET_DATA_LENGTH_EXCEEDS;
434     }
435     if (this->GetClientContext() == nullptr) {
436         return WebSocketErrorCode::WEBSOCKET_ERROR_NO_CLIENTCONTEX;
437     }
438 
439     lws_write_protocol protocol = (strlen(data) == length) ? LWS_WRITE_TEXT : LWS_WRITE_BINARY;
440     auto dataCopy = reinterpret_cast<char *>(malloc(length));
441     if (dataCopy == nullptr) {
442         NETSTACK_LOGE("webSocketClient malloc error");
443         return WEBSOCKET_SEND_NO_MEMOERY_ERROR;
444     } else if (memcpy_s(dataCopy, length, data, length) != EOK) {
445         free(dataCopy);
446         NETSTACK_LOGE("webSocketClient malloc copy error");
447         return WEBSOCKET_SEND_NO_MEMOERY_ERROR;
448     }
449     this->GetClientContext()->Push(dataCopy, length, protocol);
450     return WebSocketErrorCode::WEBSOCKET_NONE_ERR;
451 }
452 
Close(CloseOption options)453 int WebSocketClient::Close(CloseOption options)
454 {
455     NETSTACK_LOGI("Close start");
456     if (this->GetClientContext() == nullptr) {
457         return WebSocketErrorCode::WEBSOCKET_ERROR_NO_CLIENTCONTEX;
458     }
459     if (this->GetClientContext()->openStatus == 0)
460         return WebSocketErrorCode::WEBSOCKET_ERROR_HAVE_NO_CONNECT;
461 
462     if (options.reason == nullptr || options.code == 0) {
463         options.reason = "";
464         options.code = CLOSE_RESULT_FROM_CLIENT_CODE;
465     }
466     this->GetClientContext()->Close(static_cast<lws_close_status>(options.code), options.reason);
467     return WebSocketErrorCode::WEBSOCKET_NONE_ERR;
468 }
469 
Registcallback(OnOpenCallback onOpen,OnMessageCallback onMessage,OnErrorCallback onError,OnCloseCallback onClose)470 int WebSocketClient::Registcallback(OnOpenCallback onOpen, OnMessageCallback onMessage, OnErrorCallback onError,
471                                     OnCloseCallback onClose)
472 {
473     onMessageCallback_ = onMessage;
474     onCloseCallback_ = onClose;
475     onErrorCallback_ = onError;
476     onOpenCallback_ = onOpen;
477     return WebSocketErrorCode::WEBSOCKET_NONE_ERR;
478 }
479 
Destroy()480 int WebSocketClient::Destroy()
481 {
482     NETSTACK_LOGI("Destroy start");
483     if (this->GetClientContext()->GetContext() == nullptr) {
484         return WebSocketErrorCode::WEBSOCKET_ERROR_HAVE_NO_CONNECT_CONTEXT;
485     }
486     this->GetClientContext()->SetContext(nullptr);
487     lws_context_destroy(this->GetClientContext()->GetContext());
488     return WebSocketErrorCode::WEBSOCKET_NONE_ERR;
489 }
490 
491 } // namespace OHOS::NetStack::WebSocketClient