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 * Licensed under the Academic Free License version 2.1
8 * This library is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU Lesser General Public License as published by
10 * the Free Software Foundation; either version 2.1 of the License, or
11 * (at your option) any later version.
13 * This library is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU Lesser General Public License for more details.
18 * You should have received a copy of the GNU Lesser General Public License
19 * along with this library; if not, write to the Free Software
20 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
24 #include "dbus_bindings-internal.h"
25 #include "conn-internal.h"
27 /* Connection definition ============================================ */
29 PyDoc_STRVAR(Connection_tp_doc
,
30 "A D-Bus connection.\n"
34 " Connection(address, mainloop=None) -> Connection\n"
37 /* D-Bus Connection user data slot, containing an owned reference to either
38 * the Connection, or a weakref to the Connection.
40 static dbus_int32_t _connection_python_slot
;
42 /* C API for main-loop hooks ======================================== */
44 /* Return a borrowed reference to the DBusConnection which underlies this
47 DBusPyConnection_BorrowDBusConnection(PyObject
*self
)
52 if (!DBusPyConnection_Check(self
)) {
53 PyErr_SetString(PyExc_TypeError
, "A dbus.Connection is required");
56 dbc
= ((Connection
*)self
)->conn
;
58 PyErr_SetString(PyExc_RuntimeError
, "Connection is in an invalid "
59 "state: no DBusConnection");
65 /* Internal C API =================================================== */
67 /* Pass a message through a handler. */
69 DBusPyConnection_HandleMessage(Connection
*conn
,
76 obj
= PyObject_CallFunctionObjArgs(callable
, conn
, msg
,
79 DBG("%p: OK, handler %p returned None", conn
, callable
);
81 return DBUS_HANDLER_RESULT_HANDLED
;
83 else if (obj
== Py_NotImplemented
) {
84 DBG("%p: handler %p returned NotImplemented, continuing",
87 return DBUS_HANDLER_RESULT_NOT_YET_HANDLED
;
90 if (PyErr_ExceptionMatches(PyExc_MemoryError
)) {
91 DBG_EXC("%p: handler %p caused OOM", conn
, callable
);
93 return DBUS_HANDLER_RESULT_NEED_MEMORY
;
95 DBG_EXC("%p: handler %p raised exception", conn
, callable
);
96 return DBUS_HANDLER_RESULT_NOT_YET_HANDLED
;
99 long i
= PyInt_AsLong(obj
);
100 DBG("%p: handler %p returned %ld", conn
, callable
, i
);
102 if (i
== -1 && PyErr_Occurred()) {
103 PyErr_SetString(PyExc_TypeError
, "Return from D-Bus message "
104 "handler callback should be None, "
105 "NotImplemented or integer");
106 return DBUS_HANDLER_RESULT_NOT_YET_HANDLED
;
108 else if (i
== DBUS_HANDLER_RESULT_HANDLED
||
109 i
== DBUS_HANDLER_RESULT_NOT_YET_HANDLED
||
110 i
== DBUS_HANDLER_RESULT_NEED_MEMORY
) {
114 PyErr_Format(PyExc_ValueError
, "Integer return from "
115 "D-Bus message handler callback should "
116 "be a DBUS_HANDLER_RESULT_... constant, "
118 return DBUS_HANDLER_RESULT_NOT_YET_HANDLED
;
123 /* On KeyError or if unregistration is in progress, return None. */
125 DBusPyConnection_GetObjectPathHandlers(PyObject
*self
, PyObject
*path
)
130 callbacks
= PyDict_GetItem(((Connection
*)self
)->object_paths
, path
);
132 if (PyErr_ExceptionMatches(PyExc_KeyError
)) {
137 Py_INCREF(callbacks
);
141 /* Return a new reference to a Python Connection or subclass corresponding
142 * to the DBusConnection conn. For use in callbacks.
144 * Raises AssertionError if the DBusConnection does not have a Connection.
147 DBusPyConnection_ExistingFromDBusConnection(DBusConnection
*conn
)
149 PyObject
*self
, *ref
;
151 Py_BEGIN_ALLOW_THREADS
152 ref
= (PyObject
*)dbus_connection_get_data(conn
,
153 _connection_python_slot
);
156 DBG("(DBusConnection *)%p has weak reference at %p", conn
, ref
);
157 self
= PyWeakref_GetObject(ref
); /* still a borrowed ref */
158 if (self
&& self
!= Py_None
&& DBusPyConnection_Check(self
)) {
159 DBG("(DBusConnection *)%p has weak reference at %p pointing to %p",
168 PyErr_SetString(PyExc_AssertionError
,
169 "D-Bus connection does not have a Connection "
170 "instance associated with it");
174 /* Return a new reference to a Python Connection or subclass (given by cls)
175 * corresponding to the DBusConnection conn, which must have been newly
176 * created. For use by the Connection and Bus constructors.
178 * Raises AssertionError if the DBusConnection already has a Connection.
181 DBusPyConnection_NewConsumingDBusConnection(PyTypeObject
*cls
,
182 DBusConnection
*conn
,
185 Connection
*self
= NULL
;
189 DBG("%s(cls=%p, conn=%p, mainloop=%p)", __func__
, cls
, conn
, mainloop
);
190 DBUS_PY_RAISE_VIA_NULL_IF_FAIL(conn
);
192 Py_BEGIN_ALLOW_THREADS
193 ref
= (PyObject
*)dbus_connection_get_data(conn
,
194 _connection_python_slot
);
197 self
= (Connection
*)PyWeakref_GetObject(ref
);
199 if (self
&& (PyObject
*)self
!= Py_None
) {
201 PyErr_SetString(PyExc_AssertionError
,
202 "Newly created D-Bus connection already has a "
203 "Connection instance associated with it");
204 DBG("%s() fail - assertion failed, DBusPyConn has a DBusConn already", __func__
);
211 /* Change mainloop from a borrowed reference to an owned reference */
212 if (!mainloop
|| mainloop
== Py_None
) {
213 mainloop
= dbus_py_get_default_main_loop();
221 DBG("Constructing Connection from DBusConnection at %p", conn
);
223 self
= (Connection
*)(cls
->tp_alloc(cls
, 0));
229 self
->has_mainloop
= (mainloop
!= Py_None
);
231 self
->filters
= PyList_New(0);
232 if (!self
->filters
) goto err
;
233 self
->object_paths
= PyDict_New();
234 if (!self
->object_paths
) goto err
;
236 ref
= PyWeakref_NewRef((PyObject
*)self
, NULL
);
238 DBG("Created weak ref %p to (Connection *)%p for (DBusConnection *)%p",
241 Py_BEGIN_ALLOW_THREADS
242 ok
= dbus_connection_set_data(conn
, _connection_python_slot
,
244 (DBusFreeFunction
)dbus_py_take_gil_and_xdecref
);
248 DBG("Attached weak ref %p ((Connection *)%p) to (DBusConnection *)%p",
250 ref
= NULL
; /* don't DECREF it - the DBusConnection owns it now */
253 DBG("Failed to attached weak ref %p ((Connection *)%p) to "
254 "(DBusConnection *)%p - will dispose of it", ref
, self
, conn
);
259 DBUS_PY_RAISE_VIA_GOTO_IF_FAIL(conn
, err
);
261 /* the DBusPyConnection will close it now */
264 if (self
->has_mainloop
265 && !dbus_py_set_up_connection((PyObject
*)self
, mainloop
)) {
271 DBG("%s() -> %p", __func__
, self
);
273 return (PyObject
*)self
;
276 DBG("Failed to construct Connection from DBusConnection at %p", conn
);
277 Py_XDECREF(mainloop
);
281 Py_BEGIN_ALLOW_THREADS
282 dbus_connection_close(conn
);
283 dbus_connection_unref(conn
);
286 DBG("%s() fail", __func__
);
291 /* Connection type-methods ========================================== */
293 /* "Constructor" (the real constructor is Connection_NewFromDBusConnection,
294 * to which this delegates). */
296 Connection_tp_new(PyTypeObject
*cls
, PyObject
*args
, PyObject
*kwargs
)
298 DBusConnection
*conn
;
301 PyObject
*self
, *mainloop
= NULL
;
302 static char *argnames
[] = {"address", "mainloop", NULL
};
304 if (!PyArg_ParseTupleAndKeywords(args
, kwargs
, "s|O", argnames
,
305 &address
, &mainloop
)) {
309 dbus_error_init(&error
);
311 /* We always open a private connection (at the libdbus level). Sharing
312 * is done in Python, to keep things simple. */
313 Py_BEGIN_ALLOW_THREADS
314 conn
= dbus_connection_open_private(address
, &error
);
318 DBusPyException_ConsumeError(&error
);
321 self
= DBusPyConnection_NewConsumingDBusConnection(cls
, conn
, mainloop
);
328 static void Connection_tp_dealloc(Connection
*self
)
330 DBusConnection
*conn
= self
->conn
;
331 PyObject
*et
, *ev
, *etb
;
332 PyObject
*filters
= self
->filters
;
333 PyObject
*object_paths
= self
->object_paths
;
335 /* avoid clobbering any pending exception */
336 PyErr_Fetch(&et
, &ev
, &etb
);
338 if (self
->weaklist
) {
339 PyObject_ClearWeakRefs((PyObject
*)self
);
343 DBG("Deallocating Connection at %p (DBusConnection at %p)", self
, conn
);
346 DBG("Connection at %p: deleting callbacks", self
);
347 self
->filters
= NULL
;
349 self
->object_paths
= NULL
;
350 Py_XDECREF(object_paths
);
353 /* Might trigger callbacks if we're unlucky... */
354 DBG("Connection at %p has a conn, closing it...", self
);
355 Py_BEGIN_ALLOW_THREADS
356 dbus_connection_close(conn
);
360 /* make sure to do this last to preserve the invariant that
361 * self->conn is always non-NULL for any referenced Connection
362 * (until the filters and object paths were freed, we might have been
363 * in a reference cycle!)
365 DBG("Connection at %p: nulling self->conn", self
);
369 DBG("Connection at %p: unreffing conn", self
);
370 dbus_connection_unref(conn
);
373 DBG("Connection at %p: freeing self", self
);
374 PyErr_Restore(et
, ev
, etb
);
375 (self
->ob_type
->tp_free
)((PyObject
*)self
);
378 /* Connection type object =========================================== */
380 PyTypeObject DBusPyConnection_Type
= {
381 PyObject_HEAD_INIT(NULL
)
383 "_dbus_bindings.Connection", /*tp_name*/
384 sizeof(Connection
), /*tp_basicsize*/
387 (destructor
)Connection_tp_dealloc
,
394 0, /*tp_as_sequence*/
402 Py_TPFLAGS_DEFAULT
| Py_TPFLAGS_HAVE_WEAKREFS
| Py_TPFLAGS_BASETYPE
,
403 Connection_tp_doc
, /*tp_doc*/
406 0, /*tp_richcompare*/
407 offsetof(Connection
, weaklist
), /*tp_weaklistoffset*/
410 DBusPyConnection_tp_methods
, /*tp_methods*/
420 Connection_tp_new
, /*tp_new*/
426 dbus_py_init_conn_types(void)
428 /* Get a slot to store our weakref on DBus Connections */
429 _connection_python_slot
= -1;
430 if (!dbus_connection_allocate_data_slot(&_connection_python_slot
))
432 if (PyType_Ready(&DBusPyConnection_Type
) < 0)
438 dbus_py_insert_conn_types(PyObject
*this_module
)
440 if (PyModule_AddObject(this_module
, "Connection",
441 (PyObject
*)&DBusPyConnection_Type
) < 0) return FALSE
;
445 /* vim:set ft=c cino< sw=4 sts=4 et: */