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 <map>
17 #include <string>
18
19 #include "conn_log.h"
20 #include "napi_link_enhance_error_code.h"
21 #include "napi_link_enhance_connection.h"
22 #include "napi_link_enhance_server.h"
23 #include "napi_link_enhance_utils.h"
24 #include "napi_link_enhance_object.h"
25 #include "softbus_adapter_mem.h"
26 #include "softbus_connection.h"
27 #include "softbus_utils.h"
28
29 namespace Communication {
30 namespace OHOS::Softbus {
31
32 EXTERN_C_START
33
OnAcceptConnectAdapter(const char * name,uint32_t handle)34 static int32_t OnAcceptConnectAdapter(const char *name, uint32_t handle)
35 {
36 COMM_LOGI(COMM_SDK, "accept new connection, handle=%{public}u", handle);
37 CONN_CHECK_AND_RETURN_RET_LOGE(name != nullptr, SOFTBUS_INVALID_PARAM, COMM_SDK, "name is nullptr");
38 std::string serverName = name;
39 std::string deviceId = "";
40 NapiLinkEnhanceServer *enhanceServer = nullptr;
41 {
42 std::lock_guard<std::mutex> guard(NapiLinkEnhanceServer::serverMapMutex_);
43 if (NapiLinkEnhanceServer::enhanceServerMap_.count(serverName) > 0) {
44 enhanceServer = NapiLinkEnhanceServer::enhanceServerMap_[serverName];
45 }
46 }
47
48 if (enhanceServer == nullptr || enhanceServer->env_ == nullptr ||
49 !enhanceServer->IsAcceptedEnable()) {
50 COMM_LOGE(COMM_SDK, "server status error, name=%{public}s", name);
51 return LINK_ENHANCE_PARAMETER_INVALID;
52 }
53 uint32_t inHandle = handle;
54 auto func = [enhanceServer, serverName, deviceId, inHandle]() {
55 napi_value argvOut[ARGS_SIZE_ONE] = { nullptr };
56 size_t argc = ARGS_SIZE_THREE;
57 napi_value nHandle = nullptr;
58 napi_status status = napi_create_uint32(enhanceServer->env_, inHandle, &nHandle);
59 if (status != napi_ok) {
60 return;
61 }
62
63 napi_value argv[ARGS_SIZE_THREE] = { nullptr };
64 argv[PARAM0] = NapiGetStringRet(enhanceServer->env_, deviceId),
65 argv[PARAM1] = NapiGetStringRet(enhanceServer->env_, serverName),
66 argv[PARAM2] = nHandle;
67
68 napi_value constructor = nullptr;
69 if (napi_get_reference_value(enhanceServer->env_,
70 NapiLinkEnhanceConnection::consRef_, &constructor) != napi_ok) {
71 COMM_LOGE(COMM_SDK, "get connection constructor failed");
72 return;
73 }
74 if (napi_new_instance(enhanceServer->env_, constructor, argc, argv, &argvOut[ARGS_SIZE_ZERO]) != napi_ok) {
75 COMM_LOGE(COMM_SDK, "create js new connection object failed");
76 return;
77 }
78 NapiCallFunction(enhanceServer->env_, enhanceServer->acceptConnectRef_, argvOut, ARGS_SIZE_ONE);
79 };
80 return DoInJsMainThread(enhanceServer->env_, std::move(func));
81 }
82
NotifyDisconnected(NapiLinkEnhanceConnection * connection,int32_t reason)83 static int32_t NotifyDisconnected(NapiLinkEnhanceConnection *connection, int32_t reason)
84 {
85 COMM_LOGI(COMM_SDK, "disconnected, handle=%{public}u, reason=%{public}d", connection->handle_, reason);
86 if (!connection->IsDisconnectEnable()) {
87 COMM_LOGW(COMM_SDK, "not register disconnect listener");
88 return SOFTBUS_CONN_GENERAL_LISTENER_NOT_ENABLE;
89 }
90 auto func = [connection, reason]() {
91 napi_value disconnectReason = NapiGetInt32Ret(connection->env_, reason);
92 napi_value argv[ARGS_SIZE_ONE] = { nullptr };
93 argv[ARGS_SIZE_ZERO] = disconnectReason;
94 NapiCallFunction(connection->env_, connection->disconnectRef_, argv, ARGS_SIZE_ONE);
95 };
96 return DoInJsMainThread(connection->env_, std::move(func));
97 }
98
NotifyConnectResult(NapiLinkEnhanceConnection * connection,bool success,int32_t reason)99 static int32_t NotifyConnectResult(NapiLinkEnhanceConnection *connection, bool success, int32_t reason)
100 {
101 if (!connection->IsConnectResultEnable()) {
102 COMM_LOGE(COMM_SDK, "not register connect result listener");
103 return SOFTBUS_CONN_GENERAL_LISTENER_NOT_ENABLE;
104 }
105 COMM_LOGI(COMM_SDK, "find connection object, handle=%{public}u, success=%{public}d", connection->handle_, success);
106 connection->state_ = success ? ConnectionState::STATE_CONNECTED : ConnectionState::STATE_DISCONNECTED;
107 int32_t napiReason = reason;
108 if (napiReason != 0) {
109 napiReason = ConvertToJsErrcode(reason);
110 }
111 auto func = [connection, success, napiReason]() {
112 auto changeState = std::make_shared<NapiConnectionChangeState>(connection->deviceId_,
113 success, napiReason);
114 napi_value argv[ARGS_SIZE_ONE] = { nullptr };
115 argv[ARGS_SIZE_ZERO] = changeState->ToNapiValue(connection->env_);
116 NapiCallFunction(connection->env_, connection->connectResultRef_, argv, ARGS_SIZE_ONE);
117 };
118 return DoInJsMainThread(connection->env_, std::move(func));
119 }
120
NotifyConnectionStateChange(NapiLinkEnhanceConnection * connection,int32_t status,int32_t reason)121 static int32_t NotifyConnectionStateChange(NapiLinkEnhanceConnection *connection, int32_t status, int32_t reason)
122 {
123 if (connection->state_ == ConnectionState::STATE_CONNECTING) {
124 bool success = (status == CONNECTION_STATE_CONNECTED_SUCCESS);
125 return NotifyConnectResult(connection, success, reason);
126 }
127 if (status == CONNECTION_STATE_DISCONNECTED) {
128 return NotifyDisconnected(connection, reason);
129 }
130 return LINK_ENHANCE_PARAMETER_INVALID;
131 }
132
OnConnectionStateChangeAdapter(uint32_t handle,int32_t status,int32_t reason)133 static int32_t OnConnectionStateChangeAdapter(uint32_t handle, int32_t status, int32_t reason)
134 {
135 COMM_LOGI(COMM_SDK, "connection state change, handle=%{public}u, state=%{public}d, reason=%{public}d", handle,
136 status, reason);
137 std::lock_guard<std::mutex> guard(NapiLinkEnhanceConnection::connectionListMutex_);
138 int32_t ret = LINK_ENHANCE_PARAMETER_INVALID;
139 for (auto iter = NapiLinkEnhanceConnection::connectionList_.begin();
140 iter != NapiLinkEnhanceConnection::connectionList_.end();) {
141 NapiLinkEnhanceConnection *connection = *iter;
142 if (handle == 0) {
143 // indicates that server is died and clear all connections
144 ret = NotifyConnectionStateChange(connection, status, reason);
145 iter = NapiLinkEnhanceConnection::connectionList_.erase(iter);
146 continue;
147 }
148 if (connection->handle_ == handle) {
149 ret = NotifyConnectionStateChange(connection, status, reason);
150 if (status != CONNECTION_STATE_CONNECTED_SUCCESS) {
151 NapiLinkEnhanceConnection::connectionList_.erase(iter);
152 }
153 return ret;
154 } else {
155 iter++;
156 }
157 }
158 return ret;
159 }
160
NotifyDataReceived(NapiLinkEnhanceConnection * connection,const uint8_t * data,uint32_t len)161 static void NotifyDataReceived(NapiLinkEnhanceConnection *connection, const uint8_t *data, uint32_t len)
162 {
163 if (!connection->IsDataReceiveEnable()) {
164 COMM_LOGE(COMM_SDK, "not register data recv listener");
165 return;
166 }
167 auto outData = std::shared_ptr<uint8_t>(new uint8_t[len], std::default_delete<uint8_t[]>());
168 if (outData == nullptr || memcpy_s(outData.get(), len, data, len) != EOK) {
169 return;
170 }
171 auto func = [connection, outData, len]() {
172 napi_value arrayBuffer = nullptr;
173 void *dataBuffer = nullptr;
174 int32_t status = napi_create_arraybuffer(connection->env_, len, &dataBuffer, &arrayBuffer);
175 if (status != napi_ok) {
176 COMM_LOGE(COMM_SDK, "create data array object failed");
177 return;
178 }
179 (void)memcpy_s(dataBuffer, len, outData.get(), len);
180 napi_value argv[ARGS_SIZE_ONE] = { nullptr };
181 argv[ARGS_SIZE_ZERO] = arrayBuffer;
182 NapiCallFunction(connection->env_, connection->dataReceivedRef_, argv, ARGS_SIZE_ONE);
183 };
184 (void)DoInJsMainThread(connection->env_, std::move(func));
185 }
186
OnDataReceivedAdapter(uint32_t handle,const uint8_t * data,uint32_t len)187 static void OnDataReceivedAdapter(uint32_t handle, const uint8_t *data, uint32_t len)
188 {
189 CONN_CHECK_AND_RETURN_LOGE(data != nullptr, COMM_SDK, "data is nullptr");
190 COMM_LOGI(COMM_SDK, "connection data received, handle=%{public}u, len=%{public}u", handle, len);
191 std::lock_guard<std::mutex> guard(NapiLinkEnhanceConnection::connectionListMutex_);
192 for (uint32_t i = 0; i < NapiLinkEnhanceConnection::connectionList_.size(); i++) {
193 NapiLinkEnhanceConnection *connection = NapiLinkEnhanceConnection::connectionList_[i];
194 if (connection->handle_ == handle) {
195 COMM_LOGI(COMM_SDK, "find connection object, handle=%{public}u", handle);
196 NotifyDataReceived(connection, data, len);
197 return;
198 }
199 }
200 return;
201 }
202
OnServiceDiedAdapter(void)203 static void OnServiceDiedAdapter(void)
204 {
205 COMM_LOGI(COMM_SDK, "service died");
206 std::lock_guard<std::mutex> guard(NapiLinkEnhanceServer::serverMapMutex_);
207 for (auto iter = NapiLinkEnhanceServer::enhanceServerMap_.begin();
208 iter != NapiLinkEnhanceServer::enhanceServerMap_.end();) {
209 NapiLinkEnhanceServer *server = iter->second;
210 if (!server->IsStopEnable()) {
211 COMM_LOGI(COMM_SDK, "server not enable stop listener");
212 iter = NapiLinkEnhanceServer::enhanceServerMap_.erase(iter);
213 continue;
214 }
215 auto func = [server]() {
216 napi_value closeReason = NapiGetInt32Ret(server->env_, LINK_ENHANCE_SERVER_DIED);
217 napi_value argv[ARGS_SIZE_ONE] = { nullptr };
218 argv[ARGS_SIZE_ZERO] = closeReason;
219 NapiCallFunction(server->env_, server->serverStopRef_, argv, ARGS_SIZE_ONE);
220 };
221 (void)DoInJsMainThread(server->env_, std::move(func));
222 iter = NapiLinkEnhanceServer::enhanceServerMap_.erase(iter);
223 }
224 }
225
226 static IGeneralListener g_listener = {
227 .OnAcceptConnect = OnAcceptConnectAdapter,
228 .OnConnectionStateChange = OnConnectionStateChangeAdapter,
229 .OnDataReceived = OnDataReceivedAdapter,
230 .OnServiceDied = OnServiceDiedAdapter,
231 };
232
233 /*
234 * Module initialization function
235 */
Init(napi_env env,napi_value exports)236 static napi_value Init(napi_env env, napi_value exports)
237 {
238 COMM_LOGI(COMM_SDK, "enhance manager init start");
239 NapiLinkEnhanceServer::DefineJSClass(env);
240 NapiLinkEnhanceConnection::DefineJSClass(env);
241 PropertyInit(env, exports);
242 napi_property_descriptor desc[] = {
243 DECLARE_NAPI_FUNCTION("createServer", NapiLinkEnhanceServer::Create),
244 DECLARE_NAPI_FUNCTION("createConnection", NapiLinkEnhanceConnection::Create),
245 };
246 napi_define_properties(env, exports, sizeof(desc) / sizeof(desc[0]), desc);
247
248 int32_t ret = GeneralRegisterListener(&g_listener);
249 if (ret != 0) {
250 COMM_LOGE(COMM_SDK, "enhance manager register listener failed ret=%{public}d", ret);
251 }
252 return exports;
253 }
254 EXTERN_C_END
255 /*
256 * Module define
257 */
258 static napi_module enhanceConnectionModule = {
259 .nm_version = 1,
260 .nm_flags = 0,
261 .nm_filename = nullptr,
262 .nm_register_func = Init,
263 .nm_modname = "distributedsched.linkEnhance",
264 .nm_priv = ((void *)0),
265 .reserved = { 0 }
266 };
267 /*
268 * Module register function
269 */
RegisterModule(void)270 extern "C" __attribute__((constructor)) void RegisterModule(void)
271 {
272 COMM_LOGI(
273 COMM_SDK, "Register enhanceConnectionModule nm_modname:%{public}s", enhanceConnectionModule.nm_modname);
274 napi_module_register(&enhanceConnectionModule);
275 }
276 } // namespace Softbus
277 } // namespace Communication