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 "dsoftbus_adapter_impl.h"
17
18 #include <netinet/in.h>
19 #include <netinet/tcp.h>
20
21 #include "dfs_session.h"
22 #include "securec.h"
23 #include "softbus_bus_center.h"
24 #include "softbus_error_code.h"
25
26 #include "devicestatus_define.h"
27
28 namespace OHOS {
29 namespace Msdp {
30 namespace DeviceStatus {
31 namespace {
32 constexpr HiviewDFX::HiLogLabel LABEL { LOG_CORE, MSDP_DOMAIN_ID, "DSoftbusAdapterImpl" };
33 constexpr size_t BIND_STRING_LENGTH { 10 };
34 constexpr size_t INTERCEPT_STRING_LENGTH { 20 };
35 constexpr size_t DEVICE_NAME_SIZE_MAX { 256 };
36 constexpr size_t PKG_NAME_SIZE_MAX { 65 };
37 constexpr int32_t MIN_BW { 80 * 1024 * 1024 };
38 constexpr int32_t LATENCY { 1600 };
39 constexpr int32_t SOCKET_SERVER { 0 };
40 constexpr int32_t SOCKET_CLIENT { 1 };
41 }
42
43 std::mutex DSoftbusAdapterImpl::mutex_;
44
GetInstance()45 DSoftbusAdapterImpl& DSoftbusAdapterImpl::GetInstance()
46 {
47 std::lock_guard<std::mutex> lock(mutex_);
48 static DSoftbusAdapterImpl instance;
49 return instance;
50 }
51
~DSoftbusAdapterImpl()52 DSoftbusAdapterImpl::~DSoftbusAdapterImpl()
53 {
54 Disable();
55 }
56
Enable()57 int32_t DSoftbusAdapterImpl::Enable()
58 {
59 CALL_DEBUG_ENTER;
60 std::lock_guard guard(lock_);
61 return SetupServer();
62 }
63
Disable()64 void DSoftbusAdapterImpl::Disable()
65 {
66 CALL_DEBUG_ENTER;
67 std::lock_guard guard(lock_);
68 ShutdownServer();
69 }
70
AddObserver(std::shared_ptr<IDSoftbusObserver> observer)71 void DSoftbusAdapterImpl::AddObserver(std::shared_ptr<IDSoftbusObserver> observer)
72 {
73 CALL_DEBUG_ENTER;
74 std::lock_guard guard(lock_);
75 CHKPV(observer);
76 observers_.erase(Observer());
77 observers_.emplace(observer);
78 }
79
RemoveObserver(std::shared_ptr<IDSoftbusObserver> observer)80 void DSoftbusAdapterImpl::RemoveObserver(std::shared_ptr<IDSoftbusObserver> observer)
81 {
82 CALL_DEBUG_ENTER;
83 std::lock_guard guard(lock_);
84 if (auto iter = observers_.find(Observer(observer)); iter != observers_.end()) {
85 observers_.erase(iter);
86 }
87 observers_.erase(Observer());
88 }
89
OpenSession(const std::string & networkId)90 int32_t DSoftbusAdapterImpl::OpenSession(const std::string &networkId)
91 {
92 CALL_DEBUG_ENTER;
93 std::lock_guard guard(lock_);
94 return OpenSessionLocked(networkId);
95 }
96
CloseSession(const std::string & networkId)97 void DSoftbusAdapterImpl::CloseSession(const std::string &networkId)
98 {
99 CALL_DEBUG_ENTER;
100 std::lock_guard guard(lock_);
101 if (auto iter = sessions_.find(networkId); iter != sessions_.end()) {
102 Shutdown(iter->second.socket_);
103 sessions_.erase(iter);
104 }
105 }
106
FindConnection(const std::string & networkId)107 int32_t DSoftbusAdapterImpl::FindConnection(const std::string &networkId)
108 {
109 std::lock_guard guard(lock_);
110 auto iter = sessions_.find(networkId);
111 return (iter != sessions_.end() ? iter->second.socket_ : -1);
112 }
113
SendPacket(const std::string & networkId,NetPacket & packet)114 int32_t DSoftbusAdapterImpl::SendPacket(const std::string &networkId, NetPacket &packet)
115 {
116 int32_t socket = FindConnection(networkId);
117 if (socket < 0) {
118 FI_HILOGE("Node \'%{public}s\' is not connected", networkId.c_str());
119 return RET_ERR;
120 }
121 StreamBuffer buffer;
122 packet.MakeData(buffer);
123 if (buffer.Size() > MAX_PACKET_BUF_SIZE) {
124 FI_HILOGE("Packet is too large");
125 return RET_ERR;
126 }
127 int32_t ret = ::SendBytes(socket, buffer.Data(), buffer.Size());
128 if (ret != SOFTBUS_OK) {
129 FI_HILOGE("DSOFTBUS::SendBytes fail (%{public}d)", ret);
130 return RET_ERR;
131 }
132 return RET_OK;
133 }
134
OnBindLink(int32_t socket,PeerSocketInfo info)135 static void OnBindLink(int32_t socket, PeerSocketInfo info)
136 {
137 DSoftbusAdapterImpl::GetInstance()->OnBind(socket, info);
138 }
139
OnShutdownLink(int32_t socket,ShutdownReason reason)140 static void OnShutdownLink(int32_t socket, ShutdownReason reason)
141 {
142 DSoftbusAdapterImpl::GetInstance()->OnShutdown(socket, reason);
143 }
144
OnBytesAvailable(int32_t socket,const void * data,uint32_t dataLen)145 static void OnBytesAvailable(int32_t socket, const void *data, uint32_t dataLen)
146 {
147 DSoftbusAdapterImpl::GetInstance()->OnBytes(socket, data, dataLen);
148 }
149
OnBind(int32_t socket,PeerSocketInfo info)150 void DSoftbusAdapterImpl::OnBind(int32_t socket, PeerSocketInfo info)
151 {
152 std::lock_guard guard(lock_);
153 std::string networkId = info.networkId;
154
155 if (auto iter = sessions_.find(networkId); iter != sessions_.cend()) {
156 return;
157 }
158 ConfigTcpAlive(socket);
159 sessions_.emplace(networkId, Session(socket));
160
161 for (const auto &item : observers_) {
162 std::shared_ptr<IDSoftbusObserver> observer = item.Lock();
163 if (observer != nullptr) {
164 observer->OnBind(networkId);
165 }
166 }
167 }
168
OnShutdown(int32_t socket,ShutdownReason reason)169 void DSoftbusAdapterImpl::OnShutdown(int32_t socket, ShutdownReason reason)
170 {
171 std::lock_guard guard(lock_);
172 auto iter = std::find_if(sessions_.cbegin(), sessions_.cend(),
173 [socket](const auto &item) {
174 return (item.second.socket_ == socket);
175 });
176 if (iter == sessions_.cend()) {
177 return;
178 }
179 std::string networkId = iter->first;
180 sessions_.erase(iter);
181
182 for (const auto &item : observers_) {
183 std::shared_ptr<IDSoftbusObserver> observer = item.Lock();
184 if (observer != nullptr) {
185 observer->OnShutdown(networkId);
186 }
187 }
188 }
189
OnBytes(int32_t socket,const void * data,uint32_t dataLen)190 void DSoftbusAdapterImpl::OnBytes(int32_t socket, const void *data, uint32_t dataLen)
191 {
192 std::lock_guard guard(lock_);
193 auto iter = std::find_if(sessions_.begin(), sessions_.end(),
194 [socket](const auto &item) {
195 return (item.second.socket_ == socket);
196 });
197 if (iter == sessions_.end()) {
198 FI_HILOGE("Invalid socket: %{public}d", socket);
199 return;
200 }
201 std::string networkId = iter->first;
202 CircleStreamBuffer &circleBuffer = iter->second.buffer_;
203
204 if (!circleBuffer.Write(reinterpret_cast<const char *>(data), dataLen)) {
205 FI_HILOGE("Failed to write buffer");
206 }
207 HandleSessionData(networkId, circleBuffer);
208 }
209
InitSocket(SocketInfo info,int32_t socketType,int32_t & socket)210 int32_t DSoftbusAdapterImpl::InitSocket(SocketInfo info, int32_t socketType, int32_t &socket)
211 {
212 socket = ::Socket(info);
213 if (socket < 0) {
214 FI_HILOGE("DSOFTBUS::Socket failed");
215 return RET_ERR;
216 }
217 QosTV socketQos[] {
218 { .qos = QOS_TYPE_MIN_BW, .value = MIN_BW },
219 { .qos = QOS_TYPE_MAX_LATENCY, .value = LATENCY },
220 { .qos = QOS_TYPE_MIN_LATENCY, .value = LATENCY },
221 };
222 ISocketListener listener {
223 .OnBind = OnBindLink,
224 .OnShutdown = OnShutdownLink,
225 .OnBytes = OnBytesAvailable,
226 };
227 int32_t ret { -1 };
228
229 if (socketType == SOCKET_SERVER) {
230 ret = ::Listen(socket, socketQos, sizeof(socketQos) / sizeof(socketQos[0]), &listener);
231 if (ret != 0) {
232 FI_HILOGE("DSOFTBUS::Listen failed");
233 }
234 } else if (socketType == SOCKET_CLIENT) {
235 ret = ::Bind(socket, socketQos, sizeof(socketQos) / sizeof(socketQos[0]), &listener);
236 if (ret != 0) {
237 FI_HILOGE("DSOFTBUS::Bind failed");
238 }
239 }
240 if (ret != 0) {
241 ::Shutdown(socket);
242 socket = -1;
243 return RET_ERR;
244 }
245 return RET_OK;
246 }
247
SetupServer()248 int32_t DSoftbusAdapterImpl::SetupServer()
249 {
250 CALL_DEBUG_ENTER;
251 if (socketFd_ > 0) {
252 return RET_OK;
253 }
254 const std::string SESS_NAME { "ohos.msdp.device_status." };
255 std::string localNetworkId = GetLocalNetworkId();
256 if (localNetworkId.empty()) {
257 FI_HILOGE("Local network id is empty");
258 return RET_ERR;
259 }
260 localSessionName_ = SESS_NAME + localNetworkId.substr(0, BIND_STRING_LENGTH);
261 std::string sessionName { SESS_NAME + localNetworkId.substr(0, INTERCEPT_STRING_LENGTH) };
262 char name[DEVICE_NAME_SIZE_MAX] {};
263 if (strcpy_s(name, sizeof(name), sessionName.c_str()) != EOK) {
264 FI_HILOGE("Invalid name:%{public}s", sessionName.c_str());
265 return RET_ERR;
266 }
267 char pkgName[PKG_NAME_SIZE_MAX] { FI_PKG_NAME };
268
269 SocketInfo info {
270 .name = name,
271 .pkgName = pkgName,
272 .dataType = DATA_TYPE_BYTES
273 };
274 int32_t ret = InitSocket(info, SOCKET_SERVER, socketFd_);
275 if (ret != RET_OK) {
276 FI_HILOGE("Failed to setup server");
277 return RET_ERR;
278 }
279 return RET_OK;
280 }
281
ShutdownServer()282 void DSoftbusAdapterImpl::ShutdownServer()
283 {
284 CALL_DEBUG_ENTER;
285 std::for_each(sessions_.begin(), sessions_.end(), [](const auto &item) {
286 Shutdown(item.second.socket_);
287 });
288 sessions_.clear();
289 if (socketFd_ > 0) {
290 Shutdown(socketFd_);
291 socketFd_ = -1;
292 }
293 }
294
OpenSessionLocked(const std::string & networkId)295 int32_t DSoftbusAdapterImpl::OpenSessionLocked(const std::string &networkId)
296 {
297 CALL_DEBUG_ENTER;
298 if (sessions_.find(networkId) != sessions_.end()) {
299 FI_HILOGD("InputSoftbus session has already opened");
300 return RET_OK;
301 }
302 char name[DEVICE_NAME_SIZE_MAX] {};
303 if (strcpy_s(name, sizeof(name), localSessionName_.c_str()) != EOK) {
304 FI_HILOGE("Invalid name:%{public}s", localSessionName_.c_str());
305 return RET_ERR;
306 }
307 const std::string SESSION_NAME { "ohos.msdp.device_status." };
308 std::string peerSessionName { SESSION_NAME + networkId.substr(0, INTERCEPT_STRING_LENGTH) };
309 char peerName[DEVICE_NAME_SIZE_MAX] {};
310 if (strcpy_s(peerName, sizeof(peerName), peerSessionName.c_str()) != EOK) {
311 FI_HILOGE("Invalid peerSessionName:%{public}s", peerSessionName.c_str());
312 return RET_ERR;
313 }
314 char peerNetworkId[PKG_NAME_SIZE_MAX] {};
315 if (strcpy_s(peerNetworkId, sizeof(peerNetworkId), networkId.c_str()) != EOK) {
316 FI_HILOGE("Invalid peerNetworkId:%{public}s", networkId.c_str());
317 return RET_ERR;
318 }
319 char pkgName[PKG_NAME_SIZE_MAX] { FI_PKG_NAME };
320 SocketInfo info {
321 .name = name,
322 .peerName = peerName,
323 .peerNetworkId = peerNetworkId,
324 .pkgName = pkgName,
325 .dataType = DATA_TYPE_BYTES
326 };
327 int32_t socket { -1 };
328
329 int32_t ret = InitSocket(info, SOCKET_CLIENT, socket);
330 if (ret != RET_OK) {
331 FI_HILOGE("Failed to bind %{public}s", networkId.c_str());
332 return ret;
333 }
334 ConfigTcpAlive(socket);
335
336 sessions_.emplace(networkId, Session(socket));
337 return RET_OK;
338 }
339
ConfigTcpAlive(int32_t socket)340 void DSoftbusAdapterImpl::ConfigTcpAlive(int32_t socket)
341 {
342 CALL_DEBUG_ENTER;
343 if (socket < 0) {
344 FI_HILOGW("Config tcp alive, invalid sessionId");
345 return;
346 }
347 int32_t handle { -1 };
348 int32_t result = GetSessionHandle(socket, &handle);
349 if (result != RET_OK) {
350 FI_HILOGE("Failed to get the session handle, socketId:%{public}d, handle:%{public}d", socket, handle);
351 return;
352 }
353 int32_t keepAliveTimeout { 10 };
354 result = setsockopt(handle, IPPROTO_TCP, TCP_KEEPIDLE, &keepAliveTimeout, sizeof(keepAliveTimeout));
355 if (result != RET_OK) {
356 FI_HILOGE("Config tcp alive, setsockopt set idle falied, result:%{public}d", result);
357 return;
358 }
359 int32_t keepAliveCount { 5 };
360 result = setsockopt(handle, IPPROTO_TCP, TCP_KEEPCNT, &keepAliveCount, sizeof(keepAliveCount));
361 if (result != RET_OK) {
362 FI_HILOGE("Config tcp alive, setsockopt set cnt falied");
363 return;
364 }
365 int32_t interval { 1 };
366 result = setsockopt(handle, IPPROTO_TCP, TCP_KEEPINTVL, &interval, sizeof(interval));
367 if (result != RET_OK) {
368 FI_HILOGE("Config tcp alive, setsockopt set intvl falied");
369 return;
370 }
371 int32_t enable { 1 };
372 result = setsockopt(handle, SOL_SOCKET, SO_KEEPALIVE, &enable, sizeof(enable));
373 if (result != RET_OK) {
374 FI_HILOGE("Config tcp alive, setsockopt enable alive falied");
375 return;
376 }
377 }
378
HandleSessionData(const std::string & networkId,CircleStreamBuffer & circleBuffer)379 void DSoftbusAdapterImpl::HandleSessionData(const std::string &networkId, CircleStreamBuffer &circleBuffer)
380 {
381 while (circleBuffer.ResidualSize() >= static_cast<int32_t>(sizeof(PackHead))) {
382 const char *buf = circleBuffer.ReadBuf();
383 const PackHead *head = reinterpret_cast<const PackHead *>(buf);
384
385 if ((head->size < 0) || (static_cast<size_t>(head->size) > MAX_PACKET_BUF_SIZE)) {
386 FI_HILOGE("Corrupted net packet");
387 break;
388 }
389 if ((head->size + static_cast<int32_t>(sizeof(PackHead))) > circleBuffer.ResidualSize()) {
390 break;
391 }
392 NetPacket packet(head->idMsg);
393
394 if ((head->size > 0) && !packet.Write(&buf[sizeof(PackHead)], head->size)) {
395 FI_HILOGE("Failed to fill packet, PacketSize:%{public}d", head->size);
396 break;
397 }
398 circleBuffer.SeekReadPos(packet.GetPacketLength());
399 HandlePacket(networkId, packet);
400 }
401 }
402
HandlePacket(const std::string & networkId,NetPacket & packet)403 void DSoftbusAdapterImpl::HandlePacket(const std::string &networkId, NetPacket &packet)
404 {
405 for (const auto &item : observers_) {
406 std::shared_ptr<IDSoftbusObserver> observer = item.Lock();
407 if (observer != nullptr) {
408 observer->OnPacket(networkId, packet);
409 return;
410 }
411 }
412 }
413 } // namespace DeviceStatus
414 } // namespace Msdp
415 } // namespace OHOS
416