3 * OBEX library with GLib integration
5 * Copyright (C) 2011 Intel Corporation. All rights reserved.
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.
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.
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
30 #include "gobex-debug.h"
32 #define FIRST_PACKET_TIMEOUT 60
34 static GSList *transfers = NULL;
36 static void transfer_response(GObex *obex, GError *err, GObexPacket *rsp,
51 GObexDataProducer data_producer;
52 GObexDataConsumer data_consumer;
53 GObexFunc complete_func;
58 static void transfer_free(struct transfer *transfer)
60 g_obex_debug(G_OBEX_DEBUG_TRANSFER, "transfer %u", transfer->id);
62 transfers = g_slist_remove(transfers, transfer);
64 if (transfer->req_id > 0)
65 g_obex_cancel_req(transfer->obex, transfer->req_id, TRUE);
67 if (transfer->put_id > 0)
68 g_obex_remove_request_function(transfer->obex,
71 if (transfer->get_id > 0)
72 g_obex_remove_request_function(transfer->obex,
75 if (transfer->abort_id > 0)
76 g_obex_remove_request_function(transfer->obex,
79 g_obex_unref(transfer->obex);
83 static struct transfer *find_transfer(guint id)
87 for (l = transfers; l != NULL; l = g_slist_next(l)) {
88 struct transfer *t = l->data;
96 static void transfer_complete(struct transfer *transfer, GError *err)
98 guint id = transfer->id;
100 g_obex_debug(G_OBEX_DEBUG_TRANSFER, "transfer %u", id);
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)
107 transfer_free(transfer);
110 static void transfer_abort_response(GObex *obex, GError *err, GObexPacket *rsp,
113 struct transfer *transfer = user_data;
115 g_obex_debug(G_OBEX_DEBUG_TRANSFER, "transfer %u", transfer->id);
117 transfer->req_id = 0;
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);
128 static gssize put_get_data(void *buf, gsize len, gpointer user_data)
130 struct transfer *transfer = user_data;
135 ret = transfer->data_producer(buf, len, transfer->user_data);
136 if (ret == 0 || ret == -EAGAIN)
140 /* Check if SRM is active */
141 if (!g_obex_srm_active(transfer->obex))
144 /* Generate next packet */
145 req = g_obex_packet_new(transfer->opcode, FALSE,
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,
154 req = g_obex_packet_new(G_OBEX_OP_ABORT, TRUE, G_OBEX_HDR_INVALID);
156 transfer->req_id = g_obex_send_req(transfer->obex, req, -1,
157 transfer_abort_response,
161 transfer_complete(transfer, err);
168 static gboolean handle_get_body(struct transfer *transfer, GObexPacket *rsp,
171 GObexHeader *body = g_obex_packet_get_body(rsp);
179 g_obex_header_get_bytes(body, &buf, &len);
183 ret = transfer->data_consumer(buf, len, transfer->user_data);
185 g_set_error(err, G_OBEX_ERROR, G_OBEX_ERROR_CANCELLED,
186 "Data consumer callback failed");
191 static void transfer_response(GObex *obex, GError *err, GObexPacket *rsp,
194 struct transfer *transfer = user_data;
196 gboolean rspcode, final;
198 g_obex_debug(G_OBEX_DEBUG_TRANSFER, "transfer %u", transfer->id);
200 transfer->req_id = 0;
203 transfer_complete(transfer, err);
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);
214 if (transfer->opcode == G_OBEX_OP_GET) {
215 handle_get_body(transfer, rsp, &err);
220 if (rspcode == G_OBEX_RSP_SUCCESS) {
221 transfer_complete(transfer, NULL);
225 if (transfer->opcode == G_OBEX_OP_PUT) {
226 req = g_obex_packet_new(transfer->opcode, FALSE,
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,
235 transfer->req_id = g_obex_send_req(obex, req, -1, transfer_response,
239 g_obex_debug(G_OBEX_DEBUG_ERROR, "%s", err->message);
240 transfer_complete(transfer, err);
245 static struct transfer *transfer_new(GObex *obex, guint8 opcode,
246 GObexFunc complete_func, gpointer user_data)
248 static guint next_id = 1;
249 struct transfer *transfer;
251 g_obex_debug(G_OBEX_DEBUG_TRANSFER, "obex %p opcode %u", obex, opcode);
253 transfer = g_new0(struct transfer, 1);
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;
261 transfers = g_slist_append(transfers, transfer);
266 guint g_obex_put_req_pkt(GObex *obex, GObexPacket *req,
267 GObexDataProducer data_func, GObexFunc complete_func,
268 gpointer user_data, GError **err)
270 struct transfer *transfer;
272 g_obex_debug(G_OBEX_DEBUG_TRANSFER, "obex %p", obex);
274 if (g_obex_packet_get_operation(req, NULL) != G_OBEX_OP_PUT)
277 transfer = transfer_new(obex, G_OBEX_OP_PUT, complete_func, user_data);
278 transfer->data_producer = data_func;
280 g_obex_packet_add_body(req, put_get_data, transfer);
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);
289 g_obex_debug(G_OBEX_DEBUG_TRANSFER, "transfer %u", transfer->id);
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, ...)
301 g_obex_debug(G_OBEX_DEBUG_TRANSFER, "obex %p", obex);
303 va_start(args, first_hdr_id);
304 req = g_obex_packet_new_valist(G_OBEX_OP_PUT, FALSE,
308 return g_obex_put_req_pkt(obex, req, data_func, complete_func,
312 static void transfer_abort_req(GObex *obex, GObexPacket *req, gpointer user_data)
314 struct transfer *transfer = user_data;
318 g_obex_debug(G_OBEX_DEBUG_TRANSFER, "transfer %u", transfer->id);
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);
325 transfer_complete(transfer, err);
329 static guint8 put_get_bytes(struct transfer *transfer, GObexPacket *req)
337 g_obex_debug(G_OBEX_DEBUG_TRANSFER, "transfer %u", transfer->id);
339 g_obex_packet_get_operation(req, &final);
341 rsp = G_OBEX_RSP_SUCCESS;
343 rsp = G_OBEX_RSP_CONTINUE;
345 body = g_obex_packet_get_body(req);
349 g_obex_header_get_bytes(body, &buf, &len);
353 if (transfer->data_consumer(buf, len, transfer->user_data) == FALSE)
354 rsp = G_OBEX_RSP_FORBIDDEN;
359 static void transfer_put_req_first(struct transfer *transfer, GObexPacket *req,
360 guint8 first_hdr_id, va_list args)
366 g_obex_debug(G_OBEX_DEBUG_TRANSFER, "transfer %u", transfer->id);
368 rspcode = put_get_bytes(transfer, req);
370 rsp = g_obex_packet_new_valist(rspcode, TRUE, first_hdr_id, args);
372 if (!g_obex_send(transfer->obex, rsp, &err)) {
373 transfer_complete(transfer, err);
377 if (rspcode != G_OBEX_RSP_CONTINUE)
378 transfer_complete(transfer, NULL);
381 static void transfer_put_req(GObex *obex, GObexPacket *req, gpointer user_data)
383 struct transfer *transfer = user_data;
388 g_obex_debug(G_OBEX_DEBUG_TRANSFER, "transfer %u", transfer->id);
390 rspcode = put_get_bytes(transfer, req);
392 /* Don't send continue while in SRM */
393 if (g_obex_srm_active(transfer->obex) &&
394 rspcode == G_OBEX_RSP_CONTINUE)
397 rsp = g_obex_packet_new(rspcode, TRUE, G_OBEX_HDR_INVALID);
399 if (!g_obex_send(obex, rsp, &err)) {
400 transfer_complete(transfer, err);
405 if (rspcode != G_OBEX_RSP_CONTINUE)
406 transfer_complete(transfer, NULL);
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, ...)
414 struct transfer *transfer;
418 g_obex_debug(G_OBEX_DEBUG_TRANSFER, "obex %p", obex);
420 transfer = transfer_new(obex, G_OBEX_OP_PUT, complete_func, user_data);
421 transfer->data_consumer = data_func;
424 va_start(args, first_hdr_id);
425 transfer_put_req_first(transfer, req, first_hdr_id, args);
427 if (!g_slist_find(transfers, transfer))
430 id = g_obex_add_request_function(obex, G_OBEX_OP_PUT, transfer_put_req,
432 transfer->put_id = id;
434 id = g_obex_add_request_function(obex, G_OBEX_OP_ABORT,
435 transfer_abort_req, transfer);
436 transfer->abort_id = id;
438 g_obex_debug(G_OBEX_DEBUG_TRANSFER, "transfer %u", transfer->id);
443 guint g_obex_get_req_pkt(GObex *obex, GObexPacket *req,
444 GObexDataConsumer data_func, GObexFunc complete_func,
445 gpointer user_data, GError **err)
447 struct transfer *transfer;
449 g_obex_debug(G_OBEX_DEBUG_TRANSFER, "obex %p", obex);
451 if (g_obex_packet_get_operation(req, NULL) != G_OBEX_OP_GET)
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);
463 g_obex_debug(G_OBEX_DEBUG_TRANSFER, "transfer %u", transfer->id);
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, ...)
472 struct transfer *transfer;
476 g_obex_debug(G_OBEX_DEBUG_TRANSFER, "obex %p", obex);
478 transfer = transfer_new(obex, G_OBEX_OP_GET, complete_func, user_data);
479 transfer->data_consumer = data_func;
481 va_start(args, first_hdr_id);
482 req = g_obex_packet_new_valist(G_OBEX_OP_GET, TRUE,
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);
493 g_obex_debug(G_OBEX_DEBUG_TRANSFER, "transfer %u", transfer->id);
498 static gssize get_get_data(void *buf, gsize len, gpointer user_data)
500 struct transfer *transfer = user_data;
501 GObexPacket *req, *rsp;
505 g_obex_debug(G_OBEX_DEBUG_TRANSFER, "transfer %u", transfer->id);
507 ret = transfer->data_producer(buf, len, transfer->user_data);
509 if (!g_obex_srm_active(transfer->obex))
512 /* Generate next response */
513 rsp = g_obex_packet_new(G_OBEX_RSP_CONTINUE, TRUE,
515 g_obex_packet_add_body(rsp, get_get_data, transfer);
517 if (!g_obex_send(transfer->obex, rsp, &err)) {
518 transfer_complete(transfer, err);
529 transfer_complete(transfer, NULL);
533 req = g_obex_packet_new(G_OBEX_RSP_INTERNAL_SERVER_ERROR, TRUE,
535 g_obex_send(transfer->obex, req, NULL);
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);
546 static void transfer_get_req_first(struct transfer *transfer, GObexPacket *rsp)
550 g_obex_debug(G_OBEX_DEBUG_TRANSFER, "transfer %u", transfer->id);
552 g_obex_packet_add_body(rsp, get_get_data, transfer);
554 if (!g_obex_send(transfer->obex, rsp, &err)) {
555 transfer_complete(transfer, err);
560 static void transfer_get_req(GObex *obex, GObexPacket *req, gpointer user_data)
562 struct transfer *transfer = user_data;
566 g_obex_debug(G_OBEX_DEBUG_TRANSFER, "transfer %u", transfer->id);
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);
571 if (!g_obex_send(obex, rsp, &err)) {
572 transfer_complete(transfer, err);
577 guint g_obex_get_rsp_pkt(GObex *obex, GObexPacket *rsp,
578 GObexDataProducer data_func, GObexFunc complete_func,
579 gpointer user_data, GError **err)
581 struct transfer *transfer;
584 g_obex_debug(G_OBEX_DEBUG_TRANSFER, "obex %p", obex);
586 transfer = transfer_new(obex, G_OBEX_OP_GET, complete_func, user_data);
587 transfer->data_producer = data_func;
589 transfer_get_req_first(transfer, rsp);
591 if (!g_slist_find(transfers, transfer))
594 id = g_obex_add_request_function(obex, G_OBEX_OP_GET, transfer_get_req,
596 transfer->get_id = id;
598 id = g_obex_add_request_function(obex, G_OBEX_OP_ABORT,
599 transfer_abort_req, transfer);
600 transfer->abort_id = id;
602 g_obex_debug(G_OBEX_DEBUG_TRANSFER, "transfer %u", transfer->id);
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, ...)
614 g_obex_debug(G_OBEX_DEBUG_TRANSFER, "obex %p", obex);
616 va_start(args, first_hdr_id);
617 rsp = g_obex_packet_new_valist(G_OBEX_RSP_CONTINUE, TRUE,
621 return g_obex_get_rsp_pkt(obex, rsp, data_func, complete_func,
625 gboolean g_obex_cancel_transfer(guint id)
627 struct transfer *transfer = NULL;
629 g_obex_debug(G_OBEX_DEBUG_TRANSFER, "transfer %u", id);
631 transfer = find_transfer(id);
633 if (transfer == NULL)
636 transfer_free(transfer);