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 #include "proxy_connection.h"
16
17 #include "securec.h"
18 #include "c_header/ohos_bt_def.h"
19 #include "c_header/ohos_bt_socket.h"
20 #include "conn_log.h"
21 #include "softbus_adapter_mem.h"
22 #include "softbus_conn_common.h"
23 #include "softbus_error_code.h"
24 #include "softbus_utils.h"
25 #include "wrapper_br_interface.h"
26
27 typedef struct {
28 uint32_t channelId;
29 ProxyBrConnectStateCallback callback;
30 } ProxyBrConnectContext;
31
32 static SppSocketDriver *g_sppDriver = NULL;
33 ProxyEventListener g_eventListener = { 0 };
34
LegacyBrLoopRead(struct ProxyConnection * connection)35 static int32_t LegacyBrLoopRead(struct ProxyConnection *connection)
36 {
37 #define BUFFER_SIZE (1024 * 2)
38 uint8_t *buffer = (uint8_t *)SoftBusCalloc(BUFFER_SIZE);
39 CONN_CHECK_AND_RETURN_RET_LOGE(buffer != NULL, SOFTBUS_MALLOC_ERR, CONN_PROXY, "create buffer failed");
40 uint32_t channelId = connection->channelId;
41 int32_t ret = SOFTBUS_OK;
42 while (true) {
43 ret = SoftBusMutexLock(&connection->lock);
44 if (ret != SOFTBUS_OK) {
45 CONN_LOGE(CONN_PROXY, "get lock failed, channelId=%{public}u, err=%{public}d", channelId, ret);
46 ret = SOFTBUS_LOCK_ERR;
47 break;
48 }
49 int32_t socketHandle = connection->socketHandle;
50 (void)SoftBusMutexUnlock(&connection->lock);
51 if (socketHandle == BR_INVALID_SOCKET_HANDLE) {
52 ret = BR_INVALID_SOCKET_HANDLE;
53 break;
54 }
55 int32_t recvLen = g_sppDriver->Read(socketHandle, buffer, BUFFER_SIZE);
56 if (recvLen == BR_READ_SOCKET_CLOSED) {
57 CONN_LOGW(CONN_PROXY,
58 "br connection read return, connection closed, channelId=%{public}u, socketHandle=%{public}d",
59 channelId, socketHandle);
60 ret = SOFTBUS_CONN_BR_UNDERLAY_SOCKET_CLOSED;
61 break;
62 }
63 if (recvLen < 0) {
64 CONN_LOGE(CONN_PROXY,
65 "br connection read return, channelId=%{public}u, socketHandle=%{public}d, error=%{public}d", channelId,
66 socketHandle, recvLen);
67 ret = SOFTBUS_CONN_BR_UNDERLAY_READ_FAIL;
68 break;
69 }
70 g_eventListener.onDataReceived(channelId, buffer, recvLen);
71 }
72 SoftBusFree(buffer);
73 return ret;
74 }
75
BrConnectCallback(const BdAddr * bdAddr,BtUuid uuid,int32_t status,int32_t result)76 static void BrConnectCallback(const BdAddr *bdAddr, BtUuid uuid, int32_t status, int32_t result)
77 {
78 (void)bdAddr;
79 (void)uuid;
80 (void)status;
81 (void)result;
82 }
83
StartClientConnect(struct ProxyConnection * connection)84 static int32_t StartClientConnect(struct ProxyConnection *connection)
85 {
86 uint8_t binaryAddr[BT_ADDR_LEN] = { 0 };
87 int32_t ret = ConvertBtMacToBinary(connection->brMac, BT_MAC_LEN, binaryAddr, BT_ADDR_LEN);
88 CONN_CHECK_AND_RETURN_RET_LOGE(ret == SOFTBUS_OK,
89 ret, CONN_PROXY, "convert btMac to binary failed, error=%{public}d", ret);
90 BtSocketConnectionCallback callback = {
91 .connStateCb = BrConnectCallback,
92 };
93 int32_t socketHandle = g_sppDriver->Connect(connection->proxyChannel.uuid, binaryAddr, &callback);
94 if (socketHandle < 0) {
95 CONN_LOGE(CONN_PROXY, "connect failed, socketHandle=%{public}d", socketHandle);
96 return SOFTBUS_CONN_BR_UNDERLAY_CONNECT_FAIL;
97 }
98 if (SoftBusMutexLock(&connection->lock) != SOFTBUS_OK) {
99 CONN_LOGE(CONN_PROXY, "get lock failed, connId=%{public}u", connection->channelId);
100 g_sppDriver->DisConnect(socketHandle);
101 return SOFTBUS_LOCK_ERR;
102 }
103
104 if (connection->state != PROXY_CHANNEL_CONNECTING) {
105 CONN_LOGE(CONN_PROXY,
106 "channelId=%{public}u, unexpectedState=%{public}d", connection->channelId, connection->state);
107 g_sppDriver->DisConnect(socketHandle);
108 connection->state = PROXY_CHANNEL_DISCONNECTED;
109 (void)SoftBusMutexUnlock(&connection->lock);
110 return SOFTBUS_CONN_BR_INTERNAL_ERR;
111 }
112 connection->socketHandle = socketHandle;
113 (void)SoftBusMutexUnlock(&connection->lock);
114 CONN_LOGI(CONN_PROXY, "connect success, socketHandle=%{public}d", socketHandle);
115 return SOFTBUS_OK;
116 }
117
ProxyBrClientConnect(void * data)118 static void *ProxyBrClientConnect(void *data)
119 {
120 const char *name = "Proxy_Conn";
121 SoftBusThread threadSelf = SoftBusThreadGetSelf();
122 SoftBusThreadSetName(threadSelf, name);
123 ProxyBrConnectContext *ctx = (ProxyBrConnectContext *)(data);
124 CONN_CHECK_AND_RETURN_RET_LOGW(ctx != NULL, NULL, CONN_PROXY, "ctx is null");
125 uint32_t channelId = ctx->channelId;
126 ProxyBrConnectStateCallback callback = ctx->callback;
127 SoftBusFree(data);
128 CONN_CHECK_AND_RETURN_RET_LOGE(callback.onConnectSuccess != NULL, NULL, CONN_PROXY,
129 "onConnectSuccess is null");
130 CONN_CHECK_AND_RETURN_RET_LOGE(callback.onConnectFail != NULL, NULL, CONN_PROXY,
131 "onConnectFail is null");
132 struct ProxyConnection *connection = GetProxyChannelManager()->getConnectionById(channelId);
133 CONN_CHECK_AND_RETURN_RET_LOGW(
134 connection != NULL, NULL, CONN_PROXY, "connection is null, channelId=%{public}u", channelId);
135 char anomizeAddress[BT_MAC_LEN] = { 0 };
136 ConvertAnonymizeMacAddress(anomizeAddress, BT_MAC_LEN, connection->brMac, BT_MAC_LEN);
137 CONN_LOGI(CONN_PROXY,
138 "start legacy br connect, channelId=%{public}u, addr=%{public}s", channelId, anomizeAddress);
139 int32_t ret = SOFTBUS_OK;
140 do {
141 ret = StartClientConnect(connection);
142 if (ret != SOFTBUS_OK) {
143 callback.onConnectFail(connection->channelId, ret);
144 break;
145 }
146 callback.onConnectSuccess(connection->channelId);
147 ret = LegacyBrLoopRead(connection);
148 CONN_LOGW(CONN_PROXY, "client loop read exit, channelId=%{public}u, socketHandle=%{public}d, error=%{public}d",
149 connection->channelId, connection->socketHandle, ret);
150 if (SoftBusMutexLock(&connection->lock) != SOFTBUS_OK) {
151 CONN_LOGE(CONN_PROXY, "lock connection failed, channelId=%{public}u", connection->channelId);
152 g_sppDriver->DisConnect(connection->socketHandle);
153 g_eventListener.onDisconnected(connection->channelId, SOFTBUS_LOCK_ERR);
154 break;
155 }
156 if (connection->socketHandle != BR_INVALID_SOCKET_HANDLE) {
157 g_sppDriver->DisConnect(connection->socketHandle);
158 connection->socketHandle = BR_INVALID_SOCKET_HANDLE;
159 }
160 connection->state = PROXY_CHANNEL_DISCONNECTED;
161 (void)SoftBusMutexUnlock(&connection->lock);
162 g_eventListener.onDisconnected(connection->channelId, ret);
163 } while (false);
164 connection->dereference(connection);
165 return NULL;
166 }
167
ProxyBrConnect(struct ProxyConnection * connection,const ProxyBrConnectStateCallback * callback)168 int32_t ProxyBrConnect(struct ProxyConnection *connection, const ProxyBrConnectStateCallback *callback)
169 {
170 CONN_CHECK_AND_RETURN_RET_LOGE(connection != NULL, SOFTBUS_INVALID_PARAM, CONN_PROXY,
171 "connection is null");
172 CONN_CHECK_AND_RETURN_RET_LOGE(callback != NULL, SOFTBUS_INVALID_PARAM, CONN_PROXY,
173 "callback is null");
174 ProxyBrConnectContext *ctx = (ProxyBrConnectContext *)SoftBusCalloc(sizeof(ProxyBrConnectContext));
175 CONN_CHECK_AND_RETURN_RET_LOGE(ctx != NULL, SOFTBUS_LOCK_ERR, CONN_PROXY,
176 "calloc failed, connId=%{public}u", connection->channelId);
177 ctx->channelId = connection->channelId;
178 ctx->callback = *callback;
179 int32_t status = ConnStartActionAsync(ctx, ProxyBrClientConnect, NULL);
180 if (status != SOFTBUS_OK) {
181 CONN_LOGE(CONN_PROXY, "start connect thread failed, connId=%{public}u, error=%{public}d",
182 connection->channelId, status);
183 SoftBusFree(ctx);
184 return status;
185 }
186 return SOFTBUS_OK;
187 }
188
Disconnect(struct ProxyConnection * connection)189 static int32_t Disconnect(struct ProxyConnection *connection)
190 {
191 CONN_CHECK_AND_RETURN_RET_LOGE(connection != NULL,
192 SOFTBUS_INVALID_PARAM, CONN_PROXY, "connection is null");
193 int32_t ret = SoftBusMutexLock(&connection->lock);
194 CONN_CHECK_AND_RETURN_RET_LOGE(ret == SOFTBUS_OK, ret, CONN_PROXY,
195 "br disconnect lock failed, connId=%{public}u, ret=%{public}d", connection->channelId, ret);
196 int32_t socketHandle = connection->socketHandle;
197 if (connection->socketHandle == BR_INVALID_SOCKET_HANDLE) {
198 connection->state = PROXY_CHANNEL_DISCONNECTED;
199 SoftBusMutexUnlock(&connection->lock);
200 return SOFTBUS_OK;
201 }
202 connection->socketHandle = BR_INVALID_SOCKET_HANDLE;
203 connection->state = PROXY_CHANNEL_DISCONNECTED;
204 SoftBusMutexUnlock(&connection->lock);
205 // ensure that the underlayer schedules read/write before disconnection
206 SoftBusSleepMs(WAIT_DISCONNECT_TIME_MS);
207 return g_sppDriver->DisConnect(socketHandle);
208 }
209
Send(struct ProxyConnection * connection,const uint8_t * data,uint32_t dataLen)210 static int32_t Send(struct ProxyConnection *connection, const uint8_t *data, uint32_t dataLen)
211 {
212 CONN_CHECK_AND_RETURN_RET_LOGE(connection != NULL,
213 SOFTBUS_INVALID_PARAM, CONN_PROXY, "connection is null");
214 int32_t ret = SoftBusMutexLock(&connection->lock);
215 CONN_CHECK_AND_RETURN_RET_LOGE(ret == SOFTBUS_OK, ret, CONN_PROXY,
216 "lock connection failed, channelId=%{public}u, ret=%{public}d", connection->channelId, ret);
217 if (connection->state != PROXY_CHANNEL_CONNECTED) {
218 CONN_LOGE(CONN_PROXY, "connection is not ready, currentState=%{public}d", connection->state);
219 SoftBusMutexUnlock(&connection->lock);
220 return SOFTBUS_INVALID_PARAM;
221 }
222 SoftBusMutexUnlock(&connection->lock);
223
224 int32_t waitWriteLen = (int32_t)dataLen;
225 while (waitWriteLen > 0) {
226 int32_t ret = SoftBusMutexLock(&connection->lock);
227 if (ret != SOFTBUS_OK) {
228 return ret;
229 }
230 int32_t socketHandle = connection->socketHandle;
231 SoftBusMutexUnlock(&connection->lock);
232
233 if (socketHandle == BR_INVALID_SOCKET_HANDLE) {
234 CONN_LOGE(CONN_PROXY, "invalid handle");
235 return SOFTBUS_INVALID_PARAM;
236 }
237 int32_t written = g_sppDriver->Write(socketHandle, data, waitWriteLen);
238 if (written < 0) {
239 CONN_LOGE(CONN_PROXY,
240 "send data failed, channelId=%{public}u, totalLen=%{public}u, waitWriteLen=%{public}d, "
241 "alreadyWriteLen=%{public}d, error=%{public}d",
242 connection->channelId, dataLen, waitWriteLen, dataLen - waitWriteLen, written);
243 return SOFTBUS_CONN_BR_UNDERLAY_WRITE_FAIL;
244 }
245 data += written;
246 waitWriteLen -= written;
247 }
248 return SOFTBUS_OK;
249 }
250
RegisterEventListener(const ProxyEventListener * listener)251 int32_t RegisterEventListener(const ProxyEventListener *listener)
252 {
253 CONN_CHECK_AND_RETURN_RET_LOGE(listener != NULL, SOFTBUS_INVALID_PARAM, CONN_PROXY, "listener is null");
254 CONN_CHECK_AND_RETURN_RET_LOGE(listener->onDisconnected != NULL, SOFTBUS_INVALID_PARAM,
255 CONN_PROXY, "onDisconnected is null");
256 CONN_CHECK_AND_RETURN_RET_LOGE(listener->onDataReceived != NULL, SOFTBUS_INVALID_PARAM,
257 CONN_PROXY, "onDataReceived is null");
258 g_eventListener = *listener;
259 g_sppDriver = InitSppSocketDriver();
260 CONN_CHECK_AND_RETURN_RET_LOGE(g_sppDriver != NULL, SOFTBUS_CONN_PROXY_INTERNAL_ERR, CONN_INIT,
261 "init spp socket driver failed");
262 return SOFTBUS_OK;
263 }
264
265 ProxyBrConnectionManager g_proxyBrConnection = {
266 .connect = ProxyBrConnect,
267 .disconnect = Disconnect,
268 .send = Send,
269 .registerEventListener = RegisterEventListener,
270 };
271
GetProxyBrConnectionManager(void)272 ProxyBrConnectionManager *GetProxyBrConnectionManager(void)
273 {
274 return &g_proxyBrConnection;
275 }