Home | History | Annotate | Download | only in src
      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 "btsnoop_net"
     20 
     21 #include <assert.h>
     22 #include <cutils/log.h>
     23 #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 
     32 #include "osi.h"
     33 
     34 static void safe_close_(int *fd);
     35 static void *listen_fn_(void *context);
     36 
     37 static const char *LISTEN_THREAD_NAME_ = "btsnoop_net_listen";
     38 static const int LOCALHOST_ = 0x7F000001;
     39 static const int LISTEN_PORT_ = 8872;
     40 
     41 static pthread_t listen_thread_;
     42 static bool listen_thread_valid_ = false;
     43 static pthread_mutex_t client_socket_lock_ = PTHREAD_MUTEX_INITIALIZER;
     44 static int listen_socket_ = -1;
     45 static int client_socket_ = -1;
     46 
     47 void btsnoop_net_open() {
     48   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 
     56 void btsnoop_net_close() {
     57   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 
     65 void btsnoop_net_write(const void *data, size_t length) {
     66   pthread_mutex_lock(&client_socket_lock_);
     67   if (client_socket_ != -1) {
     68     if (send(client_socket_, data, length, 0) == -1 && errno == ECONNRESET) {
     69       safe_close_(&client_socket_);
     70     }
     71   }
     72   pthread_mutex_unlock(&client_socket_lock_);
     73 }
     74 
     75 static void *listen_fn_(UNUSED_ATTR void *context) {
     76 
     77   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");
    107     int client_socket = accept(listen_socket_, NULL, NULL);
    108     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;
    122     send(client_socket_, "btsnoop\0\0\0\0\1\0\0\x3\xea", 16, 0);
    123     pthread_mutex_unlock(&client_socket_lock_);
    124   }
    125 
    126 cleanup:
    127   safe_close_(&listen_socket_);
    128   return NULL;
    129 }
    130 
    131 static void safe_close_(int *fd) {
    132   assert(fd != NULL);
    133   if (*fd != -1) {
    134     close(*fd);
    135     *fd = -1;
    136   }
    137 }
    138