1611f3abf1c12a9f568114e46a21e70c74eaf6a60Sharvil Nanavati/******************************************************************************
2611f3abf1c12a9f568114e46a21e70c74eaf6a60Sharvil Nanavati *
3611f3abf1c12a9f568114e46a21e70c74eaf6a60Sharvil Nanavati *  Copyright (C) 2013 Google, Inc.
4611f3abf1c12a9f568114e46a21e70c74eaf6a60Sharvil Nanavati *
5611f3abf1c12a9f568114e46a21e70c74eaf6a60Sharvil Nanavati *  Licensed under the Apache License, Version 2.0 (the "License");
6611f3abf1c12a9f568114e46a21e70c74eaf6a60Sharvil Nanavati *  you may not use this file except in compliance with the License.
7611f3abf1c12a9f568114e46a21e70c74eaf6a60Sharvil Nanavati *  You may obtain a copy of the License at:
8611f3abf1c12a9f568114e46a21e70c74eaf6a60Sharvil Nanavati *
9611f3abf1c12a9f568114e46a21e70c74eaf6a60Sharvil Nanavati *  http://www.apache.org/licenses/LICENSE-2.0
10611f3abf1c12a9f568114e46a21e70c74eaf6a60Sharvil Nanavati *
11611f3abf1c12a9f568114e46a21e70c74eaf6a60Sharvil Nanavati *  Unless required by applicable law or agreed to in writing, software
12611f3abf1c12a9f568114e46a21e70c74eaf6a60Sharvil Nanavati *  distributed under the License is distributed on an "AS IS" BASIS,
13611f3abf1c12a9f568114e46a21e70c74eaf6a60Sharvil Nanavati *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14611f3abf1c12a9f568114e46a21e70c74eaf6a60Sharvil Nanavati *  See the License for the specific language governing permissions and
15611f3abf1c12a9f568114e46a21e70c74eaf6a60Sharvil Nanavati *  limitations under the License.
16611f3abf1c12a9f568114e46a21e70c74eaf6a60Sharvil Nanavati *
17611f3abf1c12a9f568114e46a21e70c74eaf6a60Sharvil Nanavati ******************************************************************************/
18611f3abf1c12a9f568114e46a21e70c74eaf6a60Sharvil Nanavati
19f8027005333c88a2f097cfd70d15c3d54c7764aeChris Manton#define LOG_TAG "bt_snoop_net"
20a7d7eb78b826cde99adb67fb7078aca85ea61da3Sharvil Nanavati
21f2af1c42ccb2f642b241c2261b42d0be61d45438Jack He#include <base/logging.h>
22611f3abf1c12a9f568114e46a21e70c74eaf6a60Sharvil Nanavati#include <errno.h>
23611f3abf1c12a9f568114e46a21e70c74eaf6a60Sharvil Nanavati#include <netinet/in.h>
24611f3abf1c12a9f568114e46a21e70c74eaf6a60Sharvil Nanavati#include <pthread.h>
25611f3abf1c12a9f568114e46a21e70c74eaf6a60Sharvil Nanavati#include <stdbool.h>
266aee1e82aa0bf44d7e382f1b01448fe31c490763Mark Salyzyn#include <stdio.h>
27611f3abf1c12a9f568114e46a21e70c74eaf6a60Sharvil Nanavati#include <string.h>
28611f3abf1c12a9f568114e46a21e70c74eaf6a60Sharvil Nanavati#include <sys/prctl.h>
29611f3abf1c12a9f568114e46a21e70c74eaf6a60Sharvil Nanavati#include <sys/socket.h>
30611f3abf1c12a9f568114e46a21e70c74eaf6a60Sharvil Nanavati#include <sys/types.h>
31a2647d0f5b0078d95d547a96548462b910bd453cArman Uguray#include <unistd.h>
32611f3abf1c12a9f568114e46a21e70c74eaf6a60Sharvil Nanavati
3321da63773cb7734e699a4dad662b5b84d2f3dfa8Marie Janssen#include <mutex>
3421da63773cb7734e699a4dad662b5b84d2f3dfa8Marie Janssen
3544802768c447ab480d4227b3a852a97d923b816dSharvil Nanavati#include "osi/include/log.h"
3649a86709488e5cfd5e23759da18bf9613e15b04dMarie Janssen#include "osi/include/osi.h"
37611f3abf1c12a9f568114e46a21e70c74eaf6a60Sharvil Nanavati
385ff20a23661695abb1cff6d01d71a8cad4cc7890Myles Watsonstatic void safe_close_(int* fd);
395ff20a23661695abb1cff6d01d71a8cad4cc7890Myles Watsonstatic void* listen_fn_(void* context);
40611f3abf1c12a9f568114e46a21e70c74eaf6a60Sharvil Nanavati
415ff20a23661695abb1cff6d01d71a8cad4cc7890Myles Watsonstatic const char* LISTEN_THREAD_NAME_ = "btsnoop_net_listen";
42611f3abf1c12a9f568114e46a21e70c74eaf6a60Sharvil Nanavatistatic const int LOCALHOST_ = 0x7F000001;
43611f3abf1c12a9f568114e46a21e70c74eaf6a60Sharvil Nanavatistatic const int LISTEN_PORT_ = 8872;
44611f3abf1c12a9f568114e46a21e70c74eaf6a60Sharvil Nanavati
45611f3abf1c12a9f568114e46a21e70c74eaf6a60Sharvil Nanavatistatic pthread_t listen_thread_;
46611f3abf1c12a9f568114e46a21e70c74eaf6a60Sharvil Nanavatistatic bool listen_thread_valid_ = false;
4721da63773cb7734e699a4dad662b5b84d2f3dfa8Marie Janssenstatic std::mutex client_socket_mutex_;
48611f3abf1c12a9f568114e46a21e70c74eaf6a60Sharvil Nanavatistatic int listen_socket_ = -1;
49611f3abf1c12a9f568114e46a21e70c74eaf6a60Sharvil Nanavatistatic int client_socket_ = -1;
50611f3abf1c12a9f568114e46a21e70c74eaf6a60Sharvil Nanavati
51a7d7eb78b826cde99adb67fb7078aca85ea61da3Sharvil Nanavativoid btsnoop_net_open() {
52d19e0785e662e640191a075eda07acce61c2aedaMarie Janssen#if (BT_NET_DEBUG != TRUE)
535ff20a23661695abb1cff6d01d71a8cad4cc7890Myles Watson  return;  // Disable using network sockets for security reasons
544cac544da367d7458129631ddef6db4e3312cef7Pavlin Radoslavov#endif
554cac544da367d7458129631ddef6db4e3312cef7Pavlin Radoslavov
565ff20a23661695abb1cff6d01d71a8cad4cc7890Myles Watson  listen_thread_valid_ =
575ff20a23661695abb1cff6d01d71a8cad4cc7890Myles Watson      (pthread_create(&listen_thread_, NULL, listen_fn_, NULL) == 0);
58ec728d3136aabcd7675aba4a672d932e0709c509Myles Watson  if (!listen_thread_valid_)
595ff20a23661695abb1cff6d01d71a8cad4cc7890Myles Watson    LOG_ERROR(LOG_TAG, "%s pthread_create failed: %s", __func__,
605ff20a23661695abb1cff6d01d71a8cad4cc7890Myles Watson              strerror(errno));
61611f3abf1c12a9f568114e46a21e70c74eaf6a60Sharvil Nanavati}
62611f3abf1c12a9f568114e46a21e70c74eaf6a60Sharvil Nanavati
63a7d7eb78b826cde99adb67fb7078aca85ea61da3Sharvil Nanavativoid btsnoop_net_close() {
64d19e0785e662e640191a075eda07acce61c2aedaMarie Janssen#if (BT_NET_DEBUG != TRUE)
655ff20a23661695abb1cff6d01d71a8cad4cc7890Myles Watson  return;  // Disable using network sockets for security reasons
664cac544da367d7458129631ddef6db4e3312cef7Pavlin Radoslavov#endif
674cac544da367d7458129631ddef6db4e3312cef7Pavlin Radoslavov
68611f3abf1c12a9f568114e46a21e70c74eaf6a60Sharvil Nanavati  if (listen_thread_valid_) {
69611f3abf1c12a9f568114e46a21e70c74eaf6a60Sharvil Nanavati    shutdown(listen_socket_, SHUT_RDWR);
70611f3abf1c12a9f568114e46a21e70c74eaf6a60Sharvil Nanavati    pthread_join(listen_thread_, NULL);
71611f3abf1c12a9f568114e46a21e70c74eaf6a60Sharvil Nanavati    safe_close_(&client_socket_);
72611f3abf1c12a9f568114e46a21e70c74eaf6a60Sharvil Nanavati    listen_thread_valid_ = false;
73611f3abf1c12a9f568114e46a21e70c74eaf6a60Sharvil Nanavati  }
74611f3abf1c12a9f568114e46a21e70c74eaf6a60Sharvil Nanavati}
75611f3abf1c12a9f568114e46a21e70c74eaf6a60Sharvil Nanavati
765ff20a23661695abb1cff6d01d71a8cad4cc7890Myles Watsonvoid btsnoop_net_write(const void* data, size_t length) {
77d19e0785e662e640191a075eda07acce61c2aedaMarie Janssen#if (BT_NET_DEBUG != TRUE)
785ff20a23661695abb1cff6d01d71a8cad4cc7890Myles Watson  return;  // Disable using network sockets for security reasons
794cac544da367d7458129631ddef6db4e3312cef7Pavlin Radoslavov#endif
804cac544da367d7458129631ddef6db4e3312cef7Pavlin Radoslavov
8121da63773cb7734e699a4dad662b5b84d2f3dfa8Marie Janssen  std::lock_guard<std::mutex> lock(client_socket_mutex_);
82611f3abf1c12a9f568114e46a21e70c74eaf6a60Sharvil Nanavati  if (client_socket_ != -1) {
83d6121a37c579731b89348e618a823c53b938449aPavlin Radoslavov    ssize_t ret;
84d6121a37c579731b89348e618a823c53b938449aPavlin Radoslavov    OSI_NO_INTR(ret = send(client_socket_, data, length, 0));
85d6121a37c579731b89348e618a823c53b938449aPavlin Radoslavov
86d6121a37c579731b89348e618a823c53b938449aPavlin Radoslavov    if (ret == -1 && errno == ECONNRESET) {
87611f3abf1c12a9f568114e46a21e70c74eaf6a60Sharvil Nanavati      safe_close_(&client_socket_);
88611f3abf1c12a9f568114e46a21e70c74eaf6a60Sharvil Nanavati    }
89611f3abf1c12a9f568114e46a21e70c74eaf6a60Sharvil Nanavati  }
90611f3abf1c12a9f568114e46a21e70c74eaf6a60Sharvil Nanavati}
91611f3abf1c12a9f568114e46a21e70c74eaf6a60Sharvil Nanavati
925ff20a23661695abb1cff6d01d71a8cad4cc7890Myles Watsonstatic void* listen_fn_(UNUSED_ATTR void* context) {
93b2a292b5d8df2f359c38b0787bc01181225a9bc9Pavlin Radoslavov  int enable = 1;
94a7d7eb78b826cde99adb67fb7078aca85ea61da3Sharvil Nanavati
95611f3abf1c12a9f568114e46a21e70c74eaf6a60Sharvil Nanavati  prctl(PR_SET_NAME, (unsigned long)LISTEN_THREAD_NAME_, 0, 0, 0);
96611f3abf1c12a9f568114e46a21e70c74eaf6a60Sharvil Nanavati
97611f3abf1c12a9f568114e46a21e70c74eaf6a60Sharvil Nanavati  listen_socket_ = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
98611f3abf1c12a9f568114e46a21e70c74eaf6a60Sharvil Nanavati  if (listen_socket_ == -1) {
995ff20a23661695abb1cff6d01d71a8cad4cc7890Myles Watson    LOG_ERROR(LOG_TAG, "%s socket creation failed: %s", __func__,
1005ff20a23661695abb1cff6d01d71a8cad4cc7890Myles Watson              strerror(errno));
101611f3abf1c12a9f568114e46a21e70c74eaf6a60Sharvil Nanavati    goto cleanup;
102611f3abf1c12a9f568114e46a21e70c74eaf6a60Sharvil Nanavati  }
103611f3abf1c12a9f568114e46a21e70c74eaf6a60Sharvil Nanavati
1045ff20a23661695abb1cff6d01d71a8cad4cc7890Myles Watson  if (setsockopt(listen_socket_, SOL_SOCKET, SO_REUSEADDR, &enable,
1055ff20a23661695abb1cff6d01d71a8cad4cc7890Myles Watson                 sizeof(enable)) == -1) {
1065ff20a23661695abb1cff6d01d71a8cad4cc7890Myles Watson    LOG_ERROR(LOG_TAG, "%s unable to set SO_REUSEADDR: %s", __func__,
1075ff20a23661695abb1cff6d01d71a8cad4cc7890Myles Watson              strerror(errno));
108611f3abf1c12a9f568114e46a21e70c74eaf6a60Sharvil Nanavati    goto cleanup;
109611f3abf1c12a9f568114e46a21e70c74eaf6a60Sharvil Nanavati  }
110611f3abf1c12a9f568114e46a21e70c74eaf6a60Sharvil Nanavati
111611f3abf1c12a9f568114e46a21e70c74eaf6a60Sharvil Nanavati  struct sockaddr_in addr;
112611f3abf1c12a9f568114e46a21e70c74eaf6a60Sharvil Nanavati  addr.sin_family = AF_INET;
113611f3abf1c12a9f568114e46a21e70c74eaf6a60Sharvil Nanavati  addr.sin_addr.s_addr = htonl(LOCALHOST_);
114611f3abf1c12a9f568114e46a21e70c74eaf6a60Sharvil Nanavati  addr.sin_port = htons(LISTEN_PORT_);
1155ff20a23661695abb1cff6d01d71a8cad4cc7890Myles Watson  if (bind(listen_socket_, (struct sockaddr*)&addr, sizeof(addr)) == -1) {
1165ff20a23661695abb1cff6d01d71a8cad4cc7890Myles Watson    LOG_ERROR(LOG_TAG, "%s unable to bind listen socket: %s", __func__,
1175ff20a23661695abb1cff6d01d71a8cad4cc7890Myles Watson              strerror(errno));
118611f3abf1c12a9f568114e46a21e70c74eaf6a60Sharvil Nanavati    goto cleanup;
119611f3abf1c12a9f568114e46a21e70c74eaf6a60Sharvil Nanavati  }
120611f3abf1c12a9f568114e46a21e70c74eaf6a60Sharvil Nanavati
121611f3abf1c12a9f568114e46a21e70c74eaf6a60Sharvil Nanavati  if (listen(listen_socket_, 10) == -1) {
122db554581079863974af8e1289646f5deea6fc044Marie Janssen    LOG_ERROR(LOG_TAG, "%s unable to listen: %s", __func__, strerror(errno));
123611f3abf1c12a9f568114e46a21e70c74eaf6a60Sharvil Nanavati    goto cleanup;
124611f3abf1c12a9f568114e46a21e70c74eaf6a60Sharvil Nanavati  }
125611f3abf1c12a9f568114e46a21e70c74eaf6a60Sharvil Nanavati
126611f3abf1c12a9f568114e46a21e70c74eaf6a60Sharvil Nanavati  for (;;) {
127d6121a37c579731b89348e618a823c53b938449aPavlin Radoslavov    int client_socket;
128d6121a37c579731b89348e618a823c53b938449aPavlin Radoslavov    OSI_NO_INTR(client_socket = accept(listen_socket_, NULL, NULL));
129611f3abf1c12a9f568114e46a21e70c74eaf6a60Sharvil Nanavati    if (client_socket == -1) {
130611f3abf1c12a9f568114e46a21e70c74eaf6a60Sharvil Nanavati      if (errno == EINVAL || errno == EBADF) {
131611f3abf1c12a9f568114e46a21e70c74eaf6a60Sharvil Nanavati        break;
132611f3abf1c12a9f568114e46a21e70c74eaf6a60Sharvil Nanavati      }
1335ff20a23661695abb1cff6d01d71a8cad4cc7890Myles Watson      LOG_WARN(LOG_TAG, "%s error accepting socket: %s", __func__,
1345ff20a23661695abb1cff6d01d71a8cad4cc7890Myles Watson               strerror(errno));
135611f3abf1c12a9f568114e46a21e70c74eaf6a60Sharvil Nanavati      continue;
136611f3abf1c12a9f568114e46a21e70c74eaf6a60Sharvil Nanavati    }
137611f3abf1c12a9f568114e46a21e70c74eaf6a60Sharvil Nanavati
1385ff20a23661695abb1cff6d01d71a8cad4cc7890Myles Watson    /* When a new client connects, we have to send the btsnoop file header. This
13929483137606d358f72ee544127ec8d052afe0ab0Myles Watson     * allows a decoder to treat the session as a new, valid btsnoop file. */
14021da63773cb7734e699a4dad662b5b84d2f3dfa8Marie Janssen    std::lock_guard<std::mutex> lock(client_socket_mutex_);
141611f3abf1c12a9f568114e46a21e70c74eaf6a60Sharvil Nanavati    safe_close_(&client_socket_);
142611f3abf1c12a9f568114e46a21e70c74eaf6a60Sharvil Nanavati    client_socket_ = client_socket;
143d6121a37c579731b89348e618a823c53b938449aPavlin Radoslavov
144d6121a37c579731b89348e618a823c53b938449aPavlin Radoslavov    OSI_NO_INTR(send(client_socket_, "btsnoop\0\0\0\0\1\0\0\x3\xea", 16, 0));
145611f3abf1c12a9f568114e46a21e70c74eaf6a60Sharvil Nanavati  }
146611f3abf1c12a9f568114e46a21e70c74eaf6a60Sharvil Nanavati
147611f3abf1c12a9f568114e46a21e70c74eaf6a60Sharvil Nanavaticleanup:
148611f3abf1c12a9f568114e46a21e70c74eaf6a60Sharvil Nanavati  safe_close_(&listen_socket_);
149611f3abf1c12a9f568114e46a21e70c74eaf6a60Sharvil Nanavati  return NULL;
150611f3abf1c12a9f568114e46a21e70c74eaf6a60Sharvil Nanavati}
151611f3abf1c12a9f568114e46a21e70c74eaf6a60Sharvil Nanavati
1525ff20a23661695abb1cff6d01d71a8cad4cc7890Myles Watsonstatic void safe_close_(int* fd) {
153f2af1c42ccb2f642b241c2261b42d0be61d45438Jack He  CHECK(fd != NULL);
154611f3abf1c12a9f568114e46a21e70c74eaf6a60Sharvil Nanavati  if (*fd != -1) {
155611f3abf1c12a9f568114e46a21e70c74eaf6a60Sharvil Nanavati    close(*fd);
156611f3abf1c12a9f568114e46a21e70c74eaf6a60Sharvil Nanavati    *fd = -1;
157611f3abf1c12a9f568114e46a21e70c74eaf6a60Sharvil Nanavati  }
158611f3abf1c12a9f568114e46a21e70c74eaf6a60Sharvil Nanavati}
159