• 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_socket.h"
24 #include "bluetooth_host.h"
25 #include "bluetooth_log.h"
26 #include "bluetooth_utils.h"
27 #include "bluetooth_object_map.h"
28 
29 #ifdef __cplusplus
30 extern "C" {
31 #endif
32 
33 using namespace std;
34 
35 namespace OHOS {
36 namespace Bluetooth {
37 
38 const int MAX_OBJECT_NUM = 10000;
39 
40 static BluetoothObjectMap<std::shared_ptr<ServerSocket>, MAX_OBJECT_NUM> g_serverMap;
41 static BluetoothObjectMap<std::shared_ptr<ClientSocket>, MAX_OBJECT_NUM> g_clientMap;
42 
GetSocketUuidPara(const BluetoothCreateSocketPara * socketPara,UUID & serverUuid)43 static bool GetSocketUuidPara(const BluetoothCreateSocketPara *socketPara, UUID &serverUuid)
44 {
45     if (socketPara->socketType == OHOS_SOCKET_SPP_RFCOMM) {
46         if (socketPara->uuid.uuid == nullptr || strlen(socketPara->uuid.uuid) != socketPara->uuid.uuidLen) {
47             HILOGE("param uuid invalid!");
48             return false;
49         }
50         string tmpUuid(socketPara->uuid.uuid);
51         if (!regex_match(tmpUuid, uuidRegex)) {
52             HILOGE("match the UUID faild.");
53             return false;
54         }
55         serverUuid = UUID::FromString(tmpUuid);
56     } else if (socketPara->socketType == OHOS_SOCKET_L2CAP_LE) {
57         serverUuid = UUID::RandomUUID();
58     } else {
59         HILOGE("param socketType invalid. socketType: %{public}d", socketPara->socketType);
60         return false;
61     }
62     return true;
63 }
64 
65 /**
66  * @brief Creates an server listening socket based on the service record.
67  *
68  * @param socketPara The parameters to create a server socket.
69  * @param name The service's name.
70  * @return Returns a server ID, if create fail return {@link BT_SOCKET_INVALID_ID}.
71  */
SocketServerCreate(const BluetoothCreateSocketPara * socketPara,const char * name)72 int SocketServerCreate(const BluetoothCreateSocketPara *socketPara, const char *name)
73 {
74     HILOGI("SocketServerCreate start!");
75     if (!IS_BT_ENABLED()) {
76         HILOGE("fail,BR is not TURN_ON");
77         return BT_SOCKET_INVALID_ID;
78     }
79 
80     if (socketPara == nullptr || name == nullptr) {
81         HILOGE("socketPara or name is null.");
82         return BT_SOCKET_INVALID_ID;
83     }
84 
85     UUID serverUuid;
86     if (!GetSocketUuidPara(socketPara, serverUuid)) {
87         return BT_SOCKET_INVALID_ID;
88     }
89 
90     string serverName(name);
91     std::shared_ptr<ServerSocket> server = std::make_shared<ServerSocket>(serverName, serverUuid,
92         BtSocketType(socketPara->socketType), socketPara->isEncrypt);
93     server->Listen();
94     int serverId = g_serverMap.AddObject(server);
95     HILOGI("success, serverId: %{public}d, socketType: %{public}d, isEncrypt: %{public}d", serverId,
96         socketPara->socketType, socketPara->isEncrypt);
97     return serverId;
98 }
99 
100 /**
101  * @brief Waits for a remote device to connect to this server socket.
102  *
103  * This method return a client ID indicates a client socket
104  * can be used to read data from and write data to remote device.
105  * This method will block until a connection is established.
106  *
107  * @param serverId The relative ID used to identify the current server socket, obtain the value by calling
108  * {@link SocketServerCreate}.
109  * @return Returns a client ID, if accept fail return {@link BT_SOCKET_INVALID_ID}.
110  */
SocketServerAccept(int serverId)111 int SocketServerAccept(int serverId)
112 {
113     HILOGI("SocketServerAccept start, serverId: %{public}d", serverId);
114     std::shared_ptr<ServerSocket> server = g_serverMap.GetObject(serverId);
115     if (server == nullptr) {
116         HILOGE("server is null!");
117         return BT_SOCKET_INVALID_ID;
118     }
119 
120     std::shared_ptr<ClientSocket> client = server->Accept(0);
121     if (client == nullptr) {
122         HILOGE("client is null!");
123         return BT_SOCKET_INVALID_ID;
124     }
125     int clientId = g_clientMap.AddObject(client);
126     HILOGI("success, clientId: %{public}d", clientId);
127     return clientId;
128 }
129 
130 /**
131  * @brief Disables an socket server socket and releases related resources.
132  *
133  * @param serverId The relative ID used to identify the current server socket, obtain the value by calling
134  * {@link SocketServerCreate}.
135  * @return Returns the operation result status {@link BtStatus}.
136  */
SocketServerClose(int serverId)137 int SocketServerClose(int serverId)
138 {
139     HILOGI("SocketServerClose start, serverId: %{public}d", serverId);
140     std::shared_ptr<ServerSocket> server = g_serverMap.GetObject(serverId);
141     if (server == nullptr) {
142         HILOGE("server is null!");
143         return OHOS_BT_STATUS_FAIL;
144     }
145     server->Close();
146     g_serverMap.RemoveObject(serverId);
147     return OHOS_BT_STATUS_SUCCESS;
148 }
149 
150 /**
151  * @brief Connects to a remote device over the socket.
152  * This method will block until a connection is made or the connection fails.
153  *
154  * @param socketPara The param to create a client socket and connect to a remote device.
155  * @param bdAddr The remote device address to connect.
156  * @param psm BluetoothSocketType is {@link OHOS_SOCKET_L2CAP_LE} use dynamic PSM value from remote device.
157  * BluetoothSocketType is {@link OHOS_SOCKET_SPP_RFCOMM} use -1.
158  * @return Returns a client ID, if connect fail return {@link BT_SOCKET_INVALID_ID}.
159  */
SocketConnect(const BluetoothCreateSocketPara * socketPara,const BdAddr * bdAddr,int psm)160 int SocketConnect(const BluetoothCreateSocketPara *socketPara, const BdAddr *bdAddr, int psm)
161 {
162     HILOGI("SocketConnect start.");
163     if (socketPara == nullptr || bdAddr == nullptr) {
164         HILOGE("socketPara is nullptr, or bdAddr is nullptr");
165         return BT_SOCKET_INVALID_ID;
166     }
167 
168     string strAddress;
169     ConvertAddr(bdAddr->addr, strAddress);
170     std::shared_ptr<BluetoothRemoteDevice> device = std::make_shared<BluetoothRemoteDevice>(strAddress, 0);
171 
172     UUID serverUuid;
173     if (!GetSocketUuidPara(socketPara, serverUuid)) {
174         return BT_SOCKET_INVALID_ID;
175     }
176 
177     std::shared_ptr<ClientSocket> client = std::make_shared<ClientSocket>(*device, serverUuid,
178         BtSocketType(socketPara->socketType), socketPara->isEncrypt);
179     HILOGI("socketType: %{public}d, isEncrypt: %{public}d", socketPara->socketType, socketPara->isEncrypt);
180     int result = client->Connect(psm);
181     if (result != OHOS_BT_STATUS_SUCCESS) {
182         HILOGE("SocketConnect fail, result: %{public}d", result);
183         return BT_SOCKET_INVALID_ID;
184     }
185     int clientId = g_clientMap.AddObject(client);
186     HILOGI("SocketConnect success, clientId: %{public}d", clientId);
187     return clientId;
188 }
189 
190 /**
191  * @brief Disables a connection and releases related resources.
192  *
193  * @param clientId The relative ID used to identify the current client socket.
194  * @return Returns the operation result status {@link BtStatus}.
195  */
SocketDisconnect(int clientId)196 int SocketDisconnect(int clientId)
197 {
198     HILOGI("SocketDisconnect start, clientId: %{public}d", clientId);
199     std::shared_ptr<ClientSocket> client = g_clientMap.GetObject(clientId);
200     if (client == nullptr) {
201         HILOGE("client is null, clientId: %{public}d", clientId);
202         return OHOS_BT_STATUS_FAIL;
203     }
204     client->Close();
205     g_clientMap.RemoveObject(clientId);
206     HILOGI("SocketDisConnect success, clientId: %{public}d", clientId);
207     return OHOS_BT_STATUS_SUCCESS;
208 }
209 
210 /**
211  * @brief Socket get remote device's address.
212  *
213  * @param clientId The relative ID used to identify the current client socket.
214  * @param remoteAddr Remote device's address, memory allocated by caller.
215  * @return Returns the operation result status {@link BtStatus}.
216  */
SocketGetRemoteAddr(int clientId,BdAddr * remoteAddr)217 int SocketGetRemoteAddr(int clientId, BdAddr *remoteAddr)
218 {
219     HILOGI("SocketGetRemoteAddr clientId: %{public}d", clientId);
220     if (remoteAddr == nullptr) {
221         HILOGE("remoteAddr is null");
222         return OHOS_BT_STATUS_PARM_INVALID;
223     }
224     std::shared_ptr<ClientSocket> client = g_clientMap.GetObject(clientId);
225     if (client == nullptr) {
226         HILOGE("client is null, clientId: %{public}d", clientId);
227         return OHOS_BT_STATUS_FAIL;
228     }
229     string tmpAddr = client->GetRemoteDevice().GetDeviceAddr();
230     GetAddrFromString(tmpAddr, remoteAddr->addr);
231     HILOGI("device: %{public}s", GetEncryptAddr(tmpAddr).c_str());
232     return OHOS_BT_STATUS_SUCCESS;
233 }
234 
235 /**
236  * @brief Get the connection status of this socket.
237  *
238  * @param clientId The relative ID used to identify the current client socket.
239  * @return Returns true is connected or false is not connected.
240  */
IsSocketConnected(int clientId)241 bool IsSocketConnected(int clientId)
242 {
243     HILOGI("IsSocketConnected clientId: %{public}d", clientId);
244     std::shared_ptr<ClientSocket> client = g_clientMap.GetObject(clientId);
245     if (client == nullptr) {
246         HILOGE("client is null, clientId: %{public}d", clientId);
247         return false;
248     }
249     bool isConnected = client->IsConnected();
250     HILOGI("clientId: %{public}d, isConnected: %{public}d", clientId, isConnected);
251     return isConnected;
252 }
253 
254 /**
255  * @brief Read data from socket.
256  * This method blocks until input data is available.
257  *
258  * @param clientId The relative ID used to identify the current client socket.
259  * @param buf Indicate the buffer which read in, memory allocated by caller.
260  * @param bufLen Indicate the buffer length.
261  * @return Returns the length greater than 0 as read the actual length.
262  * Returns {@link BT_SOCKET_READ_SOCKET_CLOSED} if the socket is closed.
263  * Returns {@link BT_SOCKET_READ_FAILED} if the operation failed.
264  */
SocketRead(int clientId,uint8_t * buf,uint32_t bufLen)265 int SocketRead(int clientId, uint8_t *buf, uint32_t bufLen)
266 {
267     HILOGI("SocketRead start, clientId: %{public}d, bufLen: %{public}d", clientId, bufLen);
268     if (buf == nullptr || bufLen == 0) {
269         HILOGE("buf is null or bufLen is 0!");
270         return OHOS_BT_STATUS_PARM_INVALID;
271     }
272     std::shared_ptr<ClientSocket> client = g_clientMap.GetObject(clientId);
273     if (client == nullptr) {
274         HILOGE("client is null, clientId: %{public}d", clientId);
275         return BT_SOCKET_READ_FAILED;
276     }
277 
278     int readLen = client->GetInputStream().Read(buf, bufLen);
279     HILOGI("SocketRead ret, clientId: %{public}d, readLen: %{public}d", clientId, readLen);
280     return readLen;
281 }
282 
283 /**
284  * @brief Client write data to socket.
285  *
286  * @param clientId The relative ID used to identify the current client socket.
287  * @param data Indicate the data to be written.
288  * @return Returns the actual write length.
289  * Returns {@link BT_SOCKET_WRITE_FAILED} if the operation failed.
290  */
SocketWrite(int clientId,const uint8_t * data,uint32_t len)291 int SocketWrite(int clientId, const uint8_t *data, uint32_t len)
292 {
293     HILOGI("SocketWrite start, clientId: %{public}d, len: %{public}d", clientId, len);
294     if (data == nullptr || len == 0) {
295         HILOGE("data is null or len is 0!");
296         return OHOS_BT_STATUS_PARM_INVALID;
297     }
298     std::shared_ptr<ClientSocket> client = g_clientMap.GetObject(clientId);
299     if (client == nullptr) {
300         HILOGE("client is null!");
301         return OHOS_BT_STATUS_FAIL;
302     }
303     size_t writeLen = client->GetOutputStream().Write(data, len);
304     HILOGI("end, writeLen: %{public}zu", writeLen);
305     return static_cast<int>(writeLen);
306 }
307 
308 /**
309  * @brief Get dynamic PSM value.
310  *
311  * @param serverId The relative ID used to identify the current server socket, obtain the value by calling
312  * {@link SocketServerCreate}.
313  * @return Returns the PSM value.
314  * Returns {@link BT_SOCKET_INVALID_PSM} if the operation failed.
315  */
SocketGetPsm(int serverId)316 int SocketGetPsm(int serverId)
317 {
318     HILOGI("SocketGetPsm.");
319     std::shared_ptr<ServerSocket> server = g_serverMap.GetObject(serverId);
320     if (server == nullptr) {
321         HILOGE("server is null!");
322         return BT_SOCKET_INVALID_PSM;
323     }
324     int psm = server->GetPsm();
325     return psm;
326 }
327 
328 /**
329  * @brief Adjust the socket send and recv buffer size, limit range is 4KB to 50KB
330  *
331  * @param clientId The relative ID used to identify the current client socket.
332  * @param bufferSize The buffer size want to set, unit is byte.
333  * @return  Returns the operation result status {@link BtStatus}.
334  */
SetSocketBufferSize(int clientId,uint32_t bufferSize)335 int SetSocketBufferSize(int clientId, uint32_t bufferSize)
336 {
337     HILOGI("start, clientId: %{public}d, bufferSize: %{public}d", clientId, bufferSize);
338     std::shared_ptr<ClientSocket> client = g_clientMap.GetObject(clientId);
339     if (client == nullptr) {
340         HILOGE("client is null!");
341         return OHOS_BT_STATUS_FAIL;
342     }
343     int ret = client->SetBufferSize(bufferSize);
344     if (ret == RET_BAD_PARAM) {
345         return OHOS_BT_STATUS_PARM_INVALID;
346     } else if (ret == RET_BAD_STATUS) {
347         return OHOS_BT_STATUS_FAIL;
348     }
349     return OHOS_BT_STATUS_SUCCESS;
350 }
351 
352 }  // namespace Bluetooth
353 }  // namespace OHOS
354 #ifdef __cplusplus
355 }
356 #endif