1cc290419Sopenharmony_ci/*
2cc290419Sopenharmony_ci * Copyright (C) 2021 Huawei Device Co., Ltd.
3cc290419Sopenharmony_ci * Licensed under the Apache License, Version 2.0 (the "License");
4cc290419Sopenharmony_ci * you may not use this file except in compliance with the License.
5cc290419Sopenharmony_ci * You may obtain a copy of the License at
6cc290419Sopenharmony_ci *
7cc290419Sopenharmony_ci *     http://www.apache.org/licenses/LICENSE-2.0
8cc290419Sopenharmony_ci *
9cc290419Sopenharmony_ci * Unless required by applicable law or agreed to in writing, software
10cc290419Sopenharmony_ci * distributed under the License is distributed on an "AS IS" BASIS,
11cc290419Sopenharmony_ci * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12cc290419Sopenharmony_ci * See the License for the specific language governing permissions and
13cc290419Sopenharmony_ci * limitations under the License.
14cc290419Sopenharmony_ci */
15cc290419Sopenharmony_ci#include "usb.h"
16cc290419Sopenharmony_ci
17cc290419Sopenharmony_cinamespace Hdc {
18cc290419Sopenharmony_ciHdcUSBBase::HdcUSBBase(const bool serverOrDaemonIn, void *ptrMainBase)
19cc290419Sopenharmony_ci{
20cc290419Sopenharmony_ci    serverOrDaemon = serverOrDaemonIn;
21cc290419Sopenharmony_ci    clsMainBase = ptrMainBase;
22cc290419Sopenharmony_ci    modRunning = true;
23cc290419Sopenharmony_ci}
24cc290419Sopenharmony_ci
25cc290419Sopenharmony_ciHdcUSBBase::~HdcUSBBase()
26cc290419Sopenharmony_ci{
27cc290419Sopenharmony_ci}
28cc290419Sopenharmony_ci
29cc290419Sopenharmony_civoid HdcUSBBase::ReadUSB(uv_stream_t *stream, ssize_t nread, const uv_buf_t *buf)
30cc290419Sopenharmony_ci{
31cc290419Sopenharmony_ci    StartTraceScope("HdcUSBBase::ReadUSB");
32cc290419Sopenharmony_ci    HSession hSession = (HSession)stream->data;
33cc290419Sopenharmony_ci    HdcSessionBase *hSessionBase = (HdcSessionBase *)hSession->classInstance;
34cc290419Sopenharmony_ci    if (hSessionBase->FetchIOBuf(hSession, hSession->ioBuf, nread) < 0) {
35cc290419Sopenharmony_ci        WRITE_LOG(LOG_FATAL, "ReadUSB FetchIOBuf error sessionId:%u", hSession->sessionId);
36cc290419Sopenharmony_ci        hSessionBase->FreeSession(hSession->sessionId);
37cc290419Sopenharmony_ci    }
38cc290419Sopenharmony_ci}
39cc290419Sopenharmony_ci
40cc290419Sopenharmony_cibool HdcUSBBase::ReadyForWorkThread(HSession hSession)
41cc290419Sopenharmony_ci{
42cc290419Sopenharmony_ci    // Server-end USB IO is handed over to each sub-thread, only the daemon is still read by the main IO to distribute
43cc290419Sopenharmony_ci    // to each sub-thread by DataPipe.
44cc290419Sopenharmony_ci    if (uv_tcp_init(&hSession->childLoop, &hSession->dataPipe[STREAM_WORK]) ||
45cc290419Sopenharmony_ci        uv_tcp_open(&hSession->dataPipe[STREAM_WORK], hSession->dataFd[STREAM_WORK])) {
46cc290419Sopenharmony_ci        WRITE_LOG(LOG_FATAL, "USBBase ReadyForWorkThread init child TCP failed");
47cc290419Sopenharmony_ci        return false;
48cc290419Sopenharmony_ci    }
49cc290419Sopenharmony_ci    hSession->dataPipe[STREAM_WORK].data = hSession;
50cc290419Sopenharmony_ci    HdcSessionBase *pSession = (HdcSessionBase *)hSession->classInstance;
51cc290419Sopenharmony_ci#ifdef HDC_HOST
52cc290419Sopenharmony_ci    Base::SetTcpOptions(&hSession->dataPipe[STREAM_WORK], HOST_SOCKETPAIR_SIZE);
53cc290419Sopenharmony_ci#else
54cc290419Sopenharmony_ci    Base::SetTcpOptions(&hSession->dataPipe[STREAM_WORK]);
55cc290419Sopenharmony_ci#endif
56cc290419Sopenharmony_ci    if (uv_read_start((uv_stream_t *)&hSession->dataPipe[STREAM_WORK], pSession->AllocCallback, ReadUSB)) {
57cc290419Sopenharmony_ci        WRITE_LOG(LOG_FATAL, "USBBase ReadyForWorkThread child TCP read failed");
58cc290419Sopenharmony_ci        return false;
59cc290419Sopenharmony_ci    }
60cc290419Sopenharmony_ci    WRITE_LOG(LOG_DEBUG, "USBBase ReadyForWorkThread finish dataFd[STREAM_WORK]:%d",
61cc290419Sopenharmony_ci        hSession->dataFd[STREAM_WORK]);
62cc290419Sopenharmony_ci    return true;
63cc290419Sopenharmony_ci};
64cc290419Sopenharmony_ci
65cc290419Sopenharmony_civector<uint8_t> HdcUSBBase::BuildPacketHeader(uint32_t sessionId, uint8_t option, uint32_t dataSize)
66cc290419Sopenharmony_ci{
67cc290419Sopenharmony_ci    vector<uint8_t> vecData;
68cc290419Sopenharmony_ci    USBHead head;
69cc290419Sopenharmony_ci    head.sessionId = htonl(sessionId);
70cc290419Sopenharmony_ci    for (size_t i = 0; i < sizeof(head.flag); i++) {
71cc290419Sopenharmony_ci        head.flag[i] = USB_PACKET_FLAG.data()[i];
72cc290419Sopenharmony_ci    }
73cc290419Sopenharmony_ci    head.option = option;
74cc290419Sopenharmony_ci    head.dataSize = htonl(dataSize);
75cc290419Sopenharmony_ci    vecData.insert(vecData.end(), (uint8_t *)&head, (uint8_t *)&head + sizeof(USBHead));
76cc290419Sopenharmony_ci    return vecData;
77cc290419Sopenharmony_ci}
78cc290419Sopenharmony_ci
79cc290419Sopenharmony_ci// USB big data stream, block transmission, mainly to prevent accidental data packets from writing through EP port,
80cc290419Sopenharmony_ci// inserting the send queue causes the program to crash
81cc290419Sopenharmony_ciint HdcUSBBase::SendUSBBlock(HSession hSession, uint8_t *data, const int length)
82cc290419Sopenharmony_ci{
83cc290419Sopenharmony_ci    int childRet = 0;
84cc290419Sopenharmony_ci    int ret = ERR_IO_FAIL;
85cc290419Sopenharmony_ci    StartTraceScope("HdcUSBBase::SendUSBBlock");
86cc290419Sopenharmony_ci    std::lock_guard<std::mutex> lock(hSession->hUSB->lockSendUsbBlock);
87cc290419Sopenharmony_ci    auto header = BuildPacketHeader(hSession->sessionId, USB_OPTION_HEADER, length);
88cc290419Sopenharmony_ci    do {
89cc290419Sopenharmony_ci        if ((SendUSBRaw(hSession, header.data(), header.size())) <= 0) {
90cc290419Sopenharmony_ci            WRITE_LOG(LOG_FATAL, "SendUSBRaw index failed");
91cc290419Sopenharmony_ci            break;
92cc290419Sopenharmony_ci        }
93cc290419Sopenharmony_ci        if ((childRet = SendUSBRaw(hSession, data, length)) <= 0) {
94cc290419Sopenharmony_ci            WRITE_LOG(LOG_FATAL, "SendUSBRaw body failed");
95cc290419Sopenharmony_ci            break;
96cc290419Sopenharmony_ci        }
97cc290419Sopenharmony_ci        if (childRet > 0 && (childRet % hSession->hUSB->wMaxPacketSizeSend == 0)) {
98cc290419Sopenharmony_ci            // win32 send ZLP will block winusb driver and LIBUSB_TRANSFER_ADD_ZERO_PACKET not effect
99cc290419Sopenharmony_ci            // so, we send dummy packet to prevent zero packet generate
100cc290419Sopenharmony_ci            auto dummy = BuildPacketHeader(hSession->sessionId, 0, 0);
101cc290419Sopenharmony_ci            if ((SendUSBRaw(hSession, dummy.data(), dummy.size())) <= 0) {
102cc290419Sopenharmony_ci                WRITE_LOG(LOG_FATAL, "SendUSBRaw dummy failed");
103cc290419Sopenharmony_ci                break;
104cc290419Sopenharmony_ci            }
105cc290419Sopenharmony_ci        }
106cc290419Sopenharmony_ci        ret = length;
107cc290419Sopenharmony_ci    } while (false);
108cc290419Sopenharmony_ci    return ret;
109cc290419Sopenharmony_ci}
110cc290419Sopenharmony_ci
111cc290419Sopenharmony_cibool HdcUSBBase::IsUsbPacketHeader(uint8_t *ioBuf, int ioBytes)
112cc290419Sopenharmony_ci{
113cc290419Sopenharmony_ci    StartTraceScope("HdcUSBBase::IsUsbPacketHeader");
114cc290419Sopenharmony_ci    USBHead *usbPayloadHeader = reinterpret_cast<struct USBHead *>(ioBuf);
115cc290419Sopenharmony_ci    uint32_t maybeSize = ntohl(usbPayloadHeader->dataSize);
116cc290419Sopenharmony_ci    bool isHeader = false;
117cc290419Sopenharmony_ci    do {
118cc290419Sopenharmony_ci        if (memcmp(usbPayloadHeader->flag, USB_PACKET_FLAG.c_str(), USB_PACKET_FLAG.size())) {
119cc290419Sopenharmony_ci            break;
120cc290419Sopenharmony_ci        }
121cc290419Sopenharmony_ci        if (ioBytes != sizeof(USBHead)) {
122cc290419Sopenharmony_ci            break;
123cc290419Sopenharmony_ci        }
124cc290419Sopenharmony_ci        if (maybeSize == 0) {
125cc290419Sopenharmony_ci            isHeader = true;  // nop packet
126cc290419Sopenharmony_ci            break;
127cc290419Sopenharmony_ci        } else {  // maybeSize != 0
128cc290419Sopenharmony_ci            if (usbPayloadHeader->option & USB_OPTION_HEADER) {
129cc290419Sopenharmony_ci                isHeader = true;
130cc290419Sopenharmony_ci                break;
131cc290419Sopenharmony_ci            }
132cc290419Sopenharmony_ci        }
133cc290419Sopenharmony_ci    } while (false);
134cc290419Sopenharmony_ci    return isHeader;
135cc290419Sopenharmony_ci}
136cc290419Sopenharmony_ci
137cc290419Sopenharmony_civoid HdcUSBBase::PreSendUsbSoftReset(HSession hSession, uint32_t sessionIdOld)
138cc290419Sopenharmony_ci{
139cc290419Sopenharmony_ci    StartTraceScope("HdcUSBBase::PreSendUsbSoftReset");
140cc290419Sopenharmony_ci    HUSB hUSB = hSession->hUSB;
141cc290419Sopenharmony_ci    if (hSession->serverOrDaemon && !hUSB->resetIO) {
142cc290419Sopenharmony_ci        hUSB->lockSendUsbBlock.lock();
143cc290419Sopenharmony_ci        WRITE_LOG(LOG_WARN, "SendToHdcStream check, sessionId not matched");
144cc290419Sopenharmony_ci        auto header = BuildPacketHeader(sessionIdOld, USB_OPTION_RESET, 0);
145cc290419Sopenharmony_ci        if (SendUSBRaw(hSession, header.data(), header.size()) <= 0) {
146cc290419Sopenharmony_ci            WRITE_LOG(LOG_FATAL, "PreSendUsbSoftReset send failed");
147cc290419Sopenharmony_ci        }
148cc290419Sopenharmony_ci        hUSB->lockSendUsbBlock.unlock();
149cc290419Sopenharmony_ci        hUSB->resetIO = true;
150cc290419Sopenharmony_ci    }
151cc290419Sopenharmony_ci}
152cc290419Sopenharmony_ci
153cc290419Sopenharmony_ciint HdcUSBBase::CheckPacketOption(HSession hSession, uint8_t *appendData, int dataSize)
154cc290419Sopenharmony_ci{
155cc290419Sopenharmony_ci    HUSB hUSB = hSession->hUSB;
156cc290419Sopenharmony_ci    // special short packet
157cc290419Sopenharmony_ci    USBHead *header = reinterpret_cast<USBHead *>(appendData);
158cc290419Sopenharmony_ci    header->sessionId = ntohl(header->sessionId);
159cc290419Sopenharmony_ci    header->dataSize = ntohl(header->dataSize);
160cc290419Sopenharmony_ci    if (header->sessionId != hSession->sessionId) {
161cc290419Sopenharmony_ci        // Only server do it here, daemon 'SendUsbSoftReset' no use
162cc290419Sopenharmony_ci        // hilog + ctrl^C to reproduction scene
163cc290419Sopenharmony_ci        //
164cc290419Sopenharmony_ci        // Because the USB-reset API does not work on all platforms, the last session IO data may be
165cc290419Sopenharmony_ci        // recveived, we need to ignore it.
166cc290419Sopenharmony_ci        WRITE_LOG(LOG_WARN, "CheckPacketOption softreset header->sessionId:%u sessionId:%u",
167cc290419Sopenharmony_ci            header->sessionId, hSession->sessionId);
168cc290419Sopenharmony_ci        PreSendUsbSoftReset(hSession, header->sessionId);
169cc290419Sopenharmony_ci        return 0;
170cc290419Sopenharmony_ci    }
171cc290419Sopenharmony_ci    if (header->option & USB_OPTION_HEADER) {
172cc290419Sopenharmony_ci        // header packet
173cc290419Sopenharmony_ci        hUSB->payloadSize = header->dataSize;
174cc290419Sopenharmony_ci    }
175cc290419Sopenharmony_ci    // soft ZLP
176cc290419Sopenharmony_ci    return hUSB->payloadSize;
177cc290419Sopenharmony_ci}
178cc290419Sopenharmony_ci
179cc290419Sopenharmony_ci// return value: <0 error; = 0 all finish; >0 need size
180cc290419Sopenharmony_ciint HdcUSBBase::SendToHdcStream(HSession hSession, uv_stream_t *stream, uint8_t *appendData, int dataSize)
181cc290419Sopenharmony_ci{
182cc290419Sopenharmony_ci    StartTraceScope("HdcUSBBase::SendToHdcStream");
183cc290419Sopenharmony_ci    int childRet = 0;
184cc290419Sopenharmony_ci    HUSB hUSB = hSession->hUSB;
185cc290419Sopenharmony_ci    if (IsUsbPacketHeader(appendData, dataSize)) {
186cc290419Sopenharmony_ci        return CheckPacketOption(hSession, appendData, dataSize);
187cc290419Sopenharmony_ci    }
188cc290419Sopenharmony_ci    if (hUSB->payloadSize <= static_cast<uint32_t>(childRet)) {
189cc290419Sopenharmony_ci        // last session data
190cc290419Sopenharmony_ci        WRITE_LOG(LOG_WARN, "SendToHdcStream softreset dataSize:%d payloadSize:%u childRet:%d",
191cc290419Sopenharmony_ci            dataSize, hUSB->payloadSize, childRet);
192cc290419Sopenharmony_ci        PreSendUsbSoftReset(hSession, 0);  // 0 == reset current
193cc290419Sopenharmony_ci        return 0;
194cc290419Sopenharmony_ci    }
195cc290419Sopenharmony_ci    if ((childRet = UsbToHdcProtocol(stream, appendData, dataSize)) < 0) {
196cc290419Sopenharmony_ci        WRITE_LOG(LOG_FATAL, "Error usb send to stream dataSize:%d", dataSize);
197cc290419Sopenharmony_ci        return ERR_IO_FAIL;
198cc290419Sopenharmony_ci    }
199cc290419Sopenharmony_ci    hUSB->payloadSize -= childRet;
200cc290419Sopenharmony_ci    return hUSB->payloadSize;
201cc290419Sopenharmony_ci}
202cc290419Sopenharmony_ci
203cc290419Sopenharmony_ci}
204