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