• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2024 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 
17 #include <thread>
18 #include "usb_util.h"
19 
20 namespace Hdc {
21 constexpr uint16_t DEVICE_CHECK_INTERVAL = 3000;  // ms
22 constexpr uint16_t BUF_SIZE_MEDIUM = 512;
23 constexpr uint16_t BUF_SIZE_TINY = 64;
24 constexpr uint8_t GLOBAL_TIMEOUT = 30;
25 constexpr uint16_t TIME_BASE = 1000;
26 constexpr uint16_t MAX_SIZE_IOBUF = 61440;
27 
28 uint8_t *g_bufPtr = nullptr;
29 
StringFormat(const char * const formater,va_list & vaArgs)30 const std::string StringFormat(const char * const formater, va_list &vaArgs)
31 {
32     std::vector<char> args(MAX_SIZE_IOBUF);
33     const int retSize = vsnprintf_s(args.data(), MAX_SIZE_IOBUF, MAX_SIZE_IOBUF - 1, formater, vaArgs);
34     if (retSize < 0) {
35         return std::string("");
36     } else {
37         return std::string(args.data(), retSize);
38     }
39 }
40 
StringFormat(const char * const formater,...)41 const std::string StringFormat(const char * const formater, ...)
42 {
43     va_list vaArgs;
44     va_start(vaArgs, formater);
45     std::string ret = StringFormat(formater, vaArgs);
46     va_end(vaArgs);
47     return ret;
48 }
49 
HostUsb()50 HostUsb::HostUsb()
51 {
52     if (libusb_init((libusb_context **)&ctxUSB) != 0) {
53         ctxUSB = nullptr;
54     }
55     running = false;
56 }
57 
~HostUsb()58 HostUsb::~HostUsb()
59 {
60     if (running) {
61         Stop();
62     }
63 }
64 
Stop()65 void HostUsb::Stop()
66 {
67     if (!ctxUSB) {
68         return;
69     }
70     timer->Stop();
71     libusb_exit((libusb_context *)ctxUSB);
72     running = false;
73 
74     if (g_bufPtr != nullptr) {
75         delete[] g_bufPtr;
76         g_bufPtr = nullptr;
77     }
78 }
79 
80 // Main thread USB operates in this thread
UsbWorkThread(void * arg)81 void HostUsb::UsbWorkThread(void *arg)
82 {
83     HostUsb *thisClass = (HostUsb *)arg;
84     constexpr uint8_t usbHandleTimeout = 30;  // second
85     while (thisClass->running) {
86         struct timeval zerotime;
87         zerotime.tv_sec = usbHandleTimeout;
88         zerotime.tv_usec = 0;  // if == 0,windows will be high CPU load
89         libusb_handle_events_timeout(thisClass->ctxUSB, &zerotime);
90     }
91 }
92 
WatchUsbNodeChange(void * arg)93 void HostUsb::WatchUsbNodeChange(void *arg)
94 {
95     HostUsb *thisClass = (HostUsb *)arg;
96     libusb_device **devs = nullptr;
97     libusb_device *dev = nullptr;
98     ssize_t cnt = libusb_get_device_list(thisClass->ctxUSB, &devs);
99     if (cnt < 0) {
100         return;
101     }
102     int i = 0;
103     // linux replug devid increment,windows will be not
104     while ((dev = devs[i++]) != nullptr) {  // must postfix++
105         std::string szTmpKey = StringFormat("%d-%d", libusb_get_bus_number(dev), libusb_get_device_address(dev));
106         // check is in ignore list
107         UsbCheckStatus statusCheck = thisClass->mapIgnoreDevice[szTmpKey];
108         if (statusCheck == HOST_USB_IGNORE || statusCheck == HOST_USB_REGISTER) {
109             continue;
110         }
111         std::string sn = szTmpKey;
112         if (thisClass->HasValidDevice(dev) && !thisClass->DetectMyNeed(dev, sn)) {
113             thisClass->ReviewUsbNodeLater(szTmpKey);
114         }
115     }
116     libusb_free_device_list(devs, 1);
117 }
118 
ReviewUsbNodeLater(string & nodeKey)119 void HostUsb::ReviewUsbNodeLater(string &nodeKey)
120 {
121     // add to ignore list
122     mapIgnoreDevice[nodeKey] = HOST_USB_IGNORE;
123     RemoveIgnoreDevice(nodeKey);
124 }
125 
HasValidDevice(libusb_device * device)126 bool HostUsb::HasValidDevice(libusb_device *device)
127 {
128     struct libusb_config_descriptor *descConfig = nullptr;
129     int ret = libusb_get_active_config_descriptor(device, &descConfig);
130     if (ret != 0) {
131         return false;
132     }
133     bool hasValid = false;
134     for (unsigned int j = 0; j < descConfig->bNumInterfaces; ++j) {
135         const struct libusb_interface *interface = &descConfig->interface[j];
136         if (interface->num_altsetting < 1) {
137             continue;
138         }
139         const struct libusb_interface_descriptor *ifDescriptor = &interface->altsetting[0];
140         if (!IsDebuggableDev(ifDescriptor)) {
141             continue;
142         }
143         hasValid = true;
144         break;
145     }
146     return hasValid;
147 }
148 
IsDebuggableDev(const struct libusb_interface_descriptor * ifDescriptor)149 bool HostUsb::IsDebuggableDev(const struct libusb_interface_descriptor *ifDescriptor)
150 {
151     constexpr uint8_t harmonyEpNum = 2;
152     constexpr uint8_t harmonyClass = 0xff;
153     constexpr uint8_t harmonySubClass = 0x50;
154     constexpr uint8_t harmonyProtocol = 0x01;
155 
156     if (ifDescriptor->bInterfaceClass != harmonyClass || ifDescriptor->bInterfaceSubClass != harmonySubClass ||
157         ifDescriptor->bInterfaceProtocol != harmonyProtocol) {
158         return false;
159     }
160     if (ifDescriptor->bNumEndpoints != harmonyEpNum) {
161         return false;
162     }
163     return true;
164 }
165 
DetectMyNeed(libusb_device * device,string & sn)166 bool HostUsb::DetectMyNeed(libusb_device *device, string &sn)
167 {
168     HUSB hUSB = new(std::nothrow) HdcUSB();
169     if (hUSB == nullptr) {
170         return false;
171     }
172     hUSB->device = device;
173     // just get usb SN, close handle immediately
174     int childRet = OpenDeviceMyNeed(hUSB);
175     if (childRet < 0) {
176         delete hUSB;
177         return false;
178     }
179     UpdateUSBDaemonInfo(hUSB, STATUS_READY);
180     mapIgnoreDevice[sn] = HOST_USB_REGISTER;
181     mapUsbDevice[hUSB->serialNumber] = hUSB;
182     return true;
183 }
184 
UpdateUSBDaemonInfo(HUSB hUSB,uint8_t connStatus)185 void HostUsb::UpdateUSBDaemonInfo(HUSB hUSB, uint8_t connStatus)
186 {
187     // add to list
188     HdcDaemonInformation di;
189     di.connectKey = hUSB->serialNumber;
190     di.connType = CONN_USB;
191     di.connStatus = connStatus;
192     di.usbMountPoint = "";
193     di.usbMountPoint = StringFormat("%d-%d", hUSB->busId, hUSB->devId);
194 
195     HDaemonInfo pDi = nullptr;
196     HDaemonInfo hdiNew = &di;
197     AdminDaemonMap(OP_QUERY, hUSB->serialNumber, pDi);
198     if (!pDi) {
199         AdminDaemonMap(OP_ADD, hUSB->serialNumber, hdiNew);
200     } else {
201         AdminDaemonMap(OP_UPDATE, hUSB->serialNumber, hdiNew);
202         if (connStatus == STATUS_OFFLINE) {
203             RemoveIgnoreDevice(di.usbMountPoint);
204         }
205     }
206 }
207 
208 // ==0 Represents new equipment and is what we need,<0  my need
OpenDeviceMyNeed(HUSB hUSB)209 int HostUsb::OpenDeviceMyNeed(HUSB hUSB)
210 {
211     libusb_device *device = hUSB->device;
212     int ret = -1;
213     int openRet = libusb_open(device, &hUSB->devHandle);
214     if (openRet != LIBUSB_SUCCESS) {
215         return -1;
216     }
217     while (running) {
218         libusb_device_handle *handle = hUSB->devHandle;
219         struct libusb_device_descriptor desc;
220         if (CheckDescriptor(hUSB, desc)) {
221             break;
222         }
223 #ifdef HOST_MAC
224         if (CheckActiveConfig(device, hUSB, desc)) {
225 #else
226         if (CheckActiveConfig(device, hUSB)) {
227 #endif
228             break;
229         }
230 
231         // USB filter rules are set according to specific device pedding device
232         ret = libusb_claim_interface(handle, hUSB->interfaceNumber);
233         break;
234     }
235     if (ret) {
236         // not my need device, release the device
237         libusb_close(hUSB->devHandle);
238         hUSB->devHandle = nullptr;
239     }
240     return ret;
241 }
242 
243 int HostUsb::CheckDescriptor(HUSB hUSB, libusb_device_descriptor& desc)
244 {
245     char serialNum[BUF_SIZE_MEDIUM] = "";
246     int childRet = 0;
247     uint8_t curBus = libusb_get_bus_number(hUSB->device);
248     uint8_t curDev = libusb_get_device_address(hUSB->device);
249     hUSB->busId = curBus;
250     hUSB->devId = curDev;
251     if (libusb_get_device_descriptor(hUSB->device, &desc)) {
252         return -1;
253     }
254     // Get the serial number of the device, if there is no serial number, use the ID number to replace
255     // If the device is not in time, occasionally can't get it, this is determined by the external factor, cannot be
256     // changed. LIBUSB_SUCCESS
257     childRet = libusb_get_string_descriptor_ascii(hUSB->devHandle, desc.iSerialNumber, (uint8_t *)serialNum,
258                                                   sizeof(serialNum));
259     if (childRet < 0) {
260         return -1;
261     } else {
262         hUSB->serialNumber = serialNum;
263     }
264     return 0;
265 }
266 
267 #ifdef HOST_MAC
268 int HostUsb::CheckActiveConfig(libusb_device *device, HUSB hUSB, libusb_device_descriptor& desc)
269 #else
270 int HostUsb::CheckActiveConfig(libusb_device *device, HUSB hUSB)
271 #endif
272 {
273     struct libusb_config_descriptor *descConfig = nullptr;
274     int ret = libusb_get_active_config_descriptor(device, &descConfig);
275     if (ret != 0) {
276 #ifdef HOST_MAC
277         if ((desc.bDeviceClass == 0xFF)
278             && (desc.bDeviceSubClass == 0xFF)
279             && (desc.bDeviceProtocol == 0xFF)) {
280             ret = libusb_set_configuration(hUSB->devHandle, 1);
281             if (ret != 0) {
282                 return -1;
283             }
284         }
285 
286         ret = libusb_get_active_config_descriptor(device, &descConfig);
287         if (ret != 0) {
288 #endif
289             return -1;
290         }
291 #ifdef HOST_MAC
292     }
293 #endif
294 
295     ret = -1;
296     CheckUsbEndpoint(ret, hUSB, descConfig);
297     libusb_free_config_descriptor(descConfig);
298     return ret;
299 }
300 
301 void HostUsb::CheckUsbEndpoint(int& ret, HUSB hUSB, libusb_config_descriptor *descConfig)
302 {
303     unsigned int j = 0;
304     for (j = 0; j < descConfig->bNumInterfaces; ++j) {
305         const struct libusb_interface *interface = &descConfig->interface[j];
306         if (interface->num_altsetting < 1) {
307             continue;
308         }
309         const struct libusb_interface_descriptor *ifDescriptor = &interface->altsetting[0];
310         if (!IsDebuggableDev(ifDescriptor)) {
311             continue;
312         }
313         hUSB->interfaceNumber = ifDescriptor->bInterfaceNumber;
314         unsigned int k = 0;
315         for (k = 0; k < ifDescriptor->bNumEndpoints; ++k) {
316             const struct libusb_endpoint_descriptor *ep_desc = &ifDescriptor->endpoint[k];
317             if ((ep_desc->bmAttributes & 0x03) != LIBUSB_TRANSFER_TYPE_BULK) {
318                 continue;
319             }
320             if (ep_desc->bEndpointAddress & LIBUSB_ENDPOINT_IN) {
321                 hUSB->hostBulkIn.endpoint = ep_desc->bEndpointAddress;
322                 hUSB->hostBulkIn.bulkInOut = true;
323             } else {
324                 hUSB->hostBulkOut.endpoint = ep_desc->bEndpointAddress;
325                 hUSB->wMaxPacketSizeSend = ep_desc->wMaxPacketSize;
326                 hUSB->hostBulkOut.bulkInOut = false;
327             }
328         }
329         if (hUSB->hostBulkIn.endpoint == 0 || hUSB->hostBulkOut.endpoint == 0) {
330             break;
331         }
332         ret = 0;
333     }
334 }
335 
336 bool HostUsb::FindDeviceByID(HUSB hUSB, const char *usbMountPoint, libusb_context *ctxUSB)
337 {
338     libusb_device **listDevices = nullptr;
339     bool ret = false;
340     char tmpStr[BUF_SIZE_TINY] = "";
341     int busNum = 0;
342     int devNum = 0;
343     int curBus = 0;
344     int curDev = 0;
345 
346     int deviceNum = libusb_get_device_list(ctxUSB, &listDevices);
347     if (deviceNum <= 0) {
348         libusb_free_device_list(listDevices, 1);
349         return false;
350     }
351     if (strchr(usbMountPoint, '-') && EOK == strcpy_s(tmpStr, sizeof(tmpStr), usbMountPoint)) {
352         *strchr(tmpStr, '-') = '\0';
353         busNum = atoi(tmpStr);
354         devNum = atoi(tmpStr + strlen(tmpStr) + 1);
355     } else {
356         return false;
357     }
358 
359     int i = 0;
360     for (i = 0; i < deviceNum; ++i) {
361         struct libusb_device_descriptor desc;
362         if (LIBUSB_SUCCESS != libusb_get_device_descriptor(listDevices[i], &desc)) {
363             continue;
364         }
365         curBus = libusb_get_bus_number(listDevices[i]);
366         curDev = libusb_get_device_address(listDevices[i]);
367         if ((curBus == busNum && curDev == devNum)) {
368             hUSB->device = listDevices[i];
369             int childRet = OpenDeviceMyNeed(hUSB);
370             if (!childRet) {
371                 ret = true;
372             } else {
373                 string key = string(usbMountPoint);
374                 RemoveIgnoreDevice(key);
375             }
376             break;
377         }
378     }
379     libusb_free_device_list(listDevices, 1);
380     return ret;
381 }
382 
383 // multi-thread calll
384 void HostUsb::CancelUsbIo(HUSB hUSB)
385 {
386     std::unique_lock<std::mutex> lock(hUSB->lockDeviceHandle);
387     if (!hUSB->hostBulkIn.isShutdown) {
388         if (!hUSB->hostBulkIn.isComplete) {
389             libusb_cancel_transfer(hUSB->hostBulkIn.transfer);
390             hUSB->hostBulkIn.cv.notify_one();
391         } else {
392             hUSB->hostBulkIn.isShutdown = true;
393         }
394     }
395     if (!hUSB->hostBulkOut.isShutdown) {
396         if (!hUSB->hostBulkOut.isComplete) {
397             libusb_cancel_transfer(hUSB->hostBulkOut.transfer);
398             hUSB->hostBulkOut.cv.notify_one();
399         } else {
400             hUSB->hostBulkOut.isShutdown = true;
401         }
402     }
403 }
404 
405 void HostUsb::RemoveIgnoreDevice(string &mountInfo)
406 {
407     if (mapIgnoreDevice.count(mountInfo)) {
408         mapIgnoreDevice.erase(mountInfo);
409     }
410 }
411 
412 void LIBUSB_CALL HostUsb::USBBulkCallback(struct libusb_transfer *transfer)
413 {
414     auto *ep = reinterpret_cast<HostUSBEndpoint *>(transfer->user_data);
415     std::unique_lock<std::mutex> lock(ep->mutexIo);
416     bool retrySumit = false;
417     int childRet = 0;
418     do {
419         if (transfer->status != LIBUSB_TRANSFER_COMPLETED) {
420             break;
421         }
422         if (!ep->bulkInOut && transfer->actual_length != transfer->length) {
423             transfer->length -= transfer->actual_length;
424             transfer->buffer += transfer->actual_length;
425             retrySumit = true;
426             break;
427         }
428     } while (false);
429     while (retrySumit) {
430         childRet = libusb_submit_transfer(transfer);
431         if (childRet != 0) {
432             transfer->status = LIBUSB_TRANSFER_ERROR;
433             break;
434         }
435         return;
436     }
437     ep->isComplete = true;
438     ep->cv.notify_one();
439 }
440 
441 PersistBuffer HostUsb::ReadUsbIO(HUSB hUSB, int exceptedSize)
442 {
443     int timeout = 0;
444     int childRet = 0;
445     int ret = 0;
446 
447     HostUSBEndpoint* ep = &hUSB->hostBulkIn;
448 
449     if (g_bufPtr == nullptr) {
450         g_bufPtr = new uint8_t[MAX_SIZE_IOBUF];
451     }
452 
453     hUSB->lockDeviceHandle.lock();
454     ep->isComplete = false;
455     do {
456         std::unique_lock<std::mutex> lock(ep->mutexIo);
457         libusb_fill_bulk_transfer(ep->transfer, hUSB->devHandle, ep->endpoint, g_bufPtr, exceptedSize,
458             USBBulkCallback, ep, timeout);
459         childRet = libusb_submit_transfer(ep->transfer);
460         hUSB->lockDeviceHandle.unlock();
461         if (childRet < 0) {
462             break;
463         }
464         ep->cv.wait(lock, [ep]() { return ep->isComplete; });
465         if (ep->transfer->status != 0) {
466             break;
467         }
468         ret = ep->transfer->actual_length;
469     } while (false);
470     return PersistBuffer{reinterpret_cast<char *>(g_bufPtr), static_cast<uint64_t>(ret)};
471 }
472 
473 HUSB HostUsb::GetUsbDevice(std::string connectKey)
474 {
475     return mapUsbDevice[connectKey];
476 }
477 
478 int HostUsb::WriteUsbIO(HUSB hUSB, SerializedBuffer buf)
479 {
480     int childRet = 0;
481     int ret = -14000;
482     int timeout = GLOBAL_TIMEOUT * TIME_BASE;
483     HostUSBEndpoint *ep = &hUSB->hostBulkOut;
484 
485     hUSB->lockDeviceHandle.lock();
486     ep->isComplete = false;
487     uint8_t* ptr = reinterpret_cast<uint8_t *>(buf.ptr);
488     size_t size = static_cast<size_t>(buf.size);
489     do {
490         std::unique_lock<std::mutex> lock(ep->mutexIo);
491         libusb_fill_bulk_transfer(ep->transfer, hUSB->devHandle, ep->endpoint, ptr, size, USBBulkCallback, ep,
492                                   timeout);
493         childRet = libusb_submit_transfer(ep->transfer);
494         hUSB->lockDeviceHandle.unlock();
495         if (childRet < 0) {
496             break;
497         }
498         ep->cv.wait(lock, [ep]() { return ep->isComplete; });
499         if (ep->transfer->status != 0) {
500             break;
501         }
502         ret = ep->transfer->actual_length;
503     } while (false);
504     return ret;
505 }
506 
507 int HostUsb::Initial()
508 {
509     if (!ctxUSB) {
510         return -1;
511     }
512     running = true;
513     auto WatchUsbNodeChangeFunc = [this]() { WatchUsbNodeChange(this); };
514     timer = std::make_unique<CTimer>(WatchUsbNodeChangeFunc);
515     timer->Start(DEVICE_CHECK_INTERVAL);
516     std::thread([this]() {
517         UsbWorkThread(this);
518     }).detach();
519     return 0;
520 }
521 
522 static void BuildDaemonVisableLine(HDaemonInfo hdi, bool fullDisplay, string &out)
523 {
524     if (fullDisplay) {
525         string sConn;
526         string sStatus;
527         switch (hdi->connType) {
528             case CONN_TCP:
529                 sConn = "TCP";
530                 break;
531             case CONN_USB:
532                 sConn = "USB";
533                 break;
534 #ifdef HDC_SUPPORT_UART
535             case CONN_SERIAL:
536                 sConn = "UART";
537                 break;
538 #endif
539             case CONN_BT:
540                 sConn = "BT";
541                 break;
542             default:
543                 sConn = "UNKNOW";
544                 break;
545         }
546         switch (hdi->connStatus) {
547             case STATUS_READY:
548                 sStatus = "Ready";
549                 break;
550             case STATUS_CONNECTED:
551                 sStatus = "Connected";
552                 break;
553             case STATUS_OFFLINE:
554                 sStatus = "Offline";
555                 break;
556             default:
557                 sStatus = "UNKNOW";
558                 break;
559         }
560         out = StringFormat("%s\t\t%s\t%s\t%s\n", hdi->connectKey.c_str(), sConn.c_str(), sStatus.c_str(),
561                   hdi->devName.c_str());
562     } else {
563         if (hdi->connStatus == STATUS_CONNECTED) {
564             out = StringFormat("%s\n", hdi->connectKey.c_str());
565         }
566     }
567 }
568 
569 string HostUsb::GetDaemonMapList(uint8_t opType)
570 {
571     string ret;
572     bool fullDisplay = false;
573     if (opType == OP_GET_STRLIST_FULL) {
574         fullDisplay = true;
575     }
576     lockMapDaemon.lock();
577     map<string, HDaemonInfo>::iterator iter;
578     string echoLine;
579     for (iter = mapDaemon.begin(); iter != mapDaemon.end(); ++iter) {
580         HDaemonInfo di = iter->second;
581         if (!di) {
582             continue;
583         }
584         echoLine = "";
585         if (opType == OP_GET_READY_STRLIST) {
586             if (di->connStatus == STATUS_READY) {
587                 echoLine = StringFormat("%s ", di->connectKey.c_str());
588                 ret += echoLine;
589             }
590             continue;
591         }
592         BuildDaemonVisableLine(di, fullDisplay, echoLine);
593         ret += echoLine;
594     }
595     lockMapDaemon.unlock();
596     return ret;
597 }
598 
599 string HostUsb::AdminDaemonMap(uint8_t opType, const string &connectKey, HDaemonInfo &hDaemonInfoInOut)
600 {
601     string sRet;
602     switch (opType) {
603         case OP_ADD: {
604             HDaemonInfo pdiNew = new(std::nothrow) HdcDaemonInformation();
605             if (pdiNew == nullptr) {
606                 break;
607             }
608             *pdiNew = *hDaemonInfoInOut;
609             lockMapDaemon.lock();
610             if (!mapDaemon[hDaemonInfoInOut->connectKey]) {
611                 mapDaemon[hDaemonInfoInOut->connectKey] = pdiNew;
612             }
613             lockMapDaemon.unlock();
614             break;
615         }
616         case OP_GET_READY_STRLIST:
617             sRet = GetDaemonMapList(opType);
618             break;
619         case OP_GET_STRLIST:
620         case OP_GET_STRLIST_FULL: {
621             sRet = GetDaemonMapList(opType);
622             break;
623         }
624         case OP_QUERY: {
625             lockMapDaemon.lock();
626             if (mapDaemon.count(connectKey)) {
627                 hDaemonInfoInOut = mapDaemon[connectKey];
628             }
629             lockMapDaemon.unlock();
630             break;
631         }
632         case OP_REMOVE: {
633             lockMapDaemon.lock();
634             if (mapDaemon.count(connectKey)) {
635                 mapDaemon.erase(connectKey);
636             }
637             lockMapDaemon.unlock();
638             break;
639         }
640         case OP_GET_ANY: {
641             lockMapDaemon.lock();
642             map<string, HDaemonInfo>::iterator iter;
643             for (iter = mapDaemon.begin(); iter != mapDaemon.end(); ++iter) {
644                 HDaemonInfo di = iter->second;
645                 // usb will be auto connected
646                 if (di->connStatus == STATUS_READY || di->connStatus == STATUS_CONNECTED) {
647                     hDaemonInfoInOut = di;
648                     break;
649                 }
650             }
651             lockMapDaemon.unlock();
652             break;
653         }
654         case OP_WAIT_FOR_ANY: {
655             lockMapDaemon.lock();
656             map<string, HDaemonInfo>::iterator iter;
657             for (iter = mapDaemon.begin(); iter != mapDaemon.end(); ++iter) {
658                 HDaemonInfo di = iter->second;
659                 if (di->connStatus == STATUS_CONNECTED) {
660                     hDaemonInfoInOut = di;
661                     break;
662                 }
663             }
664             lockMapDaemon.unlock();
665             break;
666         }
667         case OP_UPDATE: {  // Cannot update the Object HDi lower key value by direct value
668             lockMapDaemon.lock();
669             HDaemonInfo hdi = mapDaemon[hDaemonInfoInOut->connectKey];
670             if (hdi) {
671                 *mapDaemon[hDaemonInfoInOut->connectKey] = *hDaemonInfoInOut;
672             }
673             lockMapDaemon.unlock();
674             break;
675         }
676         default:
677             break;
678     }
679     return sRet;
680 }
681 }
682