Home | History | Annotate | Download | only in test
      1 /*
      2  *
      3  *  BlueZ - Bluetooth protocol stack for Linux
      4  *
      5  *  Copyright (C) 2002-2003  Maxim Krasnyansky <maxk (at) qualcomm.com>
      6  *  Copyright (C) 2002-2010  Marcel Holtmann <marcel (at) holtmann.org>
      7  *
      8  *
      9  *  This program is free software; you can redistribute it and/or modify
     10  *  it under the terms of the GNU General Public License as published by
     11  *  the Free Software Foundation; either version 2 of the License, or
     12  *  (at your option) any later version.
     13  *
     14  *  This program is distributed in the hope that it will be useful,
     15  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
     16  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
     17  *  GNU General Public License for more details.
     18  *
     19  *  You should have received a copy of the GNU General Public License
     20  *  along with this program; if not, write to the Free Software
     21  *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
     22  *
     23  */
     24 
     25 #ifdef HAVE_CONFIG_H
     26 #include <config.h>
     27 #endif
     28 
     29 #include <stdio.h>
     30 #include <errno.h>
     31 #include <ctype.h>
     32 #include <unistd.h>
     33 #include <stdlib.h>
     34 #include <getopt.h>
     35 #include <syslog.h>
     36 #include <signal.h>
     37 #include <sys/time.h>
     38 #include <sys/socket.h>
     39 
     40 #include <bluetooth/bluetooth.h>
     41 #include <bluetooth/sco.h>
     42 
     43 /* Test modes */
     44 enum {
     45 	SEND,
     46 	RECV,
     47 	RECONNECT,
     48 	MULTY,
     49 	DUMP,
     50 	CONNECT
     51 };
     52 
     53 static unsigned char *buf;
     54 
     55 /* Default data size */
     56 static long data_size = 672;
     57 
     58 /* Default packet type */
     59 static uint16_t pkt_type = 0;
     60 
     61 static bdaddr_t bdaddr;
     62 
     63 static float tv2fl(struct timeval tv)
     64 {
     65 	return (float)tv.tv_sec + (float)(tv.tv_usec/1000000.0);
     66 }
     67 
     68 static int do_connect(char *svr)
     69 {
     70 	struct sockaddr_sco addr;
     71 	struct sco_conninfo conn;
     72 	socklen_t optlen;
     73 	int sk;
     74 
     75 	/* Create socket */
     76 	sk = socket(PF_BLUETOOTH, SOCK_SEQPACKET, BTPROTO_SCO);
     77 	if (sk < 0) {
     78 		syslog(LOG_ERR, "Can't create socket: %s (%d)",
     79 							strerror(errno), errno);
     80 		return -1;
     81 	}
     82 
     83 	/* Bind to local address */
     84 	memset(&addr, 0, sizeof(addr));
     85 	addr.sco_family = AF_BLUETOOTH;
     86 	bacpy(&addr.sco_bdaddr, &bdaddr);
     87 
     88 	if (bind(sk, (struct sockaddr *) &addr, sizeof(addr)) < 0) {
     89 		syslog(LOG_ERR, "Can't bind socket: %s (%d)",
     90 							strerror(errno), errno);
     91 		goto error;
     92 	}
     93 
     94 	/* Connect to remote device */
     95 	memset(&addr, 0, sizeof(addr));
     96 	addr.sco_family = AF_BLUETOOTH;
     97 	addr.sco_pkt_type = pkt_type;
     98 	str2ba(svr, &addr.sco_bdaddr);
     99 
    100 	if (connect(sk, (struct sockaddr *) &addr, sizeof(addr)) < 0) {
    101 		syslog(LOG_ERR, "Can't connect: %s (%d)",
    102 							strerror(errno), errno);
    103 		goto error;
    104 	}
    105 
    106 	/* Get connection information */
    107 	memset(&conn, 0, sizeof(conn));
    108 	optlen = sizeof(conn);
    109 
    110 	if (getsockopt(sk, SOL_SCO, SCO_CONNINFO, &conn, &optlen) < 0) {
    111 		syslog(LOG_ERR, "Can't get SCO connection information: %s (%d)",
    112 							strerror(errno), errno);
    113 		goto error;
    114 	}
    115 
    116 	syslog(LOG_INFO, "Connected [handle %d, class 0x%02x%02x%02x]",
    117 		conn.hci_handle,
    118 		conn.dev_class[2], conn.dev_class[1], conn.dev_class[0]);
    119 
    120 	return sk;
    121 
    122 error:
    123 	close(sk);
    124 	return -1;
    125 }
    126 
    127 static void do_listen(void (*handler)(int sk))
    128 {
    129 	struct sockaddr_sco addr;
    130 	struct sco_conninfo conn;
    131 	socklen_t optlen;
    132 	int sk, nsk;
    133 	char ba[18];
    134 
    135 	/* Create socket */
    136 	sk = socket(PF_BLUETOOTH, SOCK_SEQPACKET, BTPROTO_SCO);
    137 	if (sk < 0) {
    138 		syslog(LOG_ERR, "Can't create socket: %s (%d)",
    139 							strerror(errno), errno);
    140 		exit(1);
    141 	}
    142 
    143 	/* Bind to local address */
    144 	memset(&addr, 0, sizeof(addr));
    145 	addr.sco_family = AF_BLUETOOTH;
    146 	addr.sco_pkt_type = pkt_type;
    147 	bacpy(&addr.sco_bdaddr, &bdaddr);
    148 
    149 	if (bind(sk, (struct sockaddr *) &addr, sizeof(addr)) < 0) {
    150 		syslog(LOG_ERR, "Can't bind socket: %s (%d)",
    151 							strerror(errno), errno);
    152 		goto error;
    153 	}
    154 
    155 	/* Listen for connections */
    156 	if (listen(sk, 10)) {
    157 		syslog(LOG_ERR,"Can not listen on the socket: %s (%d)",
    158 							strerror(errno), errno);
    159 		goto error;
    160 	}
    161 
    162 	syslog(LOG_INFO,"Waiting for connection ...");
    163 
    164 	while (1) {
    165 		memset(&addr, 0, sizeof(addr));
    166 		optlen = sizeof(addr);
    167 
    168 		nsk = accept(sk, (struct sockaddr *) &addr, &optlen);
    169 		if (nsk < 0) {
    170 			syslog(LOG_ERR,"Accept failed: %s (%d)",
    171 							strerror(errno), errno);
    172 			goto error;
    173 		}
    174 		if (fork()) {
    175 			/* Parent */
    176 			close(nsk);
    177 			continue;
    178 		}
    179 		/* Child */
    180 		close(sk);
    181 
    182 		/* Get connection information */
    183 		memset(&conn, 0, sizeof(conn));
    184 		optlen = sizeof(conn);
    185 
    186 		if (getsockopt(nsk, SOL_SCO, SCO_CONNINFO, &conn, &optlen) < 0) {
    187 			syslog(LOG_ERR, "Can't get SCO connection information: %s (%d)",
    188 							strerror(errno), errno);
    189 			close(nsk);
    190 			goto error;
    191 		}
    192 
    193 		ba2str(&addr.sco_bdaddr, ba);
    194 		syslog(LOG_INFO, "Connect from %s [handle %d, class 0x%02x%02x%02x]",
    195 			ba, conn.hci_handle,
    196 			conn.dev_class[2], conn.dev_class[1], conn.dev_class[0]);
    197 
    198 		handler(nsk);
    199 
    200 		syslog(LOG_INFO, "Disconnect");
    201 		exit(0);
    202 	}
    203 
    204 	return;
    205 
    206 error:
    207 	close(sk);
    208 	exit(1);
    209 }
    210 
    211 static void dump_mode(int sk)
    212 {
    213 	int len;
    214 
    215 	syslog(LOG_INFO,"Receiving ...");
    216 	while ((len = read(sk, buf, data_size)) > 0)
    217 		syslog(LOG_INFO, "Recevied %d bytes", len);
    218 }
    219 
    220 static void recv_mode(int sk)
    221 {
    222 	struct timeval tv_beg,tv_end,tv_diff;
    223 	long total;
    224 
    225 	syslog(LOG_INFO, "Receiving ...");
    226 
    227 	while (1) {
    228 		gettimeofday(&tv_beg, NULL);
    229 		total = 0;
    230 		while (total < data_size) {
    231 			int r;
    232 			if ((r = recv(sk, buf, data_size, 0)) <= 0) {
    233 				if (r < 0)
    234 					syslog(LOG_ERR, "Read failed: %s (%d)",
    235 							strerror(errno), errno);
    236 				return;
    237 			}
    238 			total += r;
    239 		}
    240 		gettimeofday(&tv_end, NULL);
    241 
    242 		timersub(&tv_end, &tv_beg, &tv_diff);
    243 
    244 		syslog(LOG_INFO,"%ld bytes in %.2fm speed %.2f kb", total,
    245 			tv2fl(tv_diff) / 60.0,
    246 			(float)( total / tv2fl(tv_diff) ) / 1024.0 );
    247 	}
    248 }
    249 
    250 static void send_mode(char *svr)
    251 {
    252 	struct sco_options so;
    253 	socklen_t len;
    254 	uint32_t seq;
    255 	int i, sk;
    256 
    257 	if ((sk = do_connect(svr)) < 0) {
    258 		syslog(LOG_ERR, "Can't connect to the server: %s (%d)",
    259 							strerror(errno), errno);
    260 		exit(1);
    261 	}
    262 
    263 	len = sizeof(so);
    264 	if (getsockopt(sk, SOL_SCO, SCO_OPTIONS, &so, &len) < 0) {
    265 		syslog(LOG_ERR, "Can't get SCO options: %s (%d)",
    266 							strerror(errno), errno);
    267 		exit(1);
    268 	}
    269 
    270 	syslog(LOG_INFO,"Sending ...");
    271 
    272 	for (i = 6; i < so.mtu; i++)
    273 		buf[i] = 0x7f;
    274 
    275 	seq = 0;
    276 	while (1) {
    277 		*(uint32_t *) buf = htobl(seq);
    278 		*(uint16_t *) (buf + 4) = htobs(data_size);
    279 		seq++;
    280 
    281 		if (send(sk, buf, so.mtu, 0) <= 0) {
    282 			syslog(LOG_ERR, "Send failed: %s (%d)",
    283 							strerror(errno), errno);
    284 			exit(1);
    285 		}
    286 
    287 		usleep(1);
    288 	}
    289 }
    290 
    291 static void reconnect_mode(char *svr)
    292 {
    293 	while (1) {
    294 		int sk;
    295 
    296 		if ((sk = do_connect(svr)) < 0) {
    297 			syslog(LOG_ERR, "Can't connect to the server: %s (%d)",
    298 							strerror(errno), errno);
    299 			exit(1);
    300 		}
    301 
    302 		close(sk);
    303 
    304 		sleep(5);
    305 	}
    306 }
    307 
    308 static void multy_connect_mode(char *svr)
    309 {
    310 	while (1) {
    311 		int i, sk;
    312 
    313 		for (i = 0; i < 10; i++){
    314 			if (fork())
    315 				continue;
    316 
    317 			/* Child */
    318 			sk = do_connect(svr);
    319 			if (sk < 0) {
    320 				syslog(LOG_ERR, "Can't connect to the server: %s (%d)",
    321 							strerror(errno), errno);
    322 			}
    323 			close(sk);
    324 			exit(0);
    325 		}
    326 
    327 		sleep(19);
    328 	}
    329 }
    330 
    331 static void usage(void)
    332 {
    333 	printf("scotest - SCO testing\n"
    334 		"Usage:\n");
    335 	printf("\tscotest <mode> [-b bytes] [-p pkt_type] [bd_addr]\n");
    336 	printf("Modes:\n"
    337 		"\t-d dump (server)\n"
    338 		"\t-c reconnect (client)\n"
    339 		"\t-m multiple connects (client)\n"
    340 		"\t-r receive (server)\n"
    341 		"\t-s connect and send (client)\n"
    342 		"\t-n connect and be silent (client)\n");
    343 }
    344 
    345 int main(int argc ,char *argv[])
    346 {
    347 	struct sigaction sa;
    348 	int opt, sk, mode = RECV;
    349 
    350 	while ((opt=getopt(argc,argv,"rdscmnb:p:")) != EOF) {
    351 		switch(opt) {
    352 		case 'r':
    353 			mode = RECV;
    354 			break;
    355 
    356 		case 's':
    357 			mode = SEND;
    358 			break;
    359 
    360 		case 'd':
    361 			mode = DUMP;
    362 			break;
    363 
    364 		case 'c':
    365 			mode = RECONNECT;
    366 			break;
    367 
    368 		case 'm':
    369 			mode = MULTY;
    370 			break;
    371 
    372 		case 'n':
    373 			mode = CONNECT;
    374 			break;
    375 
    376 		case 'b':
    377 			data_size = atoi(optarg);
    378 			break;
    379 
    380 		case 'p':
    381 			if (sscanf(optarg, "0x%4hx", &pkt_type) != 1) {
    382 				usage();
    383 				exit(1);
    384 			}
    385 			break;
    386 
    387 		default:
    388 			usage();
    389 			exit(1);
    390 		}
    391 	}
    392 
    393 	if (!(argc - optind) && (mode != RECV && mode != DUMP)) {
    394 		usage();
    395 		exit(1);
    396 	}
    397 
    398 	if (!(buf = malloc(data_size))) {
    399 		perror("Can't allocate data buffer");
    400 		exit(1);
    401 	}
    402 
    403 	memset(&sa, 0, sizeof(sa));
    404 	sa.sa_handler = SIG_IGN;
    405 	sa.sa_flags   = SA_NOCLDSTOP;
    406 	sigaction(SIGCHLD, &sa, NULL);
    407 
    408 	openlog("scotest", LOG_PERROR | LOG_PID, LOG_LOCAL0);
    409 
    410 	switch( mode ){
    411 		case RECV:
    412 			do_listen(recv_mode);
    413 			break;
    414 
    415 		case DUMP:
    416 			do_listen(dump_mode);
    417 			break;
    418 
    419 		case SEND:
    420 			send_mode(argv[optind]);
    421 			break;
    422 
    423 		case RECONNECT:
    424 			reconnect_mode(argv[optind]);
    425 			break;
    426 
    427 		case MULTY:
    428 			multy_connect_mode(argv[optind]);
    429 			break;
    430 
    431 		case CONNECT:
    432 			sk = do_connect(argv[optind]);
    433 			if (sk < 0)
    434 				exit(1);
    435 			dump_mode(sk);
    436 			break;
    437 	}
    438 
    439 	syslog(LOG_INFO, "Exit");
    440 
    441 	closelog();
    442 
    443 	return 0;
    444 }
    445