Allow btsnoop logs to be read over a local socket.

This change allows real-time HCI debugging over adb from a
Linux box using hcidump.

Example:
--------
adb forward tcp:8872 tcp:8872
nc localhost 8872 | hcidump -X -r /dev/stdin

Change-Id: I49c32a941f71f612807061284a755a38b76588ff
diff --git a/doc/btsnoop_net.md b/doc/btsnoop_net.md
new file mode 100644
index 0000000..efd1071
--- /dev/null
+++ b/doc/btsnoop_net.md
@@ -0,0 +1,15 @@
+btsnoop_net
+====
+btsnoop_net exposes Bluetooth snoop logs over a local TCP socket which enables
+real-time debugging of HCI data with hcidump.
+
+This feature is enabled by  setting `BtSnoopLogOutput=true` in `bt_stack.conf`.
+Once it has been enabled and the stack restarted, bluedroid will listen for
+incoming TCP connections on port 8872.
+
+To use this feature with hcidump on a Linux host, you can run:
+
+```
+  $ adb forward tcp:8872 tcp:8872
+  $ nc localhost 8872 | hcidump -r /dev/stdin
+```
diff --git a/hci/Android.mk b/hci/Android.mk
index bbad3e9..4e956c2 100644
--- a/hci/Android.mk
+++ b/hci/Android.mk
@@ -9,6 +9,7 @@
         src/lpm.c \
         src/bt_hw.c \
         src/btsnoop.c \
+        src/btsnoop_net.c \
         src/utils.c
 
 LOCAL_CFLAGS := -Wno-unused-parameter
diff --git a/hci/src/btsnoop.c b/hci/src/btsnoop.c
index c6556d6..e4b1376 100644
--- a/hci/src/btsnoop.c
+++ b/hci/src/btsnoop.c
@@ -34,6 +34,7 @@
 #include <unistd.h>
 #include <ctype.h>
 #include <fcntl.h>
+#include <stdbool.h>
 
 #include <arpa/inet.h>
 #include <netinet/in.h>
@@ -67,10 +68,16 @@
 #define SNOOPDBG(param, ...) {}
 #endif
 
-#define HCIT_TYPE_COMMAND   1
-#define HCIT_TYPE_ACL_DATA  2
-#define HCIT_TYPE_SCO_DATA  3
-#define HCIT_TYPE_EVENT     4
+typedef enum {
+  kCommandPacket = 1,
+  kAclPacket = 2,
+  kScoPacket = 3,
+  kEventPacket = 4
+} packet_type;
+
+void btsnoop_net_init();
+void btsnoop_net_cleanup();
+void btsnoop_net_write(const void *data, size_t length);
 
 /* file descriptor of the BT snoop file (by default, -1 means disabled) */
 int hci_btsnoop_fd = -1;
@@ -259,117 +266,78 @@
 }
 
 /*******************************************************************************
- ** Function          btsnoop_write
  **
- ** Description       Function used to write the actual data to the log
+ ** Function         btsnoop_write
  **
- ** Returns           none
+ ** Description      Writes raw bytes to the BTSNOOP sinks.
+ **
+ ** Returns          None
 *******************************************************************************/
+static void btsnoop_write(const void *data, size_t length) {
+    if (hci_btsnoop_fd != -1) {
+        write(hci_btsnoop_fd, data, length);
+    }
+    btsnoop_net_write(data, length);
+}
 
