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 callback_ = callback;
50 }
OnConnectionStateChanged(const BluetoothRemoteDevice & dev,UUID uuid,int status,int result)51 void OnConnectionStateChanged(const BluetoothRemoteDevice &dev, UUID uuid, int status, int result) override
52 {
53 if (callback_ == nullptr || callback_->connStateCb == nullptr) {
54 HILOGE("callback is null");
55 return;
56 }
57 BdAddr addr;
58 GetAddrFromString(dev.GetDeviceAddr(), addr.addr);
59 BtUuid btUuid;
60 string strUuid = uuid.ToString();
61 btUuid.uuid = (char *)strUuid.c_str();
62 btUuid.uuidLen = strUuid.size();
63 callback_->connStateCb(&addr, btUuid, status, result);
64 }
65
66 BtSocketConnectionCallback *callback_;
67 };
68
69 static std::map<int, std::shared_ptr<BluetoothConnectionObserverWapper>> g_clientCbMap;
70 static std::mutex g_clientCbMapMutex;
71 using ClientCbIterator = std::map<int, std::shared_ptr<BluetoothConnectionObserverWapper>>::iterator;
72
GetSocketUuidPara(const BluetoothCreateSocketPara * socketPara,UUID & serverUuid)73 static bool GetSocketUuidPara(const BluetoothCreateSocketPara *socketPara, UUID &serverUuid)
74 {
75 if (socketPara->socketType == OHOS_SOCKET_SPP_RFCOMM) {
76 if (socketPara->uuid.uuid == nullptr || strlen(socketPara->uuid.uuid) != socketPara->uuid.uuidLen) {
77 HILOGE("param uuid invalid!");
78 return false;
79 }
80 string tmpUuid(socketPara->uuid.uuid);
81 if (!regex_match(tmpUuid, uuidRegex)) {
82 HILOGE("match the UUID faild.");
83 return false;
84 }
85 serverUuid = UUID::FromString(tmpUuid);
86 } else if (socketPara->socketType == OHOS_SOCKET_L2CAP_LE) {
87 serverUuid = UUID::RandomUUID();
88 } else {
89 HILOGE("param socketType invalid. socketType: %{public}d", socketPara->socketType);
90 return false;
91 }
92 return true;
93 }
94
95 /**
96 * @brief Creates an server listening socket based on the service record.
97 *
98 * @param socketPara The parameters to create a server socket.
99 * @param name The service's name.
100 * @return Returns a server ID, if create fail return {@link BT_SOCKET_INVALID_ID}.
101 */
SocketServerCreate(const BluetoothCreateSocketPara * socketPara,const char * name)102 int SocketServerCreate(const BluetoothCreateSocketPara *socketPara, const char *name)
103 {
104 HILOGD("SocketServerCreate start!");
105 if (!IS_BT_ENABLED()) {
106 HILOGE("fail,BR is not TURN_ON");
107 return BT_SOCKET_INVALID_ID;
108 }
109
110 if (socketPara == nullptr || name == nullptr) {
111 HILOGE("socketPara or name is null.");
112 return BT_SOCKET_INVALID_ID;
113 }
114
115 UUID serverUuid;
116 if (!GetSocketUuidPara(socketPara, serverUuid)) {
117 return BT_SOCKET_INVALID_ID;
118 }
119
120 string serverName(name);
121 std::shared_ptr<ServerSocket> server = std::make_shared<ServerSocket>(serverName, serverUuid,
122 BtSocketType(socketPara->socketType), socketPara->isEncrypt);
123 server->Listen();
124 int serverId = g_serverMap.AddObject(server);
125 HILOGI("success, serverId: %{public}d, socketType: %{public}d, isEncrypt: %{public}d", serverId,
126 socketPara->socketType, socketPara->isEncrypt);
127 return serverId;
128 }
129
130 /**
131 * @brief Waits for a remote device to connect to this server socket.
132 *
133 * This method return a client ID indicates a client socket
134 * can be used to read data from and write data to remote device.
135 * This method will block until a connection is established.
136 *
137 * @param serverId The relative ID used to identify the current server socket, obtain the value by calling
138 * {@link SocketServerCreate}.
139 * @return Returns a client ID, if accept fail return {@link BT_SOCKET_INVALID_ID}.
140 */
SocketServerAccept(int serverId)141 int SocketServerAccept(int serverId)
142 {
143 HILOGI("SocketServerAccept start, serverId: %{public}d", serverId);
144 std::shared_ptr<ServerSocket> server = g_serverMap.GetObject(serverId);
145 if (server == nullptr) {
146 HILOGE("server is null!");
147 return BT_SOCKET_INVALID_ID;
148 }
149
150 std::shared_ptr<ClientSocket> client = server->Accept(0);
151 if (client == nullptr) {
152 HILOGE("client is null!");
153 return BT_SOCKET_INVALID_ID;
154 }
155 int clientId = g_clientMap.AddObject(client);
156 HILOGI("success, clientId: %{public}d", clientId);
157 return clientId;
158 }
159
160 /**
161 * @brief Disables an socket server socket and releases related resources.
162 *
163 * @param serverId The relative ID used to identify the current server socket, obtain the value by calling
164 * {@link SocketServerCreate}.
165 * @return Returns the operation result status {@link BtStatus}.
166 */
SocketServerClose(int serverId)167 int SocketServerClose(int serverId)
168 {
169 HILOGI("SocketServerClose start, serverId: %{public}d", serverId);
170 std::shared_ptr<ServerSocket> server = g_serverMap.GetObject(serverId);
171 if (server == nullptr) {
172 HILOGE("server is null!");
173 return OHOS_BT_STATUS_FAIL;
174 }
175 server->Close();
176 g_serverMap.RemoveObject(serverId);
177 return OHOS_BT_STATUS_SUCCESS;
178 }
179
180 /**
181 * @brief Set fast connection flag
182 *
183 * @param bdAddr The remote device address to connect.
184 * @return Returns the operation result status {@link BtStatus}.
185 */
SocketSetFastConnection(const BdAddr * bdAddr)186 int SocketSetFastConnection(const BdAddr *bdAddr)
187 {
188 string strAddress;
189 int leType = 1;
190 if (bdAddr == nullptr) {
191 HILOGE("bdAddr is nullptr.");
192 return OHOS_BT_STATUS_PARM_INVALID;
193 }
194 ConvertAddr(bdAddr->addr, strAddress);
195 // create a client to reuse requestfastestconn.
196 std::shared_ptr<GattClient> client = nullptr;
197 BluetoothRemoteDevice device(strAddress, leType);
198 client = std::make_shared<GattClient>(device);
199 client->Init();
200 int result = client->RequestFastestConn();
201 if (result != OHOS_BT_STATUS_SUCCESS) {
202 HILOGE("request fastest connect fail.");
203 return OHOS_BT_STATUS_FAIL;
204 }
205 return OHOS_BT_STATUS_SUCCESS;
206 }
207
208 /**
209 * @brief Connects to a remote device over the socket.
210 * This method will block until a connection is made or the connection fails.
211 *
212 * @param socketPara The param to create a client socket and connect to a remote device.
213 * @param bdAddr The remote device address to connect.
214 * @param psm BluetoothSocketType is {@link OHOS_SOCKET_L2CAP_LE} use dynamic PSM value from remote device.
215 * BluetoothSocketType is {@link OHOS_SOCKET_SPP_RFCOMM} use -1.
216 * @return Returns a client ID, if connect fail return {@link BT_SOCKET_INVALID_ID}.
217 */
SocketConnect(const BluetoothCreateSocketPara * socketPara,const BdAddr * bdAddr,int psm)218 int SocketConnect(const BluetoothCreateSocketPara *socketPara, const BdAddr *bdAddr, int psm)
219 {
220 HILOGI("SocketConnect start.");
221 if (socketPara == nullptr || bdAddr == nullptr) {
222 HILOGE("socketPara is nullptr, or bdAddr is nullptr");
223 return BT_SOCKET_INVALID_ID;
224 }
225
226 string strAddress;
227 ConvertAddr(bdAddr->addr, strAddress);
228 std::shared_ptr<BluetoothRemoteDevice> device = std::make_shared<BluetoothRemoteDevice>(strAddress, 0);
229
230 UUID serverUuid;
231 if (!GetSocketUuidPara(socketPara, serverUuid)) {
232 return BT_SOCKET_INVALID_ID;
233 }
234
235 std::shared_ptr<ClientSocket> client = std::make_shared<ClientSocket>(*device, serverUuid,
236 BtSocketType(socketPara->socketType), socketPara->isEncrypt);
237 HILOGI("socketType: %{public}d, isEncrypt: %{public}d", socketPara->socketType, socketPara->isEncrypt);
238 client->Init();
239 int result = client->Connect(psm);
240 if (result != OHOS_BT_STATUS_SUCCESS) {
241 HILOGE("SocketConnect fail, result: %{public}d", result);
242 client->Close();
243 HILOGE("SocketConnect closed.");
244 return BT_SOCKET_INVALID_ID;
245 }
246 int clientId = g_clientMap.AddObject(client);
247 HILOGI("SocketConnect success, clientId: %{public}d", clientId);
248 return clientId;
249 }
250
251 /**
252 * @brief Connects to a remote device over the socket.
253 * This method will block until a connection is made or the connection fails.
254 * @param socketPara The param to create a client socket and connect to a remote device.
255 * @param bdAddr The remote device address to connect.
256 * @param psm BluetoothSocketType is {@link OHOS_SOCKET_L2CAP_LE} use dynamic PSM value from remote device.
257 * BluetoothSocketType is {@link OHOS_SOCKET_SPP_RFCOMM} use -1.
258 * @param callback Reference to the socket state observer
259 * @return Returns a client ID, if connect fail return {@link BT_SOCKET_INVALID_ID}.
260 */
SocketConnectEx(const BluetoothCreateSocketPara * socketPara,const BdAddr * bdAddr,int psm,BtSocketConnectionCallback * callback)261 int SocketConnectEx(const BluetoothCreateSocketPara *socketPara, const BdAddr *bdAddr, int psm,
262 BtSocketConnectionCallback *callback)
263 {
264 HILOGI("SocketConnect start.");
265 if (socketPara == nullptr || bdAddr == nullptr || callback == nullptr) {
266 HILOGE("socketPara is nullptr, or bdAddr is nullptr, or callback is nullptr");
267 return BT_SOCKET_INVALID_ID;
268 }
269
270 string strAddress;
271 ConvertAddr(bdAddr->addr, strAddress);
272 std::shared_ptr<BluetoothRemoteDevice> device = std::make_shared<BluetoothRemoteDevice>(strAddress, 0);
273
274 UUID serverUuid;
275 if (!GetSocketUuidPara(socketPara, serverUuid)) {
276 return BT_SOCKET_INVALID_ID;
277 }
278
279 /** Only support registering connection callbacks for sockets of Type TYPE_RFCOMM. */
280 if (socketPara->socketType != OHOS_SOCKET_SPP_RFCOMM) {
281 HILOGE("SocketType is not support");
282 return BT_SOCKET_INVALID_TYPE;
283 }
284
285 std::shared_ptr<BluetoothConnectionObserverWapper> connWrapper =
286 std::make_shared<BluetoothConnectionObserverWapper>(callback);
287 std::shared_ptr<ClientSocket> client = std::make_shared<ClientSocket>(*device, serverUuid,
288 BtSocketType(socketPara->socketType), socketPara->isEncrypt, connWrapper);
289 HILOGI("socketType: %{public}d, isEncrypt: %{public}d", socketPara->socketType, socketPara->isEncrypt);
290 client->Init();
291 int result = client->Connect(psm);
292 if (result != OHOS_BT_STATUS_SUCCESS) {
293 HILOGE("SocketConnect fail, result: %{public}d", result);
294 client->Close();
295 HILOGE("SocketConnect closed.");
296 return BT_SOCKET_INVALID_ID;
297 }
298 int clientId = g_clientMap.AddObject(client);
299 std::lock_guard<std::mutex> lock(g_clientCbMapMutex);
300 g_clientCbMap.insert(std::pair<int, std::shared_ptr<BluetoothConnectionObserverWapper>>(clientId, connWrapper));
301 HILOGI("SocketConnect success, clientId: %{public}d", clientId);
302 return clientId;
303 }
304
305 /**
306 * @brief Disables a connection and releases related resources.
307 *
308 * @param clientId The relative ID used to identify the current client socket.
309 * @return Returns the operation result status {@link BtStatus}.
310 */
SocketDisconnect(int clientId)311 int SocketDisconnect(int clientId)
312 {
313 HILOGI("SocketDisconnect start, clientId: %{public}d", clientId);
314 std::shared_ptr<ClientSocket> client = g_clientMap.GetObject(clientId);
315 if (client == nullptr) {
316 HILOGE("client is null, clientId: %{public}d", clientId);
317 return OHOS_BT_STATUS_FAIL;
318 }
319 client->Close();
320 g_clientMap.RemoveObject(clientId);
321 std::lock_guard<std::mutex> lock(g_clientCbMapMutex);
322 ClientCbIterator it = g_clientCbMap.find(clientId);
323 if (it != g_clientCbMap.end()) {
324 auto &clientWrapper = it->second;
325 if (clientWrapper->callback_ != nullptr) {
326 clientWrapper->callback_ = nullptr;
327 }
328 g_clientCbMap.erase(it);
329 }
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");
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 HILOGI("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!");
394 return OHOS_BT_STATUS_PARM_INVALID;
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
402 int readLen = client->GetInputStream().Read(buf, bufLen);
403 HILOGI("SocketRead ret, clientId: %{public}d, readLen: %{public}d", clientId, readLen);
404 return readLen;
405 }
406
407 /**
408 * @brief Client write data to socket.
409 *
410 * @param clientId The relative ID used to identify the current client socket.
411 * @param data Indicate the data to be written.
412 * @return Returns the actual write length.
413 * Returns {@link BT_SOCKET_WRITE_FAILED} if the operation failed.
414 */
SocketWrite(int clientId,const uint8_t * data,uint32_t len)415 int SocketWrite(int clientId, const uint8_t *data, uint32_t len)
416 {
417 HILOGI("SocketWrite start, clientId: %{public}d, len: %{public}d", clientId, len);
418 if (data == nullptr || len == 0) {
419 HILOGE("data is null or len is 0!");
420 return OHOS_BT_STATUS_PARM_INVALID;
421 }
422 std::shared_ptr<ClientSocket> client = g_clientMap.GetObject(clientId);
423 if (client == nullptr) {
424 HILOGE("client is null!");
425 return OHOS_BT_STATUS_FAIL;
426 }
427 int writeLen = client->GetOutputStream().Write(data, len);
428 HILOGI("end, writeLen: %{public}d", writeLen);
429 return writeLen;
430 }
431
432 /**
433 * @brief Get dynamic PSM value for OHOS_SOCKET_L2CAP.
434 *
435 * @param serverId The relative ID used to identify the current server socket, obtain the value by calling
436 * {@link SocketServerCreate}.
437 * @return Returns the PSM value.
438 * Returns {@link BT_SOCKET_INVALID_PSM} if the operation failed.
439 */
SocketGetPsm(int serverId)440 int SocketGetPsm(int serverId)
441 {
442 HILOGI("serverId: %{public}d", serverId);
443 std::shared_ptr<ServerSocket> server = g_serverMap.GetObject(serverId);
444 CHECK_AND_RETURN_LOG_RET(server, BT_SOCKET_INVALID_PSM, "server is null!");
445 return server->GetL2capPsm();
446 }
447
448 /**
449 * @brief Get server channel number for OHOS_SOCKET_RFCOMM.
450 *
451 * @param serverId The relative ID used to identify the current server socket, obtain the value by calling
452 * {@link SocketServerCreate}.
453 * @return Returns the scn.
454 * Returns {@link BT_SOCKET_INVALID_PSM} if the operation failed.
455 */
SocketGetScn(int serverId)456 int SocketGetScn(int serverId)
457 {
458 HILOGI("serverId: %{public}d", serverId);
459 std::shared_ptr<ServerSocket> server = g_serverMap.GetObject(serverId);
460 CHECK_AND_RETURN_LOG_RET(server, BT_SOCKET_INVALID_SCN, "server is null!");
461 return server->GetRfcommScn();
462 }
463
464 /**
465 * @brief Adjust the socket send and recv buffer size, limit range is 4KB to 50KB
466 *
467 * @param clientId The relative ID used to identify the current client socket.
468 * @param bufferSize The buffer size want to set, unit is byte.
469 * @return Returns the operation result status {@link BtStatus}.
470 */
SetSocketBufferSize(int clientId,uint32_t bufferSize)471 int SetSocketBufferSize(int clientId, uint32_t bufferSize)
472 {
473 HILOGI("start, clientId: %{public}d, bufferSize: %{public}d", clientId, bufferSize);
474 std::shared_ptr<ClientSocket> client = g_clientMap.GetObject(clientId);
475 if (client == nullptr) {
476 HILOGE("client is null!");
477 return OHOS_BT_STATUS_FAIL;
478 }
479 int ret = client->SetBufferSize(bufferSize);
480 if (ret == RET_BAD_PARAM) {
481 return OHOS_BT_STATUS_PARM_INVALID;
482 } else if (ret == RET_BAD_STATUS) {
483 return OHOS_BT_STATUS_FAIL;
484 }
485 return OHOS_BT_STATUS_SUCCESS;
486 }
487 /**
488 * @brief Update the coc connection params
489 *
490 * @param param CocUpdateSocketParam instance for carry params.
491 * @param bdAddr The remote device address to connect.
492 * @return Returns the operation result status {@link BtStatus}.
493 */
SocketUpdateCocConnectionParams(BluetoothCocUpdateSocketParam * param,const BdAddr * bdAddr)494 int SocketUpdateCocConnectionParams(BluetoothCocUpdateSocketParam* param, const BdAddr *bdAddr)
495 {
496 CocUpdateSocketParam params;
497
498 HILOGI("Socket update coc params start");
499 CHECK_AND_RETURN_LOG_RET(param, OHOS_BT_STATUS_FAIL, "param is null");
500 CHECK_AND_RETURN_LOG_RET(bdAddr, OHOS_BT_STATUS_FAIL, "bdAddr is null");
501 ConvertAddr(bdAddr->addr, params.addr);
502 params.minInterval = param->minInterval;
503 params.maxInterval = param->maxInterval;
504 params.peripheralLatency = param->peripheralLatency;
505 params.supervisionTimeout = param->supervisionTimeout;
506 params.minConnEventLen = param->minConnEventLen;
507 params.maxConnEventLen = param->maxConnEventLen;
508
509 std::shared_ptr<BluetoothRemoteDevice> device = std::make_shared<BluetoothRemoteDevice>(params.addr,
510 OHOS_SOCKET_SPP_RFCOMM);
511 std::shared_ptr<ClientSocket> client = std::make_shared<ClientSocket>(*device, UUID::RandomUUID(),
512 TYPE_L2CAP_LE, false);
513 CHECK_AND_RETURN_LOG_RET(client, OHOS_BT_STATUS_FAIL, "client is null");
514 return client->UpdateCocConnectionParams(params);
515 }
516
517 } // namespace Bluetooth
518 } // namespace OHOS
519 #ifdef __cplusplus
520 }
521 #endif