xref: /aosp_15_r20/external/sandboxed-api/sandboxed_api/sandbox2/network_proxy/testing.cc (revision ec63e07ab9515d95e79c211197c445ef84cefa6a)
1 // Copyright 2023 Google LLC
2 //
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 //     https://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 "sandboxed_api/sandbox2/network_proxy/testing.h"
16 
17 #include <arpa/inet.h>
18 #include <netinet/in.h>
19 #include <poll.h>
20 #include <sys/eventfd.h>
21 #include <sys/socket.h>
22 
23 #include <cstddef>
24 #include <cstdint>
25 #include <memory>
26 #include <thread>
27 #include <utility>
28 
29 #include "absl/base/macros.h"
30 #include "absl/log/check.h"
31 #include "absl/memory/memory.h"
32 #include "absl/status/status.h"
33 #include "absl/strings/string_view.h"
34 #include "sandboxed_api/util/fileops.h"
35 #include "sandboxed_api/util/status_macros.h"
36 
37 namespace sandbox2 {
38 namespace {
39 
40 using sapi::file_util::fileops::FDCloser;
41 
CreateServerSocket(int port,bool ipv6=true)42 absl::StatusOr<FDCloser> CreateServerSocket(int port, bool ipv6 = true) {
43   // Listen to localhost only
44   sockaddr_in6 addr6;
45   sockaddr_in addr4;
46   addr6.sin6_family = AF_INET6;
47   addr4.sin_family = AF_INET;
48   addr4.sin_port = addr6.sin6_port = htons(port);
49   PCHECK(inet_pton(AF_INET, "127.0.0.1", &addr4.sin_addr.s_addr) == 1);
50   PCHECK(inet_pton(AF_INET6, "::1", &addr6.sin6_addr.s6_addr) == 1);
51   sockaddr* addr = ipv6 ? reinterpret_cast<sockaddr*>(&addr6)
52                         : reinterpret_cast<sockaddr*>(&addr4);
53   size_t addr_size = ipv6 ? sizeof(addr6) : sizeof(addr4);
54   sapi::file_util::fileops::FDCloser s(
55       socket(addr->sa_family, SOCK_STREAM | SOCK_CLOEXEC, 0));
56   if (s.get() < 0) {
57     return absl::InternalError("socket() failed");
58   }
59   int enable = 1;
60   if (setsockopt(s.get(), SOL_SOCKET, SO_REUSEADDR, &enable, sizeof(enable)) <
61       0) {
62     return absl::InternalError("setsockopt() failed");
63   }
64   if (bind(s.get(), addr, addr_size) < 0) {
65     return absl::InternalError("bind() failed");
66   }
67   if (listen(s.get(), 1) < 0) {
68     return absl::InternalError("listen() failed");
69   }
70   return s;
71 }
72 
73 }  // namespace
74 
75 absl::StatusOr<std::unique_ptr<NetworkProxyTestServer>>
Start(bool ipv6)76 NetworkProxyTestServer::Start(bool ipv6) {
77    static int port = 8085;
78   FDCloser event_fd(eventfd(0, 0));
79   if (event_fd.get() < 0) {
80     return absl::InternalError("eventfd() failed");
81   }
82   SAPI_ASSIGN_OR_RETURN(FDCloser server_socket, CreateServerSocket(port, ipv6));
83   auto server = absl::WrapUnique(new NetworkProxyTestServer(
84       port, std::move(server_socket), std::move(event_fd)));
85   server->Spawn();
86   return server;
87 }
88 
Stop()89 void NetworkProxyTestServer::Stop() {
90   if (event_fd_.get() < 0) {
91     return;
92   }
93   uint64_t value = 1;
94   PCHECK(write(event_fd_.get(), &value, sizeof(value)) == sizeof(value));
95   thread_.join();
96   event_fd_.Close();
97   server_socket_.Close();
98 }
99 
Run()100 void NetworkProxyTestServer::Run() {
101   struct pollfd pfds[] = {
102       {.fd = server_socket_.get(), .events = POLLIN},
103       {.fd = event_fd_.get(), .events = POLLIN},
104   };
105   do {
106     PCHECK(poll(pfds, ABSL_ARRAYSIZE(pfds), -1) > 0);
107     if (pfds[1].revents & POLLIN) {
108       return;
109     }
110   } while (!(pfds[0].revents & POLLIN));
111   FDCloser client(accept(server_socket_.get(), 0, 0));
112   PCHECK(client.get() >= 0);
113   constexpr absl::string_view kMsg = "Hello World\n";
114   PCHECK(write(client.get(), kMsg.data(), kMsg.size()) == kMsg.size());
115 }
116 
Spawn()117 void NetworkProxyTestServer::Spawn() {
118   thread_ = std::thread([this] { Run(); });
119 }
120 
121 }  // namespace sandbox2
122