-void btsnoop_write(uint8_t *p, uint32_t flags, const uint8_t *ptype, uint32_t len)
-{
-    uint32_t value, value_hi;
+/*******************************************************************************
+ **
+ ** Function         btsnoop_write_packet
+ **
+ ** Description      Writes a single HCI packet to BTSNOOP sinks.
+ **
+ ** Returns          None
+*******************************************************************************/
+static void btsnoop_write_packet(packet_type type,
+                                 const uint8_t *packet,
+                                 bool is_received) {
+    int length_he;
+    int length;
+    int flags;
+    int drops = 0;
+    switch (type) {
+        case kCommandPacket:
+            length_he = packet[2] + 4;
+            flags = 2;
+            break;
+        case kAclPacket:
+            length_he = (packet[3] << 8) + packet[2] + 5;
+            flags = is_received;
+            break;
+        case kScoPacket:
+            length_he = packet[2] + 4;
+            flags = is_received;
+            break;
+        case kEventPacket:
+            length_he = packet[1] + 3;
+            flags = 3;
+            break;
+    }
+
+    uint32_t time_hi, time_lo;
     struct timeval tv;
-    struct iovec io[3];
-    uint32_t header[6];
-
-    /* store the length in both original and included fields */
-    header[0] = l_to_be(len + 1);
-    header[1] = header[0];
-    /* flags: data can be sent or received */
-    header[2] = l_to_be(flags);
-    /* drops: none */
-    header[3] = 0;
-    /* time */
     gettimeofday(&tv, NULL);
-    tv_to_btsnoop_ts(&header[5], &header[4], &tv);
-    header[4] = l_to_be(header[4]);
-    header[5] = l_to_be(header[5]);
+    tv_to_btsnoop_ts(&time_lo, &time_hi, &tv);
 
-    io[0].iov_base = header;
-    io[0].iov_len = sizeof(header);
+    length = l_to_be(length_he);
+    flags = l_to_be(flags);
+    drops = l_to_be(drops);
+    time_hi = l_to_be(time_hi);
+    time_lo = l_to_be(time_lo);
 
-    io[1].iov_base = (void*)ptype;
-    io[1].iov_len = 1;
+    /* since these display functions are called from different contexts */
+    utils_lock();
 
-    io[2].iov_base = p;
-    io[2].iov_len = len;
+    btsnoop_write(&length, 4);
+    btsnoop_write(&length, 4);
+    btsnoop_write(&flags, 4);
+    btsnoop_write(&drops, 4);
+    btsnoop_write(&time_hi, 4);
+    btsnoop_write(&time_lo, 4);
+    btsnoop_write(&type, 1);
+    btsnoop_write(packet, length_he - 1);
 
-    (void) writev(hci_btsnoop_fd, io, 3);
-}
-
-/*******************************************************************************
- **
- ** Function         btsnoop_hci_cmd
- **
- ** Description      Function to add a command in the BTSNOOP file
- **
- ** Returns          None
-*******************************************************************************/
-void btsnoop_hci_cmd(uint8_t *p)
-{
-    const uint8_t cmd = HCIT_TYPE_COMMAND;
-    int plen;
-    SNOOPDBG("btsnoop_hci_cmd: fd = %d", hci_btsnoop_fd);
-    plen = (int) p[2] + 3;
-    btsnoop_write(p, 2, &cmd, plen);
-}
-
-
-/*******************************************************************************
- **
- ** Function         btsnoop_hci_evt
- **
- ** Description      Function to add a event in the BTSNOOP file
- **
- ** Returns          None
-*******************************************************************************/
-void btsnoop_hci_evt(uint8_t *p)
-{
-    const uint8_t evt = HCIT_TYPE_EVENT;
-    int plen;
-    SNOOPDBG("btsnoop_hci_evt: fd = %d", hci_btsnoop_fd);
-    plen = (int) p[1] + 2;
-
-    btsnoop_write(p, 3, &evt, plen);
-}
-
-/*******************************************************************************
- **
- ** Function         btsnoop_sco_data
- **
- ** Description      Function to add a SCO data packet in the BTSNOOP file
- **
- ** Returns          None
-*******************************************************************************/
-void btsnoop_sco_data(uint8_t *p, uint8_t is_rcvd)
-{
-    const uint8_t sco = HCIT_TYPE_SCO_DATA;
-    int plen;
-    SNOOPDBG("btsnoop_sco_data: fd = %d", hci_btsnoop_fd);
-    plen = (int) p[2] + 3;
-
-    btsnoop_write(p, is_rcvd, &sco, plen);
-}
-
-/*******************************************************************************
- **
- ** Function         btsnoop_acl_data
- **
- ** Description      Function to add an ACL data packet in the BTSNOOP file
- **
- ** Returns          None
-*******************************************************************************/
-void btsnoop_acl_data(uint8_t *p, uint8_t is_rcvd)
-{
-    const uint8_t acl = HCIT_TYPE_ACL_DATA;
-    int plen;
-
-    SNOOPDBG("btsnoop_acl_data: fd = %d", hci_btsnoop_fd);
-
-    plen = (((int) p[3]) << 8) + ((int) p[2]) +4;
-
-    btsnoop_write(p, is_rcvd, &acl, plen);
+    utils_unlock();
 }
 
 /********************************************************************************
@@ -433,7 +401,7 @@
     s = accept(s_listen, (struct sockaddr *) &cliaddr, &clilen);
 
     if (s < 0)
-{
+    {
         perror("accept");
         return -1;
     }
@@ -528,7 +496,9 @@
     if (pthread_create(&thread_id, NULL,
                        (void*)ext_parser_thread,NULL)!=0)
       perror("pthread_create");
+
 #endif
+    btsnoop_net_init();
 }
 
 void btsnoop_open(char *p_path)
@@ -549,6 +519,7 @@
 
 void btsnoop_cleanup (void)
 {
+    btsnoop_net_cleanup();
 #if defined(BTSNOOP_EXT_PARSER_INCLUDED) && (BTSNOOP_EXT_PARSER_INCLUDED == TRUE)
     ALOGD("btsnoop_cleanup");
     pthread_kill(thread_id, SIGUSR2);
@@ -605,24 +576,22 @@
     {
         case MSG_HC_TO_STACK_HCI_EVT:
             SNOOPDBG("TYPE : EVT");
-            btsnoop_hci_evt(p);
+            btsnoop_write_packet(kEventPacket, p, false);
             break;
         case MSG_HC_TO_STACK_HCI_ACL:
         case MSG_STACK_TO_HC_HCI_ACL:
             SNOOPDBG("TYPE : ACL");
-            btsnoop_acl_data(p, is_rcvd);
+            btsnoop_write_packet(kAclPacket, p, is_rcvd);
             break;
         case MSG_HC_TO_STACK_HCI_SCO:
         case MSG_STACK_TO_HC_HCI_SCO:
             SNOOPDBG("TYPE : SCO");
-            btsnoop_sco_data(p, is_rcvd);
+            btsnoop_write_packet(kScoPacket, p, is_rcvd);
             break;
         case MSG_STACK_TO_HC_HCI_CMD:
             SNOOPDBG("TYPE : CMD");
-            btsnoop_hci_cmd(p);
+            btsnoop_write_packet(kCommandPacket, p, true);
             break;
     }
 #endif // BTSNOOPDISP_INCLUDED
 }
-
-
diff --git a/hci/src/btsnoop_net.c b/hci/src/btsnoop_net.c
new file mode 100644
index 0000000..06cc01a
--- /dev/null
+++ b/hci/src/btsnoop_net.c
@@ -0,0 +1,134 @@
+/******************************************************************************
+ *
+ *  Copyright (C) 2013 Google, Inc.
+ *
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at:
+ *
+ *  http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ ******************************************************************************/
+
+#include <assert.h>
+#include <errno.h>
+#include <netinet/in.h>
+#include <pthread.h>
+#include <stdbool.h>
+#include <string.h>
+#include <sys/prctl.h>
+#include <sys/socket.h>
+#include <sys/types.h>
+
+#define LOG_TAG "btsnoop_net"
+#include <cutils/log.h>
+
+static void safe_close_(int *fd);
+static void *listen_fn_(void *context);
+
+static const char *LISTEN_THREAD_NAME_ = "btsnoop_net_listen";
+static const int LOCALHOST_ = 0x7F000001;
+static const int LISTEN_PORT_ = 8872;
+
+static pthread_t listen_thread_;
+static bool listen_thread_valid_ = false;
+static pthread_mutex_t client_socket_lock_ = PTHREAD_MUTEX_INITIALIZER;
+static int listen_socket_ = -1;
+static int client_socket_ = -1;
+
+void btsnoop_net_init() {
+  listen_thread_valid_ = (pthread_create(&listen_thread_, NULL, listen_fn_, NULL) == 0);
+  if (!listen_thread_valid_) {
+    ALOGE("%s pthread_create failed: %s", __func__, strerror(errno));
+  } else {
+    ALOGD("initialized");
+  }
+}
+
+void btsnoop_net_cleanup() {
+  if (listen_thread_valid_) {
+    shutdown(listen_socket_, SHUT_RDWR);
+    pthread_join(listen_thread_, NULL);
+    safe_close_(&client_socket_);
+    listen_thread_valid_ = false;
+  }
+}
+
+void btsnoop_net_write(const void *data, size_t length) {
+  pthread_mutex_lock(&client_socket_lock_);
+  if (client_socket_ != -1) {
+    if (send(client_socket_, data, length, 0) == -1 && errno == ECONNRESET) {
+      safe_close_(&client_socket_);
+    }
+  }
+  pthread_mutex_unlock(&client_socket_lock_);
+}
+
+static void *listen_fn_(void *context) {
+  prctl(PR_SET_NAME, (unsigned long)LISTEN_THREAD_NAME_, 0, 0, 0);
+
+  listen_socket_ = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
+  if (listen_socket_ == -1) {
+    ALOGE("%s socket creation failed: %s", __func__, strerror(errno));
+    goto cleanup;
+  }
+
+  int enable = 1;
+  if (setsockopt(listen_socket_, SOL_SOCKET, SO_REUSEADDR, &enable, sizeof(enable)) == -1) {
+    ALOGE("%s unable to set SO_REUSEADDR: %s", __func__, strerror(errno));
+    goto cleanup;
+  }
+
+  struct sockaddr_in addr;
+  addr.sin_family = AF_INET;
+  addr.sin_addr.s_addr = htonl(LOCALHOST_);
+  addr.sin_port = htons(LISTEN_PORT_);
+  if (bind(listen_socket_, (struct sockaddr *)&addr, sizeof(addr)) == -1) {
+    ALOGE("%s unable to bind listen socket: %s", __func__, strerror(errno));
+    goto cleanup;
+  }
+
+  if (listen(listen_socket_, 10) == -1) {
+    ALOGE("%s unable to listen: %s", __func__, strerror(errno));
+    goto cleanup;
+  }
+
+  for (;;) {
+    ALOGD("waiting for client connection");
+    int client_socket = accept(listen_socket_, NULL, NULL);
+    if (client_socket == -1) {
+      if (errno == EINVAL || errno == EBADF) {
+        break;
+      }
+      ALOGW("%s error accepting socket: %s", __func__, strerror(errno));
+      continue;
+    }
+
+    /* When a new client connects, we have to send the btsnoop file header. This allows
+       a decoder to treat the session as a new, valid btsnoop file. */
+    ALOGI("client connected");
+    pthread_mutex_lock(&client_socket_lock_);
+    safe_close_(&client_socket_);
+    client_socket_ = client_socket;
+    send(client_socket_, "btsnoop\0\0\0\0\1\0\0\x3\xea", 16, 0);
+    pthread_mutex_unlock(&client_socket_lock_);
+  }
+
+cleanup:
+  safe_close_(&listen_socket_);
+  return NULL;
+}
+
+static void safe_close_(int *fd) {
+  assert(fd != NULL);
+  if (*fd != -1) {
+    close(*fd);
+    *fd = -1;
+  }
+}