xref: /developtools/hdc/src/common/tcp.cpp (revision cc290419)
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 "tcp.h"
16
17namespace Hdc {
18HdcTCPBase::HdcTCPBase(const bool serverOrDaemonIn, void *ptrMainBase)
19{
20    // Calling the initialization
21    InitialChildClass(serverOrDaemonIn, ptrMainBase);
22}
23
24HdcTCPBase::~HdcTCPBase()
25{
26}
27
28// Subclasses must be explicitly called
29void HdcTCPBase::InitialChildClass(const bool serverOrDaemonIn, void *ptrMainBase)
30{
31    serverOrDaemon = serverOrDaemonIn;
32    clsMainBase = ptrMainBase;
33}
34
35void HdcTCPBase::RecvUDP(uv_udp_t *handle, ssize_t nread, const uv_buf_t *rcvbuf, const struct sockaddr *addr,
36                         unsigned flags)
37{
38    while (true) {
39        HdcTCPBase *thisClass = (HdcTCPBase *)handle->data;
40        if (nread <= 0) {
41            // ==0 finish;<0 error
42            break;
43        }
44        WRITE_LOG(LOG_DEBUG, "RecvUDP %s", rcvbuf->base);
45        if (strncmp(rcvbuf->base, HANDSHAKE_MESSAGE.c_str(), HANDSHAKE_MESSAGE.size())) {
46            break;
47        }
48        thisClass->RecvUDPEntry(addr, handle, rcvbuf);
49        break;
50    }
51    delete[] rcvbuf->base;
52}
53
54void HdcTCPBase::AllocStreamUDP(uv_handle_t *handle, size_t sizeWanted, uv_buf_t *buf)
55{
56    int bufLen = BUF_SIZE_DEFAULT;
57    char *pRecvBuf = reinterpret_cast<char *>(new uint8_t[bufLen]());
58    if (!pRecvBuf) {
59        return;
60    }
61    buf->base = pRecvBuf;
62    buf->len = bufLen;
63}
64
65void HdcTCPBase::SendUDPFinish(uv_udp_send_t *req, int status)
66{
67    delete req;
68}
69
70void HdcTCPBase::ReadStream(uv_stream_t *tcp, ssize_t nread, const uv_buf_t *buf)
71{
72    HSession hSession = (HSession)tcp->data;
73    HdcTCPBase *thisClass = (HdcTCPBase *)hSession->classModule;
74    HdcSessionBase *hSessionBase = (HdcSessionBase *)thisClass->clsMainBase;
75    bool ret = false;
76    while (true) {
77        if (nread == UV_ENOBUFS) {
78            WRITE_LOG(LOG_DEBUG, "Session IOBuf max");
79            break;
80        } else if (nread < 0) {
81            // I originally in the IO main thread, no need to send asynchronous messages, close the socket as soon as
82            // possible
83            constexpr int bufSize = 1024;
84            char buffer[bufSize] = { 0 };
85            uv_strerror_r(static_cast<int>(nread), buffer, bufSize);
86            WRITE_LOG(LOG_DEBUG, "HdcTCPBase::ReadStream < 0 %s", buffer);
87            break;
88        }
89        if (hSessionBase->FetchIOBuf(hSession, hSession->ioBuf, nread) < 0) {
90            WRITE_LOG(LOG_FATAL, "ReadStream FetchIOBuf error nread:%zd", nread);
91            break;
92        }
93        ret = true;
94        break;
95    }
96    if (!ret) {
97        // The first time is closed first, prevent the write function from continuing to write
98        Base::TryCloseHandle(reinterpret_cast<uv_handle_t *>(tcp));
99        hSessionBase->FreeSession(hSession->sessionId);
100    }
101}
102
103int HdcTCPBase::WriteUvTcpFd(uv_tcp_t *tcp, uint8_t *buf, int size)
104{
105    std::lock_guard<std::mutex> lock(writeTCPMutex);
106    uint8_t *data = buf;
107    int cnt = size;
108    uv_os_fd_t uvfd;
109    uv_fileno(reinterpret_cast<uv_handle_t*>(tcp), &uvfd);
110#ifdef _WIN32
111    int fd = (uv_os_sock_t)uvfd;
112#else
113    int fd = reinterpret_cast<int>(uvfd);
114#endif
115    constexpr int intrmax = 60000;
116    int intrcnt = 0;
117    while (cnt > 0) {
118#ifdef HDC_EMULATOR
119        int rc = write(fd, reinterpret_cast<const char*>(data), cnt);
120#else
121        int rc = send(fd, reinterpret_cast<const char*>(data), cnt, 0);
122#endif
123        if (rc < 0) {
124#ifdef _WIN32
125            int err = WSAGetLastError();
126            if (err == WSAEINTR || err == WSAEWOULDBLOCK) {
127#else
128            int err = errno;
129            if (err == EINTR || err == EAGAIN) {
130#endif
131                if (++intrcnt > intrmax) {
132                    WRITE_LOG(LOG_WARN, "WriteUvTcpFd fd:%d send interrupt err:%d", fd, err);
133                    intrcnt = 0;
134                }
135                std::this_thread::yield();
136                continue;
137            } else {
138                WRITE_LOG(LOG_FATAL, "WriteUvTcpFd fd:%d send rc:%d err:%d", fd, rc, err);
139                cnt = ERR_GENERIC;
140                break;
141            }
142        }
143        data += rc;
144        cnt -= rc;
145    }
146    delete[] buf;
147    return cnt == 0 ? size : cnt;
148}
149}  // namespace Hdc
150