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