xref: /developtools/hdc/src/host/host_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 "host_tcp.h"
16#include "server.h"
17
18namespace Hdc {
19HdcHostTCP::HdcHostTCP(const bool serverOrDaemonIn, void *ptrMainBase)
20    : HdcTCPBase(serverOrDaemonIn, ptrMainBase)
21{
22    broadcastFindWorking = false;
23}
24
25HdcHostTCP::~HdcHostTCP()
26{
27    WRITE_LOG(LOG_DEBUG, "~HdcHostTCP");
28}
29
30void HdcHostTCP::Stop()
31{
32}
33
34void HdcHostTCP::RecvUDPEntry(const sockaddr *addrSrc, uv_udp_t *handle, const uv_buf_t *rcvbuf)
35{
36    char bufString[BUF_SIZE_TINY];
37    int port = 0;
38    char *p = strstr(rcvbuf->base, "-");
39    if (!p) {
40        return;
41    }
42    port = atoi(p + 1);
43    if (!port) {
44        return;
45    }
46    uv_ip6_name((sockaddr_in6 *)addrSrc, bufString, sizeof(bufString));
47    string addrPort = string(bufString);
48    addrPort += string(":") + std::to_string(port);
49    lstDaemonResult.push_back(addrPort);
50}
51
52void HdcHostTCP::BroadcastTimer(uv_idle_t *handle)
53{
54    uv_stop(handle->loop);
55}
56
57// Executive Administration Network Broadcast Discovery, broadcastLanIP==which interface to broadcast
58void HdcHostTCP::BroadcastFindDaemon(const char *broadcastLanIP)
59{
60    if (broadcastFindWorking) {
61        return;
62    }
63    broadcastFindWorking = true;
64    lstDaemonResult.clear();
65
66    uv_loop_t loopBroadcast;
67    uv_loop_init(&loopBroadcast);
68    struct sockaddr_in6 addr;
69    uv_udp_send_t req;
70    uv_udp_t client;
71    // send
72    uv_ip6_addr(broadcastLanIP, 0, &addr);
73    uv_udp_init(&loopBroadcast, &client);
74    uv_udp_bind(&client, (const struct sockaddr *)&addr, 0);
75    uv_udp_set_broadcast(&client, 1);
76    uv_ip6_addr("FFFF:FFFF:FFFF", DEFAULT_PORT, &addr);
77    uv_buf_t buf = uv_buf_init((char *)HANDSHAKE_MESSAGE.c_str(), HANDSHAKE_MESSAGE.size());
78    uv_udp_send(&req, &client, &buf, 1, (const struct sockaddr *)&addr, nullptr);
79    // recv
80    uv_udp_t server;
81    server.data = this;
82    uv_ip6_addr(broadcastLanIP, DEFAULT_PORT, &addr);
83    uv_udp_init(&loopBroadcast, &server);
84    uv_udp_bind(&server, (const struct sockaddr *)&addr, UV_UDP_REUSEADDR);
85    uv_udp_recv_start(&server, AllocStreamUDP, RecvUDP);
86    // find timeout
87    uv_timer_t tLastCheck;
88    uv_timer_init(&loopBroadcast, &tLastCheck);
89    uv_timer_start(&tLastCheck, (uv_timer_cb)BroadcastTimer, TIME_BASE, 0);  // timeout debug 1s
90
91    uv_run(&loopBroadcast, UV_RUN_DEFAULT);
92    uv_loop_close(&loopBroadcast);
93    broadcastFindWorking = false;
94}
95
96void HdcHostTCP::Connect(uv_connect_t *connection, int status)
97{
98    HSession hSession = (HSession)connection->data;
99    delete connection;
100    HdcSessionBase *ptrConnect = (HdcSessionBase *)hSession->classInstance;
101    auto ctrl = ptrConnect->BuildCtrlString(SP_START_SESSION, 0, nullptr, 0);
102    if (status < 0) {
103        WRITE_LOG(LOG_FATAL, "Connect status:%d", status);
104        goto Finish;
105    }
106    if ((hSession->fdChildWorkTCP = Base::DuplicateUvSocket(&hSession->hWorkTCP)) < 0) {
107        WRITE_LOG(LOG_FATAL, "Connect fdChildWorkTCP:%d", hSession->fdChildWorkTCP);
108        goto Finish;
109    }
110    uv_read_stop((uv_stream_t *)&hSession->hWorkTCP);
111    Base::SetTcpOptions((uv_tcp_t *)&hSession->hWorkTCP);
112    WRITE_LOG(LOG_DEBUG, "HdcHostTCP::Connect");
113    Base::StartWorkThread(&ptrConnect->loopMain, ptrConnect->SessionWorkThread, Base::FinishWorkThread, hSession);
114    // wait for thread up
115    while (hSession->childLoop.active_handles == 0) {
116        uv_sleep(MINOR_TIMEOUT);
117    }
118    Base::SendToPollFd(hSession->ctrlFd[STREAM_MAIN], ctrl.data(), ctrl.size());
119    return;
120Finish:
121    WRITE_LOG(LOG_FATAL, "Connect failed sessionId:%u", hSession->sessionId);
122    hSession->childCleared = true;
123    ptrConnect->FreeSession(hSession->sessionId);
124}
125
126HSession HdcHostTCP::ConnectDaemon(const string &connectKey, bool isCheck)
127{
128    char ip[BUF_SIZE_TINY] = "";
129    uint16_t port = 0;
130    if (Base::ConnectKey2IPPort(connectKey.c_str(), ip, &port, sizeof(ip)) < 0) {
131        WRITE_LOG(LOG_FATAL, "ConnectKey2IPPort error connectKey:%s", Hdc::MaskString(connectKey).c_str());
132        return nullptr;
133    }
134
135    HdcSessionBase *ptrConnect = (HdcSessionBase *)clsMainBase;
136    HSession hSession = ptrConnect->MallocSession(true, CONN_TCP, this);
137    if (!hSession) {
138        WRITE_LOG(LOG_FATAL, "hSession nullptr connectKey:%s", Hdc::MaskString(connectKey).c_str());
139        return nullptr;
140    }
141    hSession->isCheck = isCheck;
142    hSession->connectKey = connectKey;
143    struct sockaddr_in dest;
144    uv_ip4_addr(ip, port, &dest);
145    uv_connect_t *conn = new(std::nothrow) uv_connect_t();
146    if (conn == nullptr) {
147        WRITE_LOG(LOG_FATAL, "ConnectDaemon new conn failed");
148        delete hSession;
149        hSession = nullptr;
150        return nullptr;
151    }
152    conn->data = hSession;
153    uv_tcp_connect(conn, (uv_tcp_t *)&hSession->hWorkTCP, (const struct sockaddr *)&dest, Connect);
154    return hSession;
155}
156
157void HdcHostTCP::FindLanDaemon()
158{
159    uv_interface_address_t *info;
160    int count;
161    int i;
162    char ipAddr[BUF_SIZE_TINY] = "";
163    if (broadcastFindWorking) {
164        return;
165    }
166    lstDaemonResult.clear();
167    uv_interface_addresses(&info, &count);
168    i = count;
169    while (--i) {
170        uv_interface_address_t interface = info[i];
171        if (interface.address.address6.sin6_family == AF_INET6) {
172            continue;
173        }
174        uv_ip6_name(&interface.address.address6, ipAddr, sizeof(ipAddr));
175        BroadcastFindDaemon(ipAddr);
176    }
177    uv_free_interface_addresses(info, count);
178}
179}  // namespace Hdc
180