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
35static void safe_close_(int *fd);
36static void *listen_fn_(void *context);
37
38static const char *LISTEN_THREAD_NAME_ = "btsnoop_net_listen";
39static const int LOCALHOST_ = 0x7F000001;
40static const int LISTEN_PORT_ = 8872;
41
42static pthread_t listen_thread_;
43static bool listen_thread_valid_ = false;
44static pthread_mutex_t client_socket_lock_ = PTHREAD_MUTEX_INITIALIZER;
45static int listen_socket_ = -1;
46static int client_socket_ = -1;
47
48void 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
61void 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
74void 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
91static 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
142cleanup:
143  safe_close_(&listen_socket_);
144  return NULL;
145}
146
147static void safe_close_(int *fd) {
148  assert(fd != NULL);
149  if (*fd != -1) {
150    close(*fd);
151    *fd = -1;
152  }
153}
154