3 * BlueZ - Bluetooth protocol stack for Linux
5 * Copyright (C) 2002-2003 Maxim Krasnyansky <maxk@qualcomm.com>
6 * Copyright (C) 2002-2010 Marcel Holtmann <marcel@holtmann.org>
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.
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.
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
38 #include <sys/socket.h>
40 #include <bluetooth/bluetooth.h>
41 #include <bluetooth/sco.h>
53 static unsigned char *buf;
55 /* Default data size */
56 static long data_size = 672;
58 static bdaddr_t bdaddr;
60 static float tv2fl(struct timeval tv)
62 return (float)tv.tv_sec + (float)(tv.tv_usec/1000000.0);
65 static int do_connect(char *svr)
67 struct sockaddr_sco addr;
68 struct sco_conninfo conn;
73 sk = socket(PF_BLUETOOTH, SOCK_SEQPACKET, BTPROTO_SCO);
75 syslog(LOG_ERR, "Can't create socket: %s (%d)",
76 strerror(errno), errno);
80 /* Bind to local address */
81 memset(&addr, 0, sizeof(addr));
82 addr.sco_family = AF_BLUETOOTH;
83 bacpy(&addr.sco_bdaddr, &bdaddr);
85 if (bind(sk, (struct sockaddr *) &addr, sizeof(addr)) < 0) {
86 syslog(LOG_ERR, "Can't bind socket: %s (%d)",
87 strerror(errno), errno);
91 /* Connect to remote device */
92 memset(&addr, 0, sizeof(addr));
93 addr.sco_family = AF_BLUETOOTH;
94 str2ba(svr, &addr.sco_bdaddr);
96 if (connect(sk, (struct sockaddr *) &addr, sizeof(addr)) < 0) {
97 syslog(LOG_ERR, "Can't connect: %s (%d)",
98 strerror(errno), errno);
102 /* Get connection information */
103 memset(&conn, 0, sizeof(conn));
104 optlen = sizeof(conn);
106 if (getsockopt(sk, SOL_SCO, SCO_CONNINFO, &conn, &optlen) < 0) {
107 syslog(LOG_ERR, "Can't get SCO connection information: %s (%d)",
108 strerror(errno), errno);
112 syslog(LOG_INFO, "Connected [handle %d, class 0x%02x%02x%02x]",
114 conn.dev_class[2], conn.dev_class[1], conn.dev_class[0]);
123 static void do_listen(void (*handler)(int sk))
125 struct sockaddr_sco addr;
126 struct sco_conninfo conn;
132 sk = socket(PF_BLUETOOTH, SOCK_SEQPACKET, BTPROTO_SCO);
134 syslog(LOG_ERR, "Can't create socket: %s (%d)",
135 strerror(errno), errno);
139 /* Bind to local address */
140 memset(&addr, 0, sizeof(addr));
141 addr.sco_family = AF_BLUETOOTH;
142 bacpy(&addr.sco_bdaddr, &bdaddr);
144 if (bind(sk, (struct sockaddr *) &addr, sizeof(addr)) < 0) {
145 syslog(LOG_ERR, "Can't bind socket: %s (%d)",
146 strerror(errno), errno);
150 /* Listen for connections */
151 if (listen(sk, 10)) {
152 syslog(LOG_ERR,"Can not listen on the socket: %s (%d)",
153 strerror(errno), errno);
157 syslog(LOG_INFO,"Waiting for connection ...");
160 memset(&addr, 0, sizeof(addr));
161 optlen = sizeof(addr);
163 nsk = accept(sk, (struct sockaddr *) &addr, &optlen);
165 syslog(LOG_ERR,"Accept failed: %s (%d)",
166 strerror(errno), errno);
177 /* Get connection information */
178 memset(&conn, 0, sizeof(conn));
179 optlen = sizeof(conn);
181 if (getsockopt(nsk, SOL_SCO, SCO_CONNINFO, &conn, &optlen) < 0) {
182 syslog(LOG_ERR, "Can't get SCO connection information: %s (%d)",
183 strerror(errno), errno);
188 ba2str(&addr.sco_bdaddr, ba);
189 syslog(LOG_INFO, "Connect from %s [handle %d, class 0x%02x%02x%02x]",
191 conn.dev_class[2], conn.dev_class[1], conn.dev_class[0]);
195 syslog(LOG_INFO, "Disconnect");
206 static void dump_mode(int sk)
210 syslog(LOG_INFO,"Receiving ...");
211 while ((len = read(sk, buf, data_size)) > 0)
212 syslog(LOG_INFO, "Recevied %d bytes", len);
215 static void recv_mode(int sk)
217 struct timeval tv_beg,tv_end,tv_diff;
220 syslog(LOG_INFO, "Receiving ...");
223 gettimeofday(&tv_beg, NULL);
225 while (total < data_size) {
227 if ((r = recv(sk, buf, data_size, 0)) <= 0) {
229 syslog(LOG_ERR, "Read failed: %s (%d)",
230 strerror(errno), errno);
235 gettimeofday(&tv_end, NULL);
237 timersub(&tv_end, &tv_beg, &tv_diff);
239 syslog(LOG_INFO,"%ld bytes in %.2fm speed %.2f kb", total,
240 tv2fl(tv_diff) / 60.0,
241 (float)( total / tv2fl(tv_diff) ) / 1024.0 );
245 static void send_mode(char *svr)
247 struct sco_options so;
252 if ((sk = do_connect(svr)) < 0) {
253 syslog(LOG_ERR, "Can't connect to the server: %s (%d)",
254 strerror(errno), errno);
259 if (getsockopt(sk, SOL_SCO, SCO_OPTIONS, &so, &len) < 0) {
260 syslog(LOG_ERR, "Can't get SCO options: %s (%d)",
261 strerror(errno), errno);
265 syslog(LOG_INFO,"Sending ...");
267 for (i = 6; i < so.mtu; i++)
272 *(uint32_t *) buf = htobl(seq);
273 *(uint16_t *) (buf + 4) = htobs(data_size);
276 if (send(sk, buf, so.mtu, 0) <= 0) {
277 syslog(LOG_ERR, "Send failed: %s (%d)",
278 strerror(errno), errno);
286 static void reconnect_mode(char *svr)
291 if ((sk = do_connect(svr)) < 0) {
292 syslog(LOG_ERR, "Can't connect to the server: %s (%d)",
293 strerror(errno), errno);
303 static void multy_connect_mode(char *svr)
308 for (i = 0; i < 10; i++){
313 sk = do_connect(svr);
315 syslog(LOG_ERR, "Can't connect to the server: %s (%d)",
316 strerror(errno), errno);
326 static void usage(void)
328 printf("scotest - SCO testing\n"
330 printf("\tscotest <mode> [-b bytes] [bd_addr]\n");
332 "\t-d dump (server)\n"
333 "\t-c reconnect (client)\n"
334 "\t-m multiple connects (client)\n"
335 "\t-r receive (server)\n"
336 "\t-s connect and send (client)\n"
337 "\t-n connect and be silent (client)\n");
340 int main(int argc ,char *argv[])
343 int opt, sk, mode = RECV;
345 while ((opt=getopt(argc,argv,"rdscmnb:")) != EOF) {
372 data_size = atoi(optarg);
381 if (!(argc - optind) && (mode != RECV && mode != DUMP)) {
386 if (!(buf = malloc(data_size))) {
387 perror("Can't allocate data buffer");
391 memset(&sa, 0, sizeof(sa));
392 sa.sa_handler = SIG_IGN;
393 sa.sa_flags = SA_NOCLDSTOP;
394 sigaction(SIGCHLD, &sa, NULL);
396 openlog("scotest", LOG_PERROR | LOG_PID, LOG_LOCAL0);
400 do_listen(recv_mode);
404 do_listen(dump_mode);
408 send_mode(argv[optind]);
412 reconnect_mode(argv[optind]);
416 multy_connect_mode(argv[optind]);
420 sk = do_connect(argv[optind]);
427 syslog(LOG_INFO, "Exit");