1 /*
2  * Copyright (c) 2024 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 "tooling/client/tcpServer/tcp_server.h"
16 
17 #include "tooling/utils/utils.h"
18 
19 namespace OHOS::ArkCompiler::Toolchain {
20 uv_async_t* g_inputSignal;
21 uv_async_t* g_releaseHandle;
22 std::string g_inputStr = "";
23 std::vector<std::string> g_allCmds = { "allocationtrack", "at", "allocationtrack-stop", "at-stop", "heapdump", "hd",
24     "heapprofiler-enable", "hp-enable", "heapprofiler-disable", "hp-disable", "sampling", "sampling", "sampling-stop",
25     "sampling-stop", "collectgarbage", "gc", "cpuprofile", "cp", "cpuprofile-stop", "cp-stop", "cpuprofile-enable",
26     "cp-enable", "cpuprofile-disable", "cp-disable", "cpuprofile-show", "cp-show", "cpuprofile-setSamplingInterval",
27     "cp-ssi", "runtime-enable", "rt-enable", "heapusage", "hu", "break", "b", "backtrack", "bt", "continue", "c",
28     "delete", "d", "disable", "disable", "display", "display", "enable", "enable", "finish", "fin", "frame", "f",
29     "help", "h", "ignore", "ig", "infobreakpoints", "infob", "infosource", "infos", "jump", "j", "list", "l", "next",
30     "n", "print", "p", "ptype", "ptype", "run", "r", "setvar", "sv", "step", "s", "undisplay", "undisplay", "watch",
31     "wa", "resume", "resume", "showstack", "ss", "step-into", "si", "step-out", "so", "step-over", "sov",
32     "runtime-disable", "rt-disable" };
33 std::vector<std::string> g_noRecvCmds = { "cpuprofile-enable", "cp-enable", "cpuprofile-disable", "cp-disable",
34     "cpuprofile-stop", "cp-stop" };
35 std::vector<std::string> g_inputOnMessages = { "b", "break", "bt", "backtrack", "d", "delete", "display", "fin",
36     "finish", "f", "frame", "h", "help", "ig", "ignore", "infob", "infobreakpoints", "infos", "infosource", "j", "jump",
37     "l", "list", "n", "next", "ptype", "s", "step", "ss", "showstack", "watch", "wa" };
38 
CreateServer(void* arg)39 void CreateServer(void* arg)
40 {
41     TcpServer::getInstance().StartTcpServer(arg);
42 }
43 
CloseServer()44 void TcpServer::CloseServer()
45 {
46     if (uv_is_active(reinterpret_cast<uv_handle_t*>(g_releaseHandle))) {
47         uv_async_send(g_releaseHandle);
48     }
49 }
50 
ServerConnect()51 void TcpServer::ServerConnect()
52 {
53     isServerActive = 1;
54     struct sockaddr_in saddr;
55     saddr.sin_family = AF_INET;
56     saddr.sin_addr.s_addr = INADDR_ANY;
57     saddr.sin_port = htons(9999); // 9999: tcp bind port
58 
59     lfd = socket(AF_INET, SOCK_STREAM, 0);
60     if (lfd == -1) {
61         std::cout << "socket failed" << std::endl;
62         CloseServer();
63         return;
64     }
65 
66     int ret = bind(lfd, (struct sockaddr*)&saddr, sizeof(saddr));
67     if (ret == -1) {
68         std::cout << "bind failed" << std::endl;
69         CloseServer();
70         return;
71     }
72 
73     ret = listen(lfd, 6); // 6: Number of backlogs
74     if (ret == -1) {
75         std::cout << "listen failed" << std::endl;
76         CloseServer();
77         return;
78     }
79 
80     struct sockaddr_in clientaddr;
81     socklen_t len = sizeof(clientaddr);
82     cfd = accept(lfd, (struct sockaddr*)&clientaddr, &len);
83     if (cfd == -1) {
84         std::cout << "accept failed" << std::endl;
85         CloseServer();
86         return;
87     }
88 }
89 
SendCommand(std::string inputStr)90 void TcpServer::SendCommand(std::string inputStr)
91 {
92     inputStr.erase(0, inputStr.find_first_not_of(" "));
93     if (inputStr.empty()) {
94         std::cout << "cmd is empty" << std::endl;
95         return;
96     }
97 
98     if (uv_is_active(reinterpret_cast<uv_handle_t*>(g_inputSignal))) {
99         uint32_t len = inputStr.length();
100         if (len < 0) {
101             CloseServer();
102             return;
103         }
104         char* msg = (char*)malloc(len + 1);
105         if (msg == nullptr) {
106             return;
107         }
108         if (strncpy_s(msg, len + 1, inputStr.c_str(), len) != 0) {
109             free(msg);
110             CloseServer();
111             return;
112         }
113         g_inputSignal->data = std::move(msg);
114         uv_async_send(g_inputSignal);
115     }
116     return;
117 }
118 
StartTcpServer([[maybe_unused]] void* arg)119 void TcpServer::StartTcpServer([[maybe_unused]] void* arg)
120 {
121     ServerConnect();
122 
123     const char* data = "connect success";
124     write(cfd, data, strlen(data));
125     int num = 0;
126     do {
127         char recvBuf[1024] = { 0 };
128         num = read(cfd, recvBuf, sizeof(recvBuf));
129         if (num < 0) {
130             std::cout << "read failed" << std::endl;
131         } else if (num > 0) {
132             g_inputStr = std::string(recvBuf);
133             SendCommand(recvBuf);
134             TcpServerWrite();
135         } else if (num == 0) {
136             std::cout << "clinet closed" << std::endl;
137         }
138     } while (num > 0);
139 
140     close(cfd);
141     close(lfd);
142 
143     CloseServer();
144     return;
145 }
146 
TcpServerWrite(std::string msg)147 void TcpServer::TcpServerWrite(std::string msg)
148 {
149     if (g_inputStr.empty()) {
150         return;
151     }
152 
153     std::vector<std::string> cliCmdStr = Utils::SplitString(g_inputStr, " ");
154     if (!FindCommand(g_allCmds, cliCmdStr[0])) {
155         g_inputStr = "error cmd";
156         write(cfd, g_inputStr.c_str(), strlen(g_inputStr.c_str()));
157         g_inputStr.clear();
158         return;
159     }
160     if (msg == "inner") {
161         if (FindCommand(g_noRecvCmds, cliCmdStr[0])) {
162             write(cfd, g_inputStr.c_str(), strlen(g_inputStr.c_str()));
163             g_inputStr.clear();
164         }
165     } else if (msg == "InputOnMessage") {
166         if (FindCommand(g_inputOnMessages, cliCmdStr[0])) {
167             write(cfd, g_inputStr.c_str(), strlen(g_inputStr.c_str()));
168             g_inputStr.clear();
169         }
170     } else if (msg == "SocketOnMessage") {
171         if (FindCommand(g_inputOnMessages, cliCmdStr[0])) {
172             return;
173         }
174         if (g_inputStr.empty()) {
175             return;
176         }
177         write(cfd, g_inputStr.c_str(), strlen(g_inputStr.c_str()));
178         g_inputStr.clear();
179     }
180     return;
181 }
182 
CreateTcpServer([[maybe_unused]] void* arg)183 int TcpServer::CreateTcpServer([[maybe_unused]] void* arg)
184 {
185     uv_thread_create(&serverTid_, CreateServer, nullptr);
186     return 0;
187 }
188 
FindCommand(std::vector<std::string> cmds, std::string cmd)189 bool TcpServer::FindCommand(std::vector<std::string> cmds, std::string cmd)
190 {
191     return find(cmds.begin(), cmds.end(), cmd) != cmds.end();
192 }
193 } // namespace OHOS::ArkCompiler::Toolchain