• 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 ((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