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