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