• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2022 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 #include "common/libs/utils/socket2socket_proxy.h"
18 
19 #include <poll.h>
20 #include <sys/socket.h>
21 
22 #include <cstring>
23 #include <functional>
24 #include <memory>
25 #include <ostream>
26 #include <string>
27 #include <thread>
28 
29 #include <android-base/logging.h>
30 
31 namespace cuttlefish {
32 namespace {
33 
Forward(const std::string & label,SharedFD from,SharedFD to)34 void Forward(const std::string& label, SharedFD from, SharedFD to) {
35   LOG(DEBUG) << label << ": Proxy thread started. Starting copying data";
36   auto success = to->CopyAllFrom(*from);
37   if (!success) {
38     if (from->GetErrno()) {
39       LOG(ERROR) << label << ": Error reading: " << from->StrError();
40     }
41     if (to->GetErrno()) {
42       LOG(ERROR) << label << ": Error writing: " << to->StrError();
43     }
44   }
45   to->Shutdown(SHUT_WR);
46   LOG(DEBUG) << label << ": Proxy thread completed";
47 }
48 
SetupProxying(SharedFD client,SharedFD target)49 void SetupProxying(SharedFD client, SharedFD target) {
50   LOG(DEBUG) << "Launching proxy threads";
51   std::thread client2target(Forward, "c2t", client, target);
52   std::thread target2client(Forward, "t2c", target, client);
53   client2target.detach();
54   target2client.detach();
55 }
56 
57 }  // namespace
58 
ProxyServer(SharedFD server,std::function<SharedFD ()> clients_factory)59 ProxyServer::ProxyServer(SharedFD server, std::function<SharedFD()> clients_factory)
60     : stop_fd_(SharedFD::Event()) {
61 
62   if (!stop_fd_->IsOpen()) {
63     LOG(FATAL) << "Failed to open eventfd: " << stop_fd_->StrError();
64     return;
65   }
66   server_ = std::thread([&, server_fd = std::move(server),
67                             clients_factory = std::move(clients_factory)]() {
68     constexpr ssize_t SERVER = 0;
69     constexpr ssize_t STOP = 1;
70 
71     std::vector<PollSharedFd> server_poll = {
72       {.fd = server_fd, .events = POLLIN},
73       {.fd = stop_fd_, .events = POLLIN}
74     };
75 
76     while (server_fd->IsOpen()) {
77       server_poll[SERVER].revents = 0;
78       server_poll[STOP].revents = 0;
79 
80       const int poll_result = SharedFD::Poll(server_poll, -1);
81       if (poll_result < 0) {
82         LOG(ERROR) << "Failed to poll to wait for incoming connection";
83         continue;
84       }
85       if (server_poll[STOP].revents & POLLIN) {
86         // Stop fd is available to read, so we received a stop event
87         // and must stop the thread
88         break;
89       }
90       if (!(server_poll[SERVER].revents & POLLIN)) {
91         continue;
92       }
93 
94       // Server fd is available to read, so we can accept the
95       // connection without blocking on that
96       auto client = SharedFD::Accept(*server_fd);
97       if (!client->IsOpen()) {
98         LOG(ERROR) << "Failed to accept incoming connection: " << client->StrError();
99         continue;
100       }
101       auto target = clients_factory();
102       if (target->IsOpen()) {
103         SetupProxying(client, target);
104       } else {
105         LOG(ERROR) << "Cannot connect to the target to setup proxying: " << target->StrError();
106       }
107       // The client will close when it goes out of scope here if the target
108       // didn't open.
109     }
110   });
111 }
112 
Join()113 void ProxyServer::Join() {
114   if (server_.joinable()) {
115     server_.join();
116   }
117 }
118 
~ProxyServer()119 ProxyServer::~ProxyServer() {
120   if (stop_fd_->EventfdWrite(1) != 0) {
121     LOG(ERROR) << "Failed to stop proxy thread: " << stop_fd_->StrError();
122   }
123   Join();
124 }
125 
Proxy(SharedFD server,std::function<SharedFD ()> conn_factory)126 void Proxy(SharedFD server, std::function<SharedFD()> conn_factory) {
127   ProxyServer proxy(std::move(server), std::move(conn_factory));
128   proxy.Join();
129 }
130 
ProxyAsync(SharedFD server,std::function<SharedFD ()> conn_factory)131 std::unique_ptr<ProxyServer> ProxyAsync(SharedFD server, std::function<SharedFD()> conn_factory) {
132   return std::unique_ptr<ProxyServer>(
133       new ProxyServer(std::move(server), std::move(conn_factory)));
134 }
135 
136 }  // namespace cuttlefish
137