1 /******************************************************************************
2  *
3  *  Copyright (C) 2022 Google, Inc.
4  *
5  *  Licensed under the Apache License, Version 2.0 (the "License");
6  *  you may not use this file except in compliance with the License.
7  *  You may obtain a copy of the License at:
8  *
9  *  http://www.apache.org/licenses/LICENSE-2.0
10  *
11  *  Unless required by applicable law or agreed to in writing, software
12  *  distributed under the License is distributed on an "AS IS" BASIS,
13  *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14  *  See the License for the specific language governing permissions and
15  *  limitations under the License.
16  *
17  ******************************************************************************/
18 
19 #include "hal/snoop_logger_socket.h"
20 
21 #include <arpa/inet.h>
22 #include <bluetooth/log.h>
23 #include <fcntl.h>
24 #include <netinet/in.h>
25 #include <pthread.h>
26 #include <stdbool.h>
27 #include <string.h>
28 #include <sys/prctl.h>
29 #include <sys/socket.h>
30 #include <sys/types.h>
31 #include <sys/un.h>
32 #include <unistd.h>
33 
34 #include <cerrno>
35 #include <mutex>
36 
37 #include "common/init_flags.h"
38 #include "hal/snoop_logger_common.h"
39 #include "os/log.h"
40 #include "os/utils.h"
41 
42 namespace bluetooth {
43 namespace hal {
44 
45 using bluetooth::hal::SnoopLoggerCommon;
46 
47 static constexpr int INVALID_FD = -1;
48 
49 constexpr int INCOMING_SOCKET_CONNECTIONS_QUEUE_SIZE_ = 10;
50 
SnoopLoggerSocket(SyscallWrapperInterface * syscall_if,int socket_address,int socket_port)51 SnoopLoggerSocket::SnoopLoggerSocket(SyscallWrapperInterface* syscall_if, int socket_address, int socket_port)
52     : syscall_if_(syscall_if),
53       socket_address_(socket_address),
54       socket_port_(socket_port),
55       notification_listen_fd_(-1),
56       notification_write_fd_(-1),
57       listen_socket_(-1),
58       fd_max_(-1),
59       client_socket_(-1) {
60   log::info("address {} port {}", socket_address, socket_port);
61 }
62 
~SnoopLoggerSocket()63 SnoopLoggerSocket::~SnoopLoggerSocket() {
64   Cleanup();
65 }
66 
Write(int & client_socket,const void * data,size_t length)67 void SnoopLoggerSocket::Write(int& client_socket, const void* data, size_t length) {
68   if (client_socket == -1) {
69     return;
70   }
71 
72   ssize_t ret;
73   RUN_NO_INTR(ret = syscall_if_->Send(client_socket, data, length, MSG_DONTWAIT));
74 
75   if (ret == -1 && syscall_if_->GetErrno() == ECONNRESET) {
76     SafeCloseSocket(client_socket);
77   } else if (ret == -1 && syscall_if_->GetErrno() == EAGAIN) {
78     log::error("Dropping snoop pkts because of congestion");
79   }
80 }
81 
Write(const void * data,size_t length)82 void SnoopLoggerSocket::Write(const void* data, size_t length) {
83   std::lock_guard<std::mutex> lock(client_socket_mutex_);
84   Write(client_socket_, data, length);
85 }
86 
InitializeCommunications()87 int SnoopLoggerSocket::InitializeCommunications() {
88   int self_pipe_fds[2];
89   int ret;
90 
91   fd_max_ = -1;
92 
93   syscall_if_->FDZero(&save_sock_fds_);
94 
95   // Set up the communication channel
96   ret = syscall_if_->Pipe2(self_pipe_fds, O_NONBLOCK | O_CLOEXEC);
97   if (ret < 0) {
98     log::error("Unable to establish a communication channel to the listen thread.");
99     return ret;
100   }
101 
102   notification_listen_fd_ = self_pipe_fds[0];
103   notification_write_fd_ = self_pipe_fds[1];
104 
105   syscall_if_->FDSet(notification_listen_fd_, &save_sock_fds_);
106   fd_max_ = notification_listen_fd_;
107 
108   listen_socket_ = CreateSocket();
109   if (listen_socket_ == INVALID_FD) {
110     log::error("Unable to create a listen socket.");
111     SafeCloseSocket(notification_listen_fd_);
112     SafeCloseSocket(notification_write_fd_);
113     return -1;
114   }
115 
116   return 0;
117 }
118 
ProcessIncomingRequest()119 bool SnoopLoggerSocket::ProcessIncomingRequest() {
120   int ret;
121   fd_set sock_fds = save_sock_fds_;
122 
123   if ((syscall_if_->Select(fd_max_ + 1, &sock_fds, NULL, NULL, NULL)) == -1) {
124     log::error("select failed {}", strerror(syscall_if_->GetErrno()));
125     if (syscall_if_->GetErrno() == EINTR) return true;
126     return false;
127   }
128 
129   if ((listen_socket_ != -1) && syscall_if_->FDIsSet(listen_socket_, &sock_fds)) {
130     int client_socket = -1;
131     ret = AcceptIncomingConnection(listen_socket_, client_socket);
132     if (ret != 0) {
133       // Unrecoverable error, stop the thread.
134       return false;
135     }
136 
137     if (client_socket < 0) {
138       return true;
139     }
140 
141     InitializeClientSocket(client_socket);
142 
143     ClientSocketConnected(client_socket);
144   } else if ((notification_listen_fd_ != -1) && syscall_if_->FDIsSet(notification_listen_fd_, &sock_fds)) {
145     log::warn("exting from listen_fn_ thread");
146     return false;
147   }
148 
149   return true;
150 }
151 
Cleanup()152 void SnoopLoggerSocket::Cleanup() {
153   SafeCloseSocket(notification_listen_fd_);
154   SafeCloseSocket(notification_write_fd_);
155   SafeCloseSocket(client_socket_);
156   SafeCloseSocket(listen_socket_);
157 }
158 
AcceptIncomingConnection(int listen_socket,int & client_socket)159 int SnoopLoggerSocket::AcceptIncomingConnection(int listen_socket, int& client_socket) {
160   socklen_t clen;
161   struct sockaddr_in client_addr;
162 
163   RUN_NO_INTR(client_socket = syscall_if_->Accept(listen_socket, (struct sockaddr*)&client_addr, &clen, SOCK_CLOEXEC));
164   if (client_socket == -1) {
165     int errno_ = syscall_if_->GetErrno();
166     log::warn("error accepting socket: {}", strerror(errno_));
167     if (errno_ == EINVAL || errno_ == EBADF) {
168       return errno_;
169     }
170     return 0;
171   }
172 
173   log::info(
174       "Client socket fd: {}, IP address: {}, port: {}",
175       client_socket,
176       inet_ntoa(client_addr.sin_addr),
177       (int)ntohs(client_addr.sin_port));
178 
179   return 0;
180 }
181 
InitializeClientSocket(int client_socket)182 void SnoopLoggerSocket::InitializeClientSocket(int client_socket) {
183   /* When a new client connects, we have to send the btsnoop file header. This
184    * allows a decoder to treat the session as a new, valid btsnoop file. */
185   Write(
186       client_socket,
187       reinterpret_cast<const char*>(&SnoopLoggerCommon::kBtSnoopFileHeader),
188       sizeof(SnoopLoggerCommon::FileHeaderType));
189 }
190 
ClientSocketConnected(int client_socket)191 void SnoopLoggerSocket::ClientSocketConnected(int client_socket) {
192   std::lock_guard<std::mutex> lock(client_socket_mutex_);
193   SafeCloseSocket(client_socket_);
194   client_socket_ = client_socket;
195   client_socket_cv_.notify_one();
196 }
197 
WaitForClientSocketConnected()198 bool SnoopLoggerSocket::WaitForClientSocketConnected() {
199   std::unique_lock<std::mutex> lk(client_socket_mutex_);
200   client_socket_cv_.wait(lk, [this] { return IsClientSocketConnected(); });
201   return IsClientSocketConnected();
202 }
203 
IsClientSocketConnected() const204 bool SnoopLoggerSocket::IsClientSocketConnected() const {
205   return client_socket_ != INVALID_FD;
206 }
207 
CreateSocket()208 int SnoopLoggerSocket::CreateSocket() {
209   log::debug("");
210   int ret;
211 
212   // Create a TCP socket file descriptor
213   int socket_fd = syscall_if_->Socket(AF_INET, SOCK_STREAM | SOCK_CLOEXEC, IPPROTO_TCP);
214   if (socket_fd < 0) {
215     log::error("can't create socket: {}", strerror(syscall_if_->GetErrno()));
216     return INVALID_FD;
217   }
218 
219   syscall_if_->FDSet(socket_fd, &save_sock_fds_);
220   if (socket_fd > fd_max_) {
221     fd_max_ = socket_fd;
222   }
223 
224   // Enable REUSEADDR
225   int enable = 1;
226   ret = syscall_if_->Setsockopt(socket_fd, SOL_SOCKET, SO_REUSEADDR, &enable, sizeof(enable));
227   if (ret < 0) {
228     log::error("unable to set SO_REUSEADDR: {}", strerror(syscall_if_->GetErrno()));
229     SafeCloseSocket(socket_fd);
230     return INVALID_FD;
231   }
232 
233   struct sockaddr_in addr;
234   addr.sin_family = AF_INET;
235   addr.sin_addr.s_addr = htonl(socket_address_);
236   addr.sin_port = htons(socket_port_);
237 
238   // Bind socket to an address
239   ret = syscall_if_->Bind(socket_fd, (struct sockaddr*)&addr, sizeof(addr));
240   if (ret < 0) {
241     log::error("unable to bind snoop socket to address: {}", strerror(syscall_if_->GetErrno()));
242     SafeCloseSocket(socket_fd);
243     return INVALID_FD;
244   }
245 
246   // Mark this socket as a socket that will accept connections.
247   ret = syscall_if_->Listen(socket_fd, INCOMING_SOCKET_CONNECTIONS_QUEUE_SIZE_);
248   if (ret < 0) {
249     log::error("unable to listen: {}", strerror(syscall_if_->GetErrno()));
250     SafeCloseSocket(socket_fd);
251     return INVALID_FD;
252   }
253 
254   return socket_fd;
255 }
256 
NotifySocketListener()257 int SnoopLoggerSocket::NotifySocketListener() {
258   log::debug("");
259   char buffer = '0';
260   int ret = -1;
261 
262   if (notification_write_fd_ == -1) {
263     return 0;
264   }
265 
266   RUN_NO_INTR(ret = syscall_if_->Write(notification_write_fd_, &buffer, 1));
267   if (ret < 0) {
268     log::error("Error in notifying the listen thread to exit ({})", ret);
269     return -1;
270   }
271 
272   return 0;
273 }
274 
SafeCloseSocket(int & fd)275 void SnoopLoggerSocket::SafeCloseSocket(int& fd) {
276   log::debug("{}", fd);
277   if (fd != -1) {
278     syscall_if_->Close(fd);
279     syscall_if_->FDClr(fd, &save_sock_fds_);
280     fd = -1;
281   }
282 }
283 
GetSyscallWrapperInterface() const284 SyscallWrapperInterface* SnoopLoggerSocket::GetSyscallWrapperInterface() const {
285   return syscall_if_;
286 }
287 
288 }  // namespace hal
289 }  // namespace bluetooth
290