1 /*
2 * Copyright (C) 2021-2022 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_spp.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
28 #ifdef __cplusplus
29 extern "C" {
30 #endif
31
32 using namespace std;
33
34 namespace OHOS {
35 namespace Bluetooth {
36 struct ServerSocketWrapper {
37 std::shared_ptr<SppServerSocket> serverSocket;
38 };
39
40 struct ClientSocketWrapper {
41 std::shared_ptr<SppClientSocket> clientSocket;
42 };
43
44 using SppServerIterator = std::map<int, std::shared_ptr<ServerSocketWrapper>>::iterator;
45 using SppClientIterator = std::map<int, std::shared_ptr<ClientSocketWrapper>>::iterator;
46
47 static int g_serverIncrease = 1;
48 static int g_clientIncrease = 1;
49 static std::map<int, std::shared_ptr<ServerSocketWrapper>> g_SppServerMap;
50 static std::map<int, std::shared_ptr<ClientSocketWrapper>> g_SppClientMap;
51
52 #define SPP_SERVER_MAP g_SppServerMap
53 #define SPP_CLIENT_MAP g_SppClientMap
54
55 /**
56 * @brief Creates an server listening socket based on the service record.
57 *
58 * @param socketPara The parameters to create a server socket.
59 * @param name The service's name.
60 * @param len The length of the service's name.
61 * @return Returns a server ID, if create fail return {@link BT_SPP_INVALID_ID}.
62 */
SppServerCreate(BtCreateSocketPara * socketPara,const char * name,unsigned int len)63 int SppServerCreate(BtCreateSocketPara *socketPara, const char *name, unsigned int len)
64 {
65 HILOGI("start!");
66 if (!IS_BT_ENABLED()) {
67 HILOGE("fail,BR is not TURN_ON");
68 return BT_SPP_INVALID_ID;
69 }
70
71 if (socketPara == nullptr || name == nullptr) {
72 HILOGE("socketPara is nullptr, or name is nullptr");
73 return BT_SPP_INVALID_ID;
74 }
75
76 if (socketPara->socketType != OHOS_SPP_SOCKET_RFCOMM || strlen(name) != len ||
77 strlen(socketPara->uuid.uuid) != socketPara->uuid.uuidLen) {
78 HILOGI("param invalid!");
79 return BT_SPP_INVALID_ID;
80 }
81
82 string serverName(name);
83 string tmpUuid(socketPara->uuid.uuid);
84 if (!regex_match(tmpUuid, uuidRegex)) {
85 HILOGE("match the UUID faild.");
86 return BT_SPP_INVALID_ID;
87 }
88 UUID serverUuid(UUID::FromString(tmpUuid));
89 std::shared_ptr<SppServerSocket> server = std::make_shared<SppServerSocket>(serverName, serverUuid,
90 SppSocketType(socketPara->socketType), socketPara->isEncrypt);
91 HILOGI("socketType: %{public}d, isEncrypt: %{public}d", socketPara->socketType, socketPara->isEncrypt);
92 std::shared_ptr<ServerSocketWrapper> ServerWrap = std::make_shared<ServerSocketWrapper>();
93 ServerWrap->serverSocket = server;
94 int serverId = g_serverIncrease++;
95 SPP_SERVER_MAP.insert(std::make_pair(serverId, ServerWrap));
96 HILOGI("success, serverId: %{public}d", serverId);
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 *
106 * @param serverId The relative ID used to identify the current server socket, obtain the value by calling
107 * {@link SppServerCreate}.
108 * @return Returns a client ID, if accept fail return {@link BT_SPP_INVALID_ID}.
109 */
SppServerAccept(int serverId)110 int SppServerAccept(int serverId)
111 {
112 HILOGI("start, serverId: %{public}d", serverId);
113 SppServerIterator iter = SPP_SERVER_MAP.find(serverId);
114 if (iter == SPP_SERVER_MAP.end()) {
115 HILOGE("serverId is not exist!");
116 return BT_SPP_INVALID_ID;
117 }
118
119 std::shared_ptr<SppServerSocket> server = iter->second->serverSocket;
120 if (server == nullptr) {
121 HILOGE("server is null!");
122 return BT_SPP_INVALID_ID;
123 }
124
125 std::shared_ptr<SppClientSocket> client = server->Accept(0);
126 if (client == nullptr) {
127 HILOGE("client is null!");
128 return BT_SPP_INVALID_ID;
129 }
130
131 std::shared_ptr<ClientSocketWrapper> clientWrap = std::make_shared<ClientSocketWrapper>();
132 clientWrap->clientSocket = client;
133 int clientId = g_clientIncrease++;
134 SPP_CLIENT_MAP.insert(std::make_pair(clientId, clientWrap));
135 HILOGI("success, clientId: %{public}d", clientId);
136 return clientId;
137 }
138
139 /**
140 * @brief Disables an spp server socket and releases related resources.
141 *
142 * @param serverId The relative ID used to identify the current server socket, obtain the value by calling
143 * {@link SppServerCreate}.
144 * @return Returns the operation result status {@link BtStatus}.
145 */
SppServerClose(int serverId)146 int SppServerClose(int serverId)
147 {
148 HILOGI("serverId: %{public}d", serverId);
149 SppServerIterator iter = SPP_SERVER_MAP.find(serverId);
150 if (iter == SPP_SERVER_MAP.end()) {
151 HILOGE("serverId is not exist!");
152 return OHOS_BT_STATUS_FAIL;
153 }
154
155 std::shared_ptr<SppServerSocket> server = iter->second->serverSocket;
156 if (server == nullptr) {
157 HILOGE("server is null!");
158 return OHOS_BT_STATUS_FAIL;
159 }
160 server->Close();
161 SPP_SERVER_MAP.erase(serverId);
162 return OHOS_BT_STATUS_SUCCESS;
163 }
164
165 /**
166 * @brief Connects to a remote device over the socket.
167 *
168 * @param socketPara The param to create a client socket and connect to a remote device.
169 * @return Returns a client ID, if connect fail return {@link BT_SPP_INVALID_ID}.
170 */
SppConnect(BtCreateSocketPara * socketPara,const BdAddr * bdAddr)171 int SppConnect(BtCreateSocketPara *socketPara, const BdAddr *bdAddr)
172 {
173 HILOGI("start!");
174 if (socketPara == nullptr || bdAddr == nullptr) {
175 HILOGE("socketPara is nullptr, or bdAddr is nullptr");
176 return BT_SPP_INVALID_ID;
177 }
178
179 string strAddress;
180 ConvertAddr(bdAddr->addr, strAddress);
181 std::shared_ptr<BluetoothRemoteDevice> device = std::make_shared<BluetoothRemoteDevice>(strAddress, 0);
182 string tmpUuid(socketPara->uuid.uuid);
183 if (!regex_match(tmpUuid, uuidRegex)) {
184 HILOGE("match the UUID faild.");
185 return BT_SPP_INVALID_ID;
186 }
187 UUID serverUuid(UUID::FromString(tmpUuid));
188 std::shared_ptr<SppClientSocket> client = std::make_shared<SppClientSocket>(*device, serverUuid,
189 SppSocketType(socketPara->socketType), socketPara->isEncrypt);
190 HILOGI("socketType: %{public}d, isEncrypt: %{public}d", socketPara->socketType, socketPara->isEncrypt);
191 int result = client->Connect();
192 if (result == OHOS_BT_STATUS_SUCCESS) {
193 std::shared_ptr<ClientSocketWrapper> clientWrap = std::make_shared<ClientSocketWrapper>();
194 clientWrap->clientSocket = client;
195 int clientId = g_clientIncrease++;
196 SPP_CLIENT_MAP.insert(std::make_pair(clientId, clientWrap));
197 HILOGI("success, clientId: %{public}d", clientId);
198 return clientId;
199 } else {
200 HILOGE("fail, result: %{public}d", result);
201 return BT_SPP_INVALID_ID;
202 }
203 }
204
205 /**
206 * @brief Disables a connection and releases related resources.
207 *
208 * @param clientId The relative ID used to identify the current client socket.
209 * @return Returns the operation result status {@link BtStatus}.
210 */
SppDisconnect(int clientId)211 int SppDisconnect(int clientId)
212 {
213 HILOGI("clientId: %{public}d", clientId);
214 SppClientIterator iter = SPP_CLIENT_MAP.find(clientId);
215 if (iter == SPP_CLIENT_MAP.end()) {
216 HILOGE("clientId is not exist!");
217 return OHOS_BT_STATUS_FAIL;
218 }
219 std::shared_ptr<SppClientSocket> client = iter->second->clientSocket;
220 if (client == nullptr) {
221 HILOGE("client is null!");
222 return OHOS_BT_STATUS_FAIL;
223 }
224 client->Close();
225 SPP_CLIENT_MAP.erase(clientId);
226 return OHOS_BT_STATUS_SUCCESS;
227 }
228
229 /**
230 * @brief Spp get remote device's address.
231 *
232 * @param clientId The relative ID used to identify the current client socket.
233 * @param remoteAddr Remote device's address, memory allocated by caller.
234 * @return Returns the operation result status {@link BtStatus}.
235 */
SppGetRemoteAddr(int clientId,BdAddr * remoteAddr)236 int SppGetRemoteAddr(int clientId, BdAddr *remoteAddr)
237 {
238 HILOGI("clientId: %{public}d", clientId);
239 SppClientIterator iter = SPP_CLIENT_MAP.find(clientId);
240 if (iter == SPP_CLIENT_MAP.end()) {
241 HILOGE("clientId is not exist!");
242 return OHOS_BT_STATUS_FAIL;
243 }
244 std::shared_ptr<SppClientSocket> client = iter->second->clientSocket;
245 if (client == nullptr) {
246 HILOGE("client is null!");
247 return OHOS_BT_STATUS_FAIL;
248 }
249 string tmpAddr = client->GetRemoteDevice().GetDeviceAddr();
250 GetAddrFromString(tmpAddr, remoteAddr->addr);
251 HILOGI("device: %{public}s", GetEncryptAddr(tmpAddr).c_str());
252 return OHOS_BT_STATUS_SUCCESS;
253 }
254
255 /**
256 * @brief Get the connection status of this socket.
257 *
258 * @param clientId The relative ID used to identify the current client socket.
259 * @return Returns true is connected or false is not connected.
260 */
IsSppConnected(int clientId)261 bool IsSppConnected(int clientId)
262 {
263 SppClientIterator iter = SPP_CLIENT_MAP.find(clientId);
264 if (iter == SPP_CLIENT_MAP.end()) {
265 HILOGE("clientId is not exist, clientId: %{public}d", clientId);
266 return false;
267 }
268 std::shared_ptr<SppClientSocket> client = iter->second->clientSocket;
269 if (client == nullptr) {
270 HILOGE("client is null, clientId: %{public}d", clientId);
271 return false;
272 }
273 bool isConnected = client->IsConnected();
274 HILOGI("clientId: %{public}d, isConnected: %{public}d", clientId, isConnected);
275 return isConnected;
276 }
277
278 /**
279 * @brief Read data from socket.
280 *
281 * @param clientId The relative ID used to identify the current client socket.
282 * @param buf Indicate the buffer which read in, memory allocated by caller.
283 * @param bufLen Indicate the buffer length.
284 * @return Returns the length greater than 0 as read the actual length.
285 * Returns {@link BT_SPP_READ_SOCKET_CLOSED} if the socket is closed.
286 * Returns {@link BT_SPP_READ_FAILED} if the operation failed.
287 */
SppRead(int clientId,char * buf,const unsigned int bufLen)288 int SppRead(int clientId, char *buf, const unsigned int bufLen)
289 {
290 SppClientIterator iter = SPP_CLIENT_MAP.find(clientId);
291 if (iter == SPP_CLIENT_MAP.end()) {
292 HILOGE("SppRead clientId is not exist!");
293 return BT_SPP_READ_FAILED;
294 }
295 std::shared_ptr<SppClientSocket> client = iter->second->clientSocket;
296 if (client == nullptr) {
297 HILOGE("SppRead client is null!");
298 return BT_SPP_READ_FAILED;
299 }
300 int readLen = client->GetInputStream().Read(buf, bufLen);
301 HILOGI("SppRead ret, clientId: %{public}d, readLen: %{public}d", clientId, readLen);
302 return readLen;
303 }
304
305 /**
306 * @brief Client write data to socket.
307 *
308 * @param clientId The relative ID used to identify the current client socket.
309 * @param data Indicate the data to be written.
310 * @return Returns the actual write length.
311 * Returns {@link BT_SPP_WRITE_FAILED} if the operation failed.
312 */
SppWrite(int clientId,const char * data,const unsigned int len)313 int SppWrite(int clientId, const char *data, const unsigned int len)
314 {
315 HILOGI("start, clientId: %{public}d, len: %{public}d", clientId, len);
316 SppClientIterator iter = SPP_CLIENT_MAP.find(clientId);
317 if (iter == SPP_CLIENT_MAP.end()) {
318 HILOGE("clientId is not exist!");
319 return OHOS_BT_STATUS_FAIL;
320 }
321 std::shared_ptr<SppClientSocket> client = iter->second->clientSocket;
322 if (client == nullptr) {
323 HILOGE("client is null!");
324 return OHOS_BT_STATUS_FAIL;
325 }
326 int writeLen = client->GetOutputStream().Write(data, len);
327 HILOGI("end, writeLen: %{public}d", writeLen);
328 return writeLen;
329 }
330 } // namespace Bluetooth
331 } // namespace OHOS
332 #ifdef __cplusplus
333 }
334 #endif