diff options
author | Jean-Baptiste Queru <jbq@google.com> | 2009-11-12 18:46:23 -0800 |
---|---|---|
committer | Jean-Baptiste Queru <jbq@google.com> | 2009-11-12 18:46:23 -0800 |
commit | 327e4ab9cc1fa9eeb7243ad6ee28dfcc7b212a5b (patch) | |
tree | 45215c0865ba46ce9e35f19be2827ebfe1f111f9 | |
parent | df782f29a530d805c13f32bb43883306c05a4504 (diff) | |
download | bluetooth-327e4ab9cc1fa9eeb7243ad6ee28dfcc7b212a5b.tar.gz |
eclair snapshot
-rw-r--r-- | bluedroid/Android.mk | 19 | ||||
-rw-r--r-- | bluedroid/bluetooth.c | 26 | ||||
-rw-r--r-- | bluedroid/include/bluedroid/bluetooth.h | 4 | ||||
-rw-r--r-- | bluez-clean-headers/bluetooth/hci.h | 18 | ||||
-rw-r--r-- | bluez-clean-headers/bluetooth/l2cap.h | 85 | ||||
-rw-r--r-- | brcm_patchram_plus/Android.mk | 19 | ||||
-rw-r--r-- | brcm_patchram_plus/brcm_patchram_plus.c | 580 | ||||
-rw-r--r-- | data/Android.mk | 2 | ||||
-rw-r--r-- | data/audio.conf | 31 | ||||
-rw-r--r-- | data/hcid.conf | 64 | ||||
-rw-r--r-- | data/input.conf | 14 | ||||
-rw-r--r-- | data/main.conf | 59 | ||||
-rw-r--r-- | tools/Android.mk | 150 | ||||
-rw-r--r-- | tools/asocket_test.c | 742 | ||||
-rw-r--r-- | tools/bttest.c (renamed from bluedroid/bttest.c) | 0 | ||||
-rw-r--r-- | tools/pipetest.c | 429 | ||||
-rw-r--r-- | tools/sock_shutdown_bug_l2cap.c | 47 | ||||
-rw-r--r-- | tools/sock_shutdown_bug_rfcomm.c | 63 | ||||
-rw-r--r-- | tools/sock_shutdown_bug_tcp.c | 63 | ||||
-rw-r--r-- | tools/sock_shutdown_test.c | 314 | ||||
-rw-r--r-- | tools/socktest.c | 816 |
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; +} |