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 ((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 ((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 = reinterpret_cast<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 if (hSession->serverOrDaemon && !hUSB->resetIO) { 133 hUSB->lockSendUsbBlock.lock(); 134 WRITE_LOG(LOG_WARN, "SendToHdcStream check, sessionId not matched"); 135 auto header = BuildPacketHeader(sessionIdOld, USB_OPTION_RESET, 0); 136 if (SendUSBRaw(hSession, header.data(), header.size()) <= 0) { 137 WRITE_LOG(LOG_FATAL, "PreSendUsbSoftReset send failed"); 138 } 139 hUSB->lockSendUsbBlock.unlock(); 140 hUSB->resetIO = true; 141 } 142 } 143 CheckPacketOption(HSession hSession,uint8_t * appendData,int dataSize)144 int HdcUSBBase::CheckPacketOption(HSession hSession, uint8_t *appendData, int dataSize) 145 { 146 HUSB hUSB = hSession->hUSB; 147 // special short packet 148 USBHead *header = reinterpret_cast<USBHead *>(appendData); 149 header->sessionId = ntohl(header->sessionId); 150 header->dataSize = ntohl(header->dataSize); 151 if (header->sessionId != hSession->sessionId) { 152 // Only server do it here, daemon 'SendUsbSoftReset' no use 153 // hilog + ctrl^C to reproduction scene 154 // 155 // Because the USB-reset API does not work on all platforms, the last session IO data may be 156 // recveived, we need to ignore it. 157 PreSendUsbSoftReset(hSession, header->sessionId); 158 return 0; 159 } 160 if (header->option & USB_OPTION_HEADER) { 161 // header packet 162 hUSB->payloadSize = header->dataSize; 163 } 164 // soft ZLP 165 return hUSB->payloadSize; 166 } 167 168 // return value: <0 error; = 0 all finish; >0 need size SendToHdcStream(HSession hSession,uv_stream_t * stream,uint8_t * appendData,int dataSize)169 int HdcUSBBase::SendToHdcStream(HSession hSession, uv_stream_t *stream, uint8_t *appendData, int dataSize) 170 { 171 int childRet = 0; 172 HUSB hUSB = hSession->hUSB; 173 if (IsUsbPacketHeader(appendData, dataSize)) { 174 return CheckPacketOption(hSession, appendData, dataSize); 175 } 176 if (hUSB->payloadSize <= static_cast<uint32_t>(childRet)) { 177 // last session data 178 PreSendUsbSoftReset(hSession, 0); // 0 == reset current 179 return 0; 180 } 181 if ((childRet = UsbToHdcProtocol(stream, appendData, dataSize)) < 0) { 182 WRITE_LOG(LOG_FATAL, "Error usb send to stream dataSize:%d", dataSize); 183 return ERR_IO_FAIL; 184 } 185 hUSB->payloadSize -= childRet; 186 return hUSB->payloadSize; 187 } 188 189 } 190