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