1 /*
2 * Copyright (C) 2025 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 #ifndef LOG_TAG
16 #define LOG_TAG "bt_cj_socket_spp_client"
17 #endif
18
19 #include "bluetooth_spp_client_impl.h"
20
21 #include "bluetooth_errorcode.h"
22 #include "bluetooth_host.h"
23 #include "cj_lambda.h"
24 #include "datetime_ex.h"
25 #include "napi_bluetooth_utils.h"
26 #include "securec.h"
27
28 namespace OHOS {
29 namespace Bluetooth {
30 std::map<int, std::shared_ptr<SppClientImpl>> SppClientImpl::clientMap;
31 int SppClientImpl::count = 0;
32 const int SOCKET_BUFFER_SIZE = 1024;
33
SppConnect(std::string deviceId,SppOption sppOption,int32_t * errCode)34 int32_t SppClientImpl::SppConnect(std::string deviceId, SppOption sppOption, int32_t* errCode)
35 {
36 HILOGD("enter");
37 std::shared_ptr<BluetoothRemoteDevice> device_ = std::make_shared<BluetoothRemoteDevice>(deviceId, 0);
38 std::shared_ptr<ClientSocket> client_ =
39 std::make_shared<ClientSocket>(*device_, UUID::FromString(sppOption.uuid_), sppOption.type_, sppOption.secure_);
40 int errorCode = client_->Connect(SPP_SOCKET_PSM_VALUE);
41 if (errorCode != BtStatus::BT_SUCCESS) {
42 HILOGE("SppConnect failed");
43 *errCode = errorCode;
44 return -1;
45 }
46 std::shared_ptr<SppClientImpl> client = std::make_shared<SppClientImpl>();
47 client->device_ = device_;
48 client->id_ = SppClientImpl::count++;
49 client->client_ = client_;
50 clientMap.insert(std::make_pair(client->id_, client));
51 HILOGD("SppConnect execute back successfully");
52 return client->id_;
53 }
54
SppCloseClientSocket(int32_t socket)55 int32_t SppClientImpl::SppCloseClientSocket(int32_t socket)
56 {
57 HILOGD("enter");
58 std::shared_ptr<SppClientImpl> client = nullptr;
59 bool isOK = false;
60
61 if (clientMap[socket]) {
62 client = clientMap[socket];
63 } else {
64 HILOGE("invalid socket.");
65 return BT_ERR_INVALID_PARAM;
66 }
67
68 if (client->client_) {
69 client->client_->Close();
70 isOK = true;
71 }
72 clientMap.erase(socket);
73 return isOK ? 0 : BT_ERR_INVALID_PARAM;
74 }
75
SppWrite(int32_t clientSocket,CArrUI8 data)76 int32_t SppClientImpl::SppWrite(int32_t clientSocket, CArrUI8 data)
77 {
78 HILOGD("enter");
79 BluetoothHost* host = &BluetoothHost::GetDefaultHost();
80 auto prohibitedTime = host->GetRefusePolicyProhibitedTime();
81 if (prohibitedTime < 0 || prohibitedTime > GetSecondsSince1970ToNow()) {
82 HILOGE("socket refuse because of Refuse Policy");
83 return BT_ERR_INVALID_PARAM;
84 }
85 auto client = clientMap[clientSocket];
86 if (client == nullptr) {
87 HILOGE("client is nullptr.");
88 return BT_ERR_INVALID_PARAM;
89 }
90 if (client->client_ == nullptr) {
91 HILOGE("client_ is nullptr.");
92 return BT_ERR_INVALID_PARAM;
93 }
94 std::shared_ptr<OutputStream> outputStream = client->client_->GetOutputStream();
95 size_t totalSize = static_cast<size_t>(data.size);
96 bool isOK = false;
97 while (totalSize) {
98 int result = outputStream->Write(data.head, totalSize);
99 if (result <= 0) {
100 HILOGE("outputStream.Write failed, ret = %{public}d", result);
101 return BT_ERR_SPP_IO;
102 }
103 totalSize = totalSize - static_cast<size_t>(result);
104 data.head += static_cast<size_t>(result);
105 isOK = true;
106 }
107 return isOK ? 0 : BT_ERR_INVALID_PARAM;
108 }
109
On(std::string type,int32_t clientSocket,int64_t cbId)110 int32_t SppClientImpl::On(std::string type, int32_t clientSocket, int64_t cbId)
111 {
112 HILOGD("enter");
113 std::shared_ptr<CjBluetoothCallbackInfo> callbackInfo = std::make_shared<BufferCallbackInfo>();
114 callbackInfo->callback_ = cbId;
115 std::shared_ptr<SppClientImpl> client = SppClientImpl::clientMap[clientSocket];
116 if (client == nullptr) {
117 HILOGE("client is nullptr.");
118 return BT_ERR_INVALID_PARAM;
119 }
120 if (client->sppReadFlag) {
121 HILOGE("client is reading... please off first");
122 return BT_ERR_INVALID_PARAM;
123 }
124 client->sppReadFlag = true;
125 client->callbackInfos_[type] = callbackInfo;
126 client->thread_ = std::make_shared<std::thread>(SppClientImpl::SppRead, clientSocket);
127 client->thread_->detach();
128 return 0;
129 }
130
Off(std::string type,int32_t clientSocket,int64_t cbId)131 int32_t SppClientImpl::Off(std::string type, int32_t clientSocket, int64_t cbId)
132 {
133 HILOGD("enter");
134 std::shared_ptr<SppClientImpl> client = SppClientImpl::clientMap[clientSocket];
135 if (client == nullptr) {
136 HILOGE("client is nullptr.");
137 return BT_ERR_INVALID_PARAM;
138 }
139 client->callbackInfos_[type] = nullptr;
140 client->sppReadFlag = false;
141 return 0;
142 }
143
SppRead(int id)144 void SppClientImpl::SppRead(int id)
145 {
146 auto client = clientMap[id];
147 if (client == nullptr || !client->sppReadFlag || client->callbackInfos_[REGISTER_SPP_READ_TYPE] == nullptr) {
148 HILOGE("thread start failed.");
149 return;
150 }
151 std::shared_ptr<InputStream> inputStream = client->client_->GetInputStream();
152 uint8_t buf[SOCKET_BUFFER_SIZE];
153
154 while (true) {
155 HILOGD("thread start.");
156 (void)memset_s(buf, SOCKET_BUFFER_SIZE, 0, SOCKET_BUFFER_SIZE);
157 int ret = inputStream->Read(buf, sizeof(buf));
158 if (ret <= 0) {
159 HILOGE("inputStream.Read failed, ret = %{public}d", ret);
160 return;
161 } else {
162 if (client == nullptr || !client->sppReadFlag || !client->callbackInfos_[REGISTER_SPP_READ_TYPE]) {
163 HILOGE("failed");
164 return;
165 }
166 std::shared_ptr<BufferCallbackInfo> callbackInfo =
167 std::static_pointer_cast<BufferCallbackInfo>(client->callbackInfos_[REGISTER_SPP_READ_TYPE]);
168 if (callbackInfo == nullptr) {
169 HILOGE("callbackInfo nullptr");
170 return;
171 }
172
173 CArrUI8 buffer {};
174 buffer.head = static_cast<uint8_t*>(malloc(sizeof(uint8_t) * ret));
175 if (buffer.head == nullptr) {
176 HILOGE("malloc failed!");
177 return;
178 }
179 buffer.size = ret;
180 if (memcpy_s(buffer.head, ret, buf, ret) != EOK) {
181 HILOGE("memcpy_s failed!");
182 free(buffer.head);
183 return;
184 }
185
186 auto cFunc = reinterpret_cast<void (*)(CArrUI8)>(callbackInfo->callback_);
187 std::function<void(CArrUI8)> func = CJLambda::Create(cFunc);
188 func(buffer);
189 free(buffer.head);
190 }
191 }
192 return;
193 }
194
GetDeviceId(int32_t clientSocket,int32_t * errCode)195 std::string SppClientImpl::GetDeviceId(int32_t clientSocket, int32_t* errCode)
196 {
197 HILOGD("enter");
198 auto client = clientMap[clientSocket];
199 if (client == nullptr) {
200 *errCode = BT_ERR_INVALID_PARAM;
201 return std::string();
202 }
203 if (client->client_ == nullptr) {
204 *errCode = BT_ERR_INVALID_PARAM;
205 return std::string();
206 }
207 BluetoothRemoteDevice remoteDevice = client->client_->GetRemoteDevice();
208 std::string addr = remoteDevice.GetDeviceAddr();
209 return addr;
210 }
211 } // namespace Bluetooth
212 } // namespace OHOS