blob: 388c91d6f69e612e81544cfb506a126de60ad52f [file] [log] [blame]
Sharvil Nanavati611f3ab2014-03-22 14:27:07 -07001/******************************************************************************
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
Sharvil Nanavatia7d7eb72014-06-14 23:45:16 -070019#define LOG_TAG "btsnoop_net"
20
Sharvil Nanavati611f3ab2014-03-22 14:27:07 -070021#include <assert.h>
Sharvil Nanavatia7d7eb72014-06-14 23:45:16 -070022#include <cutils/log.h>
Sharvil Nanavati611f3ab2014-03-22 14:27:07 -070023#include <errno.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
Sharvil Nanavatia7d7eb72014-06-14 23:45:16 -070032#include "osi.h"
Sharvil Nanavati611f3ab2014-03-22 14:27:07 -070033
34static void safe_close_(int *fd);
35static void *listen_fn_(void *context);
36
37static const char *LISTEN_THREAD_NAME_ = "btsnoop_net_listen";
38static const int LOCALHOST_ = 0x7F000001;
39static const int LISTEN_PORT_ = 8872;
40
41static pthread_t listen_thread_;
42static bool listen_thread_valid_ = false;
43static pthread_mutex_t client_socket_lock_ = PTHREAD_MUTEX_INITIALIZER;
44static int listen_socket_ = -1;
45static int client_socket_ = -1;
46
Sharvil Nanavatia7d7eb72014-06-14 23:45:16 -070047void btsnoop_net_open() {
Sharvil Nanavati611f3ab2014-03-22 14:27:07 -070048 listen_thread_valid_ = (pthread_create(&listen_thread_, NULL, listen_fn_, NULL) == 0);
49 if (!listen_thread_valid_) {
50 ALOGE("%s pthread_create failed: %s", __func__, strerror(errno));
51 } else {
52 ALOGD("initialized");
53 }
54}
55
Sharvil Nanavatia7d7eb72014-06-14 23:45:16 -070056void btsnoop_net_close() {
Sharvil Nanavati611f3ab2014-03-22 14:27:07 -070057 if (listen_thread_valid_) {
58 shutdown(listen_socket_, SHUT_RDWR);
59 pthread_join(listen_thread_, NULL);
60 safe_close_(&client_socket_);
61 listen_thread_valid_ = false;
62 }
63}
64
65void btsnoop_net_write(const void *data, size_t length) {
66 pthread_mutex_lock(&client_socket_lock_);
67 if (client_socket_ != -1) {
Sharvil Nanavati405b5c92016-06-17 14:15:46 -070068 if (TEMP_FAILURE_RETRY(send(client_socket_, data, length, 0)) == -1 && errno == ECONNRESET) {
Sharvil Nanavati611f3ab2014-03-22 14:27:07 -070069 safe_close_(&client_socket_);
70 }
71 }
72 pthread_mutex_unlock(&client_socket_lock_);
73}
74
Sharvil Nanavatia7d7eb72014-06-14 23:45:16 -070075static void *listen_fn_(UNUSED_ATTR void *context) {
76
Sharvil Nanavati611f3ab2014-03-22 14:27:07 -070077 prctl(PR_SET_NAME, (unsigned long)LISTEN_THREAD_NAME_, 0, 0, 0);
78
79 listen_socket_ = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
80 if (listen_socket_ == -1) {
81 ALOGE("%s socket creation failed: %s", __func__, strerror(errno));
82 goto cleanup;
83 }
84
85 int enable = 1;
86 if (setsockopt(listen_socket_, SOL_SOCKET, SO_REUSEADDR, &enable, sizeof(enable)) == -1) {
87 ALOGE("%s unable to set SO_REUSEADDR: %s", __func__, strerror(errno));
88 goto cleanup;
89 }
90
91 struct sockaddr_in addr;
92 addr.sin_family = AF_INET;
93 addr.sin_addr.s_addr = htonl(LOCALHOST_);
94 addr.sin_port = htons(LISTEN_PORT_);
95 if (bind(listen_socket_, (struct sockaddr *)&addr, sizeof(addr)) == -1) {
96 ALOGE("%s unable to bind listen socket: %s", __func__, strerror(errno));
97 goto cleanup;
98 }
99
100 if (listen(listen_socket_, 10) == -1) {
101 ALOGE("%s unable to listen: %s", __func__, strerror(errno));
102 goto cleanup;
103 }
104
105 for (;;) {
106 ALOGD("waiting for client connection");
Sharvil Nanavati405b5c92016-06-17 14:15:46 -0700107 int client_socket = TEMP_FAILURE_RETRY(accept(listen_socket_, NULL, NULL));
Sharvil Nanavati611f3ab2014-03-22 14:27:07 -0700108 if (client_socket == -1) {
109 if (errno == EINVAL || errno == EBADF) {
110 break;
111 }
112 ALOGW("%s error accepting socket: %s", __func__, strerror(errno));
113 continue;
114 }
115
116 /* When a new client connects, we have to send the btsnoop file header. This allows
117 a decoder to treat the session as a new, valid btsnoop file. */
118 ALOGI("client connected");
119 pthread_mutex_lock(&client_socket_lock_);
120 safe_close_(&client_socket_);
121 client_socket_ = client_socket;
Sharvil Nanavati405b5c92016-06-17 14:15:46 -0700122 TEMP_FAILURE_RETRY(send(client_socket_, "btsnoop\0\0\0\0\1\0\0\x3\xea", 16, 0));
Sharvil Nanavati611f3ab2014-03-22 14:27:07 -0700123 pthread_mutex_unlock(&client_socket_lock_);
124 }
125
126cleanup:
127 safe_close_(&listen_socket_);
128 return NULL;
129}
130
131static void safe_close_(int *fd) {
132 assert(fd != NULL);
133 if (*fd != -1) {
134 close(*fd);
135 *fd = -1;
136 }
137}