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 * 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 PyDoc_STRVAR(Connection_close__doc__
,
28 "Close the connection.");
30 Connection_close (Connection
*self
, PyObject
*args
)
32 if (!PyArg_ParseTuple(args
, ":close")) return NULL
;
33 /* Because the user explicitly asked to close the connection, we'll even
34 let them close shared connections. */
36 Py_BEGIN_ALLOW_THREADS
37 dbus_connection_close (self
->conn
);
43 PyDoc_STRVAR(Connection_get_is_connected__doc__
,
44 "get_is_connected() -> bool\n\n"
45 "Return true if this Connection is connected.\n");
47 Connection_get_is_connected (Connection
*self
, PyObject
*args
)
50 if (!PyArg_ParseTuple(args
, ":get_is_connected")) return NULL
;
51 Py_BEGIN_ALLOW_THREADS
52 ret
= dbus_connection_get_is_connected (self
->conn
);
54 return PyBool_FromLong (ret
);
57 PyDoc_STRVAR(Connection_get_is_authenticated__doc__
,
58 "get_is_authenticated() -> bool\n\n"
59 "Return true if this Connection was ever authenticated.\n");
61 Connection_get_is_authenticated (Connection
*self
, PyObject
*args
)
64 if (!PyArg_ParseTuple(args
, ":get_is_authenticated")) return NULL
;
65 Py_BEGIN_ALLOW_THREADS
66 ret
= dbus_connection_get_is_authenticated (self
->conn
);
68 return PyBool_FromLong (ret
);
71 PyDoc_STRVAR(Connection_set_exit_on_disconnect__doc__
,
72 "set_exit_on_disconnect(bool)\n\n"
73 "Set whether the C function ``_exit`` will be called when this Connection\n"
74 "becomes disconnected. This will cause the program to exit without calling\n"
75 "any cleanup code or exit handlers.\n"
77 "The default is for this feature to be disabled for Connections and enabled\n"
80 Connection_set_exit_on_disconnect (Connection
*self
, PyObject
*args
)
82 int exit_on_disconnect
;
83 if (!PyArg_ParseTuple(args
, "i:set_exit_on_disconnect",
84 &exit_on_disconnect
)) {
87 Py_BEGIN_ALLOW_THREADS
88 dbus_connection_set_exit_on_disconnect (self
->conn
,
89 exit_on_disconnect
? 1 : 0);
94 PyDoc_STRVAR(Connection__send__doc__
,
95 "_send(msg: Message) -> long\n\n"
96 "Queue the given message for sending, and return the message serial number.\n"
99 Connection__send (Connection
*self
, PyObject
*args
)
104 dbus_uint32_t serial
;
106 if (!PyArg_ParseTuple(args
, "O", &obj
)) return NULL
;
108 msg
= Message_BorrowDBusMessage(obj
);
109 if (!msg
) return NULL
;
111 Py_BEGIN_ALLOW_THREADS
112 ok
= dbus_connection_send(self
->conn
, msg
, &serial
);
116 return PyErr_NoMemory();
119 return PyLong_FromUnsignedLong(serial
);
122 /* The timeout is in seconds here, since that's conventional in Python. */
123 PyDoc_STRVAR(Connection__send_with_reply__doc__
,
124 "_send_with_reply(msg: Message, reply_handler: callable[, timeout_s: float])"
125 " -> PendingCall\n\n"
126 "Queue the message for sending; expect a reply via the returned PendingCall.\n"
130 " The message to be sent\n"
131 " `reply_handler` : callable\n"
132 " Asynchronous reply handler: will be called with one positional\n"
133 " parameter, a Message instance representing the reply.\n"
134 " `timeout_s` : float\n"
135 " If the reply takes more than this many seconds, a timeout error\n"
136 " will be created locally and raised instead. If this timeout is\n"
137 " negative (default), a sane default (supplied by libdbus) is used.\n"
139 " A `PendingCall` instance which can be used to cancel the pending call.\n"
143 Connection__send_with_reply(Connection
*self
, PyObject
*args
)
146 double timeout_s
= -1.0;
148 PyObject
*obj
, *callable
;
150 DBusPendingCall
*pending
;
152 if (!PyArg_ParseTuple(args
, "OO|f:send_with_reply", &obj
, &callable
,
157 msg
= Message_BorrowDBusMessage(obj
);
158 if (!msg
) return NULL
;
164 if (timeout_s
> ((double)INT_MAX
) / 1000.0) {
165 PyErr_SetString(PyExc_ValueError
, "Timeout too long");
168 timeout_ms
= (int)(timeout_s
* 1000.0);
171 Py_BEGIN_ALLOW_THREADS
172 ok
= dbus_connection_send_with_reply(self
->conn
, msg
, &pending
,
177 return PyErr_NoMemory();
180 return PendingCall_ConsumeDBusPendingCall(pending
, callable
);
183 /* Again, the timeout is in seconds, since that's conventional in Python. */
184 PyDoc_STRVAR(Connection__send_with_reply_and_block__doc__
,
185 "_send_with_reply_and_block(msg: Message, [, timeout_s: float])"
187 "Send the message and block while waiting for a reply.\n"
189 "This does not re-enter the main loop, so it can lead to a deadlock, if\n"
190 "the called method tries to make a synchronous call to a method in this\n"
191 "application. As such, it's probably a bad idea.\n"
195 " The message to be sent\n"
196 " `timeout_s` : float\n"
197 " If the reply takes more than this many seconds, a timeout error\n"
198 " will be created locally and raised instead. If this timeout is\n"
199 " negative (default), a sane default (supplied by libdbus) is used.\n"
201 " A `Message` instance (probably a `MethodReturnMessage`) on success\n"
203 " A `DBusException` on error (including if the reply arrives but is an\n"
208 Connection__send_with_reply_and_block(Connection
*self
, PyObject
*args
)
210 double timeout_s
= -1.0;
213 DBusMessage
*msg
, *reply
;
216 if (!PyArg_ParseTuple(args
, "O|f:_send_with_reply_and_block", &obj
,
221 msg
= Message_BorrowDBusMessage(obj
);
222 if (!msg
) return NULL
;
228 if (timeout_s
> ((double)INT_MAX
) / 1000.0) {
229 PyErr_SetString(PyExc_ValueError
, "Timeout too long");
232 timeout_ms
= (int)(timeout_s
* 1000.0);
235 dbus_error_init(&error
);
236 Py_BEGIN_ALLOW_THREADS
237 reply
= dbus_connection_send_with_reply_and_block(self
->conn
, msg
,
242 return DBusException_ConsumeError(&error
);
244 return Message_ConsumeDBusMessage(reply
);
247 PyDoc_STRVAR(Connection_flush__doc__
,
249 "Block until the outgoing message queue is empty.\n");
251 Connection_flush (Connection
*self
, PyObject
*args
)
253 Py_BEGIN_ALLOW_THREADS
254 dbus_connection_flush (self
->conn
);
260 * dbus_connection_preallocate_send
261 * dbus_connection_free_preallocated_send
262 * dbus_connection_send_preallocated
263 * dbus_connection_borrow_message
264 * dbus_connection_return_message
265 * dbus_connection_steal_borrowed_message
266 * dbus_connection_pop_message
269 /* Non-main-loop handling not yet implemented: */
270 /* dbus_connection_read_write_dispatch */
271 /* dbus_connection_read_write */
273 /* Main loop handling not yet implemented: */
274 /* dbus_connection_get_dispatch_status */
275 /* dbus_connection_dispatch */
276 /* dbus_connection_set_watch_functions */
277 /* dbus_connection_set_timeout_functions */
278 /* dbus_connection_set_wakeup_main_function */
279 /* dbus_connection_set_dispatch_status_function */
281 /* Normally in Python this would be called fileno(), but I don't want to
282 * encourage people to select() on it */
283 PyDoc_STRVAR(Connection_get_unix_fd__doc__
,
284 "get_unix_fd() -> int or None\n\n"
285 "Get the connection's UNIX file descriptor, if any.\n\n"
286 "This can be used for SELinux access control checks with ``getpeercon()``\n"
287 "for example. **Do not** read or write to the file descriptor, or try to\n"
288 "``select()`` on it.\n");
290 Connection_get_unix_fd (Connection
*self
, PyObject
*unused
)
295 Py_BEGIN_ALLOW_THREADS
296 ok
= dbus_connection_get_unix_fd (self
->conn
, &fd
);
298 if (!ok
) Py_RETURN_NONE
;
299 return PyInt_FromLong(fd
);
302 PyDoc_STRVAR(Connection_get_peer_unix_user__doc__
,
303 "get_peer_unix_user() -> long or None\n\n"
304 "Get the UNIX user ID at the other end of the connection, if it has been\n"
305 "authenticated. Return None if this is a non-UNIX platform or the\n"
306 "connection has not been authenticated.\n");
308 Connection_get_peer_unix_user (Connection
*self
, PyObject
*unused
)
313 Py_BEGIN_ALLOW_THREADS
314 ok
= dbus_connection_get_unix_user (self
->conn
, &uid
);
316 if (!ok
) Py_RETURN_NONE
;
317 return PyLong_FromUnsignedLong (uid
);
320 PyDoc_STRVAR(Connection_get_peer_unix_process_id__doc__
,
321 "get_peer_unix_process_id() -> long or None\n\n"
322 "Get the UNIX process ID at the other end of the connection, if it has been\n"
323 "authenticated. Return None if this is a non-UNIX platform or the\n"
324 "connection has not been authenticated.\n");
326 Connection_get_peer_unix_process_id (Connection
*self
, PyObject
*unused
)
331 Py_BEGIN_ALLOW_THREADS
332 ok
= dbus_connection_get_unix_process_id (self
->conn
, &pid
);
334 if (!ok
) Py_RETURN_NONE
;
335 return PyLong_FromUnsignedLong (pid
);
338 /* TODO: wrap dbus_connection_set_unix_user_function Pythonically */
340 PyDoc_STRVAR(Connection__add_filter__doc__
,
341 "_add_filter(callable)\n\n"
342 "Add the given message filter to the internal list.\n\n"
343 "Filters are handlers that are run on all incoming messages, prior to the\n"
344 "objects registered with `_register_object_path`.\n"
345 "Filters are run in the order that they were added. The same handler can\n"
346 "be added as a filter more than once, in which case it will be run more\n"
347 "than once. Filters added during a filter callback won't be run on the\n"
348 "message being processed.\n"
351 Connection__add_filter(Connection
*self
, PyObject
*callable
)
355 /* The callable must be referenced by ->filters *before* it is
356 * given to libdbus, which does not own a reference to it.
358 if (PyList_Append(self
->filters
, callable
) < 0) {
362 Py_BEGIN_ALLOW_THREADS
363 ok
= dbus_connection_add_filter(self
->conn
, _filter_message
, callable
,
368 Py_XDECREF(PyObject_CallMethod(self
->filters
, "remove", "(O)",
376 PyDoc_STRVAR(Connection__remove_filter__doc__
,
377 "_remove_filter(callable)\n\n"
378 "Remove the given message filter (see `_add_filter` for details).\n");
380 Connection__remove_filter(Connection
*self
, PyObject
*callable
)
384 /* It's safe to do this before removing it from libdbus, because
385 * the presence of callable in our arguments means we have a ref
387 obj
= PyObject_CallMethod(self
->filters
, "remove", "(O)", callable
);
388 if (!obj
) return NULL
;
391 Py_BEGIN_ALLOW_THREADS
392 dbus_connection_remove_filter(self
->conn
, _filter_message
, callable
);
398 /* object exports not yet implemented: */
400 PyDoc_STRVAR(Connection__register_object_path__doc__
,
401 "_register_object_path(path: str, on_message: callable[, on_unregister: "
402 "callable][, **kwargs])\n\n"
403 "Keyword arguments accepted:\n"
404 "fallback: bool (default False): if True, when a message arrives for a\n"
405 "'subdirectory' of the given path and there is no more specific handler,\n"
406 "use this handler. Normally this handler is only run if the paths match\n"
410 Connection__register_object_path(Connection
*self
, PyObject
*args
,
415 PyObject
*callbacks
, *path
, *tuple
, *on_message
, *on_unregister
= Py_None
;
416 static char *argnames
[] = {"path", "on_message", "on_unregister",
419 if (!PyArg_ParseTupleAndKeywords(args
, kwargs
,
420 "OO|Oi:_register_object_path",
423 &on_message
, &on_unregister
,
424 &fallback
)) return NULL
;
426 /* Take a reference to path, which we give away to libdbus in a moment.
428 Also, path needs to be a string (not a subclass which could do something
429 mad) to preserve the desirable property that the DBusConnection can
430 never strongly reference the Connection, even indirectly.
431 We make an exception for ObjectPaths because they're equally simple,
432 are known to have the same __eq__ and __hash__, and are what calling code
433 ought to be using. */
434 if (PyString_CheckExact(path
) || path
->ob_type
== &ObjectPathType
) {
437 else if (PyUnicode_Check(path
)) {
438 path
= PyUnicode_AsUTF8String(path
);
439 if (!path
) return NULL
;
441 else if (PyString_Check(path
)) {
442 path
= PyString_FromString(PyString_AS_STRING(path
));
443 if (!path
) return NULL
;
446 if (!_validate_object_path(PyString_AS_STRING(path
))) {
451 tuple
= Py_BuildValue("(OO)", on_unregister
, on_message
);
457 /* Guard against registering a handler that already exists. */
458 callbacks
= PyDict_GetItem(self
->object_paths
, path
);
459 if (callbacks
&& callbacks
!= Py_None
) {
460 PyErr_Format(PyExc_KeyError
, "Can't register the object-path "
461 "handler for '%s': there is already a handler",
462 PyString_AS_STRING(path
));
468 /* Pre-allocate a slot in the dictionary, so we know we'll be able
469 * to replace it with the callbacks without OOM.
470 * This ensures we can keep libdbus' opinion of whether those
471 * paths are handled in sync with our own. */
472 if (PyDict_SetItem(self
->object_paths
, path
, Py_None
) < 0) {
478 Py_BEGIN_ALLOW_THREADS
480 ok
= dbus_connection_register_fallback(self
->conn
,
481 PyString_AS_STRING(path
),
482 &_object_path_vtable
,
486 ok
= dbus_connection_register_object_path(self
->conn
,
487 PyString_AS_STRING(path
),
488 &_object_path_vtable
,
494 if (PyDict_SetItem(self
->object_paths
, path
, tuple
) < 0) {
495 /* That shouldn't have happened, we already allocated enough
496 memory for it. Oh well, try to undo the registration to keep
497 things in sync. If this fails too, we've leaked a bit of
498 memory in libdbus, but tbh we should never get here anyway. */
499 Py_BEGIN_ALLOW_THREADS
500 ok
= dbus_connection_unregister_object_path(self
->conn
,
501 PyString_AS_STRING(path
));
505 /* don't DECREF path: libdbus owns a ref now */
510 /* Oops, OOM. Tidy up, if we can, ignoring any error. */
511 PyDict_DelItem(self
->object_paths
, path
);
520 PyDoc_STRVAR(Connection__unregister_object_path__doc__
,
521 "_unregister_object_path(path: str)\n\n"
525 Connection__unregister_object_path(Connection
*self
, PyObject
*args
,
531 static char *argnames
[] = {"path", NULL
};
533 if (!PyArg_ParseTupleAndKeywords(args
, kwargs
,
534 "O!:_unregister_object_path",
536 &PyString_Type
, &path
)) return NULL
;
538 /* Take a ref to the path. Same comments as for _register_object_path. */
539 if (PyString_CheckExact(path
) || path
->ob_type
== &ObjectPathType
) {
543 path
= PyString_FromString(PyString_AS_STRING(path
));
544 if (!path
) return NULL
;
547 /* Guard against unregistering a handler that doesn't, in fact, exist,
548 or whose unregistration is already in progress. */
549 callbacks
= PyDict_GetItem(self
->object_paths
, path
);
550 if (!callbacks
|| callbacks
== Py_None
) {
551 PyErr_Format(PyExc_KeyError
, "Can't unregister the object-path "
552 "handler for '%s': there is no such handler",
553 PyString_AS_STRING(path
));
558 /* Hang on to a reference to the callbacks for the moment. */
559 Py_INCREF(callbacks
);
561 /* Get rid of the object-path while we still have the GIL, to
562 guard against unregistering twice from different threads (which
563 causes undefined behaviour in libdbus).
565 Because deletion would make it possible for the re-insertion below
566 to fail, we instead set the handler to None as a placeholder.
568 if (PyDict_SetItem(self
->object_paths
, path
, Py_None
) < 0) {
569 /* If that failed, there's no need to be paranoid as below - the
570 callbacks are still set, so we failed, but at least everything
572 Py_DECREF(callbacks
);
578 This is something of a critical section - the dict of object-paths
579 and libdbus' internal structures are out of sync for a bit. We have
580 to be able to cope with that.
582 It's really annoying that dbus_connection_unregister_object_path
583 can fail, *and* has undefined behaviour if the object path has
584 already been unregistered. Either/or would be fine.
587 Py_BEGIN_ALLOW_THREADS
588 ok
= dbus_connection_unregister_object_path(self
->conn
,
589 PyString_AS_STRING(path
));
593 Py_DECREF(callbacks
);
594 PyDict_DelItem(self
->object_paths
, path
);
595 /* END PARANOIA on successful code path */
596 /* The above can't fail unless by some strange trickery the key is no
597 longer present. Ignore any errors. */
603 /* Oops, OOM. Put the callbacks back in the dict so
604 * we'll have another go if/when the user frees some memory
605 * and tries calling this method again. */
606 PyDict_SetItem(self
->object_paths
, path
, callbacks
);
607 /* END PARANOIA on failing code path */
608 /* If the SetItem failed, there's nothing we can do about it - but
609 since we know it's an existing entry, it shouldn't be able to fail
612 Py_DECREF(callbacks
);
613 return PyErr_NoMemory();
617 /* dbus_connection_get_object_path_data - not useful to Python,
618 * the object path data is just a PyString containing the path */
619 /* dbus_connection_list_registered could be useful, though */
621 /* dbus_connection_set_change_sigpipe - sets global state */
623 /* Maxima. Does Python code ever need to manipulate these?
624 * OTOH they're easy to wrap */
625 /* dbus_connection_set_max_message_size */
626 /* dbus_connection_get_max_message_size */
627 /* dbus_connection_set_max_received_size */
628 /* dbus_connection_get_max_received_size */
630 /* dbus_connection_get_outgoing_size - almost certainly unneeded */
632 static struct PyMethodDef Connection_tp_methods
[] = {
633 #define ENTRY(name, flags) {#name, (PyCFunction)Connection_##name, flags, Connection_##name##__doc__}
634 ENTRY(close
, METH_NOARGS
),
635 ENTRY(flush
, METH_NOARGS
),
636 ENTRY(get_is_connected
, METH_NOARGS
),
637 ENTRY(get_is_authenticated
, METH_NOARGS
),
638 ENTRY(set_exit_on_disconnect
, METH_VARARGS
),
639 ENTRY(get_unix_fd
, METH_NOARGS
),
640 ENTRY(get_peer_unix_user
, METH_NOARGS
),
641 ENTRY(get_peer_unix_process_id
, METH_NOARGS
),
642 ENTRY(_add_filter
, METH_O
),
643 ENTRY(_register_object_path
, METH_VARARGS
|METH_KEYWORDS
),
644 ENTRY(_remove_filter
, METH_O
),
645 ENTRY(_send
, METH_VARARGS
),
646 ENTRY(_send_with_reply
, METH_VARARGS
),
647 ENTRY(_send_with_reply_and_block
, METH_VARARGS
),
648 ENTRY(_unregister_object_path
, METH_VARARGS
|METH_KEYWORDS
),
653 /* vim:set ft=c cino< sw=4 sts=4 et: */