Coverage Report

Created: 2024-09-08 07:48

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