audio/transport: Disable set_volume functionality in DA product
[platform/upstream/bluez.git] / gobex / gobex-transfer.c
1 // SPDX-License-Identifier: GPL-2.0-or-later
2 /*
3  *
4  *  OBEX library with GLib integration
5  *
6  *  Copyright (C) 2011  Intel Corporation. All rights reserved.
7  *
8  */
9
10 #ifdef HAVE_CONFIG_H
11 #include <config.h>
12 #endif
13
14 #include <string.h>
15 #include <errno.h>
16
17 #include "gobex/gobex.h"
18 #include "gobex/gobex-debug.h"
19
20 #define FIRST_PACKET_TIMEOUT 60
21
22 static GSList *transfers = NULL;
23
24 static void transfer_response(GObex *obex, GError *err, GObexPacket *rsp,
25                                                         gpointer user_data);
26
27 struct transfer {
28         guint id;
29         guint8 opcode;
30
31         GObex *obex;
32
33         guint req_id;
34
35         guint put_id;
36         guint get_id;
37         guint abort_id;
38
39         GObexDataProducer data_producer;
40         GObexDataConsumer data_consumer;
41         GObexFunc complete_func;
42
43         gpointer user_data;
44 };
45
46 static void transfer_free(struct transfer *transfer)
47 {
48         g_obex_debug(G_OBEX_DEBUG_TRANSFER, "transfer %u", transfer->id);
49
50         transfers = g_slist_remove(transfers, transfer);
51
52         if (transfer->req_id > 0)
53                 g_obex_cancel_req(transfer->obex, transfer->req_id, TRUE);
54
55         if (transfer->put_id > 0)
56                 g_obex_remove_request_function(transfer->obex,
57                                                         transfer->put_id);
58
59         if (transfer->get_id > 0)
60                 g_obex_remove_request_function(transfer->obex,
61                                                         transfer->get_id);
62
63         if (transfer->abort_id > 0)
64                 g_obex_remove_request_function(transfer->obex,
65                                                         transfer->abort_id);
66
67         g_obex_unref(transfer->obex);
68         g_free(transfer);
69 }
70
71 static struct transfer *find_transfer(guint id)
72 {
73         GSList *l;
74
75         for (l = transfers; l != NULL; l = g_slist_next(l)) {
76                 struct transfer *t = l->data;
77                 if (t->id == id)
78                         return t;
79         }
80
81         return NULL;
82 }
83
84 static void transfer_complete(struct transfer *transfer, GError *err)
85 {
86         guint id = transfer->id;
87
88         g_obex_debug(G_OBEX_DEBUG_TRANSFER, "transfer %u", id);
89
90         if (err) {
91                 /* No further tx must be performed */
92                 g_obex_drop_tx_queue(transfer->obex);
93         }
94
95         transfer->complete_func(transfer->obex, err, transfer->user_data);
96         /* Check if the complete_func removed the transfer */
97         if (find_transfer(id) == NULL)
98                 return;
99
100         transfer_free(transfer);
101 }
102
103 static void transfer_abort_response(GObex *obex, GError *err, GObexPacket *rsp,
104                                                         gpointer user_data)
105 {
106         struct transfer *transfer = user_data;
107
108         g_obex_debug(G_OBEX_DEBUG_TRANSFER, "transfer %u", transfer->id);
109
110         transfer->req_id = 0;
111
112         /* Intentionally override error */
113         err = g_error_new(G_OBEX_ERROR, G_OBEX_ERROR_CANCELLED,
114                                                 "Operation was aborted");
115         g_obex_debug(G_OBEX_DEBUG_ERROR, "%s", err->message);
116         transfer_complete(transfer, err);
117         g_error_free(err);
118 }
119
120
121 static gssize put_get_data(void *buf, gsize len, gpointer user_data)
122 {
123         struct transfer *transfer = user_data;
124         GObexPacket *req;
125         GError *err = NULL;
126         gssize ret;
127
128         ret = transfer->data_producer(buf, len, transfer->user_data);
129         if (ret == 0 || ret == -EAGAIN)
130                 return ret;
131
132         if (ret > 0) {
133                 /* Check if SRM is active */
134                 if (!g_obex_srm_active(transfer->obex))
135                         return ret;
136
137                 /* Generate next packet */
138                 req = g_obex_packet_new(transfer->opcode, FALSE,
139                                                         G_OBEX_HDR_INVALID);
140                 g_obex_packet_add_body(req, put_get_data, transfer);
141                 transfer->req_id = g_obex_send_req(transfer->obex, req, -1,
142                                                 transfer_response, transfer,
143                                                 &err);
144                 goto done;
145         }
146
147         transfer->req_id = g_obex_abort(transfer->obex, transfer_abort_response,
148                                                                 transfer, &err);
149 done:
150         if (err != NULL) {
151                 transfer_complete(transfer, err);
152                 g_error_free(err);
153         }
154
155         return ret;
156 }
157
158 static gboolean handle_get_body(struct transfer *transfer, GObexPacket *rsp,
159                                                                 GError **err)
160 {
161         GObexHeader *body = g_obex_packet_get_body(rsp);
162         gboolean ret;
163         const guint8 *buf;
164         gsize len;
165
166         if (body == NULL)
167                 return TRUE;
168
169         g_obex_header_get_bytes(body, &buf, &len);
170         if (len == 0)
171                 return TRUE;
172
173         ret = transfer->data_consumer(buf, len, transfer->user_data);
174         if (ret == FALSE)
175                 g_set_error(err, G_OBEX_ERROR, G_OBEX_ERROR_CANCELLED,
176                                 "Data consumer callback failed");
177
178         return ret;
179 }
180
181 static void transfer_response(GObex *obex, GError *err, GObexPacket *rsp,
182                                                         gpointer user_data)
183 {
184         struct transfer *transfer = user_data;
185         GObexPacket *req;
186         gboolean rspcode, final;
187         guint id;
188
189         g_obex_debug(G_OBEX_DEBUG_TRANSFER, "transfer %u", transfer->id);
190
191         id = transfer->req_id;
192         transfer->req_id = 0;
193
194         if (err != NULL) {
195                 transfer_complete(transfer, err);
196                 return;
197         }
198
199         rspcode = g_obex_packet_get_operation(rsp, &final);
200         if (rspcode != G_OBEX_RSP_SUCCESS && rspcode != G_OBEX_RSP_CONTINUE) {
201                 err = g_error_new(G_OBEX_ERROR, rspcode, "%s",
202                                                 g_obex_strerror(rspcode));
203                 goto failed;
204         }
205
206         if (transfer->opcode == G_OBEX_OP_GET) {
207                 handle_get_body(transfer, rsp, &err);
208                 if (err != NULL)
209                         goto failed;
210         }
211
212         if (rspcode == G_OBEX_RSP_SUCCESS) {
213                 transfer_complete(transfer, NULL);
214                 return;
215         }
216
217         if (transfer->opcode == G_OBEX_OP_PUT) {
218                 req = g_obex_packet_new(transfer->opcode, FALSE,
219                                                         G_OBEX_HDR_INVALID);
220                 g_obex_packet_add_body(req, put_get_data, transfer);
221         } else if (!g_obex_srm_active(transfer->obex)) {
222                 req = g_obex_packet_new(transfer->opcode, TRUE,
223                                                         G_OBEX_HDR_INVALID);
224         } else {
225                 /* Keep id since request still outstanting */
226                 transfer->req_id = id;
227                 return;
228         }
229
230         transfer->req_id = g_obex_send_req(obex, req, -1, transfer_response,
231                                                         transfer, &err);
232 failed:
233         if (err != NULL) {
234                 g_obex_debug(G_OBEX_DEBUG_ERROR, "%s", err->message);
235                 transfer_complete(transfer, err);
236                 g_error_free(err);
237         }
238 }
239
240 static struct transfer *transfer_new(GObex *obex, guint8 opcode,
241                                 GObexFunc complete_func, gpointer user_data)
242 {
243         static guint next_id = 1;
244         struct transfer *transfer;
245
246         g_obex_debug(G_OBEX_DEBUG_TRANSFER, "obex %p opcode %u", obex, opcode);
247
248         transfer = g_new0(struct transfer, 1);
249
250         transfer->id = next_id++;
251         transfer->opcode = opcode;
252         transfer->obex = g_obex_ref(obex);
253         transfer->complete_func = complete_func;
254         transfer->user_data = user_data;
255
256         transfers = g_slist_append(transfers, transfer);
257
258         return transfer;
259 }
260
261 guint g_obex_put_req_pkt(GObex *obex, GObexPacket *req,
262                         GObexDataProducer data_func, GObexFunc complete_func,
263                         gpointer user_data, GError **err)
264 {
265         struct transfer *transfer;
266
267         g_obex_debug(G_OBEX_DEBUG_TRANSFER, "obex %p", obex);
268
269         if (g_obex_packet_get_operation(req, NULL) != G_OBEX_OP_PUT)
270                 return 0;
271
272         transfer = transfer_new(obex, G_OBEX_OP_PUT, complete_func, user_data);
273         transfer->data_producer = data_func;
274
275         g_obex_packet_add_body(req, put_get_data, transfer);
276
277         transfer->req_id = g_obex_send_req(obex, req, FIRST_PACKET_TIMEOUT,
278                                         transfer_response, transfer, err);
279         if (transfer->req_id == 0) {
280                 transfer_free(transfer);
281                 return 0;
282         }
283
284         g_obex_debug(G_OBEX_DEBUG_TRANSFER, "transfer %u", transfer->id);
285
286         return transfer->id;
287 }
288
289 guint g_obex_put_req(GObex *obex, GObexDataProducer data_func,
290                         GObexFunc complete_func, gpointer user_data,
291                         GError **err, guint first_hdr_id, ...)
292 {
293         GObexPacket *req;
294         va_list args;
295
296         g_obex_debug(G_OBEX_DEBUG_TRANSFER, "obex %p", obex);
297
298         va_start(args, first_hdr_id);
299         req = g_obex_packet_new_valist(G_OBEX_OP_PUT, FALSE,
300                                                         first_hdr_id, args);
301         va_end(args);
302
303         return g_obex_put_req_pkt(obex, req, data_func, complete_func,
304                                                         user_data, err);
305 }
306
307 static void transfer_abort_req(GObex *obex, GObexPacket *req, gpointer user_data)
308 {
309         struct transfer *transfer = user_data;
310         GObexPacket *rsp;
311         GError *err;
312
313         g_obex_debug(G_OBEX_DEBUG_TRANSFER, "transfer %u", transfer->id);
314
315         err = g_error_new(G_OBEX_ERROR, G_OBEX_ERROR_CANCELLED,
316                                                 "Request was aborted");
317         rsp = g_obex_packet_new(G_OBEX_RSP_SUCCESS, TRUE, G_OBEX_HDR_INVALID);
318         g_obex_send(obex, rsp, NULL);
319
320         transfer_complete(transfer, err);
321         g_error_free(err);
322 }
323
324 static guint8 put_get_bytes(struct transfer *transfer, GObexPacket *req)
325 {
326         GObexHeader *body;
327         gboolean final;
328         guint8 rsp;
329         const guint8 *buf;
330         gsize len;
331
332         g_obex_debug(G_OBEX_DEBUG_TRANSFER, "transfer %u", transfer->id);
333
334         g_obex_packet_get_operation(req, &final);
335         if (final)
336                 rsp = G_OBEX_RSP_SUCCESS;
337         else
338                 rsp = G_OBEX_RSP_CONTINUE;
339
340         body = g_obex_packet_get_body(req);
341         if (body == NULL)
342                 return rsp;
343
344         g_obex_header_get_bytes(body, &buf, &len);
345         if (len == 0)
346                 return rsp;
347
348         if (transfer->data_consumer(buf, len, transfer->user_data) == FALSE)
349                 rsp = G_OBEX_RSP_FORBIDDEN;
350
351         return rsp;
352 }
353
354 static void transfer_put_req_first(struct transfer *transfer, GObexPacket *req,
355                                         guint8 first_hdr_id, va_list args)
356 {
357         GError *err = NULL;
358         GObexPacket *rsp;
359         guint8 rspcode;
360
361         g_obex_debug(G_OBEX_DEBUG_TRANSFER, "transfer %u", transfer->id);
362
363         rspcode = put_get_bytes(transfer, req);
364
365         rsp = g_obex_packet_new_valist(rspcode, TRUE, first_hdr_id, args);
366
367         if (!g_obex_send(transfer->obex, rsp, &err)) {
368                 transfer_complete(transfer, err);
369                 g_error_free(err);
370                 return;
371         }
372
373         if (rspcode != G_OBEX_RSP_CONTINUE)
374                 transfer_complete(transfer, NULL);
375 }
376
377 static void transfer_put_req(GObex *obex, GObexPacket *req, gpointer user_data)
378 {
379         struct transfer *transfer = user_data;
380         GError *err = NULL;
381         GObexPacket *rsp;
382         guint8 rspcode;
383
384         g_obex_debug(G_OBEX_DEBUG_TRANSFER, "transfer %u", transfer->id);
385
386         rspcode = put_get_bytes(transfer, req);
387
388         /* Don't send continue while SRM is active */
389         if (g_obex_srm_active(transfer->obex) &&
390                                 rspcode == G_OBEX_RSP_CONTINUE)
391                 goto done;
392
393         rsp = g_obex_packet_new(rspcode, TRUE, G_OBEX_HDR_INVALID);
394
395         if (!g_obex_send(obex, rsp, &err)) {
396                 transfer_complete(transfer, err);
397                 g_error_free(err);
398                 return;
399         }
400
401 done:
402         if (rspcode != G_OBEX_RSP_CONTINUE)
403                 transfer_complete(transfer, NULL);
404 }
405
406 guint g_obex_put_rsp(GObex *obex, GObexPacket *req,
407                         GObexDataConsumer data_func, GObexFunc complete_func,
408                         gpointer user_data, GError **err,
409                         guint first_hdr_id, ...)
410 {
411         struct transfer *transfer;
412         va_list args;
413         guint id;
414
415         g_obex_debug(G_OBEX_DEBUG_TRANSFER, "obex %p", obex);
416
417         transfer = transfer_new(obex, G_OBEX_OP_PUT, complete_func, user_data);
418         transfer->data_consumer = data_func;
419
420         va_start(args, first_hdr_id);
421         transfer_put_req_first(transfer, req, first_hdr_id, args);
422         va_end(args);
423         if (!g_slist_find(transfers, transfer))
424                 return 0;
425
426         id = g_obex_add_request_function(obex, G_OBEX_OP_PUT, transfer_put_req,
427                                                                 transfer);
428         transfer->put_id = id;
429
430         id = g_obex_add_request_function(obex, G_OBEX_OP_ABORT,
431                                                 transfer_abort_req, transfer);
432         transfer->abort_id = id;
433
434         g_obex_debug(G_OBEX_DEBUG_TRANSFER, "transfer %u", transfer->id);
435
436         return transfer->id;
437 }
438
439 guint g_obex_get_req_pkt(GObex *obex, GObexPacket *req,
440                         GObexDataConsumer data_func, GObexFunc complete_func,
441                         gpointer user_data, GError **err)
442 {
443         struct transfer *transfer;
444
445         g_obex_debug(G_OBEX_DEBUG_TRANSFER, "obex %p", obex);
446
447         if (g_obex_packet_get_operation(req, NULL) != G_OBEX_OP_GET)
448                 return 0;
449
450         transfer = transfer_new(obex, G_OBEX_OP_GET, complete_func, user_data);
451         transfer->data_consumer = data_func;
452         transfer->req_id = g_obex_send_req(obex, req, FIRST_PACKET_TIMEOUT,
453                                         transfer_response, transfer, err);
454         if (transfer->req_id == 0) {
455                 transfer_free(transfer);
456                 return 0;
457         }
458
459         g_obex_debug(G_OBEX_DEBUG_TRANSFER, "transfer %u", transfer->id);
460
461         return transfer->id;
462 }
463
464 guint g_obex_get_req(GObex *obex, GObexDataConsumer data_func,
465                         GObexFunc complete_func, gpointer user_data,
466                         GError **err, guint first_hdr_id, ...)
467 {
468         struct transfer *transfer;
469         GObexPacket *req;
470         va_list args;
471
472         g_obex_debug(G_OBEX_DEBUG_TRANSFER, "obex %p", obex);
473
474         transfer = transfer_new(obex, G_OBEX_OP_GET, complete_func, user_data);
475         transfer->data_consumer = data_func;
476
477         va_start(args, first_hdr_id);
478         req = g_obex_packet_new_valist(G_OBEX_OP_GET, TRUE,
479                                                         first_hdr_id, args);
480         va_end(args);
481
482         transfer->req_id = g_obex_send_req(obex, req, FIRST_PACKET_TIMEOUT,
483                                         transfer_response, transfer, err);
484         if (transfer->req_id == 0) {
485                 transfer_free(transfer);
486                 return 0;
487         }
488
489         g_obex_debug(G_OBEX_DEBUG_TRANSFER, "transfer %u", transfer->id);
490
491         return transfer->id;
492 }
493
494 static gssize get_get_data(void *buf, gsize len, gpointer user_data)
495 {
496         struct transfer *transfer = user_data;
497         GObexPacket *req, *rsp;
498         GError *err = NULL;
499         gssize ret;
500         guint8 op;
501
502         g_obex_debug(G_OBEX_DEBUG_TRANSFER, "transfer %u", transfer->id);
503
504         ret = transfer->data_producer(buf, len, transfer->user_data);
505         if (ret > 0) {
506                 if (!g_obex_srm_active(transfer->obex))
507                         return ret;
508
509                 /* Generate next response */
510                 rsp = g_obex_packet_new(G_OBEX_RSP_CONTINUE, TRUE,
511                                                         G_OBEX_HDR_INVALID);
512                 g_obex_packet_add_body(rsp, get_get_data, transfer);
513
514                 if (!g_obex_send(transfer->obex, rsp, &err)) {
515                         transfer_complete(transfer, err);
516                         g_error_free(err);
517                 }
518
519                 return ret;
520         }
521
522         if (ret == -EAGAIN)
523                 return ret;
524
525         if (ret == 0) {
526                 transfer_complete(transfer, NULL);
527                 return ret;
528         }
529
530         op = g_obex_errno_to_rsp(ret);
531
532         req = g_obex_packet_new(op, TRUE, G_OBEX_HDR_INVALID);
533         g_obex_send(transfer->obex, req, NULL);
534
535         err = g_error_new(G_OBEX_ERROR, G_OBEX_ERROR_CANCELLED,
536                                 "Data producer function failed");
537         g_obex_debug(G_OBEX_DEBUG_ERROR, "%s", err->message);
538         transfer_complete(transfer, err);
539         g_error_free(err);
540
541         return ret;
542 }
543
544 static gboolean transfer_get_req_first(struct transfer *transfer,
545                                                         GObexPacket *rsp)
546 {
547         GError *err = NULL;
548
549         g_obex_debug(G_OBEX_DEBUG_TRANSFER, "transfer %u", transfer->id);
550
551         g_obex_packet_add_body(rsp, get_get_data, transfer);
552
553         if (!g_obex_send(transfer->obex, rsp, &err)) {
554                 transfer_complete(transfer, err);
555                 g_error_free(err);
556                 return FALSE;
557         }
558
559         return TRUE;
560 }
561
562 static void transfer_get_req(GObex *obex, GObexPacket *req, gpointer user_data)
563 {
564         struct transfer *transfer = user_data;
565         GError *err = NULL;
566         GObexPacket *rsp;
567
568         g_obex_debug(G_OBEX_DEBUG_TRANSFER, "transfer %u", transfer->id);
569
570         rsp = g_obex_packet_new(G_OBEX_RSP_CONTINUE, TRUE, G_OBEX_HDR_INVALID);
571         g_obex_packet_add_body(rsp, get_get_data, transfer);
572
573         if (!g_obex_send(obex, rsp, &err)) {
574                 transfer_complete(transfer, err);
575                 g_error_free(err);
576         }
577 }
578
579 guint g_obex_get_rsp_pkt(GObex *obex, GObexPacket *rsp,
580                         GObexDataProducer data_func, GObexFunc complete_func,
581                         gpointer user_data, GError **err)
582 {
583         struct transfer *transfer;
584         guint id;
585
586         g_obex_debug(G_OBEX_DEBUG_TRANSFER, "obex %p", obex);
587
588         transfer = transfer_new(obex, G_OBEX_OP_GET, complete_func, user_data);
589         transfer->data_producer = data_func;
590
591         if (!transfer_get_req_first(transfer, rsp))
592                 return 0;
593
594         if (!g_slist_find(transfers, transfer))
595                 return 0;
596
597         id = g_obex_add_request_function(obex, G_OBEX_OP_GET, transfer_get_req,
598                                                                 transfer);
599         transfer->get_id = id;
600
601         id = g_obex_add_request_function(obex, G_OBEX_OP_ABORT,
602                                                 transfer_abort_req, transfer);
603         transfer->abort_id = id;
604
605         g_obex_debug(G_OBEX_DEBUG_TRANSFER, "transfer %u", transfer->id);
606
607         return transfer->id;
608 }
609
610 guint g_obex_get_rsp(GObex *obex, GObexDataProducer data_func,
611                         GObexFunc complete_func, gpointer user_data,
612                         GError **err, guint first_hdr_id, ...)
613 {
614         GObexPacket *rsp;
615         va_list args;
616
617         g_obex_debug(G_OBEX_DEBUG_TRANSFER, "obex %p", obex);
618
619         va_start(args, first_hdr_id);
620         rsp = g_obex_packet_new_valist(G_OBEX_RSP_CONTINUE, TRUE,
621                                                         first_hdr_id, args);
622         va_end(args);
623
624         return g_obex_get_rsp_pkt(obex, rsp, data_func, complete_func,
625                                                         user_data, err);
626 }
627
628 gboolean g_obex_cancel_transfer(guint id, GObexFunc complete_func,
629                         gpointer user_data)
630 {
631         struct transfer *transfer = NULL;
632         gboolean ret = TRUE;
633
634         g_obex_debug(G_OBEX_DEBUG_TRANSFER, "transfer %u", id);
635
636         transfer = find_transfer(id);
637
638         if (transfer == NULL)
639                 return FALSE;
640
641         if (complete_func == NULL)
642                 goto done;
643
644         transfer->complete_func = complete_func;
645         transfer->user_data = user_data;
646
647         if (!transfer->req_id) {
648                 transfer->req_id = g_obex_abort(transfer->obex,
649                                                 transfer_abort_response,
650                                                 transfer, NULL);
651                 if (transfer->req_id)
652                         return TRUE;
653         }
654
655         ret = g_obex_cancel_req(transfer->obex, transfer->req_id, FALSE);
656         if (ret)
657                 return TRUE;
658
659 done:
660         transfer_free(transfer);
661         return ret;
662 }