• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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     if (!client->GetClientContext()->IsEmpty()) {
170         client->GetClientContext()->TriggerWritable();
171     }
172     return HttpDummy(wsi, reason, user, in, len);
173 }
174 
LwsCallbackClientConnectionError(lws * wsi,lws_callback_reasons reason,void * user,void * in,size_t len)175 int LwsCallbackClientConnectionError(lws *wsi, lws_callback_reasons reason, void *user, void *in, size_t len)
176 {
177     WebSocketClient *client = static_cast<WebSocketClient *>(user);
178     NETSTACK_LOGE("ClientId:%{public}d,Callback ClientConnectionError", client->GetClientContext()->GetClientId());
179     std::string buf;
180     char *data = static_cast<char *>(in);
181     buf.assign(data, len);
182     ErrorResult errorResult;
183     errorResult.errorCode = WebSocketErrorCode::WEBSOCKET_CONNECTION_ERROR;
184     errorResult.errorMessage = data;
185     client->onErrorCallback_(client, errorResult);
186     return HttpDummy(wsi, reason, user, in, len);
187 }
188 
LwsCallbackClientReceive(lws * wsi,lws_callback_reasons reason,void * user,void * in,size_t len)189 int LwsCallbackClientReceive(lws *wsi, lws_callback_reasons reason, void *user, void *in, size_t len)
190 {
191     WebSocketClient *client = static_cast<WebSocketClient *>(user);
192     NETSTACK_LOGD("ClientId:%{public}d,Callback ClientReceive", client->GetClientContext()->GetClientId());
193     std::string buf;
194     char *data = static_cast<char *>(in);
195     buf.assign(data, len);
196     client->onMessageCallback_(client, data, len);
197     return HttpDummy(wsi, reason, user, in, len);
198 }
199 
Split(const std::string & str,const std::string & sep,size_t size)200 std::vector<std::string> Split(const std::string &str, const std::string &sep, size_t size)
201 {
202     std::string s = str;
203     std::vector<std::string> res;
204     while (!s.empty()) {
205         if (res.size() + 1 == size) {
206             res.emplace_back(s);
207             break;
208         }
209         auto pos = s.find(sep);
210         if (pos == std::string::npos) {
211             res.emplace_back(s);
212             break;
213         }
214         res.emplace_back(s.substr(0, pos));
215         s = s.substr(pos + sep.size());
216     }
217     return res;
218 }
219 
LwsCallbackClientFilterPreEstablish(lws * wsi,lws_callback_reasons reason,void * user,void * in,size_t len)220 int LwsCallbackClientFilterPreEstablish(lws *wsi, lws_callback_reasons reason, void *user, void *in, size_t len)
221 {
222     WebSocketClient *client = static_cast<WebSocketClient *>(user);
223     if (client->GetClientContext() == nullptr) {
224         NETSTACK_LOGE("Callback ClientContext is nullptr");
225         return -1;
226     }
227     client->GetClientContext()->openStatus = lws_http_client_http_response(wsi);
228     NETSTACK_LOGD("ClientId:%{public}d, libwebsockets Callback ClientFilterPreEstablish openStatus = %{public}d",
229                   client->GetClientContext()->GetClientId(), client->GetClientContext()->openStatus);
230     char statusLine[MAX_HDR_LENGTH] = {0};
231     if (lws_hdr_copy(wsi, statusLine, MAX_HDR_LENGTH, WSI_TOKEN_HTTP) < 0 || strlen(statusLine) == 0) {
232         return HttpDummy(wsi, reason, user, in, len);
233     }
234     auto vec = Split(statusLine, STATUS_LINE_SEP, STATUS_LINE_ELEM_NUM);
235     if (vec.size() >= FUNCTION_PARAM_TWO) {
236         client->GetClientContext()->openMessage = vec[1];
237     }
238     return HttpDummy(wsi, reason, user, in, len);
239 }
240 
LwsCallbackClientEstablished(lws * wsi,lws_callback_reasons reason,void * user,void * in,size_t len)241 int LwsCallbackClientEstablished(lws *wsi, lws_callback_reasons reason, void *user, void *in, size_t len)
242 {
243     WebSocketClient *client = static_cast<WebSocketClient *>(user);
244     if (client->GetClientContext() == nullptr) {
245         NETSTACK_LOGE("libwebsockets Callback ClientContext is nullptr");
246         return -1;
247     }
248     NETSTACK_LOGI("ClientId:%{public}d,Callback ClientEstablished", client->GetClientContext()->GetClientId());
249     client->GetClientContext()->TriggerWritable();
250     client->GetClientContext()->SetLws(wsi);
251     OpenResult openResult;
252     openResult.status = client->GetClientContext()->openStatus;
253     openResult.message = client->GetClientContext()->openMessage.c_str();
254     client->onOpenCallback_(client, openResult);
255 
256     return HttpDummy(wsi, reason, user, in, len);
257 }
258 
LwsCallbackClientClosed(lws * wsi,lws_callback_reasons reason,void * user,void * in,size_t len)259 int LwsCallbackClientClosed(lws *wsi, lws_callback_reasons reason, void *user, void *in, size_t len)
260 {
261     WebSocketClient *client = static_cast<WebSocketClient *>(user);
262     if (client->GetClientContext() == nullptr) {
263         NETSTACK_LOGE("Callback ClientContext is nullptr");
264         return -1;
265     }
266     NETSTACK_LOGI("ClientId:%{public}d,Callback ClientClosed", client->GetClientContext()->GetClientId());
267     std::string buf;
268     char *data = static_cast<char *>(in);
269     buf.assign(data, len);
270     CloseResult closeResult;
271     closeResult.code = CLOSE_RESULT_FROM_SERVER_CODE;
272     closeResult.reason = CLOSE_REASON_FORM_SERVER;
273     client->onCloseCallback_(client, closeResult);
274     client->GetClientContext()->SetThreadStop(true);
275     if ((client->GetClientContext()->closeReason).empty()) {
276         client->GetClientContext()->Close(client->GetClientContext()->closeStatus, LINK_DOWN);
277     }
278     return HttpDummy(wsi, reason, user, in, len);
279 }
280 
LwsCallbackWsiDestroy(lws * wsi,lws_callback_reasons reason,void * user,void * in,size_t len)281 int LwsCallbackWsiDestroy(lws *wsi, lws_callback_reasons reason, void *user, void *in, size_t len)
282 {
283     WebSocketClient *client = static_cast<WebSocketClient *>(user);
284     if (client->GetClientContext() == nullptr) {
285         NETSTACK_LOGE("Callback ClientContext is nullptr");
286         return -1;
287     }
288     NETSTACK_LOGI("Lws Callback LwsCallbackWsiDestroy");
289     client->GetClientContext()->SetLws(nullptr);
290     return HttpDummy(wsi, reason, user, in, len);
291 }
292 
LwsCallbackProtocolDestroy(lws * wsi,lws_callback_reasons reason,void * user,void * in,size_t len)293 int LwsCallbackProtocolDestroy(lws *wsi, lws_callback_reasons reason, void *user, void *in, size_t len)
294 {
295     NETSTACK_LOGI("Lws Callback ProtocolDestroy");
296     return HttpDummy(wsi, reason, user, in, len);
297 }
298 
LwsCallbackVhostCertAging(lws * wsi,lws_callback_reasons reason,void * user,void * in,size_t len)299 int LwsCallbackVhostCertAging(lws *wsi, lws_callback_reasons reason, void *user, void *in, size_t len)
300 {
301     NETSTACK_LOGI("lws callback vhost cert aging. len: %{public}zu", len);
302     return HttpDummy(wsi, reason, user, in, len);
303 }
304 
LwsCallback(lws * wsi,lws_callback_reasons reason,void * user,void * in,size_t len)305 int LwsCallback(lws *wsi, lws_callback_reasons reason, void *user, void *in, size_t len)
306 {
307     constexpr CallbackDispatcher dispatchers[] = {
308         {LWS_CALLBACK_CLIENT_APPEND_HANDSHAKE_HEADER, LwsCallbackClientAppendHandshakeHeader},
309         {LWS_CALLBACK_WS_PEER_INITIATED_CLOSE, LwsCallbackWsPeerInitiatedClose},
310         {LWS_CALLBACK_CLIENT_WRITEABLE, LwsCallbackClientWritable},
311         {LWS_CALLBACK_CLIENT_CONNECTION_ERROR, LwsCallbackClientConnectionError},
312         {LWS_CALLBACK_CLIENT_RECEIVE, LwsCallbackClientReceive},
313         {LWS_CALLBACK_CLIENT_FILTER_PRE_ESTABLISH, LwsCallbackClientFilterPreEstablish},
314         {LWS_CALLBACK_CLIENT_ESTABLISHED, LwsCallbackClientEstablished},
315         {LWS_CALLBACK_CLIENT_CLOSED, LwsCallbackClientClosed},
316         {LWS_CALLBACK_WSI_DESTROY, LwsCallbackWsiDestroy},
317         {LWS_CALLBACK_PROTOCOL_DESTROY, LwsCallbackProtocolDestroy},
318         {LWS_CALLBACK_VHOST_CERT_AGING, LwsCallbackVhostCertAging},
319     };
320     auto it = std::find_if(std::begin(dispatchers), std::end(dispatchers),
321         [&reason](const CallbackDispatcher &dispatcher) { return dispatcher.reason == reason; });
322     if (it != std::end(dispatchers)) {
323         return it->callback(wsi, reason, user, in, len);
324     }
325     return HttpDummy(wsi, reason, user, in, len);
326 }
327 
328 static struct lws_protocols protocols[] = {{"lws-minimal-client1", LwsCallback, 0, 0, 0, NULL, 0},
329                                            LWS_PROTOCOL_LIST_TERM};
330 
FillContextInfo(lws_context_creation_info & info)331 static void FillContextInfo(lws_context_creation_info &info)
332 {
333     info.options = LWS_SERVER_OPTION_DO_SSL_GLOBAL_INIT;
334     info.port = CONTEXT_PORT_NO_LISTEN;
335     info.protocols = protocols;
336     info.fd_limit_per_thread = FD_LIMIT_PER_THREAD;
337 }
338 
ParseUrl(const std::string url,char * prefix,char * address,char * path,int * port)339 bool ParseUrl(const std::string url, char *prefix, char *address, char *path, int *port)
340 {
341     char uri[MAX_URI_LENGTH] = {0};
342     if (strcpy_s(uri, MAX_URI_LENGTH, url.c_str()) < 0) {
343         NETSTACK_LOGE("strcpy_s failed");
344         return false;
345     }
346     const char *tempPrefix = nullptr;
347     const char *tempAddress = nullptr;
348     const char *tempPath = nullptr;
349     (void)lws_parse_uri(uri, &tempPrefix, &tempAddress, port, &tempPath);
350     if (strcpy_s(prefix, MAX_URI_LENGTH, tempPrefix) < 0) {
351         NETSTACK_LOGE("strcpy_s failed");
352         return false;
353     }
354     if (strcpy_s(address, MAX_URI_LENGTH, tempAddress) < 0) {
355         NETSTACK_LOGE("strcpy_s failed");
356         return false;
357     }
358     if (strcpy_s(path, MAX_URI_LENGTH, tempPath) < 0) {
359         NETSTACK_LOGE("strcpy_s failed");
360         return false;
361     }
362     return true;
363 }
364 
CreatConnectInfo(const std::string url,lws_context * lwsContext,WebSocketClient * client)365 int CreatConnectInfo(const std::string url, lws_context *lwsContext, WebSocketClient *client)
366 {
367     lws_client_connect_info connectInfo = {};
368     char prefix[MAX_URI_LENGTH] = {0};
369     char address[MAX_URI_LENGTH] = {0};
370     char pathWithoutStart[MAX_URI_LENGTH] = {0};
371     int port = 0;
372     if (!ParseUrl(url, prefix, address, pathWithoutStart, &port)) {
373         return WebSocketErrorCode::WEBSOCKET_CONNECTION_PARSEURL_ERROR;
374     }
375     std::string path = PATH_START + std::string(pathWithoutStart);
376 
377     connectInfo.context = lwsContext;
378     connectInfo.address = address;
379     connectInfo.port = port;
380     connectInfo.path = path.c_str();
381     connectInfo.host = address;
382     connectInfo.origin = address;
383 
384     connectInfo.local_protocol_name = "lws-minimal-client1";
385     connectInfo.retry_and_idle_policy = &RETRY;
386     if (strcmp(prefix, PREFIX_HTTPS) == 0 || strcmp(prefix, PREFIX_WSS) == 0) {
387         connectInfo.ssl_connection =
388             LCCSCF_USE_SSL | LCCSCF_SKIP_SERVER_CERT_HOSTNAME_CHECK | LCCSCF_ALLOW_INSECURE | LCCSCF_ALLOW_SELFSIGNED;
389     }
390     lws *wsi = nullptr;
391     connectInfo.pwsi = &wsi;
392     connectInfo.userdata = client;
393     if (lws_client_connect_via_info(&connectInfo) == nullptr) {
394         NETSTACK_LOGE("Connect lws_context_destroy");
395         return WebSocketErrorCode::WEBSOCKET_CONNECTION_TO_SERVER_FAIL;
396     }
397     return WebSocketErrorCode::WEBSOCKET_NONE_ERR;
398 }
399 
Connect(std::string url,struct OpenOptions options)400 int WebSocketClient::Connect(std::string url, struct OpenOptions options)
401 {
402     NETSTACK_LOGI("ClientId:%{public}d, Connect start", this->GetClientContext()->GetClientId());
403     if (!options.headers.empty()) {
404         if (options.headers.size() > MAX_HEADER_LENGTH) {
405             return WebSocketErrorCode::WEBSOCKET_ERROR_NO_HEADR_EXCEEDS;
406         }
407         for (const auto &item : options.headers) {
408             const std::string &key = item.first;
409             const std::string &value = item.second;
410             this->GetClientContext()->header[key] = value;
411         }
412     }
413     lws_context_creation_info info = {};
414     FillContextInfo(info);
415     lws_context *lwsContext = lws_create_context(&info);
416     if (lwsContext == nullptr) {
417         return WebSocketErrorCode::WEBSOCKET_CONNECTION_NO_MEMOERY;
418     }
419     this->GetClientContext()->SetContext(lwsContext);
420     int ret = CreatConnectInfo(url, lwsContext, this);
421     if (ret != WEBSOCKET_NONE_ERR) {
422         NETSTACK_LOGE("websocket CreatConnectInfo error");
423         GetClientContext()->SetContext(nullptr);
424         lws_context_destroy(lwsContext);
425         return ret;
426     }
427     std::thread serviceThread(RunService, this);
428 #if defined(MAC_PLATFORM) || defined(IOS_PLATFORM)
429     pthread_setname_np(WEBSOCKET_CLIENT_THREAD_RUN);
430 #else
431     pthread_setname_np(serviceThread.native_handle(), WEBSOCKET_CLIENT_THREAD_RUN);
432 #endif
433     serviceThread.detach();
434     return WebSocketErrorCode::WEBSOCKET_NONE_ERR;
435 }
436 
Send(char * data,size_t length)437 int WebSocketClient::Send(char *data, size_t length)
438 {
439     if (data == nullptr) {
440         return WebSocketErrorCode::WEBSOCKET_SEND_DATA_NULL;
441     }
442     if (length == 0) {
443         return WebSocketErrorCode::WEBSOCKET_NONE_ERR;
444     }
445     if (length > MAX_DATA_LENGTH) {
446         return WebSocketErrorCode::WEBSOCKET_DATA_LENGTH_EXCEEDS;
447     }
448     if (this->GetClientContext() == nullptr) {
449         return WebSocketErrorCode::WEBSOCKET_ERROR_NO_CLIENTCONTEX;
450     }
451 
452     lws_write_protocol protocol = (strlen(data) == length) ? LWS_WRITE_TEXT : LWS_WRITE_BINARY;
453     auto dataCopy = reinterpret_cast<char *>(malloc(length));
454     if (dataCopy == nullptr) {
455         NETSTACK_LOGE("webSocketClient malloc error");
456         return WEBSOCKET_SEND_NO_MEMOERY_ERROR;
457     } else if (memcpy_s(dataCopy, length, data, length) != EOK) {
458         free(dataCopy);
459         NETSTACK_LOGE("webSocketClient malloc copy error");
460         return WEBSOCKET_SEND_NO_MEMOERY_ERROR;
461     }
462     this->GetClientContext()->Push(dataCopy, length, protocol);
463     this->GetClientContext()->TriggerWritable();
464     return WebSocketErrorCode::WEBSOCKET_NONE_ERR;
465 }
466 
Close(CloseOption options)467 int WebSocketClient::Close(CloseOption options)
468 {
469     NETSTACK_LOGI("Close start");
470     if (this->GetClientContext() == nullptr) {
471         return WebSocketErrorCode::WEBSOCKET_ERROR_NO_CLIENTCONTEX;
472     }
473     if (this->GetClientContext()->openStatus == 0)
474         return WebSocketErrorCode::WEBSOCKET_ERROR_HAVE_NO_CONNECT;
475 
476     if (options.reason == nullptr || options.code == 0) {
477         options.reason = "";
478         options.code = CLOSE_RESULT_FROM_CLIENT_CODE;
479     }
480     this->GetClientContext()->Close(static_cast<lws_close_status>(options.code), options.reason);
481     this->GetClientContext()->TriggerWritable();
482     return WebSocketErrorCode::WEBSOCKET_NONE_ERR;
483 }
484 
Registcallback(OnOpenCallback onOpen,OnMessageCallback onMessage,OnErrorCallback onError,OnCloseCallback onClose)485 int WebSocketClient::Registcallback(OnOpenCallback onOpen, OnMessageCallback onMessage, OnErrorCallback onError,
486                                     OnCloseCallback onClose)
487 {
488     onMessageCallback_ = onMessage;
489     onCloseCallback_ = onClose;
490     onErrorCallback_ = onError;
491     onOpenCallback_ = onOpen;
492     return WebSocketErrorCode::WEBSOCKET_NONE_ERR;
493 }
494 
Destroy()495 int WebSocketClient::Destroy()
496 {
497     NETSTACK_LOGI("Destroy start");
498     if (this->GetClientContext()->GetContext() == nullptr) {
499         return WebSocketErrorCode::WEBSOCKET_ERROR_HAVE_NO_CONNECT_CONTEXT;
500     }
501     this->GetClientContext()->SetContext(nullptr);
502     lws_context_destroy(this->GetClientContext()->GetContext());
503     return WebSocketErrorCode::WEBSOCKET_NONE_ERR;
504 }
505 
506 } // namespace OHOS::NetStack::WebSocketClient