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