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