~bluetooth/ubuntu/lucid/obexd/lp_559412

« back to all changes in this revision

Viewing changes to client/session.c

  • Committer: Baptiste Mille-Mathias
  • Date: 2010-03-15 19:43:06 UTC
  • mto: This revision was merged to the branch mainline in revision 4.
  • Revision ID: baptiste.millemathias@gmail.com-20100315194306-no1149mqz1tpnlds
Tags: upstream-0.22
ImportĀ upstreamĀ versionĀ 0.22

Show diffs side-by-side

added added

removed removed

Lines of Context:
2
2
 *
3
3
 *  OBEX Client
4
4
 *
5
 
 *  Copyright (C) 2007-2009  Marcel Holtmann <marcel@holtmann.org>
 
5
 *  Copyright (C) 2007-2010  Marcel Holtmann <marcel@holtmann.org>
6
6
 *
7
7
 *
8
8
 *  This program is free software; you can redistribute it and/or modify
39
39
#include <bluetooth/sdp.h>
40
40
#include <bluetooth/sdp_lib.h>
41
41
 
 
42
#include "logging.h"
42
43
#include "pbap.h"
43
44
#include "sync.h"
44
45
#include "session.h"
55
56
 
56
57
#define DEFAULT_BUFFER_SIZE 4096
57
58
 
 
59
typedef int (*reply_callback_t) (struct session_data *session, void *data);
 
60
 
58
61
static guint64 counter = 0;
59
62
 
60
63
static unsigned char pcsuite_uuid[] = { 0x00, 0x00, 0x50, 0x05, 0x00, 0x00,
68
71
        void *data;
69
72
};
70
73
 
 
74
struct pending_request {
 
75
        struct session_data *session;
 
76
        reply_callback_t callback;
 
77
        void *data;
 
78
};
 
79
 
 
80
struct get_params {
 
81
        const char *type;
 
82
        const guint8 *apparam;
 
83
        gint apparam_size;
 
84
        session_callback_t func;
 
85
};
 
86
 
71
87
static struct session_data *session_ref(struct session_data *session)
72
88
{
73
89
        g_atomic_int_inc(&session->refcount);
461
477
        return 0;
462
478
}
463
479
 
464
 
static void agent_request(DBusConnection *conn, const char *agent_name,
465
 
                        const char *agent_path, const char *transfer_path)
466
 
{
467
 
        DBusMessage *message;
468
 
 
469
 
        if (agent_name == NULL || agent_path == NULL || transfer_path == NULL)
470
 
                return;
471
 
 
472
 
        message = dbus_message_new_method_call(agent_name,
473
 
                        agent_path, AGENT_INTERFACE, "Request");
474
 
 
475
 
        dbus_message_append_args(message,
476
 
                        DBUS_TYPE_OBJECT_PATH, &transfer_path,
477
 
                        DBUS_TYPE_INVALID);
478
 
 
479
 
        g_dbus_send_message(conn, message);
480
 
 
481
 
        /* FIXME: Reply needs be handled */
482
 
}
483
 
 
484
480
static void agent_notify_progress(DBusConnection *conn, const char *agent_name,
485
481
                        const char *agent_path, const char *transfer_path,
486
482
                        uint64_t transferred)
592
588
        session_unref(session);
593
589
}
594
590
 
595
 
int session_set_agent(struct session_data *session, const char *name,
596
 
                                                        const char *path)
597
 
{
598
 
        if (session == NULL)
599
 
                return -EINVAL;
600
 
 
601
 
        if (session->agent_name != NULL || session->agent_path != NULL)
602
 
                return -EALREADY;
603
 
 
604
 
        session->agent_name = g_strdup(name);
605
 
        session->agent_path = g_strdup(path);
606
 
 
607
 
        return 0;
608
 
}
609
 
 
610
591
static void append_entry(DBusMessageIter *dict,
611
592
                                const char *key, int type, void *val)
