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