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