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