xref: /aosp_15_r20/external/perfetto/src/websocket_bridge/websocket_bridge.cc (revision 6dbdd20afdafa5e3ca9b8809fa73465d530080dc)
1*6dbdd20aSAndroid Build Coastguard Worker /*
2*6dbdd20aSAndroid Build Coastguard Worker  * Copyright (C) 2021 The Android Open Source Project
3*6dbdd20aSAndroid Build Coastguard Worker  *
4*6dbdd20aSAndroid Build Coastguard Worker  * Licensed under the Apache License, Version 2.0 (the "License");
5*6dbdd20aSAndroid Build Coastguard Worker  * you may not use this file except in compliance with the License.
6*6dbdd20aSAndroid Build Coastguard Worker  * You may obtain a copy of the License at
7*6dbdd20aSAndroid Build Coastguard Worker  *
8*6dbdd20aSAndroid Build Coastguard Worker  *      http://www.apache.org/licenses/LICENSE-2.0
9*6dbdd20aSAndroid Build Coastguard Worker  *
10*6dbdd20aSAndroid Build Coastguard Worker  * Unless required by applicable law or agreed to in writing, software
11*6dbdd20aSAndroid Build Coastguard Worker  * distributed under the License is distributed on an "AS IS" BASIS,
12*6dbdd20aSAndroid Build Coastguard Worker  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13*6dbdd20aSAndroid Build Coastguard Worker  * See the License for the specific language governing permissions and
14*6dbdd20aSAndroid Build Coastguard Worker  * limitations under the License.
15*6dbdd20aSAndroid Build Coastguard Worker  */
16*6dbdd20aSAndroid Build Coastguard Worker 
17*6dbdd20aSAndroid Build Coastguard Worker #include "src/websocket_bridge/websocket_bridge.h"
18*6dbdd20aSAndroid Build Coastguard Worker 
19*6dbdd20aSAndroid Build Coastguard Worker #include <stdint.h>
20*6dbdd20aSAndroid Build Coastguard Worker 
21*6dbdd20aSAndroid Build Coastguard Worker #include <cstdlib>
22*6dbdd20aSAndroid Build Coastguard Worker #include <map>
23*6dbdd20aSAndroid Build Coastguard Worker #include <memory>
24*6dbdd20aSAndroid Build Coastguard Worker #include <vector>
25*6dbdd20aSAndroid Build Coastguard Worker 
26*6dbdd20aSAndroid Build Coastguard Worker #include "perfetto/ext/base/http/http_server.h"
27*6dbdd20aSAndroid Build Coastguard Worker #include "perfetto/ext/base/string_utils.h"
28*6dbdd20aSAndroid Build Coastguard Worker #include "perfetto/ext/base/unix_socket.h"
29*6dbdd20aSAndroid Build Coastguard Worker #include "perfetto/ext/base/unix_task_runner.h"
30*6dbdd20aSAndroid Build Coastguard Worker #include "perfetto/tracing/default_socket.h"
31*6dbdd20aSAndroid Build Coastguard Worker 
32*6dbdd20aSAndroid Build Coastguard Worker namespace perfetto {
33*6dbdd20aSAndroid Build Coastguard Worker namespace {
34*6dbdd20aSAndroid Build Coastguard Worker 
35*6dbdd20aSAndroid Build Coastguard Worker constexpr int kWebsocketPort = 8037;
36*6dbdd20aSAndroid Build Coastguard Worker 
37*6dbdd20aSAndroid Build Coastguard Worker struct Endpoint {
38*6dbdd20aSAndroid Build Coastguard Worker   const char* uri;
39*6dbdd20aSAndroid Build Coastguard Worker   const char* endpoint;
40*6dbdd20aSAndroid Build Coastguard Worker   base::SockFamily family;
41*6dbdd20aSAndroid Build Coastguard Worker };
42*6dbdd20aSAndroid Build Coastguard Worker 
43*6dbdd20aSAndroid Build Coastguard Worker class WSBridge : public base::HttpRequestHandler,
44*6dbdd20aSAndroid Build Coastguard Worker                  public base::UnixSocket::EventListener {
45*6dbdd20aSAndroid Build Coastguard Worker  public:
46*6dbdd20aSAndroid Build Coastguard Worker   void Main(int argc, char** argv);
47*6dbdd20aSAndroid Build Coastguard Worker 
48*6dbdd20aSAndroid Build Coastguard Worker   // base::HttpRequestHandler implementation.
49*6dbdd20aSAndroid Build Coastguard Worker   void OnHttpRequest(const base::HttpRequest&) override;
50*6dbdd20aSAndroid Build Coastguard Worker   void OnWebsocketMessage(const base::WebsocketMessage&) override;
51*6dbdd20aSAndroid Build Coastguard Worker   void OnHttpConnectionClosed(base::HttpServerConnection*) override;
52*6dbdd20aSAndroid Build Coastguard Worker 
53*6dbdd20aSAndroid Build Coastguard Worker   // base::UnixSocket::EventListener implementation.
54*6dbdd20aSAndroid Build Coastguard Worker   void OnNewIncomingConnection(base::UnixSocket*,
55*6dbdd20aSAndroid Build Coastguard Worker                                std::unique_ptr<base::UnixSocket>) override;
56*6dbdd20aSAndroid Build Coastguard Worker   void OnConnect(base::UnixSocket*, bool) override;
57*6dbdd20aSAndroid Build Coastguard Worker   void OnDisconnect(base::UnixSocket*) override;
58*6dbdd20aSAndroid Build Coastguard Worker   void OnDataAvailable(base::UnixSocket* self) override;
59*6dbdd20aSAndroid Build Coastguard Worker 
60*6dbdd20aSAndroid Build Coastguard Worker  private:
61*6dbdd20aSAndroid Build Coastguard Worker   base::HttpServerConnection* GetWebsocket(base::UnixSocket*);
62*6dbdd20aSAndroid Build Coastguard Worker 
63*6dbdd20aSAndroid Build Coastguard Worker   base::UnixTaskRunner task_runner_;
64*6dbdd20aSAndroid Build Coastguard Worker   std::vector<Endpoint> endpoints_;
65*6dbdd20aSAndroid Build Coastguard Worker   std::map<base::HttpServerConnection*, std::unique_ptr<base::UnixSocket>>
66*6dbdd20aSAndroid Build Coastguard Worker       conns_;
67*6dbdd20aSAndroid Build Coastguard Worker };
68*6dbdd20aSAndroid Build Coastguard Worker 
Main(int,char **)69*6dbdd20aSAndroid Build Coastguard Worker void WSBridge::Main(int, char**) {
70*6dbdd20aSAndroid Build Coastguard Worker #if PERFETTO_BUILDFLAG(PERFETTO_OS_WIN)
71*6dbdd20aSAndroid Build Coastguard Worker   // On Windows traced used a TCP socket.
72*6dbdd20aSAndroid Build Coastguard Worker   const auto kTracedFamily = base::SockFamily::kInet;
73*6dbdd20aSAndroid Build Coastguard Worker #else
74*6dbdd20aSAndroid Build Coastguard Worker   const auto kTracedFamily = base::SockFamily::kUnix;
75*6dbdd20aSAndroid Build Coastguard Worker #endif
76*6dbdd20aSAndroid Build Coastguard Worker   // The ADB_SERVER_SOCKET environment variable is sourced from
77*6dbdd20aSAndroid Build Coastguard Worker   // the commandline.cpp file in the ADB module of the Android platform.
78*6dbdd20aSAndroid Build Coastguard Worker   // Examples: tcp:localhost:5037 or tcp:10.52.8.53:5037.
79*6dbdd20aSAndroid Build Coastguard Worker   std::string adb_socket_endpoint;
80*6dbdd20aSAndroid Build Coastguard Worker   if (const char* adb_ss = getenv("ADB_SERVER_SOCKET"); adb_ss) {
81*6dbdd20aSAndroid Build Coastguard Worker     base::StringView adb_ss_sv(adb_ss);
82*6dbdd20aSAndroid Build Coastguard Worker     adb_socket_endpoint = base::StripPrefix(adb_ss, "tcp:");
83*6dbdd20aSAndroid Build Coastguard Worker 
84*6dbdd20aSAndroid Build Coastguard Worker     // Ensure that ADB_SERVER_SOCKET actually starts with tcp:
85*6dbdd20aSAndroid Build Coastguard Worker     PERFETTO_CHECK(adb_socket_endpoint.size() != adb_ss_sv.size());
86*6dbdd20aSAndroid Build Coastguard Worker   } else {
87*6dbdd20aSAndroid Build Coastguard Worker     adb_socket_endpoint = "127.0.0.1:5037";
88*6dbdd20aSAndroid Build Coastguard Worker   }
89*6dbdd20aSAndroid Build Coastguard Worker   PERFETTO_LOG("[WSBridge] adb server socket is:%s.",
90*6dbdd20aSAndroid Build Coastguard Worker                adb_socket_endpoint.c_str());
91*6dbdd20aSAndroid Build Coastguard Worker   endpoints_.push_back({"/traced", GetConsumerSocket(), kTracedFamily});
92*6dbdd20aSAndroid Build Coastguard Worker   endpoints_.push_back(
93*6dbdd20aSAndroid Build Coastguard Worker       {"/adb", adb_socket_endpoint.c_str(), base::SockFamily::kInet});
94*6dbdd20aSAndroid Build Coastguard Worker 
95*6dbdd20aSAndroid Build Coastguard Worker   base::HttpServer srv(&task_runner_, this);
96*6dbdd20aSAndroid Build Coastguard Worker   srv.AddAllowedOrigin("http://localhost:10000");
97*6dbdd20aSAndroid Build Coastguard Worker   srv.AddAllowedOrigin("http://127.0.0.1:10000");
98*6dbdd20aSAndroid Build Coastguard Worker   srv.AddAllowedOrigin("https://ui.perfetto.dev");
99*6dbdd20aSAndroid Build Coastguard Worker 
100*6dbdd20aSAndroid Build Coastguard Worker   srv.Start(kWebsocketPort);
101*6dbdd20aSAndroid Build Coastguard Worker   PERFETTO_LOG("[WSBridge] Listening on 127.0.0.1:%d", kWebsocketPort);
102*6dbdd20aSAndroid Build Coastguard Worker   task_runner_.Run();
103*6dbdd20aSAndroid Build Coastguard Worker }
104*6dbdd20aSAndroid Build Coastguard Worker 
OnHttpRequest(const base::HttpRequest & req)105*6dbdd20aSAndroid Build Coastguard Worker void WSBridge::OnHttpRequest(const base::HttpRequest& req) {
106*6dbdd20aSAndroid Build Coastguard Worker   for (const auto& ep : endpoints_) {
107*6dbdd20aSAndroid Build Coastguard Worker     if (req.uri != ep.uri || !req.is_websocket_handshake)
108*6dbdd20aSAndroid Build Coastguard Worker       continue;
109*6dbdd20aSAndroid Build Coastguard Worker 
110*6dbdd20aSAndroid Build Coastguard Worker     // Connect to the endpoint in blocking mode.
111*6dbdd20aSAndroid Build Coastguard Worker     auto sock_raw =
112*6dbdd20aSAndroid Build Coastguard Worker         base::UnixSocketRaw::CreateMayFail(ep.family, base::SockType::kStream);
113*6dbdd20aSAndroid Build Coastguard Worker     if (!sock_raw) {
114*6dbdd20aSAndroid Build Coastguard Worker       PERFETTO_PLOG("socket() failed");
115*6dbdd20aSAndroid Build Coastguard Worker       req.conn->SendResponseAndClose("500 Server Error");
116*6dbdd20aSAndroid Build Coastguard Worker       return;
117*6dbdd20aSAndroid Build Coastguard Worker     }
118*6dbdd20aSAndroid Build Coastguard Worker     PERFETTO_LOG("[WSBridge] New connection from \"%.*s\"",
119*6dbdd20aSAndroid Build Coastguard Worker                  static_cast<int>(req.origin.size()), req.origin.data());
120*6dbdd20aSAndroid Build Coastguard Worker     sock_raw.SetTxTimeout(3000);
121*6dbdd20aSAndroid Build Coastguard Worker     sock_raw.SetBlocking(true);
122*6dbdd20aSAndroid Build Coastguard Worker 
123*6dbdd20aSAndroid Build Coastguard Worker     if (!sock_raw.Connect(ep.endpoint)) {
124*6dbdd20aSAndroid Build Coastguard Worker       PERFETTO_ELOG("[WSBridge] Connection to %s failed", ep.endpoint);
125*6dbdd20aSAndroid Build Coastguard Worker       req.conn->SendResponseAndClose("503 Service Unavailable");
126*6dbdd20aSAndroid Build Coastguard Worker       return;
127*6dbdd20aSAndroid Build Coastguard Worker     }
128*6dbdd20aSAndroid Build Coastguard Worker     sock_raw.SetBlocking(false);
129*6dbdd20aSAndroid Build Coastguard Worker 
130*6dbdd20aSAndroid Build Coastguard Worker     PERFETTO_DLOG("[WSBridge] Connected to %s", ep.endpoint);
131*6dbdd20aSAndroid Build Coastguard Worker     conns_[req.conn] = base::UnixSocket::AdoptConnected(
132*6dbdd20aSAndroid Build Coastguard Worker         sock_raw.ReleaseFd(), this, &task_runner_, ep.family,
133*6dbdd20aSAndroid Build Coastguard Worker         base::SockType::kStream);
134*6dbdd20aSAndroid Build Coastguard Worker 
135*6dbdd20aSAndroid Build Coastguard Worker     req.conn->UpgradeToWebsocket(req);
136*6dbdd20aSAndroid Build Coastguard Worker     return;
137*6dbdd20aSAndroid Build Coastguard Worker   }  // for (endpoint)
138*6dbdd20aSAndroid Build Coastguard Worker   req.conn->SendResponseAndClose("404 Not Found");
139*6dbdd20aSAndroid Build Coastguard Worker }
140*6dbdd20aSAndroid Build Coastguard Worker 
141*6dbdd20aSAndroid Build Coastguard Worker // Called when an inbound websocket message is received from the browser.
OnWebsocketMessage(const base::WebsocketMessage & msg)142*6dbdd20aSAndroid Build Coastguard Worker void WSBridge::OnWebsocketMessage(const base::WebsocketMessage& msg) {
143*6dbdd20aSAndroid Build Coastguard Worker   auto it = conns_.find(msg.conn);
144*6dbdd20aSAndroid Build Coastguard Worker   PERFETTO_CHECK(it != conns_.end());
145*6dbdd20aSAndroid Build Coastguard Worker   // Pass through the websocket message onto the endpoint TCP socket.
146*6dbdd20aSAndroid Build Coastguard Worker   base::UnixSocket& sock = *it->second;
147*6dbdd20aSAndroid Build Coastguard Worker   sock.Send(msg.data.data(), msg.data.size());
148*6dbdd20aSAndroid Build Coastguard Worker }
149*6dbdd20aSAndroid Build Coastguard Worker 
150*6dbdd20aSAndroid Build Coastguard Worker // Called when a TCP message is received from the endpoint.
OnDataAvailable(base::UnixSocket * sock)151*6dbdd20aSAndroid Build Coastguard Worker void WSBridge::OnDataAvailable(base::UnixSocket* sock) {
152*6dbdd20aSAndroid Build Coastguard Worker   base::HttpServerConnection* websocket = GetWebsocket(sock);
153*6dbdd20aSAndroid Build Coastguard Worker   PERFETTO_CHECK(websocket);
154*6dbdd20aSAndroid Build Coastguard Worker 
155*6dbdd20aSAndroid Build Coastguard Worker   char buf[8192];
156*6dbdd20aSAndroid Build Coastguard Worker   auto rsize = sock->Receive(buf, sizeof(buf));
157*6dbdd20aSAndroid Build Coastguard Worker   if (rsize > 0) {
158*6dbdd20aSAndroid Build Coastguard Worker     websocket->SendWebsocketMessage(buf, static_cast<size_t>(rsize));
159*6dbdd20aSAndroid Build Coastguard Worker   } else {
160*6dbdd20aSAndroid Build Coastguard Worker     // Connection closed or errored.
161*6dbdd20aSAndroid Build Coastguard Worker     sock->Shutdown(/*notify=*/true);  // Will trigger OnDisconnect().
162*6dbdd20aSAndroid Build Coastguard Worker     websocket->Close();
163*6dbdd20aSAndroid Build Coastguard Worker   }
164*6dbdd20aSAndroid Build Coastguard Worker }
165*6dbdd20aSAndroid Build Coastguard Worker 
166*6dbdd20aSAndroid Build Coastguard Worker // Called when the browser terminates the websocket connection.
OnHttpConnectionClosed(base::HttpServerConnection * websocket)167*6dbdd20aSAndroid Build Coastguard Worker void WSBridge::OnHttpConnectionClosed(base::HttpServerConnection* websocket) {
168*6dbdd20aSAndroid Build Coastguard Worker   PERFETTO_DLOG("[WSBridge] Websocket connection closed");
169*6dbdd20aSAndroid Build Coastguard Worker   auto it = conns_.find(websocket);
170*6dbdd20aSAndroid Build Coastguard Worker   if (it == conns_.end())
171*6dbdd20aSAndroid Build Coastguard Worker     return;  // Can happen if ADB closed first.
172*6dbdd20aSAndroid Build Coastguard Worker   base::UnixSocket& sock = *it->second;
173*6dbdd20aSAndroid Build Coastguard Worker   sock.Shutdown(/*notify=*/true);
174*6dbdd20aSAndroid Build Coastguard Worker   conns_.erase(websocket);
175*6dbdd20aSAndroid Build Coastguard Worker }
176*6dbdd20aSAndroid Build Coastguard Worker 
OnDisconnect(base::UnixSocket * sock)177*6dbdd20aSAndroid Build Coastguard Worker void WSBridge::OnDisconnect(base::UnixSocket* sock) {
178*6dbdd20aSAndroid Build Coastguard Worker   base::HttpServerConnection* websocket = GetWebsocket(sock);
179*6dbdd20aSAndroid Build Coastguard Worker   if (!websocket)
180*6dbdd20aSAndroid Build Coastguard Worker     return;
181*6dbdd20aSAndroid Build Coastguard Worker   websocket->Close();
182*6dbdd20aSAndroid Build Coastguard Worker   sock->Shutdown(/*notify=*/false);
183*6dbdd20aSAndroid Build Coastguard Worker   conns_.erase(websocket);
184*6dbdd20aSAndroid Build Coastguard Worker   PERFETTO_DLOG("[WSBridge] Socket connection closed");
185*6dbdd20aSAndroid Build Coastguard Worker }
186*6dbdd20aSAndroid Build Coastguard Worker 
GetWebsocket(base::UnixSocket * sock)187*6dbdd20aSAndroid Build Coastguard Worker base::HttpServerConnection* WSBridge::GetWebsocket(base::UnixSocket* sock) {
188*6dbdd20aSAndroid Build Coastguard Worker   for (const auto& it : conns_) {
189*6dbdd20aSAndroid Build Coastguard Worker     if (it.second.get() == sock) {
190*6dbdd20aSAndroid Build Coastguard Worker       return it.first;
191*6dbdd20aSAndroid Build Coastguard Worker     }
192*6dbdd20aSAndroid Build Coastguard Worker   }
193*6dbdd20aSAndroid Build Coastguard Worker   return nullptr;
194*6dbdd20aSAndroid Build Coastguard Worker }
195*6dbdd20aSAndroid Build Coastguard Worker 
OnConnect(base::UnixSocket *,bool)196*6dbdd20aSAndroid Build Coastguard Worker void WSBridge::OnConnect(base::UnixSocket*, bool) {}
OnNewIncomingConnection(base::UnixSocket *,std::unique_ptr<base::UnixSocket>)197*6dbdd20aSAndroid Build Coastguard Worker void WSBridge::OnNewIncomingConnection(base::UnixSocket*,
198*6dbdd20aSAndroid Build Coastguard Worker                                        std::unique_ptr<base::UnixSocket>) {}
199*6dbdd20aSAndroid Build Coastguard Worker 
200*6dbdd20aSAndroid Build Coastguard Worker }  // namespace
201*6dbdd20aSAndroid Build Coastguard Worker 
WebsocketBridgeMain(int argc,char ** argv)202*6dbdd20aSAndroid Build Coastguard Worker int PERFETTO_EXPORT_ENTRYPOINT WebsocketBridgeMain(int argc, char** argv) {
203*6dbdd20aSAndroid Build Coastguard Worker   perfetto::WSBridge ws_bridge;
204*6dbdd20aSAndroid Build Coastguard Worker   ws_bridge.Main(argc, argv);
205*6dbdd20aSAndroid Build Coastguard Worker   return 0;
206*6dbdd20aSAndroid Build Coastguard Worker }
207*6dbdd20aSAndroid Build Coastguard Worker 
208*6dbdd20aSAndroid Build Coastguard Worker }  // namespace perfetto
209