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 "ohos_bt_socket.h"
17
18 #include <iostream>
19 #include <cstring>
20 #include <vector>
21
22 #include "ohos_bt_adapter_utils.h"
23 #include "bluetooth_def.h"
24 #include "bluetooth_gatt_client.h"
25 #include "bluetooth_socket.h"
26 #include "bluetooth_host.h"
27 #include "bluetooth_log.h"
28 #include "bluetooth_utils.h"
29 #include "bluetooth_object_map.h"
30
31 #ifdef __cplusplus
32 extern "C" {
33 #endif
34
35 using namespace std;
36
37 namespace OHOS {
38 namespace Bluetooth {
39
40 const int MAX_OBJECT_NUM = 10000;
41
42 static BluetoothObjectMap<std::shared_ptr<ServerSocket>, MAX_OBJECT_NUM> g_serverMap;
43 static BluetoothObjectMap<std::shared_ptr<ClientSocket>, MAX_OBJECT_NUM> g_clientMap;
44
45 class BluetoothConnectionObserverWapper : public BluetoothConnectionObserver {
46 public:
BluetoothConnectionObserverWapper(BtSocketConnectionCallback &callback)47 explicit BluetoothConnectionObserverWapper(BtSocketConnectionCallback &callback)
48 {
49 socektConnectCallback = callback;
50 }
51
52 __attribute__((no_sanitize("cfi")))
53 void OnConnectionStateChanged(const CallbackConnectParam ¶m) override
54 {
55 if (socektConnectCallback.connStateCb == nullptr && socektConnectCallback.bleConnStateCb == nullptr) {
56 HILOGE("callback is null");
57 return;
58 }
59 BdAddr addr;
60 GetAddrFromString(param.addr.GetDeviceAddr(), addr.addr);
61 BtUuid btUuid;
62 string strUuid = param.uuid.ToString();
63 btUuid.uuid = (char *)strUuid.c_str();
64 btUuid.uuidLen = strUuid.size();
65 if (param.type == OHOS_SOCKET_SPP_RFCOMM && socektConnectCallback.connStateCb != nullptr) {
66 socektConnectCallback.connStateCb(&addr, btUuid, param.status, param.result);
67 }
68 if (param.type == OHOS_SOCKET_L2CAP_LE && socektConnectCallback.bleConnStateCb != nullptr) {
69 socektConnectCallback.bleConnStateCb(&addr, param.psm, param.status, param.result);
70 }
71 }
72
73 BtSocketConnectionCallback socektConnectCallback;
74 };
75
76 using ClientCbIterator = std::map<int, std::shared_ptr<BluetoothConnectionObserverWapper>>::iterator;
77
GetSocketUuidPara(const BluetoothCreateSocketPara *socketPara, UUID &serverUuid)78 static bool GetSocketUuidPara(const BluetoothCreateSocketPara *socketPara, UUID &serverUuid)
79 {
80 if (socketPara->socketType == OHOS_SOCKET_SPP_RFCOMM) {
81 if (socketPara->uuid.uuid == nullptr || strlen(socketPara->uuid.uuid) != socketPara->uuid.uuidLen) {
82 HILOGE("param uuid invalid!");
83 return false;
84 }
85 string tmpUuid(socketPara->uuid.uuid);
86 if (!IsValidUuid(tmpUuid)) {
87 HILOGE("match the UUID faild.");
88 return false;
89 }
90 serverUuid = UUID::FromString(tmpUuid);
91 } else if (socketPara->socketType == OHOS_SOCKET_L2CAP_LE) {
92 serverUuid = UUID::RandomUUID();
93 } else {
94 HILOGE("param socketType invalid. socketType: %{public}d", socketPara->socketType);
95 return false;
96 }
97 return true;
98 }
99
100 /**
101 * @brief Creates an server listening socket based on the service record.
102 *
103 * @param socketPara The parameters to create a server socket.
104 * @param name The service's name.
105 * @return Returns a server ID, if create fail return {@link BT_SOCKET_INVALID_ID}.
106 */
SocketServerCreate(const BluetoothCreateSocketPara *socketPara, const char *name)107 int SocketServerCreate(const BluetoothCreateSocketPara *socketPara, const char *name)
108 {
109 HILOGD("SocketServerCreate start!");
110 if (socketPara == nullptr || name == nullptr) {
111 HILOGE("socketPara or name is null.");
112 return BT_SOCKET_INVALID_ID;
113 }
114
115 if (socketPara->socketType == OHOS_SOCKET_L2CAP_LE) {
116 CHECK_AND_RETURN_LOG_RET(IS_BLE_ENABLED(), BT_SOCKET_INVALID_ID, "BLE is not TURN_ON");
117 } else {
118 CHECK_AND_RETURN_LOG_RET(IS_BT_ENABLED(), BT_SOCKET_INVALID_ID, "BR is not TURN_ON");
119 }
120
121 UUID serverUuid;
122 if (!GetSocketUuidPara(socketPara, serverUuid)) {
123 return BT_SOCKET_INVALID_ID;
124 }
125
126 string serverName(name);
127 std::shared_ptr<ServerSocket> server = std::make_shared<ServerSocket>(serverName, serverUuid,
128 BtSocketType(socketPara->socketType), socketPara->isEncrypt);
129 int result = server->Listen();
130 if (result != BT_NO_ERROR) {
131 HILOGE("SocketServerCreate fail, result: %{public}d", result);
132 server->Close();
133 HILOGE("SocketServerCreate closed.");
134 return BT_SOCKET_INVALID_ID;
135 }
136 int serverId = g_serverMap.AddObject(server);
137 HILOGI("success, serverId: %{public}d, socketType: %{public}d, isEncrypt: %{public}d", serverId,
138 socketPara->socketType, socketPara->isEncrypt);
139 return serverId;
140 }
141
142 /**
143 * @brief Waits for a remote device to connect to this server socket.
144 *
145 * This method return a client ID indicates a client socket
146 * can be used to read data from and write data to remote device.
147 * This method will block until a connection is established.
148 *
149 * @param serverId The relative ID used to identify the current server socket, obtain the value by calling
150 * {@link SocketServerCreate}.
151 * @return Returns a client ID, if accept fail return {@link BT_SOCKET_INVALID_ID}.
152 */
SocketServerAccept(int serverId)153 int SocketServerAccept(int serverId)
154 {
155 HILOGI("SocketServerAccept start, serverId: %{public}d", serverId);
156 std::shared_ptr<ServerSocket> server = g_serverMap.GetObject(serverId);
157 if (server == nullptr) {
158 HILOGD("server is null!");
159 return BT_SOCKET_INVALID_ID;
160 }
161
162 std::shared_ptr<ClientSocket> client = server->Accept(0);
163 if (client == nullptr) {
164 HILOGE("client is null!");
165 return BT_SOCKET_INVALID_ID;
166 }
167 int clientId = g_clientMap.AddObject(client);
168 HILOGI("success, clientId: %{public}d", clientId);
169 return clientId;
170 }
171
172 /**
173 * @brief Disables an socket server socket and releases related resources.
174 *
175 * @param serverId The relative ID used to identify the current server socket, obtain the value by calling
176 * {@link SocketServerCreate}.
177 * @return Returns the operation result status {@link BtStatus}.
178 */
SocketServerClose(int serverId)179 int SocketServerClose(int serverId)
180 {
181 HILOGI("SocketServerClose start, serverId: %{public}d", serverId);
182 std::shared_ptr<ServerSocket> server = g_serverMap.GetObject(serverId);
183 if (server == nullptr) {
184 HILOGE("server is null!");
185 return OHOS_BT_STATUS_FAIL;
186 }
187 server->Close();
188 g_serverMap.RemoveObject(serverId);
189 return OHOS_BT_STATUS_SUCCESS;
190 }
191
192 /**
193 * @brief Set fast connection flag
194 *
195 * @param bdAddr The remote device address to connect.
196 * @return Returns the operation result status {@link BtStatus}.
197 */
SocketSetFastConnection(const BdAddr *bdAddr)198 int SocketSetFastConnection(const BdAddr *bdAddr)
199 {
200 string strAddress;
201 int leType = 1;
202 if (bdAddr == nullptr) {
203 HILOGE("bdAddr is nullptr.");
204 return OHOS_BT_STATUS_PARM_INVALID;
205 }
206 ConvertAddr(bdAddr->addr, strAddress);
207 // create a client to reuse requestfastestconn.
208 std::shared_ptr<GattClient> client = nullptr;
209 BluetoothRemoteDevice device(strAddress, leType);
210 client = std::make_shared<GattClient>(device);
211 client->Init();
212 int result = client->RequestFastestConn();
213 if (result != OHOS_BT_STATUS_SUCCESS) {
214 HILOGE("request fastest connect fail.");
215 return OHOS_BT_STATUS_FAIL;
216 }
217 return OHOS_BT_STATUS_SUCCESS;
218 }
219
220 /**
221 * @brief Connects to a remote device over the socket.
222 * This method will block until a connection is made or the connection fails.
223 *
224 * @param socketPara The param to create a client socket and connect to a remote device.
225 * @param bdAddr The remote device address to connect.
226 * @param psm BluetoothSocketType is {@link OHOS_SOCKET_L2CAP_LE} use dynamic PSM value from remote device.
227 * BluetoothSocketType is {@link OHOS_SOCKET_SPP_RFCOMM} use -1.
228 * @return Returns a client ID, if connect fail return {@link BT_SOCKET_INVALID_ID}.
229 */
SocketConnect(const BluetoothCreateSocketPara *socketPara, const BdAddr *bdAddr, int psm)230 int SocketConnect(const BluetoothCreateSocketPara *socketPara, const BdAddr *bdAddr, int psm)
231 {
232 HILOGI("SocketConnect start.");
233 if (socketPara == nullptr || bdAddr == nullptr) {
234 HILOGE("socketPara is nullptr, or bdAddr is nullptr");
235 return BT_SOCKET_INVALID_ID;
236 }
237
238 string strAddress;
239 ConvertAddr(bdAddr->addr, strAddress);
240 std::shared_ptr<BluetoothRemoteDevice> device = std::make_shared<BluetoothRemoteDevice>(strAddress, 0);
241
242 UUID serverUuid;
243 if (!GetSocketUuidPara(socketPara, serverUuid)) {
244 return BT_SOCKET_INVALID_ID;
245 }
246
247 std::shared_ptr<ClientSocket> client = std::make_shared<ClientSocket>(*device, serverUuid,
248 BtSocketType(socketPara->socketType), socketPara->isEncrypt);
249 HILOGI("socketType: %{public}d, isEncrypt: %{public}d", socketPara->socketType, socketPara->isEncrypt);
250 client->Init();
251 int result = client->Connect(psm);
252 if (result != OHOS_BT_STATUS_SUCCESS) {
253 HILOGE("SocketConnect fail, result: %{public}d", result);
254 client->Close();
255 HILOGE("SocketConnect closed.");
256 return BT_SOCKET_INVALID_ID;
257 }
258 int clientId = g_clientMap.AddObject(client);
259 HILOGI("SocketConnect success, clientId: %{public}d", clientId);
260 return clientId;
261 }
262
263 /**
264 * @brief Connects to a remote device over the socket.
265 * This method will block until a connection is made or the connection fails.
266 * @param socketPara The param to create a client socket and connect to a remote device.
267 * @param bdAddr The remote device address to connect.
268 * @param psm BluetoothSocketType is {@link OHOS_SOCKET_L2CAP_LE} use dynamic PSM value from remote device.
269 * BluetoothSocketType is {@link OHOS_SOCKET_SPP_RFCOMM} use -1.
270 * @param callback Reference to the socket state observer
271 * @return Returns a client ID, if connect fail return {@link BT_SOCKET_INVALID_ID}.
272 */
SocketConnectEx(const BluetoothCreateSocketPara *socketPara, const BdAddr *bdAddr, int psm, BtSocketConnectionCallback *callback)273 int SocketConnectEx(const BluetoothCreateSocketPara *socketPara, const BdAddr *bdAddr, int psm,
274 BtSocketConnectionCallback *callback)
275 {
276 HILOGI("SocketConnect start.");
277 if (socketPara == nullptr || bdAddr == nullptr || callback == nullptr) {
278 HILOGE("socketPara is nullptr, or bdAddr is nullptr, or callback is nullptr");
279 return BT_SOCKET_INVALID_ID;
280 }
281
282 string strAddress;
283 ConvertAddr(bdAddr->addr, strAddress);
284 std::shared_ptr<BluetoothRemoteDevice> device = std::make_shared<BluetoothRemoteDevice>(strAddress, 0);
285
286 UUID serverUuid;
287 if (!GetSocketUuidPara(socketPara, serverUuid)) {
288 return BT_SOCKET_INVALID_ID;
289 }
290
291 if (socketPara->socketType != OHOS_SOCKET_SPP_RFCOMM && socketPara->socketType != OHOS_SOCKET_L2CAP_LE) {
292 HILOGE("SocketType is not support");
293 return BT_SOCKET_INVALID_TYPE;
294 }
295
296 std::shared_ptr<BluetoothConnectionObserverWapper> connWrapper =
297 std::make_shared<BluetoothConnectionObserverWapper>(*callback);
298 std::shared_ptr<ClientSocket> client = std::make_shared<ClientSocket>(*device, serverUuid,
299 BtSocketType(socketPara->socketType), socketPara->isEncrypt, connWrapper);
300 HILOGI("socketType: %{public}d, isEncrypt: %{public}d", socketPara->socketType, socketPara->isEncrypt);
301 client->Init();
302 int result = client->Connect(psm);
303 if (result != OHOS_BT_STATUS_SUCCESS) {
304 HILOGE("SocketConnect fail, result: %{public}d", result);
305 client->Close();
306 HILOGE("SocketConnect closed.");
307 return BT_SOCKET_INVALID_ID;
308 }
309 int clientId = g_clientMap.AddObject(client);
310 HILOGI("SocketConnect success, clientId: %{public}d", clientId);
311 return clientId;
312 }
313
314 /**
315 * @brief Disables a connection and releases related resources.
316 *
317 * @param clientId The relative ID used to identify the current client socket.
318 * @return Returns the operation result status {@link BtStatus}.
319 */
SocketDisconnect(int clientId)320 int SocketDisconnect(int clientId)
321 {
322 HILOGI("SocketDisconnect start, clientId: %{public}d", clientId);
323 std::shared_ptr<ClientSocket> client = g_clientMap.GetObject(clientId);
324 if (client == nullptr) {
325 HILOGE("client is null, clientId: %{public}d", clientId);
326 return OHOS_BT_STATUS_FAIL;
327 }
328 client->Close();
329 g_clientMap.RemoveObject(clientId);
330 HILOGI("SocketDisConnect success, clientId: %{public}d", clientId);
331 return OHOS_BT_STATUS_SUCCESS;
332 }
333
334 /**
335 * @brief Socket get remote device's address.
336 *
337 * @param clientId The relative ID used to identify the current client socket.
338 * @param remoteAddr Remote device's address, memory allocated by caller.
339 * @return Returns the operation result status {@link BtStatus}.
340 */
SocketGetRemoteAddr(int clientId, BdAddr *remoteAddr)341 int SocketGetRemoteAddr(int clientId, BdAddr *remoteAddr)
342 {
343 HILOGI("SocketGetRemoteAddr clientId: %{public}d", clientId);
344 if (remoteAddr == nullptr) {
345 HILOGE("remoteAddr is null, clientId: %{public}d", clientId);
346 return OHOS_BT_STATUS_PARM_INVALID;
347 }
348 std::shared_ptr<ClientSocket> client = g_clientMap.GetObject(clientId);
349 if (client == nullptr) {
350 HILOGE("client is null, clientId: %{public}d", clientId);
351 return OHOS_BT_STATUS_FAIL;
352 }
353 string tmpAddr = client->GetRemoteDevice().GetDeviceAddr();
354 GetAddrFromString(tmpAddr, remoteAddr->addr);
355 HILOGI("device: %{public}s", GetEncryptAddr(tmpAddr).c_str());
356 return OHOS_BT_STATUS_SUCCESS;
357 }
358
359 /**
360 * @brief Get the connection status of this socket.
361 *
362 * @param clientId The relative ID used to identify the current client socket.
363 * @return Returns true is connected or false is not connected.
364 */
IsSocketConnected(int clientId)365 bool IsSocketConnected(int clientId)
366 {
367 HILOGI("IsSocketConnected clientId: %{public}d", clientId);
368 std::shared_ptr<ClientSocket> client = g_clientMap.GetObject(clientId);
369 if (client == nullptr) {
370 HILOGE("client is null, clientId: %{public}d", clientId);
371 return false;
372 }
373 bool isConnected = client->IsConnected();
374 HILOGI("clientId: %{public}d, isConnected: %{public}d", clientId, isConnected);
375 return isConnected;
376 }
377
378 /**
379 * @brief Read data from socket.
380 * This method blocks until input data is available.
381 *
382 * @param clientId The relative ID used to identify the current client socket.
383 * @param buf Indicate the buffer which read in, memory allocated by caller.
384 * @param bufLen Indicate the buffer length.
385 * @return Returns the length greater than 0 as read the actual length.
386 * Returns {@link BT_SOCKET_READ_SOCKET_CLOSED} if the socket is closed.
387 * Returns {@link BT_SOCKET_READ_FAILED} if the operation failed.
388 */
SocketRead(int clientId, uint8_t *buf, uint32_t bufLen)389 int SocketRead(int clientId, uint8_t *buf, uint32_t bufLen)
390 {
391 HILOGD("SocketRead start, clientId: %{public}d, bufLen: %{public}d", clientId, bufLen);
392 if (buf == nullptr || bufLen == 0) {
393 HILOGE("buf is null or bufLen is 0! clientId: %{public}d", clientId);
394 return BT_SOCKET_READ_FAILED;
395 }
396 std::shared_ptr<ClientSocket> client = g_clientMap.GetObject(clientId);
397 if (client == nullptr) {
398 HILOGE("client is null, clientId: %{public}d", clientId);
399 return BT_SOCKET_READ_FAILED;
400 }
401 if (client->GetInputStream() == nullptr) {
402 HILOGE("inputStream is null, clientId: %{public}d", clientId);
403 return BT_SOCKET_READ_FAILED;
404 }
405 int readLen = client->GetInputStream()->Read(buf, bufLen);
406 HILOGD("SocketRead ret, clientId: %{public}d, readLen: %{public}d", clientId, readLen);
407 return readLen;
408 }
409
410 /**
411 * @brief Client write data to socket.
412 *
413 * @param clientId The relative ID used to identify the current client socket.
414 * @param data Indicate the data to be written.
415 * @return Returns the actual write length.
416 * Returns {@link BT_SOCKET_WRITE_FAILED} if the operation failed.
417 */
SocketWrite(int clientId, const uint8_t *data, uint32_t len)418 int SocketWrite(int clientId, const uint8_t *data, uint32_t len)
419 {
420 HILOGD("SocketWrite start, clientId: %{public}d, len: %{public}d", clientId, len);
421 if (data == nullptr || len == 0) {
422 HILOGE("data is null or len is 0! clientId: %{public}d", clientId);
423 return BT_SOCKET_WRITE_FAILED;
424 }
425 std::shared_ptr<ClientSocket> client = g_clientMap.GetObject(clientId);
426 if (client == nullptr) {
427 HILOGE("client is null! clientId: %{public}d", clientId);
428 return BT_SOCKET_WRITE_FAILED;
429 }
430 if (client->GetOutputStream() == nullptr) {
431 HILOGE("outputStream is null, clientId: %{public}d", clientId);
432 return BT_SOCKET_READ_FAILED;
433 }
434 int writeLen = client->GetOutputStream()->Write(data, len);
435 HILOGD("end, writeLen: %{public}d", writeLen);
436 return writeLen;
437 }
438
439 /**
440 * @brief Get dynamic PSM value for OHOS_SOCKET_L2CAP.
441 *
442 * @param serverId The relative ID used to identify the current server socket, obtain the value by calling
443 * {@link SocketServerCreate}.
444 * @return Returns the PSM value.
445 * Returns {@link BT_SOCKET_INVALID_PSM} if the operation failed.
446 */
SocketGetPsm(int serverId)447 int SocketGetPsm(int serverId)
448 {
449 HILOGI("serverId: %{public}d", serverId);
450 std::shared_ptr<ServerSocket> server = g_serverMap.GetObject(serverId);
451 CHECK_AND_RETURN_LOG_RET(server, BT_SOCKET_INVALID_PSM, "server is null!");
452 return server->GetL2capPsm();
453 }
454
455 /**
456 * @brief Get server channel number for OHOS_SOCKET_RFCOMM.
457 *
458 * @param serverId The relative ID used to identify the current server socket, obtain the value by calling
459 * {@link SocketServerCreate}.
460 * @return Returns the scn.
461 * Returns {@link BT_SOCKET_INVALID_PSM} if the operation failed.
462 */
SocketGetScn(int serverId)463 int SocketGetScn(int serverId)
464 {
465 HILOGI("serverId: %{public}d", serverId);
466 std::shared_ptr<ServerSocket> server = g_serverMap.GetObject(serverId);
467 CHECK_AND_RETURN_LOG_RET(server, BT_SOCKET_INVALID_SCN, "server is null!");
468 return server->GetRfcommScn();
469 }
470
471 /**
472 * @brief Adjust the socket send and recv buffer size, limit range is 4KB to 50KB
473 *
474 * @param clientId The relative ID used to identify the current client socket.
475 * @param bufferSize The buffer size want to set, unit is byte.
476 * @return Returns the operation result status {@link BtStatus}.
477 */
SetSocketBufferSize(int clientId, uint32_t bufferSize)478 int SetSocketBufferSize(int clientId, uint32_t bufferSize)
479 {
480 HILOGI("start, clientId: %{public}d, bufferSize: %{public}d", clientId, bufferSize);
481 std::shared_ptr<ClientSocket> client = g_clientMap.GetObject(clientId);
482 if (client == nullptr) {
483 HILOGE("client is null! clientId: %{public}d", clientId);
484 return OHOS_BT_STATUS_FAIL;
485 }
486 int ret = client->SetBufferSize(bufferSize);
487 if (ret == RET_BAD_PARAM) {
488 return OHOS_BT_STATUS_PARM_INVALID;
489 } else if (ret == RET_BAD_STATUS) {
490 return OHOS_BT_STATUS_FAIL;
491 }
492 return OHOS_BT_STATUS_SUCCESS;
493 }
494 /**
495 * @brief Update the coc connection params
496 *
497 * @param param CocUpdateSocketParam instance for carry params.
498 * @param bdAddr The remote device address to connect.
499 * @return Returns the operation result status {@link BtStatus}.
500 */
SocketUpdateCocConnectionParams(BluetoothCocUpdateSocketParam* param, const BdAddr *bdAddr)501 int SocketUpdateCocConnectionParams(BluetoothCocUpdateSocketParam* param, const BdAddr *bdAddr)
502 {
503 CocUpdateSocketParam params;
504
505 HILOGI("Socket update coc params start");
506 CHECK_AND_RETURN_LOG_RET(param, OHOS_BT_STATUS_FAIL, "param is null");
507 CHECK_AND_RETURN_LOG_RET(bdAddr, OHOS_BT_STATUS_FAIL, "bdAddr is null");
508 ConvertAddr(bdAddr->addr, params.addr);
509 params.minInterval = param->minInterval;
510 params.maxInterval = param->maxInterval;
511 params.peripheralLatency = param->peripheralLatency;
512 params.supervisionTimeout = param->supervisionTimeout;
513 params.minConnEventLen = param->minConnEventLen;
514 params.maxConnEventLen = param->maxConnEventLen;
515
516 std::shared_ptr<BluetoothRemoteDevice> device = std::make_shared<BluetoothRemoteDevice>(params.addr,
517 OHOS_SOCKET_SPP_RFCOMM);
518 std::shared_ptr<ClientSocket> client = std::make_shared<ClientSocket>(*device, UUID::RandomUUID(),
519 TYPE_L2CAP_LE, false);
520 CHECK_AND_RETURN_LOG_RET(client, OHOS_BT_STATUS_FAIL, "client is null");
521 return client->UpdateCocConnectionParams(params);
522 }
523
524 } // namespace Bluetooth
525 } // namespace OHOS
526 #ifdef __cplusplus
527 }
528 #endif