Tizen 2.0 Release
[framework/connectivity/bluez.git] / test / scotest.c
1 /*
2  *
3  *  BlueZ - Bluetooth protocol stack for Linux
4  *
5  *  Copyright (C) 2002-2003  Maxim Krasnyansky <maxk@qualcomm.com>
6  *  Copyright (C) 2002-2010  Marcel Holtmann <marcel@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 static bdaddr_t bdaddr;
59
60 static float tv2fl(struct timeval tv)
61 {
62         return (float)tv.tv_sec + (float)(tv.tv_usec/1000000.0);
63 }
64
65 static int do_connect(char *svr)
66 {
67         struct sockaddr_sco addr;
68         struct sco_conninfo conn;
69         socklen_t optlen;
70         int sk;
71
72         /* Create socket */
73         sk = socket(PF_BLUETOOTH, SOCK_SEQPACKET, BTPROTO_SCO);
74         if (sk < 0) {
75                 syslog(LOG_ERR, "Can't create socket: %s (%d)",
76                                                         strerror(errno), errno);
77                 return -1;
78         }
79
80         /* Bind to local address */
81         memset(&addr, 0, sizeof(addr));
82         addr.sco_family = AF_BLUETOOTH;
83         bacpy(&addr.sco_bdaddr, &bdaddr);
84
85         if (bind(sk, (struct sockaddr *) &addr, sizeof(addr)) < 0) {
86                 syslog(LOG_ERR, "Can't bind socket: %s (%d)",
87                                                         strerror(errno), errno);
88                 goto error;
89         }
90
91         /* Connect to remote device */
92         memset(&addr, 0, sizeof(addr));
93         addr.sco_family = AF_BLUETOOTH;
94         str2ba(svr, &addr.sco_bdaddr);
95
96         if (connect(sk, (struct sockaddr *) &addr, sizeof(addr)) < 0) {
97                 syslog(LOG_ERR, "Can't connect: %s (%d)",
98                                                         strerror(errno), errno);
99                 goto error;
100         }
101
102         /* Get connection information */
103         memset(&conn, 0, sizeof(conn));
104         optlen = sizeof(conn);
105
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);
109                 goto error;
110         }
111
112         syslog(LOG_INFO, "Connected [handle %d, class 0x%02x%02x%02x]",
113                 conn.hci_handle,
114                 conn.dev_class[2], conn.dev_class[1], conn.dev_class[0]);
115
116         return sk;
117
118 error:
119         close(sk);
120         return -1;
121 }
122
123 static void do_listen(void (*handler)(int sk))
124 {
125         struct sockaddr_sco addr;
126         struct sco_conninfo conn;
127         socklen_t optlen;
128         int sk, nsk;
129         char ba[18];
130
131         /* Create socket */
132         sk = socket(PF_BLUETOOTH, SOCK_SEQPACKET, BTPROTO_SCO);
133         if (sk < 0) {
134                 syslog(LOG_ERR, "Can't create socket: %s (%d)",
135                                                         strerror(errno), errno);
136                 exit(1);
137         }
138
139         /* Bind to local address */
140         memset(&addr, 0, sizeof(addr));
141         addr.sco_family = AF_BLUETOOTH;
142         bacpy(&addr.sco_bdaddr, &bdaddr);
143
144         if (bind(sk, (struct sockaddr *) &addr, sizeof(addr)) < 0) {
145                 syslog(LOG_ERR, "Can't bind socket: %s (%d)",
146                                                         strerror(errno), errno);
147                 goto error;
148         }
149
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);
154                 goto error;
155         }
156
157         syslog(LOG_INFO,"Waiting for connection ...");
158
159         while (1) {
160                 memset(&addr, 0, sizeof(addr));
161                 optlen = sizeof(addr);
162
163                 nsk = accept(sk, (struct sockaddr *) &addr, &optlen);
164                 if (nsk < 0) {
165                         syslog(LOG_ERR,"Accept failed: %s (%d)",
166                                                         strerror(errno), errno);
167                         goto error;
168                 }
169                 if (fork()) {
170                         /* Parent */
171                         close(nsk);
172                         continue;
173                 }
174                 /* Child */
175                 close(sk);
176
177                 /* Get connection information */
178                 memset(&conn, 0, sizeof(conn));
179                 optlen = sizeof(conn);
180
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);
184                         close(nsk);
185                         goto error;
186                 }
187
188                 ba2str(&addr.sco_bdaddr, ba);
189                 syslog(LOG_INFO, "Connect from %s [handle %d, class 0x%02x%02x%02x]",
190                         ba, conn.hci_handle,
191                         conn.dev_class[2], conn.dev_class[1], conn.dev_class[0]);
192
193                 handler(nsk);
194
195                 syslog(LOG_INFO, "Disconnect");
196                 exit(0);
197         }
198
199         return;
200
201 error:
202         close(sk);
203         exit(1);
204 }
205
206 static void dump_mode(int sk)
207 {
208         int len;
209
210         syslog(LOG_INFO,"Receiving ...");
211         while ((len = read(sk, buf, data_size)) > 0)
212                 syslog(LOG_INFO, "Recevied %d bytes", len);
213 }
214
215 static void recv_mode(int sk)
216 {
217         struct timeval tv_beg,tv_end,tv_diff;
218         long total;
219
220         syslog(LOG_INFO, "Receiving ...");
221
222         while (1) {
223                 gettimeofday(&tv_beg, NULL);
224                 total = 0;
225                 while (total < data_size) {
226                         int r;
227                         if ((r = recv(sk, buf, data_size, 0)) <= 0) {
228                                 if (r < 0)
229                                         syslog(LOG_ERR, "Read failed: %s (%d)",
230                                                         strerror(errno), errno);
231                                 return;
232                         }
233                         total += r;
234                 }
235                 gettimeofday(&tv_end, NULL);
236
237                 timersub(&tv_end, &tv_beg, &tv_diff);
238
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 );
242         }
243 }
244
245 static void send_mode(char *svr)
246 {
247         struct sco_options so;
248         socklen_t len;
249         uint32_t seq;
250         int i, sk;
251
252         if ((sk = do_connect(svr)) < 0) {
253                 syslog(LOG_ERR, "Can't connect to the server: %s (%d)",
254                                                         strerror(errno), errno);
255                 exit(1);
256         }
257
258         len = sizeof(so);
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);
262                 exit(1);
263         }
264
265         syslog(LOG_INFO,"Sending ...");
266
267         for (i = 6; i < so.mtu; i++)
268                 buf[i] = 0x7f;
269
270         seq = 0;
271         while (1) {
272                 *(uint32_t *) buf = htobl(seq);
273                 *(uint16_t *) (buf + 4) = htobs(data_size);
274                 seq++;
275
276                 if (send(sk, buf, so.mtu, 0) <= 0) {
277                         syslog(LOG_ERR, "Send failed: %s (%d)",
278                                                         strerror(errno), errno);
279                         exit(1);
280                 }
281
282                 usleep(1);
283         }
284 }
285
286 static void reconnect_mode(char *svr)
287 {
288         while (1) {
289                 int sk;
290
291                 if ((sk = do_connect(svr)) < 0) {
292                         syslog(LOG_ERR, "Can't connect to the server: %s (%d)",
293                                                         strerror(errno), errno);
294                         exit(1);
295                 }
296
297                 close(sk);
298
299                 sleep(5);
300         }
301 }
302
303 static void multy_connect_mode(char *svr)
304 {
305         while (1) {
306                 int i, sk;
307
308                 for (i = 0; i < 10; i++){
309                         if (fork())
310                                 continue;
311
312                         /* Child */
313                         sk = do_connect(svr);
314                         if (sk < 0) {
315                                 syslog(LOG_ERR, "Can't connect to the server: %s (%d)",
316                                                         strerror(errno), errno);
317                         }
318                         close(sk);
319                         exit(0);
320                 }
321
322                 sleep(19);
323         }
324 }
325
326 static void usage(void)
327 {
328         printf("scotest - SCO testing\n"
329                 "Usage:\n");
330         printf("\tscotest <mode> [-b bytes] [bd_addr]\n");
331         printf("Modes:\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");
338 }
339
340 int main(int argc ,char *argv[])
341 {
342         struct sigaction sa;
343         int opt, sk, mode = RECV;
344
345         while ((opt=getopt(argc,argv,"rdscmnb:")) != EOF) {
346                 switch(opt) {
347                 case 'r':
348                         mode = RECV;
349                         break;
350
351                 case 's':
352                         mode = SEND;
353                         break;
354
355                 case 'd':
356                         mode = DUMP;
357                         break;
358
359                 case 'c':
360                         mode = RECONNECT;
361                         break;
362
363                 case 'm':
364                         mode = MULTY;
365                         break;
366
367                 case 'n':
368                         mode = CONNECT;
369                         break;
370
371                 case 'b':
372                         data_size = atoi(optarg);
373                         break;
374
375                 default:
376                         usage();
377                         exit(1);
378                 }
379         }
380
381         if (!(argc - optind) && (mode != RECV && mode != DUMP)) {
382                 usage();
383                 exit(1);
384         }
385
386         if (!(buf = malloc(data_size))) {
387                 perror("Can't allocate data buffer");
388                 exit(1);
389         }
390
391         memset(&sa, 0, sizeof(sa));
392         sa.sa_handler = SIG_IGN;
393         sa.sa_flags   = SA_NOCLDSTOP;
394         sigaction(SIGCHLD, &sa, NULL);
395
396         openlog("scotest", LOG_PERROR | LOG_PID, LOG_LOCAL0);
397
398         switch( mode ){
399                 case RECV:
400                         do_listen(recv_mode);
401                         break;
402
403                 case DUMP:
404                         do_listen(dump_mode);
405                         break;
406
407                 case SEND:
408                         send_mode(argv[optind]);
409                         break;
410
411                 case RECONNECT:
412                         reconnect_mode(argv[optind]);
413                         break;
414
415                 case MULTY:
416                         multy_connect_mode(argv[optind]);
417                         break;
418
419                 case CONNECT:
420                         sk = do_connect(argv[optind]);
421                         if (sk < 0)
422                                 exit(1);
423                         dump_mode(sk);
424                         break;
425         }
426
427         syslog(LOG_INFO, "Exit");
428
429         closelog();
430
431         return 0;
432 }