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 17namespace Hdc { 18HdcUSBBase::HdcUSBBase(const bool serverOrDaemonIn, void *ptrMainBase) 19{ 20 serverOrDaemon = serverOrDaemonIn; 21 clsMainBase = ptrMainBase; 22 modRunning = true; 23} 24 25HdcUSBBase::~HdcUSBBase() 26{ 27} 28 29void 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 40bool 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 65vector<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 81int 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 111bool 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 137void 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 153int 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 180int 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