• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 "daemon_usb.h"
16 #include <cerrno>
17 #include <cstddef>
18 #include "arpa/inet.h"
19 #include "asm-generic/int-ll64.h"
20 #include "fcntl.h"
21 #include "linux/usb/functionfs.h"
22 #include "new"
23 #include "sched.h"
24 #include "system_depend.h"
25 #include "unistd.h"
26 #include "uv/unix.h"
27 #include "daemon.h"
28 #include "usb_ffs.h"
29 
30 namespace Hdc {
31 static constexpr int CONFIG_COUNT2 = 2;
32 static constexpr int CONFIG_COUNT3 = 3;
33 static constexpr int CONFIG_COUNT5 = 5;
34 
35 struct UvData {
36     HdcDaemonUSB *daemonUsb;
37     const uint8_t *buf;
38 };
39 
HdcDaemonUSB(const bool serverOrDaemonIn,void * ptrMainBase)40 HdcDaemonUSB::HdcDaemonUSB(const bool serverOrDaemonIn, void *ptrMainBase)
41     : HdcUSBBase(serverOrDaemonIn, ptrMainBase)
42 {
43 }
44 
~HdcDaemonUSB()45 HdcDaemonUSB::~HdcDaemonUSB()
46 {
47     // Closed in the IO loop, no longer closing CLOSE ENDPOINT
48     Base::CloseFd(controlEp);
49     if (ctxRecv.buf) {
50         delete[] ctxRecv.buf;
51     }
52     uv_fs_req_cleanup(&ctxRecv.req);
53 }
54 
Stop()55 void HdcDaemonUSB::Stop()
56 {
57     WRITE_LOG(LOG_DEBUG, "HdcDaemonUSB Stop");
58     // Here only clean up the IO-related resources, session related resources clear reason to clean up the session
59     // module
60     modRunning = false;
61     WRITE_LOG(LOG_DEBUG, "HdcDaemonUSB Stop free main session");
62     Base::TryCloseHandle((uv_handle_t *)&checkEP);
63     CloseEndpoint(&usbHandle);
64     WRITE_LOG(LOG_DEBUG, "HdcDaemonUSB Stop free main session finish");
65 }
66 
GetDevPath(const std::string & path)67 string HdcDaemonUSB::GetDevPath(const std::string &path)
68 {
69     DIR *dir = ::opendir(path.c_str());
70     if (dir == nullptr) {
71         WRITE_LOG(LOG_WARN, "%s: cannot open devpath: errno: %d", path.c_str(), errno);
72         return "";
73     }
74 
75     string res = USB_FFS_BASE;
76     string node;
77     int count = 0;
78     struct dirent *entry = nullptr;
79     while ((entry = ::readdir(dir))) {
80         if (*entry->d_name == '.') {
81             continue;
82         }
83         node = entry->d_name;
84         ++count;
85     }
86     if (count > 1) {
87         res += "hdc";
88     } else {
89         res += node;
90     }
91     ::closedir(dir);
92     return res;
93 }
94 
GetMaxPacketSize(int fdFfs)95 int HdcDaemonUSB::GetMaxPacketSize(int fdFfs)
96 {
97     // no ioctl support, todo dynamic get
98     return MAX_PACKET_SIZE_HISPEED;
99 }
100 
Initial()101 int HdcDaemonUSB::Initial()
102 {
103     // after Linux-3.8,kernel switch to the USB Function FS
104     // Implement USB hdc function in user space
105     WRITE_LOG(LOG_DEBUG, "HdcDaemonUSB init");
106     basePath = GetDevPath(USB_FFS_BASE);
107     if (access((basePath + "/ep0").c_str(), F_OK) != 0) {
108         WRITE_LOG(LOG_DEBUG, "Only support usb-ffs, make sure kernel3.8+ and usb-ffs enabled, usbmode disabled");
109         return ERR_API_FAIL;
110     }
111     ctxRecv.thisClass = this;
112     ctxRecv.bufSizeMax = Base::GetUsbffsBulkSize();
113     ctxRecv.buf = new uint8_t[ctxRecv.bufSizeMax]();
114     if (!ctxRecv.buf) {
115         WRITE_LOG(LOG_FATAL, "Init alloc memory failed");
116         return ERR_BUF_ALLOC;
117     }
118 
119     HdcDaemon *daemon = (HdcDaemon *)clsMainBase;
120     WRITE_LOG(LOG_DEBUG, "HdcDaemonUSB::Initiall");
121     uv_timer_init(&daemon->loopMain, &checkEP);
122     checkEP.data = this;
123     uv_timer_start(&checkEP, WatchEPTimer, 0, TIME_BASE);
124     return 0;
125 }
126 
127 // make gnuc++ happy. Clang support direct assignment value to structure, buf g++ weakness
FillUsbV2Head(usb_functionfs_desc_v2 & descUsbFfs)128 void HdcDaemonUSB::FillUsbV2Head(usb_functionfs_desc_v2 &descUsbFfs)
129 {
130     descUsbFfs.head.magic = LONG_LE(FUNCTIONFS_DESCRIPTORS_MAGIC_V2);
131     descUsbFfs.head.length = LONG_LE(sizeof(descUsbFfs));
132     descUsbFfs.head.flags
133         = FUNCTIONFS_HAS_FS_DESC | FUNCTIONFS_HAS_HS_DESC | FUNCTIONFS_HAS_SS_DESC | FUNCTIONFS_HAS_MS_OS_DESC;
134     descUsbFfs.config1Count = CONFIG_COUNT3;
135     descUsbFfs.config2Count = CONFIG_COUNT3;
136     descUsbFfs.config3Count = CONFIG_COUNT5;
137     descUsbFfs.configWosCount = CONFIG_COUNT2;
138     descUsbFfs.config1Desc = config1;
139     descUsbFfs.config2Desc = config2;
140     descUsbFfs.config3Desc = config3;
141     descUsbFfs.wosHead = g_wosHead;
142     descUsbFfs.wosDesc = g_wosDesc;
143     descUsbFfs.osPropHead = g_osPropHead;
144     descUsbFfs.osPropValues = g_osPropValues;
145 }
146 
147 // DAEMON end USB module USB-FFS EP port connection
ConnectEPPoint(HUSB hUSB)148 int HdcDaemonUSB::ConnectEPPoint(HUSB hUSB)
149 {
150     int ret = ERR_GENERIC;
151     struct usb_functionfs_desc_v2 descUsbFfs = {};
152     FillUsbV2Head(descUsbFfs);
153     while (true) {
154         if (controlEp <= 0) {
155             // After the control port sends the instruction, the device is initialized by the device to the HOST host,
156             // which can be found for USB devices. Do not send initialization to the EP0 control port, the USB
157             // device will not be initialized by Host
158             WRITE_LOG(LOG_DEBUG, "Begin send to control(EP0) for usb descriptor init");
159             string ep0Path = basePath + "/ep0";
160             if ((controlEp = open(ep0Path.c_str(), O_RDWR)) < 0) {
161                 WRITE_LOG(LOG_WARN, "%s: cannot open control endpoint: errno=%d", ep0Path.c_str(), errno);
162                 break;
163             }
164             if (write(controlEp, &descUsbFfs, sizeof(descUsbFfs)) < 0) {
165                 WRITE_LOG(LOG_WARN, "%s: write ffs configs failed: errno=%d", ep0Path.c_str(), errno);
166                 break;
167             }
168             if (write(controlEp, &USB_FFS_VALUE, sizeof(USB_FFS_VALUE)) < 0) {
169                 WRITE_LOG(LOG_WARN, "%s: write USB_FFS_VALUE failed: errno=%d", ep0Path.c_str(), errno);
170                 break;
171             }
172             // active usbrc,Send USB initialization signal
173             SystemDepend::SetDevItem("sys.usb.ffs.ready", "1");
174             WRITE_LOG(LOG_DEBUG, "ConnectEPPoint ctrl init finish, set usb-ffs ready");
175         }
176         string outPath = basePath + "/ep1";
177         if ((hUSB->bulkOut = open(outPath.c_str(), O_RDWR)) < 0) {
178             WRITE_LOG(LOG_WARN, "%s: cannot open bulk-out ep: errno=%d", outPath.c_str(), errno);
179             break;
180         }
181         string inPath = basePath + "/ep2";
182         if ((hUSB->bulkIn = open(inPath.c_str(), O_RDWR)) < 0) {
183             WRITE_LOG(LOG_WARN, "%s: cannot open bulk-in ep: errno=%d", inPath.c_str(), errno);
184             break;
185         }
186         // cannot open with O_CLOEXEC, must fcntl
187         fcntl(controlEp, F_SETFD, FD_CLOEXEC);
188         fcntl(hUSB->bulkOut, F_SETFD, FD_CLOEXEC);
189         fcntl(hUSB->bulkIn, F_SETFD, FD_CLOEXEC);
190         hUSB->wMaxPacketSizeSend = GetMaxPacketSize(hUSB->bulkIn);
191 
192         WRITE_LOG(LOG_DEBUG, "New bulk in\\out open bulkout:%d bulkin:%d", hUSB->bulkOut, hUSB->bulkIn);
193         ret = RET_SUCCESS;
194         break;
195     }
196     if (ret != RET_SUCCESS) {
197         CloseEndpoint(hUSB, true);
198     }
199     return ret;
200 }
201 
CloseEndpoint(HUSB hUSB,bool closeCtrlEp)202 void HdcDaemonUSB::CloseEndpoint(HUSB hUSB, bool closeCtrlEp)
203 {
204     Base::CloseFd(hUSB->bulkIn);
205     Base::CloseFd(hUSB->bulkOut);
206     if (controlEp > 0 && closeCtrlEp) {
207         Base::CloseFd(controlEp);
208         controlEp = 0;
209     }
210     isAlive = false;
211     WRITE_LOG(LOG_FATAL, "DaemonUSB close endpoint");
212 }
213 
ResetOldSession(uint32_t sessionId)214 void HdcDaemonUSB::ResetOldSession(uint32_t sessionId)
215 {
216     HdcDaemon *daemon = reinterpret_cast<HdcDaemon *>(clsMainBase);
217     if (sessionId == 0) {
218         sessionId = currentSessionId;
219     }
220     HSession hSession = daemon->AdminSession(OP_QUERY, sessionId, nullptr);
221     if (hSession == nullptr) {
222         return;
223     }
224     // The Host side is restarted, but the USB cable is still connected
225     WRITE_LOG(LOG_WARN, "Hostside softreset to restart daemon, old sessionId:%u", sessionId);
226     daemon->FreeSession(sessionId);
227 }
228 
229 // Prevent other USB data misfortunes to send the program crash
AvailablePacket(uint8_t * ioBuf,int ioBytes,uint32_t * sessionId)230 int HdcDaemonUSB::AvailablePacket(uint8_t *ioBuf, int ioBytes, uint32_t *sessionId)
231 {
232     int ret = RET_SUCCESS;
233     while (true) {
234         if (!IsUsbPacketHeader(ioBuf, ioBytes)) {
235             break;
236         }
237         // usb header
238         USBHead *usbPayloadHeader = reinterpret_cast<struct USBHead *>(ioBuf);
239         uint32_t inSessionId = ntohl(usbPayloadHeader->sessionId);
240         if ((usbPayloadHeader->option & USB_OPTION_RESET)) {
241             ResetOldSession(inSessionId);
242             ret = ERR_IO_SOFT_RESET;
243             break;
244         }
245         *sessionId = inSessionId;
246         break;
247     }
248     return ret;
249 }
250 
251 // Work in subcrete,Work thread is ready
ReadyForWorkThread(HSession hSession)252 bool HdcDaemonUSB::ReadyForWorkThread(HSession hSession)
253 {
254     HdcUSBBase::ReadyForWorkThread(hSession);
255     return true;
256 };
257 
CloseBulkEp(bool bulkInOut,int bulkFd,uv_loop_t * loop)258 int HdcDaemonUSB::CloseBulkEp(bool bulkInOut, int bulkFd, uv_loop_t *loop)
259 {
260     struct CtxCloseBulkEp {
261         uv_fs_t req;
262         HdcDaemonUSB *thisClass;
263         bool bulkInOut;
264     };
265     CtxCloseBulkEp *ctx = new(std::nothrow) CtxCloseBulkEp();
266     if (ctx == nullptr) {
267         WRITE_LOG(LOG_FATAL, "CloseBulkEp new ctx failed");
268         return -1;
269     }
270     uv_fs_t *req = &ctx->req;
271     req->data = ctx;
272     ctx->bulkInOut = bulkInOut;
273     ctx->thisClass = this;
274     isAlive = false;
275     WRITE_LOG(LOG_DEBUG, "CloseBulkEp bulkFd:%d", bulkFd);
276     uv_fs_close(loop, req, bulkFd, [](uv_fs_t *req) {
277         auto ctx = (CtxCloseBulkEp *)req->data;
278         WRITE_LOG(LOG_DEBUG, "Try to abort blukin write callback %s", ctx->bulkInOut ? "bulkin" : "bulkout");
279         if (ctx->bulkInOut) {
280             ctx->thisClass->usbHandle.bulkIn = 0;
281         } else {
282             ctx->thisClass->usbHandle.bulkOut = 0;
283         }
284         uv_fs_req_cleanup(req);
285         delete ctx;
286     });
287     return 0;
288 }
289 
SendUSBIOSync(HSession hSession,HUSB hMainUSB,const uint8_t * data,const int length)290 int HdcDaemonUSB::SendUSBIOSync(HSession hSession, HUSB hMainUSB, const uint8_t *data, const int length)
291 {
292     int bulkIn = hMainUSB->bulkIn;
293     int childRet = 0;
294     int ret = ERR_IO_FAIL;
295     int offset = 0;
296     StartTraceScope("HdcDaemonUSB::SendUSBIOSync");
297     while (modRunning && isAlive && !hSession->isDead) {
298         childRet = write(bulkIn, const_cast<uint8_t *>(data) + offset, length - offset);
299         if (childRet <= 0) {
300             int err = errno;
301             if (err == EINTR) {
302                 WRITE_LOG(LOG_WARN, "BulkinWrite write EINTR, try again, offset:%u bulkIn:%d bulkOut:%d",
303                     offset, bulkIn, hMainUSB->bulkOut);
304                 continue;
305             } else {
306                 WRITE_LOG(LOG_FATAL, "BulkinWrite write fatal errno %d", err);
307                 isAlive = false;
308             }
309             break;
310         }
311         offset += childRet;
312         if (offset >= length) {
313             break;
314         }
315     }
316     if (offset == length) {
317         ret = length;
318     } else {
319         WRITE_LOG(LOG_FATAL, "BulkinWrite write failed, nsize:%d really:%d modRunning:%d isAlive:%d SessionDead:%d",
320                   length, offset, modRunning, isAlive, hSession->isDead);
321     }
322     return ret;
323 }
324 
SendUSBRaw(HSession hSession,uint8_t * data,const int length)325 int HdcDaemonUSB::SendUSBRaw(HSession hSession, uint8_t *data, const int length)
326 {
327     StartTraceScope("HdcDaemonUSB::SendUSBRaw");
328     HdcDaemon *daemon = (HdcDaemon *)hSession->classInstance;
329     std::unique_lock<std::mutex> lock(mutexUsbFfs);
330     ++hSession->ref;
331     int ret = SendUSBIOSync(hSession, &usbHandle, data, length);
332     --hSession->ref;
333     if (ret < 0) {
334         daemon->FreeSession(hSession->sessionId);
335         WRITE_LOG(LOG_DEBUG, "SendUSBRaw try to freesession");
336     }
337     return ret;
338 }
339 
340 // cross thread call
OnNewHandshakeOK(const uint32_t sessionId)341 void HdcDaemonUSB::OnNewHandshakeOK(const uint32_t sessionId)
342 {
343     currentSessionId = sessionId;  // sync with server, and set server's real Id
344 }
345 
346 // MainThreadCall, when seession was freed
OnSessionFreeFinally(const HSession hSession)347 void HdcDaemonUSB::OnSessionFreeFinally(const HSession hSession)
348 {
349     if (currentSessionId == hSession->sessionId) {
350         isAlive = false;
351         // uv_cancel ctxRecv.req == UV_EBUSY, not effect immediately. It must be close by logic
352     }
353 }
354 
PrepareNewSession(uint32_t sessionId,uint8_t * pRecvBuf,int recvBytesIO)355 HSession HdcDaemonUSB::PrepareNewSession(uint32_t sessionId, uint8_t *pRecvBuf, int recvBytesIO)
356 {
357     HdcDaemon *daemon = reinterpret_cast<HdcDaemon *>(clsMainBase);
358     StartTraceScope("HdcDaemonUSB::PrepareNewSession");
359     HSession hChildSession = daemon->MallocSession(false, CONN_USB, this, sessionId);
360     if (!hChildSession) {
361         return nullptr;
362     }
363     currentSessionId = sessionId;
364     Base::StartWorkThread(&daemon->loopMain, daemon->SessionWorkThread, Base::FinishWorkThread, hChildSession);
365     auto funcNewSessionUp = [](uv_timer_t *handle) -> void {
366         HSession hChildSession = reinterpret_cast<HSession>(handle->data);
367         HdcDaemon *daemon = reinterpret_cast<HdcDaemon *>(hChildSession->classInstance);
368         if (hChildSession->childLoop.active_handles == 0) {
369             return;
370         }
371         if (!hChildSession->isDead) {
372             auto ctrl = daemon->BuildCtrlString(SP_START_SESSION, 0, nullptr, 0);
373             Base::SendToPollFd(hChildSession->ctrlFd[STREAM_MAIN], ctrl.data(), ctrl.size());
374             WRITE_LOG(LOG_DEBUG, "Main thread usbio migrate finish");
375         }
376         Base::TryCloseHandle(reinterpret_cast<uv_handle_t *>(handle), Base::CloseTimerCallback);
377     };
378     Base::TimerUvTask(&daemon->loopMain, hChildSession, funcNewSessionUp);
379     return hChildSession;
380 }
381 
UvWriteCallback(uv_write_t * req,int status)382 void HdcDaemonUSB::UvWriteCallback(uv_write_t *req, int status)
383 {
384     StartTraceScope("HdcDaemonUSB::UvWriteCallback");
385     if (status < 0) {
386         constexpr int bufSize = 1024;
387         char buf[bufSize] = { 0 };
388         uv_strerror_r(status, buf, bufSize);
389         WRITE_LOG(LOG_WARN, "SendCallback failed,status:%d %s", status, buf);
390     }
391     UvData *uvData = (UvData *) req->data;
392     if (uvData) {
393         uvData->daemonUsb->cirbuf.Free(uvData->buf);
394         delete uvData;
395     }
396     delete req;
397 }
398 
UsbToStream(uv_stream_t * stream,const uint8_t * buf,const int size)399 int HdcDaemonUSB::UsbToStream(uv_stream_t *stream, const uint8_t *buf, const int size)
400 {
401     StartTraceScope("HdcDaemonUSB::UsbToStream");
402     int ret = ERR_GENERIC;
403     uv_write_t *reqWrite = new uv_write_t();
404     if (!reqWrite) {
405         WRITE_LOG(LOG_WARN, "UsbToStream new write_t failed size:%d", size);
406         cirbuf.Free(buf);
407         return ERR_BUF_ALLOC;
408     }
409     uv_buf_t bfr;
410     while (true) {
411         UvData *uvData = new(std::nothrow) UvData();
412         if (uvData == nullptr) {
413             WRITE_LOG(LOG_FATAL, "UsbToStream new uvData failed size:%d", size);
414             cirbuf.Free(buf);
415             return ERR_BUF_ALLOC;
416         }
417         uvData->daemonUsb = this;
418         uvData->buf = buf;
419         reqWrite->data = reinterpret_cast<void *>(uvData);
420         bfr.base = (char *)buf;
421         bfr.len = size;
422         if (!uv_is_writable(stream)) {
423             WRITE_LOG(LOG_WARN, "UsbToStream uv_is_writable false size:%d", size);
424             delete reqWrite;
425             cirbuf.Free(buf);
426             delete uvData;
427             break;
428         }
429         ret = uv_write(reqWrite, stream, &bfr, 1, UvWriteCallback);
430         if (ret < 0) {
431             WRITE_LOG(LOG_WARN, "UsbToStream uv_write false ret:%d", ret);
432             delete reqWrite;
433             cirbuf.Free(buf);
434             delete uvData;
435             ret = ERR_IO_FAIL;
436             break;
437         }
438         ret = size;
439         break;
440     }
441     return ret;
442 }
443 
UsbToHdcProtocol(uv_stream_t * stream,uint8_t * appendData,int dataSize)444 int HdcDaemonUSB::UsbToHdcProtocol(uv_stream_t *stream, uint8_t *appendData, int dataSize)
445 {
446     StartTraceScope("HdcDaemonUSB::UsbToHdcProtocol");
447     uint8_t *data = cirbuf.Malloc();
448     if (data == nullptr) {
449         WRITE_LOG(LOG_WARN, "UsbToHdcProtocol data nullptr");
450         return -1;
451     }
452     if (memcpy_s(data, dataSize, appendData, dataSize)) {
453         WRITE_LOG(LOG_WARN, "UsbToHdcProtocol memory copy failed dataSize:%d", dataSize);
454         cirbuf.Free(data);
455         return ERR_BUF_COPY;
456     }
457     return UsbToStream(stream, data, dataSize);
458 }
459 
DispatchToWorkThread(uint32_t sessionId,uint8_t * readBuf,int readBytes)460 int HdcDaemonUSB::DispatchToWorkThread(uint32_t sessionId, uint8_t *readBuf, int readBytes)
461 {
462     HSession hChildSession = nullptr;
463     HdcDaemon *daemon = reinterpret_cast<HdcDaemon *>(clsMainBase);
464     int childRet = RET_SUCCESS;
465     StartTraceScope("HdcDaemonUSB::DispatchToWorkThread");
466     if (sessionId == 0) {
467         // hdc packet data
468         sessionId = currentSessionId;
469     }
470     if (currentSessionId != 0 && sessionId != currentSessionId) {
471         WRITE_LOG(LOG_WARN, "New session coming, restart old sessionId:%u", currentSessionId);
472         ResetOldSession(currentSessionId);
473         currentSessionId = 0;
474     }
475     hChildSession = daemon->AdminSession(OP_QUERY, sessionId, nullptr);
476     if (!hChildSession) {
477         hChildSession = PrepareNewSession(sessionId, readBuf, readBytes);
478         if (!hChildSession) {
479             WRITE_LOG(LOG_WARN, "prep new session err for sessionId:%u", sessionId);
480             return ERR_SESSION_NOFOUND;
481         }
482     }
483 
484     if (hChildSession->childCleared || hChildSession->isDead) {
485         WRITE_LOG(LOG_WARN, "session dead clr:%d - %d", hChildSession->childCleared, hChildSession->isDead);
486         return ERR_SESSION_DEAD;
487     }
488     uv_stream_t *stream = reinterpret_cast<uv_stream_t *>(&hChildSession->dataPipe[STREAM_MAIN]);
489     if ((childRet = SendToHdcStream(hChildSession, stream, readBuf, readBytes)) < 0) {
490         WRITE_LOG(LOG_WARN, "DispatchToWorkThread SendToHdcStream err ret:%d", childRet);
491         return ERR_IO_FAIL;
492     }
493     return childRet;
494 }
495 
JumpAntiquePacket(const uint8_t & buf,ssize_t bytes) const496 bool HdcDaemonUSB::JumpAntiquePacket(const uint8_t &buf, ssize_t bytes) const
497 {
498     constexpr size_t antiqueFlagSize = 4;
499     constexpr size_t antiqueFullSize = 24;
500     // anti CNXN 0x4e584e43
501     uint8_t flag[] = { 0x43, 0x4e, 0x58, 0x4e };
502     if (bytes == antiqueFullSize && !memcmp(&buf, flag, antiqueFlagSize)) {
503         return true;
504     }
505     return false;
506 }
507 
508 // Only physically swap EP ports will be reset
OnUSBRead(uv_fs_t * req)509 void HdcDaemonUSB::OnUSBRead(uv_fs_t *req)
510 {  // Only read at the main thread
511     StartTraceScope("HdcDaemonUSB::OnUSBRead");
512     auto ctxIo = reinterpret_cast<CtxUvFileCommonIo *>(req->data);
513     auto hUSB = reinterpret_cast<HUSB>(ctxIo->data);
514     auto thisClass = reinterpret_cast<HdcDaemonUSB *>(ctxIo->thisClass);
515     uint8_t *bufPtr = ctxIo->buf;
516     ssize_t bytesIOBytes = req->result;
517     uint32_t sessionId = 0;
518     bool ret = false;
519     int childRet = 0;
520     if (bytesIOBytes > hUSB->wMaxPacketSizeSend && bytesIOBytes != thisClass->saveNextReadSize) {
521         WRITE_LOG(LOG_WARN, "Not full packet, wanted:%d really:%d", thisClass->saveNextReadSize, bytesIOBytes);
522     }
523     while (thisClass->isAlive) {
524         // Don't care is module running, first deal with this
525         if (bytesIOBytes < 0) {
526             // logic alive and EINTER is gdb attach
527             //
528             // [about gdb attach known issue]
529             // When GDB debugging is loaded, the number of USB read interrupts of libuv will increase. Multiple
530             // interrupts will increase the correctness of USB data reading. Setting GDB to asynchronous mode or using
531             // log debugging can avoid this problem
532             if (bytesIOBytes != -EINTR) {  // Epoll will be broken when gdb attach
533                 constexpr int bufSize = 1024;
534                 char buf[bufSize] = { 0 };
535                 uv_strerror_r(bytesIOBytes, buf, bufSize);
536                 WRITE_LOG(LOG_WARN, "USBIO ret:%d failed:%s", bytesIOBytes, buf);
537                 ret = false;
538                 break;
539             } else {
540                 WRITE_LOG(LOG_ALL, "OnUSBRead signal EINTR");
541             }
542         } else if (bytesIOBytes == 0) {  // zero packet
543             WRITE_LOG(LOG_ALL, "Zero packet received");
544         } else {
545             if (thisClass->JumpAntiquePacket(*bufPtr, bytesIOBytes)) {
546                 WRITE_LOG(LOG_DEBUG, "JumpAntiquePacket auto jump");
547                 ret = true;
548                 break;
549             }
550             // guess is head of packet
551             if ((childRet = thisClass->AvailablePacket((uint8_t *)bufPtr, bytesIOBytes, &sessionId)) != RET_SUCCESS) {
552                 if (childRet != ERR_IO_SOFT_RESET) {
553                     WRITE_LOG(LOG_WARN, "AvailablePacket check failed, ret:%d buf:%-50s", bytesIOBytes, bufPtr);
554                     break;
555                 }
556                 // reset packet
557                 childRet = 0;  // need max size
558             } else {
559                 // AvailablePacket case
560                 if ((childRet = thisClass->DispatchToWorkThread(sessionId, bufPtr, bytesIOBytes)) < 0) {
561                     WRITE_LOG(LOG_FATAL, "DispatchToWorkThread failed");
562                     break;
563                 }
564             }
565         }
566         int nextReadSize = childRet == 0 ? hUSB->wMaxPacketSizeSend : std::min(childRet, Base::GetUsbffsBulkSize());
567         thisClass->saveNextReadSize = nextReadSize;
568         if (thisClass->LoopUSBRead(hUSB, nextReadSize) < 0) {
569             WRITE_LOG(LOG_FATAL, "LoopUSBRead failed");
570             break;
571         }
572         ret = true;
573         break;
574     }
575     if (!ret) {
576         thisClass->isAlive = false;
577         thisClass->ctxRecv.atPollQueue = false;
578     }
579 }
580 
LoopUSBRead(HUSB hUSB,int readMaxWanted)581 int HdcDaemonUSB::LoopUSBRead(HUSB hUSB, int readMaxWanted)
582 {
583     StartTraceScope("HdcDaemonUSB::LoopUSBRead");
584     int ret = ERR_GENERIC;
585     HdcDaemon *daemon = reinterpret_cast<HdcDaemon *>(clsMainBase);
586     uv_buf_t iov;
587     ctxRecv.data = hUSB;
588     ctxRecv.bufSize = readMaxWanted;
589     ctxRecv.req = {};
590     uv_fs_t *req = &ctxRecv.req;
591     req->data = &ctxRecv;
592     iov = uv_buf_init(reinterpret_cast<char *>(ctxRecv.buf), ctxRecv.bufSize);
593     ret = uv_fs_read(&daemon->loopMain, req, hUSB->bulkOut, &iov, 1, -1, OnUSBRead);
594     if (ret < 0) {
595         WRITE_LOG(LOG_FATAL, "uv_fs_read < 0");
596         return ERR_API_FAIL;
597     }
598     ctxRecv.atPollQueue = true;
599     return RET_SUCCESS;
600 }
601 
602 // Because USB can connect to only one host,daemonUSB is only one Session by default
WatchEPTimer(uv_timer_t * handle)603 void HdcDaemonUSB::WatchEPTimer(uv_timer_t *handle)
604 {
605     HdcDaemonUSB *thisClass = (HdcDaemonUSB *)handle->data;
606     HUSB hUSB = &thisClass->usbHandle;
607     HdcDaemon *daemon = reinterpret_cast<HdcDaemon *>(thisClass->clsMainBase);
608     if (thisClass->isAlive || thisClass->ctxRecv.atPollQueue) {
609         return;
610     }
611     bool resetEp = false;
612     do {
613         if (hUSB->bulkIn > 0) {
614             WRITE_LOG(LOG_DEBUG, "Watchdog close bulkin");
615             thisClass->CloseBulkEp(true, thisClass->usbHandle.bulkIn, &daemon->loopMain);
616             resetEp = true;
617         }
618         if (hUSB->bulkOut > 0) {
619             WRITE_LOG(LOG_DEBUG, "Watchdog close bulkout");
620             thisClass->CloseBulkEp(false, thisClass->usbHandle.bulkOut, &daemon->loopMain);
621             resetEp = true;
622         }
623         if (thisClass->controlEp > 0) {
624             Base::CloseFd(thisClass->controlEp);
625             resetEp = true;
626         }
627     } while (false);
628     if (resetEp || thisClass->usbHandle.bulkIn != 0 || thisClass->usbHandle.bulkOut != 0) {
629         return;
630     }
631     // until all bulkport reset
632     if (thisClass->ConnectEPPoint(hUSB) != RET_SUCCESS) {
633         return;
634     }
635     // connect OK
636     thisClass->isAlive = true;
637     thisClass->LoopUSBRead(hUSB, hUSB->wMaxPacketSizeSend);
638 }
639 }  // namespace Hdc
640