1 /*
2 * Copyright (C) 2021 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 * 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
16 #include <fcntl.h>
17 #include <poll.h>
18 #include <unistd.h>
19 #include <ios>
20 #include <mutex>
21
22 #include <android-base/logging.h>
23 #include <gflags/gflags.h>
24 #include <thread>
25
26 #include "common/libs/fs/shared_buf.h"
27 #include "common/libs/fs/shared_fd.h"
28 #include "host/libs/config/cuttlefish_config.h"
29 #include "host/libs/config/logging.h"
30
31 DEFINE_int32(fifo_in, -1, "A pipe for incoming communication");
32 DEFINE_int32(fifo_out, -1, "A pipe for outgoing communication");
33 DEFINE_int32(data_port, -1, "A port for data");
34 DEFINE_int32(buffer_size, -1, "The buffer size");
35 DEFINE_int32(dump_packet_size, -1,
36 "Dump incoming/outgoing packets up to given size");
37
OpenSocket(cuttlefish::SharedFD * fd,int port)38 void OpenSocket(cuttlefish::SharedFD* fd, int port) {
39 static std::mutex mutex;
40 std::unique_lock<std::mutex> lock(mutex);
41 for (;;) {
42 *fd = cuttlefish::SharedFD::SocketLocalClient(port, SOCK_STREAM);
43 if ((*fd)->IsOpen()) {
44 return;
45 }
46 LOG(ERROR) << "Failed to open socket: " << (*fd)->StrError();
47 // Wait a little and try again
48 sleep(1);
49 }
50 }
51
DumpPackets(const char * prefix,char * buf,int size)52 void DumpPackets(const char* prefix, char* buf, int size) {
53 if (FLAGS_dump_packet_size < 0 || size <= 0) {
54 return;
55 }
56 char bytes_string[1001] = {0};
57 int len = FLAGS_dump_packet_size < size ? FLAGS_dump_packet_size : size;
58 for (int i = 0; i < len; i++) {
59 if ((i + 1) * 5 > sizeof(bytes_string)) {
60 // Buffer out of bounds
61 break;
62 }
63 sprintf(bytes_string + (i * 5), "0x%02x ", buf[i]);
64 }
65 if (len < size) {
66 LOG(DEBUG) << prefix << ": sz=" << size << ", first " << len << " bytes=["
67 << bytes_string << "...]";
68 } else {
69 LOG(DEBUG) << prefix << ": sz=" << size << ", bytes=[" << bytes_string
70 << "]";
71 }
72 }
73
main(int argc,char ** argv)74 int main(int argc, char** argv) {
75 cuttlefish::DefaultSubprocessLogging(argv);
76 gflags::ParseCommandLineFlags(&argc, &argv, true);
77 auto fifo_in = cuttlefish::SharedFD::Dup(FLAGS_fifo_in);
78 if (!fifo_in->IsOpen()) {
79 LOG(ERROR) << "Error dupping fd " << FLAGS_fifo_in << ": "
80 << fifo_in->StrError();
81 return 1;
82 }
83 close(FLAGS_fifo_in);
84
85 auto fifo_out = cuttlefish::SharedFD::Dup(FLAGS_fifo_out);
86 if (!fifo_out->IsOpen()) {
87 LOG(ERROR) << "Error dupping fd " << FLAGS_fifo_out << ": "
88 << fifo_out->StrError();
89 return 1;
90 }
91 close(FLAGS_fifo_out);
92 cuttlefish::SharedFD sock;
93 OpenSocket(&sock, FLAGS_data_port);
94
95 auto guest_to_host = std::thread([&]() {
96 while (true) {
97 char buf[FLAGS_buffer_size];
98 auto read = fifo_in->Read(buf, sizeof(buf));
99 if (read < 0) {
100 LOG(WARNING) << "Error reading from guest: " << fifo_in->StrError();
101 sleep(1);
102 continue;
103 }
104 DumpPackets("Read from FIFO", buf, read);
105 while (cuttlefish::WriteAll(sock, buf, read) == -1) {
106 LOG(WARNING) << "Failed to write to host socket (will retry): "
107 << sock->StrError();
108 // Wait for the host process to be ready
109 sleep(1);
110 OpenSocket(&sock, FLAGS_data_port);
111 }
112 }
113 });
114
115 auto host_to_guest = std::thread([&]() {
116 while (true) {
117 char buf[FLAGS_buffer_size];
118 auto read = sock->Read(buf, sizeof(buf));
119 DumpPackets("Read from socket", buf, read);
120 if (read == -1) {
121 LOG(WARNING) << "Failed to read from host socket (will retry): "
122 << sock->StrError();
123 // Wait for the host process to be ready
124 sleep(1);
125 OpenSocket(&sock, FLAGS_data_port);
126 continue;
127 }
128 auto wrote = cuttlefish::WriteAll(fifo_out, buf, read);
129 if (wrote < 0) {
130 LOG(WARNING) << "Failed to write to guest: " << fifo_out->StrError();
131 sleep(1);
132 continue;
133 }
134 }
135 });
136 guest_to_host.join();
137 host_to_guest.join();
138 }
139