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