1 /* Implementation of the _dbus_bindings Connection type, a Python wrapper
2 * for DBusConnection. See also conn-methods.c.
4 * Copyright (C) 2006 Collabora Ltd. <http://www.collabora.co.uk/>
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:
14 * The above copyright notice and this permission notice shall be
15 * included in all copies or substantial portions of the Software.
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.
27 #include "dbus_bindings-internal.h"
28 #include "conn-internal.h"
30 /* Connection definition ============================================ */
32 PyDoc_STRVAR(Connection_tp_doc
,
33 "A D-Bus connection.\n"
37 " Connection(address, mainloop=None) -> Connection\n"
40 /* D-Bus Connection user data slot, containing an owned reference to either
41 * the Connection, or a weakref to the Connection.
43 static dbus_int32_t _connection_python_slot
;
45 /* C API for main-loop hooks ======================================== */
47 /* Return a borrowed reference to the DBusConnection which underlies this
50 DBusPyConnection_BorrowDBusConnection(PyObject
*self
)
55 if (!DBusPyConnection_Check(self
)) {
56 PyErr_SetString(PyExc_TypeError
, "A dbus.Connection is required");
59 dbc
= ((Connection
*)self
)->conn
;
61 PyErr_SetString(PyExc_RuntimeError
, "Connection is in an invalid "
62 "state: no DBusConnection");
68 /* Internal C API =================================================== */
70 /* Pass a message through a handler. */
72 DBusPyConnection_HandleMessage(Connection
*conn
,
79 obj
= PyObject_CallFunctionObjArgs(callable
, conn
, msg
,
82 DBG("%p: OK, handler %p returned None", conn
, callable
);
84 return DBUS_HANDLER_RESULT_HANDLED
;
86 else if (obj
== Py_NotImplemented
) {
87 DBG("%p: handler %p returned NotImplemented, continuing",
90 return DBUS_HANDLER_RESULT_NOT_YET_HANDLED
;
93 if (PyErr_ExceptionMatches(PyExc_MemoryError
)) {
94 DBG_EXC("%p: handler %p caused OOM", conn
, callable
);
96 return DBUS_HANDLER_RESULT_NEED_MEMORY
;
98 DBG_EXC("%p: handler %p raised exception", conn
, callable
);
99 return DBUS_HANDLER_RESULT_NOT_YET_HANDLED
;
102 long i
= PyInt_AsLong(obj
);
103 DBG("%p: handler %p returned %ld", conn
, callable
, i
);
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
;
111 else if (i
== DBUS_HANDLER_RESULT_HANDLED
||
112 i
== DBUS_HANDLER_RESULT_NOT_YET_HANDLED
||
113 i
== DBUS_HANDLER_RESULT_NEED_MEMORY
) {
117 PyErr_Format(PyExc_ValueError
, "Integer return from "
118 "D-Bus message handler callback should "
119 "be a DBUS_HANDLER_RESULT_... constant, "
121 return DBUS_HANDLER_RESULT_NOT_YET_HANDLED
;
126 /* On KeyError or if unregistration is in progress, return None. */
128 DBusPyConnection_GetObjectPathHandlers(PyObject
*self
, PyObject
*path
)
133 callbacks
= PyDict_GetItem(((Connection
*)self
)->object_paths
, path
);
135 if (PyErr_ExceptionMatches(PyExc_KeyError
)) {
140 Py_INCREF(callbacks
);
144 /* Return a new reference to a Python Connection or subclass corresponding
145 * to the DBusConnection conn. For use in callbacks.
147 * Raises AssertionError if the DBusConnection does not have a Connection.
150 DBusPyConnection_ExistingFromDBusConnection(DBusConnection
*conn
)
152 PyObject
*self
, *ref
;
154 Py_BEGIN_ALLOW_THREADS
155 ref
= (PyObject
*)dbus_connection_get_data(conn
,
156 _connection_python_slot
);
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",
171 PyErr_SetString(PyExc_AssertionError
,
172 "D-Bus connection does not have a Connection "
173 "instance associated with it");
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.
181 * Raises AssertionError if the DBusConnection already has a Connection.
184 DBusPyConnection_NewConsumingDBusConnection(PyTypeObject
*cls
,
185 DBusConnection
*conn
,
188 Connection
*self
= NULL
;
192 DBG("%s(cls=%p, conn=%p, mainloop=%p)", __func__
, cls
, conn
, mainloop
);
193 DBUS_PY_RAISE_VIA_NULL_IF_FAIL(conn
);
195 Py_BEGIN_ALLOW_THREADS
196 ref
= (PyObject
*)dbus_connection_get_data(conn
,
197 _connection_python_slot
);
200 self
= (Connection
*)PyWeakref_GetObject(ref
);
202 if (self
&& (PyObject
*)self
!= Py_None
) {
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__
);
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();
224 DBG("Constructing Connection from DBusConnection at %p", conn
);
226 self
= (Connection
*)(cls
->tp_alloc(cls
, 0));
232 self
->has_mainloop
= (mainloop
!= Py_None
);
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
;
239 ref
= PyWeakref_NewRef((PyObject
*)self
, NULL
);
241 DBG("Created weak ref %p to (Connection *)%p for (DBusConnection *)%p",
244 Py_BEGIN_ALLOW_THREADS
245 ok
= dbus_connection_set_data(conn
, _connection_python_slot
,
247 (DBusFreeFunction
)dbus_py_take_gil_and_xdecref
);
251 DBG("Attached weak ref %p ((Connection *)%p) to (DBusConnection *)%p",
253 ref
= NULL
; /* don't DECREF it - the DBusConnection owns it now */
256 DBG("Failed to attached weak ref %p ((Connection *)%p) to "
257 "(DBusConnection *)%p - will dispose of it", ref
, self
, conn
);
262 DBUS_PY_RAISE_VIA_GOTO_IF_FAIL(conn
, err
);
264 /* the DBusPyConnection will close it now */
267 if (self
->has_mainloop
268 && !dbus_py_set_up_connection((PyObject
*)self
, mainloop
)) {
274 DBG("%s() -> %p", __func__
, self
);
276 return (PyObject
*)self
;
279 DBG("Failed to construct Connection from DBusConnection at %p", conn
);
280 Py_XDECREF(mainloop
);
284 Py_BEGIN_ALLOW_THREADS
285 dbus_connection_close(conn
);
286 dbus_connection_unref(conn
);
289 DBG("%s() fail", __func__
);
294 /* Connection type-methods ========================================== */
296 /* "Constructor" (the real constructor is Connection_NewFromDBusConnection,
297 * to which this delegates). */
299 Connection_tp_new(PyTypeObject
*cls
, PyObject
*args
, PyObject
*kwargs
)
301 DBusConnection
*conn
;
304 PyObject
*self
, *mainloop
= NULL
;
305 static char *argnames
[] = {"address", "mainloop", NULL
};
307 if (!PyArg_ParseTupleAndKeywords(args
, kwargs
, "s|O", argnames
,
308 &address
, &mainloop
)) {
312 dbus_error_init(&error
);
314 /* We always open a private connection (at the libdbus level). Sharing
315 * is done in Python, to keep things simple. */
316 Py_BEGIN_ALLOW_THREADS
317 conn
= dbus_connection_open_private(address
, &error
);
321 DBusPyException_ConsumeError(&error
);
324 self
= DBusPyConnection_NewConsumingDBusConnection(cls
, conn
, mainloop
);
331 static void Connection_tp_dealloc(Connection
*self
)
333 DBusConnection
*conn
= self
->conn
;
334 PyObject
*et
, *ev
, *etb
;
335 PyObject
*filters
= self
->filters
;
336 PyObject
*object_paths
= self
->object_paths
;
338 /* avoid clobbering any pending exception */
339 PyErr_Fetch(&et
, &ev
, &etb
);
341 if (self
->weaklist
) {
342 PyObject_ClearWeakRefs((PyObject
*)self
);
346 DBG("Deallocating Connection at %p (DBusConnection at %p)", self
, conn
);
349 DBG("Connection at %p: deleting callbacks", self
);
350 self
->filters
= NULL
;
352 self
->object_paths
= NULL
;
353 Py_XDECREF(object_paths
);
356 /* Might trigger callbacks if we're unlucky... */
357 DBG("Connection at %p has a conn, closing it...", self
);
358 Py_BEGIN_ALLOW_THREADS
359 dbus_connection_close(conn
);
363 /* make sure to do this last to preserve the invariant that
364 * self->conn is always non-NULL for any referenced Connection
365 * (until the filters and object paths were freed, we might have been
366 * in a reference cycle!)
368 DBG("Connection at %p: nulling self->conn", self
);
372 DBG("Connection at %p: unreffing conn", self
);
373 dbus_connection_unref(conn
);
376 DBG("Connection at %p: freeing self", self
);
377 PyErr_Restore(et
, ev
, etb
);
378 (self
->ob_type
->tp_free
)((PyObject
*)self
);
381 /* Connection type object =========================================== */
383 PyTypeObject DBusPyConnection_Type
= {
384 PyObject_HEAD_INIT(NULL
)
386 "_dbus_bindings.Connection", /*tp_name*/
387 sizeof(Connection
), /*tp_basicsize*/
390 (destructor
)Connection_tp_dealloc
,
397 0, /*tp_as_sequence*/
405 Py_TPFLAGS_DEFAULT
| Py_TPFLAGS_HAVE_WEAKREFS
| Py_TPFLAGS_BASETYPE
,
406 Connection_tp_doc
, /*tp_doc*/
409 0, /*tp_richcompare*/
410 offsetof(Connection
, weaklist
), /*tp_weaklistoffset*/
413 DBusPyConnection_tp_methods
, /*tp_methods*/
423 Connection_tp_new
, /*tp_new*/
429 dbus_py_init_conn_types(void)
431 /* Get a slot to store our weakref on DBus Connections */
432 _connection_python_slot
= -1;
433 if (!dbus_connection_allocate_data_slot(&_connection_python_slot
))
435 if (PyType_Ready(&DBusPyConnection_Type
) < 0)
441 dbus_py_insert_conn_types(PyObject
*this_module
)
443 if (PyModule_AddObject(this_module
, "Connection",
444 (PyObject
*)&DBusPyConnection_Type
) < 0) return FALSE
;
448 /* vim:set ft=c cino< sw=4 sts=4 et: */