~jderose/ubuntu/precise/dbus-python/oneiric-backport

« back to all changes in this revision

Viewing changes to .pc/since-0.84.0.patch/_dbus_bindings/conn.c

  • Committer: Package Import Robot
  • Author(s): Barry Warsaw
  • Date: 2012-01-12 14:47:33 UTC
  • Revision ID: package-import@ubuntu.com-20120112144733-xtfbmgw30h0j40d2
Tags: 0.84.0-2ubuntu1
* debian/patches:
  - since-0.84.0.patch: Upstream unreleased changes from git tag
    dbus-python-0.84.0 to HEAD.  This is a precursor to the following.
  - python3-support.patch: Upstream unreleased changes from git
    `python3` branch for supporting Python 3. (LP: #893091)
* debian/rules: Enable the test suite.

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/* Implementation of the _dbus_bindings Connection type, a Python wrapper
 
2
 * for DBusConnection. See also conn-methods.c.
 
3
 *
 
4
 * Copyright (C) 2006-2008 Collabora Ltd. <http://www.collabora.co.uk/>
 
5
 *
 
6
 * Permission is hereby granted, free of charge, to any person
 
7
 * obtaining a copy of this software and associated documentation
 
8
 * files (the "Software"), to deal in the Software without
 
9
 * restriction, including without limitation the rights to use, copy,
 
10
 * modify, merge, publish, distribute, sublicense, and/or sell copies
 
11
 * of the Software, and to permit persons to whom the Software is
 
12
 * furnished to do so, subject to the following conditions:
 
13
 *
 
14
 * The above copyright notice and this permission notice shall be
 
15
 * included in all copies or substantial portions of the Software.
 
16
 *
 
17
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
 
18
 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
 
19
 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
 
20
 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
 
21
 * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
 
22
 * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 
23
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
 
24
 * DEALINGS IN THE SOFTWARE.
 
25
 */
 
26
 
 
27
#include "dbus_bindings-internal.h"
 
28
#include "conn-internal.h"
 
29
 
 
30
/* Connection definition ============================================ */
 
31
 
 
32
PyDoc_STRVAR(Connection_tp_doc,
 
33
"A D-Bus connection.\n"
 
34
"\n"
 
35
"::\n"
 
36
"\n"
 
37
"   Connection(address, mainloop=None) -> Connection\n"
 
38
);
 
39
 
 
40
/* D-Bus Connection user data slot, containing an owned reference to either
 
41
 * the Connection, or a weakref to the Connection.
 
42
 */
 
43
static dbus_int32_t _connection_python_slot;
 
44
 
 
45
/* C API for main-loop hooks ======================================== */
 
46
 
 
47
/* Return a borrowed reference to the DBusConnection which underlies this
 
48
 * Connection. */
 
49
DBusConnection *
 
50
DBusPyConnection_BorrowDBusConnection(PyObject *self)
 
51
{
 
52
    DBusConnection *dbc;
 
53
 
 
54
    TRACE(self);
 
55
    if (!DBusPyConnection_Check(self)) {
 
56
        PyErr_SetString(PyExc_TypeError, "A dbus.Connection is required");
 
57
        return NULL;
 
58
    }
 
59
    dbc = ((Connection *)self)->conn;
 
60
    if (!dbc) {
 
61
        PyErr_SetString(PyExc_RuntimeError, "Connection is in an invalid "
 
62
                        "state: no DBusConnection");
 
63
        return NULL;
 
64
    }
 
65
    return dbc;
 
66
}
 
67
 
 
68
/* Internal C API =================================================== */
 
69
 
 
70
/* Pass a message through a handler. */
 
71
DBusHandlerResult
 
72
DBusPyConnection_HandleMessage(Connection *conn,
 
73
                               PyObject *msg,
 
74
                               PyObject *callable)
 
75
{
 
76
    PyObject *obj;
 
77
 
 
78
    TRACE(conn);
 
79
    obj = PyObject_CallFunctionObjArgs(callable, conn, msg,
 
80
                                                 NULL);
 
81
    if (obj == Py_None) {
 
82
        DBG("%p: OK, handler %p returned None", conn, callable);
 
83
        Py_CLEAR(obj);
 
84
        return DBUS_HANDLER_RESULT_HANDLED;
 
85
    }
 
86
    else if (obj == Py_NotImplemented) {
 
87
        DBG("%p: handler %p returned NotImplemented, continuing",
 
88
            conn, callable);
 
89
        Py_CLEAR(obj);
 
90
        return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
 
91
    }
 
92
    else if (!obj) {
 
93
        if (PyErr_ExceptionMatches(PyExc_MemoryError)) {
 
94
            DBG_EXC("%p: handler %p caused OOM", conn, callable);
 
95
            PyErr_Clear();
 
96
            return DBUS_HANDLER_RESULT_NEED_MEMORY;
 
97
        }
 
98
        DBG_EXC("%p: handler %p raised exception", conn, callable);
 
99
        return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
 
100
    }
 
101
    else {
 
102
        long i = PyInt_AsLong(obj);
 
103
        DBG("%p: handler %p returned %ld", conn, callable, i);
 
104
        Py_CLEAR(obj);
 
105
        if (i == -1 && PyErr_Occurred()) {
 
106
            PyErr_SetString(PyExc_TypeError, "Return from D-Bus message "
 
107
                            "handler callback should be None, "
 
108
                            "NotImplemented or integer");
 
109
            return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
 
110
        }
 
111
        else if (i == DBUS_HANDLER_RESULT_HANDLED ||
 
112
            i == DBUS_HANDLER_RESULT_NOT_YET_HANDLED ||
 
113
            i == DBUS_HANDLER_RESULT_NEED_MEMORY) {
 
114
            return i;
 
115
        }
 
116
        else {
 
117
            PyErr_Format(PyExc_ValueError, "Integer return from "
 
118
                        "D-Bus message handler callback should "
 
119
                        "be a DBUS_HANDLER_RESULT_... constant, "
 
120
                        "not %d", (int)i);
 
121
            return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
 
122
        }
 
123
    }
 
124
}
 
125
 
 
126
/* On KeyError or if unregistration is in progress, return None. */
 
127
PyObject *
 
128
DBusPyConnection_GetObjectPathHandlers(PyObject *self, PyObject *path)
 
129
{
 
130
    PyObject *callbacks;
 
131
 
 
132
    TRACE(self);
 
133
    callbacks = PyDict_GetItem(((Connection *)self)->object_paths, path);
 
134
    if (!callbacks) {
 
135
        if (PyErr_ExceptionMatches(PyExc_KeyError)) {
 
136
            PyErr_Clear();
 
137
            Py_RETURN_NONE;
 
138
        }
 
139
    }
 
140
    Py_INCREF(callbacks);
 
141
    return callbacks;
 
142
}
 
143
 
 
144
/* Return a new reference to a Python Connection or subclass corresponding
 
145
 * to the DBusConnection conn. For use in callbacks.
 
146
 *
 
147
 * Raises AssertionError if the DBusConnection does not have a Connection.
 
148
 */
 
149
PyObject *
 
150
DBusPyConnection_ExistingFromDBusConnection(DBusConnection *conn)
 
151
{
 
152
    PyObject *self, *ref;
 
153
 
 
154
    Py_BEGIN_ALLOW_THREADS
 
155
    ref = (PyObject *)dbus_connection_get_data(conn,
 
156
                                               _connection_python_slot);
 
157
    Py_END_ALLOW_THREADS
 
158
    if (ref) {
 
159
        DBG("(DBusConnection *)%p has weak reference at %p", conn, ref);
 
160
        self = PyWeakref_GetObject(ref);   /* still a borrowed ref */
 
161
        if (self && self != Py_None && DBusPyConnection_Check(self)) {
 
162
            DBG("(DBusConnection *)%p has weak reference at %p pointing to %p",
 
163
                conn, ref, self);
 
164
            TRACE(self);
 
165
            Py_INCREF(self);
 
166
            TRACE(self);
 
167
            return self;
 
168
        }
 
169
    }
 
170
 
 
171
    PyErr_SetString(PyExc_AssertionError,
 
172
                    "D-Bus connection does not have a Connection "
 
173
                    "instance associated with it");
 
174
    return NULL;
 
175
}
 
176
 
 
177
/* Return a new reference to a Python Connection or subclass (given by cls)
 
178
 * corresponding to the DBusConnection conn, which must have been newly
 
179
 * created. For use by the Connection and Bus constructors.
 
180
 *
 
181
 * Raises AssertionError if the DBusConnection already has a Connection.
 
182
 */
 
183
static PyObject *
 
184
DBusPyConnection_NewConsumingDBusConnection(PyTypeObject *cls,
 
185
                                            DBusConnection *conn,
 
186
                                            PyObject *mainloop)
 
187
{
 
188
    Connection *self = NULL;
 
189
    PyObject *ref;
 
190
    dbus_bool_t ok;
 
191
 
 
192
    DBG("%s(cls=%p, conn=%p, mainloop=%p)", __func__, cls, conn, mainloop);
 
193
    DBUS_PY_RAISE_VIA_NULL_IF_FAIL(conn);
 
194
 
 
195
    Py_BEGIN_ALLOW_THREADS
 
196
    ref = (PyObject *)dbus_connection_get_data(conn,
 
197
                                               _connection_python_slot);
 
198
    Py_END_ALLOW_THREADS
 
199
    if (ref) {
 
200
        self = (Connection *)PyWeakref_GetObject(ref);
 
201
        ref = NULL;
 
202
        if (self && (PyObject *)self != Py_None) {
 
203
            self = NULL;
 
204
            PyErr_SetString(PyExc_AssertionError,
 
205
                            "Newly created D-Bus connection already has a "
 
206
                            "Connection instance associated with it");
 
207
            DBG("%s() fail - assertion failed, DBusPyConn has a DBusConn already", __func__);
 
208
            DBG_WHEREAMI;
 
209
            return NULL;
 
210
        }
 
211
    }
 
212
    ref = NULL;
 
213
 
 
214
    /* Change mainloop from a borrowed reference to an owned reference */
 
215
    if (!mainloop || mainloop == Py_None) {
 
216
        mainloop = dbus_py_get_default_main_loop();
 
217
        if (!mainloop)
 
218
            goto err;
 
219
    }
 
220
    else {
 
221
        Py_INCREF(mainloop);
 
222
    }
 
223
 
 
224
    DBG("Constructing Connection from DBusConnection at %p", conn);
 
225
 
 
226
    self = (Connection *)(cls->tp_alloc(cls, 0));
 
227
    if (!self) goto err;
 
228
    TRACE(self);
 
229
 
 
230
    DBG_WHEREAMI;
 
231
 
 
232
    self->has_mainloop = (mainloop != Py_None);
 
233
    self->conn = NULL;
 
234
    self->filters = PyList_New(0);
 
235
    if (!self->filters) goto err;
 
236
    self->object_paths = PyDict_New();
 
237
    if (!self->object_paths) goto err;
 
238
 
 
239
    ref = PyWeakref_NewRef((PyObject *)self, NULL);
 
240
    if (!ref) goto err;
 
241
    DBG("Created weak ref %p to (Connection *)%p for (DBusConnection *)%p",
 
242
        ref, self, conn);
 
243
 
 
244
    Py_BEGIN_ALLOW_THREADS
 
245
    ok = dbus_connection_set_data(conn, _connection_python_slot,
 
246
                                  (void *)ref,
 
247
                                  (DBusFreeFunction)dbus_py_take_gil_and_xdecref);
 
248
    Py_END_ALLOW_THREADS
 
249
 
 
250
    if (ok) {
 
251
        DBG("Attached weak ref %p ((Connection *)%p) to (DBusConnection *)%p",
 
252
            ref, self, conn);
 
253
        ref = NULL;     /* don't DECREF it - the DBusConnection owns it now */
 
254
    }
 
255
    else {
 
256
        DBG("Failed to attached weak ref %p ((Connection *)%p) to "
 
257
            "(DBusConnection *)%p - will dispose of it", ref, self, conn);
 
258
        PyErr_NoMemory();
 
259
        goto err;
 
260
    }
 
261
 
 
262
    DBUS_PY_RAISE_VIA_GOTO_IF_FAIL(conn, err);
 
263
    self->conn = conn;
 
264
    /* the DBusPyConnection will close it now */
 
265
    conn = NULL;
 
266
 
 
267
    if (self->has_mainloop
 
268
        && !dbus_py_set_up_connection((PyObject *)self, mainloop)) {
 
269
        goto err;
 
270
    }
 
271
 
 
272
    Py_CLEAR(mainloop);
 
273
 
 
274
    DBG("%s() -> %p", __func__, self);
 
275
    TRACE(self);
 
276
    return (PyObject *)self;
 
277
 
 
278
err:
 
279
    DBG("Failed to construct Connection from DBusConnection at %p", conn);
 
280
    Py_CLEAR(mainloop);
 
281
    Py_CLEAR(self);
 
282
    Py_CLEAR(ref);
 
283
    if (conn) {
 
284
        Py_BEGIN_ALLOW_THREADS
 
285
        dbus_connection_close(conn);
 
286
        dbus_connection_unref(conn);
 
287
        Py_END_ALLOW_THREADS
 
288
    }
 
289
    DBG("%s() fail", __func__);
 
290
    DBG_WHEREAMI;
 
291
    return NULL;
 
292
}
 
293
 
 
294
/* Connection type-methods ========================================== */
 
295
 
 
296
/* Constructor */
 
297
static PyObject *
 
298
Connection_tp_new(PyTypeObject *cls, PyObject *args, PyObject *kwargs)
 
299
{
 
300
    DBusConnection *conn;
 
301
    const char *address;
 
302
    PyObject *address_or_conn;
 
303
    DBusError error;
 
304
    PyObject *self, *mainloop = NULL;
 
305
    static char *argnames[] = {"address", "mainloop", NULL};
 
306
 
 
307
    if (!PyArg_ParseTupleAndKeywords(args, kwargs, "O|O", argnames,
 
308
                                     &address_or_conn, &mainloop)) {
 
309
        return NULL;
 
310
    }
 
311
 
 
312
    if (DBusPyLibDBusConnection_CheckExact(address_or_conn)) {
 
313
        DBusPyLibDBusConnection *wrapper =
 
314
            (DBusPyLibDBusConnection *) address_or_conn;
 
315
 
 
316
        DBUS_PY_RAISE_VIA_NULL_IF_FAIL(wrapper->conn);
 
317
 
 
318
        conn = dbus_connection_ref (wrapper->conn);
 
319
    }
 
320
    else if ((address = PyString_AsString(address_or_conn)) != NULL) {
 
321
        dbus_error_init(&error);
 
322
 
 
323
        /* We always open a private connection (at the libdbus level). Sharing
 
324
         * is done in Python, to keep things simple. */
 
325
        Py_BEGIN_ALLOW_THREADS
 
326
        conn = dbus_connection_open_private(address, &error);
 
327
        Py_END_ALLOW_THREADS
 
328
 
 
329
        if (!conn) {
 
330
            DBusPyException_ConsumeError(&error);
 
331
            return NULL;
 
332
        }
 
333
    }
 
334
    else {
 
335
        return NULL;
 
336
    }
 
337
 
 
338
    self = DBusPyConnection_NewConsumingDBusConnection(cls, conn, mainloop);
 
339
    TRACE(self);
 
340
 
 
341
    return self;
 
342
}
 
343
 
 
344
/* Post-construction: nothing to do (but don't chain up to object.__init__,
 
345
 * which takes no arguments and does nothing) */
 
346
static int
 
347
Connection_tp_init(PyObject *self UNUSED, PyObject *args UNUSED,
 
348
        PyObject *kwargs UNUSED)
 
349
{
 
350
    return 0;
 
351
}
 
352
 
 
353
/* Destructor */
 
354
static void Connection_tp_dealloc(Connection *self)
 
355
{
 
356
    DBusConnection *conn = self->conn;
 
357
    PyObject *et, *ev, *etb;
 
358
    PyObject *filters = self->filters;
 
359
    PyObject *object_paths = self->object_paths;
 
360
 
 
361
    /* avoid clobbering any pending exception */
 
362
    PyErr_Fetch(&et, &ev, &etb);
 
363
 
 
364
    if (self->weaklist) {
 
365
        PyObject_ClearWeakRefs((PyObject *)self);
 
366
    }
 
367
 
 
368
    TRACE(self);
 
369
    DBG("Deallocating Connection at %p (DBusConnection at %p)", self, conn);
 
370
    DBG_WHEREAMI;
 
371
 
 
372
    DBG("Connection at %p: deleting callbacks", self);
 
373
    self->filters = NULL;
 
374
    Py_CLEAR(filters);
 
375
    self->object_paths = NULL;
 
376
    Py_CLEAR(object_paths);
 
377
 
 
378
    if (conn) {
 
379
        /* Might trigger callbacks if we're unlucky... */
 
380
        DBG("Connection at %p has a conn, closing it...", self);
 
381
        Py_BEGIN_ALLOW_THREADS
 
382
        dbus_connection_close(conn);
 
383
        Py_END_ALLOW_THREADS
 
384
    }
 
385
 
 
386
    /* make sure to do this last to preserve the invariant that
 
387
     * self->conn is always non-NULL for any referenced Connection
 
388
     * (until the filters and object paths were freed, we might have been
 
389
     * in a reference cycle!)
 
390
     */
 
391
    DBG("Connection at %p: nulling self->conn", self);
 
392
    self->conn = NULL;
 
393
 
 
394
    if (conn) {
 
395
        DBG("Connection at %p: unreffing conn", self);
 
396
        dbus_connection_unref(conn);
 
397
    }
 
398
 
 
399
    DBG("Connection at %p: freeing self", self);
 
400
    PyErr_Restore(et, ev, etb);
 
401
    (self->ob_type->tp_free)((PyObject *)self);
 
402
}
 
403
 
 
404
/* Connection type object =========================================== */
 
405
 
 
406
PyTypeObject DBusPyConnection_Type = {
 
407
    PyObject_HEAD_INIT(NULL)
 
408
    0,                      /*ob_size*/
 
409
    "_dbus_bindings.Connection", /*tp_name*/
 
410
    sizeof(Connection),     /*tp_basicsize*/
 
411
    0,                      /*tp_itemsize*/
 
412
    /* methods */
 
413
    (destructor)Connection_tp_dealloc,
 
414
    0,                      /*tp_print*/
 
415
    0,                      /*tp_getattr*/
 
416
    0,                      /*tp_setattr*/
 
417
    0,                      /*tp_compare*/
 
418
    0,                      /*tp_repr*/
 
419
    0,                      /*tp_as_number*/
 
420
    0,                      /*tp_as_sequence*/
 
421
    0,                      /*tp_as_mapping*/
 
422
    0,                      /*tp_hash*/
 
423
    0,                      /*tp_call*/
 
424
    0,                      /*tp_str*/
 
425
    0,                      /*tp_getattro*/
 
426
    0,                      /*tp_setattro*/
 
427
    0,                      /*tp_as_buffer*/
 
428
    Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_WEAKREFS | Py_TPFLAGS_BASETYPE,
 
429
    Connection_tp_doc,      /*tp_doc*/
 
430
    0,                      /*tp_traverse*/
 
431
    0,                      /*tp_clear*/
 
432
    0,                      /*tp_richcompare*/
 
433
    offsetof(Connection, weaklist),   /*tp_weaklistoffset*/
 
434
    0,                      /*tp_iter*/
 
435
    0,                      /*tp_iternext*/
 
436
    DBusPyConnection_tp_methods,  /*tp_methods*/
 
437
    0,                      /*tp_members*/
 
438
    0,                      /*tp_getset*/
 
439
    0,                      /*tp_base*/
 
440
    0,                      /*tp_dict*/
 
441
    0,                      /*tp_descr_get*/
 
442
    0,                      /*tp_descr_set*/
 
443
    0,                      /*tp_dictoffset*/
 
444
    Connection_tp_init,     /*tp_init*/
 
445
    0,                      /*tp_alloc*/
 
446
    Connection_tp_new,      /*tp_new*/
 
447
    0,                      /*tp_free*/
 
448
    0,                      /*tp_is_gc*/
 
449
};
 
450
 
 
451
dbus_bool_t
 
452
dbus_py_init_conn_types(void)
 
453
{
 
454
    /* Get a slot to store our weakref on DBus Connections */
 
455
    _connection_python_slot = -1;
 
456
    if (!dbus_connection_allocate_data_slot(&_connection_python_slot))
 
457
        return FALSE;
 
458
    if (PyType_Ready(&DBusPyConnection_Type) < 0)
 
459
        return FALSE;
 
460
    return TRUE;
 
461
}
 
462
 
 
463
dbus_bool_t
 
464
dbus_py_insert_conn_types(PyObject *this_module)
 
465
{
 
466
    /* PyModule_AddObject steals a ref */
 
467
    Py_INCREF (&DBusPyConnection_Type);
 
468
    if (PyModule_AddObject(this_module, "Connection",
 
469
                           (PyObject *)&DBusPyConnection_Type) < 0) return FALSE;
 
470
    return TRUE;
 
471
}
 
472
 
 
473
/* vim:set ft=c cino< sw=4 sts=4 et: */