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