From 799757ccf1d03c33c75bc597cd5ef77741dcb6a7 Mon Sep 17 00:00:00 2001 From: Adrian Bunk Date: Fri, 3 Jun 2011 09:17:04 +0000 Subject: Imported upstream 4.91 --- test/scotest.c | 434 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 434 insertions(+) create mode 100644 test/scotest.c (limited to 'test/scotest.c') diff --git a/test/scotest.c b/test/scotest.c new file mode 100644 index 0000000..50b622a --- /dev/null +++ b/test/scotest.c @@ -0,0 +1,434 @@ +/* + * + * BlueZ - Bluetooth protocol stack for Linux + * + * Copyright (C) 2002-2003 Maxim Krasnyansky + * Copyright (C) 2002-2010 Marcel Holtmann + * + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * 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 + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + * + */ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +/* Test modes */ +enum { + SEND, + RECV, + RECONNECT, + MULTY, + DUMP, + CONNECT +}; + +static unsigned char *buf; + +/* Default data size */ +static long data_size = 672; + +static bdaddr_t bdaddr; + +static float tv2fl(struct timeval tv) +{ + return (float)tv.tv_sec + (float)(tv.tv_usec/1000000.0); +} + +static int do_connect(char *svr) +{ + struct sockaddr_sco addr; + struct sco_conninfo conn; + socklen_t optlen; + int sk; + + /* Create socket */ + sk = socket(PF_BLUETOOTH, SOCK_SEQPACKET, BTPROTO_SCO); + if (sk < 0) { + syslog(LOG_ERR, "Can't create socket: %s (%d)", + strerror(errno), errno); + return -1; + } + + /* Bind to local address */ + memset(&addr, 0, sizeof(addr)); + addr.sco_family = AF_BLUETOOTH; + bacpy(&addr.sco_bdaddr, &bdaddr); + + if (bind(sk, (struct sockaddr *) &addr, sizeof(addr)) < 0) { + syslog(LOG_ERR, "Can't bind socket: %s (%d)", + strerror(errno), errno); + goto error; + } + + /* Connect to remote device */ + memset(&addr, 0, sizeof(addr)); + addr.sco_family = AF_BLUETOOTH; + str2ba(svr, &addr.sco_bdaddr); + + if (connect(sk, (struct sockaddr *) &addr, sizeof(addr)) < 0) { + syslog(LOG_ERR, "Can't connect: %s (%d)", + strerror(errno), errno); + goto error; + } + + /* Get connection information */ + memset(&conn, 0, sizeof(conn)); + optlen = sizeof(conn); + + if (getsockopt(sk, SOL_SCO, SCO_CONNINFO, &conn, &optlen) < 0) { + syslog(LOG_ERR, "Can't get SCO connection information: %s (%d)", + strerror(errno), errno); + goto error; + } + + syslog(LOG_INFO, "Connected [handle %d, class 0x%02x%02x%02x]", + conn.hci_handle, + conn.dev_class[2], conn.dev_class[1], conn.dev_class[0]); + + return sk; + +error: + close(sk); + return -1; +} + +static void do_listen(void (*handler)(int sk)) +{ + struct sockaddr_sco addr; + struct sco_conninfo conn; + socklen_t optlen; + int sk, nsk; + char ba[18]; + + /* Create socket */ + sk = socket(PF_BLUETOOTH, SOCK_SEQPACKET, BTPROTO_SCO); + if (sk < 0) { + syslog(LOG_ERR, "Can't create socket: %s (%d)", + strerror(errno), errno); + exit(1); + } + + /* Bind to local address */ + memset(&addr, 0, sizeof(addr)); + addr.sco_family = AF_BLUETOOTH; + bacpy(&addr.sco_bdaddr, &bdaddr); + + if (bind(sk, (struct sockaddr *) &addr, sizeof(addr)) < 0) { + syslog(LOG_ERR, "Can't bind socket: %s (%d)", + strerror(errno), errno); + goto error; + } + + /* Listen for connections */ + if (listen(sk, 10)) { + syslog(LOG_ERR,"Can not listen on the socket: %s (%d)", + strerror(errno), errno); + goto error; + } + + syslog(LOG_INFO,"Waiting for connection ..."); + + while (1) { + memset(&addr, 0, sizeof(addr)); + optlen = sizeof(addr); + + nsk = accept(sk, (struct sockaddr *) &addr, &optlen); + if (nsk < 0) { + syslog(LOG_ERR,"Accept failed: %s (%d)", + strerror(errno), errno); + goto error; + } + if (fork()) { + /* Parent */ + close(nsk); + continue; + } + /* Child */ + close(sk); + + /* Get connection information */ + memset(&conn, 0, sizeof(conn)); + optlen = sizeof(conn); + + if (getsockopt(nsk, SOL_SCO, SCO_CONNINFO, &conn, &optlen) < 0) { + syslog(LOG_ERR, "Can't get SCO connection information: %s (%d)", + strerror(errno), errno); + close(nsk); + goto error; + } + + ba2str(&addr.sco_bdaddr, ba); + syslog(LOG_INFO, "Connect from %s [handle %d, class 0x%02x%02x%02x]", + ba, conn.hci_handle, + conn.dev_class[2], conn.dev_class[1], conn.dev_class[0]); + + handler(nsk); + + syslog(LOG_INFO, "Disconnect"); + exit(0); + } + + return; + +error: + close(sk); + exit(1); +} + +static void dump_mode(int sk) +{ + int len; + + syslog(LOG_INFO,"Receiving ..."); + while ((len = read(sk, buf, data_size)) > 0) + syslog(LOG_INFO, "Recevied %d bytes", len); +} + +static void recv_mode(int sk) +{ + struct timeval tv_beg,tv_end,tv_diff; + long total; + uint32_t seq; + + syslog(LOG_INFO, "Receiving ..."); + + seq = 0; + while (1) { + gettimeofday(&tv_beg, NULL); + total = 0; + while (total < data_size) { + int r; + if ((r = recv(sk, buf, data_size, 0)) <= 0) { + if (r < 0) + syslog(LOG_ERR, "Read failed: %s (%d)", + strerror(errno), errno); + return; + } + total += r; + } + gettimeofday(&tv_end, NULL); + + timersub(&tv_end, &tv_beg, &tv_diff); + + syslog(LOG_INFO,"%ld bytes in %.2fm speed %.2f kb", total, + tv2fl(tv_diff) / 60.0, + (float)( total / tv2fl(tv_diff) ) / 1024.0 ); + } +} + +static void send_mode(char *svr) +{ + struct sco_options so; + socklen_t len; + uint32_t seq; + int i, sk; + + if ((sk = do_connect(svr)) < 0) { + syslog(LOG_ERR, "Can't connect to the server: %s (%d)", + strerror(errno), errno); + exit(1); + } + + len = sizeof(so); + if (getsockopt(sk, SOL_SCO, SCO_OPTIONS, &so, &len) < 0) { + syslog(LOG_ERR, "Can't get SCO options: %s (%d)", + strerror(errno), errno); + exit(1); + } + + syslog(LOG_INFO,"Sending ..."); + + for (i = 6; i < so.mtu; i++) + buf[i] = 0x7f; + + seq = 0; + while (1) { + *(uint32_t *) buf = htobl(seq); + *(uint16_t *) (buf + 4) = htobs(data_size); + seq++; + + if (send(sk, buf, so.mtu, 0) <= 0) { + syslog(LOG_ERR, "Send failed: %s (%d)", + strerror(errno), errno); + exit(1); + } + + usleep(1); + } +} + +static void reconnect_mode(char *svr) +{ + while (1) { + int sk; + + if ((sk = do_connect(svr)) < 0) { + syslog(LOG_ERR, "Can't connect to the server: %s (%d)", + strerror(errno), errno); + exit(1); + } + + close(sk); + + sleep(5); + } +} + +static void multy_connect_mode(char *svr) +{ + while (1) { + int i, sk; + + for (i = 0; i < 10; i++){ + if (fork()) + continue; + + /* Child */ + sk = do_connect(svr); + if (sk < 0) { + syslog(LOG_ERR, "Can't connect to the server: %s (%d)", + strerror(errno), errno); + } + close(sk); + exit(0); + } + + sleep(19); + } +} + +static void usage(void) +{ + printf("scotest - SCO testing\n" + "Usage:\n"); + printf("\tscotest [-b bytes] [bd_addr]\n"); + printf("Modes:\n" + "\t-d dump (server)\n" + "\t-c reconnect (client)\n" + "\t-m multiple connects (client)\n" + "\t-r receive (server)\n" + "\t-s connect and send (client)\n" + "\t-n connect and be silent (client)\n"); +} + +int main(int argc ,char *argv[]) +{ + struct sigaction sa; + int opt, sk, mode = RECV; + + while ((opt=getopt(argc,argv,"rdscmnb:")) != EOF) { + switch(opt) { + case 'r': + mode = RECV; + break; + + case 's': + mode = SEND; + break; + + case 'd': + mode = DUMP; + break; + + case 'c': + mode = RECONNECT; + break; + + case 'm': + mode = MULTY; + break; + + case 'n': + mode = CONNECT; + break; + + case 'b': + data_size = atoi(optarg); + break; + + default: + usage(); + exit(1); + } + } + + if (!(argc - optind) && (mode != RECV && mode != DUMP)) { + usage(); + exit(1); + } + + if (!(buf = malloc(data_size))) { + perror("Can't allocate data buffer"); + exit(1); + } + + memset(&sa, 0, sizeof(sa)); + sa.sa_handler = SIG_IGN; + sa.sa_flags = SA_NOCLDSTOP; + sigaction(SIGCHLD, &sa, NULL); + + openlog("scotest", LOG_PERROR | LOG_PID, LOG_LOCAL0); + + switch( mode ){ + case RECV: + do_listen(recv_mode); + break; + + case DUMP: + do_listen(dump_mode); + break; + + case SEND: + send_mode(argv[optind]); + break; + + case RECONNECT: + reconnect_mode(argv[optind]); + break; + + case MULTY: + multy_connect_mode(argv[optind]); + break; + + case CONNECT: + sk = do_connect(argv[optind]); + if (sk < 0) + exit(1); + dump_mode(sk); + break; + } + + syslog(LOG_INFO, "Exit"); + + closelog(); + + return 0; +} -- cgit v1.2.3