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