1 /******************************************************************************
2 *
3 * Copyright (C) 2013 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 #define LOG_TAG "bt_snoop_net"
20
21 #include <assert.h>
22 #include <errno.h>
23 #include <netinet/in.h>
24 #include <pthread.h>
25 #include <stdbool.h>
26 #include <string.h>
27 #include <sys/prctl.h>
28 #include <sys/socket.h>
29 #include <sys/types.h>
30
31 #include "osi/include/osi.h"
32 #include "osi/include/log.h"
33
34 static void safe_close_(int *fd);
35 static void *listen_fn_(void *context);
36
37 static const char *LISTEN_THREAD_NAME_ = "btsnoop_net_listen";
38 static const int LOCALHOST_ = 0x7F000001;
39 static const int LISTEN_PORT_ = 8872;
40
41 static pthread_t listen_thread_;
42 static bool listen_thread_valid_ = false;
43 static pthread_mutex_t client_socket_lock_ = PTHREAD_MUTEX_INITIALIZER;
44 static int listen_socket_ = -1;
45 static int client_socket_ = -1;
46
btsnoop_net_open()47 void btsnoop_net_open() {
48 #if (!defined(BT_NET_DEBUG) || (BT_NET_DEBUG != TRUE))
49 return; // Disable using network sockets for security reasons
50 #endif
51
52 listen_thread_valid_ = (pthread_create(&listen_thread_, NULL, listen_fn_, NULL) == 0);
53 if (!listen_thread_valid_) {
54 LOG_ERROR("%s pthread_create failed: %s", __func__, strerror(errno));
55 } else {
56 LOG_DEBUG("initialized");
57 }
58 }
59
btsnoop_net_close()60 void btsnoop_net_close() {
61 #if (!defined(BT_NET_DEBUG) || (BT_NET_DEBUG != TRUE))
62 return; // Disable using network sockets for security reasons
63 #endif
64
65 if (listen_thread_valid_) {
66 shutdown(listen_socket_, SHUT_RDWR);
67 pthread_join(listen_thread_, NULL);
68 safe_close_(&client_socket_);
69 listen_thread_valid_ = false;
70 }
71 }
72
btsnoop_net_write(const void * data,size_t length)73 void btsnoop_net_write(const void *data, size_t length) {
74 #if (!defined(BT_NET_DEBUG) || (BT_NET_DEBUG != TRUE))
75 return; // Disable using network sockets for security reasons
76 #endif
77
78 pthread_mutex_lock(&client_socket_lock_);
79 if (client_socket_ != -1) {
80 if (TEMP_FAILURE_RETRY(send(client_socket_, data, length, 0)) == -1 && errno == ECONNRESET) {
81 safe_close_(&client_socket_);
82 }
83 }
84 pthread_mutex_unlock(&client_socket_lock_);
85 }
86
listen_fn_(UNUSED_ATTR void * context)87 static void *listen_fn_(UNUSED_ATTR void *context) {
88
89 prctl(PR_SET_NAME, (unsigned long)LISTEN_THREAD_NAME_, 0, 0, 0);
90
91 listen_socket_ = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
92 if (listen_socket_ == -1) {
93 LOG_ERROR("%s socket creation failed: %s", __func__, strerror(errno));
94 goto cleanup;
95 }
96
97 int enable = 1;
98 if (setsockopt(listen_socket_, SOL_SOCKET, SO_REUSEADDR, &enable, sizeof(enable)) == -1) {
99 LOG_ERROR("%s unable to set SO_REUSEADDR: %s", __func__, strerror(errno));
100 goto cleanup;
101 }
102
103 struct sockaddr_in addr;
104 addr.sin_family = AF_INET;
105 addr.sin_addr.s_addr = htonl(LOCALHOST_);
106 addr.sin_port = htons(LISTEN_PORT_);
107 if (bind(listen_socket_, (struct sockaddr *)&addr, sizeof(addr)) == -1) {
108 LOG_ERROR("%s unable to bind listen socket: %s", __func__, strerror(errno));
109 goto cleanup;
110 }
111
112 if (listen(listen_socket_, 10) == -1) {
113 LOG_ERROR("%s unable to listen: %s", __func__, strerror(errno));
114 goto cleanup;
115 }
116
117 for (;;) {
118 int client_socket = TEMP_FAILURE_RETRY(accept(listen_socket_, NULL, NULL));
119 if (client_socket == -1) {
120 if (errno == EINVAL || errno == EBADF) {
121 break;
122 }
123 LOG_WARN("%s error accepting socket: %s", __func__, strerror(errno));
124 continue;
125 }
126
127 /* When a new client connects, we have to send the btsnoop file header. This allows
128 a decoder to treat the session as a new, valid btsnoop file. */
129 pthread_mutex_lock(&client_socket_lock_);
130 safe_close_(&client_socket_);
131 client_socket_ = client_socket;
132 TEMP_FAILURE_RETRY(send(client_socket_, "btsnoop\0\0\0\0\1\0\0\x3\xea", 16, 0));
133 pthread_mutex_unlock(&client_socket_lock_);
134 }
135
136 cleanup:
137 safe_close_(&listen_socket_);
138 return NULL;
139 }
140
safe_close_(int * fd)141 static void safe_close_(int *fd) {
142 assert(fd != NULL);
143 if (*fd != -1) {
144 close(*fd);
145 *fd = -1;
146 }
147 }
148