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 "daemon_tcp.h"
16 #include <cstdlib>
17 #include "arpa/inet.h"
18 #include "netinet/in.h"
19 #include "new"
20 #include "sys/socket.h"
21 #include "system_depend.h"
22 #include "unistd.h"
23 #include "common.h"
24 #include "session.h"
25
26 namespace Hdc {
HdcDaemonTCP(const bool serverOrDaemonIn,void * ptrMainBase)27 HdcDaemonTCP::HdcDaemonTCP(const bool serverOrDaemonIn, void *ptrMainBase)
28 : HdcTCPBase(serverOrDaemonIn, ptrMainBase)
29 {
30 // If the listening value for the property setting is obtained, it will be 0 randomly assigned.
31 string strTCPPort;
32 SystemDepend::GetDevItem("persist.hdc.port", strTCPPort);
33 tcpListenPort = atoi(strTCPPort.c_str());
34 if (tcpListenPort <= 0) {
35 tcpListenPort = 0;
36 }
37 #ifdef HDC_DEBUG
38 const uint16_t DEBUG_TCP_PORT = 10178;
39 tcpListenPort = DEBUG_TCP_PORT;
40 #endif
41 }
42
~HdcDaemonTCP()43 HdcDaemonTCP::~HdcDaemonTCP()
44 {
45 }
46
Stop()47 void HdcDaemonTCP::Stop()
48 {
49 Base::TryCloseHandle((const uv_handle_t *)&servUDP);
50 Base::TryCloseHandle((const uv_handle_t *)&servTCP);
51 WRITE_LOG(LOG_DEBUG, "Stop tcpListenPort:%u", tcpListenPort);
52 }
53
TransmitConfig(const sockaddr * addrSrc,uv_udp_t * handle)54 void HdcDaemonTCP::TransmitConfig(const sockaddr *addrSrc, uv_udp_t *handle)
55 {
56 char srcIP[BUF_SIZE_TINY] = "";
57 struct sockaddr addrSrcIPPort;
58 uv_udp_send_t *req = new uv_udp_send_t();
59 if (!req) {
60 return;
61 }
62 string sendBuf = Base::StringFormat("%s-%d", HANDSHAKE_MESSAGE.c_str(), tcpListenPort);
63 uv_buf_t sndbuf = uv_buf_init((char *)sendBuf.c_str(), sendBuf.size());
64 uv_ip4_name(const_cast<sockaddr_in *>(reinterpret_cast<const sockaddr_in *>(addrSrc)), srcIP, sizeof(srcIP));
65 uv_ip4_addr(srcIP, DEFAULT_PORT, const_cast<sockaddr_in *>(reinterpret_cast<const sockaddr_in *>(&addrSrcIPPort)));
66 uv_udp_send(req, handle, &sndbuf, 1, &addrSrcIPPort, SendUDPFinish);
67 }
68
AcceptClient(uv_stream_t * server,int status)69 void HdcDaemonTCP::AcceptClient(uv_stream_t *server, int status)
70 {
71 uv_loop_t *ptrLoop = server->loop;
72 uv_tcp_t *pServTCP = (uv_tcp_t *)server;
73 HdcDaemonTCP *thisClass = (HdcDaemonTCP *)pServTCP->data;
74 HdcSessionBase *ptrConnect = reinterpret_cast<HdcSessionBase *>(thisClass->clsMainBase);
75 HdcSessionBase *daemon = reinterpret_cast<HdcSessionBase *>(thisClass->clsMainBase);
76 const uint16_t maxWaitTime = UV_DEFAULT_INTERVAL;
77 auto ctrl = daemon->BuildCtrlString(SP_START_SESSION, 0, nullptr, 0);
78 HSession hSession = ptrConnect->MallocSession(false, CONN_TCP, thisClass);
79 if (!hSession) {
80 WRITE_LOG(LOG_FATAL, "malloc tcp session failed");
81 return;
82 }
83 if (uv_accept(server, (uv_stream_t *)&hSession->hWorkTCP) < 0) {
84 WRITE_LOG(LOG_FATAL, "uv_accept error sessionId:%u", hSession->sessionId);
85 goto Finish;
86 }
87 if ((hSession->fdChildWorkTCP = Base::DuplicateUvSocket(&hSession->hWorkTCP)) < 0) {
88 WRITE_LOG(LOG_FATAL, "AcceptClient error fdChildWorkTCP:%d", hSession->fdChildWorkTCP);
89 goto Finish;
90 }
91 Base::TryCloseHandle((uv_handle_t *)&hSession->hWorkTCP);
92 Base::StartWorkThread(ptrLoop, ptrConnect->SessionWorkThread, Base::FinishWorkThread, hSession);
93 // wait for thread up
94 while (hSession->childLoop.active_handles == 0) {
95 usleep(maxWaitTime);
96 }
97 Base::SendToPollFd(hSession->ctrlFd[STREAM_MAIN], ctrl.data(), ctrl.size());
98 return;
99 Finish:
100 ptrConnect->FreeSession(hSession->sessionId);
101 }
102
RecvUDPEntry(const sockaddr * addrSrc,uv_udp_t * handle,const uv_buf_t * rcvbuf)103 void HdcDaemonTCP::RecvUDPEntry(const sockaddr *addrSrc, uv_udp_t *handle, const uv_buf_t *rcvbuf)
104 {
105 TransmitConfig(addrSrc, handle);
106 }
107
SetUDPListen()108 void HdcDaemonTCP::SetUDPListen()
109 {
110 struct sockaddr_in addr;
111 HdcSessionBase *ptrConnect = (HdcSessionBase *)clsMainBase;
112 // udp broadcast
113 servUDP.data = this;
114 uv_udp_init(&ptrConnect->loopMain, &servUDP);
115 uv_ip4_addr("0.0.0.0", DEFAULT_PORT, &addr);
116 uv_udp_bind(&servUDP, (const struct sockaddr *)&addr, UV_UDP_REUSEADDR);
117 uv_udp_recv_start(&servUDP, AllocStreamUDP, RecvUDP);
118 }
119
120 // Set the daemon-side TCP listening
SetTCPListen()121 int HdcDaemonTCP::SetTCPListen()
122 {
123 // tcp listen
124 HdcSessionBase *ptrConnect = (HdcSessionBase *)clsMainBase;
125 servTCP.data = this;
126 struct sockaddr_in addr = {};
127 int namelen;
128 const int DEFAULT_BACKLOG = 128;
129
130 uv_tcp_init(&ptrConnect->loopMain, &servTCP);
131 uv_ip4_addr("0.0.0.0", tcpListenPort, &addr); // tcpListenPort == 0
132 uv_tcp_bind(&servTCP, (const struct sockaddr *)&addr, 0);
133 if (uv_listen((uv_stream_t *)&servTCP, DEFAULT_BACKLOG, (uv_connection_cb)AcceptClient)) {
134 return ERR_API_FAIL;
135 }
136 // Get listen port
137 Base::ZeroStruct(addr);
138 namelen = sizeof(addr);
139 if (uv_tcp_getsockname(&servTCP, (sockaddr *)&addr, &namelen)) {
140 return ERR_API_FAIL;
141 }
142 tcpListenPort = ntohs(addr.sin_port);
143 SystemDepend::SetDevItem("persist.hdc.port", std::to_string(tcpListenPort).c_str());
144 return RET_SUCCESS;
145 }
146
Initial()147 int HdcDaemonTCP::Initial()
148 {
149 WRITE_LOG(LOG_DEBUG, "HdcDaemonTCP init");
150 SetUDPListen();
151 if (SetTCPListen() != RET_SUCCESS) {
152 WRITE_LOG(LOG_FATAL, "TCP listen failed");
153 return ERR_GENERIC;
154 }
155 #ifndef UNIT_TEST
156 WRITE_LOG(LOG_INFO, "TCP listen on port:[%d]", tcpListenPort);
157 #endif
158 return RET_SUCCESS;
159 }
160 } // namespace Hdc
161