tizen 2.3.1 release
[framework/connectivity/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
429         va_start(args, first_hdr_id);
430         transfer_put_req_first(transfer, req, first_hdr_id, args);
431         va_end(args);
432         if (!g_slist_find(transfers, transfer))
433                 return 0;
434
435         id = g_obex_add_request_function(obex, G_OBEX_OP_PUT, transfer_put_req,
436                                                                 transfer);
437         transfer->put_id = id;
438
439         id = g_obex_add_request_function(obex, G_OBEX_OP_ABORT,
440                                                 transfer_abort_req, transfer);
441         transfer->abort_id = id;
442
443         g_obex_debug(G_OBEX_DEBUG_TRANSFER, "transfer %u", transfer->id);
444
445         return transfer->id;
446 }
447
448 guint g_obex_get_req_pkt(GObex *obex, GObexPacket *req,
449                         GObexDataConsumer data_func, GObexFunc complete_func,
450                         gpointer user_data, GError **err)
451 {
452         struct transfer *transfer;
453
454         g_obex_debug(G_OBEX_DEBUG_TRANSFER, "obex %p", obex);
455
456         if (g_obex_packet_get_operation(req, NULL) != G_OBEX_OP_GET)
457                 return 0;
458
459         transfer = transfer_new(obex, G_OBEX_OP_GET, complete_func, user_data);
460         transfer->data_consumer = data_func;
461         transfer->req_id = g_obex_send_req(obex, req, FIRST_PACKET_TIMEOUT,
462                                         transfer_response, transfer, err);
463         if (transfer->req_id == 0) {
464                 transfer_free(transfer);
465                 return 0;
466         }
467
468         g_obex_debug(G_OBEX_DEBUG_TRANSFER, "transfer %u", transfer->id);
469
470         return transfer->id;
471 }
472
473 guint g_obex_get_req(GObex *obex, GObexDataConsumer data_func,
474                         GObexFunc complete_func, gpointer user_data,
475                         GError **err, guint8 first_hdr_id, ...)
476 {
477         struct transfer *transfer;
478         GObexPacket *req;
479         va_list args;
480
481         g_obex_debug(G_OBEX_DEBUG_TRANSFER, "obex %p", obex);
482
483         transfer = transfer_new(obex, G_OBEX_OP_GET, complete_func, user_data);
484         transfer->data_consumer = data_func;
485
486         va_start(args, first_hdr_id);
487         req = g_obex_packet_new_valist(G_OBEX_OP_GET, TRUE,
488                                                         first_hdr_id, args);
489         va_end(args);
490
491         transfer->req_id = g_obex_send_req(obex, req, FIRST_PACKET_TIMEOUT,
492                                         transfer_response, transfer, err);
493         if (transfer->req_id == 0) {
494                 transfer_free(transfer);
495                 return 0;
496         }
497
498         g_obex_debug(G_OBEX_DEBUG_TRANSFER, "transfer %u", transfer->id);
499
500         return transfer->id;
501 }
502
503 static gssize get_get_data(void *buf, gsize len, gpointer user_data)
504 {
505         struct transfer *transfer = user_data;
506         GObexPacket *req, *rsp;
507         GError *err = NULL;
508         gssize ret;
509         guint8 op;
510
511         g_obex_debug(G_OBEX_DEBUG_TRANSFER, "transfer %u", transfer->id);
512
513         ret = transfer->data_producer(buf, len, transfer->user_data);
514         if (ret > 0) {
515                 if (!g_obex_srm_active(transfer->obex))
516                         return ret;
517
518                 /* Generate next response */
519                 rsp = g_obex_packet_new(G_OBEX_RSP_CONTINUE, TRUE,
520                                                         G_OBEX_HDR_INVALID);
521                 g_obex_packet_add_body(rsp, get_get_data, transfer);
522
523                 if (!g_obex_send(transfer->obex, rsp, &err)) {
524                         transfer_complete(transfer, err);
525                         g_error_free(err);
526                 }
527
528                 return ret;
529         }
530
531         if (ret == -EAGAIN)
532                 return ret;
533
534         if (ret == 0) {
535                 transfer_complete(transfer, NULL);
536                 return ret;
537         }
538
539         op = g_obex_errno_to_rsp(ret);
540
541         req = g_obex_packet_new(op, TRUE, G_OBEX_HDR_INVALID);
542         g_obex_send(transfer->obex, req, NULL);
543
544         err = g_error_new(G_OBEX_ERROR, G_OBEX_ERROR_CANCELLED,
545                                 "Data producer function failed");
546         g_obex_debug(G_OBEX_DEBUG_ERROR, "%s", err->message);
547         transfer_complete(transfer, err);
548         g_error_free(err);
549
550         return ret;
551 }
552
553 static gboolean transfer_get_req_first(struct transfer *transfer,
554                                                         GObexPacket *rsp)
555 {
556         GError *err = NULL;
557
558         g_obex_debug(G_OBEX_DEBUG_TRANSFER, "transfer %u", transfer->id);
559
560         g_obex_packet_add_body(rsp, get_get_data, transfer);
561
562         if (!g_obex_send(transfer->obex, rsp, &err)) {
563                 transfer_complete(transfer, err);
564                 g_error_free(err);
565                 return FALSE;
566         }
567
568         return TRUE;
569 }
570
571 static void transfer_get_req(GObex *obex, GObexPacket *req, gpointer user_data)
572 {
573         struct transfer *transfer = user_data;
574         GError *err = NULL;
575         GObexPacket *rsp;
576
577         g_obex_debug(G_OBEX_DEBUG_TRANSFER, "transfer %u", transfer->id);
578
579         rsp = g_obex_packet_new(G_OBEX_RSP_CONTINUE, TRUE, G_OBEX_HDR_INVALID);
580         g_obex_packet_add_body(rsp, get_get_data, transfer);
581
582         if (!g_obex_send(obex, rsp, &err)) {
583                 transfer_complete(transfer, err);
584                 g_error_free(err);
585         }
586 }
587
588 guint g_obex_get_rsp_pkt(GObex *obex, GObexPacket *rsp,
589                         GObexDataProducer data_func, GObexFunc complete_func,
590                         gpointer user_data, GError **err)
591 {
592         struct transfer *transfer;
593         guint id;
594
595         g_obex_debug(G_OBEX_DEBUG_TRANSFER, "obex %p", obex);
596
597         transfer = transfer_new(obex, G_OBEX_OP_GET, complete_func, user_data);
598         transfer->data_producer = data_func;
599
600         if (!transfer_get_req_first(transfer, rsp))
601                 return 0;
602
603         if (!g_slist_find(transfers, transfer))
604                 return 0;
605
606         id = g_obex_add_request_function(obex, G_OBEX_OP_GET, transfer_get_req,
607                                                                 transfer);
608         transfer->get_id = id;
609
610         id = g_obex_add_request_function(obex, G_OBEX_OP_ABORT,
611                                                 transfer_abort_req, transfer);
612         transfer->abort_id = id;
613
614         g_obex_debug(G_OBEX_DEBUG_TRANSFER, "transfer %u", transfer->id);
615
616         return transfer->id;
617 }
618
619 guint g_obex_get_rsp(GObex *obex, GObexDataProducer data_func,
620                         GObexFunc complete_func, gpointer user_data,
621                         GError **err, guint8 first_hdr_id, ...)
622 {
623         GObexPacket *rsp;
624         va_list args;
625
626         g_obex_debug(G_OBEX_DEBUG_TRANSFER, "obex %p", obex);
627
628         va_start(args, first_hdr_id);
629         rsp = g_obex_packet_new_valist(G_OBEX_RSP_CONTINUE, TRUE,
630                                                         first_hdr_id, args);
631         va_end(args);
632
633         return g_obex_get_rsp_pkt(obex, rsp, data_func, complete_func,
634                                                         user_data, err);
635 }
636
637 gboolean g_obex_cancel_transfer(guint id, GObexFunc complete_func,
638                         gpointer user_data)
639 {
640         struct transfer *transfer = NULL;
641         gboolean ret = TRUE;
642
643         g_obex_debug(G_OBEX_DEBUG_TRANSFER, "transfer %u", id);
644
645         transfer = find_transfer(id);
646
647         if (transfer == NULL)
648                 return FALSE;
649
650         if (complete_func == NULL)
651                 goto done;
652
653         transfer->complete_func = complete_func;
654         transfer->user_data = user_data;
655
656         if (!transfer->req_id) {
657                 transfer->req_id = g_obex_abort(transfer->obex,
658                                                 transfer_abort_response,
659                                                 transfer, NULL);
660                 if (transfer->req_id)
661                         return TRUE;
662         }
663
664         ret = g_obex_cancel_req(transfer->obex, transfer->req_id, FALSE);
665         if (ret)
666                 return TRUE;
667
668 done:
669         transfer_free(transfer);
670         return ret;
671 }