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