• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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