1 /*
2 * Copyright (C) 2021 Huawei Device Co., Ltd.
3 * Licensed under the Apache License, Version 2.0 (the "License");
4 * you may not use this file except in compliance with the License.
5 * You may obtain a copy of the License at
6 *
7 * http://www.apache.org/licenses/LICENSE-2.0
8 *
9 * Unless required by applicable law or agreed to in writing, software
10 * distributed under the License is distributed on an "AS IS" BASIS,
11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 * See the License for the specific language governing permissions and
13 * limitations under the License.
14 */
15 #include "host_usb.h"
16 #include <stdlib.h>
17 #include <thread>
18
19 #include "server.h"
20 namespace Hdc {
HdcHostUSB(const bool serverOrDaemonIn, void *ptrMainBase, void *ctxUSBin)21 HdcHostUSB::HdcHostUSB(const bool serverOrDaemonIn, void *ptrMainBase, void *ctxUSBin)
22 : HdcUSBBase(serverOrDaemonIn, ptrMainBase)
23 {
24 modRunning = false;
25 HdcServer *pServer = (HdcServer *)ptrMainBase;
26 ctxUSB = (libusb_context *)ctxUSBin;
27 uv_timer_init(&pServer->loopMain, &devListWatcher);
28 }
29
~HdcHostUSB()30 HdcHostUSB::~HdcHostUSB()
31 {
32 if (modRunning) {
33 Stop();
34 }
35 WRITE_LOG(LOG_DEBUG, "~HdcHostUSB");
36 }
37
Stop()38 void HdcHostUSB::Stop()
39 {
40 if (!ctxUSB) {
41 return;
42 }
43 Base::TryCloseHandle((uv_handle_t *)&devListWatcher);
44 modRunning = false;
45 }
46
Initial()47 int HdcHostUSB::Initial()
48 {
49 if (!ctxUSB) {
50 WRITE_LOG(LOG_FATAL, "USB mod ctxUSB is nullptr, recompile please");
51 return -1;
52 }
53 WRITE_LOG(LOG_DEBUG, "HdcHostUSB init");
54 modRunning = true;
55 StartupUSBWork(); // Main thread registration, IO in sub-thread
56 return 0;
57 }
58
UsbLogHandler(libusb_context* ctx, enum libusb_log_level level, const char* str)59 static void UsbLogHandler(libusb_context* ctx, enum libusb_log_level level, const char* str)
60 {
61 int l = -1;
62 switch (level) {
63 case LIBUSB_LOG_LEVEL_ERROR:
64 l = LOG_FATAL;
65 break;
66 case LIBUSB_LOG_LEVEL_WARNING:
67 l = LOG_WARN;
68 break;
69 case LIBUSB_LOG_LEVEL_INFO:
70 l = LOG_INFO;
71 break;
72 case LIBUSB_LOG_LEVEL_DEBUG:
73 l = LOG_DEBUG;
74 break;
75 default:
76 break;
77 }
78 if (l >= 0) {
79 char *newStr = strdup(str);
80 if (!newStr) {
81 return;
82 }
83 char *p = strstr(newStr, "libusb:");
84 if (!p) {
85 p = newStr;
86 }
87 char *q = strrchr(newStr, '\n');
88 if (q) {
89 *q = '\0';
90 }
91 WRITE_LOG(l, "%s", p);
92 free(newStr);
93 }
94 }
InitLogging(void *ctxUSB)95 void HdcHostUSB::InitLogging(void *ctxUSB)
96 {
97 if (ctxUSB == nullptr) {
98 WRITE_LOG(LOG_FATAL, "InitLogging failed ctxUSB is nullptr");
99 return;
100 }
101 std::string debugEnv = "LIBUSB_DEBUG";
102 libusb_log_level debugLevel;
103
104 switch (static_cast<Hdc::HdcLogLevel>(Base::GetLogLevel())) {
105 case LOG_WARN:
106 debugLevel = LIBUSB_LOG_LEVEL_ERROR;
107 break;
108 case LOG_INFO:
109 debugLevel = LIBUSB_LOG_LEVEL_WARNING;
110 break;
111 case LOG_DEBUG:
112 debugLevel = LIBUSB_LOG_LEVEL_INFO;
113 break;
114 case LOG_VERBOSE:
115 debugLevel = LIBUSB_LOG_LEVEL_DEBUG;
116 break;
117 case LOG_FATAL:
118 // pass through to no libusb logging
119 default:
120 debugLevel = LIBUSB_LOG_LEVEL_NONE;
121 break;
122 }
123
124 libusb_set_option((libusb_context *)ctxUSB, LIBUSB_OPTION_LOG_LEVEL, debugLevel);
125 libusb_set_log_cb((libusb_context *)ctxUSB, UsbLogHandler,
126 LIBUSB_LOG_CB_CONTEXT | LIBUSB_LOG_CB_GLOBAL);
127
128 #ifdef _WIN32
129 debugEnv += "=";
130 debugEnv += std::to_string(debugLevel);
131 _putenv(debugEnv.c_str());
132 #else
133 setenv(debugEnv.c_str(), std::to_string(debugLevel).c_str(), 1);
134 #endif
135 }
136
DetectMyNeed(libusb_device *device, string &sn)137 bool HdcHostUSB::DetectMyNeed(libusb_device *device, string &sn)
138 {
139 HUSB hUSB = new(std::nothrow) HdcUSB();
140 if (hUSB == nullptr) {
141 WRITE_LOG(LOG_FATAL, "DetectMyNeed new hUSB failed");
142 return false;
143 }
144 hUSB->device = device;
145 // just get usb SN, close handle immediately
146 int childRet = OpenDeviceMyNeed(hUSB);
147 if (childRet < 0) {
148 WRITE_LOG(LOG_FATAL, "DetectMyNeed OpenDeviceMyNeed childRet:%d", childRet);
149 delete hUSB;
150 return false;
151 }
152 libusb_release_interface(hUSB->devHandle, hUSB->interfaceNumber);
153 libusb_close(hUSB->devHandle);
154 hUSB->devHandle = nullptr;
155
156 WRITE_LOG(LOG_INFO, "Needed device found, busid:%d devid:%d connectkey:%s", hUSB->busId, hUSB->devId,
157 Hdc::MaskString(hUSB->serialNumber).c_str());
158 // USB device is automatically connected after recognition, auto connect USB
159 UpdateUSBDaemonInfo(hUSB, nullptr, STATUS_READY);
160 HdcServer *hdcServer = (HdcServer *)clsMainBase;
161 HSession hSession = hdcServer->MallocSession(true, CONN_USB, this);
162 if (!hSession) {
163 WRITE_LOG(LOG_FATAL, "malloc usb session failed sn:%s", Hdc::MaskString(sn).c_str());
164 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
KickoutZombie(HSession hSession)182 void 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
RemoveIgnoreDevice(string &mountInfo)198 void HdcHostUSB::RemoveIgnoreDevice(string &mountInfo)
199 {
200 if (mapIgnoreDevice.count(mountInfo)) {
201 mapIgnoreDevice.erase(mountInfo);
202 }
203 }
204
ReviewUsbNodeLater(string &nodeKey)205 void 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
WatchUsbNodeChange(uv_timer_t *handle)215 void 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
HasValidDevice(libusb_device *device)246 bool 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
UsbWorkThread(void *arg)271 void 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
StartupUSBWork()284 int 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
CheckDescriptor(HUSB hUSB, libusb_device_descriptor& desc)295 int 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
UpdateUSBDaemonInfo(HUSB hUSB, HSession hSession, uint8_t connStatus)324 void 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
IsDebuggableDev(const struct libusb_interface_descriptor *ifDescriptor)346 bool 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
CheckActiveConfig(libusb_device *device, HUSB hUSB, libusb_device_descriptor& desc)363 int 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
CheckUsbEndpoint(int& ret, HUSB hUSB, libusb_config_descriptor *descConfig)395 void 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
CancelUsbIo(HSession hSession)438 void 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
UsbToHdcProtocol(uv_stream_t *stream, uint8_t *appendData, int dataSize)463 int 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
USBBulkCallback(struct libusb_transfer *transfer)508 void 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
SubmitUsbBio(HSession hSession, bool sendOrRecv, uint8_t *buf, int bufSize)539 int 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
BeginUsbRead(HSession hSession)578 void 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
OpenDeviceMyNeed(HUSB hUSB)627 int 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
SendUSBRaw(HSession hSession, uint8_t *data, const int length)659 int 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
FindDeviceByID(HUSB hUSB, const char *usbMountPoint, libusb_context *ctxUSB)675 bool 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
ReadyForWorkThread(HSession hSession)728 bool HdcHostUSB::ReadyForWorkThread(HSession hSession)
729 {
730 HdcUSBBase::ReadyForWorkThread(hSession);
731 return true;
732 };
733
734 // Determines that daemonInfo must have the device
ConnectDetectDaemon(const HSession hSession, const HDaemonInfo pdi)735 HSession 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
SendSoftResetToDaemon(HSession hSession, uint32_t sessionIdOld)776 void 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