Lines 41-48
struct _GAttrib {
Link Here
|
41 |
struct queue *track_ids; |
41 |
struct queue *track_ids; |
42 |
}; |
42 |
}; |
43 |
|
43 |
|
|
|
44 |
struct id_pair { |
45 |
unsigned int org_id; |
46 |
unsigned int pend_id; |
47 |
}; |
48 |
|
44 |
struct attrib_callbacks { |
49 |
struct attrib_callbacks { |
45 |
unsigned int id; |
50 |
struct id_pair *id; |
46 |
GAttribResultFunc result_func; |
51 |
GAttribResultFunc result_func; |
47 |
GAttribNotifyFunc notify_func; |
52 |
GAttribNotifyFunc notify_func; |
48 |
GDestroyNotify destroy_func; |
53 |
GDestroyNotify destroy_func; |
Lines 51-56
struct attrib_callbacks {
Link Here
|
51 |
uint16_t notify_handle; |
56 |
uint16_t notify_handle; |
52 |
}; |
57 |
}; |
53 |
|
58 |
|
|
|
59 |
static bool find_with_org_id(const void *data, const void *user_data) |
60 |
{ |
61 |
const struct id_pair *p = data; |
62 |
unsigned int orig_id = PTR_TO_UINT(user_data); |
63 |
|
64 |
return (p->org_id == orig_id); |
65 |
} |
66 |
|
67 |
static struct id_pair *store_id(GAttrib *attrib, unsigned int org_id, |
68 |
unsigned int pend_id) |
69 |
{ |
70 |
struct id_pair *t; |
71 |
|
72 |
t = new0(struct id_pair, 1); |
73 |
if (!t) |
74 |
return NULL; |
75 |
|
76 |
t->org_id = org_id; |
77 |
t->pend_id = pend_id; |
78 |
|
79 |
if (queue_push_tail(attrib->track_ids, t)) |
80 |
return t; |
81 |
|
82 |
return NULL; |
83 |
} |
84 |
|
54 |
GAttrib *g_attrib_new(GIOChannel *io, guint16 mtu, bool ext_signed) |
85 |
GAttrib *g_attrib_new(GIOChannel *io, guint16 mtu, bool ext_signed) |
55 |
{ |
86 |
{ |
56 |
gint fd; |
87 |
gint fd; |
Lines 119-124
static void attrib_callbacks_destroy(void *data)
Link Here
|
119 |
if (cb->destroy_func) |
150 |
if (cb->destroy_func) |
120 |
cb->destroy_func(cb->user_data); |
151 |
cb->destroy_func(cb->user_data); |
121 |
|
152 |
|
|
|
153 |
if (queue_remove(cb->parent->track_ids, cb->id)) |
154 |
free(cb->id); |
155 |
|
122 |
free(data); |
156 |
free(data); |
123 |
} |
157 |
} |
124 |
|
158 |
|
Lines 148-154
void g_attrib_unref(GAttrib *attrib)
Link Here
|
148 |
bt_att_unref(attrib->att); |
182 |
bt_att_unref(attrib->att); |
149 |
|
183 |
|
150 |
queue_destroy(attrib->callbacks, attrib_callbacks_destroy); |
184 |
queue_destroy(attrib->callbacks, attrib_callbacks_destroy); |
151 |
queue_destroy(attrib->track_ids, NULL); |
185 |
queue_destroy(attrib->track_ids, free); |
152 |
|
186 |
|
153 |
free(attrib->buf); |
187 |
free(attrib->buf); |
154 |
|
188 |
|
Lines 261-266
guint g_attrib_send(GAttrib *attrib, guint id, const guint8 *pdu, guint16 len,
Link Here
|
261 |
struct attrib_callbacks *cb = NULL; |
295 |
struct attrib_callbacks *cb = NULL; |
262 |
bt_att_response_func_t response_cb = NULL; |
296 |
bt_att_response_func_t response_cb = NULL; |
263 |
bt_att_destroy_func_t destroy_cb = NULL; |
297 |
bt_att_destroy_func_t destroy_cb = NULL; |
|
|
298 |
unsigned int pend_id; |
264 |
|
299 |
|
265 |
if (!attrib) |
300 |
if (!attrib) |
266 |
return 0; |
301 |
return 0; |
Lines 282-328
guint g_attrib_send(GAttrib *attrib, guint id, const guint8 *pdu, guint16 len,
Link Here
|
282 |
|
317 |
|
283 |
} |
318 |
} |
284 |
|
319 |
|
285 |
if (id == 0) |
320 |
pend_id = bt_att_send(attrib->att, pdu[0], (void *) pdu + 1, len - 1, |
286 |
id = bt_att_send(attrib->att, pdu[0], (void *) pdu + 1, |
321 |
response_cb, cb, destroy_cb); |
287 |
len - 1, response_cb, cb, destroy_cb); |
|
|
288 |
else { |
289 |
int err; |
290 |
|
291 |
err = bt_att_resend(attrib->att, id, pdu[0], (void *) pdu + 1, |
292 |
len - 1, response_cb, cb, destroy_cb); |
293 |
if (err) |
294 |
return 0; |
295 |
} |
296 |
|
322 |
|
297 |
if (!id) |
323 |
/* |
298 |
return id; |
324 |
* We store here pair as it is easier to handle it in response and in |
|
|
325 |
* case where user request us to use specific id request - see below. |
326 |
*/ |
327 |
if (id == 0) |
328 |
id = pend_id; |
299 |
|
329 |
|
300 |
/* |
330 |
/* |
301 |
* If user what us to use given id, lets keep track on that so we give |
331 |
* If user what us to use given id, lets keep track on that so we give |
302 |
* user a possibility to cancel ongoing request. |
332 |
* user a possibility to cancel ongoing request. |
303 |
*/ |
333 |
*/ |
304 |
if (cb) { |
334 |
if (cb) |
305 |
cb->id = id; |
335 |
cb->id = store_id(attrib, id, pend_id); |
306 |
queue_push_tail(attrib->track_ids, UINT_TO_PTR(id)); |
|
|
307 |
} |
308 |
|
336 |
|
309 |
return id; |
337 |
return id; |
310 |
} |
338 |
} |
311 |
|
339 |
|
312 |
gboolean g_attrib_cancel(GAttrib *attrib, guint id) |
340 |
gboolean g_attrib_cancel(GAttrib *attrib, guint id) |
313 |
{ |
341 |
{ |
|
|
342 |
struct id_pair *p; |
343 |
|
314 |
if (!attrib) |
344 |
if (!attrib) |
315 |
return FALSE; |
345 |
return FALSE; |
316 |
|
346 |
|
|
|
347 |
/* |
348 |
* If request belongs to gattrib and is not yet done it has to be on |
349 |
* the tracking id queue |
350 |
* |
351 |
* FIXME: It can happen that on the queue there is id_pair with |
352 |
* given id which was provided by the user. In the same time it might |
353 |
* happen that other attrib user got dynamic allocated req_id with same |
354 |
* value as the one provided by the other user. |
355 |
* In such case there are two clients having same request id and in |
356 |
* this point of time we don't know which one calls cancel. For |
357 |
* now we cancel request in which id was specified by the user. |
358 |
*/ |
359 |
p = queue_remove_if(attrib->track_ids, find_with_org_id, |
360 |
UINT_TO_PTR(id)); |
361 |
if (!p) |
362 |
return FALSE; |
363 |
|
364 |
id = p->pend_id; |
365 |
free(p); |
366 |
|
317 |
return bt_att_cancel(attrib->att, id); |
367 |
return bt_att_cancel(attrib->att, id); |
318 |
} |
368 |
} |
319 |
|
369 |
|
320 |
static void cancel_request(void *data, void *user_data) |
370 |
static void cancel_request(void *data, void *user_data) |
321 |
{ |
371 |
{ |
322 |
unsigned int id = PTR_TO_UINT(data); |
372 |
struct id_pair *p = data; |
323 |
GAttrib *attrib = user_data; |
373 |
GAttrib *attrib = user_data; |
324 |
|
374 |
|
325 |
bt_att_cancel(attrib->att, id); |
375 |
bt_att_cancel(attrib->att, p->pend_id); |
326 |
} |
376 |
} |
327 |
|
377 |
|
328 |
gboolean g_attrib_cancel_all(GAttrib *attrib) |
378 |
gboolean g_attrib_cancel_all(GAttrib *attrib) |
Lines 330-337
gboolean g_attrib_cancel_all(GAttrib *attrib)
Link Here
|
330 |
if (!attrib) |
380 |
if (!attrib) |
331 |
return FALSE; |
381 |
return FALSE; |
332 |
|
382 |
|
|
|
383 |
/* Cancel only request which belongs to gattrib */ |
333 |
queue_foreach(attrib->track_ids, cancel_request, attrib); |
384 |
queue_foreach(attrib->track_ids, cancel_request, attrib); |
334 |
queue_remove_all(attrib->track_ids, NULL, NULL, NULL); |
385 |
queue_remove_all(attrib->track_ids, NULL, NULL, free); |
335 |
|
386 |
|
336 |
return TRUE; |
387 |
return TRUE; |
337 |
} |
388 |
} |