upgrade obexd to 0.47
[profile/ivi/obexd.git] / client / bluetooth.c
1 /*
2  *
3  *  OBEX Client
4  *
5  *  Copyright (C) 2012 Intel Corporation
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 <errno.h>
29 #include <inttypes.h>
30
31 #include <glib.h>
32 #include <gdbus.h>
33 #include <btio.h>
34
35 #include <bluetooth/bluetooth.h>
36 #include <bluetooth/rfcomm.h>
37 #include <bluetooth/sdp.h>
38 #include <bluetooth/sdp_lib.h>
39
40 #include "log.h"
41 #include "transport.h"
42 #include "bluetooth.h"
43
44 #define BT_BUS_NAME             "org.bluez"
45 #define BT_PATH                 "/"
46 #define BT_ADAPTER_IFACE        "org.bluez.Adapter"
47 #define BT_MANAGER_IFACE        "org.bluez.Manager"
48
49 #define BT_RX_MTU 32767
50 #define BT_TX_MTU 32767
51
52 #define OBC_BT_ERROR obc_bt_error_quark()
53
54 struct bluetooth_session {
55         guint id;
56         bdaddr_t src;
57         bdaddr_t dst;
58         uint16_t port;
59         DBusConnection *conn; /* system bus connection */
60         sdp_session_t *sdp;
61         GIOChannel *io;
62         GSList *pending_calls;
63         char *adapter;
64         char *service;
65         obc_transport_func func;
66         void *user_data;
67 };
68
69 static GSList *sessions = NULL;
70
71 static GQuark obc_bt_error_quark(void)
72 {
73         return g_quark_from_static_string("obc-bluetooth-error-quark");
74 }
75
76 static int send_method_call(struct bluetooth_session *session,
77                                         const char *path,
78                                         const char *interface,
79                                         const char *method,
80                                         DBusPendingCallNotifyFunction cb,
81                                         int type, ...)
82 {
83         DBusMessage *msg;
84         DBusPendingCall *call;
85         va_list args;
86
87         msg = dbus_message_new_method_call(BT_BUS_NAME, path, interface,
88                                                                 method);
89         if (!msg) {
90                 error("Unable to allocate new D-Bus %s message", method);
91                 return -ENOMEM;
92         }
93
94         va_start(args, type);
95
96         if (!dbus_message_append_args_valist(msg, type, args)) {
97                 dbus_message_unref(msg);
98                 va_end(args);
99                 return -EINVAL;
100         }
101
102         va_end(args);
103
104         if (!cb) {
105                 g_dbus_send_message(session->conn, msg);
106                 return 0;
107         }
108
109         if (!dbus_connection_send_with_reply(session->conn, msg, &call, -1)) {
110                 error("Sending %s failed", method);
111                 dbus_message_unref(msg);
112                 return -EIO;
113         }
114
115         dbus_pending_call_set_notify(call, cb, session, NULL);
116
117         session->pending_calls = g_slist_prepend(session->pending_calls, call);
118
119         dbus_message_unref(msg);
120
121         return 0;
122 }
123
124 static void finalize_call(DBusPendingCall *call)
125 {
126         if (!dbus_pending_call_get_completed(call))
127                 dbus_pending_call_cancel(call);
128
129         dbus_pending_call_unref(call);
130 }
131
132 static void session_destroy(struct bluetooth_session *session)
133 {
134         GSList *l;
135
136         DBG("%p", session);
137
138         if (g_slist_find(sessions, session) == NULL)
139                 return;
140
141         sessions = g_slist_remove(sessions, session);
142
143         if (session->adapter)
144                 send_method_call(session, session->adapter, BT_ADAPTER_IFACE,
145                                                 "ReleaseSession", NULL,
146                                                 DBUS_TYPE_INVALID);
147
148         l = session->pending_calls;
149
150         while (l) {
151                 DBusPendingCall *call = l->data;
152                 l = l->next;
153
154                 session->pending_calls = g_slist_remove(session->pending_calls, call);
155                 finalize_call(call);
156         }
157
158         if (session->io != NULL) {
159                 g_io_channel_shutdown(session->io, TRUE, NULL);
160                 g_io_channel_unref(session->io);
161         }
162
163         if (session->conn)
164                 dbus_connection_unref(session->conn);
165
166         g_free(session->service);
167         g_free(session->adapter);
168         g_free(session);
169 }
170
171 static void transport_callback(GIOChannel *io, GError *err, gpointer user_data)
172 {
173         struct bluetooth_session *session = user_data;
174
175         DBG("");
176
177         if (session->func)
178                 session->func(io, err, session->user_data);
179
180         if (err != NULL)
181                 session_destroy(session);
182 }
183
184 static GIOChannel *transport_connect(const bdaddr_t *src, const bdaddr_t *dst,
185                                         uint16_t port, BtIOConnect function,
186                                         gpointer user_data)
187 {
188         GIOChannel *io;
189         GError *err = NULL;
190
191         DBG("port %u", port);
192
193         if (port > 31) {
194                 io = bt_io_connect(BT_IO_L2CAP, function, user_data,
195                                 NULL, &err,
196                                 BT_IO_OPT_SOURCE_BDADDR, src,
197                                 BT_IO_OPT_DEST_BDADDR, dst,
198                                 BT_IO_OPT_PSM, port,
199                                 BT_IO_OPT_MODE, BT_IO_MODE_ERTM,
200                                 BT_IO_OPT_OMTU, BT_TX_MTU,
201                                 BT_IO_OPT_IMTU, BT_RX_MTU,
202                                 BT_IO_OPT_SEC_LEVEL, BT_IO_SEC_LOW,
203                                 BT_IO_OPT_INVALID);
204         } else {
205                 io = bt_io_connect(BT_IO_RFCOMM, function, user_data,
206                                 NULL, &err,
207                                 BT_IO_OPT_SOURCE_BDADDR, src,
208                                 BT_IO_OPT_DEST_BDADDR, dst,
209                                 BT_IO_OPT_CHANNEL, port,
210                                 BT_IO_OPT_SEC_LEVEL, BT_IO_SEC_LOW,
211                                 BT_IO_OPT_INVALID);
212         }
213
214         if (io != NULL)
215                 return io;
216
217         error("%s", err->message);
218         g_error_free(err);
219         return NULL;
220 }
221
222 static void search_callback(uint8_t type, uint16_t status,
223                         uint8_t *rsp, size_t size, void *user_data)
224 {
225         struct bluetooth_session *session = user_data;
226         unsigned int scanned, bytesleft = size;
227         int seqlen = 0;
228         uint8_t dataType;
229         uint16_t port = 0;
230         GError *gerr = NULL;
231
232         if (status || type != SDP_SVC_SEARCH_ATTR_RSP)
233                 goto failed;
234
235         scanned = sdp_extract_seqtype(rsp, bytesleft, &dataType, &seqlen);
236         if (!scanned || !seqlen)
237                 goto failed;
238
239         rsp += scanned;
240         bytesleft -= scanned;
241         do {
242                 sdp_record_t *rec;
243                 sdp_list_t *protos;
244                 sdp_data_t *data;
245                 int recsize, ch = -1;
246
247                 recsize = 0;
248                 rec = sdp_extract_pdu(rsp, bytesleft, &recsize);
249                 if (!rec)
250                         break;
251
252                 if (!recsize) {
253                         sdp_record_free(rec);
254                         break;
255                 }
256
257                 if (!sdp_get_access_protos(rec, &protos)) {
258                         ch = sdp_get_proto_port(protos, RFCOMM_UUID);
259                         sdp_list_foreach(protos,
260                                         (sdp_list_func_t) sdp_list_free, NULL);
261                         sdp_list_free(protos, NULL);
262                         protos = NULL;
263                 }
264
265                 data = sdp_data_get(rec, 0x0200);
266                 /* PSM must be odd and lsb of upper byte must be 0 */
267                 if (data != NULL && (data->val.uint16 & 0x0101) == 0x0001)
268                         ch = data->val.uint16;
269
270                 sdp_record_free(rec);
271
272                 if (ch > 0) {
273                         port = ch;
274                         break;
275                 }
276
277                 scanned += recsize;
278                 rsp += recsize;
279                 bytesleft -= recsize;
280         } while (scanned < size && bytesleft > 0);
281
282         if (port == 0)
283                 goto failed;
284
285         session->port = port;
286
287         g_io_channel_set_close_on_unref(session->io, FALSE);
288         g_io_channel_unref(session->io);
289
290         session->io = transport_connect(&session->src, &session->dst, port,
291                                                 transport_callback, session);
292         if (session->io != NULL) {
293                 sdp_close(session->sdp);
294                 session->sdp = NULL;
295                 return;
296         }
297
298 failed:
299         if (session->io != NULL) {
300                 g_io_channel_shutdown(session->io, TRUE, NULL);
301                 g_io_channel_unref(session->io);
302                 session->io = NULL;
303         }
304
305         g_set_error(&gerr, OBC_BT_ERROR, -EIO,
306                                         "Unable to find service record");
307         if (session->func)
308                 session->func(session->io, gerr, session->user_data);
309
310         g_clear_error(&gerr);
311
312         session_destroy(session);
313 }
314
315 static gboolean process_callback(GIOChannel *io, GIOCondition cond,
316                                                         gpointer user_data)
317 {
318         struct bluetooth_session *session = user_data;
319
320         if (cond & (G_IO_ERR | G_IO_HUP | G_IO_NVAL))
321                 return FALSE;
322
323         if (sdp_process(session->sdp) < 0)
324                 return FALSE;
325
326         return TRUE;
327 }
328
329 static int bt_string2uuid(uuid_t *uuid, const char *string)
330 {
331         uint32_t data0, data4;
332         uint16_t data1, data2, data3, data5;
333
334         if (sscanf(string, "%08x-%04hx-%04hx-%04hx-%08x%04hx",
335                                 &data0, &data1, &data2, &data3, &data4, &data5) == 6) {
336                 uint8_t val[16];
337
338                 data0 = g_htonl(data0);
339                 data1 = g_htons(data1);
340                 data2 = g_htons(data2);
341                 data3 = g_htons(data3);
342                 data4 = g_htonl(data4);
343                 data5 = g_htons(data5);
344
345                 memcpy(&val[0], &data0, 4);
346                 memcpy(&val[4], &data1, 2);
347                 memcpy(&val[6], &data2, 2);
348                 memcpy(&val[8], &data3, 2);
349                 memcpy(&val[10], &data4, 4);
350                 memcpy(&val[14], &data5, 2);
351
352                 sdp_uuid128_create(uuid, val);
353
354                 return 0;
355         }
356
357         return -EINVAL;
358 }
359
360 static gboolean service_callback(GIOChannel *io, GIOCondition cond,
361                                                         gpointer user_data)
362 {
363         struct bluetooth_session *session = user_data;
364         sdp_list_t *search, *attrid;
365         uint32_t range = 0x0000ffff;
366         GError *gerr = NULL;
367         uuid_t uuid;
368
369         if (cond & G_IO_NVAL)
370                 return FALSE;
371
372         if (cond & G_IO_ERR)
373                 goto failed;
374
375         if (sdp_set_notify(session->sdp, search_callback, session) < 0)
376                 goto failed;
377
378         if (bt_string2uuid(&uuid, session->service) < 0)
379                 goto failed;
380
381         search = sdp_list_append(NULL, &uuid);
382         attrid = sdp_list_append(NULL, &range);
383
384         if (sdp_service_search_attr_async(session->sdp,
385                                 search, SDP_ATTR_REQ_RANGE, attrid) < 0) {
386                 sdp_list_free(attrid, NULL);
387                 sdp_list_free(search, NULL);
388                 goto failed;
389         }
390
391         sdp_list_free(attrid, NULL);
392         sdp_list_free(search, NULL);
393
394         g_io_add_watch(io, G_IO_IN | G_IO_HUP | G_IO_ERR | G_IO_NVAL,
395                                                 process_callback, session);
396
397         return FALSE;
398
399 failed:
400         g_io_channel_shutdown(session->io, TRUE, NULL);
401         g_io_channel_unref(session->io);
402         session->io = NULL;
403
404         g_set_error(&gerr, OBC_BT_ERROR, -EIO,
405                                         "Unable to find service record");
406         if (session->func)
407                 session->func(session->io, gerr, session->user_data);
408         g_clear_error(&gerr);
409
410         session_destroy(session);
411         return FALSE;
412 }
413
414 static sdp_session_t *service_connect(const bdaddr_t *src, const bdaddr_t *dst,
415                                         GIOFunc function, gpointer user_data)
416 {
417         struct bluetooth_session *session = user_data;
418         sdp_session_t *sdp;
419         GIOChannel *io;
420
421         sdp = sdp_connect(src, dst, SDP_NON_BLOCKING);
422         if (sdp == NULL)
423                 return NULL;
424
425         io = g_io_channel_unix_new(sdp_get_socket(sdp));
426         if (io == NULL) {
427                 sdp_close(sdp);
428                 return NULL;
429         }
430
431         g_io_add_watch(io, G_IO_OUT | G_IO_HUP | G_IO_ERR | G_IO_NVAL,
432                                                         function, user_data);
433
434         session->io = io;
435
436         return sdp;
437 }
438
439 static int session_connect(struct bluetooth_session *session)
440 {
441         int err;
442
443         if (session->port > 0) {
444                 session->io = transport_connect(&session->src, &session->dst,
445                                                         session->port,
446                                                         transport_callback,
447                                                         session);
448                 err = (session->io == NULL) ? -EINVAL : 0;
449         } else {
450                 session->sdp = service_connect(&session->src, &session->dst,
451                                                 service_callback, session);
452                 err = (session->sdp == NULL) ? -ENOMEM : 0;
453         }
454
455         return err;
456 }
457
458 static void adapter_reply(DBusPendingCall *call, void *user_data)
459 {
460         struct bluetooth_session *session = user_data;
461         DBusError err;
462         DBusMessage *reply;
463         GError *gerr = NULL;
464
465         reply = dbus_pending_call_steal_reply(call);
466
467         session->pending_calls = g_slist_remove(session->pending_calls, call);
468         finalize_call(call);
469
470         dbus_error_init(&err);
471         if (dbus_set_error_from_message(&err, reply)) {
472                 error("manager replied with an error: %s, %s",
473                                 err.name, err.message);
474                 dbus_error_free(&err);
475
476                 goto failed;
477         }
478
479         if (session_connect(session) == 0)
480                 goto proceed;
481
482 failed:
483         g_set_error(&gerr, OBC_BT_ERROR, -EINVAL,
484                                         "Unable to request session");
485         if (session->func)
486                 session->func(session->io, gerr, session->user_data);
487         g_clear_error(&gerr);
488
489         session_destroy(session);
490
491 proceed:
492         dbus_message_unref(reply);
493 }
494
495 static int request_session(struct bluetooth_session *session, const char *adapter)
496 {
497         session->adapter = g_strdup(adapter);
498         return send_method_call(session, adapter, BT_ADAPTER_IFACE,
499                                         "RequestSession", adapter_reply,
500                                         DBUS_TYPE_INVALID);
501 }
502
503 static void manager_reply(DBusPendingCall *call, void *user_data)
504 {
505         struct bluetooth_session *session = user_data;
506         DBusError err;
507         DBusMessage *reply;
508         char *adapter;
509         GError *gerr = NULL;
510
511         reply = dbus_pending_call_steal_reply(call);
512
513         session->pending_calls = g_slist_remove(session->pending_calls, call);
514         finalize_call(call);
515
516         dbus_error_init(&err);
517         if (dbus_set_error_from_message(&err, reply)) {
518                 error("manager replied with an error: %s, %s",
519                                 err.name, err.message);
520                 dbus_error_free(&err);
521
522                 goto failed;
523         }
524
525         if (!dbus_message_get_args(reply, NULL,
526                                 DBUS_TYPE_OBJECT_PATH, &adapter,
527                                 DBUS_TYPE_INVALID))
528                 goto failed;
529
530         DBG("adapter path %s", adapter);
531
532         if (request_session(session, adapter) == 0)
533                 goto proceed;
534
535 failed:
536         g_set_error(&gerr, OBC_BT_ERROR, -EINVAL, "No adapter found");
537         if (session->func)
538                 session->func(session->io, gerr, session->user_data);
539         g_clear_error(&gerr);
540
541         session_destroy(session);
542
543 proceed:
544         dbus_message_unref(reply);
545 }
546
547 static int find_adapter(struct bluetooth_session *session, const char *source)
548 {
549         if (source == NULL) {
550                 bacpy(&session->src, BDADDR_ANY);
551                 return send_method_call(session, BT_PATH, BT_MANAGER_IFACE,
552                                         "DefaultAdapter", manager_reply,
553                                         DBUS_TYPE_INVALID);
554         }
555
556         str2ba(source, &session->src);
557         return send_method_call(session, BT_PATH, BT_MANAGER_IFACE,
558                                         "FindAdapter", manager_reply,
559                                         DBUS_TYPE_STRING, &source,
560                                         DBUS_TYPE_INVALID);
561 }
562
563 static guint bluetooth_connect(const char *source, const char *destination,
564                                 const char *service, uint16_t port,
565                                 obc_transport_func func, void *user_data)
566 {
567         struct bluetooth_session *session;
568         static guint id = 0;
569
570         DBG("");
571
572         if (destination == NULL)
573                 return 0;
574
575         session = g_try_malloc0(sizeof(*session));
576         if (session == NULL)
577                 return 0;
578
579         session->id = ++id;
580         session->func = func;
581         session->user_data = user_data;
582
583         session->conn = g_dbus_setup_bus(DBUS_BUS_SYSTEM, NULL, NULL);
584         if (session->conn == NULL) {
585                 g_free(session);
586                 return 0;
587         }
588
589         session->service = g_strdup(service);
590         str2ba(destination, &session->dst);
591
592         if (find_adapter(session, source) < 0) {
593                 g_free(session);
594                 return 0;
595         }
596
597         sessions = g_slist_prepend(sessions, session);
598
599         return session->id;
600 }
601
602 static void bluetooth_disconnect(guint id)
603 {
604         GSList *l;
605
606         DBG("");
607
608         for (l = sessions; l; l = l->next) {
609                 struct bluetooth_session *session = l->data;
610
611                 if (session->id == id) {
612                         session_destroy(session);
613                         return;
614                 }
615         }
616 }
617
618 static int bluetooth_getpacketopt(GIOChannel *io, int *tx_mtu, int *rx_mtu)
619 {
620         int sk = g_io_channel_unix_get_fd(io);
621         int type;
622         int omtu = -1;
623         int imtu = -1;
624         socklen_t len = sizeof(int);
625
626         DBG("");
627
628         if (getsockopt(sk, SOL_SOCKET, SO_TYPE, &type, &len) < 0)
629                 return -errno;
630
631         if (type != SOCK_SEQPACKET)
632                 return -EINVAL;
633
634         if (!bt_io_get(io, BT_IO_L2CAP, NULL, BT_IO_OPT_OMTU, &omtu,
635                                                 BT_IO_OPT_IMTU, &imtu,
636                                                 BT_IO_OPT_INVALID))
637                 return -EINVAL;
638
639         if (tx_mtu)
640                 *tx_mtu = omtu;
641
642         if (rx_mtu)
643                 *rx_mtu = imtu;
644
645         return 0;
646 }
647
648 static struct obc_transport bluetooth = {
649         .name = "Bluetooth",
650         .connect = bluetooth_connect,
651         .getpacketopt = bluetooth_getpacketopt,
652         .disconnect = bluetooth_disconnect,
653 };
654
655 int bluetooth_init(void)
656 {
657         DBG("");
658
659         return obc_transport_register(&bluetooth);
660 }
661
662 void bluetooth_exit(void)
663 {
664         DBG("");
665
666         obc_transport_unregister(&bluetooth);
667 }