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