612
593
{
978
959
 
979
960
static void unregister_transfer(struct session_data *session)
980
961
{
981
 
        gw_obex_xfer_close(session->xfer, NULL);
982
 
        gw_obex_xfer_free(session->xfer);
983
 
        session->xfer = NULL;
 
962
        if (session->xfer) {
 
963
                gw_obex_xfer_close(session->xfer, NULL);
 
964
                gw_obex_xfer_free(session->xfer);
 
965
                session->xfer = NULL;
 
966
        }
984
967
 
985
968
        g_free(session->filename);
986
969
        session->filename = NULL;
1081
1064
        }
1082
1065
 
1083
1066
        if (err) {
1084
 
                fprintf(stderr, "gw_obex_xfer_read(): %s\n",
 
1067
                error("gw_obex_xfer_read(): %s",
1085
1068
                                OBEX_ResponseToString(err));
1086
1069
                goto complete;
1087
1070
        }
1157
1140
        }
1158
1141
 
1159
1142
        if (ret == FALSE) {
1160
 
                fprintf(stderr, "gw_obex_xfer_read(): %s\n",
 
1143
                error("gw_obex_xfer_read(): %s",
1161
1144
                                OBEX_ResponseToString(err));
1162
1145
                goto complete;
1163
1146
        }
1215
1198
        g_free(callback);
1216
1199
}
1217
1200
 
 
1201
static void put_xfer_progress(GwObexXfer *xfer, gpointer user_data)
 
1202
{
 
1203
        struct session_data *session = user_data;
 
1204
        ssize_t len;
 
1205
        gint written;
 
1206
 
 
1207
        if (session->buffer_len == 0) {
 
1208
                session->buffer_len = DEFAULT_BUFFER_SIZE;
 
1209
                session->buffer = g_new0(char, DEFAULT_BUFFER_SIZE);
 
1210
        }
 
1211
 
 
1212
        len = read(session->fd, session->buffer + session->filled,
 
1213
                                session->buffer_len - session->filled);
 
1214
        if (len <= 0)
 
1215
                goto complete;
 
1216
 
 
1217
        if (gw_obex_xfer_write(xfer, session->buffer, session->filled + len,
 
1218
                                                &written, NULL) == FALSE)
 
1219
                goto complete;
 
1220
 
 
1221
        if (gw_obex_xfer_flush(xfer, NULL) == FALSE)
 
1222
                goto complete;
 
1223
 
 
1224
        session->filled = (session->filled + len) - written;
 
1225
 
 
1226
        memmove(session->buffer, session->buffer + written, session->filled);
 
1227
 
 
1228
        session->transferred += written;
 
1229
 
 
1230
        agent_notify_progress(session->conn, session->agent_name,
 
1231
                        session->agent_path, session->transfer_path,
 
1232
                        session->transferred);
 
1233
        return;
 
1234
 
 
1235
complete:
 
1236
        if (len == 0)
 
1237
                agent_notify_complete(session->conn, session->agent_name,
 
1238
                                session->agent_path, session->transfer_path);
 
1239
        else
 
1240
                agent_notify_error(session->conn, session->agent_name,
 
1241
                                session->agent_path, session->transfer_path,
 
1242
                                "Error sending object");
 
1243
 
 
1244
        unregister_transfer(session);
 
1245
 
 
1246
        if (session->pending->len > 0) {
 
1247
                gchar *filename = g_ptr_array_index(session->pending, 0);
 
1248
                gchar *basename = g_path_get_basename(filename);
 
1249
 
 
1250
                g_ptr_array_remove(session->pending, filename);
 
1251
 
 
1252
                session_send(session, filename, basename);
 
1253
                g_free(filename);
 
1254
                g_free(basename);
 
1255
        }
 
1256
 
 
1257
        session_unref(session);
 
1258
}
 
1259
 
 
1260
static void agent_request_reply(DBusPendingCall *call, gpointer user_data)
 
1261
{
 
1262
        struct pending_request *pending = user_data;
 
1263
        struct session_data *session = pending->session;
 
1264
        DBusMessage *reply = dbus_pending_call_steal_reply(call);
 
1265
        const char *name;
 
1266
        DBusError derr;
 
1267
 
 
1268
        dbus_error_init(&derr);
 
1269
        if (dbus_set_error_from_message(&derr, reply)) {
 
1270
                error("Replied with an error: %s, %s",
 
1271
                                derr.name, derr.message);
 
1272
                dbus_error_free(&derr);
 
1273
                goto fail;
 
1274
        }
 
1275
 
 
1276
        dbus_message_get_args(reply, NULL,
 
1277
                        DBUS_TYPE_STRING, &name,
 
1278
                        DBUS_TYPE_INVALID);
 
1279
 
 
1280
        if (strlen(name)) {
 
1281
                g_free(session->name);
 
1282
                session->name = g_strdup(name);
 
1283
        }
 
1284
 
 
1285
        if (pending->callback(session, pending->data))
 
1286
                goto fail;
 
1287
 
 
1288
        g_free(pending);
 
1289
 
 
1290
        return;
 
1291
 
 
1292
fail:
 
1293
        unregister_transfer(session);
 
1294
 
 
1295
        session_unref(session);
 
1296
 
 
1297
        if (session->pending->len > 0) {
 
1298
                gchar *filename = g_ptr_array_index(session->pending, 0);
 
1299
                gchar *basename = g_path_get_basename(filename);
 
1300
 
 
1301
                g_ptr_array_remove(session->pending, filename);
 
1302
 
 
1303
                session_send(session, filename, basename);
 
1304
                g_free(filename);
 
1305
                g_free(basename);
 
1306
        }
 
1307
 
 
1308
        g_free(pending);
 
1309
}
 
1310
 
 
1311
static void agent_request(DBusConnection *conn, struct session_data *session,
 
1312
                reply_callback_t cb, void *user_data)
 
1313
{
 
1314
        DBusMessage *message;
 
1315
        DBusPendingCall *call;
 
1316
        struct pending_request *pending;
 
1317
 
 
1318
        if (session->agent_name == NULL || session->agent_path == NULL ||
 
1319
                        session->transfer_path == NULL) {
 
1320
                if (cb(session, user_data))
 
1321
                        goto fail;
 
1322
 
 
1323
                return;
 
1324
        }
 
1325
 
 
1326
        message = dbus_message_new_method_call(session->agent_name,
 
1327
                        session->agent_path, AGENT_INTERFACE, "Request");
 
1328
 
 
1329
        dbus_message_append_args(message,
 
1330
                        DBUS_TYPE_OBJECT_PATH, &session->transfer_path,
 
1331
                        DBUS_TYPE_INVALID);
 
1332
 
 
1333
        if (!dbus_connection_send_with_reply(conn, message, &call, -1)) {
 
1334
                dbus_message_unref(message);
 
1335
                return;
 
1336
        }
 
1337
 
 
1338
        dbus_message_unref(message);
 
1339
 
 
1340
        pending = g_new0(struct pending_request, 1);
 
1341
        pending->session = session;
 
1342
        pending->callback = cb;
 
1343
        pending->data = user_data;
 
1344
 
 
1345
        dbus_pending_call_set_notify(call, agent_request_reply, pending, NULL);
 
1346
        dbus_pending_call_unref(call);
 
1347
 
 
1348
        return;
 
1349
 
 
1350
fail:
 
1351
        unregister_transfer(session);
 
1352
 
 
1353
        session_unref(session);
 
1354
}
 
1355
 
 
1356
static int session_get_reply(struct session_data *session, void *data)
 
1357
{
 
1358
        struct get_params *params = data;
 
1359
        struct callback_data *callback;
 
1360
        GwObexXfer *xfer;
 
1361
 
 
1362
        xfer = gw_obex_get_async_with_apparam(session->obex, session->filename,
 
1363
                        params->type, params->apparam, params->apparam_size,
 
1364
                        NULL);
 
1365
 
 
1366
        if (xfer == NULL) {
 
1367
                close(session->fd);
 
1368
                session_unref(session);
 
1369
                g_free(params);
 
1370
                return -EIO;
 
1371
        }
 
1372
 
 
1373
        callback = g_try_malloc0(sizeof(*callback));
 
1374
        if (callback == NULL) {
 
1375
                close(session->fd);
 
1376
                session_unref(session);
 
1377
                gw_obex_xfer_free(xfer);
 
1378
                g_free(params);
 
1379
                return -ENOMEM;
 
1380
        }
 
1381
 
 
1382
        callback->session = session;
 
1383
        callback->func = params->func;
 
1384
 
 
1385
        if (params->type == NULL)
 
1386
                gw_obex_xfer_set_callback(xfer, get_xfer_progress, callback);
 
1387
        else
 
1388
                gw_obex_xfer_set_callback(xfer, get_xfer_listing_progress,
 
1389
                                        callback);
 
1390
 
 
1391
        session->xfer = xfer;
 
1392
 
 
1393
        agent_notify_progress(session->conn, session->agent_name,
 
1394
                        session->agent_path, session->transfer_path, 0);
 
1395
 
 
1396
        g_free(params);
 
1397
 
 
1398
        return 0;
 
1399
}
 
1400
 
1218
1401
int session_get(struct session_data *session, const char *type,
1219
1402
                const char *filename, const char *targetname,
1220
1403
                const guint8  *apparam, gint apparam_size,
1221
1404
                session_callback_t func)
1222
1405
{
1223
 
        struct callback_data *callback;
1224
 
        GwObexXfer *xfer;
 
1406
        struct get_params *params;
1225
1407
        int err, fd = 0;
1226
1408
 
1227
1409
        if (session->obex == NULL)
1234
1416
                fd = open(targetname, O_WRONLY | O_CREAT, 0600);
1235
1417
                if (fd < 0) {
1236
1418
                        err = errno;
1237
 
                        fprintf(stderr, "open(): %s(%d)\n", strerror(err), err);
 
1419
                        error("open(): %s(%d)", strerror(err), err);
1238
1420
                        return -err;
1239
1421
                }
1240
1422
        }
1241
1423
 
1242
 
        if (type == NULL || !g_str_equal(type, "x-obex/folder-listing")) {
 
1424
        /* for OBEX specific mime types we don't need to register a transfer */
 
1425
        if (type == NULL || (strncmp(type, "x-obex/", 7) && strncmp(type, "x-bt/", 5))) {
1243
1426
                session->transfer_path = register_transfer(session->conn, session);
1244
1427
                if (session->transfer_path == NULL) {
1245
1428
                        if (fd)
1257
1440
 
1258
1441
        session_ref(session);
1259
1442
 
1260
 
        xfer = gw_obex_get_async_with_apparam(session->obex,
1261
 
                                filename, type, apparam, apparam_size, NULL);
1262
 
        if (xfer == NULL) {
1263
 
                close(session->fd);
1264
 
                session_unref(session);
1265
 
                return -EIO;
1266
 
        }
1267
 
 
1268
 
        callback = g_try_malloc0(sizeof(*callback));
1269
 
        if (callback == NULL) {
1270
 
                close(session->fd);
1271
 
                session_unref(session);
1272
 
                gw_obex_xfer_free(xfer);
1273
 
                return -ENOMEM;
1274
 
        }
1275
 
 
1276
 
        callback->session = session;
1277
 
        callback->func = func;
1278
 
 
1279
 
        if (type == NULL)
1280
 
                gw_obex_xfer_set_callback(xfer, get_xfer_progress, callback);
1281
 
        else
1282
 
                gw_obex_xfer_set_callback(xfer, get_xfer_listing_progress,
1283
 
                                        callback);
1284
 
 
1285
 
        session->xfer = xfer;
1286
 
 
1287
 
        agent_request(session->conn, session->agent_name,
1288
 
                        session->agent_path, session->transfer_path);
1289
 
 
1290
 
        agent_notify_progress(session->conn, session->agent_name,
1291
 
                        session->agent_path, session->transfer_path, 0);
 
1443
        params = g_new0(struct get_params, 1);
 
1444
        params->type = type;
 
1445
        params->apparam = apparam;
 
1446
        params->apparam_size = apparam_size;
 
1447
        params->func = func;
 
1448
 
 
1449
        agent_request(session->conn, session, session_get_reply, params);
1292
1450
 
1293
1451
        return 0;
1294
1452
}
1458
1616
        { }
1459
1617
};
1460
1618
 
1461
 
static void put_xfer_progress(GwObexXfer *xfer, gpointer user_data)
 
1619
 
 
1620
static int session_send_reply(struct session_data *session, void *data)
1462
1621
{
1463
 
        struct session_data *session = user_data;
1464
 
        ssize_t len;
1465
 
        gint written;
1466
 
 
1467
 
        if (session->buffer_len == 0) {
1468
 
                session->buffer_len = DEFAULT_BUFFER_SIZE;
1469
 
                session->buffer = g_new0(char, DEFAULT_BUFFER_SIZE);
1470
 
        }
1471
 
 
1472
 
        len = read(session->fd, session->buffer + session->filled,
1473
 
                                session->buffer_len - session->filled);
1474
 
        if (len <= 0)
1475
 
                goto complete;
1476
 
 
1477
 
        if (gw_obex_xfer_write(xfer, session->buffer, session->filled + len,
1478
 
                                                &written, NULL) == FALSE)
1479
 
                goto complete;
1480
 
 
1481
 
        if (gw_obex_xfer_flush(xfer, NULL) == FALSE)
1482
 
                goto complete;
1483
 
 
1484
 
        session->filled = (session->filled + len) - written;
1485
 
 
1486
 
        memmove(session->buffer + written, session->buffer, session->filled);
1487
 
 
1488
 
        session->transferred += written;
 
1622
        GwObexXfer *xfer;
 
1623
 
 
1624
        xfer = gw_obex_put_async(session->obex, session->name, NULL,
 
1625
                        session->size, -1, NULL);
 
1626
        if (xfer == NULL)
 
1627
                return -ENOTCONN;
 
1628
 
 
1629
        gw_obex_xfer_set_callback(xfer, put_xfer_progress, session);
 
1630
 
 
1631
        session->xfer = xfer;
1489
1632
 
1490
1633
        agent_notify_progress(session->conn, session->agent_name,
1491
 
                        session->agent_path, session->transfer_path,
1492
 
                        session->transferred);
1493
 
        return;
1494
 
 
1495
 
complete:
1496
 
        if (len == 0)
1497
 
                agent_notify_complete(session->conn, session->agent_name,
1498
 
                                session->agent_path, session->transfer_path);
1499
 
        else
1500
 
                agent_notify_error(session->conn, session->agent_name,
1501
 
                                session->agent_path, session->transfer_path,
1502
 
                                "Error sending object");
1503
 
 
1504
 
        unregister_transfer(session);
1505
 
 
1506
 
        if (session->pending->len > 0) {
1507
 
                gchar *filename = g_ptr_array_index(session->pending, 0);
1508
 
                gchar *basename = g_path_get_basename(filename);
1509
 
 
1510
 
                g_ptr_array_remove(session->pending, filename);
1511
 
 
1512
 
                session_send(session, filename, basename);
1513
 
                g_free(filename);
1514
 
                g_free(basename);
1515
 
        }
1516
 
 
1517
 
        session_unref(session);
 
1634
                        session->agent_path, session->transfer_path, 0);
 
1635
 
 
1636
        return 0;
1518
1637
}
1519
1638
 
1520
1639
int session_send(struct session_data *session, const char *filename,
1521
1640
                                const char *targetname)
1522
1641
{
1523
 
        GwObexXfer *xfer;
1524
1642
        struct stat st;
1525
 
        int fd;
 
1643
        int fd, err;
1526
1644
 
1527
1645
        if (session->obex == NULL)
1528
1646
                return -ENOTCONN;
1529
1647
 
1530
 
        if (session->xfer != NULL) {
 
1648
        if (session->transfer_path != NULL) {
1531
1649
                g_ptr_array_add(session->pending, g_strdup(filename));
1532
1650
                return 0;
1533
1651
        }
1534
1652
 
 
1653
        session->transfer_path = register_transfer(session->conn, session);
 
1654
        if (session->transfer_path == NULL) {
 
1655
                err = -EINVAL;
 
1656
                goto fail;
 
1657
        }
 
1658
 
1535
1659
        fd = open(filename, O_RDONLY);
1536
 
        if (fd < 0)
1537
 
                return -EIO;
 
1660
        if (fd < 0) {
 
1661
                err = -EIO;
 
1662
                goto fail;
 
1663
        }
1538
1664
 
1539
1665
        if (fstat(fd, &st) < 0) {
1540
1666
                close(fd);
1541
 
                return -EIO;
1542
 
        }
1543
 
 
1544
 
        session->transfer_path = register_transfer(session->conn, session);
1545
 
        if (session->transfer_path == NULL) {
1546
 
                close(fd);
1547
 
                return -EIO;
 
1667
                err = -EIO;
 
1668
                goto fail;
1548
1669
        }
1549
1670
 
1550
1671
        session->fd = fd;
1555
1676
 
1556
1677
        session_ref(session);
1557
1678
 
1558
 
        xfer = gw_obex_put_async(session->obex, session->name, NULL,
1559
 
                                                session->size, -1, NULL);
1560
 
        if (xfer == NULL)
1561
 
                return -ENOTCONN;
1562
 
 
1563
 
        gw_obex_xfer_set_callback(xfer, put_xfer_progress, session);
1564
 
 
1565
 
        session->xfer = xfer;
1566
 
 
1567
 
        agent_request(session->conn, session->agent_name,
1568
 
                        session->agent_path, session->transfer_path);
1569
 
 
1570
 
        agent_notify_progress(session->conn, session->agent_name,
1571
 
                        session->agent_path, session->transfer_path, 0);
 
1679
        agent_request(session->conn, session, session_send_reply, NULL);
1572
1680
 
1573
1681
        return 0;
 
1682
 
 
1683
fail:
 
1684
        agent_notify_error(session->conn, session->agent_name,
 
1685
                        session->agent_path, session->transfer_path,
 
1686
                        "Could not open file for sending");
 
1687
 
 
1688
        return err;
1574
1689
}
1575
1690
 
1576
1691
int session_pull(struct session_data *session,
1695
1810
        session_unref(session);
1696
1811
}
1697
1812
 
 
1813
 
 
1814
static int session_put_reply(struct session_data *session, void *data)
 
1815
{
 
1816
        GwObexXfer *xfer;
 
1817
 
 
1818
        xfer = gw_obex_put_async(session->obex, session->name, NULL,
 
1819
                                                session->size, -1, NULL);
 
1820
        if (xfer == NULL)
 
1821
                return -ENOTCONN;
 
1822
 
 
1823
        session_ref(session);
 
1824
 
 
1825
        gw_obex_xfer_set_callback(xfer, put_buf_xfer_progress, session);
 
1826
 
 
1827
        session->xfer = xfer;
 
1828
 
 
1829
        agent_notify_progress(session->conn, session->agent_name,
 
1830
                session->agent_path, session->transfer_path, 0);
 
1831
 
 
1832
        return 0;
 
1833
}
 
1834
 
1698
1835
int session_put(struct session_data *session, char *buf, const char *targetname)
1699
1836
{
1700
 
        GwObexXfer *xfer;
1701
 
 
1702
1837
        if (session->obex == NULL)
1703
1838
                return -ENOTCONN;
1704
1839
 
1711
1846
        session->name = g_strdup(targetname);
1712
1847
        session->buffer = buf;
1713
1848
 
1714
 
        xfer = gw_obex_put_async(session->obex, session->name, NULL,
1715
 
                                                session->size, -1, NULL);
1716
 
        if (xfer == NULL)
1717
 
                return -ENOTCONN;
 
1849
        agent_request(session->conn, session, session_put_reply, NULL);
 
1850
 
 
1851
        return 0;
 
1852
}
 
1853
 
 
1854
int session_set_agent(struct session_data *session, const char *name,
 
1855
                                                        const char *path)
 
1856
{
 
1857
        if (session == NULL)
 
1858
                return -EINVAL;
 
1859
 
 
1860
        if (session->agent_name != NULL || session->agent_path != NULL)
 
1861
                return -EALREADY;
 
1862
 
 
1863
        session->agent_name = g_strdup(name);
 
1864
        session->agent_path = g_strdup(path);
 
1865
 
 
1866
        session->owner_watch = g_dbus_add_disconnect_watch(session->conn,
 
1867
                                        session->owner, owner_disconnected,
 
1868
                                                                session, NULL);
1718
1869
 
1719
1870
        session_ref(session);
1720
1871
 
1721
 
        gw_obex_xfer_set_callback(xfer, put_buf_xfer_progress, session);
1722
 
 
1723
 
        session->xfer = xfer;
1724
 
 
1725
 
        agent_request(session->conn, session->agent_name,
1726
 
                session->agent_path, session->transfer_path);
1727
 
 
1728
 
        agent_notify_progress(session->conn, session->agent_name,
1729
 
                session->agent_path, session->transfer_path, 0);
1730
 
 
1731
1872
        return 0;
1732
1873
}