Coverage Report

Created: 2025-01-28 06:43

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