1
/* Implementation of normal Python-accessible methods on the _dbus_bindings
2
* Connection type; separated out to keep the file size manageable.
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"
31
_object_path_unregister(DBusConnection *conn, void *user_data)
33
PyGILState_STATE gil = PyGILState_Ensure();
34
PyObject *tuple = NULL;
35
Connection *conn_obj = NULL;
38
conn_obj = (Connection *)DBusPyConnection_ExistingFromDBusConnection(conn);
39
if (!conn_obj) goto out;
42
DBG("Connection at %p unregistering object path %s",
43
conn_obj, PyString_AS_STRING((PyObject *)user_data));
44
tuple = DBusPyConnection_GetObjectPathHandlers((PyObject *)conn_obj, (PyObject *)user_data);
46
if (tuple == Py_None) goto out;
48
DBG("%s", "... yes we have handlers for that object path");
50
/* 0'th item is the unregisterer (if that's a word) */
51
callable = PyTuple_GetItem(tuple, 0);
52
if (callable && callable != Py_None) {
53
DBG("%s", "... and we even have an unregisterer");
54
/* any return from the unregisterer is ignored */
55
Py_XDECREF(PyObject_CallFunctionObjArgs(callable, conn_obj, NULL));
60
/* the user_data (a Python str) is no longer ref'd by the DBusConnection */
62
if (PyErr_Occurred()) {
65
PyGILState_Release(gil);
68
static DBusHandlerResult
69
_object_path_message(DBusConnection *conn, DBusMessage *message,
72
DBusHandlerResult ret;
73
PyGILState_STATE gil = PyGILState_Ensure();
74
Connection *conn_obj = NULL;
75
PyObject *tuple = NULL;
77
PyObject *callable; /* borrowed */
79
dbus_message_ref(message);
80
msg_obj = DBusPyMessage_ConsumeDBusMessage(message);
82
ret = DBUS_HANDLER_RESULT_NEED_MEMORY;
86
conn_obj = (Connection *)DBusPyConnection_ExistingFromDBusConnection(conn);
88
ret = DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
93
DBG("Connection at %p messaging object path %s",
94
conn_obj, PyString_AS_STRING((PyObject *)user_data));
95
DBG_DUMP_MESSAGE(message);
96
tuple = DBusPyConnection_GetObjectPathHandlers((PyObject *)conn_obj, (PyObject *)user_data);
97
if (!tuple || tuple == Py_None) {
98
ret = DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
102
DBG("%s", "... yes we have handlers for that object path");
104
/* 1st item (0-based) is the message callback */
105
callable = PyTuple_GetItem(tuple, 1);
107
DBG("%s", "... error getting message handler from tuple");
108
ret = DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
110
else if (callable == Py_None) {
111
/* there was actually no handler after all */
112
DBG("%s", "... but those handlers don't do messages");
113
ret = DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
116
DBG("%s", "... and we have a message handler for that object path");
117
ret = DBusPyConnection_HandleMessage(conn_obj, msg_obj, callable);
124
if (PyErr_Occurred()) {
127
PyGILState_Release(gil);
131
static const DBusObjectPathVTable _object_path_vtable = {
132
_object_path_unregister,
133
_object_path_message,
136
static DBusHandlerResult
137
_filter_message(DBusConnection *conn, DBusMessage *message, void *user_data)
139
DBusHandlerResult ret;
140
PyGILState_STATE gil = PyGILState_Ensure();
141
Connection *conn_obj = NULL;
142
PyObject *callable = NULL;
144
#ifndef DBUS_PYTHON_DISABLE_CHECKS
148
dbus_message_ref(message);
149
msg_obj = DBusPyMessage_ConsumeDBusMessage(message);
151
DBG("%s", "OOM while trying to construct Message");
152
ret = DBUS_HANDLER_RESULT_NEED_MEMORY;
156
conn_obj = (Connection *)DBusPyConnection_ExistingFromDBusConnection(conn);
158
DBG("%s", "failed to traverse DBusConnection -> Connection weakref");
159
ret = DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
164
/* The user_data is a pointer to a Python object. To avoid
165
* cross-library reference cycles, the DBusConnection isn't allowed
166
* to reference it. However, as long as the Connection is still
167
* alive, its ->filters list owns a reference to the same Python
168
* object, so the object should also still be alive.
170
* To ensure that this works, be careful whenever manipulating the
171
* filters list! (always put things in the list *before* giving
172
* them to libdbus, etc.)
174
#ifdef DBUS_PYTHON_DISABLE_CHECKS
175
callable = (PyObject *)user_data;
177
size = PyList_GET_SIZE(conn_obj->filters);
178
for (i = 0; i < size; i++) {
179
callable = PyList_GET_ITEM(conn_obj->filters, i);
180
if (callable == user_data) {
190
DBG("... filter %p has vanished from ->filters, so not calling it",
192
ret = DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
197
ret = DBusPyConnection_HandleMessage(conn_obj, msg_obj, callable);
202
PyGILState_Release(gil);
206
PyDoc_STRVAR(Connection__require_main_loop__doc__,
207
"_require_main_loop()\n\n"
208
"Raise an exception if this Connection is not bound to any main loop -\n"
209
"in this state, asynchronous calls, receiving signals and exporting objects\n"
212
"`dbus.mainloop.NULL_MAIN_LOOP` is treated like a valid main loop - if you're\n"
213
"using that, you presumably know what you're doing.\n");
215
Connection__require_main_loop (Connection *self, PyObject *args UNUSED)
217
if (!self->has_mainloop) {
218
PyErr_SetString(PyExc_RuntimeError,
219
"To make asynchronous calls, receive signals or "
220
"export objects, D-Bus connections must be attached "
221
"to a main loop by passing mainloop=... to the "
222
"constructor or calling "
223
"dbus.set_default_main_loop(...)");
229
PyDoc_STRVAR(Connection_close__doc__,
231
"Close the connection.");
233
Connection_close (Connection *self, PyObject *args UNUSED)
236
/* Because the user explicitly asked to close the connection, we'll even
237
let them close shared connections. */
239
Py_BEGIN_ALLOW_THREADS
240
dbus_connection_close(self->conn);
246
PyDoc_STRVAR(Connection_get_is_connected__doc__,
247
"get_is_connected() -> bool\n\n"
248
"Return true if this Connection is connected.\n");
250
Connection_get_is_connected (Connection *self, PyObject *args UNUSED)
255
DBUS_PY_RAISE_VIA_NULL_IF_FAIL(self->conn);
256
Py_BEGIN_ALLOW_THREADS
257
ret = dbus_connection_get_is_connected(self->conn);
259
return PyBool_FromLong(ret);
262
PyDoc_STRVAR(Connection_get_is_authenticated__doc__,
263
"get_is_authenticated() -> bool\n\n"
264
"Return true if this Connection was ever authenticated.\n");
266
Connection_get_is_authenticated (Connection *self, PyObject *args UNUSED)
271
DBUS_PY_RAISE_VIA_NULL_IF_FAIL(self->conn);
272
Py_BEGIN_ALLOW_THREADS
273
ret = dbus_connection_get_is_authenticated(self->conn);
275
return PyBool_FromLong(ret);
278
PyDoc_STRVAR(Connection_set_exit_on_disconnect__doc__,
279
"set_exit_on_disconnect(bool)\n\n"
280
"Set whether the C function ``_exit`` will be called when this Connection\n"
281
"becomes disconnected. This will cause the program to exit without calling\n"
282
"any cleanup code or exit handlers.\n"
284
"The default is for this feature to be disabled for Connections and enabled\n"
287
Connection_set_exit_on_disconnect (Connection *self, PyObject *args)
289
int exit_on_disconnect;
292
DBUS_PY_RAISE_VIA_NULL_IF_FAIL(self->conn);
293
if (!PyArg_ParseTuple(args, "i:set_exit_on_disconnect",
294
&exit_on_disconnect)) {
297
Py_BEGIN_ALLOW_THREADS
298
dbus_connection_set_exit_on_disconnect(self->conn,
299
exit_on_disconnect ? 1 : 0);
304
PyDoc_STRVAR(Connection_send_message__doc__,
305
"send_message(msg) -> long\n\n"
306
"Queue the given message for sending, and return the message serial number.\n"
309
" `msg` : dbus.lowlevel.Message\n"
310
" The message to be sent.\n"
313
Connection_send_message(Connection *self, PyObject *args)
318
dbus_uint32_t serial;
321
DBUS_PY_RAISE_VIA_NULL_IF_FAIL(self->conn);
322
if (!PyArg_ParseTuple(args, "O", &obj)) return NULL;
324
msg = DBusPyMessage_BorrowDBusMessage(obj);
325
if (!msg) return NULL;
327
Py_BEGIN_ALLOW_THREADS
328
ok = dbus_connection_send(self->conn, msg, &serial);
332
return PyErr_NoMemory();
335
return PyLong_FromUnsignedLong(serial);
338
PyDoc_STRVAR(Connection_set_allow_anonymous__doc__,
339
"set_allow_anonymous(bool)\n\n"
340
"Allows anonymous clients. Call this on the server side of a connection in a on_connection_added callback"
343
Connection_set_allow_anonymous(Connection *self, PyObject *args)
348
DBUS_PY_RAISE_VIA_NULL_IF_FAIL(self->conn);
349
if (!PyArg_ParseTuple(args, "i", &t)) {
353
Py_BEGIN_ALLOW_THREADS
354
dbus_connection_set_allow_anonymous(self->conn, t ? 1 : 0);
359
/* The timeout is in seconds here, since that's conventional in Python. */
360
PyDoc_STRVAR(Connection_send_message_with_reply__doc__,
361
"send_message_with_reply(msg, reply_handler, timeout_s=-1, "
362
"require_main_loop=False) -> dbus.lowlevel.PendingCall\n\n"
363
"Queue the message for sending; expect a reply via the returned PendingCall,\n"
364
"which can also be used to cancel the pending call.\n"
367
" `msg` : dbus.lowlevel.Message\n"
368
" The message to be sent\n"
369
" `reply_handler` : callable\n"
370
" Asynchronous reply handler: will be called with one positional\n"
371
" parameter, a Message instance representing the reply.\n"
372
" `timeout_s` : float\n"
373
" If the reply takes more than this many seconds, a timeout error\n"
374
" will be created locally and raised instead. If this timeout is\n"
375
" negative (default), a sane default (supplied by libdbus) is used.\n"
376
" `require_main_loop` : bool\n"
377
" If True, raise RuntimeError if this Connection does not have a main\n"
378
" loop configured. If False (default) and there is no main loop, you are\n"
379
" responsible for calling block() on the PendingCall.\n"
383
Connection_send_message_with_reply(Connection *self, PyObject *args, PyObject *kw)
386
double timeout_s = -1.0;
388
PyObject *obj, *callable;
390
DBusPendingCall *pending;
391
int require_main_loop = 0;
392
static char *argnames[] = {"msg", "reply_handler", "timeout_s",
393
"require_main_loop", NULL};
396
DBUS_PY_RAISE_VIA_NULL_IF_FAIL(self->conn);
397
if (!PyArg_ParseTupleAndKeywords(args, kw,
398
"OO|di:send_message_with_reply",
400
&obj, &callable, &timeout_s,
401
&require_main_loop)) {
404
if (require_main_loop && !Connection__require_main_loop(self, NULL)) {
408
msg = DBusPyMessage_BorrowDBusMessage(obj);
409
if (!msg) return NULL;
415
if (timeout_s > ((double)INT_MAX) / 1000.0) {
416
PyErr_SetString(PyExc_ValueError, "Timeout too long");
419
timeout_ms = (int)(timeout_s * 1000.0);
422
Py_BEGIN_ALLOW_THREADS
423
ok = dbus_connection_send_with_reply(self->conn, msg, &pending,
428
return PyErr_NoMemory();
432
/* connection is disconnected (doesn't return FALSE!) */
433
return DBusPyException_SetString ("Connection is disconnected - "
434
"unable to make method call");
437
return DBusPyPendingCall_ConsumeDBusPendingCall(pending, callable);
440
/* Again, the timeout is in seconds, since that's conventional in Python. */
441
PyDoc_STRVAR(Connection_send_message_with_reply_and_block__doc__,
442
"send_message_with_reply_and_block(msg, timeout_s=-1)"
443
" -> dbus.lowlevel.Message\n\n"
444
"Send the message and block while waiting for a reply.\n"
446
"This does not re-enter the main loop, so it can lead to a deadlock, if\n"
447
"the called method tries to make a synchronous call to a method in this\n"
448
"application. As such, it's probably a bad idea.\n"
451
" `msg` : dbus.lowlevel.Message\n"
452
" The message to be sent\n"
453
" `timeout_s` : float\n"
454
" If the reply takes more than this many seconds, a timeout error\n"
455
" will be created locally and raised instead. If this timeout is\n"
456
" negative (default), a sane default (supplied by libdbus) is used.\n"
458
" A `dbus.lowlevel.Message` instance (probably a `dbus.lowlevel.MethodReturnMessage`) on success\n"
459
":Raises dbus.DBusException:\n"
460
" On error (including if the reply arrives but is an\n"
465
Connection_send_message_with_reply_and_block(Connection *self, PyObject *args)
467
double timeout_s = -1.0;
470
DBusMessage *msg, *reply;
474
DBUS_PY_RAISE_VIA_NULL_IF_FAIL(self->conn);
475
if (!PyArg_ParseTuple(args, "O|d:send_message_with_reply_and_block", &obj,
480
msg = DBusPyMessage_BorrowDBusMessage(obj);
481
if (!msg) return NULL;
487
if (timeout_s > ((double)INT_MAX) / 1000.0) {
488
PyErr_SetString(PyExc_ValueError, "Timeout too long");
491
timeout_ms = (int)(timeout_s * 1000.0);
494
dbus_error_init(&error);
495
Py_BEGIN_ALLOW_THREADS
496
reply = dbus_connection_send_with_reply_and_block(self->conn, msg,
500
/* FIXME: if we instead used send_with_reply and blocked on the resulting
501
* PendingCall, then we could get all args from the error, not just
504
return DBusPyException_ConsumeError(&error);
506
return DBusPyMessage_ConsumeDBusMessage(reply);
509
PyDoc_STRVAR(Connection_flush__doc__,
511
"Block until the outgoing message queue is empty.\n");
513
Connection_flush (Connection *self, PyObject *args UNUSED)
516
DBUS_PY_RAISE_VIA_NULL_IF_FAIL(self->conn);
517
Py_BEGIN_ALLOW_THREADS
518
dbus_connection_flush (self->conn);
524
* dbus_connection_preallocate_send
525
* dbus_connection_free_preallocated_send
526
* dbus_connection_send_preallocated
527
* dbus_connection_borrow_message
528
* dbus_connection_return_message
529
* dbus_connection_steal_borrowed_message
530
* dbus_connection_pop_message
533
/* Non-main-loop handling not yet implemented: */
534
/* dbus_connection_read_write_dispatch */
535
/* dbus_connection_read_write */
537
/* Main loop handling not yet implemented: */
538
/* dbus_connection_get_dispatch_status */
539
/* dbus_connection_dispatch */
540
/* dbus_connection_set_watch_functions */
541
/* dbus_connection_set_timeout_functions */
542
/* dbus_connection_set_wakeup_main_function */
543
/* dbus_connection_set_dispatch_status_function */
545
/* Normally in Python this would be called fileno(), but I don't want to
546
* encourage people to select() on it */
547
PyDoc_STRVAR(Connection_get_unix_fd__doc__,
548
"get_unix_fd() -> int or None\n\n"
549
"Get the connection's UNIX file descriptor, if any.\n\n"
550
"This can be used for SELinux access control checks with ``getpeercon()``\n"
551
"for example. **Do not** read or write to the file descriptor, or try to\n"
552
"``select()`` on it.\n");
554
Connection_get_unix_fd (Connection *self, PyObject *unused UNUSED)
560
DBUS_PY_RAISE_VIA_NULL_IF_FAIL(self->conn);
561
Py_BEGIN_ALLOW_THREADS
562
ok = dbus_connection_get_unix_fd (self->conn, &fd);
564
if (!ok) Py_RETURN_NONE;
565
return PyInt_FromLong(fd);
568
PyDoc_STRVAR(Connection_get_peer_unix_user__doc__,
569
"get_peer_unix_user() -> long or None\n\n"
570
"Get the UNIX user ID at the other end of the connection, if it has been\n"
571
"authenticated. Return None if this is a non-UNIX platform or the\n"
572
"connection has not been authenticated.\n");
574
Connection_get_peer_unix_user (Connection *self, PyObject *unused UNUSED)
580
DBUS_PY_RAISE_VIA_NULL_IF_FAIL(self->conn);
581
Py_BEGIN_ALLOW_THREADS
582
ok = dbus_connection_get_unix_user (self->conn, &uid);
584
if (!ok) Py_RETURN_NONE;
585
return PyLong_FromUnsignedLong (uid);
588
PyDoc_STRVAR(Connection_get_peer_unix_process_id__doc__,
589
"get_peer_unix_process_id() -> long or None\n\n"
590
"Get the UNIX process ID at the other end of the connection, if it has been\n"
591
"authenticated. Return None if this is a non-UNIX platform or the\n"
592
"connection has not been authenticated.\n");
594
Connection_get_peer_unix_process_id (Connection *self, PyObject *unused UNUSED)
600
DBUS_PY_RAISE_VIA_NULL_IF_FAIL(self->conn);
601
Py_BEGIN_ALLOW_THREADS
602
ok = dbus_connection_get_unix_process_id (self->conn, &pid);
604
if (!ok) Py_RETURN_NONE;
605
return PyLong_FromUnsignedLong (pid);
608
/* TODO: wrap dbus_connection_set_unix_user_function Pythonically */
610
PyDoc_STRVAR(Connection_add_message_filter__doc__,
611
"add_message_filter(callable)\n\n"
612
"Add the given message filter to the internal list.\n\n"
613
"Filters are handlers that are run on all incoming messages, prior to the\n"
614
"objects registered to handle object paths.\n"
616
"Filters are run in the order that they were added. The same handler can\n"
617
"be added as a filter more than once, in which case it will be run more\n"
618
"than once. Filters added during a filter callback won't be run on the\n"
619
"message being processed.\n"
622
Connection_add_message_filter(Connection *self, PyObject *callable)
627
DBUS_PY_RAISE_VIA_NULL_IF_FAIL(self->conn);
628
/* The callable must be referenced by ->filters *before* it is
629
* given to libdbus, which does not own a reference to it.
631
if (PyList_Append(self->filters, callable) < 0) {
635
Py_BEGIN_ALLOW_THREADS
636
ok = dbus_connection_add_filter(self->conn, _filter_message, callable,
641
Py_XDECREF(PyObject_CallMethod(self->filters, "remove", "(O)",
649
PyDoc_STRVAR(Connection_remove_message_filter__doc__,
650
"remove_message_filter(callable)\n\n"
651
"Remove the given message filter (see `add_message_filter` for details).\n"
653
":Raises LookupError:\n"
654
" The given callable is not among the registered filters\n");
656
Connection_remove_message_filter(Connection *self, PyObject *callable)
661
DBUS_PY_RAISE_VIA_NULL_IF_FAIL(self->conn);
662
/* It's safe to do this before removing it from libdbus, because
663
* the presence of callable in our arguments means we have a ref
665
obj = PyObject_CallMethod(self->filters, "remove", "(O)", callable);
666
if (!obj) return NULL;
669
Py_BEGIN_ALLOW_THREADS
670
dbus_connection_remove_filter(self->conn, _filter_message, callable);
676
PyDoc_STRVAR(Connection__register_object_path__doc__,
677
"register_object_path(path, on_message, on_unregister=None, fallback=False)\n"
679
"Register a callback to be called when messages arrive at the given\n"
680
"object-path. Used to export objects' methods on the bus in a low-level\n"
681
"way. For the high-level interface to this functionality (usually\n"
682
"recommended) see the `dbus.service.Object` base class.\n"
686
" Object path to be acted on\n"
687
" `on_message` : callable\n"
688
" Called when a message arrives at the given object-path, with\n"
689
" two positional parameters: the first is this Connection,\n"
690
" the second is the incoming `dbus.lowlevel.Message`.\n"
691
" `on_unregister` : callable or None\n"
692
" If not None, called when the callback is unregistered.\n"
693
" `fallback` : bool\n"
694
" If True (the default is False), when a message arrives for a\n"
695
" 'subdirectory' of the given path and there is no more specific\n"
696
" handler, use this handler. Normally this handler is only run if\n"
697
" the paths match exactly.\n"
700
Connection__register_object_path(Connection *self, PyObject *args,
705
PyObject *callbacks, *path, *tuple, *on_message, *on_unregister = Py_None;
706
static char *argnames[] = {"path", "on_message", "on_unregister",
710
DBUS_PY_RAISE_VIA_NULL_IF_FAIL(self->conn);
711
if (!Connection__require_main_loop(self, NULL)) {
714
if (!PyArg_ParseTupleAndKeywords(args, kwargs,
715
"OO|Oi:_register_object_path",
718
&on_message, &on_unregister,
719
&fallback)) return NULL;
721
/* Take a reference to path, which we give away to libdbus in a moment.
723
Also, path needs to be a string (not a subclass which could do something
724
mad) to preserve the desirable property that the DBusConnection can
725
never strongly reference the Connection, even indirectly.
727
if (PyString_CheckExact(path)) {
730
else if (PyUnicode_Check(path)) {
731
path = PyUnicode_AsUTF8String(path);
732
if (!path) return NULL;
734
else if (PyString_Check(path)) {
735
path = PyString_FromString(PyString_AS_STRING(path));
736
if (!path) return NULL;
739
PyErr_SetString(PyExc_TypeError, "path must be a str or unicode object");
743
if (!dbus_py_validate_object_path(PyString_AS_STRING(path))) {
748
tuple = Py_BuildValue("(OO)", on_unregister, on_message);
754
/* Guard against registering a handler that already exists. */
755
callbacks = PyDict_GetItem(self->object_paths, path);
756
if (callbacks && callbacks != Py_None) {
757
PyErr_Format(PyExc_KeyError, "Can't register the object-path "
758
"handler for '%s': there is already a handler",
759
PyString_AS_STRING(path));
765
/* Pre-allocate a slot in the dictionary, so we know we'll be able
766
* to replace it with the callbacks without OOM.
767
* This ensures we can keep libdbus' opinion of whether those
768
* paths are handled in sync with our own. */
769
if (PyDict_SetItem(self->object_paths, path, Py_None) < 0) {
775
Py_BEGIN_ALLOW_THREADS
777
ok = dbus_connection_register_fallback(self->conn,
778
PyString_AS_STRING(path),
779
&_object_path_vtable,
783
ok = dbus_connection_register_object_path(self->conn,
784
PyString_AS_STRING(path),
785
&_object_path_vtable,
791
if (PyDict_SetItem(self->object_paths, path, tuple) < 0) {
792
/* That shouldn't have happened, we already allocated enough
793
memory for it. Oh well, try to undo the registration to keep
794
things in sync. If this fails too, we've leaked a bit of
795
memory in libdbus, but tbh we should never get here anyway. */
796
Py_BEGIN_ALLOW_THREADS
797
ok = dbus_connection_unregister_object_path(self->conn,
798
PyString_AS_STRING(path));
802
/* don't DECREF path: libdbus owns a ref now */
807
/* Oops, OOM. Tidy up, if we can, ignoring any error. */
808
PyDict_DelItem(self->object_paths, path);
817
PyDoc_STRVAR(Connection__unregister_object_path__doc__,
818
"unregister_object_path(path)\n\n"
819
"Remove a previously registered handler for the given object path.\n"
823
" The object path whose handler is to be removed\n"
824
":Raises KeyError: if there is no handler registered for exactly that\n"
828
Connection__unregister_object_path(Connection *self, PyObject *args,
834
static char *argnames[] = {"path", NULL};
837
DBUS_PY_RAISE_VIA_NULL_IF_FAIL(self->conn);
838
if (!PyArg_ParseTupleAndKeywords(args, kwargs,
839
"O:_unregister_object_path",
840
argnames, &path)) return NULL;
842
/* Take a ref to the path. Same comments as for _register_object_path. */
843
if (PyString_CheckExact(path)) {
846
else if (PyUnicode_Check(path)) {
847
path = PyUnicode_AsUTF8String(path);
848
if (!path) return NULL;
850
else if (PyString_Check(path)) {
851
path = PyString_FromString(PyString_AS_STRING(path));
852
if (!path) return NULL;
855
PyErr_SetString(PyExc_TypeError, "path must be a str or unicode object");
859
/* Guard against unregistering a handler that doesn't, in fact, exist,
860
or whose unregistration is already in progress. */
861
callbacks = PyDict_GetItem(self->object_paths, path);
862
if (!callbacks || callbacks == Py_None) {
863
PyErr_Format(PyExc_KeyError, "Can't unregister the object-path "
864
"handler for '%s': there is no such handler",
865
PyString_AS_STRING(path));
870
/* Hang on to a reference to the callbacks for the moment. */
871
Py_INCREF(callbacks);
873
/* Get rid of the object-path while we still have the GIL, to
874
guard against unregistering twice from different threads (which
875
causes undefined behaviour in libdbus).
877
Because deletion would make it possible for the re-insertion below
878
to fail, we instead set the handler to None as a placeholder.
880
if (PyDict_SetItem(self->object_paths, path, Py_None) < 0) {
881
/* If that failed, there's no need to be paranoid as below - the
882
callbacks are still set, so we failed, but at least everything
890
This is something of a critical section - the dict of object-paths
891
and libdbus' internal structures are out of sync for a bit. We have
892
to be able to cope with that.
894
It's really annoying that dbus_connection_unregister_object_path
895
can fail, *and* has undefined behaviour if the object path has
896
already been unregistered. Either/or would be fine.
899
Py_BEGIN_ALLOW_THREADS
900
ok = dbus_connection_unregister_object_path(self->conn,
901
PyString_AS_STRING(path));
906
PyDict_DelItem(self->object_paths, path);
907
/* END PARANOIA on successful code path */
908
/* The above can't fail unless by some strange trickery the key is no
909
longer present. Ignore any errors. */
915
/* Oops, OOM. Put the callbacks back in the dict so
916
* we'll have another go if/when the user frees some memory
917
* and tries calling this method again. */
918
PyDict_SetItem(self->object_paths, path, callbacks);
919
/* END PARANOIA on failing code path */
920
/* If the SetItem failed, there's nothing we can do about it - but
921
since we know it's an existing entry, it shouldn't be able to fail
925
return PyErr_NoMemory();
929
PyDoc_STRVAR(Connection_list_exported_child_objects__doc__,
930
"list_exported_child_objects(path: str) -> list of str\n\n"
931
"Return a list of the names of objects exported on this Connection as\n"
932
"direct children of the given object path.\n"
934
"Each name returned may be converted to a valid object path using\n"
935
"``dbus.ObjectPath('%s%s%s' % (path, (path != '/' and '/' or ''), name))``.\n"
936
"For the purposes of this function, every parent or ancestor of an exported\n"
937
"object is considered to be an exported object, even if it's only an object\n"
938
"synthesized by the library to support introspection.\n");
940
Connection_list_exported_child_objects (Connection *self, PyObject *args,
944
char **kids, **kid_ptr;
947
static char *argnames[] = {"path", NULL};
949
DBUS_PY_RAISE_VIA_NULL_IF_FAIL(self->conn);
950
if (!PyArg_ParseTupleAndKeywords(args, kwargs, "s", argnames, &path)) {
954
if (!dbus_py_validate_object_path(path)) {
958
Py_BEGIN_ALLOW_THREADS
959
ok = dbus_connection_list_registered(self->conn, path, &kids);
963
return PyErr_NoMemory();
970
for (kid_ptr = kids; *kid_ptr; kid_ptr++) {
971
PyObject *tmp = PyString_FromString(*kid_ptr);
977
if (PyList_Append(ret, tmp) < 0) {
985
dbus_free_string_array(kids);
990
/* dbus_connection_get_object_path_data - not useful to Python,
991
* the object path data is just a PyString containing the path */
992
/* dbus_connection_list_registered could be useful, though */
994
/* dbus_connection_set_change_sigpipe - sets global state */
996
/* Maxima. Does Python code ever need to manipulate these?
997
* OTOH they're easy to wrap */
998
/* dbus_connection_set_max_message_size */
999
/* dbus_connection_get_max_message_size */
1000
/* dbus_connection_set_max_received_size */
1001
/* dbus_connection_get_max_received_size */
1003
/* dbus_connection_get_outgoing_size - almost certainly unneeded */
1005
PyDoc_STRVAR(new_for_bus__doc__,
1006
"Connection._new_for_bus([address: str or int]) -> Connection\n"
1008
"If the address is an int it must be one of the constants BUS_SESSION,\n"
1009
"BUS_SYSTEM, BUS_STARTER; if a string, it must be a D-Bus address.\n"
1010
"The default is BUS_SESSION.\n"
1013
PyDoc_STRVAR(get_unique_name__doc__,
1014
"get_unique_name() -> str\n\n"
1015
"Return this application's unique name on this bus.\n"
1017
":Raises DBusException: if the connection has no unique name yet\n"
1018
" (for Bus objects this can't happen, for peer-to-peer connections\n"
1019
" this means you haven't called `set_unique_name`)\n");
1021
PyDoc_STRVAR(set_unique_name__doc__,
1022
"set_unique_name(str)\n\n"
1023
"Set this application's unique name on this bus. Raise ValueError if it has\n"
1024
"already been set.\n");
1026
struct PyMethodDef DBusPyConnection_tp_methods[] = {
1027
#define ENTRY(name, flags) {#name, (PyCFunction)Connection_##name, flags, Connection_##name##__doc__}
1028
ENTRY(_require_main_loop, METH_NOARGS),
1029
ENTRY(close, METH_NOARGS),
1030
ENTRY(flush, METH_NOARGS),
1031
ENTRY(get_is_connected, METH_NOARGS),
1032
ENTRY(get_is_authenticated, METH_NOARGS),
1033
ENTRY(set_exit_on_disconnect, METH_VARARGS),
1034
ENTRY(get_unix_fd, METH_NOARGS),
1035
ENTRY(get_peer_unix_user, METH_NOARGS),
1036
ENTRY(get_peer_unix_process_id, METH_NOARGS),
1037
ENTRY(add_message_filter, METH_O),
1038
ENTRY(_register_object_path, METH_VARARGS|METH_KEYWORDS),
1039
ENTRY(remove_message_filter, METH_O),
1040
ENTRY(send_message, METH_VARARGS),
1041
ENTRY(send_message_with_reply, METH_VARARGS|METH_KEYWORDS),
1042
ENTRY(send_message_with_reply_and_block, METH_VARARGS),
1043
ENTRY(_unregister_object_path, METH_VARARGS|METH_KEYWORDS),
1044
ENTRY(list_exported_child_objects, METH_VARARGS|METH_KEYWORDS),
1045
{"_new_for_bus", (PyCFunction)DBusPyConnection_NewForBus,
1046
METH_CLASS|METH_VARARGS|METH_KEYWORDS,
1047
new_for_bus__doc__},
1048
{"get_unique_name", (PyCFunction)DBusPyConnection_GetUniqueName,
1050
get_unique_name__doc__},
1051
{"set_unique_name", (PyCFunction)DBusPyConnection_SetUniqueName,
1053
set_unique_name__doc__},
1054
ENTRY(set_allow_anonymous, METH_VARARGS),
1059
/* vim:set ft=c cino< sw=4 sts=4 et: */