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
17 namespace Hdc {
HdcTCPBase(const bool serverOrDaemonIn,void * ptrMainBase)18 HdcTCPBase::HdcTCPBase(const bool serverOrDaemonIn, void *ptrMainBase)
19 {
20 // Calling the initialization
21 InitialChildClass(serverOrDaemonIn, ptrMainBase);
22 }
23
~HdcTCPBase()24 HdcTCPBase::~HdcTCPBase()
25 {
26 }
27
28 // Subclasses must be explicitly called
InitialChildClass(const bool serverOrDaemonIn,void * ptrMainBase)29 void HdcTCPBase::InitialChildClass(const bool serverOrDaemonIn, void *ptrMainBase)
30 {
31 serverOrDaemon = serverOrDaemonIn;
32 clsMainBase = ptrMainBase;
33 }
34
RecvUDP(uv_udp_t * handle,ssize_t nread,const uv_buf_t * rcvbuf,const struct sockaddr * addr,unsigned flags)35 void 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 CALLSTAT_GUARD(((HdcSessionBase *)(thisClass->clsMainBase))->loopMainStatus,
45 handle->loop, "HdcTCPBase::RecvUDP");
46 WRITE_LOG(LOG_DEBUG, "RecvUDP %s", rcvbuf->base);
47 if (strncmp(rcvbuf->base, HANDSHAKE_MESSAGE.c_str(), HANDSHAKE_MESSAGE.size())) {
48 break;
49 }
50 thisClass->RecvUDPEntry(addr, handle, rcvbuf);
51 break;
52 }
53 delete[] rcvbuf->base;
54 }
55
AllocStreamUDP(uv_handle_t * handle,size_t sizeWanted,uv_buf_t * buf)56 void HdcTCPBase::AllocStreamUDP(uv_handle_t *handle, size_t sizeWanted, uv_buf_t *buf)
57 {
58 int bufLen = BUF_SIZE_DEFAULT;
59 char *pRecvBuf = reinterpret_cast<char *>(new uint8_t[bufLen]());
60 if (!pRecvBuf) {
61 return;
62 }
63 buf->base = pRecvBuf;
64 buf->len = bufLen;
65 }
66
SendUDPFinish(uv_udp_send_t * req,int status)67 void HdcTCPBase::SendUDPFinish(uv_udp_send_t *req, int status)
68 {
69 delete req;
70 }
71
ReadStream(uv_stream_t * tcp,ssize_t nread,const uv_buf_t * buf)72 void HdcTCPBase::ReadStream(uv_stream_t *tcp, ssize_t nread, const uv_buf_t *buf)
73 {
74 HSession hSession = (HSession)tcp->data;
75 HdcTCPBase *thisClass = (HdcTCPBase *)hSession->classModule;
76 HdcSessionBase *hSessionBase = (HdcSessionBase *)thisClass->clsMainBase;
77 CALLSTAT_GUARD(hSession->childLoopStatus, tcp->loop, "HdcTCPBase::ReadStream");
78 bool ret = false;
79 while (true) {
80 if (nread < 0) {
81 break;
82 }
83 #ifdef HDC_SUPPORT_ENCRYPT_TCP
84 if (hSessionBase->FetchIOBuf(hSession, hSession->ioBuf, nread, hSession->sslHandshake) < 0) {
85 WRITE_LOG(LOG_FATAL, "ReadStream FetchIOBuf error nread:%zd, sid:%u", nread, hSession->sessionId);
86 break;
87 }
88 #else
89 if (hSessionBase->FetchIOBuf(hSession, hSession->ioBuf, nread) < 0) {
90 WRITE_LOG(LOG_FATAL, "ReadStream FetchIOBuf error nread:%zd, sid:%u", nread, hSession->sessionId);
91 break;
92 }
93 #endif
94 ret = true;
95 break;
96 }
97 if (!ret) {
98 char buffer[BUF_SIZE_DEFAULT] = { 0 };
99 if (nread < 0) {
100 uv_strerror_r(static_cast<int>(nread), buffer, BUF_SIZE_DEFAULT);
101 WRITE_LOG(LOG_INFO, "HdcTCPBase::ReadStream < 0 %s sid:%u", buffer, hSession->sessionId);
102 }
103 #ifdef HDC_HOST
104 hSession->isRunningOk = false;
105 hSession->faultInfo = (nread < 0) ? buffer : "package parse error";
106 #endif
107 // The first time is closed first, prevent the write function from continuing to write
108 Base::TryCloseHandle(reinterpret_cast<uv_handle_t *>(tcp));
109 hSessionBase->FreeSession(hSession->sessionId);
110 }
111 }
112
WriteUvSslFd(uv_tcp_t * tcp,uint8_t * buf,int size,int & cnt)113 bool HdcTCPBase::WriteUvSslFd(uv_tcp_t *tcp, uint8_t *buf, int size, int &cnt)
114 {
115 if (!tcp || !buf || size < 0 ||cnt < 0) {
116 WRITE_LOG(LOG_FATAL, "WriteUvSslFd error, input parameter abnormal.");
117 return false;
118 }
119 #ifdef HDC_SUPPORT_ENCRYPT_TCP
120 HSession hSession = reinterpret_cast<HSession>(tcp->data);
121 if (!hSession) {
122 WRITE_LOG(LOG_FATAL, "WriteUvSslFd error, hSession is null.");
123 return false;
124 }
125
126 if (!hSession->sslHandshake) { // plaintext tcp transfer.
127 return true;
128 }
129
130 HdcSSLBase *hssl = static_cast<HdcSSLBase *>(hSession->classSSL);
131 if (!hssl) {
132 WRITE_LOG(LOG_FATAL, "WriteUvSslFd error, hssl is null.");
133 return false;
134 }
135
136 cnt = hssl->Encrypt(size, buf);
137 if (cnt < 0) {
138 WRITE_LOG(LOG_FATAL, "WriteSSL error, cnt:%d", cnt);
139 return false;
140 }
141 #endif
142 return true;
143 }
144
WriteUvTcpFd(uv_tcp_t * tcp,uint8_t * buf,int size)145 int HdcTCPBase::WriteUvTcpFd(uv_tcp_t *tcp, uint8_t *buf, int size)
146 {
147 std::lock_guard<std::mutex> lock(writeTCPMutex);
148 uint8_t *data = buf;
149 int cnt = size;
150 if (!WriteUvSslFd(tcp, buf, size, cnt)) {
151 delete[] buf;
152 return ERR_GENERIC;
153 }
154 uv_os_fd_t uvfd;
155 uv_fileno(reinterpret_cast<uv_handle_t*>(tcp), &uvfd);
156 #ifdef _WIN32
157 int fd = (uv_os_sock_t)uvfd;
158 #else
159 int fd = reinterpret_cast<int>(uvfd);
160 #endif
161 constexpr int intrmax = 60000;
162 int intrcnt = 0;
163 while (cnt > 0) {
164 #ifdef HDC_EMULATOR
165 int rc = write(fd, reinterpret_cast<const char*>(data), cnt);
166 #else
167 int rc = send(fd, reinterpret_cast<const char*>(data), cnt, 0);
168 #endif
169 if (rc < 0) {
170 #ifdef _WIN32
171 int err = WSAGetLastError();
172 if (err == WSAEINTR || err == WSAEWOULDBLOCK) {
173 #else
174 int err = errno;
175 if (err == EINTR || err == EAGAIN) {
176 #endif
177 if (++intrcnt > intrmax) {
178 WRITE_LOG(LOG_WARN, "WriteUvTcpFd fd:%d send interrupt err:%d", fd, err);
179 intrcnt = 0;
180 }
181 std::this_thread::yield();
182 continue;
183 } else {
184 WRITE_LOG(LOG_FATAL, "WriteUvTcpFd fd:%d send rc:%d err:%d", fd, rc, err);
185 cnt = ERR_GENERIC;
186 break;
187 }
188 }
189 data += rc;
190 cnt -= rc;
191 }
192 delete[] buf;
193 return cnt == 0 ? size : cnt;
194 }
195 } // namespace Hdc
196