1/*
2 * Copyright (c) 2022-2024 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 "softbus_adapter.h"
17
18#include <securec.h>
19#include <unistd.h>
20
21#include "softbus_bus_center.h"
22#include "softbus_common.h"
23
24#include "dscreen_errcode.h"
25#include "dscreen_hisysevent.h"
26#include "dscreen_util.h"
27
28namespace OHOS {
29namespace DistributedHardware {
30IMPLEMENT_SINGLE_INSTANCE(SoftbusAdapter);
31static void ScreenOnSoftbusSessionOpened(int32_t sessionId, PeerSocketInfo info)
32{
33    SoftbusAdapter::GetInstance().OnSoftbusSessionOpened(sessionId, info);
34}
35
36static void ScreenOnSoftbusSessionClosed(int32_t sessionId, ShutdownReason reason)
37{
38    SoftbusAdapter::GetInstance().OnSoftbusSessionClosed(sessionId, reason);
39}
40
41static void ScreenOnBytesReceived(int32_t sessionId, const void *data, uint32_t dataLen)
42{
43    SoftbusAdapter::GetInstance().OnBytesReceived(sessionId, data, dataLen);
44}
45
46static void ScreenOnStreamReceived(int32_t sessionId, const StreamData *data, const StreamData *ext,
47    const StreamFrameInfo *frameInfo)
48{
49    SoftbusAdapter::GetInstance().OnStreamReceived(sessionId, data, ext, frameInfo);
50}
51
52static void ScreenOnMessageReceived(int sessionId, const void *data, unsigned int dataLen)
53{
54    SoftbusAdapter::GetInstance().OnMessageReceived(sessionId, data, dataLen);
55}
56
57SoftbusAdapter::SoftbusAdapter()
58{
59    DHLOGI("SoftbusAdapter");
60    sessListener_.OnBind = ScreenOnSoftbusSessionOpened;
61    sessListener_.OnShutdown = ScreenOnSoftbusSessionClosed;
62    sessListener_.OnBytes = ScreenOnBytesReceived;
63    sessListener_.OnStream = ScreenOnStreamReceived;
64    sessListener_.OnMessage = ScreenOnMessageReceived;
65    sessListener_.OnFile = nullptr;
66    sessListener_.OnQos = nullptr;
67    sessListener_.OnError = nullptr;
68    sessListener_.OnNegotiate = nullptr;
69}
70
71SoftbusAdapter::~SoftbusAdapter()
72{
73    DHLOGI("~SoftbusAdapter");
74}
75
76int32_t SoftbusAdapter::RegisterSoftbusListener(const std::shared_ptr<ISoftbusListener> &listener,
77    const std::string &sessionName, const std::string &peerDevId)
78{
79    if (listener == nullptr) {
80        DHLOGE("%{public}s: listener is nullptr.", DSCREEN_LOG_TAG);
81        return ERR_DH_SCREEN_ADAPTER_REGISTER_SOFTBUS_LISTENER_FAIL;
82    }
83    DHLOGI("%{public}s: RegisterListener sess:%{public}s id:%{public}s.", DSCREEN_LOG_TAG, sessionName.c_str(),
84        GetAnonyString(peerDevId).c_str());
85    std::string strListenerKey = sessionName + "_" + peerDevId;
86    std::lock_guard<std::mutex> lisLock(listenerMtx_);
87    if (mapListeners_.find(strListenerKey) != mapListeners_.end()) {
88        DHLOGE("%{public}s: Session listener already register.", DSCREEN_LOG_TAG);
89        return ERR_DH_SCREEN_ADAPTER_REGISTER_SOFTBUS_LISTENER_FAIL;
90    }
91    mapListeners_.insert(std::make_pair(strListenerKey, listener));
92
93    return DH_SUCCESS;
94}
95
96int32_t SoftbusAdapter::UnRegisterSoftbusListener(const std::string &sessionName, const std::string &peerDevId)
97{
98    DHLOGI("%{public}s: UnRegisterListener sess:%{public}s id:%{public}s.", DSCREEN_LOG_TAG, sessionName.c_str(),
99        GetAnonyString(peerDevId).c_str());
100    std::string strListenerKey = sessionName + "_" + peerDevId;
101
102    std::lock_guard<std::mutex> lisLock(listenerMtx_);
103    mapListeners_.erase(strListenerKey);
104
105    return DH_SUCCESS;
106}
107
108int32_t SoftbusAdapter::CreateSoftbusSessionServer(const std::string &pkgname, const std::string &sessionName,
109    const std::string &peerDevId)
110{
111    DHLOGI("%{public}s: CreateSessionServer sess:%{public}s id:%{public}s.", DSCREEN_LOG_TAG, sessionName.c_str(),
112        GetAnonyString(peerDevId).c_str());
113    {
114        std::lock_guard<std::mutex> lock(serverIdMapMutex_);
115        std::string idMapValue = sessionName + "_" + peerDevId;
116        for (auto it = serverIdMap_.begin(); it != serverIdMap_.end(); it++) {
117            if (((it->second).find(idMapValue) != std::string::npos)) {
118                DHLOGI("%{public}s: Session already create.", sessionName.c_str());
119                return DH_SUCCESS;
120            }
121        }
122    }
123
124    SocketInfo serverInfo = {
125        .name = const_cast<char*>(sessionName.c_str()),
126        .pkgName = const_cast<char*>(pkgname.c_str()),
127        .dataType = DATA_TYPE_VIDEO_STREAM,
128    };
129    int32_t socketId = Socket(serverInfo);
130    if (socketId < 0) {
131        DHLOGE("Create Socket fail socketId:%{public}" PRId32, socketId);
132        return ERR_DH_SCREEN_ADAPTER_BAD_VALUE;
133    }
134    QosTV qos[] = {
135        {.qos = QOS_TYPE_MIN_BW,        .value = 40 * 1024 * 1024},
136        {.qos = QOS_TYPE_MAX_LATENCY,        .value = 8000},
137        {.qos = QOS_TYPE_MIN_LATENCY,        .value = 2000},
138    };
139
140    int32_t ret = Listen(socketId, qos, sizeof(qos) / sizeof(qos[0]), &sessListener_);
141    if (ret != DH_SUCCESS) {
142        DHLOGE("Listen socket error for sessionName:%{public}s", sessionName.c_str());
143        return ERR_DH_SCREEN_ADAPTER_BAD_VALUE;
144    }
145    {
146        std::lock_guard<std::mutex> lock(serverIdMapMutex_);
147        serverIdMap_.insert(std::make_pair(socketId, sessionName + "_" + peerDevId));
148    }
149    DHLOGI("%{public}s: CreateSessionServer success sessionId. %{public}" PRId32, DSCREEN_LOG_TAG, socketId);
150    return DH_SUCCESS;
151}
152
153int32_t SoftbusAdapter::RemoveSoftbusSessionServer(const std::string &pkgname, const std::string &sessionName,
154    const std::string &peerDevId)
155{
156    (void)pkgname;
157    if (sessionName.empty() || peerDevId.empty()) {
158        return ERR_DH_SCREEN_TRANS_NULL_VALUE;
159    }
160    DHLOGI("%{public}s: RemoveSessionServer sess:%{public}s id:%{public}s", DSCREEN_LOG_TAG, sessionName.c_str(),
161        GetAnonyString(peerDevId).c_str());
162    int32_t serverSocketId = INVALID_SESSION_ID;
163    {
164        std::lock_guard<std::mutex> lock(serverIdMapMutex_);
165        std::string idMapValue = sessionName + "_" + peerDevId;
166        for (auto it = serverIdMap_.begin(); it != serverIdMap_.end();) {
167            if (((it->second).find(idMapValue) != std::string::npos)) {
168                serverSocketId = it->first;
169                it = serverIdMap_.erase(it);
170            } else {
171                ++it;
172            }
173        }
174    }
175    Shutdown(serverSocketId);
176    DHLOGI("%{public}s: RemoveSessionServer success.", DSCREEN_LOG_TAG);
177    return DH_SUCCESS;
178}
179
180int32_t SoftbusAdapter::OpenSoftbusSession(const std::string &mySessionName, const std::string &peerSessionName,
181    const std::string &peerDevId)
182{
183    DHLOGI("%{public}s: OpenSoftbusSession mysess:%{public}s peersess:%{public}s id:%{public}s.", DSCREEN_LOG_TAG,
184        mySessionName.c_str(), peerSessionName.c_str(), GetAnonyString(peerDevId).c_str());
185
186    QosTV qos[] = {
187        {.qos = QOS_TYPE_MIN_BW,        .value = 40 * 1024 * 1024},
188        {.qos = QOS_TYPE_MAX_LATENCY,        .value = 8000},
189        {.qos = QOS_TYPE_MIN_LATENCY,        .value = 2000},
190    };
191    std::string localSesionName = mySessionName + "_" + std::to_string(GetCurrentTimeUs());
192    SocketInfo clientInfo = {
193        .name = const_cast<char*>((localSesionName.c_str())),
194        .peerName = const_cast<char*>(peerSessionName.c_str()),
195        .peerNetworkId = const_cast<char*>(peerDevId.c_str()),
196        .pkgName = const_cast<char*>(PKG_NAME.c_str()),
197        .dataType = DATA_TYPE_VIDEO_STREAM,
198    };
199    int32_t socketId = Socket(clientInfo);
200    if (socketId < 0) {
201        DHLOGE("Create OpenSoftbusChannel Socket error");
202        return ERR_DH_SCREEN_ADAPTER_PARA_ERROR;
203    }
204    int32_t ret = Bind(socketId, qos, sizeof(qos) / sizeof(qos[0]), &sessListener_);
205    if (ret != DH_SUCCESS) {
206        DHLOGE("Bind SocketClient error");
207        return ERR_DH_SCREEN_ADAPTER_PARA_ERROR;
208    }
209    {
210        std::lock_guard<std::mutex> lock(idMapMutex_);
211        devId2SessIdMap_.insert(std::make_pair(socketId, mySessionName + "_" + peerDevId));
212    }
213    std::shared_ptr<ISoftbusListener> &listener = GetSoftbusListenerByName(socketId);
214    if (listener == nullptr) {
215        DHLOGE("Get softbus listener failed.");
216        return ERR_DH_SCREEN_TRANS_ERROR;
217    }
218    PeerSocketInfo info;
219    ret = OnSoftbusSessionOpened(socketId, info);
220    if (ret != DH_SUCCESS) {
221        return ret;
222    }
223    DHLOGI("%{public}s: OpenSoftbusSession success sessionId: %{public}" PRId32, DSCREEN_LOG_TAG, socketId);
224    return socketId;
225}
226
227int32_t SoftbusAdapter::CloseSoftbusSession(const int32_t sessionId)
228{
229    DHLOGI("%{public}s: CloseSoftbusSession, sessid:%{public}" PRId32, DSCREEN_LOG_TAG, sessionId);
230    Shutdown(sessionId);
231    {
232        std::lock_guard<std::mutex> lock(idMapMutex_);
233        devId2SessIdMap_.erase(sessionId);
234    }
235    std::lock_guard<std::mutex> lisLock(listenerMtx_);
236    mapSessListeners_.erase(sessionId);
237
238    DHLOGI("%{public}s: CloseSoftbusSession success.", DSCREEN_LOG_TAG);
239    return DH_SUCCESS;
240}
241
242int32_t SoftbusAdapter::SendSoftbusBytes(int32_t sessionId, const void *data, int32_t dataLen) const
243{
244    DHLOGD("%{public}s: SendSoftbusBytes, sessid:%{public}" PRId32, DSCREEN_LOG_TAG, sessionId);
245    int32_t ret = SendBytes(sessionId, data, dataLen);
246    if (ret != DH_SUCCESS) {
247        DHLOGE("%{public}s: SendBytes failed ret:%{public}" PRId32, DSCREEN_LOG_TAG, ret);
248        return ERR_DH_SCREEN_TRANS_ERROR;
249    }
250
251    return DH_SUCCESS;
252}
253
254int32_t SoftbusAdapter::SendSoftbusStream(int32_t sessionId, const StreamData *data, const StreamData *ext,
255    const StreamFrameInfo *param) const
256{
257    DHLOGD("%{public}s: SendSoftbusStream, sessid:%{public}" PRId32, DSCREEN_LOG_TAG, sessionId);
258    int32_t ret = SendStream(sessionId, data, ext, param);
259    if (ret != DH_SUCCESS) {
260        DHLOGE("%{public}s: SendStream failed ret:%{public}" PRId32, DSCREEN_LOG_TAG, ret);
261        return ERR_DH_SCREEN_TRANS_ERROR;
262    }
263
264    return DH_SUCCESS;
265}
266
267std::shared_ptr<ISoftbusListener> &SoftbusAdapter::GetSoftbusListenerByName(int32_t sessionId)
268{
269    DHLOGD("%{public}s: GetSoftbusListenerByName, sessionId:%{public}" PRId32, DSCREEN_LOG_TAG, sessionId);
270    std::string strListenerKey = "";
271    {
272        std::lock_guard<std::mutex> lock(idMapMutex_);
273        for (auto it = devId2SessIdMap_.begin(); it != devId2SessIdMap_.end(); it++) {
274            if (it->first == sessionId) {
275                strListenerKey = it->second;
276                break;
277            }
278        }
279    }
280    std::lock_guard<std::mutex> lisLock(listenerMtx_);
281    if (mapListeners_.find(strListenerKey) == mapListeners_.end()) {
282        DHLOGE("%{public}s: Find listener failed.", DSCREEN_LOG_TAG);
283        return nullListener_;
284    }
285    return mapListeners_[strListenerKey];
286}
287
288std::shared_ptr<ISoftbusListener> &SoftbusAdapter::GetSoftbusListenerById(int32_t sessionId)
289{
290    std::lock_guard<std::mutex> lisLock(listenerMtx_);
291    if (mapSessListeners_.find(sessionId) == mapSessListeners_.end()) {
292        DHLOGE("%{public}s: Find listener failed.", DSCREEN_LOG_TAG);
293        return nullListener_;
294    }
295
296    return mapSessListeners_[sessionId];
297}
298
299int32_t SoftbusAdapter::OnSoftbusSessionOpened(int32_t sessionId, PeerSocketInfo info)
300{
301    DHLOGI("%{public}s: OnSoftbusSessionOpened session:%{public}" PRId32, DSCREEN_LOG_TAG, sessionId);
302    {
303        std::lock_guard<std::mutex> lock(serverIdMapMutex_);
304        for (auto it = serverIdMap_.begin(); it != serverIdMap_.end(); it++) {
305            if (info.networkId == nullptr) {
306                break;
307            }
308            std::string peerDevId(info.networkId);
309            if ((it->second).find(peerDevId) != std::string::npos) {
310                std::lock_guard<std::mutex> sessionLock(idMapMutex_);
311                devId2SessIdMap_.insert(std::make_pair(sessionId, it->second));
312                break;
313            }
314        }
315    }
316
317    std::shared_ptr<ISoftbusListener> &listener = GetSoftbusListenerByName(sessionId);
318    if (listener == nullptr) {
319        DHLOGE("Get softbus listener failed.");
320        return ERR_DH_SCREEN_TRANS_ERROR;
321    }
322    listener->OnSessionOpened(sessionId, info);
323
324    std::lock_guard<std::mutex> lisLock(listenerMtx_);
325    mapSessListeners_.insert(std::make_pair(sessionId, listener));
326
327    return DH_SUCCESS;
328}
329
330void SoftbusAdapter::OnSoftbusSessionClosed(int32_t sessionId, ShutdownReason reason)
331{
332    DHLOGI("%{public}s: OnSessionClosed sessionId:%{public}" PRId32, DSCREEN_LOG_TAG, sessionId);
333    std::shared_ptr<ISoftbusListener> &listener = GetSoftbusListenerById(sessionId);
334    if (listener == nullptr) {
335        DHLOGE("Get softbus listener failed.");
336        return;
337    }
338    listener->OnSessionClosed(sessionId, reason);
339    {
340        std::lock_guard<std::mutex> lock(idMapMutex_);
341        devId2SessIdMap_.erase(sessionId);
342    }
343    std::lock_guard<std::mutex> lisLock(listenerMtx_);
344    mapSessListeners_.erase(sessionId);
345}
346
347void SoftbusAdapter::OnBytesReceived(int32_t sessionId, const void *data, uint32_t dataLen)
348{
349    DHLOGD("%{public}s: OnBytesReceived, sessionId:%{public}" PRId32, DSCREEN_LOG_TAG, sessionId);
350    if (data == nullptr) {
351        DHLOGE("BytesData is null.");
352        return;
353    }
354    if (dataLen == 0 || dataLen > DSCREEN_MAX_RECV_DATA_LEN) {
355        DHLOGE("BytesData length is too large, dataLen:%{public}" PRIu32, dataLen);
356        return;
357    }
358
359    std::shared_ptr<ISoftbusListener> &listener = GetSoftbusListenerByName(sessionId);
360    if (listener == nullptr) {
361        DHLOGE("Get softbus listener failed.");
362        return;
363    }
364    listener->OnBytesReceived(sessionId, data, dataLen);
365}
366
367void SoftbusAdapter::OnStreamReceived(int32_t sessionId, const StreamData *data, const StreamData *ext,
368    const StreamFrameInfo *frameInfo)
369{
370    DHLOGD("%{public}s OnStreamReceived, sessionId:%{public}" PRId32, DSCREEN_LOG_TAG, sessionId);
371    if (data == nullptr) {
372        DHLOGE("StreamData is null.");
373        return;
374    }
375    if (data->bufLen <= 0 || data->bufLen > static_cast<int32_t>(DSCREEN_MAX_RECV_DATA_LEN)) {
376        DHLOGE("StreamData length is too large, dataLen:%{public}" PRId32, data->bufLen);
377        return;
378    }
379
380    std::shared_ptr<ISoftbusListener> &listener = GetSoftbusListenerByName(sessionId);
381    if (listener == nullptr) {
382        DHLOGE("Get softbus listener failed.");
383        return;
384    }
385    listener->OnStreamReceived(sessionId, data, ext, frameInfo);
386}
387
388void SoftbusAdapter::OnMessageReceived(int sessionId, const void *data, unsigned int dataLen) const
389{
390    (void)data;
391    (void)dataLen;
392    DHLOGD("%{public}s OnMessageReceived, sessionId:%{public}" PRId32, DSCREEN_LOG_TAG, sessionId);
393}
394} // namespace DistributedHardware
395} // namespace OHOS