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