1 /* Implementation of the _dbus_bindings Server type, a Python wrapper
2 * for DBusServer. See also server-methods.c.
4 * Copyright (C) 2008 Huang Peng <phuang@redhat.com> .
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 "server-internal.h"
30 /* Server definition ============================================ */
32 PyDoc_STRVAR(Server_tp_doc
,
37 " Server(address, mainloop=None) -> Server\n"
40 /* D-Bus Server user data slot, containing an owned reference to either
41 * the Server, or a weakref to the Server.
43 static dbus_int32_t _server_python_slot
;
45 /* C API for main-loop hooks ======================================== */
47 /* Return a borrowed reference to the DBusServer which underlies this
50 DBusPyServer_BorrowDBusServer(PyObject
*self
)
55 if (!DBusPyServer_Check(self
)) {
56 PyErr_SetString(PyExc_TypeError
, "A dbus.Server is required");
59 dbs
= ((Server
*)self
)->server
;
61 PyErr_SetString(PyExc_RuntimeError
, "Server is in an invalid "
62 "state: no DBusServer");
68 /* Internal C API =================================================== */
70 /* Return a new reference to a Python Server or subclass corresponding
71 * to the DBusServer server. For use in callbacks.
73 * Raises AssertionError if the DBusServer does not have a Server.
76 DBusPyServer_ExistingFromDBusServer(DBusServer
*server
)
80 Py_BEGIN_ALLOW_THREADS
81 ref
= (PyObject
*)dbus_server_get_data(server
,
85 DBG("(DBusServer *)%p has weak reference at %p", server
, ref
);
86 self
= PyWeakref_GetObject(ref
); /* still a borrowed ref */
87 if (self
&& self
!= Py_None
&& DBusPyServer_Check(self
)) {
88 DBG("(DBusServer *)%p has weak reference at %p pointing to %p",
97 PyErr_SetString(PyExc_AssertionError
,
98 "D-Bus server does not have a Server "
99 "instance associated with it");
103 /* Return a new reference to a Python Server or subclass (given by cls)
104 * corresponding to the DBusServer server, which must have been newly
105 * created. For use by the Server and Bus constructors.
107 * Raises AssertionError if the DBusServer already has a Server.
111 Server_new_connection_callback (DBusServer
*server
, DBusConnection
*connection
, void * data UNUSED
)
113 PyObject
*conn
= NULL
;
114 PyObject
*result
= NULL
;
115 PyObject
*args
= NULL
;
118 self
= (Server
*)DBusPyServer_ExistingFromDBusServer(server
);
122 if (self
->new_connection_callback
) {
123 conn
= DBusPyConnection_NewConsumingDBusConnection(self
->new_connection_type
, connection
, self
->mainloop
);
126 dbus_connection_ref (connection
);
128 args
= Py_BuildValue ("(OO)", self
, conn
);
131 result
= PyObject_Call (self
->new_connection_callback
, args
, NULL
);
143 Py_XDECREF ((PyObject
*)self
);
146 /* Server type-methods ========================================== */
148 /* "Constructor" (the real constructor is Server_NewFromDBusServer,
149 * to which this delegates). */
151 Server_tp_new(PyTypeObject
*cls
, PyObject
*args UNUSED
, PyObject
*kwargs UNUSED
)
154 self
= cls
->tp_alloc (cls
, 0);
155 return (PyObject
*)self
;
161 Server_tp_init(Server
*self
, PyObject
*args
, PyObject
*kwargs
)
163 PyObject
*mainloop
= NULL
;
164 DBusServer
*server
= NULL
;
165 char *address
= NULL
;
167 PyObject
*ref
= NULL
;
171 static char *argnames
[] = {"address", "mainloop", NULL
};
173 if (!PyArg_ParseTupleAndKeywords(args
, kwargs
, "s|O", argnames
,
174 &address
, &mainloop
)) {
178 if (!mainloop
|| mainloop
== Py_None
) {
179 mainloop
= dbus_py_get_default_main_loop();
181 PyErr_SetString (PyExc_Exception
,
182 "Can not get default mainloop.");
187 Py_INCREF (mainloop
);
191 dbus_error_init(&error
);
193 Py_BEGIN_ALLOW_THREADS
194 server
= dbus_server_listen(address
, &error
);
198 DBusPyException_ConsumeError(&error
);
202 dbus_server_set_new_connection_function (server
, Server_new_connection_callback
, NULL
, NULL
);
204 Py_INCREF (mainloop
);
205 self
->mainloop
= mainloop
;
206 self
->server
= server
;
207 self
->new_connection_callback
= NULL
;
208 self
->new_connection_type
= NULL
;
210 ref
= PyWeakref_NewRef((PyObject
*)self
, NULL
);
212 DBG("Created weak ref %p to (Server *)%p for (DBusServer *)%p",
215 Py_BEGIN_ALLOW_THREADS
216 ok
= dbus_server_set_data(server
, _server_python_slot
,
218 (DBusFreeFunction
)dbus_py_take_gil_and_xdecref
);
222 DBG("Attached weak ref %p ((Server *)%p) to (DBusServer *)%p",
224 ref
= NULL
; /* don't DECREF it - the DBusServer owns it now */
227 DBG("Failed to attached weak ref %p ((Server *)%p) to "
228 "(DBusServer *)%p - will dispose of it", ref
, self
, server
);
233 DBUS_PY_RAISE_VIA_GOTO_IF_FAIL(server
, err
);
234 self
->server
= server
;
235 /* the DBusPyServer will close it now */
238 if (!dbus_py_set_up_server((PyObject
*)self
, mainloop
)) {
244 DBG("%s() -> %p", __func__
, self
);
249 DBG("Failed to construct Server.");
250 Py_XDECREF(mainloop
);
253 Py_BEGIN_ALLOW_THREADS
254 dbus_server_unref(server
);
257 DBG("%s() fail", __func__
);
264 static void Server_tp_dealloc(Server
*self
)
266 DBusServer
*server
= self
->server
;
267 PyObject
*et
, *ev
, *etb
;
269 /* avoid clobbering any pending exception */
270 PyErr_Fetch(&et
, &ev
, &etb
);
272 if (self
->weaklist
) {
273 PyObject_ClearWeakRefs((PyObject
*)self
);
277 DBG("Deallocating Server at %p (DBusServer at %p)", self
, server
);
280 DBG("Server at %p: deleting callbacks", self
);
283 /* Might trigger callbacks if we're unlucky... */
284 DBG("Server at %p has a server, closing it...", self
);
285 Py_BEGIN_ALLOW_THREADS
289 /* make sure to do this last to preserve the invariant that
290 * self->server is always non-NULL for any referenced Server
291 * (until the filters and object paths were freed, we might have been
292 * in a reference cycle!)
294 DBG("Server at %p: nulling self->server", self
);
295 self
->server
= server
;
298 DBG("Server at %p: unreffing server", self
);
299 dbus_server_unref(server
);
302 Py_XDECREF (self
->mainloop
);
304 DBG("Server at %p: freeing self", self
);
305 PyErr_Restore(et
, ev
, etb
);
306 (self
->ob_type
->tp_free
)((PyObject
*)self
);
309 /* Server type object =========================================== */
311 PyTypeObject DBusPyServer_Type
= {
312 PyObject_HEAD_INIT(NULL
)
314 "_dbus_bindings.Server",/*tp_name*/
315 sizeof(Server
), /*tp_basicsize*/
318 (destructor
)Server_tp_dealloc
,
325 0, /*tp_as_sequence*/
333 Py_TPFLAGS_DEFAULT
| Py_TPFLAGS_HAVE_WEAKREFS
| Py_TPFLAGS_BASETYPE
,
334 Server_tp_doc
, /*tp_doc*/
337 0, /*tp_richcompare*/
338 offsetof(Server
, weaklist
), /*tp_weaklistoffset*/
341 DBusPyServer_tp_methods
,/*tp_methods*/
349 (initproc
) Server_tp_init
,
352 Server_tp_new
, /*tp_new*/
358 dbus_py_init_server_types(void)
360 /* Get a slot to store our weakref on DBus Servers */
361 _server_python_slot
= -1;
362 if (!dbus_server_allocate_data_slot(&_server_python_slot
))
364 if (PyType_Ready(&DBusPyServer_Type
) < 0)
370 dbus_py_insert_server_types(PyObject
*this_module
)
372 if (PyModule_AddObject(this_module
, "Server",
373 (PyObject
*)&DBusPyServer_Type
) < 0) return FALSE
;
377 /* vim:set ft=c cino< sw=4 sts=4 et: */