• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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"
20 namespace Hdc {
HdcHostUSB(const bool serverOrDaemonIn,void * ptrMainBase,void * ctxUSBin)21 HdcHostUSB::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 
~HdcHostUSB()30 HdcHostUSB::~HdcHostUSB()
31 {
32     if (modRunning) {
33         Stop();
34     }
35     WRITE_LOG(LOG_DEBUG, "~HdcHostUSB");
36 }
37 
Stop()38 void HdcHostUSB::Stop()
39 {
40     if (!ctxUSB) {
41         return;
42     }
43     Base::TryCloseHandle((uv_handle_t *)&devListWatcher);
44     modRunning = false;
45 }
46 
Initial()47 int 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 
UsbLogHandler(libusb_context * ctx,enum libusb_log_level level,const char * str)59 static 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 }
InitLogging(void * ctxUSB)95 void 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::LogLevel>(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 
DetectMyNeed(libusb_device * device,string & sn)137 bool 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         delete hUSB;
149         return false;
150     }
151     libusb_release_interface(hUSB->devHandle, hUSB->interfaceNumber);
152     libusb_close(hUSB->devHandle);
153     hUSB->devHandle = nullptr;
154 
155     WRITE_LOG(LOG_INFO, "Needed device found, busid:%d devid:%d connectkey:%s", hUSB->busId, hUSB->devId,
156               hUSB->serialNumber.c_str());
157     // USB device is automatically connected after recognition, auto connect USB
158     UpdateUSBDaemonInfo(hUSB, nullptr, STATUS_READY);
159     HdcServer *hdcServer = (HdcServer *)clsMainBase;
160     HSession hSession = hdcServer->MallocSession(true, CONN_USB, this);
161     hSession->connectKey = hUSB->serialNumber;
162     uv_timer_t *waitTimeDoCmd = new(std::nothrow) uv_timer_t;
163     if (waitTimeDoCmd == nullptr) {
164         WRITE_LOG(LOG_FATAL, "DetectMyNeed new waitTimeDoCmd failed");
165         delete hUSB;
166         return false;
167     }
168     uv_timer_init(&hdcServer->loopMain, waitTimeDoCmd);
169     waitTimeDoCmd->data = hSession;
170     uv_timer_start(waitTimeDoCmd, hdcServer->UsbPreConnect, 0, DEVICE_CHECK_INTERVAL);
171     mapIgnoreDevice[sn] = HOST_USB_REGISTER;
172     delete hUSB;
173     return true;
174 }
175 
KickoutZombie(HSession hSession)176 void HdcHostUSB::KickoutZombie(HSession hSession)
177 {
178     HdcServer *ptrConnect = (HdcServer *)hSession->classInstance;
179     HUSB hUSB = hSession->hUSB;
180     if (!hUSB->devHandle) {
181         WRITE_LOG(LOG_WARN, "KickoutZombie devHandle:%p isDead:%d", hUSB->devHandle, hSession->isDead);
182         return;
183     }
184     if (LIBUSB_ERROR_NO_DEVICE != libusb_kernel_driver_active(hUSB->devHandle, hUSB->interfaceNumber)) {
185         return;
186     }
187     WRITE_LOG(LOG_WARN, "KickoutZombie LIBUSB_ERROR_NO_DEVICE serialNumber:%s", hUSB->serialNumber.c_str());
188     ptrConnect->FreeSession(hSession->sessionId);
189 }
190 
RemoveIgnoreDevice(string & mountInfo)191 void HdcHostUSB::RemoveIgnoreDevice(string &mountInfo)
192 {
193     if (mapIgnoreDevice.count(mountInfo)) {
194         mapIgnoreDevice.erase(mountInfo);
195     }
196 }
197 
ReviewUsbNodeLater(string & nodeKey)198 void HdcHostUSB::ReviewUsbNodeLater(string &nodeKey)
199 {
200     HdcServer *hdcServer = (HdcServer *)clsMainBase;
201     // add to ignore list
202     mapIgnoreDevice[nodeKey] = HOST_USB_IGNORE;
203     int delayRemoveFromList = DEVICE_CHECK_INTERVAL * MINOR_TIMEOUT;  // wait little time for daemon reinit
204     Base::DelayDo(&hdcServer->loopMain, delayRemoveFromList, 0, nodeKey, nullptr,
205                   [this](const uint8_t flag, string &msg, const void *) -> void { RemoveIgnoreDevice(msg); });
206 }
207 
WatchUsbNodeChange(uv_timer_t * handle)208 void HdcHostUSB::WatchUsbNodeChange(uv_timer_t *handle)
209 {
210     HdcHostUSB *thisClass = (HdcHostUSB *)handle->data;
211     HdcServer *ptrConnect = (HdcServer *)thisClass->clsMainBase;
212     libusb_device **devs = nullptr;
213     libusb_device *dev = nullptr;
214     // kick zombie
215     ptrConnect->EnumUSBDeviceRegister(KickoutZombie);
216     // find new
217     ssize_t cnt = libusb_get_device_list(thisClass->ctxUSB, &devs);
218     if (cnt < 0) {
219         WRITE_LOG(LOG_FATAL, "Failed to get device list");
220         return;
221     }
222     int i = 0;
223     // linux replug devid increment,windows will be not
224     while ((dev = devs[i++]) != nullptr) {  // must postfix++
225         string szTmpKey = Base::StringFormat("%d-%d", libusb_get_bus_number(dev), libusb_get_device_address(dev));
226         // check is in ignore list
227         UsbCheckStatus statusCheck = thisClass->mapIgnoreDevice[szTmpKey];
228         if (statusCheck == HOST_USB_IGNORE || statusCheck == HOST_USB_REGISTER) {
229             continue;
230         }
231         string sn = szTmpKey;
232         if (thisClass->HasValidDevice(dev) && !thisClass->DetectMyNeed(dev, sn)) {
233             thisClass->ReviewUsbNodeLater(szTmpKey);
234         }
235     }
236     libusb_free_device_list(devs, 1);
237 }
238 
HasValidDevice(libusb_device * device)239 bool HdcHostUSB::HasValidDevice(libusb_device *device)
240 {
241     struct libusb_config_descriptor *descConfig = nullptr;
242     int ret = libusb_get_active_config_descriptor(device, &descConfig);
243     if (ret != 0) {
244         WRITE_LOG(LOG_WARN, "get active config des fail, errno is %d.", errno);
245         return false;
246     }
247     bool hasValid = false;
248     for (unsigned int j = 0; j < descConfig->bNumInterfaces; ++j) {
249         const struct libusb_interface *interface = &descConfig->interface[j];
250         if (interface->num_altsetting < 1) {
251             continue;
252         }
253         const struct libusb_interface_descriptor *ifDescriptor = &interface->altsetting[0];
254         if (!IsDebuggableDev(ifDescriptor)) {
255             continue;
256         }
257         hasValid = true;
258         break;
259     }
260     return hasValid;
261 }
262 
263 // Main thread USB operates in this thread
UsbWorkThread(void * arg)264 void HdcHostUSB::UsbWorkThread(void *arg)
265 {
266     HdcHostUSB *thisClass = (HdcHostUSB *)arg;
267     constexpr uint8_t usbHandleTimeout = 30;  // second
268     while (thisClass->modRunning) {
269         struct timeval zerotime;
270         zerotime.tv_sec = usbHandleTimeout;
271         zerotime.tv_usec = 0;  // if == 0,windows will be high CPU load
272         libusb_handle_events_timeout(thisClass->ctxUSB, &zerotime);
273     }
274     WRITE_LOG(LOG_DEBUG, "Host Sessionbase usb workthread finish");
275 }
276 
StartupUSBWork()277 int HdcHostUSB::StartupUSBWork()
278 {
279     // Because libusb(winusb backend) does not support hotplug under win32, we use list mode for all platforms
280     WRITE_LOG(LOG_DEBUG, "USBHost loopfind mode");
281     devListWatcher.data = this;
282     uv_timer_start(&devListWatcher, WatchUsbNodeChange, 0, DEVICE_CHECK_INTERVAL);
283     // Running pendding in independent threads does not significantly improve the efficiency
284     uv_thread_create(&threadUsbWork, UsbWorkThread, this);
285     return 0;
286 }
287 
CheckDescriptor(HUSB hUSB,libusb_device_descriptor & desc)288 int HdcHostUSB::CheckDescriptor(HUSB hUSB, libusb_device_descriptor& desc)
289 {
290     char serialNum[BUF_SIZE_MEDIUM] = "";
291     int childRet = 0;
292     uint8_t curBus = libusb_get_bus_number(hUSB->device);
293     uint8_t curDev = libusb_get_device_address(hUSB->device);
294     hUSB->busId = curBus;
295     hUSB->devId = curDev;
296     if (libusb_get_device_descriptor(hUSB->device, &desc)) {
297         WRITE_LOG(LOG_WARN, "CheckDescriptor libusb_get_device_descriptor failed %d-%d", curBus, curDev);
298         return -1;
299     }
300     // Get the serial number of the device, if there is no serial number, use the ID number to replace
301     // If the device is not in time, occasionally can't get it, this is determined by the external factor, cannot be
302     // changed. LIBUSB_SUCCESS
303     childRet = libusb_get_string_descriptor_ascii(hUSB->devHandle, desc.iSerialNumber, (uint8_t *)serialNum,
304                                                   sizeof(serialNum));
305     if (childRet < 0) {
306         WRITE_LOG(LOG_WARN, "CheckDescriptor libusb_get_string_descriptor_ascii failed %d-%d", curBus, curDev);
307         return -1;
308     } else {
309         hUSB->serialNumber = serialNum;
310     }
311     WRITE_LOG(LOG_DEBUG, "CheckDescriptor busId-devId:%d-%d serialNum:%s", curBus, curDev, serialNum);
312     return 0;
313 }
314 
315 // hSession can be null
UpdateUSBDaemonInfo(HUSB hUSB,HSession hSession,uint8_t connStatus)316 void HdcHostUSB::UpdateUSBDaemonInfo(HUSB hUSB, HSession hSession, uint8_t connStatus)
317 {
318     // add to list
319     HdcServer *pServer = (HdcServer *)clsMainBase;
320     HdcDaemonInformation di;
321     di.connectKey = hUSB->serialNumber;
322     di.connType = CONN_USB;
323     di.connStatus = connStatus;
324     di.hSession = hSession;
325     di.usbMountPoint = "";
326     di.usbMountPoint = Base::StringFormat("%d-%d", hUSB->busId, hUSB->devId);
327 
328     HDaemonInfo pDi = nullptr;
329     HDaemonInfo hdiNew = &di;
330     pServer->AdminDaemonMap(OP_QUERY, hUSB->serialNumber, pDi);
331     if (!pDi) {
332         pServer->AdminDaemonMap(OP_ADD, hUSB->serialNumber, hdiNew);
333     } else {
334         pServer->AdminDaemonMap(OP_UPDATE, hUSB->serialNumber, hdiNew);
335     }
336 }
337 
IsDebuggableDev(const struct libusb_interface_descriptor * ifDescriptor)338 bool HdcHostUSB::IsDebuggableDev(const struct libusb_interface_descriptor *ifDescriptor)
339 {
340     constexpr uint8_t harmonyEpNum = 2;
341     constexpr uint8_t harmonyClass = 0xff;
342     constexpr uint8_t harmonySubClass = 0x50;
343     constexpr uint8_t harmonyProtocol = 0x01;
344 
345     if (ifDescriptor->bInterfaceClass != harmonyClass || ifDescriptor->bInterfaceSubClass != harmonySubClass ||
346         ifDescriptor->bInterfaceProtocol != harmonyProtocol) {
347         return false;
348     }
349     if (ifDescriptor->bNumEndpoints != harmonyEpNum) {
350         return false;
351     }
352     return true;
353 }
354 
CheckActiveConfig(libusb_device * device,HUSB hUSB,libusb_device_descriptor & desc)355 int HdcHostUSB::CheckActiveConfig(libusb_device *device, HUSB hUSB, libusb_device_descriptor& desc)
356 {
357     struct libusb_config_descriptor *descConfig = nullptr;
358     int ret = libusb_get_active_config_descriptor(device, &descConfig);
359     if (ret != 0) {
360 #ifdef HOST_MAC
361         if ((desc.bDeviceClass == 0xFF)
362             && (desc.bDeviceSubClass == 0xFF)
363             && (desc.bDeviceProtocol == 0xFF)) {
364             ret = libusb_set_configuration(hUSB->devHandle, 1);
365             if (ret != 0) {
366                 WRITE_LOG(LOG_WARN, "set config failed ret:%d", ret);
367                 return -1;
368             }
369         }
370 
371         ret = libusb_get_active_config_descriptor(device, &descConfig);
372         if (ret != 0) {
373 #endif
374             return -1;
375         }
376 #ifdef HOST_MAC
377     }
378 #endif
379 
380     ret = -1;
381     CheckUsbEndpoint(ret, hUSB, descConfig);
382     libusb_free_config_descriptor(descConfig);
383     return ret;
384 }
385 
CheckUsbEndpoint(int & ret,HUSB hUSB,libusb_config_descriptor * descConfig)386 void HdcHostUSB::CheckUsbEndpoint(int& ret, HUSB hUSB, libusb_config_descriptor *descConfig)
387 {
388     unsigned int j = 0;
389     for (j = 0; j < descConfig->bNumInterfaces; ++j) {
390         const struct libusb_interface *interface = &descConfig->interface[j];
391         if (interface->num_altsetting < 1) {
392             continue;
393         }
394         const struct libusb_interface_descriptor *ifDescriptor = &interface->altsetting[0];
395         if (!IsDebuggableDev(ifDescriptor)) {
396             continue;
397         }
398         WRITE_LOG(LOG_DEBUG, "CheckActiveConfig IsDebuggableDev passed and then check endpoint attr");
399         hUSB->interfaceNumber = ifDescriptor->bInterfaceNumber;
400         unsigned int k = 0;
401         for (k = 0; k < ifDescriptor->bNumEndpoints; ++k) {
402             const struct libusb_endpoint_descriptor *ep_desc = &ifDescriptor->endpoint[k];
403             if ((ep_desc->bmAttributes & 0x03) != LIBUSB_TRANSFER_TYPE_BULK) {
404                 continue;
405             }
406             if (ep_desc->bEndpointAddress & LIBUSB_ENDPOINT_IN) {
407                 hUSB->hostBulkIn.endpoint = ep_desc->bEndpointAddress;
408                 hUSB->hostBulkIn.bulkInOut = true;
409             } else {
410                 hUSB->hostBulkOut.endpoint = ep_desc->bEndpointAddress;
411                 hUSB->wMaxPacketSizeSend = ep_desc->wMaxPacketSize;
412                 hUSB->hostBulkOut.bulkInOut = false;
413             }
414         }
415         if (hUSB->hostBulkIn.endpoint == 0 || hUSB->hostBulkOut.endpoint == 0) {
416             break;
417         }
418         ret = 0;
419     }
420 }
421 
422 // multi-thread calll
CancelUsbIo(HSession hSession)423 void HdcHostUSB::CancelUsbIo(HSession hSession)
424 {
425     WRITE_LOG(LOG_DEBUG, "HostUSB CancelUsbIo, ref:%u", uint32_t(hSession->ref));
426     HUSB hUSB = hSession->hUSB;
427     std::unique_lock<std::mutex> lock(hUSB->lockDeviceHandle);
428     if (!hUSB->hostBulkIn.isShutdown) {
429         if (!hUSB->hostBulkIn.isComplete) {
430             libusb_cancel_transfer(hUSB->hostBulkIn.transfer);
431             hUSB->hostBulkIn.cv.notify_one();
432         } else {
433             hUSB->hostBulkIn.isShutdown = true;
434         }
435     }
436     if (!hUSB->hostBulkOut.isShutdown) {
437         if (!hUSB->hostBulkOut.isComplete) {
438             libusb_cancel_transfer(hUSB->hostBulkOut.transfer);
439             hUSB->hostBulkOut.cv.notify_one();
440         } else {
441             hUSB->hostBulkOut.isShutdown = true;
442         }
443     }
444 }
445 
446 // 3rd write child-hdc-workthread
447 // no use uvwrite, raw write to socketpair's fd
UsbToHdcProtocol(uv_stream_t * stream,uint8_t * appendData,int dataSize)448 int HdcHostUSB::UsbToHdcProtocol(uv_stream_t *stream, uint8_t *appendData, int dataSize)
449 {
450     HSession hSession = (HSession)stream->data;
451     unsigned int fd = hSession->dataFd[STREAM_MAIN];
452     fd_set fdSet;
453     struct timeval timeout = { 3, 0 };
454     FD_ZERO(&fdSet);
455     FD_SET(fd, &fdSet);
456     int index = 0;
457     int childRet = 0;
458 
459     while (index < dataSize) {
460         if ((childRet = select(fd + 1, nullptr, &fdSet, nullptr, &timeout)) <= 0) {
461             constexpr int bufSize = 1024;
462             char buf[bufSize] = { 0 };
463 #ifdef _WIN32
464             strerror_s(buf, bufSize, errno);
465 #else
466             strerror_r(errno, buf, bufSize);
467 #endif
468             WRITE_LOG(LOG_FATAL, "select error:%d [%s][%d]", errno, buf, childRet);
469             break;
470         }
471         childRet = send(fd, reinterpret_cast<const char *>(appendData) + index, dataSize - index, 0);
472         if (childRet < 0) {
473             constexpr int bufSize = 1024;
474             char buf[bufSize] = { 0 };
475 #ifdef _WIN32
476             strerror_s(buf, bufSize, errno);
477 #else
478             strerror_r(errno, buf, bufSize);
479 #endif
480             WRITE_LOG(LOG_FATAL, "UsbToHdcProtocol senddata err:%d [%s]", errno, buf);
481             break;
482         }
483         index += childRet;
484     }
485     if (index != dataSize) {
486         WRITE_LOG(LOG_FATAL, "UsbToHdcProtocol partialsenddata err:%d [%d]", index, dataSize);
487         return ERR_IO_FAIL;
488     }
489     return index;
490 }
491 
USBBulkCallback(struct libusb_transfer * transfer)492 void LIBUSB_CALL HdcHostUSB::USBBulkCallback(struct libusb_transfer *transfer)
493 {
494     auto *ep = reinterpret_cast<HostUSBEndpoint *>(transfer->user_data);
495     std::unique_lock<std::mutex> lock(ep->mutexIo);
496     bool retrySumit = false;
497     int childRet = 0;
498     do {
499         if (transfer->status != LIBUSB_TRANSFER_COMPLETED) {
500             WRITE_LOG(LOG_FATAL, "USBBulkCallback1 failed, ret:%d", transfer->status);
501             break;
502         }
503         if (!ep->bulkInOut && transfer->actual_length != transfer->length) {
504             transfer->length -= transfer->actual_length;
505             transfer->buffer += transfer->actual_length;
506             retrySumit = true;
507             break;
508         }
509     } while (false);
510     while (retrySumit) {
511         childRet = libusb_submit_transfer(transfer);
512         if (childRet != 0) {
513             WRITE_LOG(LOG_FATAL, "USBBulkCallback2 failed, ret:%d", childRet);
514             transfer->status = LIBUSB_TRANSFER_ERROR;
515             break;
516         }
517         return;
518     }
519     ep->isComplete = true;
520     ep->cv.notify_one();
521 }
522 
SubmitUsbBio(HSession hSession,bool sendOrRecv,uint8_t * buf,int bufSize)523 int HdcHostUSB::SubmitUsbBio(HSession hSession, bool sendOrRecv, uint8_t *buf, int bufSize)
524 {
525     HUSB hUSB = hSession->hUSB;
526     int timeout = 0;
527     int childRet = 0;
528     int ret = ERR_IO_FAIL;
529     HostUSBEndpoint *ep = nullptr;
530 
531     if (sendOrRecv) {
532         timeout = GLOBAL_TIMEOUT * TIME_BASE;
533         ep = &hUSB->hostBulkOut;
534     } else {
535         timeout = 0;  // infinity
536         ep = &hUSB->hostBulkIn;
537     }
538     hUSB->lockDeviceHandle.lock();
539     ep->isComplete = false;
540     do {
541         std::unique_lock<std::mutex> lock(ep->mutexIo);
542         libusb_fill_bulk_transfer(ep->transfer, hUSB->devHandle, ep->endpoint, buf, bufSize, USBBulkCallback, ep,
543                                   timeout);
544         childRet = libusb_submit_transfer(ep->transfer);
545         hUSB->lockDeviceHandle.unlock();
546         if (childRet < 0) {
547             WRITE_LOG(LOG_FATAL, "SubmitUsbBio libusb_submit_transfer failed, ret:%d", childRet);
548             break;
549         }
550         ep->cv.wait(lock, [ep]() { return ep->isComplete; });
551         if (ep->transfer->status != 0) {
552             WRITE_LOG(LOG_FATAL, "SubmitUsbBio transfer failed, status:%d", ep->transfer->status);
553             break;
554         }
555         ret = ep->transfer->actual_length;
556     } while (false);
557     return ret;
558 }
559 
BeginUsbRead(HSession hSession)560 void HdcHostUSB::BeginUsbRead(HSession hSession)
561 {
562     HUSB hUSB = hSession->hUSB;
563     hUSB->hostBulkIn.isShutdown = false;
564     hUSB->hostBulkOut.isShutdown = false;
565     ++hSession->ref;
566     // loop read
567     std::thread([this, hSession, hUSB]() {
568         int childRet = 0;
569         int nextReadSize = 0;
570         while (!hSession->isDead) {
571             // if readIO < wMaxPacketSizeSend, libusb report overflow
572             nextReadSize = (childRet < hUSB->wMaxPacketSizeSend ? hUSB->wMaxPacketSizeSend
573                                                                 : std::min(childRet, Base::GetUsbffsBulkSize()));
574             childRet = SubmitUsbBio(hSession, false, hUSB->hostBulkIn.buf, nextReadSize);
575             if (childRet < 0) {
576                 WRITE_LOG(LOG_FATAL, "Read usb failed, ret:%d", childRet);
577                 break;
578             }
579             childRet = SendToHdcStream(hSession, reinterpret_cast<uv_stream_t *>(&hSession->dataPipe[STREAM_MAIN]),
580                                        hUSB->hostBulkIn.buf, childRet);
581             if (childRet < 0) {
582                 WRITE_LOG(LOG_FATAL, "SendToHdcStream failed, ret:%d", childRet);
583                 break;
584             }
585         }
586         --hSession->ref;
587         auto server = reinterpret_cast<HdcServer *>(clsMainBase);
588         hUSB->hostBulkIn.isShutdown = true;
589         server->FreeSession(hSession->sessionId);
590         WRITE_LOG(LOG_DEBUG, "Usb loop read finish");
591     }).detach();
592 }
593 
594 // ==0 Represents new equipment and is what we need,<0  my need
OpenDeviceMyNeed(HUSB hUSB)595 int HdcHostUSB::OpenDeviceMyNeed(HUSB hUSB)
596 {
597     libusb_device *device = hUSB->device;
598     int ret = -1;
599     if (LIBUSB_SUCCESS != libusb_open(device, &hUSB->devHandle)) {
600         return -100;
601     }
602     while (modRunning) {
603         libusb_device_handle *handle = hUSB->devHandle;
604         struct libusb_device_descriptor desc;
605         if (CheckDescriptor(hUSB, desc)) {
606             break;
607         }
608         if (CheckActiveConfig(device, hUSB, desc)) {
609             break;
610         }
611         // USB filter rules are set according to specific device pedding device
612         ret = libusb_claim_interface(handle, hUSB->interfaceNumber);
613         break;
614     }
615     if (ret) {
616         // not my need device, release the device
617         libusb_close(hUSB->devHandle);
618         hUSB->devHandle = nullptr;
619     }
620     return ret;
621 }
622 
SendUSBRaw(HSession hSession,uint8_t * data,const int length)623 int HdcHostUSB::SendUSBRaw(HSession hSession, uint8_t *data, const int length)
624 {
625     int ret = ERR_GENERIC;
626     HdcSessionBase *server = reinterpret_cast<HdcSessionBase *>(hSession->classInstance);
627     ++hSession->ref;
628     ret = SubmitUsbBio(hSession, true, data, length);
629     if (ret < 0) {
630         WRITE_LOG(LOG_FATAL, "Send usb failed, ret:%d", ret);
631         CancelUsbIo(hSession);
632         hSession->hUSB->hostBulkOut.isShutdown = true;
633         server->FreeSession(hSession->sessionId);
634     }
635     --hSession->ref;
636     return ret;
637 }
638 
FindDeviceByID(HUSB hUSB,const char * usbMountPoint,libusb_context * ctxUSB)639 bool HdcHostUSB::FindDeviceByID(HUSB hUSB, const char *usbMountPoint, libusb_context *ctxUSB)
640 {
641     libusb_device **listDevices = nullptr;
642     bool ret = false;
643     char tmpStr[BUF_SIZE_TINY] = "";
644     int busNum = 0;
645     int devNum = 0;
646     int curBus = 0;
647     int curDev = 0;
648 
649     int device_num = libusb_get_device_list(ctxUSB, &listDevices);
650     WRITE_LOG(LOG_DEBUG, "device_num:%d", device_num);
651     if (device_num <= 0) {
652         libusb_free_device_list(listDevices, 1);
653         return false;
654     }
655     WRITE_LOG(LOG_DEBUG, "usbMountPoint:%s", usbMountPoint);
656     if (strchr(usbMountPoint, '-') && EOK == strcpy_s(tmpStr, sizeof(tmpStr), usbMountPoint)) {
657         *strchr(tmpStr, '-') = '\0';
658         busNum = atoi(tmpStr);
659         devNum = atoi(tmpStr + strlen(tmpStr) + 1);
660     } else
661         return false;
662     WRITE_LOG(LOG_DEBUG, "busNum:%d devNum:%d", busNum, devNum);
663 
664     int i = 0;
665     for (i = 0; i < device_num; ++i) {
666         struct libusb_device_descriptor desc;
667         if (LIBUSB_SUCCESS != libusb_get_device_descriptor(listDevices[i], &desc)) {
668             WRITE_LOG(LOG_DEBUG, "libusb_get_device_descriptor failed i:%d", i);
669             continue;
670         }
671         curBus = libusb_get_bus_number(listDevices[i]);
672         curDev = libusb_get_device_address(listDevices[i]);
673         WRITE_LOG(LOG_DEBUG, "curBus:%d curDev:%d", curBus, curDev);
674         if ((curBus == busNum && curDev == devNum)) {
675             hUSB->device = listDevices[i];
676             int childRet = OpenDeviceMyNeed(hUSB);
677             WRITE_LOG(LOG_DEBUG, "OpenDeviceMyNeed childRet:%d", childRet);
678             if (!childRet) {
679                 ret = true;
680             }
681             break;
682         }
683     }
684     libusb_free_device_list(listDevices, 1);
685     return ret;
686 }
687 
ReadyForWorkThread(HSession hSession)688 bool HdcHostUSB::ReadyForWorkThread(HSession hSession)
689 {
690     HdcUSBBase::ReadyForWorkThread(hSession);
691     return true;
692 };
693 
694 // Determines that daemonInfo must have the device
ConnectDetectDaemon(const HSession hSession,const HDaemonInfo pdi)695 HSession HdcHostUSB::ConnectDetectDaemon(const HSession hSession, const HDaemonInfo pdi)
696 {
697     HdcServer *pServer = (HdcServer *)clsMainBase;
698     HUSB hUSB = hSession->hUSB;
699     hUSB->usbMountPoint = pdi->usbMountPoint;
700     hUSB->ctxUSB = ctxUSB;
701     if (!FindDeviceByID(hUSB, hUSB->usbMountPoint.c_str(), hUSB->ctxUSB)) {
702         pServer->FreeSession(hSession->sessionId);
703         return nullptr;
704     }
705     UpdateUSBDaemonInfo(hUSB, hSession, STATUS_CONNECTED);
706     BeginUsbRead(hSession);
707     hUSB->usbMountPoint = pdi->usbMountPoint;
708     WRITE_LOG(LOG_DEBUG, "HSession HdcHostUSB::ConnectDaemon");
709 
710     Base::StartWorkThread(&pServer->loopMain, pServer->SessionWorkThread, Base::FinishWorkThread, hSession);
711     // wait for thread up
712     while (hSession->childLoop.active_handles == 0) {
713         uv_sleep(1);
714     }
715     auto ctrl = pServer->BuildCtrlString(SP_START_SESSION, 0, nullptr, 0);
716     Base::SendToPollFd(hSession->ctrlFd[STREAM_MAIN], ctrl.data(), ctrl.size());
717     return hSession;
718 }
719 }  // namespace Hdc
720