summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJean-Baptiste Queru <jbq@google.com>2009-11-12 18:46:23 -0800
committerJean-Baptiste Queru <jbq@google.com>2009-11-12 18:46:23 -0800
commit327e4ab9cc1fa9eeb7243ad6ee28dfcc7b212a5b (patch)
tree45215c0865ba46ce9e35f19be2827ebfe1f111f9
parentdf782f29a530d805c13f32bb43883306c05a4504 (diff)
downloadbluetooth-327e4ab9cc1fa9eeb7243ad6ee28dfcc7b212a5b.tar.gz
eclair snapshot
-rw-r--r--bluedroid/Android.mk19
-rw-r--r--bluedroid/bluetooth.c26
-rw-r--r--bluedroid/include/bluedroid/bluetooth.h4
-rw-r--r--bluez-clean-headers/bluetooth/hci.h18
-rw-r--r--bluez-clean-headers/bluetooth/l2cap.h85
-rw-r--r--brcm_patchram_plus/Android.mk19
-rw-r--r--brcm_patchram_plus/brcm_patchram_plus.c580
-rw-r--r--data/Android.mk2
-rw-r--r--data/audio.conf31
-rw-r--r--data/hcid.conf64
-rw-r--r--data/input.conf14
-rw-r--r--data/main.conf59
-rw-r--r--tools/Android.mk150
-rw-r--r--tools/asocket_test.c742
-rw-r--r--tools/bttest.c (renamed from bluedroid/bttest.c)0
-rw-r--r--tools/pipetest.c429
-rw-r--r--tools/sock_shutdown_bug_l2cap.c47
-rw-r--r--tools/sock_shutdown_bug_rfcomm.c63
-rw-r--r--tools/sock_shutdown_bug_tcp.c63
-rw-r--r--tools/sock_shutdown_test.c314
-rw-r--r--tools/socktest.c816
21 files changed, 3447 insertions, 98 deletions
diff --git a/bluedroid/Android.mk b/bluedroid/Android.mk
index b4f8a39..17df49b 100644
--- a/bluedroid/Android.mk
+++ b/bluedroid/Android.mk
@@ -19,22 +19,3 @@ LOCAL_SHARED_LIBRARIES := \
LOCAL_MODULE := libbluedroid
include $(BUILD_SHARED_LIBRARY)
-
-
-#
-# bttest
-#
-
-include $(CLEAR_VARS)
-
-LOCAL_SRC_FILES := bttest.c
-
-LOCAL_C_INCLUDES := $(LOCAL_PATH)/include
-
-LOCAL_SHARED_LIBRARIES := libbluedroid
-
-LOCAL_MODULE_PATH := $(TARGET_OUT_OPTIONAL_EXECUTABLES)
-LOCAL_MODULE_TAGS := eng
-LOCAL_MODULE := bttest
-
-include $(BUILD_EXECUTABLE)
diff --git a/bluedroid/bluetooth.c b/bluedroid/bluetooth.c
index 4559eee..b953082 100644
--- a/bluedroid/bluetooth.c
+++ b/bluedroid/bluetooth.c
@@ -178,9 +178,9 @@ int bt_enable() {
goto out;
}
- LOGI("Starting hcid deamon");
- if (property_set("ctl.start", "hcid") < 0) {
- LOGE("Failed to start hcid");
+ LOGI("Starting bluetoothd deamon");
+ if (property_set("ctl.start", "bluetoothd") < 0) {
+ LOGE("Failed to start bluetoothd");
goto out;
}
sleep(HCID_START_DELAY_SEC);
@@ -198,9 +198,9 @@ int bt_disable() {
int ret = -1;
int hci_sock = -1;
- LOGI("Stopping hcid deamon");
- if (property_set("ctl.stop", "hcid") < 0) {
- LOGE("Error stopping hcid");
+ LOGI("Stopping bluetoothd deamon");
+ if (property_set("ctl.stop", "bluetoothd") < 0) {
+ LOGE("Error stopping bluetoothd");
goto out;
}
usleep(HCID_STOP_DELAY_USEC);
@@ -255,3 +255,17 @@ out:
if (hci_sock >= 0) close(hci_sock);
return ret;
}
+
+int ba2str(const bdaddr_t *ba, char *str) {
+ return sprintf(str, "%2.2X:%2.2X:%2.2X:%2.2X:%2.2X:%2.2X",
+ ba->b[5], ba->b[4], ba->b[3], ba->b[2], ba->b[1], ba->b[0]);
+}
+
+int str2ba(const char *str, bdaddr_t *ba) {
+ int i;
+ for (i = 5; i >= 0; i--) {
+ ba->b[i] = (uint8_t) strtoul(str, &str, 16);
+ str++;
+ }
+ return 0;
+}
diff --git a/bluedroid/include/bluedroid/bluetooth.h b/bluedroid/include/bluedroid/bluetooth.h
index 64603e9..70085e4 100644
--- a/bluedroid/include/bluedroid/bluetooth.h
+++ b/bluedroid/include/bluedroid/bluetooth.h
@@ -19,6 +19,7 @@
#ifdef __cplusplus
extern "C" {
#endif
+#include <bluetooth/bluetooth.h>
/* Enable the bluetooth interface.
*
@@ -41,6 +42,9 @@ int bt_disable();
/* Returns 1 if enabled, 0 if disabled, and -ve on error */
int bt_is_enabled();
+int ba2str(const bdaddr_t *ba, char *str);
+int str2ba(const char *str, bdaddr_t *ba);
+
#ifdef __cplusplus
}
#endif
diff --git a/bluez-clean-headers/bluetooth/hci.h b/bluez-clean-headers/bluetooth/hci.h
index c0ab284..506d7a0 100644
--- a/bluez-clean-headers/bluetooth/hci.h
+++ b/bluez-clean-headers/bluetooth/hci.h
@@ -15,6 +15,7 @@
#ifdef __cplusplus
#endif
#include <sys/socket.h>
+#include <sys/ioctl.h>
#define HCI_MAX_DEV 16
#define HCI_MAX_ACL_SIZE 1024
#define HCI_MAX_SCO_SIZE 255
@@ -675,4 +676,21 @@ enum {
HCI_SECMGR
};
+struct sockaddr_hci {
+ sa_family_t hci_family;
+ unsigned short hci_dev;
+};
+struct hci_conn_info {
+ uint16_t handle;
+ bdaddr_t bdaddr;
+ uint8_t type;
+ uint8_t out;
+ uint16_t state;
+ uint32_t link_mode;
+};
+struct hci_conn_list_req {
+ uint16_t dev_id;
+ uint16_t conn_num;
+ struct hci_conn_info conn_info[0];
+};
#endif
diff --git a/bluez-clean-headers/bluetooth/l2cap.h b/bluez-clean-headers/bluetooth/l2cap.h
new file mode 100644
index 0000000..5fd8162
--- /dev/null
+++ b/bluez-clean-headers/bluetooth/l2cap.h
@@ -0,0 +1,85 @@
+/****************************************************************************
+ ****************************************************************************
+ ***
+ *** This header was automatically generated from a Linux kernel header
+ *** of the same name, to make information necessary for userspace to
+ *** call into the kernel available to libc. It contains only constants,
+ *** structures, and macros generated from the original header, and thus,
+ *** contains no copyrightable information.
+ ***
+ ****************************************************************************
+ ****************************************************************************/
+#ifndef __L2CAP_H
+#define __L2CAP_H
+
+#ifdef __cplusplus
+#endif
+#include <sys/socket.h>
+#define L2CAP_DEFAULT_MTU 672
+#define L2CAP_DEFAULT_FLUSH_TO 0xFFFF
+#define L2CAP_CONN_TIMEOUT (HZ * 40)
+#define L2CAP_OPTIONS 0x01
+#define L2CAP_CONNINFO 0x02
+#define L2CAP_LM 0x03
+#define L2CAP_LM_MASTER 0x0001
+#define L2CAP_LM_AUTH 0x0002
+#define L2CAP_LM_ENCRYPT 0x0004
+#define L2CAP_LM_TRUSTED 0x0008
+#define L2CAP_LM_RELIABLE 0x0010
+#define L2CAP_LM_SECURE 0x0020
+#define L2CAP_COMMAND_REJ 0x01
+#define L2CAP_CONN_REQ 0x02
+#define L2CAP_CONN_RSP 0x03
+#define L2CAP_CONF_REQ 0x04
+#define L2CAP_CONF_RSP 0x05
+#define L2CAP_DISCONN_REQ 0x06
+#define L2CAP_DISCONN_RSP 0x07
+#define L2CAP_ECHO_REQ 0x08
+#define L2CAP_ECHO_RSP 0x09
+#define L2CAP_INFO_REQ 0x0a
+#define L2CAP_INFO_RSP 0x0b
+#define L2CAP_HDR_SIZE 4
+#define L2CAP_CMD_HDR_SIZE 4
+#define L2CAP_CMD_REJ_SIZE 2
+#define L2CAP_CONN_REQ_SIZE 4
+#define L2CAP_CONN_RSP_SIZE 8
+#define L2CAP_CR_SUCCESS 0x0000
+#define L2CAP_CR_PEND 0x0001
+#define L2CAP_CR_BAD_PSM 0x0002
+#define L2CAP_CR_SEC_BLOCK 0x0003
+#define L2CAP_CR_NO_MEM 0x0004
+#define L2CAP_CS_NO_INFO 0x0000
+#define L2CAP_CS_AUTHEN_PEND 0x0001
+#define L2CAP_CS_AUTHOR_PEND 0x0002
+#define L2CAP_CONF_REQ_SIZE 4
+#define L2CAP_CONF_RSP_SIZE 6
+#define L2CAP_CONF_SUCCESS 0x0000
+#define L2CAP_CONF_UNACCEPT 0x0001
+#define L2CAP_CONF_REJECT 0x0002
+#define L2CAP_CONF_UNKNOWN 0x0003
+#define L2CAP_CONF_OPT_SIZE 2
+#define L2CAP_CONF_MTU 0x01
+#define L2CAP_CONF_FLUSH_TO 0x02
+#define L2CAP_CONF_QOS 0x03
+#define L2CAP_CONF_RFC 0x04
+#define L2CAP_CONF_RFC_MODE 0x04
+#define L2CAP_CONF_MAX_SIZE 22
+#define L2CAP_MODE_BASIC 0x00
+#define L2CAP_MODE_RETRANS 0x01
+#define L2CAP_MODE_FLOWCTL 0x02
+#define L2CAP_DISCONN_REQ_SIZE 4
+#define L2CAP_DISCONN_RSP_SIZE 4
+#define L2CAP_INFO_REQ_SIZE 2
+#define L2CAP_INFO_RSP_SIZE 4
+#define L2CAP_IT_CL_MTU 0x0001
+#define L2CAP_IT_FEAT_MASK 0x0002
+#define L2CAP_IR_SUCCESS 0x0000
+#define L2CAP_IR_NOTSUPP 0x0001
+#ifdef __cplusplus
+#endif
+struct sockaddr_l2 {
+ sa_family_t l2_family;
+ unsigned short l2_psm;
+ bdaddr_t l2_bdaddr;
+};
+#endif
diff --git a/brcm_patchram_plus/Android.mk b/brcm_patchram_plus/Android.mk
new file mode 100644
index 0000000..3f4e8c7
--- /dev/null
+++ b/brcm_patchram_plus/Android.mk
@@ -0,0 +1,19 @@
+ifeq ($(BOARD_HAVE_BLUETOOTH_BCM),true)
+
+LOCAL_PATH:= $(call my-dir)
+
+#
+# brcm_patchram_plus.c
+#
+
+include $(CLEAR_VARS)
+
+LOCAL_SRC_FILES := brcm_patchram_plus.c
+
+LOCAL_MODULE := brcm_patchram_plus
+
+LOCAL_SHARED_LIBRARIES := libcutils
+
+include $(BUILD_EXECUTABLE)
+
+endif
diff --git a/brcm_patchram_plus/brcm_patchram_plus.c b/brcm_patchram_plus/brcm_patchram_plus.c
new file mode 100644
index 0000000..7345acd
--- /dev/null
+++ b/brcm_patchram_plus/brcm_patchram_plus.c
@@ -0,0 +1,580 @@
+/**
+ * brcm_patchram_plus.c
+ *
+ * Copyright (C) 2009 Broadcom Corporation.
+ *
+ * This software is licensed under the terms of the GNU General Public License,
+ * version 2, as published by the Free Software Foundation (the "GPL"), and may
+ * be copied, distributed, and modified under those terms.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GPL for more details.
+ *
+ * A copy of the GPL is available at http://www.broadcom.com/licenses/GPLv2.php
+ * or by writing to the Free Software Foundation, Inc.,
+ * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
+ */
+
+
+/*****************************************************************************
+**
+** Name: brcm_patchram_plus.c
+**
+** Description: This program downloads a patchram files in the HCD format
+** to Broadcom Bluetooth based silicon and combo chips and
+** and other utility functions.
+**
+** It can be invoked from the command line in the form
+** <-d> to print a debug log
+** <--patchram patchram_file>
+** <--baudrate baud_rate>
+** <--bd_addr bd_address>
+** <--enable_lpm>
+** <--enable_hci>
+** uart_device_name
+**
+** For example:
+**
+** brcm_patchram_plus -d --patchram \
+** BCM2045B2_002.002.011.0348.0349.hcd /dev/ttyHS0
+**
+** It will return 0 for success and a number greater than 0
+** for any errors.
+**
+** For Android, this program invoked using a
+** "system(2)" call from the beginning of the bt_enable
+** function inside the file
+** system/bluetooth/bluedroid/bluetooth.c.
+**
+** If the Android system property "ro.bt.bcm_bdaddr_path" is
+** set, then the bd_addr will be read from this path.
+** This is overridden by --bd_addr on the command line.
+**
+******************************************************************************/
+
+// TODO: Integrate BCM support into Bluez hciattach
+
+#include <stdio.h>
+#include <getopt.h>
+#include <errno.h>
+
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+
+#include <stdlib.h>
+
+#ifdef ANDROID
+#include <termios.h>
+#else
+#include <sys/termios.h>
+#endif
+
+#include <string.h>
+#include <signal.h>
+
+#include <cutils/properties.h>
+
+#ifndef N_HCI
+#define N_HCI 15
+#endif
+
+#define HCIUARTSETPROTO _IOW('U', 200, int)
+#define HCIUARTGETPROTO _IOR('U', 201, int)
+#define HCIUARTGETDEVICE _IOR('U', 202, int)
+
+#define HCI_UART_H4 0
+#define HCI_UART_BCSP 1
+#define HCI_UART_3WIRE 2
+#define HCI_UART_H4DS 3
+#define HCI_UART_LL 4
+
+
+int uart_fd = -1;
+int hcdfile_fd = -1;
+int termios_baudrate = 0;
+int bdaddr_flag = 0;
+int enable_lpm = 0;
+int enable_hci = 0;
+int debug = 0;
+
+struct termios termios;
+unsigned char buffer[1024];
+
+unsigned char hci_reset[] = { 0x01, 0x03, 0x0c, 0x00 };
+
+unsigned char hci_download_minidriver[] = { 0x01, 0x2e, 0xfc, 0x00 };
+
+unsigned char hci_update_baud_rate[] = { 0x01, 0x18, 0xfc, 0x06, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00 };
+
+unsigned char hci_write_bd_addr[] = { 0x01, 0x01, 0xfc, 0x06,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
+
+unsigned char hci_write_sleep_mode[] = { 0x01, 0x27, 0xfc, 0x0c,
+ 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x00, 0x00, 0x00,
+ 0x00, 0x00 };
+
+int
+parse_patchram(char *optarg)
+{
+ char *p;
+
+ if (!(p = strrchr(optarg, '.'))) {
+ fprintf(stderr, "file %s not an HCD file\n", optarg);
+ exit(3);
+ }
+
+ p++;
+
+ if (strcasecmp("hcd", p) != 0) {
+ fprintf(stderr, "file %s not an HCD file\n", optarg);
+ exit(4);
+ }
+
+ if ((hcdfile_fd = open(optarg, O_RDONLY)) == -1) {
+ fprintf(stderr, "file %s could not be opened, error %d\n", optarg, errno);
+ exit(5);
+ }
+
+ return(0);
+}
+
+void
+BRCM_encode_baud_rate(uint baud_rate, unsigned char *encoded_baud)
+{
+ if(baud_rate == 0 || encoded_baud == NULL) {
+ fprintf(stderr, "Baudrate not supported!");
+ return;
+ }
+
+ encoded_baud[3] = (unsigned char)(baud_rate >> 24);
+ encoded_baud[2] = (unsigned char)(baud_rate >> 16);
+ encoded_baud[1] = (unsigned char)(baud_rate >> 8);
+ encoded_baud[0] = (unsigned char)(baud_rate & 0xFF);
+}
+
+typedef struct {
+ int baud_rate;
+ int termios_value;
+} tBaudRates;
+
+tBaudRates baud_rates[] = {
+ { 115200, B115200 },
+ { 230400, B230400 },
+ { 460800, B460800 },
+ { 500000, B500000 },
+ { 576000, B576000 },
+ { 921600, B921600 },
+ { 1000000, B1000000 },
+ { 1152000, B1152000 },
+ { 1500000, B1500000 },
+ { 2000000, B2000000 },
+ { 2500000, B2500000 },
+ { 3000000, B3000000 },
+#ifndef __CYGWIN__
+ { 3500000, B3500000 },
+ { 4000000, B4000000 }
+#endif
+};
+
+int
+validate_baudrate(int baud_rate, int *value)
+{
+ unsigned int i;
+
+ for (i = 0; i < (sizeof(baud_rates) / sizeof(tBaudRates)); i++) {
+ if (baud_rates[i].baud_rate == baud_rate) {
+ *value = baud_rates[i].termios_value;
+ return(1);
+ }
+ }
+
+ return(0);
+}
+
+int
+parse_baudrate(char *optarg)
+{
+ int baudrate = atoi(optarg);
+
+ if (validate_baudrate(baudrate, &termios_baudrate)) {
+ BRCM_encode_baud_rate(baudrate, &hci_update_baud_rate[6]);
+ }
+
+ return(0);
+}
+
+int
+parse_bdaddr(char *optarg)
+{
+ int bd_addr[6];
+ int i;
+
+ sscanf(optarg, "%02X:%02X:%02X:%02X:%02X:%02X",
+ &bd_addr[5], &bd_addr[4], &bd_addr[3],
+ &bd_addr[2], &bd_addr[1], &bd_addr[0]);
+
+ for (i = 0; i < 6; i++) {
+ hci_write_bd_addr[4 + i] = bd_addr[i];
+ }
+
+ bdaddr_flag = 1;
+
+ return(0);
+}
+
+int
+parse_enable_lpm(char *optarg)
+{
+ enable_lpm = 1;
+ return(0);
+}
+
+int
+parse_enable_hci(char *optarg)
+{
+ enable_hci = 1;
+ return(0);
+}
+
+int
+parse_cmd_line(int argc, char **argv)
+{
+ int c;
+ int digit_optind = 0;
+
+ typedef int (*PFI)();
+
+ PFI parse_param[] = { parse_patchram, parse_baudrate,
+ parse_bdaddr, parse_enable_lpm, parse_enable_hci };
+
+ while (1)
+ {
+ int this_option_optind = optind ? optind : 1;
+ int option_index = 0;
+
+ static struct option long_options[] = {
+ {"patchram", 1, 0, 0},
+ {"baudrate", 1, 0, 0},
+ {"bd_addr", 1, 0, 0},
+ {"enable_lpm", 0, 0, 0},
+ {"enable_hci", 0, 0, 0},
+ {0, 0, 0, 0}
+ };
+
+ c = getopt_long_only (argc, argv, "d", long_options, &option_index);
+
+ if (c == -1) {
+ break;
+ }
+
+ switch (c) {
+ case 0:
+ printf ("option %s", long_options[option_index].name);
+
+ if (optarg) {
+ printf (" with arg %s", optarg);
+ }
+
+ printf ("\n");
+
+ (*parse_param[option_index])(optarg);
+ break;
+
+ case 'd':
+ debug = 1;
+ break;
+
+ case '?':
+ //nobreak
+ default:
+
+ printf("Usage %s:\n", argv[0]);
+ printf("\t<-d> to print a debug log\n");
+ printf("\t<--patchram patchram_file>\n");
+ printf("\t<--baudrate baud_rate>\n");
+ printf("\t<--bd_addr bd_address>\n");
+ printf("\t<--enable_lpm\n");
+ printf("\t<--enable_hci\n");
+ printf("\tuart_device_name\n");
+ break;
+
+ }
+ }
+
+ if (optind < argc) {
+ if (optind < argc) {
+ printf ("%s ", argv[optind]);
+
+ if ((uart_fd = open(argv[optind], O_RDWR | O_NOCTTY)) == -1) {
+ fprintf(stderr, "port %s could not be opened, error %d\n", argv[2], errno);
+ }
+ }
+
+ printf ("\n");
+ }
+
+ return(0);
+}
+
+void
+init_uart()
+{
+ tcflush(uart_fd, TCIOFLUSH);
+ tcgetattr(uart_fd, &termios);
+
+#ifndef __CYGWIN__
+ cfmakeraw(&termios);
+#else
+ termios.c_iflag &= ~(IGNBRK | BRKINT | PARMRK | ISTRIP
+ | INLCR | IGNCR | ICRNL | IXON);
+ termios.c_oflag &= ~OPOST;
+ termios.c_lflag &= ~(ECHO | ECHONL | ICANON | ISIG | IEXTEN);
+ termios.c_cflag &= ~(CSIZE | PARENB);
+ termios.c_cflag |= CS8;
+#endif
+
+ termios.c_cflag |= CRTSCTS;
+ tcsetattr(uart_fd, TCSANOW, &termios);
+ tcflush(uart_fd, TCIOFLUSH);
+ tcsetattr(uart_fd, TCSANOW, &termios);
+ tcflush(uart_fd, TCIOFLUSH);
+ tcflush(uart_fd, TCIOFLUSH);
+ cfsetospeed(&termios, B115200);
+ cfsetispeed(&termios, B115200);
+ tcsetattr(uart_fd, TCSANOW, &termios);
+}
+
+void
+dump(unsigned char *out, int len)
+{
+ int i;
+
+ for (i = 0; i < len; i++) {
+ if (i && !(i % 16)) {
+ fprintf(stderr, "\n");
+ }
+
+ fprintf(stderr, "%02x ", out[i]);
+ }
+
+ fprintf(stderr, "\n");
+}
+
+void
+read_event(int fd, unsigned char *buffer)
+{
+ int i = 0;
+ int len = 3;
+ int count;
+
+ while ((count = read(fd, &buffer[i], len)) < len) {
+ i += count;
+ len -= count;
+ }
+
+ i += count;
+ len = buffer[2];
+
+ while ((count = read(fd, &buffer[i], len)) < len) {
+ i += count;
+ len -= count;
+ }
+
+ if (debug) {
+ count += i;
+
+ fprintf(stderr, "received %d\n", count);
+ dump(buffer, count);
+ }
+}
+
+void
+hci_send_cmd(unsigned char *buf, int len)
+{
+ if (debug) {
+ fprintf(stderr, "writing\n");
+ dump(buf, len);
+ }
+
+ write(uart_fd, buf, len);
+}
+
+void
+expired(int sig)
+{
+ hci_send_cmd(hci_reset, sizeof(hci_reset));
+ alarm(4);
+}
+
+void
+proc_reset()
+{
+ signal(SIGALRM, expired);
+
+
+ hci_send_cmd(hci_reset, sizeof(hci_reset));
+
+ alarm(4);
+
+ read_event(uart_fd, buffer);
+
+ alarm(0);
+}
+
+void
+proc_patchram()
+{
+ int len;
+
+ hci_send_cmd(hci_download_minidriver, sizeof(hci_download_minidriver));
+
+ read_event(uart_fd, buffer);
+
+ read(uart_fd, &buffer[0], 2);
+
+ while (read(hcdfile_fd, &buffer[1], 3)) {
+ buffer[0] = 0x01;
+
+ len = buffer[3];
+
+ read(hcdfile_fd, &buffer[4], len);
+
+ hci_send_cmd(buffer, len + 4);
+
+ read_event(uart_fd, buffer);
+ }
+
+ proc_reset();
+}
+
+void
+proc_baudrate()
+{
+ hci_send_cmd(hci_update_baud_rate, sizeof(hci_update_baud_rate));
+
+ read_event(uart_fd, buffer);
+
+ cfsetospeed(&termios, termios_baudrate);
+ cfsetispeed(&termios, termios_baudrate);
+ tcsetattr(uart_fd, TCSANOW, &termios);
+
+ if (debug) {
+ fprintf(stderr, "Done setting baudrate\n");
+ }
+}
+
+void
+proc_bdaddr()
+{
+ hci_send_cmd(hci_write_bd_addr, sizeof(hci_write_bd_addr));
+
+ read_event(uart_fd, buffer);
+}
+
+void
+proc_enable_lpm()
+{
+ hci_send_cmd(hci_write_sleep_mode, sizeof(hci_write_sleep_mode));
+
+ read_event(uart_fd, buffer);
+}
+
+void
+proc_enable_hci()
+{
+ int i = N_HCI;
+ int proto = HCI_UART_H4;
+ if (enable_lpm) {
+ proto = HCI_UART_LL;
+ }
+ if (ioctl(uart_fd, TIOCSETD, &i) < 0) {
+ fprintf(stderr, "Can't set line discipline\n");
+ return;
+ }
+
+ if (ioctl(uart_fd, HCIUARTSETPROTO, proto) < 0) {
+ fprintf(stderr, "Can't set hci protocol\n");
+ return;
+ }
+ fprintf(stderr, "Done setting line discpline\n");
+ return;
+}
+
+void
+read_default_bdaddr()
+{
+ int sz;
+ int fd;
+ char path[PROPERTY_VALUE_MAX];
+ char bdaddr[18];
+
+ property_get("ro.bt.bdaddr_path", path, "");
+ if (path[0] == 0)
+ return;
+
+ fd = open(path, O_RDONLY);
+ if (fd < 0) {
+ fprintf(stderr, "open(%s) failed: %s (%d)", path, strerror(errno),
+ errno);
+ return;
+ }
+
+ sz = read(fd, bdaddr, sizeof(bdaddr));
+ if (sz < 0) {
+ fprintf(stderr, "read(%s) failed: %s (%d)", path, strerror(errno),
+ errno);
+ close(fd);
+ return;
+ } else if (sz != sizeof(bdaddr)) {
+ fprintf(stderr, "read(%s) unexpected size %d", path, sz);
+ close(fd);
+ return;
+ }
+
+ printf("Read default bdaddr of %s\n", bdaddr);
+ parse_bdaddr(bdaddr);
+}
+
+int
+main (int argc, char **argv)
+{
+ read_default_bdaddr();
+
+ parse_cmd_line(argc, argv);
+
+ if (uart_fd < 0) {
+ exit(1);
+ }
+
+ init_uart();
+
+ proc_reset();
+
+ if (hcdfile_fd > 0) {
+ proc_patchram();
+ }
+
+ if (termios_baudrate) {
+ proc_baudrate();
+ }
+
+ if (bdaddr_flag) {
+ proc_bdaddr();
+ }
+
+ if (enable_lpm) {
+ proc_enable_lpm();
+ }
+
+ if (enable_hci) {
+ proc_enable_hci();
+ while (1) {
+ sleep(UINT_MAX);
+ }
+ }
+
+ exit(0);
+}
diff --git a/data/Android.mk b/data/Android.mk
index a4dfdab..07501e1 100644
--- a/data/Android.mk
+++ b/data/Android.mk
@@ -21,7 +21,7 @@ dest_dir := $(TARGET_OUT)/etc/bluez
files := \
audio.conf \
input.conf \
- hcid.conf
+ main.conf
copy_to := $(addprefix $(dest_dir)/,$(files))
diff --git a/data/audio.conf b/data/audio.conf
index 434848a..26ce1c7 100644
--- a/data/audio.conf
+++ b/data/audio.conf
@@ -1,12 +1,37 @@
-# Configuration file for the bluez audio plugin (A2DP)
+# Configuration file for the audio service
+# This section contains options which are not specific to any
+# particular interface
+# NOTE: Enable=Sink means that bluetoothd exposes Sink interface for remote
+# devices, and the local device is a Source
[General]
-Enable=Source,Control,Sink
-Disable=Headset,Gateway
+Enable=Sink,Control
+Disable=Headset,Gateway,Source
# Switch to master role for incoming connections (defaults to true)
#Master=true
+# SCO routing. Either PCM or HCI (in which case audio is routed to/from ALSA)
+# Defaults to HCI
+#SCORouting=PCM
+
+# Automatically connect both A2DP and HFP/HSP profiles for incoming
+# connections. Some headsets that support both profiles will only connect the
+# other one automatically so the default setting of true is usually a good
+# idea.
+#AutoConnect=true
+
+# Headset interface specific options (i.e. options which affect how the audio
+# service interacts with remote headset devices)
+#[Headset]
+
+# Set to true to support HFP (in addition to HSP only which is the default)
+# Defaults to false
+#HFP=true
+
+# Maximum number of connected HSP/HFP devices per adapter. Defaults to 1
+#MaxConnections=1
+
# Just an example of potential config options for the other interfaces
[A2DP]
SBCSources=1
diff --git a/data/hcid.conf b/data/hcid.conf
deleted file mode 100644
index 56df63a..0000000
--- a/data/hcid.conf
+++ /dev/null
@@ -1,64 +0,0 @@
-#
-# HCI daemon configuration file.
-#
-
-# HCId options
-options {
- # Automatically initialize new devices
- autoinit yes;
-
- # Security Manager mode
- # none - Security manager disabled
- # auto - Use local PIN for incoming connections
- # user - Always ask user for a PIN
- #
- security user;
-
- # Pairing mode
- # none - Pairing disabled
- # multi - Allow pairing with already paired devices
- # once - Pair once and deny successive attempts
- pairing multi;
-}
-
-# Default settings for HCI devices
-device {
- # Local device name
- # %d - device id
- # %h - host name
- # %b - ro.product.brand
- # %m - ro.product.model
- # %n - ro.product.name
- name "%m";
-
- # Local device class
- # 0x400000 - Service class: Telephony
- # 0x000200 - Major class: Phone
- # 0x00000C - Minor class: Smart phone
- class 0x40020C;
-
- # Default packet type
- #pkt_type DH1,DM1,HV1;
-
- # Inquiry and Page scan
- iscan disable;
- pscan enable;
-
- # Page timeout (in 0.625ms slots): 10 seconds
- pageto 16384;
-
- # Default link mode
- # none - no specific policy
- # accept - always accept incoming connections
- # master - become master on incoming connections,
- # deny role switch on outgoing connections
- lm accept;
-
- # Default link policy
- # none - no specific policy
- # rswitch - allow role switch
- # hold - allow hold mode
- # sniff - allow sniff mode
- # park - allow park mode
- lp rswitch,hold,sniff,park;
-}
diff --git a/data/input.conf b/data/input.conf
index 0fe7b0b..abfb64f 100644
--- a/data/input.conf
+++ b/data/input.conf
@@ -1,5 +1,9 @@
-[Bluetooth Service]
-Identifier=input
-Name=Input service
-Description=Bluetooth HID based Input service
-Autostart=false
+# Configuration file for the input service
+
+# This section contains options which are not specific to any
+# particular interface
+[General]
+
+# Set idle timeout (in minutes) before the connection will
+# be disconnect (defaults to 0 for no timeout)
+#IdleTimeout=30
diff --git a/data/main.conf b/data/main.conf
new file mode 100644
index 0000000..8153eb2
--- /dev/null
+++ b/data/main.conf
@@ -0,0 +1,59 @@
+[General]
+
+# List of plugins that should not be loaded on bluetoothd startup
+#DisablePlugins = network,input
+
+# Default adaper name
+# %h - substituted for hostname
+# %d - substituted for adapter id
+# %b - substituted for ro.product.brand
+# %m - substituted for ro.product.model
+# %n - substituted for ro.product.name
+Name = %m
+
+# Default device class. Only the major and minor device class bits are
+# considered.
+# Local device class
+# 0x400000 - Service class: Telephony
+# 0x000200 - Major class: Phone
+# 0x00000C - Minor class: Smart phone
+Class = 0x40020C
+
+# How long to stay in discoverable mode before going back to non-discoverable
+# The value is in seconds. Default is 180, i.e. 3 minutes.
+# 0 = disable timer, i.e. stay discoverable forever
+DiscoverableTimeout = 120
+
+# How long to stay in pairable mode before going back to non-discoverable
+# The value is in seconds. Default is 0.
+# 0 = disable timer, i.e. stay pairable forever
+PairableTimeout = 0
+
+# Use some other page timeout than the controller default one
+# which is 16384 (10 seconds).
+PageTimeout = 8192
+
+# Discover scheduler interval used in Adapter.DiscoverDevices
+# The value is in seconds. Defaults is 0 to use controller scheduler.
+DiscoverSchedulerInterval = 0
+
+# What value should be assumed for the adapter Powered property when
+# SetProperty(Powered, ...) hasn't been called yet. Defaults to true
+InitiallyPowered = true
+
+# Remember the previously stored Powered state when initializing adapters
+RememberPowered = true
+
+# Use vendor, product and version information for DID profile support.
+# The values are separated by ":" and VID, PID and version.
+DeviceID = android:generic:1.5
+
+# Do reverse service discovery for previously unknown devices that connect to
+# us. This option is really only needed for qualification since the BITE tester
+# doesn't like us doing reverse SDP for some test cases (though there could in
+# theory be other useful purposes for this too). Defaults to true.
+ReverseServiceDiscovery = true
+
+# Enable name resolving after inquiry. Set it to 'false' if you don't need
+# remote devices name and want shorter discovery cycle. Defaults to 'true'.
+NameResolving = true
diff --git a/tools/Android.mk b/tools/Android.mk
new file mode 100644
index 0000000..87dedad
--- /dev/null
+++ b/tools/Android.mk
@@ -0,0 +1,150 @@
+BUILD_EXTRA_BT_TOOLS:=false
+
+LOCAL_PATH:= $(call my-dir)
+
+#
+# bttest
+#
+
+include $(CLEAR_VARS)
+
+LOCAL_SRC_FILES := bttest.c
+
+LOCAL_C_INCLUDES := \
+ $(LOCAL_PATH)/../bluedroid/include \
+ system/bluetooth/bluez-clean-headers
+
+LOCAL_SHARED_LIBRARIES := libbluedroid
+
+LOCAL_MODULE_PATH := $(TARGET_OUT_OPTIONAL_EXECUTABLES)
+LOCAL_MODULE_TAGS := eng
+LOCAL_MODULE := bttest
+
+include $(BUILD_EXECUTABLE)
+
+ifeq ($(BUILD_EXTRA_BT_TOOLS),true)
+
+#
+# socktest
+#
+
+include $(CLEAR_VARS)
+
+LOCAL_SRC_FILES := socktest.c
+
+LOCAL_C_INCLUDES := \
+ $(LOCAL_PATH)/../bluedroid/include \
+ $(LOCAL_PATH)/../bluez-clean-headers
+
+LOCAL_SHARED_LIBRARIES := libbluedroid
+
+LOCAL_MODULE_PATH := $(TARGET_OUT_OPTIONAL_EXECUTABLES)
+LOCAL_MODULE_TAGS := eng
+LOCAL_MODULE := socktest
+
+include $(BUILD_EXECUTABLE)
+
+#
+# asocket_test
+#
+
+include $(CLEAR_VARS)
+
+LOCAL_SRC_FILES := asocket_test.c
+
+LOCAL_C_INCLUDES := \
+ $(LOCAL_PATH)/../bluez-clean-headers
+
+LOCAL_SHARED_LIBRARIES := libcutils
+
+LOCAL_MODULE_PATH := $(TARGET_OUT_OPTIONAL_EXECUTABLES)
+LOCAL_MODULE_TAGS := eng
+LOCAL_MODULE := asocket_test
+
+include $(BUILD_EXECUTABLE)
+
+#
+# sock_shutdown_test
+#
+
+include $(CLEAR_VARS)
+
+LOCAL_SRC_FILES := sock_shutdown_test.c
+
+LOCAL_C_INCLUDES := \
+ $(LOCAL_PATH)/../bluez-clean-headers
+
+LOCAL_MODULE_PATH := $(TARGET_OUT_OPTIONAL_EXECUTABLES)
+LOCAL_MODULE_TAGS := eng
+LOCAL_MODULE := sock_shutdown_test
+
+include $(BUILD_EXECUTABLE)
+
+#
+# sock_shutdown_bug_l2cap
+#
+
+include $(CLEAR_VARS)
+
+LOCAL_SRC_FILES := sock_shutdown_bug_l2cap.c
+
+LOCAL_C_INCLUDES := \
+ $(LOCAL_PATH)/../bluez-clean-headers
+
+LOCAL_MODULE_PATH := $(TARGET_OUT_OPTIONAL_EXECUTABLES)
+LOCAL_MODULE_TAGS := eng
+LOCAL_MODULE := sock_shutdown_bug_l2cap
+
+LOCAL_SHARED_LIBRARIES := libbluetooth
+
+include $(BUILD_EXECUTABLE)
+
+#
+# sock_shutdown_bug_rfcomm
+#
+
+include $(CLEAR_VARS)
+
+LOCAL_SRC_FILES := sock_shutdown_bug_rfcomm.c
+
+LOCAL_C_INCLUDES := \
+ $(LOCAL_PATH)/../bluez-clean-headers
+
+LOCAL_MODULE_PATH := $(TARGET_OUT_OPTIONAL_EXECUTABLES)
+LOCAL_MODULE_TAGS := eng
+LOCAL_MODULE := sock_shutdown_bug_rfcomm
+
+LOCAL_SHARED_LIBRARIES := libbluetooth
+
+include $(BUILD_EXECUTABLE)
+
+#
+# sock_shutdown_bug_tcp
+#
+
+include $(CLEAR_VARS)
+
+LOCAL_SRC_FILES := sock_shutdown_bug_tcp.c
+
+LOCAL_MODULE_PATH := $(TARGET_OUT_OPTIONAL_EXECUTABLES)
+LOCAL_MODULE_TAGS := eng
+LOCAL_MODULE := sock_shutdown_bug_tcp
+
+LOCAL_SHARED_LIBRARIES := libbluetooth
+
+include $(BUILD_EXECUTABLE)
+#
+# pipetest
+#
+
+include $(CLEAR_VARS)
+
+LOCAL_SRC_FILES := pipetest.c
+
+LOCAL_MODULE_PATH := $(TARGET_OUT_OPTIONAL_EXECUTABLES)
+LOCAL_MODULE_TAGS := eng
+LOCAL_MODULE := pipetest
+
+include $(BUILD_EXECUTABLE)
+
+endif
diff --git a/tools/asocket_test.c b/tools/asocket_test.c
new file mode 100644
index 0000000..0c00526
--- /dev/null
+++ b/tools/asocket_test.c
@@ -0,0 +1,742 @@
+/*
+** Copyright 2009 The Android Open Source Project
+**
+** 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.
+*/
+
+/** socket testing */
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <errno.h>
+#include <sys/uio.h>
+#include <unistd.h>
+
+#include <pthread.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <errno.h>
+#include <unistd.h>
+#include <sys/socket.h>
+#include <sys/ioctl.h>
+#include <sys/poll.h>
+#include <sys/un.h>
+#include <netinet/in.h>
+
+#include <bluetooth/bluetooth.h>
+#include <bluetooth/rfcomm.h>
+#include <bluetooth/sco.h>
+#include <bluetooth/l2cap.h>
+
+#include "cutils/abort_socket.h"
+
+enum sock_type {
+ UNIX = 0,
+ RFCOMM,
+ SCO,
+ L2CAP,
+ TCP,
+};
+
+struct thread_args {
+ int fd;
+ int type;
+ int delay;
+};
+
+struct sockaddr_un local_addr_un = {AF_UNIX, "/data/foo"};
+struct sockaddr_rc local_addr_rc = {AF_BLUETOOTH, *BDADDR_ANY, 4};
+struct sockaddr_sco local_addr_sco = {AF_BLUETOOTH, *BDADDR_LOCAL};
+struct sockaddr_l2 local_addr_l2 = {AF_BLUETOOTH, htobs(0x1001), *BDADDR_ANY, 0};
+struct sockaddr_in local_addr_in = {AF_INET, 9999, {0}, {0}};
+
+struct sockaddr_un remote_addr_un ;
+struct sockaddr_rc remote_addr_rc ;
+struct sockaddr_sco remote_addr_sco ;
+struct sockaddr_l2 remote_addr_l2 ;
+struct sockaddr_in remote_addr_in ;
+
+static void print_events(int events) {
+ if (events & POLLIN) printf("POLLIN ");
+ if (events & POLLPRI) printf("POLLPRI ");
+ if (events & POLLOUT) printf("POLLOUT ");
+ if (events & POLLERR) printf("POLLERR ");
+ if (events & POLLHUP) printf("POLLHUP ");
+ if (events & POLLNVAL) printf("POLLNVAL ");
+ printf("\n");
+}
+
+static void print_fds(struct pollfd *ufds, nfds_t nfds) {
+ unsigned int i;
+ for (i=0; i<nfds; i++)
+ printf("%d ", ufds[i].fd);
+}
+
+static int _socket(int type) {
+ int ret;
+ int family = -1;
+ int typ = -1;
+ int protocol = -1;
+
+ switch (type) {
+ case UNIX:
+ family = PF_UNIX;
+ typ = SOCK_STREAM;
+ protocol = 0;
+ break;
+ case RFCOMM:
+ family = PF_BLUETOOTH;
+ typ = SOCK_STREAM;
+ protocol = BTPROTO_RFCOMM;
+ break;
+ case SCO:
+ family = PF_BLUETOOTH;
+ typ = SOCK_SEQPACKET;
+ protocol = BTPROTO_SCO;
+ break;
+ case L2CAP:
+ family = PF_BLUETOOTH;
+ typ = SOCK_SEQPACKET;
+ protocol = BTPROTO_L2CAP;
+ break;
+ case TCP:
+ family = PF_INET;
+ typ = SOCK_STREAM;
+ protocol = 0;
+ break;
+ }
+
+ printf("%d: socket()\n", gettid());
+ ret = socket(family, typ, protocol);
+ printf("%d: socket() = %d\n", gettid(), ret);
+ if (ret < 0) printf("\terr %d (%s)\n", errno, strerror(errno));
+
+ return ret;
+}
+
+static int _close(int fd, int type) {
+ int ret;
+
+ printf("%d: close(%d)\n", gettid(), fd);
+ ret = close(fd);
+ printf("%d: close(%d) = %d\n", gettid(), fd, ret);
+ if (ret < 0) printf("\terr %d (%s)\n", errno, strerror(errno));
+
+ return ret;
+}
+
+static int _bind(int fd, int type) {
+ int len = 0;
+ int ret;
+ struct sockaddr *addr = NULL;
+
+ switch (type) {
+ case UNIX:
+ unlink(local_addr_un.sun_path);
+ addr = (struct sockaddr *) &local_addr_un;
+ len = sizeof(local_addr_un);
+ break;
+ case RFCOMM:
+ addr = (struct sockaddr *) &local_addr_rc;
+ len = sizeof(local_addr_rc);
+ break;
+ case SCO:
+ addr = (struct sockaddr *) &local_addr_sco;
+ len = sizeof(local_addr_sco);
+ break;
+ case L2CAP:
+ addr = (struct sockaddr *) &local_addr_l2;
+ len = sizeof(local_addr_l2);
+ break;
+ case TCP:
+ addr = (struct sockaddr *) &local_addr_in;
+ len = sizeof(local_addr_in);
+ break;
+ }
+
+ printf("%d: bind(%d)\n", gettid(), fd);
+ ret = bind(fd, addr, len);
+ printf("%d: bind(%d) = %d\n", gettid(), fd, ret);
+ if (ret < 0) printf("\terr %d (%s)\n", errno, strerror(errno));
+
+ return ret;
+}
+
+static int _listen(int fd, int type) {
+ int ret;
+
+ printf("%d: listen(%d)\n", gettid(), fd);
+ ret = listen(fd, 1);
+ printf("%d: listen(%d) = %d\n", gettid(), fd, ret);
+ if (ret < 0) printf("\terr %d (%s)\n", errno, strerror(errno));
+
+ return ret;
+}
+
+static int _read(int fd) {
+ int ret;
+ char buf;
+
+ printf("%d: read(%d)\n", gettid(), fd);
+ ret = read(fd, &buf, 1);
+ printf("%d: read(%d) = %d [%d]\n", gettid(), fd, ret, (int)buf);
+ if (ret < 0) printf("\terr %d (%s)\n", errno, strerror(errno));
+
+ return ret;
+}
+
+
+static int _accept(int fd, int type) {
+ int ret;
+ int len;
+ struct sockaddr *addr = NULL;
+
+ switch (type) {
+ case UNIX:
+ addr = (struct sockaddr *) &remote_addr_un;
+ len = sizeof(remote_addr_un);
+ break;
+ case RFCOMM:
+ addr = (struct sockaddr *) &remote_addr_rc;
+ len = sizeof(remote_addr_rc);
+ break;
+ case SCO:
+ addr = (struct sockaddr *) &remote_addr_sco;
+ len = sizeof(remote_addr_sco);
+ break;
+ case L2CAP:
+ addr = (struct sockaddr *) &remote_addr_l2;
+ len = sizeof(remote_addr_l2);
+ break;
+ case TCP:
+ addr = (struct sockaddr *) &remote_addr_in;
+ len = sizeof(remote_addr_in);
+ break;
+ }
+
+ printf("%d: accept(%d)\n", gettid(), fd);
+ ret = accept(fd, addr, &len);
+ printf("%d: accept(%d) = %d\n", gettid(), fd, ret);
+ if (ret < 0) printf("\terr %d (%s)\n", errno, strerror(errno));
+ else {
+ printf("\tlen = %d\n", len);
+ }
+
+ return ret;
+}
+
+static int _connect(int fd, int type) {
+ int ret;
+ int len = 0;
+ struct sockaddr *addr = NULL;
+
+ switch (type) {
+ case UNIX:
+ addr = (struct sockaddr *) &local_addr_un;
+ len = sizeof(local_addr_un);
+ break;
+ case RFCOMM:
+ addr = (struct sockaddr *) &local_addr_rc;
+ len = sizeof(local_addr_rc);
+ break;
+ case SCO:
+ addr = (struct sockaddr *) &local_addr_sco;
+ len = sizeof(local_addr_sco);
+ break;
+ case L2CAP:
+ addr = (struct sockaddr *) &local_addr_l2;
+ len = sizeof(local_addr_l2);
+ break;
+ case TCP:
+ addr = (struct sockaddr *) &local_addr_in;
+ len = sizeof(local_addr_in);
+ break;
+ }
+
+ printf("%d: connect(%d)\n", gettid(), fd);
+ ret = connect(fd, addr, len);
+ printf("%d: connect(%d) = %d\n", gettid(), fd, ret);
+ if (ret < 0) printf("\terr %d (%s)\n", errno, strerror(errno));
+
+ return ret;
+}
+
+static int _write(int fd, int type) {
+ int ret;
+ char buf = 69;
+
+ printf("%d: write(%d)\n", gettid(), fd);
+ ret = write(fd, &buf, 1);
+ printf("%d: write(%d) = %d\n", gettid(), fd, ret);
+ if (ret < 0) printf("\terr %d (%s)\n", errno, strerror(errno));
+
+ return ret;
+}
+
+static int _shutdown(int fd, int how) {
+ int ret;
+
+ printf("%d: shutdown(%d)\n", gettid(), fd);
+ ret = shutdown(fd, how);
+ printf("%d: shutdown(%d) = %d\n", gettid(), fd, ret);
+ if (ret < 0) printf("\terr %d (%s)\n", errno, strerror(errno));
+
+ return ret;
+}
+
+static int _poll(struct pollfd *ufds, nfds_t nfds, int timeout) {
+ int ret;
+ unsigned int i;
+
+ printf("%d: poll(", gettid());
+ print_fds(ufds, nfds);
+ printf(")\n");
+ ret = poll(ufds, nfds, timeout);
+ printf("%d: poll() = %d\n", gettid(), ret);
+ if (ret < 0) printf("\terr %d (%s)\n", errno, strerror(errno));
+ if (ret > 0) {
+ for (i=0; i<nfds; i++) {
+ if (ufds[i].revents) {
+ printf("\tfd %d ", ufds[i].fd); print_events(ufds[i].revents);
+ }
+ }
+ }
+ return ret;
+}
+
+static void thread_delay_close(struct thread_args *args) {
+ printf("%d: START\n", gettid());
+ sleep(args->delay);
+ _close(args->fd, args->type);
+ printf("%d: END\n", gettid());
+}
+
+static void thread_poll(void *args) {
+ int fd = (int)args;
+ struct pollfd pfd;
+ printf("%d: START\n", gettid());
+ pfd.fd = fd;
+ pfd.events = 0;
+ _poll(&pfd, 1, -1);
+ printf("%d: END\n", gettid());
+}
+
+static void thread_read(void *args) {
+ int fd = (int)args;
+ printf("%d: START\n", gettid());
+ _read(fd);
+ printf("%d: END\n", gettid());
+}
+
+static void thread_pollin(void *args) {
+ int fd = (int)args;
+ struct pollfd pfd;
+ printf("%d: START\n", gettid());
+ pfd.fd = fd;
+ pfd.events = POLLIN;
+ _poll(&pfd, 1, -1);
+ printf("%d: END\n", gettid());
+}
+
+static void thread_shutdown(int fd) {
+ printf("%d: START\n", gettid());
+ sleep(4);
+ _shutdown(fd, SHUT_RDWR);
+ printf("%d: END\n", gettid());
+}
+
+static void thread_accept(struct thread_args *args) {
+ printf("%d: START\n", gettid());
+ sleep(args->delay);
+ _accept(args->fd, args->type);
+ printf("%d: END\n", gettid());
+}
+
+static void thread_connect(struct thread_args *args) {
+ printf("%d: START\n", gettid());
+ sleep(args->delay);
+ _connect(args->fd, args->type);
+ printf("%d: END\n", gettid());
+}
+
+static void thread_delay_close_write(struct thread_args *args) {
+ printf("%d: START\n", gettid());
+ sleep(args->delay);
+ _close(args->fd, args->type);
+ sleep(args->delay);
+ _write(args->fd, args->type);
+ printf("%d: END\n", gettid());
+}
+
+static void thread_accept_write(struct thread_args *args) {
+ printf("%d: START\n", gettid());
+ sleep(args->delay);
+ _accept(args->fd, args->type);
+ sleep(args->delay);
+ _write(args->fd, args->type);
+ printf("%d: END\n", gettid());
+}
+
+static void thread_delay_connect(struct thread_args *args) {
+ printf("%d: START\n", gettid());
+ sleep(args->delay);
+ args->fd = _socket(args->type);
+ _connect(args->fd, args->type);
+ printf("%d: END\n", gettid());
+}
+
+static int do_accept_accept_accept(int type) {
+ int fd;
+
+ fd = _socket(type);
+ if (fd < 0) goto error;
+
+ if (_bind(fd, type) < 0) goto error;
+
+ if (_listen(fd, type) < 0) goto error;
+
+ while (1) {
+ _accept(fd, type);
+ }
+
+ return 0;
+
+error:
+ return -1;
+}
+
+static int do_accept_and_close(int type) {
+ int fd;
+ pthread_t thread;
+ struct thread_args args = {-1, type, 1};
+
+ fd = _socket(type);
+ if (fd < 0) goto error;
+
+ if (_bind(fd, type) < 0) goto error;
+
+ if (_listen(fd, type) < 0) goto error;
+
+ args.fd = fd;
+ pthread_create(&thread, NULL, (void *)thread_delay_close, (void *)&args);
+
+ _accept(fd, type);
+
+ pthread_join(thread, NULL);
+
+ return 0;
+
+error:
+ return -1;
+}
+
+static int do_accept_shutdown(int type) {
+ int fd;
+ pthread_t thread;
+ struct thread_args args = {-1, type, 0};
+
+ fd = _socket(type);
+ if (fd < 0) goto error;
+
+ if (_bind(fd, type) < 0) goto error;
+
+ if (_listen(fd, type) < 0) goto error;
+
+ args.fd = fd;
+ pthread_create(&thread, NULL, (void *)thread_accept, (void *)&args);
+
+ sleep(4);
+ _shutdown(fd, SHUT_RDWR);
+
+ pthread_join(thread, NULL);
+
+ _close(fd, type);
+
+ return 0;
+
+error:
+ return -1;
+}
+
+static int do_connect_shutdown(int type) {
+ int fd;
+ pthread_t thread;
+ struct thread_args args = {-1, type, 0};
+
+ fd = _socket(type);
+ if (fd < 0) goto error;
+
+ args.fd = fd;
+ pthread_create(&thread, NULL, (void *)thread_connect, (void *)&args);
+
+ sleep(4);
+ _shutdown(fd, SHUT_RDWR);
+
+ pthread_join(thread, NULL);
+
+ _close(fd, type);
+
+ return 0;
+
+error:
+ return -1;
+}
+
+// accept in one thread. close then write in another
+static int do_accept_close_write(int type) {
+ int fd;
+ pthread_t thread;
+ struct thread_args args = {-1, type, 1};
+
+ fd = _socket(type);
+ if (fd < 0) goto error;
+
+ if (_bind(fd, type) < 0) goto error;
+
+ if (_listen(fd, type) < 0) goto error;
+
+ args.fd = fd;
+ pthread_create(&thread, NULL, (void *)thread_delay_close_write, (void *)&args);
+
+ _accept(fd, type);
+
+ pthread_join(thread, NULL);
+
+ return 0;
+
+error:
+ return -1;
+}
+
+static int do_poll_poll_poll_shutdown(int type) {
+ const int MAX_T = 32;
+ int fd;
+ pthread_t t[MAX_T];
+ int i;
+
+ fd = _socket(type);
+
+ for (i=0; i<MAX_T; i++)
+ pthread_create(&t[i], NULL, (void *)thread_poll, (void *)fd);
+
+ sleep(1);
+
+ _shutdown(fd, SHUT_RDWR);
+
+ for (i=0; i<MAX_T; i++)
+ pthread_join(t[i], NULL);
+
+ _close(fd, type);
+
+ return 0;
+}
+
+static int do_poll_poll_poll_close(int type) {
+ const int MAX_T = 32;
+ int fd;
+ pthread_t t[MAX_T];
+ int i;
+
+ fd = _socket(type);
+
+ for (i=0; i<MAX_T; i++)
+ pthread_create(&t[i], NULL, (void *)thread_poll, (void *)fd);
+
+ sleep(1);
+
+ _close(fd, type);
+
+ for (i=0; i<MAX_T; i++)
+ pthread_join(t[i], NULL);
+
+ return 0;
+}
+
+static int do_read_read_read_close(int type) {
+ const int MAX_T = 32;
+ int fd;
+ pthread_t t[MAX_T];
+ int i;
+
+ fd = _socket(type);
+
+ for (i=0; i<MAX_T; i++)
+ pthread_create(&t[i], NULL, (void *)thread_read, (void *)fd);
+
+ sleep(1);
+
+ _close(fd, type);
+
+ for (i=0; i<MAX_T; i++)
+ pthread_join(t[i], NULL);
+
+ return 0;
+}
+
+static int do_read_read_read_shutdown(int type) {
+ const int MAX_T = 32;
+ int fd;
+ pthread_t t[MAX_T];
+ int i;
+
+ fd = _socket(type);
+
+ for (i=0; i<MAX_T; i++)
+ pthread_create(&t[i], NULL, (void *)thread_read, (void *)fd);
+
+ sleep(1);
+
+ _shutdown(fd, SHUT_RDWR);
+
+ for (i=0; i<MAX_T; i++)
+ pthread_join(t[i], NULL);
+
+ _close(fd, type);
+
+ return 0;
+}
+
+static int do_connected_read1_shutdown1(int type) {
+ int fd1, fd2;
+ pthread_t t1;
+ pthread_t t2;
+ struct thread_args a1 = {-1, type, 0};
+ struct thread_args a2 = {-1, type, 2};
+
+ fd1 = _socket(type);
+ if (fd1 < 0) goto error;
+
+ if (_bind(fd1, type) < 0) goto error;
+
+ if (_listen(fd1, type) < 0) goto error;
+
+ a1.fd = fd1;
+ pthread_create(&t1, NULL, (void *)thread_accept_write, (void *)&a1);
+
+ fd2 = _socket(type);
+ if (_connect(fd2, type)) goto error;
+
+ pthread_create(&t2, NULL, (void *)thread_shutdown, (void *)&fd2);
+
+ while (1) if (_read(fd2)) break;
+
+ pthread_join(t1, NULL);
+ pthread_join(t2, NULL);
+
+ return 0;
+
+error:
+ return -1;
+}
+
+// accept in one thread, connect from two different threads
+static int do_accept_connect_connect(int type) {
+ int fd;
+ pthread_t t1;
+ pthread_t t2;
+ struct thread_args a1 = {-1, type, 1};
+ struct thread_args a2 = {-1, type, 2};
+
+ fd = _socket(type);
+ if (fd < 0) goto error;
+
+ if (_bind(fd, type) < 0) goto error;
+
+ if (_listen(fd, type) < 0) goto error;
+
+ pthread_create(&t1, NULL, (void *)thread_delay_connect, (void *)&a1);
+ pthread_create(&t2, NULL, (void *)thread_delay_connect, (void *)&a2);
+
+ _accept(fd, type);
+
+ pthread_join(t1, NULL);
+ pthread_join(t2, NULL);
+
+ return 0;
+
+error:
+ return -1;
+}
+
+struct {
+ char *name;
+ int (*ptr)(int);
+} action_table[] = {
+ {"accept_accept_accept", do_accept_accept_accept},
+ {"accept_and_close", do_accept_and_close},
+ {"accept_shutdown", do_accept_shutdown},
+ {"connect_shutdown", do_connect_shutdown},
+ {"accept_close_write", do_accept_close_write},
+ {"accept_connect_connect", do_accept_connect_connect},
+ {"poll_poll_poll_shutdown", do_poll_poll_poll_shutdown},
+ {"poll_poll_poll_close", do_poll_poll_poll_close},
+ {"read_read_read_shutdown", do_read_read_read_shutdown},
+ {"read_read_read_close", do_read_read_read_close},
+ {"connected_read1_shutdown1", do_connected_read1_shutdown1},
+ {NULL, NULL},
+};
+
+struct {
+ char *name;
+ enum sock_type type;
+} type_table[] = {
+ {"unix", UNIX},
+ {"rfcomm", RFCOMM},
+ {"sco", SCO},
+ {"l2cap", L2CAP},
+ {"tcp", TCP},
+ {NULL, -1},
+};
+
+static void usage() {
+ int i;
+
+ printf("socktest TYPE ACTION\n");
+ printf("\nTYPE:\n");
+ for (i = 0; type_table[i].name; i++) {
+ printf("\t%s\n", type_table[i].name);
+ }
+ printf("\nACTION:\n");
+ for (i = 0; action_table[i].name; i++) {
+ printf("\t%s\n", action_table[i].name);
+ }
+}
+
+int main(int argc, char **argv) {
+ int i;
+ int type = -1;
+
+ if (argc != 3) {
+ usage();
+ return -1;
+ }
+ for (i = 0; type_table[i].name; i++) {
+ if (!strcmp(argv[1], type_table[i].name)) {
+ type = type_table[i].type;
+ break;
+ }
+ }
+ if (type == -1) {
+ usage();
+ return -1;
+ }
+ for (i = 0; action_table[i].name; i++) {
+ if (!strcmp(argv[2], action_table[i].name)) {
+ printf("TYPE = %s ACTION = %s\n", type_table[type].name,
+ action_table[i].name);
+ return (*action_table[i].ptr)(type);
+ }
+ }
+ usage();
+ return -1;
+}
diff --git a/bluedroid/bttest.c b/tools/bttest.c
index 3a78ed5..3a78ed5 100644
--- a/bluedroid/bttest.c
+++ b/tools/bttest.c
diff --git a/tools/pipetest.c b/tools/pipetest.c
new file mode 100644
index 0000000..634e4b9
--- /dev/null
+++ b/tools/pipetest.c
@@ -0,0 +1,429 @@
+/*
+ * Copyright 2009 The Android Open Source Project
+ *
+ * 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.
+ */
+
+/* Helper to test linux pipe's */
+
+#include <pthread.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <errno.h>
+#include <unistd.h>
+#include <sys/poll.h>
+#include <sys/socket.h>
+
+static void print_events(int events) {
+ if (events & POLLIN) printf("POLLIN ");
+ if (events & POLLPRI) printf("POLLPRI ");
+ if (events & POLLOUT) printf("POLLOUT ");
+ if (events & POLLERR) printf("POLLERR ");
+ if (events & POLLHUP) printf("POLLHUP ");
+ if (events & POLLNVAL) printf("POLLNVAL ");
+ printf("\n");
+}
+
+static int _socketpair(int fd[2]) {
+ int ret;
+ printf("%d: socketpair()\n", gettid());
+ ret = socketpair(AF_UNIX, SOCK_STREAM, 0, fd);
+ printf("%d: socketpair() = %d\n", gettid(), ret);
+ if (ret) printf("\terr %d (%s)\n", errno, strerror(errno));
+ return ret;
+}
+
+static int _close(int fd) {
+ int ret;
+ printf("%d: close(%d)\n", gettid(), fd);
+ ret = close(fd);
+ printf("%d: close(%d) = %d\n", gettid(), fd, ret);
+ if (ret) printf("\terr %d (%s)\n", errno, strerror(errno));
+ return ret;
+}
+
+static int _poll(struct pollfd *ufds, nfds_t nfds, int timeout) {
+ int ret;
+ unsigned int i;
+ printf("%d: poll()\n", gettid());
+ ret = poll(ufds, nfds, timeout);
+ printf("%d: poll() = %d\n", gettid(), ret);
+ if (ret < 0) printf("\terr %d (%s)\n", errno, strerror(errno));
+ if (ret > 0) {
+ for (i=0; i<nfds; i++) {
+ if (ufds[i].revents) {
+ printf("\tfd %d ", ufds[i].fd); print_events(ufds[i].revents);
+ }
+ }
+ }
+ return ret;
+}
+
+static int _write(int fd, char *buf, int len) {
+ int ret;
+
+ printf("%d: write(%d)\n", gettid(), fd);
+ ret = write(fd, buf, len);
+ printf("%d: write(%d) = %d\n", gettid(), fd, ret);
+ if (ret < 0) printf("\terr %d (%s)\n", errno, strerror(errno));
+
+ return ret;
+}
+
+static int _read(int fd) {
+ int ret;
+ char buf;
+
+ printf("%d: read(%d)\n", gettid(), fd);
+ ret = read(fd, &buf, 1);
+ printf("%d: read(%d) = %d [%d]\n", gettid(), fd, ret, (int)buf);
+ if (ret < 0) printf("\terr %d (%s)\n", errno, strerror(errno));
+
+ return ret;
+}
+
+static int _shutdown(int fd, int how) {
+ int ret;
+
+ printf("%d: shutdown(%d)\n", gettid(), fd);
+ ret = shutdown(fd, how);
+ printf("%d: shutdown(%d) = %d\n", gettid(), fd, ret);
+ if (ret < 0) printf("\terr %d (%s)\n", errno, strerror(errno));
+
+ return ret;
+}
+static void thread_poll(void *args) {
+ int fd = (int)args;
+ struct pollfd pfd;
+ printf("%d: START\n", gettid());
+ pfd.fd = fd;
+ pfd.events = 0;
+ _poll(&pfd, 1, -1);
+ printf("%d: END\n", gettid());
+}
+
+static void thread_pollin(void *args) {
+ int fd = (int)args;
+ struct pollfd pfd;
+ printf("%d: START\n", gettid());
+ pfd.fd = fd;
+ pfd.events = POLLIN;
+ _poll(&pfd, 1, -1);
+ printf("%d: END\n", gettid());
+}
+
+static void thread_pollin_rand_delay(void *args) {
+ int fd = (int)args;
+ struct pollfd pfd;
+ int delay = (int)((double)random() * (10000000.0 / 2147483647.0));
+ printf("%d: START (delay = %d)\n", gettid(), delay);
+ pfd.fd = fd;
+ pfd.events = POLLIN;
+ usleep(delay);
+ _poll(&pfd, 1, -1);
+ printf("%d: END\n", gettid());
+}
+
+static void thread_read(void *args) {
+ int fd = (int)args;
+ printf("%d: START\n", gettid());
+ _read(fd);
+ printf("%d: END\n", gettid());
+}
+
+static void thread_close(void *args) {
+ int fd = (int)args;
+ printf("%d: START\n", gettid());
+ _close(fd);
+ printf("%d: END\n", gettid());
+}
+
+static int do_poll_poll_close() {
+ pthread_t t1;
+ pthread_t t2;
+ int fd[2];
+
+ if (pipe(fd)) return -1;
+
+ pthread_create(&t1, NULL, (void *)thread_poll, NULL);
+ pthread_create(&t2, NULL, (void *)thread_poll, NULL);
+
+ sleep(1);
+
+ _close(fd[1]);
+
+ pthread_join(t1, NULL);
+ pthread_join(t2, NULL);
+
+ return 0;
+}
+
+static int do_socketpair_poll1_shutdown2() {
+ int fd[2];
+ pthread_t t;
+
+ if (_socketpair(fd)) return -1;
+
+ pthread_create(&t, NULL, (void *)thread_poll, (void *)fd[1]);
+
+ sleep(1);
+
+ _shutdown(fd[0], SHUT_RDWR);
+
+ sleep(1);
+
+ _close(fd[0]);
+
+ pthread_join(t, NULL);
+
+ return 0;
+}
+
+static int do_socketpair_poll1_shutdown1() {
+ int fd[2];
+ pthread_t t;
+
+ if (_socketpair(fd)) return -1;
+
+ pthread_create(&t, NULL, (void *)thread_poll, (void *)fd[0]);
+
+ sleep(1);
+
+ _shutdown(fd[0], SHUT_RDWR);
+
+ sleep(1);
+
+ _close(fd[0]);
+
+ pthread_join(t, NULL);
+
+ return 0;
+}
+
+static int do_socketpair_poll1_close1() {
+ int fd[2];
+ pthread_t t;
+
+ if (_socketpair(fd)) return -1;
+
+ pthread_create(&t, NULL, (void *)thread_poll, (void *)fd[0]);
+
+ sleep(1);
+
+ _close(fd[0]);
+
+ pthread_join(t, NULL);
+
+ return 0;
+}
+
+static int do_socketpair_read1_shutdown1() {
+ int fd[2];
+ pthread_t t;
+
+ if (_socketpair(fd)) return -1;
+
+ pthread_create(&t, NULL, (void *)thread_read, (void *)fd[0]);
+
+ sleep(1);
+
+ _shutdown(fd[0], SHUT_RDWR);
+
+ sleep(1);
+
+ _close(fd[0]);
+
+ pthread_join(t, NULL);
+
+ return 0;
+}
+
+static int do_pipe_pipe_pipe() {
+ int fd[2];
+ int i;
+
+ while (1) {
+ if (pipe(fd)) {
+ printf("pipe: %s\n", strerror(errno));
+ return -1;
+ }
+ printf("%d %d\n", fd[0], fd[1]);
+ close(fd[0]);
+ close(fd[1]);
+ }
+
+ return 0;
+}
+static int do_pollin_pollin_write() {
+ pthread_t t1;
+ pthread_t t2;
+ int fd[2];
+ char buf = 'a';
+ int i;
+
+ if (pipe(fd)) return -1;
+
+ pthread_create(&t1, NULL, (void *)thread_pollin, (void *)fd[0]);
+ pthread_create(&t2, NULL, (void *)thread_pollin, (void *)fd[0]);
+
+ sleep(1);
+
+ for (i = 0; i < 100; i++)
+ _write(fd[1], &buf, 1);
+
+ pthread_join(t1, NULL);
+ pthread_join(t2, NULL);
+
+ return 0;
+}
+
+static int do_pollin_pollin_pollin_write_pollin_pollin_pollin() {
+ const int MAX_T = 10;
+ pthread_t t[MAX_T];
+ int fd[2];
+ char buf = 'a';
+ int i;
+
+ if (pipe(fd)) return -1;
+
+ for (i=0; i<MAX_T; i++)
+ pthread_create(&t[i], NULL, (void *)thread_pollin_rand_delay, (void *)fd[0]);
+
+ sleep(5);
+
+ _write(fd[1], &buf, 1);
+
+ for (i=0; i<MAX_T; i++)
+ pthread_join(t[i], NULL);
+
+ _close(fd[0]);
+ _close(fd[1]);
+
+ return 0;
+}
+
+static int do_poll_poll_shutdown() {
+#if 0
+ pthread_t t1;
+ pthread_t t2;
+ int fd[2];
+
+ if (pipe(fd)) return -1;
+
+ pthread_create(&t1, NULL, (void *)thread_poll, (void *)fd[0]);
+ pthread_create(&t2, NULL, (void *)thread_poll, (void *)fd[0]);
+
+ sleep(1);
+
+ _shutdown(fd[1], SHUT_RDWR);
+
+ pthread_join(t1, NULL);
+ pthread_join(t2, NULL);
+#endif
+
+ return -1;
+}
+
+static int THREADS = 100;
+
+static int do_close_poll_poll_poll() {
+ pthread_t t[THREADS];
+ int i;
+ int fd[2];
+
+ if (pipe(fd)) return -1;
+
+ _close(fd[1]);
+
+ for (i = 0; i < THREADS; i++)
+ pthread_create(&t[i], NULL, (void *)thread_poll, (void *)fd[0]);
+
+ for (i = 0; i < THREADS; i++)
+ pthread_join(t[i], NULL);
+
+ return 0;
+}
+
+static int do_close_close_close() {
+ pthread_t t[THREADS];
+ int i;
+ int fd[2];
+
+ if (pipe(fd)) return -1;
+
+ for (i = 0; i < THREADS; i++)
+ pthread_create(&t[i], NULL, (void *)thread_close, (void *)fd[i%2]);
+
+ return 0;
+}
+
+static int pipe_close_w_close_r_repeat() {
+ int fd[2];
+ pthread_t t;
+ int i;
+
+ for (i = 0; i < THREADS; i++) {
+ if (pipe(fd)) return -1;
+ pthread_create(&t, NULL, (void *)thread_poll, (void *)fd[0]);
+ _close(fd[1]);
+ _close(fd[0]);
+ pthread_join(t, NULL);
+ }
+
+ return 0;
+}
+
+struct {
+ char *name;
+ int (*ptr)();
+} function_table[] = {
+ {"socketpair_poll1_shutdown2", do_socketpair_poll1_shutdown2},
+ {"socketpair_poll1_shutdown1", do_socketpair_poll1_shutdown1},
+ {"socketpair_poll1_close1", do_socketpair_poll1_close1},
+ {"socketpair_read1_shutdown1", do_socketpair_read1_shutdown1},
+ {"pipe_pipe_pipe", do_pipe_pipe_pipe},
+ {"poll_poll_close", do_poll_poll_close},
+ {"pollin_pollin_write", do_pollin_pollin_write},
+ {"pollin_pollin_pollin_write_pollin_pollin_pollin", do_pollin_pollin_pollin_write_pollin_pollin_pollin},
+ {"poll_poll_shutdown", do_poll_poll_shutdown},
+ {"close_poll_poll_poll", do_close_poll_poll_poll},
+ {"close_close_close", do_close_close_close},
+ {"pipe_close_w_close_w_repeat", pipe_close_w_close_r_repeat},
+ {NULL, NULL},
+};
+
+static void usage() {
+ int i;
+
+ printf("Usage:\n");
+ for (i = 0; function_table[i].name; i++) {
+ printf("\tpipetest %s\n", function_table[i].name);
+ }
+}
+
+int main(int argc, char **argv) {
+ int i;
+
+ if (argc != 2) {
+ usage();
+ return -1;
+ }
+ for (i = 0; function_table[i].name; i++) {
+ if (!strcmp(argv[1], function_table[i].name)) {
+ printf("%s\n", function_table[i].name);
+ return (*function_table[i].ptr)();
+ }
+ }
+ usage();
+ return -1;
+}
diff --git a/tools/sock_shutdown_bug_l2cap.c b/tools/sock_shutdown_bug_l2cap.c
new file mode 100644
index 0000000..1bb2373
--- /dev/null
+++ b/tools/sock_shutdown_bug_l2cap.c
@@ -0,0 +1,47 @@
+/*
+** Copyright 2009 The Android Open Source Project
+**
+** 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 <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <sys/socket.h>
+#include <fcntl.h>
+
+#include <bluetooth/bluetooth.h>
+#include <bluetooth/l2cap.h>
+
+int main(int argc, char **argv) {
+ int fd;
+ int ret;
+ long flags;
+ struct sockaddr_l2 addr;
+
+ addr.l2_family = AF_BLUETOOTH;
+ str2ba("00:01:02:0A:0B:0C", &addr.l2_bdaddr);
+ addr.l2_psm = htobs(1);
+
+ fd = socket(PF_BLUETOOTH, SOCK_SEQPACKET, BTPROTO_L2CAP);
+ flags = fcntl(fd, F_GETFL);
+ fcntl(fd, F_SETFL, flags | O_NONBLOCK);
+
+ connect(fd, (struct sockaddr *)&addr, sizeof(addr));
+
+ sleep(1);
+ shutdown(fd, SHUT_RDWR);
+ sleep(1);
+ close(fd);
+ return 0;
+}
diff --git a/tools/sock_shutdown_bug_rfcomm.c b/tools/sock_shutdown_bug_rfcomm.c
new file mode 100644
index 0000000..7c4a37f
--- /dev/null
+++ b/tools/sock_shutdown_bug_rfcomm.c
@@ -0,0 +1,63 @@
+/*
+** Copyright 2009 The Android Open Source Project
+**
+** 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 <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <sys/socket.h>
+#include <fcntl.h>
+#include <errno.h>
+
+#include <bluetooth/bluetooth.h>
+#include <bluetooth/rfcomm.h>
+
+int main(int argc, char **argv) {
+ int fd;
+ int ret;
+ long flags;
+ struct sockaddr_rc addr;
+
+ addr.rc_family = AF_BLUETOOTH;
+ addr.rc_channel = 19;
+ str2ba("00:17:E8:2C:A8:00", &addr.rc_bdaddr);
+
+ fd = socket(PF_BLUETOOTH, SOCK_STREAM, BTPROTO_RFCOMM);
+ flags = fcntl(fd, F_GETFL);
+ fcntl(fd, F_SETFL, flags | O_NONBLOCK);
+
+ ret = connect(fd, (struct sockaddr *)&addr, sizeof(addr));
+ if (ret < 0) {
+ printf("%d errno %d %s\n", __LINE__, errno, strerror(errno));
+ }
+
+ sleep(2);
+ shutdown(fd, SHUT_RDWR);
+
+
+ fd = socket(PF_BLUETOOTH, SOCK_STREAM, BTPROTO_RFCOMM);
+
+ ret = connect(fd, (struct sockaddr *)&addr, sizeof(addr));
+ if (ret < 0) {
+ printf("%d errno %d %s\n", __LINE__, errno, strerror(errno));
+ }
+
+ sleep(2);
+
+ shutdown(fd, SHUT_RDWR);
+
+ sleep(2);
+ return 0;
+}
diff --git a/tools/sock_shutdown_bug_tcp.c b/tools/sock_shutdown_bug_tcp.c
new file mode 100644
index 0000000..6333320
--- /dev/null
+++ b/tools/sock_shutdown_bug_tcp.c
@@ -0,0 +1,63 @@
+/*
+** Copyright 2009 The Android Open Source Project
+**
+** 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 <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <sys/socket.h>
+#include <fcntl.h>
+#include <errno.h>
+#include <netinet/in.h>
+
+int main(int argc, char **argv) {
+ int fd;
+ int ret;
+ long flags;
+ struct sockaddr_in addr;
+
+ addr.sin_family = AF_INET;
+ addr.sin_port = 12348;
+
+ fd = socket(PF_INET, SOCK_STREAM, 0);
+
+ ret = bind(fd, (struct sockaddr *)&addr, sizeof(addr));
+ if (ret < 0) {
+ printf("%d errno %d %s\n", __LINE__, errno, strerror(errno));
+ }
+
+ ret = listen(fd, 1);
+ if (ret < 0) {
+ printf("%d errno %d %s\n", __LINE__, errno, strerror(errno));
+ }
+
+ sleep(2);
+
+ close(fd);
+
+ sleep(2);
+
+ fd = socket(PF_INET, SOCK_STREAM, 0);
+
+ ret = bind(fd, (struct sockaddr *)&addr, sizeof(addr));
+ if (ret < 0) {
+ printf("%d errno %d %s\n", __LINE__, errno, strerror(errno));
+ }
+
+ sleep(2000000000);
+
+ return 0;
+}
+
diff --git a/tools/sock_shutdown_test.c b/tools/sock_shutdown_test.c
new file mode 100644
index 0000000..29f6b59
--- /dev/null
+++ b/tools/sock_shutdown_test.c
@@ -0,0 +1,314 @@
+/*
+** Copyright 2009 The Android Open Source Project
+**
+** 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.
+*/
+
+/** testing behavior of shutdown() */
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <errno.h>
+#include <sys/uio.h>
+#include <unistd.h>
+
+#include <pthread.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <errno.h>
+#include <unistd.h>
+#include <sys/socket.h>
+#include <sys/ioctl.h>
+#include <sys/poll.h>
+#include <sys/un.h>
+#include <netinet/in.h>
+
+#include <bluetooth/bluetooth.h>
+#include <bluetooth/rfcomm.h>
+#include <bluetooth/sco.h>
+#include <bluetooth/l2cap.h>
+
+enum sock_type {
+ UNIX = 0,
+ RFCOMM,
+ SCO,
+ L2CAP,
+ TCP,
+};
+
+struct thread_args {
+ int fd;
+ int type;
+ int delay;
+};
+
+struct sockaddr_un local_addr_un = {AF_UNIX, "/tmp/foo"};
+struct sockaddr_rc local_addr_rc = {AF_BLUETOOTH, *BDADDR_ANY, 4};
+struct sockaddr_sco local_addr_sco = {AF_BLUETOOTH, *BDADDR_LOCAL};
+struct sockaddr_l2 local_addr_l2 = {AF_BLUETOOTH, htobs(0x1001), *BDADDR_ANY, 0};
+struct sockaddr_in local_addr_in = {AF_INET, 9999, {0}, {0}};
+
+struct sockaddr_un remote_addr_un ;
+struct sockaddr_rc remote_addr_rc ;
+struct sockaddr_sco remote_addr_sco ;
+struct sockaddr_l2 remote_addr_l2 ;
+struct sockaddr_in remote_addr_in ;
+
+static int _socket(int type) {
+ int ret;
+ int family = -1;
+ int typ = -1;
+ int protocol = -1;
+
+ switch (type) {
+ case UNIX:
+ family = PF_UNIX;
+ typ = SOCK_STREAM;
+ protocol = 0;
+ break;
+ case RFCOMM:
+ family = PF_BLUETOOTH;
+ typ = SOCK_STREAM;
+ protocol = BTPROTO_RFCOMM;
+ break;
+ case SCO:
+ family = PF_BLUETOOTH;
+ typ = SOCK_SEQPACKET;
+ protocol = BTPROTO_SCO;
+ break;
+ case L2CAP:
+ family = PF_BLUETOOTH;
+ typ = SOCK_SEQPACKET;
+ protocol = BTPROTO_L2CAP;
+ break;
+ case TCP:
+ family = PF_INET;
+ typ = SOCK_STREAM;
+ protocol = 0;
+ break;
+ }
+
+ printf("%d: socket()\n", gettid());
+ ret = socket(family, typ, protocol);
+ printf("%d: socket() = %d\n", gettid(), ret);
+ if (ret < 0) printf("\terr %d (%s)\n", errno, strerror(errno));
+
+ return ret;
+}
+
+static int _close(int fd) {
+ int ret;
+
+ printf("%d: close(%d)\n", gettid(), fd);
+ ret = close(fd);
+ printf("%d: close(%d) = %d\n", gettid(), fd, ret);
+ if (ret < 0) printf("\terr %d (%s)\n", errno, strerror(errno));
+
+ return ret;
+}
+
+static int _bind(int fd, int type) {
+ int len = 0;
+ int ret;
+ struct sockaddr *addr = NULL;
+
+ switch (type) {
+ case UNIX:
+ unlink(local_addr_un.sun_path);
+ addr = (struct sockaddr *) &local_addr_un;
+ len = sizeof(local_addr_un);
+ break;
+ case RFCOMM:
+ addr = (struct sockaddr *) &local_addr_rc;
+ len = sizeof(local_addr_rc);
+ break;
+ case SCO:
+ addr = (struct sockaddr *) &local_addr_sco;
+ len = sizeof(local_addr_sco);
+ break;
+ case L2CAP:
+ addr = (struct sockaddr *) &local_addr_l2;
+ len = sizeof(local_addr_l2);
+ break;
+ case TCP:
+ addr = (struct sockaddr *) &local_addr_in;
+ len = sizeof(local_addr_in);
+ break;
+ }
+
+ printf("%d: bind(%d)\n", gettid(), fd);
+ ret = bind(fd, addr, len);
+ printf("%d: bind(%d) = %d\n", gettid(), fd, ret);
+ if (ret < 0) printf("\terr %d (%s)\n", errno, strerror(errno));
+
+ return ret;
+}
+
+static int _listen(int fd, int type) {
+ int ret;
+
+ printf("%d: listen(%d)\n", gettid(), fd);
+ ret = listen(fd, 1);
+ printf("%d: listen(%d) = %d\n", gettid(), fd, ret);
+ if (ret < 0) printf("\terr %d (%s)\n", errno, strerror(errno));
+
+ return ret;
+}
+
+static int _accept(int fd, int type) {
+ int ret;
+ int len;
+ struct sockaddr *addr = NULL;
+
+ switch (type) {
+ case UNIX:
+ addr = (struct sockaddr *) &remote_addr_un;
+ len = sizeof(remote_addr_un);
+ break;
+ case RFCOMM:
+ addr = (struct sockaddr *) &remote_addr_rc;
+ len = sizeof(remote_addr_rc);
+ break;
+ case SCO:
+ addr = (struct sockaddr *) &remote_addr_sco;
+ len = sizeof(remote_addr_sco);
+ break;
+ case L2CAP:
+ addr = (struct sockaddr *) &remote_addr_l2;
+ len = sizeof(remote_addr_l2);
+ break;
+ case TCP:
+ addr = (struct sockaddr *) &remote_addr_in;
+ len = sizeof(remote_addr_in);
+ break;
+ }
+
+ printf("%d: accept(%d)\n", gettid(), fd);
+ ret = accept(fd, addr, &len);
+ printf("%d: accept(%d) = %d\n", gettid(), fd, ret);
+ if (ret < 0) printf("\terr %d (%s)\n", errno, strerror(errno));
+ else {
+ printf("\tlen = %d\n", len);
+ }
+
+ return ret;
+}
+
+static int _shutdown(int fd, int how) {
+ int ret;
+
+ printf("%d: shutdown(%d)\n", gettid(), fd);
+ ret = shutdown(fd, how);
+ printf("%d: shutdown(%d) = %d\n", gettid(), fd, ret);
+ if (ret < 0) printf("\terr %d (%s)\n", errno, strerror(errno));
+
+ return ret;
+}
+
+static void thread_accept(struct thread_args *args) {
+ printf("%d: START\n", gettid());
+ sleep(args->delay);
+ _accept(args->fd, args->type);
+ printf("%d: END\n", gettid());
+}
+
+static int do_accept_shutdown(int type) {
+ int fd;
+ pthread_t thread;
+ struct thread_args args = {-1, type, 0};
+
+ fd = _socket(type);
+ if (fd < 0) goto error;
+
+ if (_bind(fd, type) < 0) goto error;
+
+ if (_listen(fd, type) < 0) goto error;
+
+ args.fd = fd;
+ pthread_create(&thread, NULL, (void *)thread_accept, (void *)&args);
+
+ sleep(2);
+ _shutdown(fd, SHUT_RDWR);
+
+ pthread_join(thread, NULL);
+
+ _close(fd);
+
+ return 0;
+
+error:
+ return -1;
+}
+
+struct {
+ char *name;
+ int (*ptr)(int);
+} action_table[] = {
+ {"accept_shutdown", do_accept_shutdown},
+ {NULL, NULL},
+};
+
+struct {
+ char *name;
+ enum sock_type type;
+} type_table[] = {
+ {"unix", UNIX},
+ {"rfcomm", RFCOMM},
+ {"sco", SCO},
+ {"l2cap", L2CAP},
+ {"tcp", TCP},
+ {NULL, -1},
+};
+
+static void usage() {
+ int i;
+
+ printf("sock_shutdown_test TYPE ACTION\n");
+ printf("\nTYPE:\n");
+ for (i = 0; type_table[i].name; i++) {
+ printf("\t%s\n", type_table[i].name);
+ }
+ printf("\nACTION:\n");
+ for (i = 0; action_table[i].name; i++) {
+ printf("\t%s\n", action_table[i].name);
+ }
+}
+
+int main(int argc, char **argv) {
+ int i;
+ int type = -1;
+
+ if (argc != 3) {
+ usage();
+ return -1;
+ }
+ for (i = 0; type_table[i].name; i++) {
+ if (!strcmp(argv[1], type_table[i].name)) {
+ type = type_table[i].type;
+ break;
+ }
+ }
+ if (type == -1) {
+ usage();
+ return -1;
+ }
+ for (i = 0; action_table[i].name; i++) {
+ if (!strcmp(argv[2], action_table[i].name)) {
+ printf("TYPE = %s ACTION = %s\n", type_table[type].name,
+ action_table[i].name);
+ return (*action_table[i].ptr)(type);
+ }
+ }
+ usage();
+ return -1;
+}
diff --git a/tools/socktest.c b/tools/socktest.c
new file mode 100644
index 0000000..b0c45c5
--- /dev/null
+++ b/tools/socktest.c
@@ -0,0 +1,816 @@
+/*
+** Copyright 2009 The Android Open Source Project
+**
+** 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.
+*/
+
+/** socket testing */
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <errno.h>
+#include <sys/uio.h>
+#include <unistd.h>
+
+#include <fcntl.h>
+#include <pthread.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <errno.h>
+#include <unistd.h>
+#include <sys/socket.h>
+#include <sys/ioctl.h>
+#include <sys/poll.h>
+#include <sys/un.h>
+#include <netinet/in.h>
+
+#include <bluetooth/bluetooth.h>
+#include <bluetooth/rfcomm.h>
+#include <bluetooth/sco.h>
+#include <bluetooth/l2cap.h>
+
+enum sock_type {
+ UNIX = 0,
+ RFCOMM,
+ SCO,
+ L2CAP,
+ TCP,
+};
+
+struct thread_args {
+ int fd;
+ int type;
+ int delay;
+};
+
+struct sockaddr_un local_addr_un = {AF_UNIX, "/data/foo"};
+struct sockaddr_rc local_addr_rc = {AF_BLUETOOTH, *BDADDR_ANY, 4};
+struct sockaddr_sco local_addr_sco = {AF_BLUETOOTH, *BDADDR_LOCAL};
+struct sockaddr_l2 local_addr_l2 = {AF_BLUETOOTH, htobs(0x1001), *BDADDR_ANY, 0};
+struct sockaddr_in local_addr_in = {AF_INET, 9999, {0}, {0}};
+
+struct sockaddr_un remote_addr_un ;
+struct sockaddr_rc remote_addr_rc ;
+struct sockaddr_sco remote_addr_sco ;
+struct sockaddr_l2 remote_addr_l2 ;
+struct sockaddr_in remote_addr_in ;
+
+static void print_events(int events) {
+ if (events & POLLIN) printf("POLLIN ");
+ if (events & POLLPRI) printf("POLLPRI ");
+ if (events & POLLOUT) printf("POLLOUT ");
+ if (events & POLLERR) printf("POLLERR ");
+ if (events & POLLHUP) printf("POLLHUP ");
+ if (events & POLLNVAL) printf("POLLNVAL ");
+ printf("\n");
+}
+
+static void print_fds(struct pollfd *ufds, nfds_t nfds) {
+ unsigned int i;
+ for (i=0; i<nfds; i++)
+ printf("%d ", ufds[i].fd);
+}
+
+static int _socket(int type) {
+ int ret;
+ int family = -1;
+ int typ = -1;
+ int protocol = -1;
+
+ switch (type) {
+ case UNIX:
+ family = PF_UNIX;
+ typ = SOCK_STREAM;
+ protocol = 0;
+ break;
+ case RFCOMM:
+ family = PF_BLUETOOTH;
+ typ = SOCK_STREAM;
+ protocol = BTPROTO_RFCOMM;
+ break;
+ case SCO:
+ family = PF_BLUETOOTH;
+ typ = SOCK_SEQPACKET;
+ protocol = BTPROTO_SCO;
+ break;
+ case L2CAP:
+ family = PF_BLUETOOTH;
+ typ = SOCK_SEQPACKET;
+ protocol = BTPROTO_L2CAP;
+ break;
+ case TCP:
+ family = PF_INET;
+ typ = SOCK_STREAM;
+ protocol = 0;
+ break;
+ }
+
+ printf("%ld: socket()\n", pthread_self());
+ ret = socket(family, typ, protocol);
+ printf("%ld: socket() = %d\n", pthread_self(), ret);
+ if (ret < 0) printf("\terr %d (%s)\n", errno, strerror(errno));
+
+ return ret;
+}
+
+static int _close(int fd, int type) {
+ int ret;
+
+ printf("%ld: close(%d)\n", pthread_self(), fd);
+ ret = close(fd);
+ printf("%ld: close(%d) = %d\n", pthread_self(), fd, ret);
+ if (ret < 0) printf("\terr %d (%s)\n", errno, strerror(errno));
+
+ return ret;
+}
+
+static int _bind(int fd, int type) {
+ int len = 0;
+ int ret;
+ struct sockaddr *addr = NULL;
+
+ switch (type) {
+ case UNIX:
+ unlink(local_addr_un.sun_path);
+ addr = (struct sockaddr *) &local_addr_un;
+ len = sizeof(local_addr_un);
+ break;
+ case RFCOMM:
+ addr = (struct sockaddr *) &local_addr_rc;
+ len = sizeof(local_addr_rc);
+ break;
+ case SCO:
+ addr = (struct sockaddr *) &local_addr_sco;
+ len = sizeof(local_addr_sco);
+ break;
+ case L2CAP:
+ addr = (struct sockaddr *) &local_addr_l2;
+ len = sizeof(local_addr_l2);
+ break;
+ case TCP:
+ addr = (struct sockaddr *) &local_addr_in;
+ len = sizeof(local_addr_in);
+ break;
+ }
+
+ printf("%ld: bind(%d)\n", pthread_self(), fd);
+ ret = bind(fd, addr, len);
+ printf("%ld: bind(%d) = %d\n", pthread_self(), fd, ret);
+ if (ret < 0) printf("\terr %d (%s)\n", errno, strerror(errno));
+
+ return ret;
+}
+
+static int _listen(int fd, int type) {
+ int ret;
+
+ printf("%ld: listen(%d)\n", pthread_self(), fd);
+ ret = listen(fd, 1);
+ printf("%ld: listen(%d) = %d\n", pthread_self(), fd, ret);
+ if (ret < 0) printf("\terr %d (%s)\n", errno, strerror(errno));
+
+ return ret;
+}
+
+static int _read(int fd) {
+ int ret;
+ char buf;
+
+ printf("%ld: read(%d)\n", pthread_self(), fd);
+ ret = read(fd, &buf, 1);
+ printf("%ld: read(%d) = %d [%d]\n", pthread_self(), fd, ret, (int)buf);
+ if (ret < 0) printf("\terr %d (%s)\n", errno, strerror(errno));
+
+ return ret;
+}
+
+
+static int _accept(int fd, int type) {
+ int ret;
+ int len;
+ struct sockaddr *addr = NULL;
+
+ switch (type) {
+ case UNIX:
+ addr = (struct sockaddr *) &remote_addr_un;
+ len = sizeof(remote_addr_un);
+ break;
+ case RFCOMM:
+ addr = (struct sockaddr *) &remote_addr_rc;
+ len = sizeof(remote_addr_rc);
+ break;
+ case SCO:
+ addr = (struct sockaddr *) &remote_addr_sco;
+ len = sizeof(remote_addr_sco);
+ break;
+ case L2CAP:
+ addr = (struct sockaddr *) &remote_addr_l2;
+ len = sizeof(remote_addr_l2);
+ break;
+ case TCP:
+ addr = (struct sockaddr *) &remote_addr_in;
+ len = sizeof(remote_addr_in);
+ break;
+ }
+
+ printf("%ld: accept(%d)\n", pthread_self(), fd);
+ ret = accept(fd, addr, &len);
+ printf("%ld: accept(%d) = %d\n", pthread_self(), fd, ret);
+ if (ret < 0) printf("\terr %d (%s)\n", errno, strerror(errno));
+ else {
+ printf("\tlen = %d\n", len);
+ }
+
+ return ret;
+}
+
+int get_bdaddr(const char *str, bdaddr_t *ba) {
+ char *d = ((char *)ba) + 5, *endp;
+ int i;
+ for(i = 0; i < 6; i++) {
+ *d-- = strtol(str, &endp, 16);
+ if (*endp != ':' && i != 5) {
+ memset(ba, 0, sizeof(bdaddr_t));
+ return -1;
+ }
+ str = endp + 1;
+ }
+ return 0;
+}
+
+static int _connect(int fd, int type) {
+ int ret;
+ int len = 0;
+ struct sockaddr *addr = NULL;
+
+ switch (type) {
+ case UNIX:
+ addr = (struct sockaddr *) &local_addr_un;
+ len = sizeof(local_addr_un);
+ break;
+ case RFCOMM:
+ get_bdaddr("00:11:22:33:44:55", &local_addr_rc.rc_bdaddr);
+ addr = (struct sockaddr *) &local_addr_rc;
+ len = sizeof(local_addr_rc);
+ break;
+ case SCO:
+ addr = (struct sockaddr *) &local_addr_sco;
+ len = sizeof(local_addr_sco);
+ break;
+ case L2CAP:
+ addr = (struct sockaddr *) &local_addr_l2;
+ len = sizeof(local_addr_l2);
+ break;
+ case TCP:
+ addr = (struct sockaddr *) &local_addr_in;
+ len = sizeof(local_addr_in);
+ break;
+ }
+
+ printf("%ld: connect(%d)\n", pthread_self(), fd);
+ ret = connect(fd, addr, len);
+ printf("%ld: connect(%d) = %d\n", pthread_self(), fd, ret);
+ if (ret < 0) printf("\terr %d (%s)\n", errno, strerror(errno));
+
+ return ret;
+}
+
+static int _write(int fd, int type) {
+ int ret;
+ char buf = 69;
+
+ printf("%ld: write(%d)\n", pthread_self(), fd);
+ ret = write(fd, &buf, 1);
+ printf("%ld: write(%d) = %d\n", pthread_self(), fd, ret);
+ if (ret < 0) printf("\terr %d (%s)\n", errno, strerror(errno));
+
+ return ret;
+}
+
+static int _shutdown(int fd, int how) {
+ int ret;
+
+ printf("%ld: shutdown(%d)\n", pthread_self(), fd);
+ ret = shutdown(fd, how);
+ printf("%ld: shutdown(%d) = %d\n", pthread_self(), fd, ret);
+ if (ret < 0) printf("\terr %d (%s)\n", errno, strerror(errno));
+
+ return ret;
+}
+
+static int _poll(struct pollfd *ufds, nfds_t nfds, int timeout) {
+ int ret;
+ unsigned int i;
+
+ printf("%ld: poll(", pthread_self());
+ print_fds(ufds, nfds);
+ printf(")\n");
+ ret = poll(ufds, nfds, timeout);
+ printf("%ld: poll() = %d\n", pthread_self(), ret);
+ if (ret < 0) printf("\terr %d (%s)\n", errno, strerror(errno));
+ if (ret > 0) {
+ for (i=0; i<nfds; i++) {
+ if (ufds[i].revents) {
+ printf("\tfd %d ", ufds[i].fd); print_events(ufds[i].revents);
+ }
+ }
+ }
+ return ret;
+}
+
+static void thread_delay_close(struct thread_args *args) {
+ printf("%ld: START\n", pthread_self());
+ sleep(args->delay);
+ _close(args->fd, args->type);
+ printf("%ld: END\n", pthread_self());
+}
+
+static void thread_poll(void *args) {
+ int fd = (int)args;
+ struct pollfd pfd;
+ printf("%ld: START\n", pthread_self());
+ pfd.fd = fd;
+ pfd.events = 0;
+ _poll(&pfd, 1, -1);
+ printf("%ld: END\n", pthread_self());
+}
+
+static void thread_read(void *args) {
+ int fd = (int)args;
+ printf("%ld: START\n", pthread_self());
+ _read(fd);
+ printf("%ld: END\n", pthread_self());
+}
+
+static void thread_pollin(void *args) {
+ int fd = (int)args;
+ struct pollfd pfd;
+ printf("%ld: START\n", pthread_self());
+ pfd.fd = fd;
+ pfd.events = POLLIN;
+ _poll(&pfd, 1, -1);
+ printf("%ld: END\n", pthread_self());
+}
+
+static void thread_shutdown(int fd) {
+ printf("%ld: START\n", pthread_self());
+ sleep(4);
+ _shutdown(fd, SHUT_RDWR);
+ printf("%ld: END\n", pthread_self());
+}
+
+static void thread_accept(struct thread_args *args) {
+ printf("%ld: START\n", pthread_self());
+ sleep(args->delay);
+ _accept(args->fd, args->type);
+ printf("%ld: END\n", pthread_self());
+}
+
+static void thread_connect(struct thread_args *args) {
+ printf("%ld: START\n", pthread_self());
+ sleep(args->delay);
+ _connect(args->fd, args->type);
+ printf("%ld: END\n", pthread_self());
+}
+
+static void thread_delay_close_write(struct thread_args *args) {
+ printf("%ld: START\n", pthread_self());
+ sleep(args->delay);
+ _close(args->fd, args->type);
+ sleep(args->delay);
+ _write(args->fd, args->type);
+ printf("%ld: END\n", pthread_self());
+}
+
+static void thread_accept_write(struct thread_args *args) {
+ printf("%ld: START\n", pthread_self());
+ sleep(args->delay);
+ _accept(args->fd, args->type);
+ sleep(args->delay);
+ _write(args->fd, args->type);
+ printf("%ld: END\n", pthread_self());
+}
+
+static void thread_delay_connect(struct thread_args *args) {
+ printf("%ld: START\n", pthread_self());
+ sleep(args->delay);
+ args->fd = _socket(args->type);
+ _connect(args->fd, args->type);
+ printf("%ld: END\n", pthread_self());
+}
+
+static int do_accept_accept_accept(int type) {
+ int fd;
+
+ fd = _socket(type);
+ if (fd < 0) goto error;
+
+ if (_bind(fd, type) < 0) goto error;
+
+ if (_listen(fd, type) < 0) goto error;
+
+ while (1) {
+ _accept(fd, type);
+ }
+
+ return 0;
+
+error:
+ return -1;
+}
+
+static int do_accept_and_close(int type) {
+ int fd;
+ pthread_t thread;
+ struct thread_args args = {-1, type, 1};
+
+ fd = _socket(type);
+ if (fd < 0) goto error;
+
+ if (_bind(fd, type) < 0) goto error;
+
+ if (_listen(fd, type) < 0) goto error;
+
+ args.fd = fd;
+ pthread_create(&thread, NULL, (void *)thread_delay_close, (void *)&args);
+
+ _accept(fd, type);
+
+ pthread_join(thread, NULL);
+
+ return 0;
+
+error:
+ return -1;
+}
+
+static int do_accept_shutdown(int type) {
+ int fd;
+ pthread_t thread;
+ struct thread_args args = {-1, type, 0};
+
+ fd = _socket(type);
+ if (fd < 0) goto error;
+
+ if (_bind(fd, type) < 0) goto error;
+
+ if (_listen(fd, type) < 0) goto error;
+
+ args.fd = fd;
+ pthread_create(&thread, NULL, (void *)thread_accept, (void *)&args);
+
+ sleep(4);
+ _shutdown(fd, SHUT_RDWR);
+
+ pthread_join(thread, NULL);
+
+ _close(fd, type);
+
+ return 0;
+
+error:
+ return -1;
+}
+
+static int do_connect_shutdown(int type) {
+ int fd;
+ pthread_t thread;
+ struct thread_args args = {-1, type, 0};
+
+ fd = _socket(type);
+ if (fd < 0) goto error;
+
+ args.fd = fd;
+ pthread_create(&thread, NULL, (void *)thread_connect, (void *)&args);
+
+ sleep(4);
+ _shutdown(fd, SHUT_RDWR);
+
+ pthread_join(thread, NULL);
+
+ _close(fd, type);
+
+ return 0;
+
+error:
+ return -1;
+}
+
+static int do_connectnb_shutdown(int type) {
+ int fd;
+ int flags;
+ pthread_t thread;
+ struct thread_args args = {-1, type, 0};
+
+
+ fd = _socket(type);
+ if (fd < 0) goto error;
+
+ flags = fcntl(fd, F_GETFL);
+ if (flags == -1)
+ return -1;
+ if (fcntl(fd, F_SETFL, flags | O_NONBLOCK))
+ return -1;
+
+ _connect(fd, type);
+
+ sleep(1);
+ _shutdown(fd, SHUT_RDWR);
+
+ sleep(2);
+
+ _close(fd, type);
+
+ return 0;
+
+error:
+ return -1;
+}
+
+static int do_connectnb_close(int type) {
+ int fd;
+ pthread_t thread;
+ struct thread_args args = {-1, type, 0};
+ int flags;
+
+ fd = _socket(type);
+ if (fd < 0) goto error;
+
+ flags = fcntl(fd, F_GETFL);
+ if (flags == -1)
+ return -1;
+ if (fcntl(fd, F_SETFL, flags | O_NONBLOCK))
+ return -1;
+
+ _connect(fd, type);
+
+ sleep(2);
+
+ _close(fd, type);
+
+ return 0;
+
+error:
+ return -1;
+}
+
+// accept in one thread. close then write in another
+static int do_accept_close_write(int type) {
+ int fd;
+ pthread_t thread;
+ struct thread_args args = {-1, type, 1};
+
+ fd = _socket(type);
+ if (fd < 0) goto error;
+
+ if (_bind(fd, type) < 0) goto error;
+
+ if (_listen(fd, type) < 0) goto error;
+
+ args.fd = fd;
+ pthread_create(&thread, NULL, (void *)thread_delay_close_write, (void *)&args);
+
+ _accept(fd, type);
+
+ pthread_join(thread, NULL);
+
+ return 0;
+
+error:
+ return -1;
+}
+
+static int do_poll_poll_poll_shutdown(int type) {
+ const int MAX_T = 32;
+ int fd;
+ pthread_t t[MAX_T];
+ int i;
+
+ fd = _socket(type);
+
+ for (i=0; i<MAX_T; i++)
+ pthread_create(&t[i], NULL, (void *)thread_poll, (void *)fd);
+
+ sleep(1);
+
+ _shutdown(fd, SHUT_RDWR);
+
+ for (i=0; i<MAX_T; i++)
+ pthread_join(t[i], NULL);
+
+ _close(fd, type);
+
+ return 0;
+}
+
+static int do_poll_poll_poll_close(int type) {
+ const int MAX_T = 32;
+ int fd;
+ pthread_t t[MAX_T];
+ int i;
+
+ fd = _socket(type);
+
+ for (i=0; i<MAX_T; i++)
+ pthread_create(&t[i], NULL, (void *)thread_poll, (void *)fd);
+
+ sleep(1);
+
+ _close(fd, type);
+
+ for (i=0; i<MAX_T; i++)
+ pthread_join(t[i], NULL);
+
+ return 0;
+}
+
+static int do_read_read_read_close(int type) {
+ const int MAX_T = 32;
+ int fd;
+ pthread_t t[MAX_T];
+ int i;
+
+ fd = _socket(type);
+
+ for (i=0; i<MAX_T; i++)
+ pthread_create(&t[i], NULL, (void *)thread_read, (void *)fd);
+
+ sleep(1);
+
+ _close(fd, type);
+
+ for (i=0; i<MAX_T; i++)
+ pthread_join(t[i], NULL);
+
+ return 0;
+}
+
+static int do_read_read_read_shutdown(int type) {
+ const int MAX_T = 32;
+ int fd;
+ pthread_t t[MAX_T];
+ int i;
+
+ fd = _socket(type);
+
+ for (i=0; i<MAX_T; i++)
+ pthread_create(&t[i], NULL, (void *)thread_read, (void *)fd);
+
+ sleep(1);
+
+ _shutdown(fd, SHUT_RDWR);
+
+ for (i=0; i<MAX_T; i++)
+ pthread_join(t[i], NULL);
+
+ _close(fd, type);
+
+ return 0;
+}
+
+static int do_connected_read1_shutdown1(int type) {
+ int fd1, fd2;
+ pthread_t t1;
+ pthread_t t2;
+ struct thread_args a1 = {-1, type, 0};
+ struct thread_args a2 = {-1, type, 2};
+
+ fd1 = _socket(type);
+ if (fd1 < 0) goto error;
+
+ if (_bind(fd1, type) < 0) goto error;
+
+ if (_listen(fd1, type) < 0) goto error;
+
+ a1.fd = fd1;
+ pthread_create(&t1, NULL, (void *)thread_accept_write, (void *)&a1);
+
+ fd2 = _socket(type);
+ if (_connect(fd2, type)) goto error;
+
+ pthread_create(&t2, NULL, (void *)thread_shutdown, (void *)&fd2);
+
+ while (1) if (_read(fd2)) break;
+
+ pthread_join(t1, NULL);
+ pthread_join(t2, NULL);
+
+ return 0;
+
+error:
+ return -1;
+}
+
+// accept in one thread, connect from two different threads
+static int do_accept_connect_connect(int type) {
+ int fd;
+ pthread_t t1;
+ pthread_t t2;
+ struct thread_args a1 = {-1, type, 1};
+ struct thread_args a2 = {-1, type, 2};
+
+ fd = _socket(type);
+ if (fd < 0) goto error;
+
+ if (_bind(fd, type) < 0) goto error;
+
+ if (_listen(fd, type) < 0) goto error;
+
+ pthread_create(&t1, NULL, (void *)thread_delay_connect, (void *)&a1);
+ pthread_create(&t2, NULL, (void *)thread_delay_connect, (void *)&a2);
+
+ _accept(fd, type);
+
+ pthread_join(t1, NULL);
+ pthread_join(t2, NULL);
+
+ return 0;
+
+error:
+ return -1;
+}
+
+struct {
+ char *name;
+ int (*ptr)(int);
+} action_table[] = {
+ {"accept_accept_accept", do_accept_accept_accept},
+ {"accept_and_close", do_accept_and_close},
+ {"accept_shutdown", do_accept_shutdown},
+ {"connect_shutdown", do_connect_shutdown},
+ {"connectnb_shutdown", do_connectnb_shutdown},
+ {"connectnb_close", do_connectnb_close},
+ {"accept_close_write", do_accept_close_write},
+ {"accept_connect_connect", do_accept_connect_connect},
+ {"poll_poll_poll_shutdown", do_poll_poll_poll_shutdown},
+ {"poll_poll_poll_close", do_poll_poll_poll_close},
+ {"read_read_read_shutdown", do_read_read_read_shutdown},
+ {"read_read_read_close", do_read_read_read_close},
+ {"connected_read1_shutdown1", do_connected_read1_shutdown1},
+ {NULL, NULL},
+};
+
+struct {
+ char *name;
+ enum sock_type type;
+} type_table[] = {
+ {"unix", UNIX},
+ {"rfcomm", RFCOMM},
+ {"sco", SCO},
+ {"l2cap", L2CAP},
+ {"tcp", TCP},
+ {NULL, -1},
+};
+
+static void usage() {
+ int i;
+
+ printf("socktest TYPE ACTION\n");
+ printf("\nTYPE:\n");
+ for (i = 0; type_table[i].name; i++) {
+ printf("\t%s\n", type_table[i].name);
+ }
+ printf("\nACTION:\n");
+ for (i = 0; action_table[i].name; i++) {
+ printf("\t%s\n", action_table[i].name);
+ }
+}
+
+int main(int argc, char **argv) {
+ int i;
+ int type = -1;
+
+ if (argc != 3) {
+ usage();
+ return -1;
+ }
+ for (i = 0; type_table[i].name; i++) {
+ if (!strcmp(argv[1], type_table[i].name)) {
+ type = type_table[i].type;
+ break;
+ }
+ }
+ if (type == -1) {
+ usage();
+ return -1;
+ }
+ for (i = 0; action_table[i].name; i++) {
+ if (!strcmp(argv[2], action_table[i].name)) {
+ printf("TYPE = %s ACTION = %s\n", type_table[type].name,
+ action_table[i].name);
+ return (*action_table[i].ptr)(type);
+ }
+ }
+ usage();
+ return -1;
+}