OSDN Git Service

Stop trying to send A2DP packets quickly to catch-up on missed write()'s after
[android-x86/external-bluetooth-bluez.git] / test / agent.c
1 /*
2  *
3  *  BlueZ - Bluetooth protocol stack for Linux
4  *
5  *  Copyright (C) 2004-2009  Marcel Holtmann <marcel@holtmann.org>
6  *
7  *
8  *  This program is free software; you can redistribute it and/or modify
9  *  it under the terms of the GNU General Public License as published by
10  *  the Free Software Foundation; either version 2 of the License, or
11  *  (at your option) any later version.
12  *
13  *  This program is distributed in the hope that it will be useful,
14  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
15  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16  *  GNU General Public License for more details.
17  *
18  *  You should have received a copy of the GNU General Public License
19  *  along with this program; if not, write to the Free Software
20  *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
21  *
22  */
23
24 #ifdef HAVE_CONFIG_H
25 #include <config.h>
26 #endif
27
28 #include <stdio.h>
29 #include <errno.h>
30 #include <unistd.h>
31 #include <stdlib.h>
32 #include <signal.h>
33 #include <getopt.h>
34 #include <string.h>
35
36 #include <dbus/dbus.h>
37
38 static char *passkey = NULL;
39
40 static int do_reject = 0;
41
42 static volatile sig_atomic_t __io_canceled = 0;
43 static volatile sig_atomic_t __io_terminated = 0;
44
45 static void sig_term(int sig)
46 {
47         __io_canceled = 1;
48 }
49
50 static DBusHandlerResult agent_filter(DBusConnection *conn,
51                                                 DBusMessage *msg, void *data)
52 {
53         const char *name, *old, *new;
54
55         if (!dbus_message_is_signal(msg, DBUS_INTERFACE_DBUS,
56                                                 "NameOwnerChanged"))
57                 return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
58
59         if (!dbus_message_get_args(msg, NULL,
60                                         DBUS_TYPE_STRING, &name,
61                                         DBUS_TYPE_STRING, &old,
62                                         DBUS_TYPE_STRING, &new,
63                                         DBUS_TYPE_INVALID)) {
64                 fprintf(stderr,
65                         "Invalid arguments for NameOwnerChanged signal");
66                 return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
67         }
68
69         if (!strcmp(name, "org.bluez") && *new == '\0') {
70                 fprintf(stderr, "Agent has been terminated\n");
71                 __io_terminated = 1;
72         }
73
74         return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
75 }
76
77 static DBusHandlerResult request_pincode_message(DBusConnection *conn,
78                                                 DBusMessage *msg, void *data)
79 {
80         DBusMessage *reply;
81         const char *path;
82
83         if (!passkey)
84                 return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
85
86         if (!dbus_message_get_args(msg, NULL,
87                                         DBUS_TYPE_OBJECT_PATH, &path,
88                                         DBUS_TYPE_INVALID)) {
89                 fprintf(stderr, "Invalid arguments for RequestPinCode method");
90                 return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
91         }
92
93         if (do_reject) {
94                 reply = dbus_message_new_error(msg,
95                                         "org.bluez.Error.Rejected", "");
96                 goto send;
97         }
98
99         reply = dbus_message_new_method_return(msg);
100         if (!reply) {
101                 fprintf(stderr, "Can't create reply message\n");
102                 return DBUS_HANDLER_RESULT_NEED_MEMORY;
103         }
104
105         printf("Pincode request for device %s\n", path);
106
107         dbus_message_append_args(reply, DBUS_TYPE_STRING, &passkey,
108                                         DBUS_TYPE_INVALID);
109
110 send:
111         dbus_connection_send(conn, reply, NULL);
112
113         dbus_connection_flush(conn);
114
115         dbus_message_unref(reply);
116
117         return DBUS_HANDLER_RESULT_HANDLED;
118 }
119
120 static DBusHandlerResult request_passkey_message(DBusConnection *conn,
121                                                 DBusMessage *msg, void *data)
122 {
123         DBusMessage *reply;
124         const char *path;
125         unsigned int int_passkey;
126
127         if (!passkey)
128                 return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
129
130
131         if (!dbus_message_get_args(msg, NULL,
132                                         DBUS_TYPE_OBJECT_PATH, &path,
133                                         DBUS_TYPE_INVALID)) {
134                 fprintf(stderr, "Invalid arguments for RequestPasskey method");
135                 return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
136         }
137
138         if (do_reject) {
139                 reply = dbus_message_new_error(msg,
140                                         "org.bluez.Error.Rejected", "");
141                 goto send;
142         }
143
144         reply = dbus_message_new_method_return(msg);
145         if (!reply) {
146                 fprintf(stderr, "Can't create reply message\n");
147                 return DBUS_HANDLER_RESULT_NEED_MEMORY;
148         }
149
150         printf("Passkey request for device %s\n", path);
151
152         int_passkey = strtoul(passkey, NULL, 10);
153
154         dbus_message_append_args(reply, DBUS_TYPE_UINT32, &int_passkey,
155                                         DBUS_TYPE_INVALID);
156
157 send:
158         dbus_connection_send(conn, reply, NULL);
159
160         dbus_connection_flush(conn);
161
162         dbus_message_unref(reply);
163
164         return DBUS_HANDLER_RESULT_HANDLED;
165 }
166
167 static DBusHandlerResult cancel_message(DBusConnection *conn,
168                                                 DBusMessage *msg, void *data)
169 {
170         DBusMessage *reply;
171
172         if (!dbus_message_get_args(msg, NULL, DBUS_TYPE_INVALID)) {
173                 fprintf(stderr, "Invalid arguments for passkey Confirm method");
174                 return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
175         }
176
177         printf("Request canceled\n");
178
179         reply = dbus_message_new_method_return(msg);
180         if (!reply) {
181                 fprintf(stderr, "Can't create reply message\n");
182                 return DBUS_HANDLER_RESULT_NEED_MEMORY;
183         }
184
185         dbus_connection_send(conn, reply, NULL);
186
187         dbus_connection_flush(conn);
188
189         dbus_message_unref(reply);
190
191         return DBUS_HANDLER_RESULT_HANDLED;
192 }
193
194 static DBusHandlerResult release_message(DBusConnection *conn,
195                                                 DBusMessage *msg, void *data)
196 {
197         DBusMessage *reply;
198
199         if (!dbus_message_get_args(msg, NULL, DBUS_TYPE_INVALID)) {
200                 fprintf(stderr, "Invalid arguments for Release method");
201                 return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
202         }
203
204         if (!__io_canceled)
205                 fprintf(stderr, "Agent has been released\n");
206
207         __io_terminated = 1;
208
209         reply = dbus_message_new_method_return(msg);
210         if (!reply) {
211                 fprintf(stderr, "Can't create reply message\n");
212                 return DBUS_HANDLER_RESULT_NEED_MEMORY;
213         }
214
215         dbus_connection_send(conn, reply, NULL);
216
217         dbus_connection_flush(conn);
218
219         dbus_message_unref(reply);
220
221         return DBUS_HANDLER_RESULT_HANDLED;
222 }
223
224 static DBusHandlerResult authorize_message(DBusConnection *conn,
225                                                 DBusMessage *msg, void *data)
226 {
227         DBusMessage *reply;
228         const char *path, *uuid;
229
230         if (!dbus_message_get_args(msg, NULL, DBUS_TYPE_OBJECT_PATH, &path,
231                                         DBUS_TYPE_STRING, &uuid,
232                                         DBUS_TYPE_INVALID)) {
233                 fprintf(stderr, "Invalid arguments for Authorize method");
234                 return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
235         }
236
237         if (do_reject) {
238                 reply = dbus_message_new_error(msg,
239                                         "org.bluez.Error.Rejected", "");
240                 goto send;
241         }
242
243         reply = dbus_message_new_method_return(msg);
244         if (!reply) {
245                 fprintf(stderr, "Can't create reply message\n");
246                 return DBUS_HANDLER_RESULT_NEED_MEMORY;
247         }
248
249         printf("Authorizing request for %s\n", path);
250
251 send:
252         dbus_connection_send(conn, reply, NULL);
253
254         dbus_connection_flush(conn);
255
256         dbus_message_unref(reply);
257
258         return DBUS_HANDLER_RESULT_HANDLED;
259 }
260
261 static DBusHandlerResult agent_message(DBusConnection *conn,
262                                                 DBusMessage *msg, void *data)
263 {
264         if (dbus_message_is_method_call(msg, "org.bluez.Agent",
265                                                         "RequestPinCode"))
266                 return request_pincode_message(conn, msg, data);
267
268         if (dbus_message_is_method_call(msg, "org.bluez.Agent",
269                                                         "RequestPasskey"))
270                 return request_passkey_message(conn, msg, data);
271
272         if (dbus_message_is_method_call(msg, "org.bluez.Agent", "Cancel"))
273                 return cancel_message(conn, msg, data);
274
275         if (dbus_message_is_method_call(msg, "org.bluez.Agent", "Release"))
276                 return release_message(conn, msg, data);
277
278         if (dbus_message_is_method_call(msg, "org.bluez.Agent", "Authorize"))
279                 return authorize_message(conn, msg, data);
280
281         return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
282 }
283
284 static const DBusObjectPathVTable agent_table = {
285         .message_function = agent_message,
286 };
287
288 static int register_agent(DBusConnection *conn, const char *adapter_path,
289                                                 const char *agent_path,
290                                                 const char *capabilities)
291 {
292         DBusMessage *msg, *reply;
293         DBusError err;
294
295         if (!dbus_connection_register_object_path(conn, agent_path,
296                                                         &agent_table, NULL)) {
297                 fprintf(stderr, "Can't register object path for agent\n");
298                 return -1;
299         }
300
301         msg = dbus_message_new_method_call("org.bluez", adapter_path,
302                                         "org.bluez.Adapter", "RegisterAgent");
303         if (!msg) {
304                 fprintf(stderr, "Can't allocate new method call\n");
305                 return -1;
306         }
307
308         dbus_message_append_args(msg, DBUS_TYPE_OBJECT_PATH, &agent_path,
309                                         DBUS_TYPE_STRING, &capabilities,
310                                         DBUS_TYPE_INVALID);
311
312         dbus_error_init(&err);
313
314         reply = dbus_connection_send_with_reply_and_block(conn, msg, -1, &err);
315
316         dbus_message_unref(msg);
317
318         if (!reply) {
319                 fprintf(stderr, "Can't register agent\n");
320                 if (dbus_error_is_set(&err)) {
321                         fprintf(stderr, "%s\n", err.message);
322                         dbus_error_free(&err);
323                 }
324                 return -1;
325         }
326
327         dbus_message_unref(reply);
328
329         dbus_connection_flush(conn);
330
331         return 0;
332 }
333
334 static int unregister_agent(DBusConnection *conn, const char *adapter_path,
335                                                         const char *agent_path)
336 {
337         DBusMessage *msg, *reply;
338         DBusError err;
339
340         msg = dbus_message_new_method_call("org.bluez", adapter_path,
341                                         "org.bluez.Adapter", "UnregisterAgent");
342         if (!msg) {
343                 fprintf(stderr, "Can't allocate new method call\n");
344                 return -1;
345         }
346
347         dbus_message_append_args(msg, DBUS_TYPE_OBJECT_PATH, &agent_path,
348                                                         DBUS_TYPE_INVALID);
349
350         dbus_error_init(&err);
351
352         reply = dbus_connection_send_with_reply_and_block(conn, msg, -1, &err);
353
354         dbus_message_unref(msg);
355
356         if (!reply) {
357                 fprintf(stderr, "Can't unregister agent\n");
358                 if (dbus_error_is_set(&err)) {
359                         fprintf(stderr, "%s\n", err.message);
360                         dbus_error_free(&err);
361                 }
362                 return -1;
363         }
364
365         dbus_message_unref(reply);
366
367         dbus_connection_flush(conn);
368
369         dbus_connection_unregister_object_path(conn, agent_path);
370
371         return 0;
372 }
373
374 static int create_paired_device(DBusConnection *conn, const char *adapter_path,
375                                                 const char *agent_path,
376                                                 const char *capabilities,
377                                                 const char *device)
378 {
379         dbus_bool_t success;
380         DBusMessage *msg;
381
382         msg = dbus_message_new_method_call("org.bluez", adapter_path,
383                                                 "org.bluez.Adapter",
384                                                 "CreatePairedDevice");
385         if (!msg) {
386                 fprintf(stderr, "Can't allocate new method call\n");
387                 return -1;
388         }
389
390         dbus_message_append_args(msg, DBUS_TYPE_STRING, &device,
391                                         DBUS_TYPE_OBJECT_PATH, &agent_path,
392                                         DBUS_TYPE_STRING, &capabilities,
393                                         DBUS_TYPE_INVALID);
394
395         success = dbus_connection_send(conn, msg, NULL);
396
397         dbus_message_unref(msg);
398
399         if (!success) {
400                 fprintf(stderr, "Not enough memory for message send\n");
401                 return -1;
402         }
403
404         dbus_connection_flush(conn);
405
406         return 0;
407 }
408
409 static char *get_default_adapter_path(DBusConnection *conn)
410 {
411         DBusMessage *msg, *reply;
412         DBusError err;
413         const char *reply_path;
414         char *path;
415
416         msg = dbus_message_new_method_call("org.bluez", "/",
417                                         "org.bluez.Manager", "DefaultAdapter");
418
419         if (!msg) {
420                 fprintf(stderr, "Can't allocate new method call\n");
421                 return NULL;
422         }
423
424         dbus_error_init(&err);
425
426         reply = dbus_connection_send_with_reply_and_block(conn, msg, -1, &err);
427
428         dbus_message_unref(msg);
429
430         if (!reply) {
431                 fprintf(stderr,
432                         "Can't get default adapter\n");
433                 if (dbus_error_is_set(&err)) {
434                         fprintf(stderr, "%s\n", err.message);
435                         dbus_error_free(&err);
436                 }
437                 return NULL;
438         }
439
440         if (!dbus_message_get_args(reply, &err,
441                                         DBUS_TYPE_OBJECT_PATH, &reply_path,
442                                         DBUS_TYPE_INVALID)) {
443                 fprintf(stderr,
444                         "Can't get reply arguments\n");
445                 if (dbus_error_is_set(&err)) {
446                         fprintf(stderr, "%s\n", err.message);
447                         dbus_error_free(&err);
448                 }
449                 return NULL;
450         }
451
452         path = strdup(reply_path);
453
454         dbus_message_unref(reply);
455
456         dbus_connection_flush(conn);
457
458         return path;
459 }
460
461 static char *get_adapter_path(DBusConnection *conn, const char *adapter)
462 {
463         DBusMessage *msg, *reply;
464         DBusError err;
465         const char *reply_path;
466         char *path;
467
468         if (!adapter)
469                 return get_default_adapter_path(conn);
470
471         msg = dbus_message_new_method_call("org.bluez", "/",
472                                         "org.bluez.Manager", "FindAdapter");
473
474         if (!msg) {
475                 fprintf(stderr, "Can't allocate new method call\n");
476                 return NULL;
477         }
478
479         dbus_message_append_args(msg, DBUS_TYPE_STRING, &adapter,
480                                         DBUS_TYPE_INVALID);
481
482         dbus_error_init(&err);
483
484         reply = dbus_connection_send_with_reply_and_block(conn, msg, -1, &err);
485
486         dbus_message_unref(msg);
487
488         if (!reply) {
489                 fprintf(stderr,
490                         "Can't find adapter %s\n", adapter);
491                 if (dbus_error_is_set(&err)) {
492                         fprintf(stderr, "%s\n", err.message);
493                         dbus_error_free(&err);
494                 }
495                 return NULL;
496         }
497
498         if (!dbus_message_get_args(reply, &err,
499                                         DBUS_TYPE_OBJECT_PATH, &reply_path,
500                                         DBUS_TYPE_INVALID)) {
501                 fprintf(stderr,
502                         "Can't get reply arguments\n");
503                 if (dbus_error_is_set(&err)) {
504                         fprintf(stderr, "%s\n", err.message);
505                         dbus_error_free(&err);
506                 }
507                 return NULL;
508         }
509
510         path = strdup(reply_path);
511
512         dbus_message_unref(reply);
513
514         dbus_connection_flush(conn);
515
516         return path;
517 }
518
519 static void usage(void)
520 {
521         printf("Bluetooth agent ver %s\n\n", VERSION);
522
523         printf("Usage:\n"
524                 "\tagent [--adapter adapter-path] [--path agent-path] <passkey> [<device>]\n"
525                 "\n");
526 }
527
528 static struct option main_options[] = {
529         { "adapter",    1, 0, 'a' },
530         { "path",       1, 0, 'p' },
531         { "capabilites",1, 0, 'c' },
532         { "reject",     0, 0, 'r' },
533         { "help",       0, 0, 'h' },
534         { 0, 0, 0, 0 }
535 };
536
537 int main(int argc, char *argv[])
538 {
539         const char *capabilities = "DisplayYesNo";
540         struct sigaction sa;
541         DBusConnection *conn;
542         char match_string[128], default_path[128], *adapter_id = NULL;
543         char *adapter_path = NULL, *agent_path = NULL, *device = NULL;
544         int opt;
545
546         snprintf(default_path, sizeof(default_path),
547                                         "/org/bluez/agent_%d", getpid());
548
549         while ((opt = getopt_long(argc, argv, "+a:p:c:rh", main_options, NULL)) != EOF) {
550                 switch(opt) {
551                 case 'a':
552                         adapter_id = optarg;
553                         break;
554                 case 'p':
555                         if (optarg[0] != '/') {
556                                 fprintf(stderr, "Invalid path\n");
557                                 exit(1);
558                         }
559                         agent_path = strdup(optarg);
560                         break;
561                 case 'c':
562                         capabilities = optarg;
563                         break;
564                 case 'r':
565                         do_reject = 1;
566                         break;
567                 case 'h':
568                         usage();
569                         exit(0);
570                 default:
571                         exit(1);
572                 }
573         }
574
575         argc -= optind;
576         argv += optind;
577         optind = 0;
578
579         if (argc < 1) {
580                 usage();
581                 exit(1);
582         }
583
584         passkey = strdup(argv[0]);
585
586         if (argc > 1)
587                 device = strdup(argv[1]);
588
589         if (!agent_path)
590                 agent_path = strdup(default_path);
591
592         conn = dbus_bus_get(DBUS_BUS_SYSTEM, NULL);
593         if (!conn) {
594                 fprintf(stderr, "Can't get on system bus");
595                 exit(1);
596         }
597
598         adapter_path = get_adapter_path(conn, adapter_id);
599         if (!adapter_path)
600                 exit(1);
601
602         if (device) {
603                 if (create_paired_device(conn, adapter_path, agent_path,
604                                                 capabilities, device) < 0) {
605                         dbus_connection_unref(conn);
606                         exit(1);
607                 }
608         } else {
609                 if (register_agent(conn, adapter_path, agent_path,
610                                                         capabilities) < 0) {
611                         dbus_connection_unref(conn);
612                         exit(1);
613                 }
614         }
615
616         if (!dbus_connection_add_filter(conn, agent_filter, NULL, NULL))
617                 fprintf(stderr, "Can't add signal filter");
618
619         snprintf(match_string, sizeof(match_string),
620                         "interface=%s,member=NameOwnerChanged,arg0=%s",
621                         DBUS_INTERFACE_DBUS, "org.bluez");
622
623         dbus_bus_add_match(conn, match_string, NULL);
624
625         memset(&sa, 0, sizeof(sa));
626         sa.sa_flags   = SA_NOCLDSTOP;
627         sa.sa_handler = sig_term;
628         sigaction(SIGTERM, &sa, NULL);
629         sigaction(SIGINT,  &sa, NULL);
630
631         while (!__io_canceled && !__io_terminated) {
632                 if (dbus_connection_read_write_dispatch(conn, 500) != TRUE)
633                         break;
634         }
635
636         if (!__io_terminated && !device)
637                 unregister_agent(conn, adapter_path, agent_path);
638
639         free(adapter_path);
640         free(agent_path);
641
642         free(passkey);
643
644         dbus_connection_unref(conn);
645
646         return 0;
647 }