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