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 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 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 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 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 147 static void safe_close_(int *fd) { 148 assert(fd != NULL); 149 if (*fd != -1) { 150 close(*fd); 151 *fd = -1; 152 } 153 } 154