1cc290419Sopenharmony_ci/*
2cc290419Sopenharmony_ci * Copyright (C) 2021 Huawei Device Co., Ltd.
3cc290419Sopenharmony_ci * Licensed under the Apache License, Version 2.0 (the "License");
4cc290419Sopenharmony_ci * you may not use this file except in compliance with the License.
5cc290419Sopenharmony_ci * You may obtain a copy of the License at
6cc290419Sopenharmony_ci *
7cc290419Sopenharmony_ci *     http://www.apache.org/licenses/LICENSE-2.0
8cc290419Sopenharmony_ci *
9cc290419Sopenharmony_ci * Unless required by applicable law or agreed to in writing, software
10cc290419Sopenharmony_ci * distributed under the License is distributed on an "AS IS" BASIS,
11cc290419Sopenharmony_ci * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12cc290419Sopenharmony_ci * See the License for the specific language governing permissions and
13cc290419Sopenharmony_ci * limitations under the License.
14cc290419Sopenharmony_ci */
15cc290419Sopenharmony_ci#include "host_usb.h"
16cc290419Sopenharmony_ci#include <stdlib.h>
17cc290419Sopenharmony_ci#include <thread>
18cc290419Sopenharmony_ci
19cc290419Sopenharmony_ci#include "server.h"
20cc290419Sopenharmony_cinamespace Hdc {
21cc290419Sopenharmony_ciHdcHostUSB::HdcHostUSB(const bool serverOrDaemonIn, void *ptrMainBase, void *ctxUSBin)
22cc290419Sopenharmony_ci    : HdcUSBBase(serverOrDaemonIn, ptrMainBase)
23cc290419Sopenharmony_ci{
24cc290419Sopenharmony_ci    modRunning = false;
25cc290419Sopenharmony_ci    HdcServer *pServer = (HdcServer *)ptrMainBase;
26cc290419Sopenharmony_ci    ctxUSB = (libusb_context *)ctxUSBin;
27cc290419Sopenharmony_ci    uv_timer_init(&pServer->loopMain, &devListWatcher);
28cc290419Sopenharmony_ci}
29cc290419Sopenharmony_ci
30cc290419Sopenharmony_ciHdcHostUSB::~HdcHostUSB()
31cc290419Sopenharmony_ci{
32cc290419Sopenharmony_ci    if (modRunning) {
33cc290419Sopenharmony_ci        Stop();
34cc290419Sopenharmony_ci    }
35cc290419Sopenharmony_ci    WRITE_LOG(LOG_DEBUG, "~HdcHostUSB");
36cc290419Sopenharmony_ci}
37cc290419Sopenharmony_ci
38cc290419Sopenharmony_civoid HdcHostUSB::Stop()
39cc290419Sopenharmony_ci{
40cc290419Sopenharmony_ci    if (!ctxUSB) {
41cc290419Sopenharmony_ci        return;
42cc290419Sopenharmony_ci    }
43cc290419Sopenharmony_ci    Base::TryCloseHandle((uv_handle_t *)&devListWatcher);
44cc290419Sopenharmony_ci    modRunning = false;
45cc290419Sopenharmony_ci}
46cc290419Sopenharmony_ci
47cc290419Sopenharmony_ciint HdcHostUSB::Initial()
48cc290419Sopenharmony_ci{
49cc290419Sopenharmony_ci    if (!ctxUSB) {
50cc290419Sopenharmony_ci        WRITE_LOG(LOG_FATAL, "USB mod ctxUSB is nullptr, recompile please");
51cc290419Sopenharmony_ci        return -1;
52cc290419Sopenharmony_ci    }
53cc290419Sopenharmony_ci    WRITE_LOG(LOG_DEBUG, "HdcHostUSB init");
54cc290419Sopenharmony_ci    modRunning = true;
55cc290419Sopenharmony_ci    StartupUSBWork();  // Main thread registration, IO in sub-thread
56cc290419Sopenharmony_ci    return 0;
57cc290419Sopenharmony_ci}
58cc290419Sopenharmony_ci
59cc290419Sopenharmony_cistatic void UsbLogHandler(libusb_context* ctx, enum libusb_log_level level, const char* str)
60cc290419Sopenharmony_ci{
61cc290419Sopenharmony_ci    int l = -1;
62cc290419Sopenharmony_ci    switch (level) {
63cc290419Sopenharmony_ci        case LIBUSB_LOG_LEVEL_ERROR:
64cc290419Sopenharmony_ci            l = LOG_FATAL;
65cc290419Sopenharmony_ci            break;
66cc290419Sopenharmony_ci        case LIBUSB_LOG_LEVEL_WARNING:
67cc290419Sopenharmony_ci            l = LOG_WARN;
68cc290419Sopenharmony_ci            break;
69cc290419Sopenharmony_ci        case LIBUSB_LOG_LEVEL_INFO:
70cc290419Sopenharmony_ci            l = LOG_INFO;
71cc290419Sopenharmony_ci            break;
72cc290419Sopenharmony_ci        case LIBUSB_LOG_LEVEL_DEBUG:
73cc290419Sopenharmony_ci            l = LOG_DEBUG;
74cc290419Sopenharmony_ci            break;
75cc290419Sopenharmony_ci        default:
76cc290419Sopenharmony_ci            break;
77cc290419Sopenharmony_ci    }
78cc290419Sopenharmony_ci    if (l >= 0) {
79cc290419Sopenharmony_ci        char *newStr = strdup(str);
80cc290419Sopenharmony_ci        if (!newStr) {
81cc290419Sopenharmony_ci            return;
82cc290419Sopenharmony_ci        }
83cc290419Sopenharmony_ci        char *p = strstr(newStr, "libusb:");
84cc290419Sopenharmony_ci        if (!p) {
85cc290419Sopenharmony_ci            p = newStr;
86cc290419Sopenharmony_ci        }
87cc290419Sopenharmony_ci        char *q = strrchr(newStr, '\n');
88cc290419Sopenharmony_ci        if (q) {
89cc290419Sopenharmony_ci            *q = '\0';
90cc290419Sopenharmony_ci        }
91cc290419Sopenharmony_ci        WRITE_LOG(l, "%s", p);
92cc290419Sopenharmony_ci        free(newStr);
93cc290419Sopenharmony_ci    }
94cc290419Sopenharmony_ci}
95cc290419Sopenharmony_civoid HdcHostUSB::InitLogging(void *ctxUSB)
96cc290419Sopenharmony_ci{
97cc290419Sopenharmony_ci    if (ctxUSB == nullptr) {
98cc290419Sopenharmony_ci        WRITE_LOG(LOG_FATAL, "InitLogging failed ctxUSB is nullptr");
99cc290419Sopenharmony_ci        return;
100cc290419Sopenharmony_ci    }
101cc290419Sopenharmony_ci    std::string debugEnv = "LIBUSB_DEBUG";
102cc290419Sopenharmony_ci    libusb_log_level debugLevel;
103cc290419Sopenharmony_ci
104cc290419Sopenharmony_ci    switch (static_cast<Hdc::HdcLogLevel>(Base::GetLogLevel())) {
105cc290419Sopenharmony_ci        case LOG_WARN:
106cc290419Sopenharmony_ci            debugLevel = LIBUSB_LOG_LEVEL_ERROR;
107cc290419Sopenharmony_ci            break;
108cc290419Sopenharmony_ci        case LOG_INFO:
109cc290419Sopenharmony_ci            debugLevel = LIBUSB_LOG_LEVEL_WARNING;
110cc290419Sopenharmony_ci            break;
111cc290419Sopenharmony_ci        case LOG_DEBUG:
112cc290419Sopenharmony_ci            debugLevel = LIBUSB_LOG_LEVEL_INFO;
113cc290419Sopenharmony_ci            break;
114cc290419Sopenharmony_ci        case LOG_VERBOSE:
115cc290419Sopenharmony_ci            debugLevel = LIBUSB_LOG_LEVEL_DEBUG;
116cc290419Sopenharmony_ci            break;
117cc290419Sopenharmony_ci        case LOG_FATAL:
118cc290419Sopenharmony_ci            // pass through to no libusb logging
119cc290419Sopenharmony_ci        default:
120cc290419Sopenharmony_ci            debugLevel = LIBUSB_LOG_LEVEL_NONE;
121cc290419Sopenharmony_ci            break;
122cc290419Sopenharmony_ci    }
123cc290419Sopenharmony_ci
124cc290419Sopenharmony_ci    libusb_set_option((libusb_context *)ctxUSB, LIBUSB_OPTION_LOG_LEVEL, debugLevel);
125cc290419Sopenharmony_ci    libusb_set_log_cb((libusb_context *)ctxUSB, UsbLogHandler,
126cc290419Sopenharmony_ci                      LIBUSB_LOG_CB_CONTEXT | LIBUSB_LOG_CB_GLOBAL);
127cc290419Sopenharmony_ci
128cc290419Sopenharmony_ci#ifdef _WIN32
129cc290419Sopenharmony_ci    debugEnv += "=";
130cc290419Sopenharmony_ci    debugEnv += std::to_string(debugLevel);
131cc290419Sopenharmony_ci    _putenv(debugEnv.c_str());
132cc290419Sopenharmony_ci#else
133cc290419Sopenharmony_ci    setenv(debugEnv.c_str(), std::to_string(debugLevel).c_str(), 1);
134cc290419Sopenharmony_ci#endif
135cc290419Sopenharmony_ci}
136cc290419Sopenharmony_ci
137cc290419Sopenharmony_cibool HdcHostUSB::DetectMyNeed(libusb_device *device, string &sn)
138cc290419Sopenharmony_ci{
139cc290419Sopenharmony_ci    HUSB hUSB = new(std::nothrow) HdcUSB();
140cc290419Sopenharmony_ci    if (hUSB == nullptr) {
141cc290419Sopenharmony_ci        WRITE_LOG(LOG_FATAL, "DetectMyNeed new hUSB failed");
142cc290419Sopenharmony_ci        return false;
143cc290419Sopenharmony_ci    }
144cc290419Sopenharmony_ci    hUSB->device = device;
145cc290419Sopenharmony_ci    // just get usb SN, close handle immediately
146cc290419Sopenharmony_ci    int childRet = OpenDeviceMyNeed(hUSB);
147cc290419Sopenharmony_ci    if (childRet < 0) {
148cc290419Sopenharmony_ci        WRITE_LOG(LOG_FATAL, "DetectMyNeed OpenDeviceMyNeed childRet:%d", childRet);
149cc290419Sopenharmony_ci        delete hUSB;
150cc290419Sopenharmony_ci        return false;
151cc290419Sopenharmony_ci    }
152cc290419Sopenharmony_ci    libusb_release_interface(hUSB->devHandle, hUSB->interfaceNumber);
153cc290419Sopenharmony_ci    libusb_close(hUSB->devHandle);
154cc290419Sopenharmony_ci    hUSB->devHandle = nullptr;
155cc290419Sopenharmony_ci
156cc290419Sopenharmony_ci    WRITE_LOG(LOG_INFO, "Needed device found, busid:%d devid:%d connectkey:%s", hUSB->busId, hUSB->devId,
157cc290419Sopenharmony_ci              Hdc::MaskString(hUSB->serialNumber).c_str());
158cc290419Sopenharmony_ci    // USB device is automatically connected after recognition, auto connect USB
159cc290419Sopenharmony_ci    UpdateUSBDaemonInfo(hUSB, nullptr, STATUS_READY);
160cc290419Sopenharmony_ci    HdcServer *hdcServer = (HdcServer *)clsMainBase;
161cc290419Sopenharmony_ci    HSession hSession = hdcServer->MallocSession(true, CONN_USB, this);
162cc290419Sopenharmony_ci    if (!hSession) {
163cc290419Sopenharmony_ci        WRITE_LOG(LOG_FATAL, "malloc usb session failed sn:%s", Hdc::MaskString(sn).c_str());
164cc290419Sopenharmony_ci        return false;
165cc290419Sopenharmony_ci    }
166cc290419Sopenharmony_ci    hSession->connectKey = hUSB->serialNumber;
167cc290419Sopenharmony_ci    uv_timer_t *waitTimeDoCmd = new(std::nothrow) uv_timer_t;
168cc290419Sopenharmony_ci    if (waitTimeDoCmd == nullptr) {
169cc290419Sopenharmony_ci        WRITE_LOG(LOG_FATAL, "DetectMyNeed new waitTimeDoCmd failed");
170cc290419Sopenharmony_ci        delete hUSB;
171cc290419Sopenharmony_ci        hdcServer->FreeSession(hSession->sessionId);
172cc290419Sopenharmony_ci        return false;
173cc290419Sopenharmony_ci    }
174cc290419Sopenharmony_ci    uv_timer_init(&hdcServer->loopMain, waitTimeDoCmd);
175cc290419Sopenharmony_ci    waitTimeDoCmd->data = hSession;
176cc290419Sopenharmony_ci    uv_timer_start(waitTimeDoCmd, hdcServer->UsbPreConnect, 0, DEVICE_CHECK_INTERVAL);
177cc290419Sopenharmony_ci    mapIgnoreDevice[sn] = HOST_USB_REGISTER;
178cc290419Sopenharmony_ci    delete hUSB;
179cc290419Sopenharmony_ci    return true;
180cc290419Sopenharmony_ci}
181cc290419Sopenharmony_ci
182cc290419Sopenharmony_civoid HdcHostUSB::KickoutZombie(HSession hSession)
183cc290419Sopenharmony_ci{
184cc290419Sopenharmony_ci    HdcServer *ptrConnect = (HdcServer *)hSession->classInstance;
185cc290419Sopenharmony_ci    HUSB hUSB = hSession->hUSB;
186cc290419Sopenharmony_ci    if (!hUSB->devHandle) {
187cc290419Sopenharmony_ci        WRITE_LOG(LOG_WARN, "KickoutZombie devHandle:%p isDead:%d", hUSB->devHandle, hSession->isDead);
188cc290419Sopenharmony_ci        return;
189cc290419Sopenharmony_ci    }
190cc290419Sopenharmony_ci    if (LIBUSB_ERROR_NO_DEVICE != libusb_kernel_driver_active(hUSB->devHandle, hUSB->interfaceNumber)) {
191cc290419Sopenharmony_ci        return;
192cc290419Sopenharmony_ci    }
193cc290419Sopenharmony_ci    WRITE_LOG(LOG_WARN, "KickoutZombie LIBUSB_ERROR_NO_DEVICE serialNumber:%s",
194cc290419Sopenharmony_ci              Hdc::MaskString(hUSB->serialNumber).c_str());
195cc290419Sopenharmony_ci    ptrConnect->FreeSession(hSession->sessionId);
196cc290419Sopenharmony_ci}
197cc290419Sopenharmony_ci
198cc290419Sopenharmony_civoid HdcHostUSB::RemoveIgnoreDevice(string &mountInfo)
199cc290419Sopenharmony_ci{
200cc290419Sopenharmony_ci    if (mapIgnoreDevice.count(mountInfo)) {
201cc290419Sopenharmony_ci        mapIgnoreDevice.erase(mountInfo);
202cc290419Sopenharmony_ci    }
203cc290419Sopenharmony_ci}
204cc290419Sopenharmony_ci
205cc290419Sopenharmony_civoid HdcHostUSB::ReviewUsbNodeLater(string &nodeKey)
206cc290419Sopenharmony_ci{
207cc290419Sopenharmony_ci    HdcServer *hdcServer = (HdcServer *)clsMainBase;
208cc290419Sopenharmony_ci    // add to ignore list
209cc290419Sopenharmony_ci    mapIgnoreDevice[nodeKey] = HOST_USB_IGNORE;
210cc290419Sopenharmony_ci    int delayRemoveFromList = DEVICE_CHECK_INTERVAL * MINOR_TIMEOUT;  // wait little time for daemon reinit
211cc290419Sopenharmony_ci    Base::DelayDo(&hdcServer->loopMain, delayRemoveFromList, 0, nodeKey, nullptr,
212cc290419Sopenharmony_ci                  [this](const uint8_t flag, string &msg, const void *) -> void { RemoveIgnoreDevice(msg); });
213cc290419Sopenharmony_ci}
214cc290419Sopenharmony_ci
215cc290419Sopenharmony_civoid HdcHostUSB::WatchUsbNodeChange(uv_timer_t *handle)
216cc290419Sopenharmony_ci{
217cc290419Sopenharmony_ci    HdcHostUSB *thisClass = static_cast<HdcHostUSB *>(handle->data);
218cc290419Sopenharmony_ci    HdcServer *ptrConnect = static_cast<HdcServer *>(thisClass->clsMainBase);
219cc290419Sopenharmony_ci    libusb_device **devs = nullptr;
220cc290419Sopenharmony_ci    libusb_device *dev = nullptr;
221cc290419Sopenharmony_ci    // kick zombie
222cc290419Sopenharmony_ci    ptrConnect->EnumUSBDeviceRegister(KickoutZombie);
223cc290419Sopenharmony_ci    // find new
224cc290419Sopenharmony_ci    ssize_t cnt = libusb_get_device_list(thisClass->ctxUSB, &devs);
225cc290419Sopenharmony_ci    if (cnt < 0) {
226cc290419Sopenharmony_ci        WRITE_LOG(LOG_FATAL, "Failed to get device list");
227cc290419Sopenharmony_ci        return;
228cc290419Sopenharmony_ci    }
229cc290419Sopenharmony_ci    int i = 0;
230cc290419Sopenharmony_ci    // linux replug devid increment,windows will be not
231cc290419Sopenharmony_ci    while ((dev = devs[i++]) != nullptr) {  // must postfix++
232cc290419Sopenharmony_ci        string szTmpKey = Base::StringFormat("%d-%d", libusb_get_bus_number(dev), libusb_get_device_address(dev));
233cc290419Sopenharmony_ci        // check is in ignore list
234cc290419Sopenharmony_ci        UsbCheckStatus statusCheck = thisClass->mapIgnoreDevice[szTmpKey];
235cc290419Sopenharmony_ci        if (statusCheck == HOST_USB_IGNORE || statusCheck == HOST_USB_REGISTER) {
236cc290419Sopenharmony_ci            continue;
237cc290419Sopenharmony_ci        }
238cc290419Sopenharmony_ci        string sn = szTmpKey;
239cc290419Sopenharmony_ci        if (thisClass->HasValidDevice(dev) && !thisClass->DetectMyNeed(dev, sn)) {
240cc290419Sopenharmony_ci            thisClass->ReviewUsbNodeLater(szTmpKey);
241cc290419Sopenharmony_ci        }
242cc290419Sopenharmony_ci    }
243cc290419Sopenharmony_ci    libusb_free_device_list(devs, 1);
244cc290419Sopenharmony_ci}
245cc290419Sopenharmony_ci
246cc290419Sopenharmony_cibool HdcHostUSB::HasValidDevice(libusb_device *device)
247cc290419Sopenharmony_ci{
248cc290419Sopenharmony_ci    struct libusb_config_descriptor *descConfig = nullptr;
249cc290419Sopenharmony_ci    int ret = libusb_get_active_config_descriptor(device, &descConfig);
250cc290419Sopenharmony_ci    if (ret != 0) {
251cc290419Sopenharmony_ci        WRITE_LOG(LOG_WARN, "get active config des fail, errno is %d.", errno);
252cc290419Sopenharmony_ci        return false;
253cc290419Sopenharmony_ci    }
254cc290419Sopenharmony_ci    bool hasValid = false;
255cc290419Sopenharmony_ci    for (unsigned int j = 0; j < descConfig->bNumInterfaces; ++j) {
256cc290419Sopenharmony_ci        const struct libusb_interface *interface = &descConfig->interface[j];
257cc290419Sopenharmony_ci        if (interface->num_altsetting < 1) {
258cc290419Sopenharmony_ci            continue;
259cc290419Sopenharmony_ci        }
260cc290419Sopenharmony_ci        const struct libusb_interface_descriptor *ifDescriptor = &interface->altsetting[0];
261cc290419Sopenharmony_ci        if (!IsDebuggableDev(ifDescriptor)) {
262cc290419Sopenharmony_ci            continue;
263cc290419Sopenharmony_ci        }
264cc290419Sopenharmony_ci        hasValid = true;
265cc290419Sopenharmony_ci        break;
266cc290419Sopenharmony_ci    }
267cc290419Sopenharmony_ci    return hasValid;
268cc290419Sopenharmony_ci}
269cc290419Sopenharmony_ci
270cc290419Sopenharmony_ci// Main thread USB operates in this thread
271cc290419Sopenharmony_civoid HdcHostUSB::UsbWorkThread(void *arg)
272cc290419Sopenharmony_ci{
273cc290419Sopenharmony_ci    HdcHostUSB *thisClass = (HdcHostUSB *)arg;
274cc290419Sopenharmony_ci    constexpr uint8_t usbHandleTimeout = 30;  // second
275cc290419Sopenharmony_ci    while (thisClass->modRunning) {
276cc290419Sopenharmony_ci        struct timeval zerotime;
277cc290419Sopenharmony_ci        zerotime.tv_sec = usbHandleTimeout;
278cc290419Sopenharmony_ci        zerotime.tv_usec = 0;  // if == 0,windows will be high CPU load
279cc290419Sopenharmony_ci        libusb_handle_events_timeout(thisClass->ctxUSB, &zerotime);
280cc290419Sopenharmony_ci    }
281cc290419Sopenharmony_ci    WRITE_LOG(LOG_DEBUG, "Host Sessionbase usb workthread finish");
282cc290419Sopenharmony_ci}
283cc290419Sopenharmony_ci
284cc290419Sopenharmony_ciint HdcHostUSB::StartupUSBWork()
285cc290419Sopenharmony_ci{
286cc290419Sopenharmony_ci    // Because libusb(winusb backend) does not support hotplug under win32, we use list mode for all platforms
287cc290419Sopenharmony_ci    WRITE_LOG(LOG_DEBUG, "USBHost loopfind mode");
288cc290419Sopenharmony_ci    devListWatcher.data = this;
289cc290419Sopenharmony_ci    uv_timer_start(&devListWatcher, WatchUsbNodeChange, 0, DEVICE_CHECK_INTERVAL);
290cc290419Sopenharmony_ci    // Running pendding in independent threads does not significantly improve the efficiency
291cc290419Sopenharmony_ci    uv_thread_create(&threadUsbWork, UsbWorkThread, this);
292cc290419Sopenharmony_ci    return 0;
293cc290419Sopenharmony_ci}
294cc290419Sopenharmony_ci
295cc290419Sopenharmony_ciint HdcHostUSB::CheckDescriptor(HUSB hUSB, libusb_device_descriptor& desc)
296cc290419Sopenharmony_ci{
297cc290419Sopenharmony_ci    char serialNum[BUF_SIZE_MEDIUM] = "";
298cc290419Sopenharmony_ci    int childRet = 0;
299cc290419Sopenharmony_ci    uint8_t curBus = libusb_get_bus_number(hUSB->device);
300cc290419Sopenharmony_ci    uint8_t curDev = libusb_get_device_address(hUSB->device);
301cc290419Sopenharmony_ci    hUSB->busId = curBus;
302cc290419Sopenharmony_ci    hUSB->devId = curDev;
303cc290419Sopenharmony_ci    if (libusb_get_device_descriptor(hUSB->device, &desc)) {
304cc290419Sopenharmony_ci        WRITE_LOG(LOG_WARN, "CheckDescriptor libusb_get_device_descriptor failed %d-%d", curBus, curDev);
305cc290419Sopenharmony_ci        return -1;
306cc290419Sopenharmony_ci    }
307cc290419Sopenharmony_ci    // Get the serial number of the device, if there is no serial number, use the ID number to replace
308cc290419Sopenharmony_ci    // If the device is not in time, occasionally can't get it, this is determined by the external factor, cannot be
309cc290419Sopenharmony_ci    // changed. LIBUSB_SUCCESS
310cc290419Sopenharmony_ci    childRet = libusb_get_string_descriptor_ascii(hUSB->devHandle, desc.iSerialNumber, (uint8_t *)serialNum,
311cc290419Sopenharmony_ci                                                  sizeof(serialNum));
312cc290419Sopenharmony_ci    if (childRet < 0) {
313cc290419Sopenharmony_ci        WRITE_LOG(LOG_WARN, "CheckDescriptor libusb_get_string_descriptor_ascii failed %d-%d", curBus, curDev);
314cc290419Sopenharmony_ci        return -1;
315cc290419Sopenharmony_ci    } else {
316cc290419Sopenharmony_ci        hUSB->serialNumber = serialNum;
317cc290419Sopenharmony_ci    }
318cc290419Sopenharmony_ci    WRITE_LOG(LOG_DEBUG, "CheckDescriptor busId-devId:%d-%d serialNum:%s", curBus, curDev,
319cc290419Sopenharmony_ci              Hdc::MaskString(serialNum).c_str());
320cc290419Sopenharmony_ci    return 0;
321cc290419Sopenharmony_ci}
322cc290419Sopenharmony_ci
323cc290419Sopenharmony_ci// hSession can be null
324cc290419Sopenharmony_civoid HdcHostUSB::UpdateUSBDaemonInfo(HUSB hUSB, HSession hSession, uint8_t connStatus)
325cc290419Sopenharmony_ci{
326cc290419Sopenharmony_ci    // add to list
327cc290419Sopenharmony_ci    HdcServer *pServer = (HdcServer *)clsMainBase;
328cc290419Sopenharmony_ci    HdcDaemonInformation di;
329cc290419Sopenharmony_ci    di.connectKey = hUSB->serialNumber;
330cc290419Sopenharmony_ci    di.connType = CONN_USB;
331cc290419Sopenharmony_ci    di.connStatus = connStatus;
332cc290419Sopenharmony_ci    di.hSession = hSession;
333cc290419Sopenharmony_ci    di.usbMountPoint = "";
334cc290419Sopenharmony_ci    di.usbMountPoint = Base::StringFormat("%d-%d", hUSB->busId, hUSB->devId);
335cc290419Sopenharmony_ci
336cc290419Sopenharmony_ci    HDaemonInfo pDi = nullptr;
337cc290419Sopenharmony_ci    HDaemonInfo hdiNew = &di;
338cc290419Sopenharmony_ci    pServer->AdminDaemonMap(OP_QUERY, hUSB->serialNumber, pDi);
339cc290419Sopenharmony_ci    if (!pDi) {
340cc290419Sopenharmony_ci        pServer->AdminDaemonMap(OP_ADD, hUSB->serialNumber, hdiNew);
341cc290419Sopenharmony_ci    } else {
342cc290419Sopenharmony_ci        pServer->AdminDaemonMap(OP_UPDATE, hUSB->serialNumber, hdiNew);
343cc290419Sopenharmony_ci    }
344cc290419Sopenharmony_ci}
345cc290419Sopenharmony_ci
346cc290419Sopenharmony_cibool HdcHostUSB::IsDebuggableDev(const struct libusb_interface_descriptor *ifDescriptor)
347cc290419Sopenharmony_ci{
348cc290419Sopenharmony_ci    constexpr uint8_t harmonyEpNum = 2;
349cc290419Sopenharmony_ci    constexpr uint8_t harmonyClass = 0xff;
350cc290419Sopenharmony_ci    constexpr uint8_t harmonySubClass = 0x50;
351cc290419Sopenharmony_ci    constexpr uint8_t harmonyProtocol = 0x01;
352cc290419Sopenharmony_ci
353cc290419Sopenharmony_ci    if (ifDescriptor->bInterfaceClass != harmonyClass || ifDescriptor->bInterfaceSubClass != harmonySubClass ||
354cc290419Sopenharmony_ci        ifDescriptor->bInterfaceProtocol != harmonyProtocol) {
355cc290419Sopenharmony_ci        return false;
356cc290419Sopenharmony_ci    }
357cc290419Sopenharmony_ci    if (ifDescriptor->bNumEndpoints != harmonyEpNum) {
358cc290419Sopenharmony_ci        return false;
359cc290419Sopenharmony_ci    }
360cc290419Sopenharmony_ci    return true;
361cc290419Sopenharmony_ci}
362cc290419Sopenharmony_ci
363cc290419Sopenharmony_ciint HdcHostUSB::CheckActiveConfig(libusb_device *device, HUSB hUSB, libusb_device_descriptor& desc)
364cc290419Sopenharmony_ci{
365cc290419Sopenharmony_ci    struct libusb_config_descriptor *descConfig = nullptr;
366cc290419Sopenharmony_ci    int ret = libusb_get_active_config_descriptor(device, &descConfig);
367cc290419Sopenharmony_ci    if (ret != 0) {
368cc290419Sopenharmony_ci#ifdef HOST_MAC
369cc290419Sopenharmony_ci        if ((desc.bDeviceClass == 0xFF)
370cc290419Sopenharmony_ci            && (desc.bDeviceSubClass == 0xFF)
371cc290419Sopenharmony_ci            && (desc.bDeviceProtocol == 0xFF)) {
372cc290419Sopenharmony_ci            ret = libusb_set_configuration(hUSB->devHandle, 1);
373cc290419Sopenharmony_ci            if (ret != 0) {
374cc290419Sopenharmony_ci                WRITE_LOG(LOG_WARN, "set config failed ret:%d", ret);
375cc290419Sopenharmony_ci                return -1;
376cc290419Sopenharmony_ci            }
377cc290419Sopenharmony_ci        }
378cc290419Sopenharmony_ci
379cc290419Sopenharmony_ci        ret = libusb_get_active_config_descriptor(device, &descConfig);
380cc290419Sopenharmony_ci        if (ret != 0) {
381cc290419Sopenharmony_ci#endif
382cc290419Sopenharmony_ci            WRITE_LOG(LOG_WARN, "get active config descriptor failed ret:%d", ret);
383cc290419Sopenharmony_ci            return -1;
384cc290419Sopenharmony_ci        }
385cc290419Sopenharmony_ci#ifdef HOST_MAC
386cc290419Sopenharmony_ci    }
387cc290419Sopenharmony_ci#endif
388cc290419Sopenharmony_ci
389cc290419Sopenharmony_ci    ret = -1;
390cc290419Sopenharmony_ci    CheckUsbEndpoint(ret, hUSB, descConfig);
391cc290419Sopenharmony_ci    libusb_free_config_descriptor(descConfig);
392cc290419Sopenharmony_ci    return ret;
393cc290419Sopenharmony_ci}
394cc290419Sopenharmony_ci
395cc290419Sopenharmony_civoid HdcHostUSB::CheckUsbEndpoint(int& ret, HUSB hUSB, libusb_config_descriptor *descConfig)
396cc290419Sopenharmony_ci{
397cc290419Sopenharmony_ci    unsigned int j = 0;
398cc290419Sopenharmony_ci    for (j = 0; j < descConfig->bNumInterfaces; ++j) {
399cc290419Sopenharmony_ci        const struct libusb_interface *interface = &descConfig->interface[j];
400cc290419Sopenharmony_ci        if (interface->num_altsetting < 1) {
401cc290419Sopenharmony_ci            WRITE_LOG(LOG_DEBUG, "interface->num_altsetting = 0, j = %d", j);
402cc290419Sopenharmony_ci            continue;
403cc290419Sopenharmony_ci        }
404cc290419Sopenharmony_ci        const struct libusb_interface_descriptor *ifDescriptor = &interface->altsetting[0];
405cc290419Sopenharmony_ci        if (!IsDebuggableDev(ifDescriptor)) {
406cc290419Sopenharmony_ci            WRITE_LOG(LOG_DEBUG, "IsDebuggableDev fail, j = %d", j);
407cc290419Sopenharmony_ci            continue;
408cc290419Sopenharmony_ci        }
409cc290419Sopenharmony_ci        WRITE_LOG(LOG_DEBUG, "CheckActiveConfig IsDebuggableDev passed and then check endpoint attr");
410cc290419Sopenharmony_ci        hUSB->interfaceNumber = ifDescriptor->bInterfaceNumber;
411cc290419Sopenharmony_ci        unsigned int k = 0;
412cc290419Sopenharmony_ci        for (k = 0; k < ifDescriptor->bNumEndpoints; ++k) {
413cc290419Sopenharmony_ci            const struct libusb_endpoint_descriptor *ep_desc = &ifDescriptor->endpoint[k];
414cc290419Sopenharmony_ci            if ((ep_desc->bmAttributes & 0x03) != LIBUSB_TRANSFER_TYPE_BULK) {
415cc290419Sopenharmony_ci                WRITE_LOG(LOG_DEBUG, "check ep_desc->bmAttributes fail, all %d k = %d, bmAttributes %d",
416cc290419Sopenharmony_ci                    ifDescriptor->bNumEndpoints, k, ep_desc->bmAttributes);
417cc290419Sopenharmony_ci                continue;
418cc290419Sopenharmony_ci            }
419cc290419Sopenharmony_ci            if (ep_desc->bEndpointAddress & LIBUSB_ENDPOINT_IN) {
420cc290419Sopenharmony_ci                hUSB->hostBulkIn.endpoint = ep_desc->bEndpointAddress;
421cc290419Sopenharmony_ci                hUSB->hostBulkIn.bulkInOut = true;
422cc290419Sopenharmony_ci            } else {
423cc290419Sopenharmony_ci                hUSB->hostBulkOut.endpoint = ep_desc->bEndpointAddress;
424cc290419Sopenharmony_ci                hUSB->wMaxPacketSizeSend = ep_desc->wMaxPacketSize;
425cc290419Sopenharmony_ci                hUSB->hostBulkOut.bulkInOut = false;
426cc290419Sopenharmony_ci            }
427cc290419Sopenharmony_ci        }
428cc290419Sopenharmony_ci        if (hUSB->hostBulkIn.endpoint == 0 || hUSB->hostBulkOut.endpoint == 0) {
429cc290419Sopenharmony_ci            WRITE_LOG(LOG_DEBUG, "hostBulkIn.endpoint %d hUSB->hostBulkOut.endpoint %d",
430cc290419Sopenharmony_ci                    hUSB->hostBulkIn.endpoint, hUSB->hostBulkOut.endpoint);
431cc290419Sopenharmony_ci            break;
432cc290419Sopenharmony_ci        }
433cc290419Sopenharmony_ci        ret = 0;
434cc290419Sopenharmony_ci    }
435cc290419Sopenharmony_ci}
436cc290419Sopenharmony_ci
437cc290419Sopenharmony_ci// multi-thread calll
438cc290419Sopenharmony_civoid HdcHostUSB::CancelUsbIo(HSession hSession)
439cc290419Sopenharmony_ci{
440cc290419Sopenharmony_ci    WRITE_LOG(LOG_INFO, "HostUSB CancelUsbIo, sid:%u ref:%u", hSession->sessionId, uint32_t(hSession->ref));
441cc290419Sopenharmony_ci    HUSB hUSB = hSession->hUSB;
442cc290419Sopenharmony_ci    std::unique_lock<std::mutex> lock(hUSB->lockDeviceHandle);
443cc290419Sopenharmony_ci    if (!hUSB->hostBulkIn.isShutdown) {
444cc290419Sopenharmony_ci        if (!hUSB->hostBulkIn.isComplete) {
445cc290419Sopenharmony_ci            libusb_cancel_transfer(hUSB->hostBulkIn.transfer);
446cc290419Sopenharmony_ci            hUSB->hostBulkIn.cv.notify_one();
447cc290419Sopenharmony_ci        } else {
448cc290419Sopenharmony_ci            hUSB->hostBulkIn.isShutdown = true;
449cc290419Sopenharmony_ci        }
450cc290419Sopenharmony_ci    }
451cc290419Sopenharmony_ci    if (!hUSB->hostBulkOut.isShutdown) {
452cc290419Sopenharmony_ci        if (!hUSB->hostBulkOut.isComplete) {
453cc290419Sopenharmony_ci            libusb_cancel_transfer(hUSB->hostBulkOut.transfer);
454cc290419Sopenharmony_ci            hUSB->hostBulkOut.cv.notify_one();
455cc290419Sopenharmony_ci        } else {
456cc290419Sopenharmony_ci            hUSB->hostBulkOut.isShutdown = true;
457cc290419Sopenharmony_ci        }
458cc290419Sopenharmony_ci    }
459cc290419Sopenharmony_ci}
460cc290419Sopenharmony_ci
461cc290419Sopenharmony_ci// 3rd write child-hdc-workthread
462cc290419Sopenharmony_ci// no use uvwrite, raw write to socketpair's fd
463cc290419Sopenharmony_ciint HdcHostUSB::UsbToHdcProtocol(uv_stream_t *stream, uint8_t *appendData, int dataSize)
464cc290419Sopenharmony_ci{
465cc290419Sopenharmony_ci    HSession hSession = (HSession)stream->data;
466cc290419Sopenharmony_ci    unsigned int fd = hSession->dataFd[STREAM_MAIN];
467cc290419Sopenharmony_ci    int index = 0;
468cc290419Sopenharmony_ci    int childRet = 0;
469cc290419Sopenharmony_ci    int retryTimes = 0;
470cc290419Sopenharmony_ci    const int maxRetryTimes = 3;
471cc290419Sopenharmony_ci    const int oneSecond = 1;
472cc290419Sopenharmony_ci
473cc290419Sopenharmony_ci    while (index < dataSize) {
474cc290419Sopenharmony_ci        fd_set fdSet;
475cc290419Sopenharmony_ci        FD_ZERO(&fdSet);
476cc290419Sopenharmony_ci        FD_SET(fd, &fdSet);
477cc290419Sopenharmony_ci        struct timeval timeout = { 3, 0 };
478cc290419Sopenharmony_ci        childRet = select(fd + 1, nullptr, &fdSet, nullptr, &timeout);
479cc290419Sopenharmony_ci        if (childRet <= 0) {
480cc290419Sopenharmony_ci            hdc_strerrno(buf);
481cc290419Sopenharmony_ci            WRITE_LOG(LOG_FATAL, "select error:%d [%s][%d] retry times %d alread send %d bytes, total %d bytes",
482cc290419Sopenharmony_ci                    errno, buf, childRet, retryTimes, index, dataSize);
483cc290419Sopenharmony_ci            Base::DispUvStreamInfo(stream, "hostusb select failed");
484cc290419Sopenharmony_ci            if (retryTimes >= maxRetryTimes) {
485cc290419Sopenharmony_ci                break;
486cc290419Sopenharmony_ci            }
487cc290419Sopenharmony_ci            retryTimes++;
488cc290419Sopenharmony_ci            sleep(oneSecond);
489cc290419Sopenharmony_ci            continue;
490cc290419Sopenharmony_ci        }
491cc290419Sopenharmony_ci        childRet = send(fd, reinterpret_cast<const char *>(appendData) + index, dataSize - index, 0);
492cc290419Sopenharmony_ci        if (childRet < 0) {
493cc290419Sopenharmony_ci            hdc_strerrno(buf);
494cc290419Sopenharmony_ci            WRITE_LOG(LOG_FATAL, "UsbToHdcProtocol senddata err:%d [%s]", errno, buf);
495cc290419Sopenharmony_ci            Base::DispUvStreamInfo(stream, "hostusb send failed");
496cc290419Sopenharmony_ci            break;
497cc290419Sopenharmony_ci        }
498cc290419Sopenharmony_ci        index += childRet;
499cc290419Sopenharmony_ci    }
500cc290419Sopenharmony_ci    hSession->stat.dataSendBytes += index;
501cc290419Sopenharmony_ci    if (index != dataSize) {
502cc290419Sopenharmony_ci        WRITE_LOG(LOG_FATAL, "UsbToHdcProtocol partialsenddata err:%d [%d]", index, dataSize);
503cc290419Sopenharmony_ci        return ERR_IO_FAIL;
504cc290419Sopenharmony_ci    }
505cc290419Sopenharmony_ci    return index;
506cc290419Sopenharmony_ci}
507cc290419Sopenharmony_ci
508cc290419Sopenharmony_civoid LIBUSB_CALL HdcHostUSB::USBBulkCallback(struct libusb_transfer *transfer)
509cc290419Sopenharmony_ci{
510cc290419Sopenharmony_ci    auto *ep = reinterpret_cast<HostUSBEndpoint *>(transfer->user_data);
511cc290419Sopenharmony_ci    std::unique_lock<std::mutex> lock(ep->mutexIo);
512cc290419Sopenharmony_ci    bool retrySumit = false;
513cc290419Sopenharmony_ci    int childRet = 0;
514cc290419Sopenharmony_ci    do {
515cc290419Sopenharmony_ci        if (transfer->status != LIBUSB_TRANSFER_COMPLETED) {
516cc290419Sopenharmony_ci            WRITE_LOG(LOG_FATAL, "USBBulkCallback1 failed, ret:%d", transfer->status);
517cc290419Sopenharmony_ci            break;
518cc290419Sopenharmony_ci        }
519cc290419Sopenharmony_ci        if (!ep->bulkInOut && transfer->actual_length != transfer->length) {
520cc290419Sopenharmony_ci            transfer->length -= transfer->actual_length;
521cc290419Sopenharmony_ci            transfer->buffer += transfer->actual_length;
522cc290419Sopenharmony_ci            retrySumit = true;
523cc290419Sopenharmony_ci            break;
524cc290419Sopenharmony_ci        }
525cc290419Sopenharmony_ci    } while (false);
526cc290419Sopenharmony_ci    while (retrySumit) {
527cc290419Sopenharmony_ci        childRet = libusb_submit_transfer(transfer);
528cc290419Sopenharmony_ci        if (childRet != 0) {
529cc290419Sopenharmony_ci            WRITE_LOG(LOG_FATAL, "USBBulkCallback2 failed, ret:%d", childRet);
530cc290419Sopenharmony_ci            transfer->status = LIBUSB_TRANSFER_ERROR;
531cc290419Sopenharmony_ci            break;
532cc290419Sopenharmony_ci        }
533cc290419Sopenharmony_ci        return;
534cc290419Sopenharmony_ci    }
535cc290419Sopenharmony_ci    ep->isComplete = true;
536cc290419Sopenharmony_ci    ep->cv.notify_one();
537cc290419Sopenharmony_ci}
538cc290419Sopenharmony_ci
539cc290419Sopenharmony_ciint HdcHostUSB::SubmitUsbBio(HSession hSession, bool sendOrRecv, uint8_t *buf, int bufSize)
540cc290419Sopenharmony_ci{
541cc290419Sopenharmony_ci    HUSB hUSB = hSession->hUSB;
542cc290419Sopenharmony_ci    int timeout = 0;
543cc290419Sopenharmony_ci    int childRet = 0;
544cc290419Sopenharmony_ci    int ret = ERR_IO_FAIL;
545cc290419Sopenharmony_ci    HostUSBEndpoint *ep = nullptr;
546cc290419Sopenharmony_ci
547cc290419Sopenharmony_ci    if (sendOrRecv) {
548cc290419Sopenharmony_ci        timeout = GLOBAL_TIMEOUT * TIME_BASE;
549cc290419Sopenharmony_ci        ep = &hUSB->hostBulkOut;
550cc290419Sopenharmony_ci    } else {
551cc290419Sopenharmony_ci        timeout = 0;  // infinity
552cc290419Sopenharmony_ci        ep = &hUSB->hostBulkIn;
553cc290419Sopenharmony_ci    }
554cc290419Sopenharmony_ci    hUSB->lockDeviceHandle.lock();
555cc290419Sopenharmony_ci    ep->isComplete = false;
556cc290419Sopenharmony_ci    do {
557cc290419Sopenharmony_ci        std::unique_lock<std::mutex> lock(ep->mutexIo);
558cc290419Sopenharmony_ci        libusb_fill_bulk_transfer(ep->transfer, hUSB->devHandle, ep->endpoint, buf, bufSize, USBBulkCallback, ep,
559cc290419Sopenharmony_ci                                  timeout);
560cc290419Sopenharmony_ci        childRet = libusb_submit_transfer(ep->transfer);
561cc290419Sopenharmony_ci        hUSB->lockDeviceHandle.unlock();
562cc290419Sopenharmony_ci        if (childRet < 0) {
563cc290419Sopenharmony_ci            WRITE_LOG(LOG_FATAL, "SubmitUsbBio libusb_submit_transfer failed, sid:%u ret:%d",
564cc290419Sopenharmony_ci                hSession->sessionId, childRet);
565cc290419Sopenharmony_ci            break;
566cc290419Sopenharmony_ci        }
567cc290419Sopenharmony_ci        ep->cv.wait(lock, [ep]() { return ep->isComplete; });
568cc290419Sopenharmony_ci        if (ep->transfer->status != 0) {
569cc290419Sopenharmony_ci            WRITE_LOG(LOG_FATAL, "SubmitUsbBio transfer failed, sid:%u status:%d",
570cc290419Sopenharmony_ci                hSession->sessionId, ep->transfer->status);
571cc290419Sopenharmony_ci            break;
572cc290419Sopenharmony_ci        }
573cc290419Sopenharmony_ci        ret = ep->transfer->actual_length;
574cc290419Sopenharmony_ci    } while (false);
575cc290419Sopenharmony_ci    return ret;
576cc290419Sopenharmony_ci}
577cc290419Sopenharmony_ci
578cc290419Sopenharmony_civoid HdcHostUSB::BeginUsbRead(HSession hSession)
579cc290419Sopenharmony_ci{
580cc290419Sopenharmony_ci    HUSB hUSB = hSession->hUSB;
581cc290419Sopenharmony_ci    hUSB->hostBulkIn.isShutdown = false;
582cc290419Sopenharmony_ci    hUSB->hostBulkOut.isShutdown = false;
583cc290419Sopenharmony_ci    ++hSession->ref;
584cc290419Sopenharmony_ci    // loop read
585cc290419Sopenharmony_ci    std::thread([this, hSession, hUSB]() {
586cc290419Sopenharmony_ci        int childRet = 0;
587cc290419Sopenharmony_ci        int nextReadSize = 0;
588cc290419Sopenharmony_ci        int bulkInSize = hUSB->hostBulkIn.sizeEpBuf;
589cc290419Sopenharmony_ci        while (!hSession->isDead) {
590cc290419Sopenharmony_ci            // if readIO < wMaxPacketSizeSend, libusb report overflow
591cc290419Sopenharmony_ci            nextReadSize = (childRet < hUSB->wMaxPacketSizeSend ?
592cc290419Sopenharmony_ci                                       hUSB->wMaxPacketSizeSend : std::min(childRet, bulkInSize));
593cc290419Sopenharmony_ci            childRet = SubmitUsbBio(hSession, false, hUSB->hostBulkIn.buf, nextReadSize);
594cc290419Sopenharmony_ci            if (childRet < 0) {
595cc290419Sopenharmony_ci                WRITE_LOG(LOG_FATAL, "Read usb failed, sid:%u ret:%d", hSession->sessionId, childRet);
596cc290419Sopenharmony_ci                break;
597cc290419Sopenharmony_ci            }
598cc290419Sopenharmony_ci
599cc290419Sopenharmony_ci            // when a session is set up for a period of time, the read data is discarded to empty the USB channel.
600cc290419Sopenharmony_ci            if (hSession->isNeedDropData) {
601cc290419Sopenharmony_ci                hSession->dropBytes += childRet;
602cc290419Sopenharmony_ci                childRet = 0;
603cc290419Sopenharmony_ci                continue;
604cc290419Sopenharmony_ci            }
605cc290419Sopenharmony_ci            if (childRet == 0) {
606cc290419Sopenharmony_ci                WRITE_LOG(LOG_WARN, "Read usb return 0, continue read, sid:%u", hSession->sessionId);
607cc290419Sopenharmony_ci                childRet = nextReadSize;
608cc290419Sopenharmony_ci                continue;
609cc290419Sopenharmony_ci            }
610cc290419Sopenharmony_ci            childRet = SendToHdcStream(hSession, reinterpret_cast<uv_stream_t *>(&hSession->dataPipe[STREAM_MAIN]),
611cc290419Sopenharmony_ci                                       hUSB->hostBulkIn.buf, childRet);
612cc290419Sopenharmony_ci            if (childRet < 0) {
613cc290419Sopenharmony_ci                WRITE_LOG(LOG_FATAL, "SendToHdcStream failed, sid:%u ret:%d", hSession->sessionId, childRet);
614cc290419Sopenharmony_ci                break;
615cc290419Sopenharmony_ci            }
616cc290419Sopenharmony_ci        }
617cc290419Sopenharmony_ci        --hSession->ref;
618cc290419Sopenharmony_ci        auto server = reinterpret_cast<HdcServer *>(clsMainBase);
619cc290419Sopenharmony_ci        hUSB->hostBulkIn.isShutdown = true;
620cc290419Sopenharmony_ci        server->FreeSession(hSession->sessionId);
621cc290419Sopenharmony_ci        RemoveIgnoreDevice(hUSB->usbMountPoint);
622cc290419Sopenharmony_ci        WRITE_LOG(LOG_INFO, "Usb loop read finish sid:%u", hSession->sessionId);
623cc290419Sopenharmony_ci    }).detach();
624cc290419Sopenharmony_ci}
625cc290419Sopenharmony_ci
626cc290419Sopenharmony_ci// ==0 Represents new equipment and is what we need,<0  my need
627cc290419Sopenharmony_ciint HdcHostUSB::OpenDeviceMyNeed(HUSB hUSB)
628cc290419Sopenharmony_ci{
629cc290419Sopenharmony_ci    libusb_device *device = hUSB->device;
630cc290419Sopenharmony_ci    int ret = -1;
631cc290419Sopenharmony_ci    int OpenRet = libusb_open(device, &hUSB->devHandle);
632cc290419Sopenharmony_ci    if (OpenRet != LIBUSB_SUCCESS) {
633cc290419Sopenharmony_ci        WRITE_LOG(LOG_DEBUG, "libusb_open fail xret %d", OpenRet);
634cc290419Sopenharmony_ci        return ERR_LIBUSB_OPEN;
635cc290419Sopenharmony_ci    }
636cc290419Sopenharmony_ci    while (modRunning) {
637cc290419Sopenharmony_ci        libusb_device_handle *handle = hUSB->devHandle;
638cc290419Sopenharmony_ci        struct libusb_device_descriptor desc;
639cc290419Sopenharmony_ci        if (CheckDescriptor(hUSB, desc)) {
640cc290419Sopenharmony_ci            break;
641cc290419Sopenharmony_ci        }
642cc290419Sopenharmony_ci        if (CheckActiveConfig(device, hUSB, desc)) {
643cc290419Sopenharmony_ci            break;
644cc290419Sopenharmony_ci        }
645cc290419Sopenharmony_ci        // USB filter rules are set according to specific device pedding device
646cc290419Sopenharmony_ci        ret = libusb_claim_interface(handle, hUSB->interfaceNumber);
647cc290419Sopenharmony_ci        WRITE_LOG(LOG_DEBUG, "libusb_claim_interface ret %d, interfaceNumber %d",
648cc290419Sopenharmony_ci            ret, hUSB->interfaceNumber);
649cc290419Sopenharmony_ci        break;
650cc290419Sopenharmony_ci    }
651cc290419Sopenharmony_ci    if (ret) {
652cc290419Sopenharmony_ci        // not my need device, release the device
653cc290419Sopenharmony_ci        libusb_close(hUSB->devHandle);
654cc290419Sopenharmony_ci        hUSB->devHandle = nullptr;
655cc290419Sopenharmony_ci    }
656cc290419Sopenharmony_ci    return ret;
657cc290419Sopenharmony_ci}
658cc290419Sopenharmony_ci
659cc290419Sopenharmony_ciint HdcHostUSB::SendUSBRaw(HSession hSession, uint8_t *data, const int length)
660cc290419Sopenharmony_ci{
661cc290419Sopenharmony_ci    int ret = ERR_GENERIC;
662cc290419Sopenharmony_ci    HdcSessionBase *server = reinterpret_cast<HdcSessionBase *>(hSession->classInstance);
663cc290419Sopenharmony_ci    ++hSession->ref;
664cc290419Sopenharmony_ci    ret = SubmitUsbBio(hSession, true, data, length);
665cc290419Sopenharmony_ci    if (ret < 0) {
666cc290419Sopenharmony_ci        WRITE_LOG(LOG_FATAL, "Send usb failed, sid:%u ret:%d", hSession->sessionId, ret);
667cc290419Sopenharmony_ci        CancelUsbIo(hSession);
668cc290419Sopenharmony_ci        hSession->hUSB->hostBulkOut.isShutdown = true;
669cc290419Sopenharmony_ci        server->FreeSession(hSession->sessionId);
670cc290419Sopenharmony_ci    }
671cc290419Sopenharmony_ci    --hSession->ref;
672cc290419Sopenharmony_ci    return ret;
673cc290419Sopenharmony_ci}
674cc290419Sopenharmony_ci
675cc290419Sopenharmony_cibool HdcHostUSB::FindDeviceByID(HUSB hUSB, const char *usbMountPoint, libusb_context *ctxUSB)
676cc290419Sopenharmony_ci{
677cc290419Sopenharmony_ci    libusb_device **listDevices = nullptr;
678cc290419Sopenharmony_ci    bool ret = false;
679cc290419Sopenharmony_ci    char tmpStr[BUF_SIZE_TINY] = "";
680cc290419Sopenharmony_ci    int busNum = 0;
681cc290419Sopenharmony_ci    int devNum = 0;
682cc290419Sopenharmony_ci    int curBus = 0;
683cc290419Sopenharmony_ci    int curDev = 0;
684cc290419Sopenharmony_ci
685cc290419Sopenharmony_ci    int device_num = libusb_get_device_list(ctxUSB, &listDevices);
686cc290419Sopenharmony_ci    WRITE_LOG(LOG_DEBUG, "device_num:%d", device_num);
687cc290419Sopenharmony_ci    if (device_num <= 0) {
688cc290419Sopenharmony_ci        libusb_free_device_list(listDevices, 1);
689cc290419Sopenharmony_ci        return false;
690cc290419Sopenharmony_ci    }
691cc290419Sopenharmony_ci    WRITE_LOG(LOG_DEBUG, "usbMountPoint:%s", usbMountPoint);
692cc290419Sopenharmony_ci    if (strchr(usbMountPoint, '-') && EOK == strcpy_s(tmpStr, sizeof(tmpStr), usbMountPoint)) {
693cc290419Sopenharmony_ci        *strchr(tmpStr, '-') = '\0';
694cc290419Sopenharmony_ci        busNum = atoi(tmpStr);
695cc290419Sopenharmony_ci        devNum = atoi(tmpStr + strlen(tmpStr) + 1);
696cc290419Sopenharmony_ci    } else {
697cc290419Sopenharmony_ci        return false;
698cc290419Sopenharmony_ci    }
699cc290419Sopenharmony_ci    WRITE_LOG(LOG_DEBUG, "busNum:%d devNum:%d", busNum, devNum);
700cc290419Sopenharmony_ci
701cc290419Sopenharmony_ci    int i = 0;
702cc290419Sopenharmony_ci    for (i = 0; i < device_num; ++i) {
703cc290419Sopenharmony_ci        struct libusb_device_descriptor desc;
704cc290419Sopenharmony_ci        if (LIBUSB_SUCCESS != libusb_get_device_descriptor(listDevices[i], &desc)) {
705cc290419Sopenharmony_ci            WRITE_LOG(LOG_DEBUG, "libusb_get_device_descriptor failed i:%d", i);
706cc290419Sopenharmony_ci            continue;
707cc290419Sopenharmony_ci        }
708cc290419Sopenharmony_ci        curBus = libusb_get_bus_number(listDevices[i]);
709cc290419Sopenharmony_ci        curDev = libusb_get_device_address(listDevices[i]);
710cc290419Sopenharmony_ci        WRITE_LOG(LOG_DEBUG, "curBus:%d curDev:%d", curBus, curDev);
711cc290419Sopenharmony_ci        if ((curBus == busNum && curDev == devNum)) {
712cc290419Sopenharmony_ci            hUSB->device = listDevices[i];
713cc290419Sopenharmony_ci            int childRet = OpenDeviceMyNeed(hUSB);
714cc290419Sopenharmony_ci            WRITE_LOG(LOG_DEBUG, "OpenDeviceMyNeed childRet:%d", childRet);
715cc290419Sopenharmony_ci            if (!childRet) {
716cc290419Sopenharmony_ci                ret = true;
717cc290419Sopenharmony_ci            } else {
718cc290419Sopenharmony_ci                string key = string(usbMountPoint);
719cc290419Sopenharmony_ci                RemoveIgnoreDevice(key);
720cc290419Sopenharmony_ci            }
721cc290419Sopenharmony_ci            break;
722cc290419Sopenharmony_ci        }
723cc290419Sopenharmony_ci    }
724cc290419Sopenharmony_ci    libusb_free_device_list(listDevices, 1);
725cc290419Sopenharmony_ci    return ret;
726cc290419Sopenharmony_ci}
727cc290419Sopenharmony_ci
728cc290419Sopenharmony_cibool HdcHostUSB::ReadyForWorkThread(HSession hSession)
729cc290419Sopenharmony_ci{
730cc290419Sopenharmony_ci    HdcUSBBase::ReadyForWorkThread(hSession);
731cc290419Sopenharmony_ci    return true;
732cc290419Sopenharmony_ci};
733cc290419Sopenharmony_ci
734cc290419Sopenharmony_ci// Determines that daemonInfo must have the device
735cc290419Sopenharmony_ciHSession HdcHostUSB::ConnectDetectDaemon(const HSession hSession, const HDaemonInfo pdi)
736cc290419Sopenharmony_ci{
737cc290419Sopenharmony_ci    HdcServer *pServer = (HdcServer *)clsMainBase;
738cc290419Sopenharmony_ci    HUSB hUSB = hSession->hUSB;
739cc290419Sopenharmony_ci    hUSB->usbMountPoint = pdi->usbMountPoint;
740cc290419Sopenharmony_ci    hUSB->ctxUSB = ctxUSB;
741cc290419Sopenharmony_ci    if (!FindDeviceByID(hUSB, hUSB->usbMountPoint.c_str(), hUSB->ctxUSB)) {
742cc290419Sopenharmony_ci        pServer->FreeSession(hSession->sessionId);
743cc290419Sopenharmony_ci        RemoveIgnoreDevice(hUSB->usbMountPoint);
744cc290419Sopenharmony_ci        WRITE_LOG(LOG_WARN, "FindDeviceByID fail");
745cc290419Sopenharmony_ci        return nullptr;
746cc290419Sopenharmony_ci    }
747cc290419Sopenharmony_ci    UpdateUSBDaemonInfo(hUSB, hSession, STATUS_CONNECTED);
748cc290419Sopenharmony_ci    hSession->isNeedDropData = true;
749cc290419Sopenharmony_ci    hSession->dropBytes = 0;
750cc290419Sopenharmony_ci    WRITE_LOG(LOG_INFO, "ConnectDetectDaemon set isNeedDropData true, sid:%u", hSession->sessionId);
751cc290419Sopenharmony_ci    BeginUsbRead(hSession);
752cc290419Sopenharmony_ci    hUSB->usbMountPoint = pdi->usbMountPoint;
753cc290419Sopenharmony_ci    WRITE_LOG(LOG_DEBUG, "HSession HdcHostUSB::ConnectDaemon, sid:%u", hSession->sessionId);
754cc290419Sopenharmony_ci
755cc290419Sopenharmony_ci    Base::StartWorkThread(&pServer->loopMain, pServer->SessionWorkThread, Base::FinishWorkThread, hSession);
756cc290419Sopenharmony_ci    // wait for thread up
757cc290419Sopenharmony_ci    while (hSession->childLoop.active_handles == 0) {
758cc290419Sopenharmony_ci        uv_sleep(1);
759cc290419Sopenharmony_ci    }
760cc290419Sopenharmony_ci
761cc290419Sopenharmony_ci    auto funcDelayStartSessionNotify = [hSession](const uint8_t flag, string &msg, const void *p) -> void {
762cc290419Sopenharmony_ci        HdcServer *pServer = (HdcServer *)hSession->classInstance;
763cc290419Sopenharmony_ci        auto ctrl = pServer->BuildCtrlString(SP_START_SESSION, 0, nullptr, 0);
764cc290419Sopenharmony_ci        hSession->isNeedDropData = false;
765cc290419Sopenharmony_ci        WRITE_LOG(LOG_INFO, "funcDelayStartSessionNotify set isNeedDropData false, sid:%u drop %llu bytes data",
766cc290419Sopenharmony_ci            hSession->sessionId, uint64_t(hSession->dropBytes));
767cc290419Sopenharmony_ci        Base::SendToPollFd(hSession->ctrlFd[STREAM_MAIN], ctrl.data(), ctrl.size());
768cc290419Sopenharmony_ci    };
769cc290419Sopenharmony_ci
770cc290419Sopenharmony_ci    // delay NEW_SESSION_DROP_USB_DATA_TIME_MS to start session
771cc290419Sopenharmony_ci    SendSoftResetToDaemon(hSession, 0);
772cc290419Sopenharmony_ci    Base::DelayDoSimple(&(pServer->loopMain), NEW_SESSION_DROP_USB_DATA_TIME_MS, funcDelayStartSessionNotify);
773cc290419Sopenharmony_ci    return hSession;
774cc290419Sopenharmony_ci}
775cc290419Sopenharmony_ci
776cc290419Sopenharmony_civoid HdcHostUSB::SendSoftResetToDaemon(HSession hSession, uint32_t sessionIdOld)
777cc290419Sopenharmony_ci{
778cc290419Sopenharmony_ci    HUSB hUSB = hSession->hUSB;
779cc290419Sopenharmony_ci    hUSB->lockSendUsbBlock.lock();
780cc290419Sopenharmony_ci    WRITE_LOG(LOG_INFO, "SendSoftResetToDaemon sid:%u sidOld:%u", hSession->sessionId, sessionIdOld);
781cc290419Sopenharmony_ci    auto header = BuildPacketHeader(sessionIdOld, USB_OPTION_RESET, 0);
782cc290419Sopenharmony_ci    if (SendUSBRaw(hSession, header.data(), header.size()) <= 0) {
783cc290419Sopenharmony_ci        WRITE_LOG(LOG_FATAL, "SendSoftResetToDaemon send failed");
784cc290419Sopenharmony_ci    }
785cc290419Sopenharmony_ci    hUSB->lockSendUsbBlock.unlock();
786cc290419Sopenharmony_ci    WRITE_LOG(LOG_INFO, "SendSoftResetToDaemon sid:%u finished", hSession->sessionId);
787cc290419Sopenharmony_ci}
788cc290419Sopenharmony_ci}  // namespace Hdc
789