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