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