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