gobex: Fix segfault caused by interrupted transfer
[platform/upstream/bluez.git] / gobex / gobex.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 <unistd.h>
28 #include <string.h>
29 #include <errno.h>
30
31 #include "gobex.h"
32 #include "gobex-debug.h"
33
34 #define G_OBEX_DEFAULT_MTU      4096
35 #define G_OBEX_MINIMUM_MTU      255
36 #define G_OBEX_MAXIMUM_MTU      65535
37
38 #define G_OBEX_DEFAULT_TIMEOUT  10
39 #define G_OBEX_ABORT_TIMEOUT    5
40
41 #define G_OBEX_OP_NONE          0xff
42
43 #define FINAL_BIT               0x80
44
45 #define CONNID_INVALID          0xffffffff
46
47 /* Challenge request */
48 #define NONCE_TAG               0x00
49 #define NONCE_LEN               16
50
51 /* Challenge response */
52 #define DIGEST_TAG              0x00
53
54 guint gobex_debug = 0;
55
56 struct srm_config {
57         guint8 op;
58         gboolean enabled;
59         guint8 srm;
60         guint8 srmp;
61         gboolean outgoing;
62 };
63
64 struct _GObex {
65         int ref_count;
66         GIOChannel *io;
67         guint io_source;
68
69         gboolean (*read) (GObex *obex, GError **err);
70         gboolean (*write) (GObex *obex, GError **err);
71
72         guint8 *rx_buf;
73         size_t rx_data;
74         guint16 rx_pkt_len;
75         guint8 rx_last_op;
76
77         guint8 *tx_buf;
78         size_t tx_data;
79         size_t tx_sent;
80
81         gboolean suspended;
82         gboolean use_srm;
83
84         struct srm_config *srm;
85
86         guint write_source;
87
88         gssize io_rx_mtu;
89         gssize io_tx_mtu;
90
91         guint16 rx_mtu;
92         guint16 tx_mtu;
93
94         guint32 conn_id;
95         GObexApparam *authchal;
96
97         GQueue *tx_queue;
98
99         GSList *req_handlers;
100
101         GObexFunc disconn_func;
102         gpointer disconn_func_data;
103
104         struct pending_pkt *pending_req;
105 };
106
107 struct pending_pkt {
108         guint id;
109         GObex *obex;
110         GObexPacket *pkt;
111         guint timeout;
112         guint timeout_id;
113         GObexResponseFunc rsp_func;
114         gpointer rsp_data;
115         gboolean cancelled;
116         gboolean suspended;
117         gboolean authenticating;
118 };
119
120 struct req_handler {
121         guint id;
122         guint8 opcode;
123         GObexRequestFunc func;
124         gpointer user_data;
125 };
126
127 struct connect_data {
128         guint8 version;
129         guint8 flags;
130         guint16 mtu;
131 } __attribute__ ((packed));
132
133 struct setpath_data {
134         guint8 flags;
135         guint8 constants;
136 } __attribute__ ((packed));
137
138 static struct error_code {
139         guint8 code;
140         const char *name;
141 } obex_errors[] = {
142         { G_OBEX_RSP_CONTINUE,                  "Continue" },
143         { G_OBEX_RSP_SUCCESS,                   "Success" },
144         { G_OBEX_RSP_CREATED,                   "Created" },
145         { G_OBEX_RSP_ACCEPTED,                  "Accepted" },
146         { G_OBEX_RSP_NON_AUTHORITATIVE,         "Non Authoritative" },
147         { G_OBEX_RSP_NO_CONTENT,                "No Content" },
148         { G_OBEX_RSP_RESET_CONTENT,             "Reset Content" },
149         { G_OBEX_RSP_PARTIAL_CONTENT,           "Partial Content" },
150         { G_OBEX_RSP_MULTIPLE_CHOICES,          "Multiple Choices" },
151         { G_OBEX_RSP_MOVED_PERMANENTLY,         "Moved Permanently" },
152         { G_OBEX_RSP_MOVED_TEMPORARILY,         "Moved Temporarily" },
153         { G_OBEX_RSP_SEE_OTHER,                 "See Other" },
154         { G_OBEX_RSP_NOT_MODIFIED,              "Not Modified" },
155         { G_OBEX_RSP_USE_PROXY,                 "Use Proxy" },
156         { G_OBEX_RSP_BAD_REQUEST,               "Bad Request" },
157         { G_OBEX_RSP_UNAUTHORIZED,              "Unauthorized" },
158         { G_OBEX_RSP_PAYMENT_REQUIRED,          "Payment Required" },
159         { G_OBEX_RSP_FORBIDDEN,                 "Forbidden" },
160         { G_OBEX_RSP_NOT_FOUND,                 "Not Found" },
161         { G_OBEX_RSP_METHOD_NOT_ALLOWED,        "Method Not Allowed" },
162         { G_OBEX_RSP_NOT_ACCEPTABLE,            "Not Acceptable" },
163         { G_OBEX_RSP_PROXY_AUTH_REQUIRED,       "Proxy Authentication Required" },
164         { G_OBEX_RSP_REQUEST_TIME_OUT,          "Request Time Out" },
165         { G_OBEX_RSP_CONFLICT,                  "Conflict" },
166         { G_OBEX_RSP_GONE,                      "Gone" },
167         { G_OBEX_RSP_LENGTH_REQUIRED,           "Length Required" },
168         { G_OBEX_RSP_PRECONDITION_FAILED,       "Precondition Failed" },
169         { G_OBEX_RSP_REQ_ENTITY_TOO_LARGE,      "Request Entity Too Large" },
170         { G_OBEX_RSP_REQ_URL_TOO_LARGE,         "Request URL Too Large" },
171         { G_OBEX_RSP_UNSUPPORTED_MEDIA_TYPE,    "Unsupported Media Type" },
172         { G_OBEX_RSP_INTERNAL_SERVER_ERROR,     "Internal Server Error" },
173         { G_OBEX_RSP_NOT_IMPLEMENTED,           "Not Implemented" },
174         { G_OBEX_RSP_BAD_GATEWAY,               "Bad Gateway" },
175         { G_OBEX_RSP_SERVICE_UNAVAILABLE,       "Service Unavailable" },
176         { G_OBEX_RSP_GATEWAY_TIMEOUT,           "Gateway Timeout" },
177         { G_OBEX_RSP_VERSION_NOT_SUPPORTED,     "Version Not Supported" },
178         { G_OBEX_RSP_DATABASE_FULL,             "Database Full" },
179         { G_OBEX_RSP_DATABASE_LOCKED,           "Database Locked" },
180         { 0x00,                                 NULL }
181 };
182
183 const char *g_obex_strerror(guint8 err_code)
184 {
185         struct error_code *error;
186
187         for (error = obex_errors; error->name != NULL; error++) {
188                 if (error->code == err_code)
189                         return error->name;
190         }
191
192         return "<unknown>";
193 }
194
195 static ssize_t req_header_offset(guint8 opcode)
196 {
197         switch (opcode) {
198         case G_OBEX_OP_CONNECT:
199                 return sizeof(struct connect_data);
200         case G_OBEX_OP_SETPATH:
201                 return sizeof(struct setpath_data);
202         case G_OBEX_OP_DISCONNECT:
203         case G_OBEX_OP_PUT:
204         case G_OBEX_OP_GET:
205         case G_OBEX_OP_SESSION:
206         case G_OBEX_OP_ABORT:
207         case G_OBEX_OP_ACTION:
208                 return 0;
209         default:
210                 return -1;
211         }
212 }
213
214 static ssize_t rsp_header_offset(guint8 opcode)
215 {
216         switch (opcode) {
217         case G_OBEX_OP_CONNECT:
218                 return sizeof(struct connect_data);
219         case G_OBEX_OP_SETPATH:
220         case G_OBEX_OP_DISCONNECT:
221         case G_OBEX_OP_PUT:
222         case G_OBEX_OP_GET:
223         case G_OBEX_OP_SESSION:
224         case G_OBEX_OP_ABORT:
225         case G_OBEX_OP_ACTION:
226                 return 0;
227         default:
228                 return -1;
229         }
230 }
231
232 static void pending_pkt_free(struct pending_pkt *p)
233 {
234         if (p->obex != NULL)
235                 g_obex_unref(p->obex);
236
237         if (p->timeout_id > 0)
238                 g_source_remove(p->timeout_id);
239
240         g_obex_packet_free(p->pkt);
241
242         g_free(p);
243 }
244
245 static gboolean req_timeout(gpointer user_data)
246 {
247         GObex *obex = user_data;
248         struct pending_pkt *p = obex->pending_req;
249         GError *err;
250
251         g_assert(p != NULL);
252
253         p->timeout_id = 0;
254         obex->pending_req = NULL;
255
256         err = g_error_new(G_OBEX_ERROR, G_OBEX_ERROR_TIMEOUT,
257                                         "Timed out waiting for response");
258
259         g_obex_debug(G_OBEX_DEBUG_ERROR, "%s", err->message);
260
261         if (p->rsp_func)
262                 p->rsp_func(obex, err, NULL, p->rsp_data);
263
264         g_error_free(err);
265         pending_pkt_free(p);
266
267         return FALSE;
268 }
269
270 static gboolean write_stream(GObex *obex, GError **err)
271 {
272         GIOStatus status;
273         gsize bytes_written;
274         char *buf;
275
276         buf = (char *) &obex->tx_buf[obex->tx_sent];
277         status = g_io_channel_write_chars(obex->io, buf, obex->tx_data,
278                                                         &bytes_written, err);
279         if (status != G_IO_STATUS_NORMAL)
280                 return FALSE;
281
282         g_obex_dump(G_OBEX_DEBUG_DATA, "<", buf, bytes_written);
283
284         obex->tx_sent += bytes_written;
285         obex->tx_data -= bytes_written;
286
287         return TRUE;
288 }
289
290 static gboolean write_packet(GObex *obex, GError **err)
291 {
292         GIOStatus status;
293         gsize bytes_written;
294         char *buf;
295
296         buf = (char *) &obex->tx_buf[obex->tx_sent];
297         status = g_io_channel_write_chars(obex->io, buf, obex->tx_data,
298                                                         &bytes_written, err);
299         if (status != G_IO_STATUS_NORMAL)
300                 return FALSE;
301
302         if (bytes_written != obex->tx_data)
303                 return FALSE;
304
305         g_obex_dump(G_OBEX_DEBUG_DATA, "<", buf, bytes_written);
306
307         obex->tx_sent += bytes_written;
308         obex->tx_data -= bytes_written;
309
310         return TRUE;
311 }
312
313 static void set_srmp(GObex *obex, guint8 srmp, gboolean outgoing)
314 {
315         struct srm_config *config = obex->srm;
316
317         if (config == NULL)
318                 return;
319
320         /* Dont't reset if direction doesn't match */
321         if (srmp > G_OBEX_SRMP_NEXT_WAIT && config->outgoing != outgoing)
322                 return;
323
324         config->srmp = srmp;
325         config->outgoing = outgoing;
326 }
327
328 static void set_srm(GObex *obex, guint8 op, guint8 srm)
329 {
330         struct srm_config *config = obex->srm;
331         gboolean enable;
332
333         if (config == NULL) {
334                 if (srm == G_OBEX_SRM_DISABLE)
335                         return;
336
337                 config = g_new0(struct srm_config, 1);
338                 config->op = op;
339                 config->srm = srm;
340                 obex->srm = config;
341                 return;
342         }
343
344         /* Indicate response, treat it as request */
345         if (config->srm == G_OBEX_SRM_INDICATE) {
346                 if (srm != G_OBEX_SRM_ENABLE)
347                         goto done;
348                 config->srm = srm;
349                 return;
350         }
351
352         enable = (srm == G_OBEX_SRM_ENABLE);
353         if (config->enabled == enable)
354                 goto done;
355
356         config->enabled = enable;
357
358         g_obex_debug(G_OBEX_DEBUG_COMMAND, "SRM %s", config->enabled ?
359                                                 "Enabled" : "Disabled");
360
361 done:
362         if (config->enabled)
363                 return;
364
365         g_free(obex->srm);
366         obex->srm = NULL;
367 }
368
369 static gboolean g_obex_srm_enabled(GObex *obex)
370 {
371         if (!obex->use_srm)
372                 return FALSE;
373
374         if (obex->srm == NULL)
375                 return FALSE;
376
377         return obex->srm->enabled;
378 }
379
380 static void check_srm_final(GObex *obex, guint8 op)
381 {
382         if (!g_obex_srm_enabled(obex))
383                 return;
384
385         switch (obex->srm->op) {
386         case G_OBEX_OP_CONNECT:
387                 return;
388         default:
389                 if (op <= G_OBEX_RSP_CONTINUE)
390                         return;
391         }
392
393         set_srm(obex, op, G_OBEX_SRM_DISABLE);
394 }
395
396 static void setup_srm(GObex *obex, GObexPacket *pkt, gboolean outgoing)
397 {
398         GObexHeader *hdr;
399         guint8 op;
400         gboolean final;
401
402         if (!obex->use_srm)
403                 return;
404
405         op = g_obex_packet_get_operation(pkt, &final);
406
407         hdr = g_obex_packet_get_header(pkt, G_OBEX_HDR_SRM);
408         if (hdr != NULL) {
409                 guint8 srm;
410                 g_obex_header_get_uint8(hdr, &srm);
411                 g_obex_debug(G_OBEX_DEBUG_COMMAND, "srm 0x%02x", srm);
412                 set_srm(obex, op, srm);
413         } else if (!g_obex_srm_enabled(obex))
414                 set_srm(obex, op, G_OBEX_SRM_DISABLE);
415
416         hdr = g_obex_packet_get_header(pkt, G_OBEX_HDR_SRMP);
417         if (hdr != NULL) {
418                 guint8 srmp;
419                 g_obex_header_get_uint8(hdr, &srmp);
420                 g_obex_debug(G_OBEX_DEBUG_COMMAND, "srmp 0x%02x", srmp);
421                 set_srmp(obex, srmp, outgoing);
422         } else if (obex->pending_req && obex->pending_req->suspended)
423                 g_obex_packet_add_uint8(pkt, G_OBEX_HDR_SRMP, G_OBEX_SRMP_WAIT);
424         else
425                 set_srmp(obex, -1, outgoing);
426
427         if (final)
428                 check_srm_final(obex, op);
429 }
430
431 static gboolean write_data(GIOChannel *io, GIOCondition cond,
432                                                         gpointer user_data)
433 {
434         GObex *obex = user_data;
435
436         if (cond & G_IO_NVAL)
437                 return FALSE;
438
439         if (cond & (G_IO_HUP | G_IO_ERR))
440                 goto stop_tx;
441
442         if (obex->tx_data == 0) {
443                 struct pending_pkt *p = g_queue_pop_head(obex->tx_queue);
444                 ssize_t len;
445
446                 if (p == NULL)
447                         goto stop_tx;
448
449                 setup_srm(obex, p->pkt, TRUE);
450
451                 if (g_obex_srm_enabled(obex))
452                         goto encode;
453
454                 /* Can't send a request while there's a pending one */
455                 if (obex->pending_req && p->id > 0) {
456                         g_queue_push_head(obex->tx_queue, p);
457                         goto stop_tx;
458                 }
459
460 encode:
461                 len = g_obex_packet_encode(p->pkt, obex->tx_buf, obex->tx_mtu);
462                 if (len == -EAGAIN) {
463                         g_queue_push_head(obex->tx_queue, p);
464                         g_obex_suspend(obex);
465                         goto stop_tx;
466                 }
467
468                 if (len < 0) {
469                         pending_pkt_free(p);
470                         goto done;
471                 }
472
473                 if (p->id > 0) {
474                         if (obex->pending_req != NULL)
475                                 pending_pkt_free(obex->pending_req);
476                         obex->pending_req = p;
477                         p->timeout_id = g_timeout_add_seconds(p->timeout,
478                                                         req_timeout, obex);
479                 } else {
480                         /* During packet encode final bit can be set */
481                         if (obex->tx_buf[0] & FINAL_BIT)
482                                 check_srm_final(obex,
483                                                 obex->tx_buf[0] & ~FINAL_BIT);
484                         pending_pkt_free(p);
485                 }
486
487                 obex->tx_data = len;
488                 obex->tx_sent = 0;
489         }
490
491         if (obex->suspended) {
492                 obex->write_source = 0;
493                 return FALSE;
494         }
495
496         if (!obex->write(obex, NULL))
497                 goto stop_tx;
498
499 done:
500         if (obex->tx_data > 0 || g_queue_get_length(obex->tx_queue) > 0)
501                 return TRUE;
502
503 stop_tx:
504         obex->rx_last_op = G_OBEX_OP_NONE;
505         obex->tx_data = 0;
506         obex->write_source = 0;
507         return FALSE;
508 }
509
510 static void enable_tx(GObex *obex)
511 {
512         GIOCondition cond;
513
514         if (obex->suspended)
515                 return;
516
517         if (!obex->io || obex->write_source > 0)
518                 return;
519
520         cond = G_IO_OUT | G_IO_HUP | G_IO_ERR | G_IO_NVAL;
521         obex->write_source = g_io_add_watch(obex->io, cond, write_data, obex);
522 }
523
524 void g_obex_drop_tx_queue(GObex *obex)
525 {
526         struct pending_pkt *p;
527
528         g_obex_debug(G_OBEX_DEBUG_COMMAND, "");
529
530         while ((p = g_queue_pop_head(obex->tx_queue)))
531                 pending_pkt_free(p);
532 }
533
534 static gboolean g_obex_send_internal(GObex *obex, struct pending_pkt *p,
535                                                                 GError **err)
536 {
537
538         if (obex->io == NULL) {
539                 if (!err)
540                         return FALSE;
541                 g_set_error(err, G_OBEX_ERROR, G_OBEX_ERROR_DISCONNECTED,
542                                         "The transport is not connected");
543                 g_obex_debug(G_OBEX_DEBUG_ERROR, "%s", (*err)->message);
544                 return FALSE;
545         }
546
547         if (g_obex_packet_get_operation(p->pkt, NULL) == G_OBEX_OP_ABORT)
548                 g_queue_push_head(obex->tx_queue, p);
549         else
550                 g_queue_push_tail(obex->tx_queue, p);
551
552         if (obex->pending_req == NULL || p->id == 0)
553                 enable_tx(obex);
554
555         return TRUE;
556 }
557
558 static void init_connect_data(GObex *obex, struct connect_data *data)
559 {
560         guint16 u16;
561
562         memset(data, 0, sizeof(*data));
563
564         data->version = 0x10;
565         data->flags = 0;
566
567         u16 = g_htons(obex->rx_mtu);
568         memcpy(&data->mtu, &u16, sizeof(u16));
569 }
570
571 static guint8 *digest_response(const guint8 *nonce)
572 {
573         GChecksum *md5;
574         guint8 *result;
575         gsize size;
576
577         result = g_new0(guint8, NONCE_LEN);
578
579         md5 = g_checksum_new(G_CHECKSUM_MD5);
580         if (md5 == NULL)
581                 return result;
582
583         g_checksum_update(md5, nonce, NONCE_LEN);
584 #ifdef TIZEN_FEATURE_BLUEZ_MODIFY
585         g_checksum_update(md5, (guint8 *) ":0000", 5);
586 #else
587         g_checksum_update(md5, (guint8 *) ":BlueZ", 6);
588 #endif /* TIZEN_FEATURE_BLUEZ_MODIFY */
589
590
591         size = NONCE_LEN;
592         g_checksum_get_digest(md5, result, &size);
593
594         g_checksum_free(md5);
595
596         return result;
597 }
598
599 static void prepare_auth_rsp(GObex *obex, GObexPacket *rsp)
600 {
601         GObexHeader *hdr;
602         GObexApparam *authrsp;
603         const guint8 *nonce;
604         guint8 *result;
605         gsize len;
606
607         /* Check if client is already responding to authentication challenge */
608         hdr = g_obex_packet_get_header(rsp, G_OBEX_HDR_AUTHRESP);
609         if (hdr)
610                 goto done;
611
612         if (!g_obex_apparam_get_bytes(obex->authchal, NONCE_TAG, &nonce, &len))
613                 goto done;
614
615         if (len != NONCE_LEN)
616                 goto done;
617
618         result = digest_response(nonce);
619         authrsp = g_obex_apparam_set_bytes(NULL, DIGEST_TAG, result, NONCE_LEN);
620
621         hdr = g_obex_header_new_tag(G_OBEX_HDR_AUTHRESP, authrsp);
622         g_obex_packet_add_header(rsp, hdr);
623
624         g_obex_apparam_free(authrsp);
625         g_free(result);
626
627 done:
628         g_obex_apparam_free(obex->authchal);
629         obex->authchal = NULL;
630 }
631
632 static void prepare_connect_rsp(GObex *obex, GObexPacket *rsp)
633 {
634         GObexHeader *hdr;
635         struct connect_data data;
636         static guint32 next_connid = 1;
637
638         init_connect_data(obex, &data);
639         g_obex_packet_set_data(rsp, &data, sizeof(data), G_OBEX_DATA_COPY);
640
641         hdr = g_obex_packet_get_header(rsp, G_OBEX_HDR_CONNECTION);
642         if (hdr) {
643                 g_obex_header_get_uint32(hdr, &obex->conn_id);
644                 goto done;
645         }
646
647         obex->conn_id = next_connid++;
648
649         hdr = g_obex_header_new_uint32(G_OBEX_HDR_CONNECTION, obex->conn_id);
650         g_obex_packet_prepend_header(rsp, hdr);
651
652 done:
653         if (obex->authchal)
654                 prepare_auth_rsp(obex, rsp);
655 }
656
657 static void prepare_srm_rsp(GObex *obex, GObexPacket *pkt)
658 {
659         GObexHeader *hdr;
660
661         if (!obex->use_srm || obex->srm == NULL)
662                 return;
663
664         if (obex->srm->enabled)
665                 return;
666
667         hdr = g_obex_packet_get_header(pkt, G_OBEX_HDR_SRM);
668         if (hdr != NULL)
669                 return;
670
671         hdr = g_obex_header_new_uint8(G_OBEX_HDR_SRM, G_OBEX_SRM_ENABLE);
672         g_obex_packet_prepend_header(pkt, hdr);
673 }
674
675 gboolean g_obex_send(GObex *obex, GObexPacket *pkt, GError **err)
676 {
677         struct pending_pkt *p;
678         gboolean ret;
679
680         g_obex_debug(G_OBEX_DEBUG_COMMAND, "conn %u", obex->conn_id);
681
682         if (obex == NULL || pkt == NULL) {
683                 if (!err)
684                         return FALSE;
685                 g_set_error(err, G_OBEX_ERROR, G_OBEX_ERROR_INVALID_ARGS,
686                                 "Invalid arguments");
687                 g_obex_debug(G_OBEX_DEBUG_ERROR, "%s", (*err)->message);
688                 return FALSE;
689         }
690
691         switch (obex->rx_last_op) {
692         case G_OBEX_OP_CONNECT:
693                 prepare_connect_rsp(obex, pkt);
694                 break;
695         case G_OBEX_OP_GET:
696         case G_OBEX_OP_PUT:
697                 prepare_srm_rsp(obex, pkt);
698                 break;
699         }
700
701         p = g_new0(struct pending_pkt, 1);
702         p->pkt = pkt;
703
704         ret = g_obex_send_internal(obex, p, err);
705         if (ret == FALSE)
706                 pending_pkt_free(p);
707
708         return ret;
709 }
710
711 static void prepare_srm_req(GObex *obex, GObexPacket *pkt)
712 {
713         GObexHeader *hdr;
714
715         if (!obex->use_srm)
716                 return;
717
718         if (obex->srm != NULL && obex->srm->enabled)
719                 return;
720
721         hdr = g_obex_packet_get_header(pkt, G_OBEX_HDR_SRM);
722         if (hdr != NULL)
723                 return;
724
725         hdr = g_obex_header_new_uint8(G_OBEX_HDR_SRM, G_OBEX_SRM_ENABLE);
726         g_obex_packet_prepend_header(pkt, hdr);
727 }
728
729 guint g_obex_send_req(GObex *obex, GObexPacket *req, int timeout,
730                         GObexResponseFunc func, gpointer user_data,
731                         GError **err)
732 {
733         GObexHeader *hdr;
734         struct pending_pkt *p;
735         static guint id = 1;
736         guint8 op;
737
738         g_obex_debug(G_OBEX_DEBUG_COMMAND, "conn %u", obex->conn_id);
739
740         op = g_obex_packet_get_operation(req, NULL);
741         if (op == G_OBEX_OP_PUT || op == G_OBEX_OP_GET) {
742                 /* Only enable SRM automatically for GET and PUT */
743                 prepare_srm_req(obex, req);
744         }
745
746         if (obex->conn_id == CONNID_INVALID)
747                 goto create_pending;
748
749         if (obex->rx_last_op == G_OBEX_RSP_CONTINUE)
750                 goto create_pending;
751
752         if (g_obex_srm_enabled(obex) && obex->pending_req != NULL)
753                 goto create_pending;
754
755         hdr = g_obex_packet_get_header(req, G_OBEX_HDR_CONNECTION);
756         if (hdr != NULL)
757                 goto create_pending;
758
759         hdr = g_obex_header_new_uint32(G_OBEX_HDR_CONNECTION, obex->conn_id);
760         g_obex_packet_prepend_header(req, hdr);
761
762 create_pending:
763         p = g_new0(struct pending_pkt, 1);
764
765         p->pkt = req;
766         p->id = id++;
767         p->rsp_func = func;
768         p->rsp_data = user_data;
769
770         if (timeout < 0)
771                 p->timeout = G_OBEX_DEFAULT_TIMEOUT;
772         else
773                 p->timeout = timeout;
774
775         if (!g_obex_send_internal(obex, p, err)) {
776                 pending_pkt_free(p);
777                 return 0;
778         }
779
780         return p->id;
781 }
782
783 static int pending_pkt_cmp(gconstpointer a, gconstpointer b)
784 {
785         const struct pending_pkt *p = a;
786         guint id = GPOINTER_TO_UINT(b);
787
788         return (p->id - id);
789 }
790
791 static gboolean pending_req_abort(GObex *obex, GError **err)
792 {
793         struct pending_pkt *p = obex->pending_req;
794         GObexPacket *req;
795
796         if (p->cancelled)
797                 return TRUE;
798
799         p->cancelled = TRUE;
800
801         if (p->timeout_id > 0)
802                 g_source_remove(p->timeout_id);
803
804         p->timeout = G_OBEX_ABORT_TIMEOUT;
805         p->timeout_id = g_timeout_add_seconds(p->timeout, req_timeout, obex);
806
807         req = g_obex_packet_new(G_OBEX_OP_ABORT, TRUE, G_OBEX_HDR_INVALID);
808
809         return g_obex_send(obex, req, err);
810 }
811
812 static gboolean cancel_complete(gpointer user_data)
813 {
814         struct pending_pkt *p = user_data;
815         GObex *obex = p->obex;
816         GError *err;
817
818         g_assert(p->rsp_func != NULL);
819
820         err = g_error_new(G_OBEX_ERROR, G_OBEX_ERROR_CANCELLED,
821                                         "The request was cancelled");
822         p->rsp_func(obex, err, NULL, p->rsp_data);
823
824         g_error_free(err);
825
826         pending_pkt_free(p);
827
828         return FALSE;
829 }
830
831 gboolean g_obex_cancel_req(GObex *obex, guint req_id, gboolean remove_callback)
832 {
833         GList *match;
834         struct pending_pkt *p;
835
836         if (obex->pending_req && obex->pending_req->id == req_id) {
837                 if (!pending_req_abort(obex, NULL)) {
838                         p = obex->pending_req;
839                         obex->pending_req = NULL;
840                         goto immediate_completion;
841                 }
842
843                 if (remove_callback)
844                         obex->pending_req->rsp_func = NULL;
845
846                 return TRUE;
847         }
848
849         match = g_queue_find_custom(obex->tx_queue, GUINT_TO_POINTER(req_id),
850                                                         pending_pkt_cmp);
851         if (match == NULL)
852                 return FALSE;
853
854         p = match->data;
855
856         g_queue_delete_link(obex->tx_queue, match);
857
858 immediate_completion:
859         p->cancelled = TRUE;
860         p->obex = g_obex_ref(obex);
861
862         if (remove_callback || p->rsp_func == NULL)
863                 pending_pkt_free(p);
864         else
865                 g_idle_add(cancel_complete, p);
866
867         return TRUE;
868 }
869
870 gboolean g_obex_send_rsp(GObex *obex, guint8 rspcode, GError **err,
871                                                 guint first_hdr_type, ...)
872 {
873         GObexPacket *rsp;
874         va_list args;
875
876         va_start(args, first_hdr_type);
877         rsp = g_obex_packet_new_valist(rspcode, TRUE, first_hdr_type, args);
878         va_end(args);
879
880         return g_obex_send(obex, rsp, err);
881 }
882
883 void g_obex_set_disconnect_function(GObex *obex, GObexFunc func,
884                                                         gpointer user_data)
885 {
886         obex->disconn_func = func;
887         obex->disconn_func_data = user_data;
888 }
889
890 static int req_handler_cmpop(gconstpointer a, gconstpointer b)
891 {
892         const struct req_handler *handler = a;
893         guint opcode = GPOINTER_TO_UINT(b);
894
895         return (int) handler->opcode - (int) opcode;
896 }
897
898 static int req_handler_cmpid(gconstpointer a, gconstpointer b)
899 {
900         const struct req_handler *handler = a;
901         guint id = GPOINTER_TO_UINT(b);
902
903         return (int) handler->id - (int) id;
904 }
905
906 guint g_obex_add_request_function(GObex *obex, guint8 opcode,
907                                                 GObexRequestFunc func,
908                                                 gpointer user_data)
909 {
910         struct req_handler *handler;
911         static guint next_id = 1;
912
913         handler = g_new0(struct req_handler, 1);
914         handler->id = next_id++;
915         handler->opcode = opcode;
916         handler->func = func;
917         handler->user_data = user_data;
918
919         obex->req_handlers = g_slist_prepend(obex->req_handlers, handler);
920
921         return handler->id;
922 }
923
924 gboolean g_obex_remove_request_function(GObex *obex, guint id)
925 {
926         struct req_handler *handler;
927         GSList *match;
928
929         match = g_slist_find_custom(obex->req_handlers, GUINT_TO_POINTER(id),
930                                                         req_handler_cmpid);
931         if (match == NULL)
932                 return FALSE;
933
934         handler = match->data;
935
936         obex->req_handlers = g_slist_delete_link(obex->req_handlers, match);
937         g_free(handler);
938
939         return TRUE;
940 }
941
942 static void g_obex_srm_suspend(GObex *obex)
943 {
944         struct pending_pkt *p = obex->pending_req;
945         GObexPacket *req;
946
947         if (p->timeout_id > 0) {
948                 g_source_remove(p->timeout_id);
949                 p->timeout_id = 0;
950         }
951
952         p->suspended = TRUE;
953
954         req = g_obex_packet_new(G_OBEX_OP_GET, TRUE,
955                                         G_OBEX_HDR_SRMP, G_OBEX_SRMP_WAIT,
956                                         G_OBEX_HDR_INVALID);
957
958         g_obex_send(obex, req, NULL);
959 }
960
961 void g_obex_suspend(GObex *obex)
962 {
963         struct pending_pkt *req = obex->pending_req;
964
965         g_obex_debug(G_OBEX_DEBUG_COMMAND, "conn %u", obex->conn_id);
966
967         if (!g_obex_srm_active(obex) || !req)
968                 goto done;
969
970         /* Send SRMP wait in case of GET */
971         if (g_obex_packet_get_operation(req->pkt, NULL) == G_OBEX_OP_GET) {
972                 g_obex_srm_suspend(obex);
973                 return;
974         }
975
976 done:
977         obex->suspended = TRUE;
978
979         if (obex->write_source > 0) {
980                 g_source_remove(obex->write_source);
981                 obex->write_source = 0;
982         }
983 }
984
985 static void g_obex_srm_resume(GObex *obex)
986 {
987         struct pending_pkt *p = obex->pending_req;
988         GObexPacket *req;
989
990         p->timeout_id = g_timeout_add_seconds(p->timeout, req_timeout, obex);
991         p->suspended = FALSE;
992
993         req = g_obex_packet_new(G_OBEX_OP_GET, TRUE, G_OBEX_HDR_INVALID);
994
995         g_obex_send(obex, req, NULL);
996 }
997
998 void g_obex_resume(GObex *obex)
999 {
1000         struct pending_pkt *req = obex->pending_req;
1001
1002         g_obex_debug(G_OBEX_DEBUG_COMMAND, "conn %u", obex->conn_id);
1003
1004         obex->suspended = FALSE;
1005
1006         if (g_obex_srm_active(obex) || !req)
1007                 goto done;
1008
1009         if (g_obex_packet_get_operation(req->pkt, NULL) == G_OBEX_OP_GET)
1010                 g_obex_srm_resume(obex);
1011
1012 done:
1013         if (g_queue_get_length(obex->tx_queue) > 0 || obex->tx_data > 0)
1014                 enable_tx(obex);
1015 }
1016
1017 gboolean g_obex_srm_active(GObex *obex)
1018 {
1019         gboolean ret = FALSE;
1020
1021         if (!g_obex_srm_enabled(obex))
1022                 goto done;
1023
1024         if (obex->srm->srmp <= G_OBEX_SRMP_NEXT_WAIT)
1025                 goto done;
1026
1027         ret = TRUE;
1028 done:
1029         g_obex_debug(G_OBEX_DEBUG_COMMAND, "%s", ret ? "yes" : "no");
1030         return ret;
1031 }
1032
1033 static void auth_challenge(GObex *obex)
1034 {
1035         struct pending_pkt *p = obex->pending_req;
1036
1037         if (p->authenticating)
1038                 return;
1039
1040         p->authenticating = TRUE;
1041
1042         prepare_auth_rsp(obex, p->pkt);
1043
1044         /* Remove it as pending and add it back to the queue so it gets sent
1045          * again */
1046         if (p->timeout_id > 0) {
1047                 g_source_remove(p->timeout_id);
1048                 p->timeout_id = 0;
1049         }
1050         obex->pending_req = NULL;
1051         g_obex_send_internal(obex, p, NULL);
1052 }
1053
1054 static void parse_connect_data(GObex *obex, GObexPacket *pkt)
1055 {
1056         const struct connect_data *data;
1057         GObexHeader *hdr;
1058         guint16 u16;
1059         size_t data_len;
1060
1061         data = g_obex_packet_get_data(pkt, &data_len);
1062         if (data == NULL || data_len != sizeof(*data))
1063                 return;
1064
1065         memcpy(&u16, &data->mtu, sizeof(u16));
1066
1067         obex->tx_mtu = g_ntohs(u16);
1068         if (obex->io_tx_mtu > 0 && obex->tx_mtu > obex->io_tx_mtu)
1069                 obex->tx_mtu = obex->io_tx_mtu;
1070         obex->tx_buf = g_realloc(obex->tx_buf, obex->tx_mtu);
1071
1072         hdr = g_obex_packet_get_header(pkt, G_OBEX_HDR_CONNECTION);
1073         if (hdr)
1074                 g_obex_header_get_uint32(hdr, &obex->conn_id);
1075
1076         hdr = g_obex_packet_get_header(pkt, G_OBEX_HDR_AUTHCHAL);
1077         if (hdr)
1078                 obex->authchal = g_obex_header_get_apparam(hdr);
1079 }
1080
1081 static gboolean parse_response(GObex *obex, GObexPacket *rsp)
1082 {
1083         struct pending_pkt *p = obex->pending_req;
1084         guint8 opcode, rspcode;
1085         gboolean final;
1086
1087         rspcode = g_obex_packet_get_operation(rsp, &final);
1088
1089         opcode = g_obex_packet_get_operation(p->pkt, NULL);
1090         if (opcode == G_OBEX_OP_CONNECT) {
1091                 parse_connect_data(obex, rsp);
1092                 if (rspcode == G_OBEX_RSP_UNAUTHORIZED && obex->authchal)
1093                         auth_challenge(obex);
1094         }
1095
1096         setup_srm(obex, rsp, FALSE);
1097
1098         if (!g_obex_srm_enabled(obex))
1099                 return final;
1100
1101         /*
1102          * Resposes have final bit set but in case of GET with SRM
1103          * we should not remove the request since the remote side will
1104          * continue sending responses until the transfer is finished
1105          */
1106         if (opcode == G_OBEX_OP_GET && rspcode == G_OBEX_RSP_CONTINUE) {
1107                 if (p->timeout_id > 0)
1108                         g_source_remove(p->timeout_id);
1109
1110                 p->timeout_id = g_timeout_add_seconds(p->timeout, req_timeout,
1111                                                                         obex);
1112                 return FALSE;
1113         }
1114
1115         return final;
1116 }
1117
1118 static void handle_response(GObex *obex, GError *err, GObexPacket *rsp)
1119 {
1120         struct pending_pkt *p;
1121         gboolean disconn = err ? TRUE : FALSE, final_rsp = TRUE;
1122
1123         if (rsp != NULL)
1124                 final_rsp = parse_response(obex, rsp);
1125
1126         if (!obex->pending_req)
1127                 return;
1128
1129         p = obex->pending_req;
1130
1131         /* Reset if final so it can no longer be cancelled */
1132         if (final_rsp)
1133                 obex->pending_req = NULL;
1134
1135         if (p->cancelled)
1136                 err = g_error_new(G_OBEX_ERROR, G_OBEX_ERROR_CANCELLED,
1137                                         "The operation was cancelled");
1138
1139         if (err)
1140                 g_obex_debug(G_OBEX_DEBUG_ERROR, "%s", err->message);
1141
1142         if (p->rsp_func) {
1143                 p->rsp_func(obex, err, rsp, p->rsp_data);
1144
1145                 /* Check if user callback removed the request */
1146                 if (!final_rsp && p != obex->pending_req)
1147                         return;
1148         }
1149
1150         if (p->cancelled)
1151                 g_error_free(err);
1152
1153         if (final_rsp)
1154                 pending_pkt_free(p);
1155
1156         if (!disconn && g_queue_get_length(obex->tx_queue) > 0)
1157                 enable_tx(obex);
1158 }
1159
1160 static gboolean check_connid(GObex *obex, GObexPacket *pkt)
1161 {
1162         GObexHeader *hdr;
1163         guint32 id;
1164
1165         if (obex->conn_id == CONNID_INVALID)
1166                 return TRUE;
1167
1168         hdr = g_obex_packet_get_header(pkt, G_OBEX_HDR_CONNECTION);
1169         if (hdr == NULL)
1170                 return TRUE;
1171
1172         g_obex_header_get_uint32(hdr, &id);
1173
1174         return obex->conn_id == id;
1175 }
1176
1177 static int parse_request(GObex *obex, GObexPacket *req)
1178 {
1179         guint8 op;
1180         gboolean final;
1181
1182         op = g_obex_packet_get_operation(req, &final);
1183         switch (op) {
1184         case G_OBEX_OP_CONNECT:
1185                 parse_connect_data(obex, req);
1186                 break;
1187         case G_OBEX_OP_ABORT:
1188                 break;
1189         default:
1190                 if (check_connid(obex, req))
1191                         break;
1192
1193                 return -G_OBEX_RSP_SERVICE_UNAVAILABLE;
1194         }
1195
1196         setup_srm(obex, req, FALSE);
1197
1198         return op;
1199 }
1200
1201 static void handle_request(GObex *obex, GObexPacket *req)
1202 {
1203         GSList *match;
1204         int op;
1205
1206         op = parse_request(obex, req);
1207         if (op < 0)
1208                 goto fail;
1209
1210         match = g_slist_find_custom(obex->req_handlers, GUINT_TO_POINTER(op),
1211                                                         req_handler_cmpop);
1212         if (match) {
1213                 struct req_handler *handler = match->data;
1214                 handler->func(obex, req, handler->user_data);
1215                 return;
1216         }
1217
1218         op = -G_OBEX_RSP_NOT_IMPLEMENTED;
1219
1220 fail:
1221         g_obex_debug(G_OBEX_DEBUG_ERROR, "%s", g_obex_strerror(-op));
1222         g_obex_send_rsp(obex, -op, NULL, G_OBEX_HDR_INVALID);
1223 }
1224
1225 static gboolean read_stream(GObex *obex, GError **err)
1226 {
1227         GIOChannel *io = obex->io;
1228         GIOStatus status;
1229         gsize rbytes, toread;
1230         guint16 u16;
1231         char *buf;
1232
1233         if (obex->rx_data >= 3)
1234                 goto read_body;
1235
1236         rbytes = 0;
1237         toread = 3 - obex->rx_data;
1238         buf = (char *) &obex->rx_buf[obex->rx_data];
1239
1240         status = g_io_channel_read_chars(io, buf, toread, &rbytes, NULL);
1241         if (status != G_IO_STATUS_NORMAL)
1242                 return TRUE;
1243
1244         obex->rx_data += rbytes;
1245         if (obex->rx_data < 3)
1246                 goto done;
1247
1248         memcpy(&u16, &buf[1], sizeof(u16));
1249         obex->rx_pkt_len = g_ntohs(u16);
1250
1251         if (obex->rx_pkt_len > obex->rx_mtu) {
1252                 if (!err)
1253                         return FALSE;
1254                 g_set_error(err, G_OBEX_ERROR, G_OBEX_ERROR_PARSE_ERROR,
1255                                 "Too big incoming packet");
1256                 g_obex_debug(G_OBEX_DEBUG_ERROR, "%s", (*err)->message);
1257                 return FALSE;
1258         }
1259
1260 read_body:
1261         if (obex->rx_data >= obex->rx_pkt_len)
1262                 goto done;
1263
1264         do {
1265                 toread = obex->rx_pkt_len - obex->rx_data;
1266                 buf = (char *) &obex->rx_buf[obex->rx_data];
1267
1268                 status = g_io_channel_read_chars(io, buf, toread, &rbytes, NULL);
1269                 if (status != G_IO_STATUS_NORMAL)
1270                         goto done;
1271
1272                 obex->rx_data += rbytes;
1273         } while (rbytes > 0 && obex->rx_data < obex->rx_pkt_len);
1274
1275 done:
1276         g_obex_dump(G_OBEX_DEBUG_DATA, ">", obex->rx_buf, obex->rx_data);
1277
1278         return TRUE;
1279 }
1280
1281 static gboolean read_packet(GObex *obex, GError **err)
1282 {
1283         GIOChannel *io = obex->io;
1284         GError *read_err = NULL;
1285         GIOStatus status;
1286         gsize rbytes;
1287         guint16 u16;
1288
1289         if (obex->rx_data > 0) {
1290                 g_set_error(err, G_OBEX_ERROR, G_OBEX_ERROR_PARSE_ERROR,
1291                                 "RX buffer not empty before reading packet");
1292                 goto fail;
1293         }
1294
1295         status = g_io_channel_read_chars(io, (char *) obex->rx_buf,
1296                                         obex->rx_mtu, &rbytes, &read_err);
1297         if (status != G_IO_STATUS_NORMAL) {
1298                 g_set_error(err, G_OBEX_ERROR, G_OBEX_ERROR_PARSE_ERROR,
1299                                 "Unable to read data: %s", read_err->message);
1300                 g_error_free(read_err);
1301                 goto fail;
1302         }
1303
1304         obex->rx_data += rbytes;
1305
1306         if (rbytes < 3) {
1307                 g_set_error(err, G_OBEX_ERROR, G_OBEX_ERROR_PARSE_ERROR,
1308                                 "Incomplete packet received");
1309                 goto fail;
1310         }
1311
1312         memcpy(&u16, &obex->rx_buf[1], sizeof(u16));
1313         obex->rx_pkt_len = g_ntohs(u16);
1314
1315         if (obex->rx_pkt_len != rbytes) {
1316                 g_set_error(err, G_OBEX_ERROR, G_OBEX_ERROR_PARSE_ERROR,
1317                         "Data size doesn't match packet size (%zu != %u)",
1318                         rbytes, obex->rx_pkt_len);
1319                 return FALSE;
1320         }
1321
1322         g_obex_dump(G_OBEX_DEBUG_DATA, ">", obex->rx_buf, obex->rx_data);
1323
1324         return TRUE;
1325 fail:
1326         if (err)
1327                 g_obex_debug(G_OBEX_DEBUG_ERROR, "%s", (*err)->message);
1328
1329         return FALSE;
1330 }
1331
1332 static gboolean incoming_data(GIOChannel *io, GIOCondition cond,
1333                                                         gpointer user_data)
1334 {
1335         GObex *obex = user_data;
1336         GObexPacket *pkt;
1337         ssize_t header_offset;
1338         GError *err = NULL;
1339         guint8 opcode;
1340
1341         if (cond & G_IO_NVAL)
1342                 return FALSE;
1343
1344         if (cond & (G_IO_HUP | G_IO_ERR)) {
1345                 err = g_error_new(G_OBEX_ERROR, G_OBEX_ERROR_DISCONNECTED,
1346                                         "Transport got disconnected");
1347                 goto failed;
1348         }
1349
1350         if (!obex->read(obex, &err))
1351                 goto failed;
1352
1353         if (obex->rx_data < 3 || obex->rx_data < obex->rx_pkt_len)
1354                 return TRUE;
1355
1356         obex->rx_last_op = obex->rx_buf[0] & ~FINAL_BIT;
1357
1358         if (obex->pending_req) {
1359                 struct pending_pkt *p = obex->pending_req;
1360                 opcode = g_obex_packet_get_operation(p->pkt, NULL);
1361                 header_offset = rsp_header_offset(opcode);
1362         } else {
1363                 opcode = obex->rx_last_op;
1364                 /* Unexpected response -- fail silently */
1365                 if (opcode > 0x1f && opcode != G_OBEX_OP_ABORT) {
1366                         obex->rx_data = 0;
1367                         return TRUE;
1368                 }
1369                 header_offset = req_header_offset(opcode);
1370         }
1371
1372         if (header_offset < 0) {
1373                 err = g_error_new(G_OBEX_ERROR, G_OBEX_ERROR_PARSE_ERROR,
1374                                 "Unknown header offset for opcode 0x%02x",
1375                                 opcode);
1376                 goto failed;
1377         }
1378
1379         pkt = g_obex_packet_decode(obex->rx_buf, obex->rx_data, header_offset,
1380                                                         G_OBEX_DATA_REF, &err);
1381         if (pkt == NULL)
1382                 goto failed;
1383
1384         /* Protect against user callback freeing the object */
1385         g_obex_ref(obex);
1386
1387         if (obex->pending_req)
1388                 handle_response(obex, NULL, pkt);
1389         else
1390                 handle_request(obex, pkt);
1391
1392         obex->rx_data = 0;
1393
1394         g_obex_unref(obex);
1395
1396         if (err != NULL)
1397                 g_error_free(err);
1398
1399         if (pkt != NULL)
1400                 g_obex_packet_free(pkt);
1401
1402         return TRUE;
1403
1404 failed:
1405         if (err)
1406                 g_obex_debug(G_OBEX_DEBUG_ERROR, "%s", err->message);
1407
1408         g_io_channel_unref(obex->io);
1409         obex->io = NULL;
1410         obex->io_source = 0;
1411         obex->rx_data = 0;
1412
1413         /* Protect against user callback freeing the object */
1414         g_obex_ref(obex);
1415
1416         if (obex->pending_req)
1417                 handle_response(obex, err, NULL);
1418
1419         if (obex->disconn_func)
1420                 obex->disconn_func(obex, err, obex->disconn_func_data);
1421
1422         g_obex_unref(obex);
1423
1424         g_error_free(err);
1425
1426         return FALSE;
1427 }
1428
1429 static GDebugKey keys[] = {
1430         { "error",      G_OBEX_DEBUG_ERROR },
1431         { "command",    G_OBEX_DEBUG_COMMAND },
1432         { "transfer",   G_OBEX_DEBUG_TRANSFER },
1433         { "header",     G_OBEX_DEBUG_HEADER },
1434         { "packet",     G_OBEX_DEBUG_PACKET },
1435         { "data",       G_OBEX_DEBUG_DATA },
1436         { "apparam",    G_OBEX_DEBUG_APPARAM },
1437 };
1438
1439 GObex *g_obex_new(GIOChannel *io, GObexTransportType transport_type,
1440                                         gssize io_rx_mtu, gssize io_tx_mtu)
1441 {
1442         GObex *obex;
1443         GIOCondition cond;
1444
1445         if (gobex_debug == 0) {
1446                 const char *env = g_getenv("GOBEX_DEBUG");
1447
1448                 if (env) {
1449                         gobex_debug = g_parse_debug_string(env, keys, 7);
1450                         g_setenv("G_MESSAGES_DEBUG", "gobex", FALSE);
1451                 } else
1452                         gobex_debug = G_OBEX_DEBUG_NONE;
1453         }
1454
1455         g_obex_debug(G_OBEX_DEBUG_COMMAND, "");
1456
1457         if (io == NULL)
1458                 return NULL;
1459
1460         if (io_rx_mtu >= 0 && io_rx_mtu < G_OBEX_MINIMUM_MTU)
1461                 return NULL;
1462
1463         if (io_tx_mtu >= 0 && io_tx_mtu < G_OBEX_MINIMUM_MTU)
1464                 return NULL;
1465
1466         obex = g_new0(GObex, 1);
1467
1468         obex->io = g_io_channel_ref(io);
1469         obex->ref_count = 1;
1470         obex->conn_id = CONNID_INVALID;
1471         obex->rx_last_op = G_OBEX_OP_NONE;
1472
1473         obex->io_rx_mtu = io_rx_mtu;
1474         obex->io_tx_mtu = io_tx_mtu;
1475
1476         if (io_rx_mtu > G_OBEX_MAXIMUM_MTU)
1477                 obex->rx_mtu = G_OBEX_MAXIMUM_MTU;
1478         else if (io_rx_mtu < G_OBEX_MINIMUM_MTU)
1479                 obex->rx_mtu = G_OBEX_DEFAULT_MTU;
1480         else
1481                 obex->rx_mtu = io_rx_mtu;
1482
1483         obex->tx_mtu = G_OBEX_MINIMUM_MTU;
1484
1485         obex->tx_queue = g_queue_new();
1486         obex->rx_buf = g_malloc(obex->rx_mtu);
1487         obex->tx_buf = g_malloc(obex->tx_mtu);
1488
1489         switch (transport_type) {
1490         case G_OBEX_TRANSPORT_STREAM:
1491                 obex->read = read_stream;
1492                 obex->write = write_stream;
1493                 break;
1494         case G_OBEX_TRANSPORT_PACKET:
1495                 obex->use_srm = TRUE;
1496                 obex->read = read_packet;
1497                 obex->write = write_packet;
1498                 break;
1499         default:
1500                 g_obex_unref(obex);
1501                 return NULL;
1502         }
1503
1504         g_io_channel_set_encoding(io, NULL, NULL);
1505         g_io_channel_set_buffered(io, FALSE);
1506         cond = G_IO_IN | G_IO_HUP | G_IO_ERR | G_IO_NVAL;
1507         obex->io_source = g_io_add_watch(io, cond, incoming_data, obex);
1508
1509         return obex;
1510 }
1511
1512 GObex *g_obex_ref(GObex *obex)
1513 {
1514         int refs;
1515
1516         if (obex == NULL)
1517                 return NULL;
1518
1519         refs = __sync_add_and_fetch(&obex->ref_count, 1);
1520
1521         g_obex_debug(G_OBEX_DEBUG_COMMAND, "ref %u", refs);
1522
1523         return obex;
1524 }
1525
1526 static void tx_queue_free(void *data, void *user_data)
1527 {
1528         pending_pkt_free(data);
1529 }
1530
1531 void g_obex_unref(GObex *obex)
1532 {
1533         int refs;
1534
1535         refs = __sync_sub_and_fetch(&obex->ref_count, 1);
1536
1537         g_obex_debug(G_OBEX_DEBUG_COMMAND, "ref %u", refs);
1538
1539         if (refs > 0)
1540                 return;
1541
1542         g_slist_free_full(obex->req_handlers, g_free);
1543
1544         g_queue_foreach(obex->tx_queue, tx_queue_free, NULL);
1545         g_queue_free(obex->tx_queue);
1546
1547         if (obex->io != NULL)
1548                 g_io_channel_unref(obex->io);
1549
1550         if (obex->io_source > 0)
1551                 g_source_remove(obex->io_source);
1552
1553         if (obex->write_source > 0)
1554                 g_source_remove(obex->write_source);
1555
1556         g_free(obex->rx_buf);
1557         g_free(obex->tx_buf);
1558         g_free(obex->srm);
1559
1560         if (obex->pending_req)
1561                 pending_pkt_free(obex->pending_req);
1562
1563         if (obex->authchal)
1564                 g_obex_apparam_free(obex->authchal);
1565
1566         g_free(obex);
1567 }
1568
1569 /* Higher level functions */
1570 #ifdef TIZEN_FEATURE_BLUEZ_MODIFY
1571 void g_obex_io_shutdown(GObex *obex)
1572 {
1573         GError *err = NULL;
1574         if (obex->io != NULL)
1575                 g_io_channel_shutdown(obex->io, FALSE, &err);
1576 }
1577 #endif
1578 guint g_obex_connect(GObex *obex, GObexResponseFunc func, gpointer user_data,
1579                                         GError **err, guint first_hdr_id, ...)
1580 {
1581         GObexPacket *req;
1582         struct connect_data data;
1583         va_list args;
1584
1585         g_obex_debug(G_OBEX_DEBUG_COMMAND, "");
1586
1587         va_start(args, first_hdr_id);
1588         req = g_obex_packet_new_valist(G_OBEX_OP_CONNECT, TRUE,
1589                                                         first_hdr_id, args);
1590         va_end(args);
1591
1592         init_connect_data(obex, &data);
1593         g_obex_packet_set_data(req, &data, sizeof(data), G_OBEX_DATA_COPY);
1594
1595         return g_obex_send_req(obex, req, -1, func, user_data, err);
1596 }
1597
1598 guint g_obex_disconnect(GObex *obex, GObexResponseFunc func, gpointer user_data,
1599                                                                 GError **err)
1600 {
1601         GObexPacket *req;
1602
1603         g_obex_debug(G_OBEX_DEBUG_COMMAND, "");
1604
1605         req = g_obex_packet_new(G_OBEX_OP_DISCONNECT, TRUE, G_OBEX_HDR_INVALID);
1606
1607         return g_obex_send_req(obex, req, -1, func, user_data, err);
1608 }
1609
1610 guint g_obex_setpath(GObex *obex, const char *path, GObexResponseFunc func,
1611                                         gpointer user_data, GError **err)
1612 {
1613         GObexPacket *req;
1614         struct setpath_data data;
1615         const char *folder;
1616
1617         g_obex_debug(G_OBEX_DEBUG_COMMAND, "conn %u", obex->conn_id);
1618
1619         req = g_obex_packet_new(G_OBEX_OP_SETPATH, TRUE, G_OBEX_HDR_INVALID);
1620
1621         memset(&data, 0, sizeof(data));
1622
1623         if (path != NULL && strncmp("..", path, 2) == 0) {
1624                 data.flags = 0x03;
1625                 folder = (path[2] == '/') ? &path[3] : NULL;
1626         } else {
1627                 data.flags = 0x02;
1628                 folder = path;
1629         }
1630
1631         if (folder != NULL) {
1632                 GObexHeader *hdr;
1633                 hdr = g_obex_header_new_unicode(G_OBEX_HDR_NAME, folder);
1634                 g_obex_packet_add_header(req, hdr);
1635         }
1636
1637         g_obex_packet_set_data(req, &data, sizeof(data), G_OBEX_DATA_COPY);
1638
1639         return g_obex_send_req(obex, req, -1, func, user_data, err);
1640 }
1641
1642 guint g_obex_mkdir(GObex *obex, const char *path, GObexResponseFunc func,
1643                                         gpointer user_data, GError **err)
1644 {
1645         GObexPacket *req;
1646         struct setpath_data data;
1647
1648         g_obex_debug(G_OBEX_DEBUG_COMMAND, "conn %u", obex->conn_id);
1649
1650         req = g_obex_packet_new(G_OBEX_OP_SETPATH, TRUE, G_OBEX_HDR_NAME, path,
1651                                                         G_OBEX_HDR_INVALID);
1652
1653         memset(&data, 0, sizeof(data));
1654         g_obex_packet_set_data(req, &data, sizeof(data), G_OBEX_DATA_COPY);
1655
1656         return g_obex_send_req(obex, req, -1, func, user_data, err);
1657 }
1658
1659 guint g_obex_delete(GObex *obex, const char *name, GObexResponseFunc func,
1660                                         gpointer user_data, GError **err)
1661 {
1662         GObexPacket *req;
1663
1664         g_obex_debug(G_OBEX_DEBUG_COMMAND, "conn %u", obex->conn_id);
1665
1666         req = g_obex_packet_new(G_OBEX_OP_PUT, TRUE, G_OBEX_HDR_NAME, name,
1667                                                         G_OBEX_HDR_INVALID);
1668
1669         return g_obex_send_req(obex, req, -1, func, user_data, err);
1670 }
1671
1672 guint g_obex_copy(GObex *obex, const char *name, const char *dest,
1673                         GObexResponseFunc func, gpointer user_data,
1674                         GError **err)
1675 {
1676         GObexPacket *req;
1677
1678         g_obex_debug(G_OBEX_DEBUG_COMMAND, "conn %u", obex->conn_id);
1679
1680         req = g_obex_packet_new(G_OBEX_OP_ACTION, TRUE,
1681                                         G_OBEX_HDR_ACTION, G_OBEX_ACTION_COPY,
1682                                         G_OBEX_HDR_NAME, name,
1683                                         G_OBEX_HDR_DESTNAME, dest,
1684                                         G_OBEX_HDR_INVALID);
1685
1686         return g_obex_send_req(obex, req, -1, func, user_data, err);
1687 }
1688
1689 guint g_obex_move(GObex *obex, const char *name, const char *dest,
1690                         GObexResponseFunc func, gpointer user_data,
1691                         GError **err)
1692 {
1693         GObexPacket *req;
1694
1695         g_obex_debug(G_OBEX_DEBUG_COMMAND, "conn %u", obex->conn_id);
1696
1697         req = g_obex_packet_new(G_OBEX_OP_ACTION, TRUE,
1698                                         G_OBEX_HDR_ACTION, G_OBEX_ACTION_MOVE,
1699                                         G_OBEX_HDR_NAME, name,
1700                                         G_OBEX_HDR_DESTNAME, dest,
1701                                         G_OBEX_HDR_INVALID);
1702
1703         return g_obex_send_req(obex, req, -1, func, user_data, err);
1704 }
1705
1706 guint g_obex_abort(GObex *obex, GObexResponseFunc func, gpointer user_data,
1707                                                                 GError **err)
1708 {
1709         GObexPacket *req;
1710
1711         req = g_obex_packet_new(G_OBEX_OP_ABORT, TRUE, G_OBEX_HDR_INVALID);
1712
1713         return g_obex_send_req(obex, req, -1, func, user_data, err);
1714 }
1715
1716 guint8 g_obex_errno_to_rsp(int err)
1717 {
1718         switch (err) {
1719         case 0:
1720                 return G_OBEX_RSP_SUCCESS;
1721         case -EPERM:
1722         case -EACCES:
1723                 return G_OBEX_RSP_FORBIDDEN;
1724         case -ENOENT:
1725                 return G_OBEX_RSP_NOT_FOUND;
1726         case -EINVAL:
1727         case -EBADR:
1728                 return G_OBEX_RSP_BAD_REQUEST;
1729         case -EFAULT:
1730                 return G_OBEX_RSP_SERVICE_UNAVAILABLE;
1731         case -ENOSYS:
1732                 return G_OBEX_RSP_NOT_IMPLEMENTED;
1733         case -ENOTEMPTY:
1734         case -EEXIST:
1735                 return G_OBEX_RSP_PRECONDITION_FAILED;
1736         default:
1737                 return G_OBEX_RSP_INTERNAL_SERVER_ERROR;
1738         }
1739 }