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 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"
36 " Connection(address, mainloop=None) -> Connection\n"
39 /* D-Bus Connection user data slot, containing an owned reference to either
40 * the Connection, or a weakref to the Connection.
42 static dbus_int32_t _connection_python_slot
;
44 /* C API for main-loop hooks ======================================== */
46 /* Return a borrowed reference to the DBusConnection which underlies this
49 DBusPyConnection_BorrowDBusConnection(PyObject
*self
)
54 if (!DBusPyConnection_Check(self
)) {
55 PyErr_SetString(PyExc_TypeError
, "A dbus.Connection is required");
58 dbc
= ((Connection
*)self
)->conn
;
60 PyErr_SetString(PyExc_RuntimeError
, "Connection is in an invalid "
61 "state: no DBusConnection");
67 /* Internal C API =================================================== */
69 /* Pass a message through a handler. */
71 DBusPyConnection_HandleMessage(Connection
*conn
,
78 obj
= PyObject_CallFunctionObjArgs(callable
, conn
, msg
,
81 DBG("%p: OK, handler %p returned None", conn
, callable
);
83 return DBUS_HANDLER_RESULT_HANDLED
;
85 else if (obj
== Py_NotImplemented
) {
86 DBG("%p: handler %p returned NotImplemented, continuing",
89 return DBUS_HANDLER_RESULT_NOT_YET_HANDLED
;
92 if (PyErr_ExceptionMatches(PyExc_MemoryError
)) {
93 DBG_EXC("%p: handler %p caused OOM", conn
, callable
);
95 return DBUS_HANDLER_RESULT_NEED_MEMORY
;
97 DBG_EXC("%p: handler %p raised exception", conn
, callable
);
98 return DBUS_HANDLER_RESULT_NOT_YET_HANDLED
;
101 long i
= PyInt_AsLong(obj
);
102 DBG("%p: handler %p returned %ld", conn
, callable
, i
);
104 if (i
== -1 && PyErr_Occurred()) {
105 PyErr_SetString(PyExc_TypeError
, "Return from D-Bus message "
106 "handler callback should be None, "
107 "NotImplemented or integer");
108 return DBUS_HANDLER_RESULT_NOT_YET_HANDLED
;
110 else if (i
== DBUS_HANDLER_RESULT_HANDLED
||
111 i
== DBUS_HANDLER_RESULT_NOT_YET_HANDLED
||
112 i
== DBUS_HANDLER_RESULT_NEED_MEMORY
) {
116 PyErr_Format(PyExc_ValueError
, "Integer return from "
117 "D-Bus message handler callback should "
118 "be a DBUS_HANDLER_RESULT_... constant, "
120 return DBUS_HANDLER_RESULT_NOT_YET_HANDLED
;
125 /* On KeyError or if unregistration is in progress, return None. */
127 DBusPyConnection_GetObjectPathHandlers(PyObject
*self
, PyObject
*path
)
132 callbacks
= PyDict_GetItem(((Connection
*)self
)->object_paths
, path
);
134 if (PyErr_ExceptionMatches(PyExc_KeyError
)) {
139 Py_INCREF(callbacks
);
143 /* Return a new reference to a Python Connection or subclass corresponding
144 * to the DBusConnection conn. For use in callbacks.
146 * Raises AssertionError if the DBusConnection does not have a Connection.
149 DBusPyConnection_ExistingFromDBusConnection(DBusConnection
*conn
)
151 PyObject
*self
, *ref
;
153 Py_BEGIN_ALLOW_THREADS
154 ref
= (PyObject
*)dbus_connection_get_data(conn
,
155 _connection_python_slot
);
158 DBG("(DBusConnection *)%p has weak reference at %p", conn
, ref
);
159 self
= PyWeakref_GetObject(ref
); /* still a borrowed ref */
160 if (self
&& self
!= Py_None
&& DBusPyConnection_Check(self
)) {
161 DBG("(DBusConnection *)%p has weak reference at %p pointing to %p",
170 PyErr_SetString(PyExc_AssertionError
,
171 "D-Bus connection does not have a Connection "
172 "instance associated with it");
176 /* Return a new reference to a Python Connection or subclass (given by cls)
177 * corresponding to the DBusConnection conn, which must have been newly
178 * created. For use by the Connection and Bus constructors.
180 * Raises AssertionError if the DBusConnection already has a Connection.
183 DBusPyConnection_NewConsumingDBusConnection(PyTypeObject
*cls
,
184 DBusConnection
*conn
,
187 Connection
*self
= NULL
;
191 DBG("%s(cls=%p, conn=%p, mainloop=%p)", __func__
, cls
, conn
, mainloop
);
192 DBUS_PY_RAISE_VIA_NULL_IF_FAIL(conn
);
194 Py_BEGIN_ALLOW_THREADS
195 ref
= (PyObject
*)dbus_connection_get_data(conn
,
196 _connection_python_slot
);
199 self
= (Connection
*)PyWeakref_GetObject(ref
);
201 if (self
&& (PyObject
*)self
!= Py_None
) {
203 PyErr_SetString(PyExc_AssertionError
,
204 "Newly created D-Bus connection already has a "
205 "Connection instance associated with it");
206 DBG("%s() fail - assertion failed, DBusPyConn has a DBusConn already", __func__
);
213 /* Change mainloop from a borrowed reference to an owned reference */
214 if (!mainloop
|| mainloop
== Py_None
) {
215 mainloop
= dbus_py_get_default_main_loop();
223 DBG("Constructing Connection from DBusConnection at %p", conn
);
225 self
= (Connection
*)(cls
->tp_alloc(cls
, 0));
231 self
->has_mainloop
= (mainloop
!= Py_None
);
233 self
->filters
= PyList_New(0);
234 if (!self
->filters
) goto err
;
235 self
->object_paths
= PyDict_New();
236 if (!self
->object_paths
) goto err
;
238 ref
= PyWeakref_NewRef((PyObject
*)self
, NULL
);
240 DBG("Created weak ref %p to (Connection *)%p for (DBusConnection *)%p",
243 Py_BEGIN_ALLOW_THREADS
244 ok
= dbus_connection_set_data(conn
, _connection_python_slot
,
246 (DBusFreeFunction
)dbus_py_take_gil_and_xdecref
);
250 DBG("Attached weak ref %p ((Connection *)%p) to (DBusConnection *)%p",
252 ref
= NULL
; /* don't DECREF it - the DBusConnection owns it now */
255 DBG("Failed to attached weak ref %p ((Connection *)%p) to "
256 "(DBusConnection *)%p - will dispose of it", ref
, self
, conn
);
261 DBUS_PY_RAISE_VIA_GOTO_IF_FAIL(conn
, err
);
263 /* the DBusPyConnection will close it now */
266 if (self
->has_mainloop
267 && !dbus_py_set_up_connection((PyObject
*)self
, mainloop
)) {
273 DBG("%s() -> %p", __func__
, self
);
275 return (PyObject
*)self
;
278 DBG("Failed to construct Connection from DBusConnection at %p", conn
);
279 Py_XDECREF(mainloop
);
283 Py_BEGIN_ALLOW_THREADS
284 dbus_connection_close(conn
);
285 dbus_connection_unref(conn
);
288 DBG("%s() fail", __func__
);
293 /* Connection type-methods ========================================== */
295 /* "Constructor" (the real constructor is Connection_NewFromDBusConnection,
296 * to which this delegates). */
298 Connection_tp_new(PyTypeObject
*cls
, PyObject
*args
, PyObject
*kwargs
)
300 DBusConnection
*conn
;
303 PyObject
*self
, *mainloop
= NULL
;
304 static char *argnames
[] = {"address", "mainloop", NULL
};
306 if (!PyArg_ParseTupleAndKeywords(args
, kwargs
, "s|O", argnames
,
307 &address
, &mainloop
)) {
311 dbus_error_init(&error
);
313 /* We always open a private connection (at the libdbus level). Sharing
314 * is done in Python, to keep things simple. */
315 Py_BEGIN_ALLOW_THREADS
316 conn
= dbus_connection_open_private(address
, &error
);
320 DBusPyException_ConsumeError(&error
);
323 self
= DBusPyConnection_NewConsumingDBusConnection(cls
, conn
, mainloop
);
330 static void Connection_tp_dealloc(Connection
*self
)
332 DBusConnection
*conn
= self
->conn
;
333 PyObject
*filters
= self
->filters
;
334 PyObject
*object_paths
= self
->object_paths
;
336 if (self
->weaklist
) {
337 PyObject_ClearWeakRefs((PyObject
*)self
);
341 DBG("Deallocating Connection at %p (DBusConnection at %p)", self
, conn
);
344 DBG("Connection at %p: deleting callbacks", self
);
345 self
->filters
= NULL
;
347 self
->object_paths
= NULL
;
348 Py_XDECREF(object_paths
);
351 /* Might trigger callbacks if we're unlucky... */
352 DBG("Connection at %p has a conn, closing it...", self
);
353 Py_BEGIN_ALLOW_THREADS
354 dbus_connection_close(conn
);
358 /* make sure to do this last to preserve the invariant that
359 * self->conn is always non-NULL for any referenced Connection
360 * (until the filters and object paths were freed, we might have been
361 * in a reference cycle!)
363 DBG("Connection at %p: nulling self->conn", self
);
367 DBG("Connection at %p: unreffing conn", self
);
368 dbus_connection_unref(conn
);
371 DBG("Connection at %p: freeing self", self
);
372 (self
->ob_type
->tp_free
)((PyObject
*)self
);
375 /* Connection type object =========================================== */
377 PyTypeObject DBusPyConnection_Type
= {
378 PyObject_HEAD_INIT(NULL
)
380 "_dbus_bindings.Connection", /*tp_name*/
381 sizeof(Connection
), /*tp_basicsize*/
384 (destructor
)Connection_tp_dealloc
,
391 0, /*tp_as_sequence*/
399 Py_TPFLAGS_DEFAULT
| Py_TPFLAGS_HAVE_WEAKREFS
| Py_TPFLAGS_BASETYPE
,
400 Connection_tp_doc
, /*tp_doc*/
403 0, /*tp_richcompare*/
404 offsetof(Connection
, weaklist
), /*tp_weaklistoffset*/
407 DBusPyConnection_tp_methods
, /*tp_methods*/
417 Connection_tp_new
, /*tp_new*/
423 dbus_py_init_conn_types(void)
425 /* Get a slot to store our weakref on DBus Connections */
426 _connection_python_slot
= -1;
427 if (!dbus_connection_allocate_data_slot(&_connection_python_slot
))
429 if (PyType_Ready(&DBusPyConnection_Type
) < 0)
435 dbus_py_insert_conn_types(PyObject
*this_module
)
437 if (PyModule_AddObject(this_module
, "Connection",
438 (PyObject
*)&DBusPyConnection_Type
) < 0) return FALSE
;
442 /* vim:set ft=c cino< sw=4 sts=4 et: */