• 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 "usb.h"
16 
17 namespace Hdc {
HdcUSBBase(const bool serverOrDaemonIn,void * ptrMainBase)18 HdcUSBBase::HdcUSBBase(const bool serverOrDaemonIn, void *ptrMainBase)
19 {
20     serverOrDaemon = serverOrDaemonIn;
21     clsMainBase = ptrMainBase;
22     modRunning = true;
23 }
24 
~HdcUSBBase()25 HdcUSBBase::~HdcUSBBase()
26 {
27 }
28 
ReadUSB(uv_stream_t * stream,ssize_t nread,const uv_buf_t * buf)29 void HdcUSBBase::ReadUSB(uv_stream_t *stream, ssize_t nread, const uv_buf_t *buf)
30 {
31     StartTraceScope("HdcUSBBase::ReadUSB");
32     HSession hSession = (HSession)stream->data;
33     HdcSessionBase *hSessionBase = (HdcSessionBase *)hSession->classInstance;
34     CALLSTAT_GUARD(hSession->childLoopStatus, stream->loop, "HdcUSBBase::ReadUSB");
35     if (hSessionBase->FetchIOBuf(hSession, hSession->ioBuf, nread) < 0) {
36         WRITE_LOG(LOG_FATAL, "ReadUSB FetchIOBuf error sessionId:%u", hSession->sessionId);
37         hSessionBase->FreeSession(hSession->sessionId);
38     }
39 }
40 
ReadyForWorkThread(HSession hSession)41 bool HdcUSBBase::ReadyForWorkThread(HSession hSession)
42 {
43     // Server-end USB IO is handed over to each sub-thread, only the daemon is still read by the main IO to distribute
44     // to each sub-thread by DataPipe.
45     uv_tcp_t *stream = &hSession->dataPipe[STREAM_WORK];
46     if (uv_tcp_init(&hSession->childLoop, stream) ||
47         uv_tcp_open(stream, hSession->dataFd[STREAM_WORK])) {
48         WRITE_LOG(LOG_FATAL, "USBBase ReadyForWorkThread init child TCP failed, sid:%u", hSession->sessionId);
49         return false;
50     }
51     stream->data = hSession;
52     HdcSessionBase *pSession = (HdcSessionBase *)hSession->classInstance;
53 #ifdef HDC_HOST
54     Base::SetTcpOptions(stream, HOST_SOCKETPAIR_SIZE);
55 #else
56     Base::SetTcpOptions(stream);
57 #endif
58     if (uv_read_start((uv_stream_t *)stream, pSession->AllocCallback, ReadUSB)) {
59         WRITE_LOG(LOG_FATAL, "USBBase ReadyForWorkThread child TCP read failed, sid:%u", hSession->sessionId);
60         return false;
61     }
62     WRITE_LOG(LOG_INFO, "USBBase ReadyForWorkThread finish dataFd[STREAM_WORK]:%d, sid:%u",
63         hSession->dataFd[STREAM_WORK], hSession->sessionId);
64     return true;
65 };
66 
BuildPacketHeader(uint32_t sessionId,uint8_t option,uint32_t dataSize)67 vector<uint8_t> HdcUSBBase::BuildPacketHeader(uint32_t sessionId, uint8_t option, uint32_t dataSize)
68 {
69     vector<uint8_t> vecData;
70     USBHead head;
71     head.sessionId = htonl(sessionId);
72     for (size_t i = 0; i < sizeof(head.flag); i++) {
73         head.flag[i] = USB_PACKET_FLAG.data()[i];
74     }
75     head.option = option;
76     head.dataSize = htonl(dataSize);
77     vecData.insert(vecData.end(), (uint8_t *)&head, (uint8_t *)&head + sizeof(USBHead));
78     return vecData;
79 }
80 
81 // USB big data stream, block transmission, mainly to prevent accidental data packets from writing through EP port,
82 // inserting the send queue causes the program to crash
SendUSBBlock(HSession hSession,uint8_t * data,const int length)83 int HdcUSBBase::SendUSBBlock(HSession hSession, uint8_t *data, const int length)
84 {
85     int childRet = 0;
86     int ret = ERR_IO_FAIL;
87     StartTraceScope("HdcUSBBase::SendUSBBlock");
88     std::lock_guard<std::mutex> lock(hSession->hUSB->lockSendUsbBlock);
89     auto header = BuildPacketHeader(hSession->sessionId, USB_OPTION_HEADER, length);
90     do {
91         if ((SendUSBRaw(hSession, header.data(), header.size())) <= 0) {
92             WRITE_LOG(LOG_FATAL, "SendUSBRaw index failed");
93             break;
94         }
95         if ((childRet = SendUSBRaw(hSession, data, length)) <= 0) {
96             WRITE_LOG(LOG_FATAL, "SendUSBRaw body failed");
97             break;
98         }
99         if (childRet > 0 && (childRet % hSession->hUSB->wMaxPacketSizeSend == 0)) {
100             // win32 send ZLP will block winusb driver and LIBUSB_TRANSFER_ADD_ZERO_PACKET not effect
101             // so, we send dummy packet to prevent zero packet generate
102             auto dummy = BuildPacketHeader(hSession->sessionId, 0, 0);
103             if ((SendUSBRaw(hSession, dummy.data(), dummy.size())) <= 0) {
104                 WRITE_LOG(LOG_FATAL, "SendUSBRaw dummy failed");
105                 break;
106             }
107         }
108         ret = length;
109     } while (false);
110     return ret;
111 }
112 
IsUsbPacketHeader(uint8_t * ioBuf,int ioBytes)113 bool HdcUSBBase::IsUsbPacketHeader(uint8_t *ioBuf, int ioBytes)
114 {
115     StartTraceScope("HdcUSBBase::IsUsbPacketHeader");
116     USBHead *usbPayloadHeader = reinterpret_cast<struct USBHead *>(ioBuf);
117     uint32_t maybeSize = ntohl(usbPayloadHeader->dataSize);
118     bool isHeader = false;
119     do {
120         if (memcmp(usbPayloadHeader->flag, USB_PACKET_FLAG.c_str(), USB_PACKET_FLAG.size())) {
121             break;
122         }
123         if (ioBytes != sizeof(USBHead)) {
124             break;
125         }
126         if (maybeSize == 0) {
127             isHeader = true;  // nop packet
128             break;
129         } else {  // maybeSize != 0
130             if (usbPayloadHeader->option & USB_OPTION_HEADER) {
131                 isHeader = true;
132                 break;
133             }
134         }
135     } while (false);
136     return isHeader;
137 }
138 
PreSendUsbSoftReset(HSession hSession,uint32_t sessionIdOld)139 void HdcUSBBase::PreSendUsbSoftReset(HSession hSession, uint32_t sessionIdOld)
140 {
141     StartTraceScope("HdcUSBBase::PreSendUsbSoftReset");
142     HUSB hUSB = hSession->hUSB;
143     if (hSession->serverOrDaemon && !hUSB->resetIO) {
144         hUSB->lockSendUsbBlock.lock();
145         WRITE_LOG(LOG_WARN, "SendToHdcStream check, sessionId not matched");
146         auto header = BuildPacketHeader(sessionIdOld, USB_OPTION_RESET, 0);
147         if (SendUSBRaw(hSession, header.data(), header.size()) <= 0) {
148             WRITE_LOG(LOG_FATAL, "PreSendUsbSoftReset send failed");
149         }
150         hUSB->lockSendUsbBlock.unlock();
151         hUSB->resetIO = true;
152     }
153 }
154 
CheckPacketOption(HSession hSession,uint8_t * appendData,int dataSize)155 int HdcUSBBase::CheckPacketOption(HSession hSession, uint8_t *appendData, int dataSize)
156 {
157     HUSB hUSB = hSession->hUSB;
158     // special short packet
159     USBHead *header = reinterpret_cast<USBHead *>(appendData);
160     header->sessionId = ntohl(header->sessionId);
161     header->dataSize = ntohl(header->dataSize);
162     if (header->sessionId != hSession->sessionId) {
163         // Only server do it here, daemon 'SendUsbSoftReset' no use
164         // hilog + ctrl^C to reproduction scene
165         //
166         // Because the USB-reset API does not work on all platforms, the last session IO data may be
167         // recveived, we need to ignore it.
168         WRITE_LOG(LOG_WARN, "CheckPacketOption softreset header->sessionId:%u sessionId:%u",
169             header->sessionId, hSession->sessionId);
170         PreSendUsbSoftReset(hSession, header->sessionId);
171         return 0;
172     }
173     if (header->option & USB_OPTION_HEADER) {
174         // header packet
175         hUSB->payloadSize = header->dataSize;
176     }
177     // soft ZLP
178     return hUSB->payloadSize;
179 }
180 
181 // return value: <0 error; = 0 all finish; >0 need size
SendToHdcStream(HSession hSession,uv_stream_t * stream,uint8_t * appendData,int dataSize)182 int HdcUSBBase::SendToHdcStream(HSession hSession, uv_stream_t *stream, uint8_t *appendData, int dataSize)
183 {
184     StartTraceScope("HdcUSBBase::SendToHdcStream");
185     int childRet = 0;
186     HUSB hUSB = hSession->hUSB;
187     if (IsUsbPacketHeader(appendData, dataSize)) {
188         return CheckPacketOption(hSession, appendData, dataSize);
189     }
190     if (hUSB->payloadSize <= static_cast<uint32_t>(childRet)) {
191         // last session data
192         WRITE_LOG(LOG_WARN, "SendToHdcStream softreset dataSize:%d payloadSize:%u childRet:%d",
193             dataSize, hUSB->payloadSize, childRet);
194         PreSendUsbSoftReset(hSession, 0);  // 0 == reset current
195         return 0;
196     }
197     if ((childRet = UsbToHdcProtocol(stream, appendData, dataSize)) < 0) {
198         WRITE_LOG(LOG_FATAL, "Error usb send to stream dataSize:%d", dataSize);
199         return ERR_IO_FAIL;
200     }
201     hUSB->payloadSize -= childRet;
202     return hUSB->payloadSize;
203 }
204 
205 }
206