tizen 2.3.1 release
[framework/connectivity/bluez.git] / src / sdpd-database.c
1 /*
2  *
3  *  BlueZ - Bluetooth protocol stack for Linux
4  *
5  *  Copyright (C) 2001-2002  Nokia Corporation
6  *  Copyright (C) 2002-2003  Maxim Krasnyansky <maxk@qualcomm.com>
7  *  Copyright (C) 2002-2010  Marcel Holtmann <marcel@holtmann.org>
8  *  Copyright (C) 2002-2003  Stephen Crane <steve.crane@rococosoft.com>
9  *
10  *
11  *  This program is free software; you can redistribute it and/or modify
12  *  it under the terms of the GNU General Public License as published by
13  *  the Free Software Foundation; either version 2 of the License, or
14  *  (at your option) any later version.
15  *
16  *  This program is distributed in the hope that it will be useful,
17  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
18  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
19  *  GNU General Public License for more details.
20  *
21  *  You should have received a copy of the GNU General Public License
22  *  along with this program; if not, write to the Free Software
23  *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
24  *
25  */
26
27 #ifdef HAVE_CONFIG_H
28 #include <config.h>
29 #endif
30
31 #include <stdlib.h>
32 #include <stdbool.h>
33
34 #include "lib/bluetooth.h"
35 #include "lib/sdp.h"
36 #include "lib/sdp_lib.h"
37
38 #include "sdpd.h"
39 #include "log.h"
40
41 static sdp_list_t *service_db;
42 static sdp_list_t *access_db;
43
44 typedef struct {
45         uint32_t handle;
46         bdaddr_t device;
47 } sdp_access_t;
48
49 /*
50  * Ordering function called when inserting a service record.
51  * The service repository is a linked list in sorted order
52  * and the service record handle is the sort key
53  */
54 int record_sort(const void *r1, const void *r2)
55 {
56         const sdp_record_t *rec1 = r1;
57         const sdp_record_t *rec2 = r2;
58
59         if (!rec1 || !rec2) {
60                 error("NULL RECORD LIST FATAL");
61                 return -1;
62         }
63
64         return rec1->handle - rec2->handle;
65 }
66
67 static int access_sort(const void *r1, const void *r2)
68 {
69         const sdp_access_t *rec1 = r1;
70         const sdp_access_t *rec2 = r2;
71
72         if (!rec1 || !rec2) {
73                 error("NULL RECORD LIST FATAL");
74                 return -1;
75         }
76
77         return rec1->handle - rec2->handle;
78 }
79
80 static void access_free(void *p)
81 {
82         free(p);
83 }
84
85 /*
86  * Reset the service repository by deleting its contents
87  */
88 void sdp_svcdb_reset(void)
89 {
90         sdp_list_free(service_db, (sdp_free_func_t) sdp_record_free);
91         service_db = NULL;
92
93         sdp_list_free(access_db, access_free);
94         access_db = NULL;
95 }
96
97 typedef struct _indexed {
98         int sock;
99         sdp_record_t *record;
100 } sdp_indexed_t;
101
102 static sdp_list_t *socket_index;
103
104 /*
105  * collect all services registered over this socket
106  */
107 void sdp_svcdb_collect_all(int sock)
108 {
109         sdp_list_t *p, *q;
110
111         for (p = socket_index, q = 0; p; ) {
112                 sdp_indexed_t *item = p->data;
113                 if (item->sock == sock) {
114                         sdp_list_t *next = p->next;
115                         sdp_record_remove(item->record->handle);
116                         sdp_record_free(item->record);
117                         free(item);
118                         if (q)
119                                 q->next = next;
120                         else
121                                 socket_index = next;
122                         free(p);
123                         p = next;
124                 } else if (item->sock > sock)
125                         return;
126                 else {
127                         q = p;
128                         p = p->next;
129                 }
130         }
131 }
132
133 void sdp_svcdb_collect(sdp_record_t *rec)
134 {
135         sdp_list_t *p, *q;
136
137         for (p = socket_index, q = 0; p; q = p, p = p->next) {
138                 sdp_indexed_t *item = p->data;
139                 if (rec == item->record) {
140                         free(item);
141                         if (q)
142                                 q->next = p->next;
143                         else
144                                 socket_index = p->next;
145                         free(p);
146                         return;
147                 }
148         }
149 }
150
151 static int compare_indices(const void *i1, const void *i2)
152 {
153         const sdp_indexed_t *s1 = i1;
154         const sdp_indexed_t *s2 = i2;
155         return s1->sock - s2->sock;
156 }
157
158 void sdp_svcdb_set_collectable(sdp_record_t *record, int sock)
159 {
160         sdp_indexed_t *item = malloc(sizeof(sdp_indexed_t));
161
162         if (!item) {
163                 SDPDBG("No memory");
164                 return;
165         }
166
167         item->sock = sock;
168         item->record = record;
169         socket_index = sdp_list_insert_sorted(socket_index, item, compare_indices);
170 }
171
172 /*
173  * Add a service record to the repository
174  */
175 void sdp_record_add(const bdaddr_t *device, sdp_record_t *rec)
176 {
177         sdp_access_t *dev;
178
179         SDPDBG("Adding rec : 0x%lx", (long) rec);
180         SDPDBG("with handle : 0x%x", rec->handle);
181
182         service_db = sdp_list_insert_sorted(service_db, rec, record_sort);
183
184         dev = malloc(sizeof(*dev));
185         if (!dev)
186                 return;
187
188         bacpy(&dev->device, device);
189         dev->handle = rec->handle;
190
191         access_db = sdp_list_insert_sorted(access_db, dev, access_sort);
192 }
193
194 static sdp_list_t *record_locate(uint32_t handle)
195 {
196         if (service_db) {
197                 sdp_list_t *p;
198                 sdp_record_t r;
199
200                 r.handle = handle;
201                 p = sdp_list_find(service_db, &r, record_sort);
202                 return p;
203         }
204
205         SDPDBG("Could not find svcRec for : 0x%x", handle);
206         return NULL;
207 }
208
209 static sdp_list_t *access_locate(uint32_t handle)
210 {
211         if (access_db) {
212                 sdp_list_t *p;
213                 sdp_access_t a;
214
215                 a.handle = handle;
216                 p = sdp_list_find(access_db, &a, access_sort);
217                 return p;
218         }
219
220         SDPDBG("Could not find access data for : 0x%x", handle);
221         return NULL;
222 }
223
224 /*
225  * Given a service record handle, find the record associated with it.
226  */
227 sdp_record_t *sdp_record_find(uint32_t handle)
228 {
229         sdp_list_t *p = record_locate(handle);
230
231         if (!p) {
232                 SDPDBG("Couldn't find record for : 0x%x", handle);
233                 return 0;
234         }
235
236         return p->data;
237 }
238
239 /*
240  * Given a service record handle, remove its record from the repository
241  */
242 int sdp_record_remove(uint32_t handle)
243 {
244         sdp_list_t *p = record_locate(handle);
245         sdp_record_t *r;
246         sdp_access_t *a;
247
248         if (!p) {
249                 error("Remove : Couldn't find record for : 0x%x", handle);
250                 return -1;
251         }
252
253         r = p->data;
254         if (r)
255                 service_db = sdp_list_remove(service_db, r);
256
257         p = access_locate(handle);
258         if (p == NULL || p->data == NULL)
259                 return 0;
260
261         a = p->data;
262
263         access_db = sdp_list_remove(access_db, a);
264         access_free(a);
265
266         return 0;
267 }
268
269 /*
270  * Return a pointer to the linked list containing the records in sorted order
271  */
272 sdp_list_t *sdp_get_record_list(void)
273 {
274         return service_db;
275 }
276
277 int sdp_check_access(uint32_t handle, bdaddr_t *device)
278 {
279         sdp_list_t *p = access_locate(handle);
280         sdp_access_t *a;
281
282         if (!p)
283                 return 1;
284
285         a = p->data;
286         if (!a)
287                 return 1;
288
289         if (bacmp(&a->device, device) &&
290                         bacmp(&a->device, BDADDR_ANY) &&
291                         bacmp(device, BDADDR_ANY))
292                 return 0;
293
294         return 1;
295 }
296
297 uint32_t sdp_next_handle(void)
298 {
299         uint32_t handle = 0x10000;
300
301         while (sdp_record_find(handle))
302                 handle++;
303
304         return handle;
305 }