1 /* Implementation of the _dbus_bindings Connection type, a Python wrapper
2 * for DBusConnection. See also conn-methods-impl.h.
4 * Copyright (C) 2006 Collabora Ltd. <http://www.collabora.co.uk/>
6 * Licensed under the Academic Free License version 2.1
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License as published by
10 * This program is free software; you can redistribute it and/or modify
11 * it under the terms of the GNU General Public License as published by
12 * the Free Software Foundation; either version 2 of the License, or
13 * (at your option) any later version.
15 * This program is distributed in the hope that it will be useful,
16 * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 * GNU General Public License for more details.
20 * You should have received a copy of the GNU General Public License
21 * along with this program; if not, write to the Free Software
22 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
26 #include "dbus_bindings-internal.h"
27 #include "conn-internal.h"
29 /* Connection definition ============================================ */
31 PyDoc_STRVAR(Connection_tp_doc
,
32 "A D-Bus connection.\n\n"
33 "Connection(address: str, mainloop=None) -> Connection\n"
36 /* D-Bus Connection user data slot, containing an owned reference to either
37 * the Connection, or a weakref to the Connection.
39 static dbus_int32_t _connection_python_slot
;
41 /* C API for main-loop hooks ======================================== */
43 /* Return a borrowed reference to the DBusConnection which underlies this
46 DBusPyConnection_BorrowDBusConnection(PyObject
*self
)
50 if (!DBusPyConnection_Check(self
)) {
51 PyErr_SetString(PyExc_TypeError
, "A dbus.Connection is required");
54 dbc
= ((Connection
*)self
)->conn
;
56 PyErr_SetString(PyExc_RuntimeError
, "Connection is in an invalid "
57 "state: no DBusConnection");
63 /* Internal C API =================================================== */
65 /* Pass a message through a handler. */
67 DBusPyConnection_HandleMessage(Connection
*conn
,
71 PyObject
*obj
= PyObject_CallFunctionObjArgs(callable
, conn
, msg
,
74 DBG("%p: OK, handler %p returned None", conn
, callable
);
76 return DBUS_HANDLER_RESULT_HANDLED
;
78 else if (obj
== Py_NotImplemented
) {
79 DBG("%p: handler %p returned NotImplemented, continuing",
82 return DBUS_HANDLER_RESULT_NOT_YET_HANDLED
;
85 if (PyErr_ExceptionMatches(PyExc_MemoryError
)) {
86 DBG_EXC("%p: handler %p caused OOM", conn
, callable
);
88 return DBUS_HANDLER_RESULT_NEED_MEMORY
;
90 DBG_EXC("%p: handler %p raised exception", conn
, callable
);
91 return DBUS_HANDLER_RESULT_NOT_YET_HANDLED
;
94 long i
= PyInt_AsLong(obj
);
95 DBG("%p: handler %p returned %ld", conn
, callable
, i
);
97 if (i
== -1 && PyErr_Occurred()) {
98 PyErr_SetString(PyExc_TypeError
, "Return from D-Bus message "
99 "handler callback should be None, "
100 "NotImplemented or integer");
101 return DBUS_HANDLER_RESULT_NOT_YET_HANDLED
;
103 else if (i
== DBUS_HANDLER_RESULT_HANDLED
||
104 i
== DBUS_HANDLER_RESULT_NOT_YET_HANDLED
||
105 i
== DBUS_HANDLER_RESULT_NEED_MEMORY
) {
109 PyErr_Format(PyExc_ValueError
, "Integer return from "
110 "D-Bus message handler callback should "
111 "be a DBUS_HANDLER_RESULT_... constant, "
113 return DBUS_HANDLER_RESULT_NOT_YET_HANDLED
;
118 /* On KeyError or if unregistration is in progress, return None. */
120 DBusPyConnection_GetObjectPathHandlers(PyObject
*self
, PyObject
*path
)
122 PyObject
*callbacks
= PyDict_GetItem(((Connection
*)self
)->object_paths
,
125 if (PyErr_ExceptionMatches(PyExc_KeyError
)) {
130 Py_INCREF(callbacks
);
134 /* Return a new reference to a Python Connection or subclass corresponding
135 * to the DBusConnection conn. For use in callbacks.
137 * Raises AssertionError if the DBusConnection does not have a Connection.
140 DBusPyConnection_ExistingFromDBusConnection(DBusConnection
*conn
)
142 PyObject
*self
, *ref
;
144 Py_BEGIN_ALLOW_THREADS
145 ref
= (PyObject
*)dbus_connection_get_data(conn
,
146 _connection_python_slot
);
149 self
= PyWeakref_GetObject(ref
); /* still a borrowed ref */
150 if (self
&& self
!= Py_None
&& DBusPyConnection_Check(self
)) {
156 PyErr_SetString(PyExc_AssertionError
,
157 "D-Bus connection does not have a Connection "
158 "instance associated with it");
162 /* Return a new reference to a Python Connection or subclass (given by cls)
163 * corresponding to the DBusConnection conn, which must have been newly
164 * created. For use by the Connection and Bus constructors.
166 * Raises AssertionError if the DBusConnection already has a Connection.
169 DBusPyConnection_NewConsumingDBusConnection(PyTypeObject
*cls
,
170 DBusConnection
*conn
,
173 Connection
*self
= NULL
;
177 DBG("%s(cls=%p, conn=%p, mainloop=%p)", __func__
, cls
, conn
, mainloop
);
178 DBUS_PY_RAISE_VIA_NULL_IF_FAIL(conn
);
180 Py_BEGIN_ALLOW_THREADS
181 ref
= (PyObject
*)dbus_connection_get_data(conn
,
182 _connection_python_slot
);
185 self
= (Connection
*)PyWeakref_GetObject(ref
);
187 if (self
&& (PyObject
*)self
!= Py_None
) {
189 PyErr_SetString(PyExc_AssertionError
,
190 "Newly created D-Bus connection already has a "
191 "Connection instance associated with it");
192 DBG("%s() fail - assertion failed, DBusPyConn has a DBusConn already", __func__
);
199 if (!mainloop
|| mainloop
== Py_None
) {
200 mainloop
= dbus_py_get_default_main_loop();
201 if (!mainloop
|| mainloop
== Py_None
) {
202 PyErr_SetString(PyExc_ValueError
,
203 "D-Bus connections must be attached to a main "
204 "loop by passing mainloop=... to the constructor "
205 "or calling dbus.Bus.set_default_main_loop(...)");
213 DBG("Constructing Connection from DBusConnection at %p", conn
);
215 self
= (Connection
*)(cls
->tp_alloc(cls
, 0));
221 self
->filters
= PyList_New(0);
222 if (!self
->filters
) goto err
;
223 self
->object_paths
= PyDict_New();
224 if (!self
->object_paths
) goto err
;
226 ref
= PyWeakref_NewRef((PyObject
*)self
, NULL
);
229 Py_BEGIN_ALLOW_THREADS
230 ok
= dbus_connection_set_data(conn
, _connection_python_slot
,
232 (DBusFreeFunction
)dbus_py_take_gil_and_xdecref
);
240 DBUS_PY_RAISE_VIA_GOTO_IF_FAIL(conn
, err
);
243 if (!dbus_py_set_up_connection((PyObject
*)self
, mainloop
)) {
249 DBG("%s() -> %p", __func__
, self
);
250 return (PyObject
*)self
;
253 DBG("Failed to construct Connection from DBusConnection at %p", conn
);
254 Py_XDECREF(mainloop
);
258 Py_BEGIN_ALLOW_THREADS
259 dbus_connection_close(conn
);
260 dbus_connection_unref(conn
);
263 DBG("%s() fail", __func__
);
268 /* Connection type-methods ========================================== */
270 /* "Constructor" (the real constructor is Connection_NewFromDBusConnection,
271 * to which this delegates). */
273 Connection_tp_new(PyTypeObject
*cls
, PyObject
*args
, PyObject
*kwargs
)
275 DBusConnection
*conn
;
278 PyObject
*self
, *mainloop
= NULL
;
279 static char *argnames
[] = {"address", "mainloop", NULL
};
281 if (!PyArg_ParseTupleAndKeywords(args
, kwargs
, "s|O", argnames
,
282 &address
, &mainloop
)) {
286 dbus_error_init(&error
);
288 /* We always open a private connection (at the libdbus level). Sharing
289 * is done in Python, to keep things simple. */
290 Py_BEGIN_ALLOW_THREADS
291 conn
= dbus_connection_open_private(address
, &error
);
295 DBusPyException_ConsumeError(&error
);
298 self
= DBusPyConnection_NewConsumingDBusConnection(cls
, conn
, mainloop
);
304 static void Connection_tp_dealloc(Connection
*self
)
306 DBusConnection
*conn
= self
->conn
;
307 PyObject
*filters
= self
->filters
;
308 PyObject
*object_paths
= self
->object_paths
;
310 DBG("Deallocating Connection at %p (DBusConnection at %p)", self
, conn
);
314 /* Might trigger callbacks if we're unlucky... */
315 DBG("Connection at %p has a conn, closing it...", self
);
316 Py_BEGIN_ALLOW_THREADS
317 dbus_connection_close(conn
);
321 DBG("Connection at %p: deleting callbacks", self
);
322 self
->filters
= NULL
;
324 self
->object_paths
= NULL
;
325 Py_XDECREF(object_paths
);
327 /* make sure to do this last to preserve the invariant that
328 * self->conn is always non-NULL for any referenced Connection
329 * (until the filters and object paths were freed, we might have been
330 * in a reference cycle!)
332 DBG("Connection at %p: nulling self->conn", self
);
335 DBG("Connection at %p: unreffing conn", self
);
336 dbus_connection_unref(conn
);
338 DBG("Connection at %p: freeing self", self
);
339 (self
->ob_type
->tp_free
)((PyObject
*)self
);
342 /* Connection type object =========================================== */
344 PyTypeObject DBusPyConnection_Type
= {
345 PyObject_HEAD_INIT(NULL
)
347 "_dbus_bindings.Connection", /*tp_name*/
348 sizeof(Connection
), /*tp_basicsize*/
351 (destructor
)Connection_tp_dealloc
,
358 0, /*tp_as_sequence*/
366 Py_TPFLAGS_DEFAULT
| Py_TPFLAGS_HAVE_WEAKREFS
| Py_TPFLAGS_BASETYPE
,
367 Connection_tp_doc
, /*tp_doc*/
370 0, /*tp_richcompare*/
371 offsetof(Connection
, weaklist
), /*tp_weaklistoffset*/
374 DBusPyConnection_tp_methods
, /*tp_methods*/
384 Connection_tp_new
, /*tp_new*/
390 dbus_py_init_conn_types(void)
392 /* Get a slot to store our weakref on DBus Connections */
393 _connection_python_slot
= -1;
394 if (!dbus_connection_allocate_data_slot(&_connection_python_slot
))
396 if (PyType_Ready(&DBusPyConnection_Type
) < 0)
402 dbus_py_insert_conn_types(PyObject
*this_module
)
404 if (PyModule_AddObject(this_module
, "Connection",
405 (PyObject
*)&DBusPyConnection_Type
) < 0) return FALSE
;
409 /* vim:set ft=c cino< sw=4 sts=4 et: */