mirror of
https://gitlab.gnome.org/GNOME/glib.git
synced 2024-12-25 15:06:14 +01:00
Merge branch 'gdbus-merge'
Conflicts: docs/reference/gio/gio-docs.xml docs/reference/gio/gio-sections.txt gio/tests/Makefile.am
This commit is contained in:
commit
6223341cac
10
configure.in
10
configure.in
@ -3496,6 +3496,16 @@ if test x$glib_win32_static_compilation = xyes; then
|
||||
fi
|
||||
])
|
||||
|
||||
# Check for libdbus1 - Optional - is only used in the GDBus test cases
|
||||
#
|
||||
PKG_CHECK_MODULES(DBUS1,
|
||||
dbus-1,
|
||||
[AC_DEFINE(HAVE_DBUS1, 1, [Define if dbus-1 is available]) have_dbus1=yes],
|
||||
have_dbus1=no)
|
||||
AC_SUBST(DBUS1_CFLAGS)
|
||||
AC_SUBST(DBUS1_LIBS)
|
||||
AM_CONDITIONAL(HAVE_DBUS1, [test "x$have_dbus1" = "xyes"])
|
||||
|
||||
AC_CONFIG_FILES([
|
||||
glib-2.0.pc
|
||||
glib-2.0-uninstalled.pc
|
||||
|
@ -114,15 +114,23 @@ HTML_IMAGES = \
|
||||
content_files = \
|
||||
version.xml \
|
||||
overview.xml \
|
||||
migrating.xml \
|
||||
migrating-posix.xml \
|
||||
migrating-gnome-vfs.xml \
|
||||
migrating-gconf.xml \
|
||||
migrating-gdbus.xml \
|
||||
gio-querymodules.xml \
|
||||
glib-compile-schemas.xml\
|
||||
gsettings.xml \
|
||||
gsettings-schema-convert.xml
|
||||
gsettings-schema-convert.xml \
|
||||
gdbus.xml \
|
||||
$(NULL)
|
||||
|
||||
expand_content_files = \
|
||||
overview.xml \
|
||||
migrating.xml
|
||||
migrating-posix.xml \
|
||||
migrating-gnome-vfs.xml \
|
||||
migrating-gconf.xml \
|
||||
migrating-gdbus.xml
|
||||
|
||||
extra_files = \
|
||||
version.xml.in \
|
||||
@ -137,7 +145,8 @@ man_MANS = \
|
||||
gio-querymodules.1 \
|
||||
glib-compile-schemas.1 \
|
||||
gsettings.1 \
|
||||
gsettings-schema-convert.1
|
||||
gsettings-schema-convert.1 \
|
||||
gdbus.1
|
||||
|
||||
if ENABLE_MAN
|
||||
|
||||
|
266
docs/reference/gio/gdbus.xml
Normal file
266
docs/reference/gio/gdbus.xml
Normal file
@ -0,0 +1,266 @@
|
||||
<refentry id="gdbus" lang="en">
|
||||
|
||||
<refmeta>
|
||||
<refentrytitle>gdbus</refentrytitle>
|
||||
<manvolnum>1</manvolnum>
|
||||
<refmiscinfo class="manual">User Commands</refmiscinfo>
|
||||
</refmeta>
|
||||
|
||||
<refnamediv>
|
||||
<refname>gdbus</refname>
|
||||
<refpurpose>Introspect and call remote objects</refpurpose>
|
||||
</refnamediv>
|
||||
|
||||
<refsynopsisdiv>
|
||||
<cmdsynopsis>
|
||||
<command>gdbus</command>
|
||||
<arg choice="plain">introspect</arg>
|
||||
<group>
|
||||
<arg choice="plain">--system</arg>
|
||||
<arg choice="plain">--session</arg>
|
||||
<arg choice="plain">--address <replaceable>address</replaceable></arg>
|
||||
</group>
|
||||
<arg choice="plain">--dest <replaceable>bus_name</replaceable></arg>
|
||||
<arg choice="plain">--object-path <replaceable>/path/to/object</replaceable></arg>
|
||||
</cmdsynopsis>
|
||||
<cmdsynopsis>
|
||||
<command>gdbus</command>
|
||||
<arg choice="plain">monitor</arg>
|
||||
<group>
|
||||
<arg choice="plain">--system</arg>
|
||||
<arg choice="plain">--session</arg>
|
||||
<arg choice="plain">--address <replaceable>address</replaceable></arg>
|
||||
</group>
|
||||
<arg choice="plain">--dest <replaceable>bus_name</replaceable></arg>
|
||||
<group>
|
||||
<arg choice="plain">--object-path <replaceable>/path/to/object</replaceable></arg>
|
||||
</group>
|
||||
</cmdsynopsis>
|
||||
<cmdsynopsis>
|
||||
<command>gdbus</command>
|
||||
<arg choice="plain">call</arg>
|
||||
<group>
|
||||
<arg choice="plain">--system</arg>
|
||||
<arg choice="plain">--session</arg>
|
||||
<arg choice="plain">--address <replaceable>address</replaceable></arg>
|
||||
</group>
|
||||
<arg choice="plain">--dest <replaceable>bus_name</replaceable></arg>
|
||||
<arg choice="plain">--object-path <replaceable>/path/to/object</replaceable></arg>
|
||||
<arg choice="plain">--method <replaceable>org.project.InterfaceName.MethodName</replaceable></arg>
|
||||
<arg choice="plain">ARG1</arg>
|
||||
<arg choice="plain" rep="repeat">ARG2</arg>
|
||||
</cmdsynopsis>
|
||||
<cmdsynopsis>
|
||||
<command>gdbus</command>
|
||||
<arg choice="plain">help</arg>
|
||||
</cmdsynopsis>
|
||||
</refsynopsisdiv>
|
||||
|
||||
<refsect1>
|
||||
<title>Description</title>
|
||||
<para>
|
||||
<command>gdbus</command> offers a simple commandline utility for
|
||||
introspecting and calling methods on remote objects.
|
||||
</para>
|
||||
<refsect2>
|
||||
<title>Commands</title>
|
||||
<variablelist>
|
||||
<varlistentry>
|
||||
<term><option>introspect</option></term>
|
||||
<listitem><para>
|
||||
Prints out interfaces and property values for a remote object.
|
||||
For this to work, the owner of the object needs to implement the
|
||||
<literal>org.freedesktop.DBus.Introspectable</literal> interface.
|
||||
</para></listitem>
|
||||
</varlistentry>
|
||||
<varlistentry>
|
||||
<term><option>monitor</option></term>
|
||||
<listitem><para>
|
||||
Monitors one or all objects owned by the owner of
|
||||
<replaceable>bus_name</replaceable>.
|
||||
</para></listitem>
|
||||
</varlistentry>
|
||||
<varlistentry>
|
||||
<term><option>call</option></term>
|
||||
<listitem><para>
|
||||
Invokes a method on a remote object. Each argument to pass to the
|
||||
method must be specified as a serialized
|
||||
<link linkend="GVariant"><type>GVariant</type></link> except that strings do
|
||||
not need explicit quotes. The return values are printed out as
|
||||
serialized <link linkend="GVariant"><type>GVariant</type></link>
|
||||
values.
|
||||
</para></listitem>
|
||||
</varlistentry>
|
||||
<varlistentry>
|
||||
<term><option>help</option></term>
|
||||
<listitem><para>
|
||||
Prints help and exit.
|
||||
</para></listitem>
|
||||
</varlistentry>
|
||||
</variablelist>
|
||||
</refsect2>
|
||||
</refsect1>
|
||||
|
||||
<refsect1>
|
||||
<title>Bash Completion</title>
|
||||
<para>
|
||||
<command>gdbus</command> ships with a bash completion script to
|
||||
complete commands, destinations, bus names, object paths and
|
||||
interface/method names.
|
||||
</para>
|
||||
</refsect1>
|
||||
|
||||
<refsect1>
|
||||
<title>Examples</title>
|
||||
This shows how to introspect an object - note that the value of each
|
||||
property is displayed:
|
||||
<programlisting>
|
||||
$ gdbus introspect --system \
|
||||
--dest org.freedesktop.NetworkManager \
|
||||
--object-path /org/freedesktop/NetworkManager/Devices/0
|
||||
node /org/freedesktop/NetworkManager/Devices/0 {
|
||||
interface org.freedesktop.DBus.Introspectable {
|
||||
methods:
|
||||
Introspect(out s data);
|
||||
};
|
||||
interface org.freedesktop.DBus.Properties {
|
||||
methods:
|
||||
Get(in s interface,
|
||||
in s propname,
|
||||
out v value);
|
||||
Set(in s interface,
|
||||
in s propname,
|
||||
in v value);
|
||||
GetAll(in s interface,
|
||||
out a{sv} props);
|
||||
};
|
||||
interface org.freedesktop.NetworkManager.Device.Wired {
|
||||
signals:
|
||||
PropertiesChanged(a{sv} arg_0);
|
||||
properties:
|
||||
readonly b Carrier = false;
|
||||
readonly u Speed = 0;
|
||||
readonly s HwAddress = '00:1D:72:88:BE:97';
|
||||
};
|
||||
interface org.freedesktop.NetworkManager.Device {
|
||||
methods:
|
||||
Disconnect();
|
||||
signals:
|
||||
StateChanged(u arg_0,
|
||||
u arg_1,
|
||||
u arg_2);
|
||||
properties:
|
||||
readonly u DeviceType = 1;
|
||||
readonly b Managed = true;
|
||||
readwrite o Ip6Config = '/';
|
||||
readwrite o Dhcp4Config = '/';
|
||||
readwrite o Ip4Config = '/';
|
||||
readonly u State = 2;
|
||||
readwrite u Ip4Address = 0;
|
||||
readonly u Capabilities = 3;
|
||||
readonly s Driver = 'e1000e';
|
||||
readwrite s Interface = 'eth0';
|
||||
readonly s Udi = '/sys/devices/pci0000:00/0000:00:19.0/net/eth0';
|
||||
};
|
||||
};
|
||||
</programlisting>
|
||||
<para>
|
||||
In a similar fashion, the <option>introspect</option> command can be
|
||||
used to learn details about the <literal>Notify</literal> method:
|
||||
</para>
|
||||
<programlisting>
|
||||
[...]
|
||||
interface org.freedesktop.Notifications {
|
||||
methods:
|
||||
GetServerInformation(out s return_name,
|
||||
out s return_vendor,
|
||||
out s return_version,
|
||||
out s return_spec_version);
|
||||
GetCapabilities(out as return_caps);
|
||||
CloseNotification(in u id);
|
||||
Notify(in s app_name,
|
||||
in u id,
|
||||
in s icon,
|
||||
in s summary,
|
||||
in s body,
|
||||
in as actions,
|
||||
in a{sv} hints,
|
||||
in i timeout,
|
||||
out u return_id);
|
||||
};
|
||||
[...]
|
||||
</programlisting>
|
||||
<para>
|
||||
With this information, it's easy to use the <option>call</option>
|
||||
command to display a notification
|
||||
</para>
|
||||
<programlisting>
|
||||
$ gdbus call --session \
|
||||
--dest org.freedesktop.Notifications \
|
||||
--object-path /org/freedesktop/Notifications \
|
||||
--method org.freedesktop.Notifications.Notify \
|
||||
my_app_name \
|
||||
42 \
|
||||
gtk-dialog-info \
|
||||
"The Summary" \
|
||||
"Here's the body of the notification" \
|
||||
[] \
|
||||
{} \
|
||||
5000
|
||||
(uint32 12,)
|
||||
</programlisting>
|
||||
<para>
|
||||
Monitoring all objects on a service:
|
||||
</para>
|
||||
<programlisting>
|
||||
$ gdbus monitor --system --dest org.freedesktop.ConsoleKit
|
||||
Monitoring signals from all objects owned by org.freedesktop.ConsoleKit
|
||||
The name org.freedesktop.ConsoleKit is owned by :1.15
|
||||
/org/freedesktop/ConsoleKit/Session2: org.freedesktop.ConsoleKit.Session.ActiveChanged (false,)
|
||||
/org/freedesktop/ConsoleKit/Seat1: org.freedesktop.ConsoleKit.Seat.ActiveSessionChanged ('',)
|
||||
/org/freedesktop/ConsoleKit/Session2: org.freedesktop.ConsoleKit.Session.ActiveChanged (true,)
|
||||
/org/freedesktop/ConsoleKit/Seat1: org.freedesktop.ConsoleKit.Seat.ActiveSessionChanged ('/org/freedesktop/ConsoleKit/Session2',)
|
||||
</programlisting>
|
||||
<para>
|
||||
Monitoring a single object on a service:
|
||||
</para>
|
||||
<programlisting>
|
||||
$ gdbus monitor --system --dest org.freedesktop.NetworkManager --object-path /org/freedesktop/NetworkManager/AccessPoint/4141
|
||||
Monitoring signals on object /org/freedesktop/NetworkManager/AccessPoint/4141 owned by org.freedesktop.NetworkManager
|
||||
The name org.freedesktop.NetworkManager is owned by :1.5
|
||||
/org/freedesktop/NetworkManager/AccessPoint/4141: org.freedesktop.NetworkManager.AccessPoint.PropertiesChanged ({'Strength': <byte 0x5c>},)
|
||||
/org/freedesktop/NetworkManager/AccessPoint/4141: org.freedesktop.NetworkManager.AccessPoint.PropertiesChanged ({'Strength': <byte 0x64>},)
|
||||
/org/freedesktop/NetworkManager/AccessPoint/4141: org.freedesktop.NetworkManager.AccessPoint.PropertiesChanged ({'Strength': <byte 0x5e>},)
|
||||
/org/freedesktop/NetworkManager/AccessPoint/4141: org.freedesktop.NetworkManager.AccessPoint.PropertiesChanged ({'Strength': <byte 0x64>},)
|
||||
</programlisting>
|
||||
|
||||
</refsect1>
|
||||
|
||||
<refsect1>
|
||||
<title>AUTHOR</title>
|
||||
<para>
|
||||
Written by David Zeuthen <email>zeuthen@gmail.com</email> with
|
||||
a lot of help from many others.
|
||||
</para>
|
||||
</refsect1>
|
||||
|
||||
<refsect1>
|
||||
<title>BUGS</title>
|
||||
<para>
|
||||
Please send bug reports to either the distribution bug tracker
|
||||
or the upstream bug tracker at
|
||||
<ulink url="https://bugzilla.gnome.org/enter_bug.cgi?product=glib"/>.
|
||||
</para>
|
||||
</refsect1>
|
||||
|
||||
<refsect1>
|
||||
<title>SEE ALSO</title>
|
||||
<para>
|
||||
<citerefentry>
|
||||
<refentrytitle>dbus-send</refentrytitle><manvolnum>1</manvolnum>
|
||||
</citerefentry>
|
||||
</para>
|
||||
</refsect1>
|
||||
|
||||
</refentry>
|
||||
|
@ -107,9 +107,11 @@
|
||||
<xi:include href="xml/gsocketcontrolmessage.xml"/>
|
||||
<xi:include href="xml/gunixfdlist.xml"/>
|
||||
<xi:include href="xml/gunixfdmessage.xml"/>
|
||||
<xi:include href="xml/gcredentials.xml"/>
|
||||
<xi:include href="xml/gunixcredentialsmessage.xml"/>
|
||||
</chapter>
|
||||
<chapter id="highlevel-socket">
|
||||
<title>Highlevel network support</title>
|
||||
<title>Highlevel network functionallity</title>
|
||||
<xi:include href="xml/gsocketclient.xml"/>
|
||||
<xi:include href="xml/gsocketconnection.xml"/>
|
||||
<xi:include href="xml/gunixconnection.xml"/>
|
||||
@ -125,6 +127,25 @@
|
||||
<xi:include href="xml/gnetworkservice.xml"/>
|
||||
<xi:include href="xml/gsrvtarget.xml"/>
|
||||
</chapter>
|
||||
<chapter id="gdbus-lowlevel">
|
||||
<title>Lowlevel D-Bus Support</title>
|
||||
<xi:include href="xml/gdbusutils.xml"/>
|
||||
<xi:include href="xml/gdbusaddress.xml"/>
|
||||
<xi:include href="xml/gdbusintrospection.xml"/>
|
||||
<xi:include href="xml/gdbuserror.xml"/>
|
||||
<xi:include href="xml/gdbusmessage.xml"/>
|
||||
<xi:include href="xml/gdbusconnection.xml"/>
|
||||
<xi:include href="xml/gdbusmethodinvocation.xml"/>
|
||||
<xi:include href="xml/gdbusserver.xml"/>
|
||||
<xi:include href="xml/gdbusauthobserver.xml"/>
|
||||
</chapter>
|
||||
<chapter id="gdbus-convenience">
|
||||
<title>Highlevel D-Bus Support</title>
|
||||
<xi:include href="xml/gdbusnameowning.xml"/>
|
||||
<xi:include href="xml/gdbusnamewatching.xml"/>
|
||||
<xi:include href="xml/gdbusproxywatching.xml"/>
|
||||
<xi:include href="xml/gdbusproxy.xml"/>
|
||||
</chapter>
|
||||
<chapter id="utils">
|
||||
<title>Utilities</title>
|
||||
<xi:include href="xml/gfilenamecompleter.xml"/>
|
||||
@ -146,10 +167,17 @@
|
||||
<xi:include href="gsettings.xml"/>
|
||||
<xi:include href="glib-compile-schemas.xml"/>
|
||||
<xi:include href="gsettings-schema-convert.xml"/>
|
||||
<xi:include href="gdbus.xml"/>
|
||||
</chapter>
|
||||
</part>
|
||||
|
||||
<xi:include href="xml/migrating.xml"/>
|
||||
<part id="migrating">
|
||||
<title>Migrating to GIO</title>
|
||||
<xi:include href="xml/migrating-posix.xml"/>
|
||||
<xi:include href="xml/migrating-gnome-vfs.xml"/>
|
||||
<xi:include href="xml/migrating-gconf.xml"/>
|
||||
<xi:include href="xml/migrating-gdbus.xml"/>
|
||||
</part>
|
||||
|
||||
<chapter id="gio-hierarchy">
|
||||
<title>Object Hierarchy</title>
|
||||
|
@ -1804,6 +1804,12 @@ GTcpConnection
|
||||
g_tcp_connection_set_graceful_disconnect
|
||||
g_tcp_connection_get_graceful_disconnect
|
||||
<SUBSECTION>
|
||||
GUnixConnection
|
||||
g_unix_connection_receive_fd
|
||||
g_unix_connection_send_fd
|
||||
g_unix_connection_receive_credentials
|
||||
g_unix_connection_send_credentials
|
||||
<SUBSECTION>
|
||||
g_socket_connection_factory_create_connection
|
||||
g_socket_connection_factory_lookup_type
|
||||
g_socket_connection_factory_register_type
|
||||
@ -2173,3 +2179,383 @@ G_SETTINGS_SCHEMA_GET_CLASS
|
||||
<SUBSECTION Private>
|
||||
g_settings_get_type
|
||||
</SECTION>
|
||||
|
||||
<SECTION>
|
||||
<FILE>gunixcredentialsmessage</FILE>
|
||||
<TITLE>GUnixCredentialsMessage</TITLE>
|
||||
GUnixCredentialsMessage
|
||||
GUnixCredentialsMessageClass
|
||||
g_unix_credentials_message_new
|
||||
g_unix_credentials_message_new_with_credentials
|
||||
g_unix_credentials_message_get_credentials
|
||||
g_unix_credentials_message_is_supported
|
||||
<SUBSECTION Standard>
|
||||
G_IS_UNIX_CREDENTIALS_MESSAGE
|
||||
G_IS_UNIX_CREDENTIALS_MESSAGE_CLASS
|
||||
G_TYPE_UNIX_CREDENTIALS_MESSAGE
|
||||
G_UNIX_CREDENTIALS_MESSAGE
|
||||
G_UNIX_CREDENTIALS_MESSAGE_CLASS
|
||||
G_UNIX_CREDENTIALS_MESSAGE_GET_CLASS
|
||||
<SUBSECTION Private>
|
||||
GUnixCredentialsMessagePrivate
|
||||
g_unix_credentials_message_get_type
|
||||
</SECTION>
|
||||
|
||||
<SECTION>
|
||||
<FILE>gcredentials</FILE>
|
||||
<TITLE>GCredentials</TITLE>
|
||||
GCredentials
|
||||
GCredentialsClass
|
||||
g_credentials_new
|
||||
g_credentials_to_string
|
||||
g_credentials_get_native
|
||||
g_credentials_set_native
|
||||
g_credentials_is_same_user
|
||||
g_credentials_get_unix_user
|
||||
g_credentials_set_unix_user
|
||||
<SUBSECTION Standard>
|
||||
G_CREDENTIALS
|
||||
G_IS_CREDENTIALS
|
||||
G_TYPE_CREDENTIALS
|
||||
g_credentials_get_type
|
||||
G_CREDENTIALS_CLASS
|
||||
G_IS_CREDENTIALS_CLASS
|
||||
G_CREDENTIALS_GET_CLASS
|
||||
</SECTION>
|
||||
|
||||
<SECTION>
|
||||
<FILE>gdbusaddress</FILE>
|
||||
g_dbus_is_address
|
||||
g_dbus_is_supported_address
|
||||
g_dbus_address_get_stream
|
||||
g_dbus_address_get_stream_finish
|
||||
g_dbus_address_get_stream_sync
|
||||
g_dbus_address_get_for_bus_sync
|
||||
</SECTION>
|
||||
|
||||
<SECTION>
|
||||
<FILE>gdbusutils</FILE>
|
||||
g_dbus_generate_guid
|
||||
g_dbus_is_guid
|
||||
g_dbus_is_name
|
||||
g_dbus_is_unique_name
|
||||
g_dbus_is_member_name
|
||||
g_dbus_is_interface_name
|
||||
</SECTION>
|
||||
|
||||
<SECTION>
|
||||
<FILE>gdbusauthobserver</FILE>
|
||||
<TITLE>GDBusAuthObserver</TITLE>
|
||||
GDBusAuthObserver
|
||||
GDBusAuthObserverClass
|
||||
g_dbus_auth_observer_new
|
||||
g_dbus_auth_observer_authorize_authenticated_peer
|
||||
<SUBSECTION Standard>
|
||||
G_DBUS_AUTH_OBSERVER
|
||||
G_IS_DBUS_AUTH_OBSERVER
|
||||
G_TYPE_DBUS_AUTH_OBSERVER
|
||||
g_dbus_server_get_gtype
|
||||
G_DBUS_AUTH_OBSERVER_CLASS
|
||||
G_IS_DBUS_AUTH_OBSERVER_CLASS
|
||||
G_DBUS_AUTH_OBSERVER_GET_CLASS
|
||||
</SECTION>
|
||||
|
||||
<SECTION>
|
||||
<FILE>gdbusserver</FILE>
|
||||
<TITLE>GDBusServer</TITLE>
|
||||
GDBusServer
|
||||
GDBusServerClass
|
||||
GDBusServerFlags
|
||||
g_dbus_server_new_sync
|
||||
g_dbus_server_start
|
||||
g_dbus_server_stop
|
||||
g_dbus_server_is_active
|
||||
g_dbus_server_get_guid
|
||||
g_dbus_server_get_flags
|
||||
g_dbus_server_get_client_address
|
||||
<SUBSECTION Standard>
|
||||
G_DBUS_SERVER
|
||||
G_IS_DBUS_SERVER
|
||||
G_TYPE_DBUS_SERVER
|
||||
g_dbus_server_get_gtype
|
||||
G_DBUS_SERVER_CLASS
|
||||
G_IS_DBUS_SERVER_CLASS
|
||||
G_DBUS_SERVER_GET_CLASS
|
||||
</SECTION>
|
||||
|
||||
<SECTION>
|
||||
<FILE>gdbusmessage</FILE>
|
||||
<TITLE>GDBusMessage</TITLE>
|
||||
GDBusMessageType
|
||||
GDBusMessageFlags
|
||||
GDBusMessageHeaderField
|
||||
GDBusMessage
|
||||
GDBusMessageClass
|
||||
g_dbus_message_new
|
||||
g_dbus_message_new_signal
|
||||
g_dbus_message_new_method_call
|
||||
g_dbus_message_new_method_reply
|
||||
g_dbus_message_new_method_error
|
||||
g_dbus_message_new_method_error_valist
|
||||
g_dbus_message_new_method_error_literal
|
||||
g_dbus_message_print
|
||||
g_dbus_message_get_message_type
|
||||
g_dbus_message_set_message_type
|
||||
g_dbus_message_get_serial
|
||||
g_dbus_message_set_serial
|
||||
g_dbus_message_get_flags
|
||||
g_dbus_message_set_flags
|
||||
g_dbus_message_get_body
|
||||
g_dbus_message_set_body
|
||||
g_dbus_message_get_unix_fd_list
|
||||
g_dbus_message_set_unix_fd_list
|
||||
g_dbus_message_get_header_fields
|
||||
g_dbus_message_get_header
|
||||
g_dbus_message_set_header
|
||||
g_dbus_message_get_destination
|
||||
g_dbus_message_set_destination
|
||||
g_dbus_message_get_error_name
|
||||
g_dbus_message_set_error_name
|
||||
g_dbus_message_get_interface
|
||||
g_dbus_message_set_interface
|
||||
g_dbus_message_get_member
|
||||
g_dbus_message_set_member
|
||||
g_dbus_message_get_path
|
||||
g_dbus_message_set_path
|
||||
g_dbus_message_get_reply_serial
|
||||
g_dbus_message_set_reply_serial
|
||||
g_dbus_message_get_sender
|
||||
g_dbus_message_set_sender
|
||||
g_dbus_message_get_signature
|
||||
g_dbus_message_set_signature
|
||||
g_dbus_message_get_arg0
|
||||
g_dbus_message_to_blob
|
||||
g_dbus_message_bytes_needed
|
||||
g_dbus_message_new_from_blob
|
||||
g_dbus_message_to_gerror
|
||||
<SUBSECTION Standard>
|
||||
G_DBUS_MESSAGE
|
||||
G_IS_DBUS_MESSAGE
|
||||
G_TYPE_DBUS_MESSAGE
|
||||
g_dbus_message_get_type
|
||||
G_DBUS_MESSAGE_CLASS
|
||||
G_IS_DBUS_MESSAGE_CLASS
|
||||
G_DBUS_MESSAGE_GET_CLASS
|
||||
</SECTION>
|
||||
|
||||
<SECTION>
|
||||
<FILE>gdbusconnection</FILE>
|
||||
<TITLE>GDBusConnection</TITLE>
|
||||
GBusType
|
||||
g_bus_get
|
||||
g_bus_get_finish
|
||||
g_bus_get_sync
|
||||
GDBusConnection
|
||||
GDBusConnectionClass
|
||||
GDBusConnectionFlags
|
||||
g_dbus_connection_new
|
||||
g_dbus_connection_new_finish
|
||||
g_dbus_connection_new_sync
|
||||
g_dbus_connection_new_for_address
|
||||
g_dbus_connection_new_for_address_finish
|
||||
g_dbus_connection_new_for_address_sync
|
||||
GDBusCapabilityFlags
|
||||
g_dbus_connection_close
|
||||
g_dbus_connection_is_closed
|
||||
g_dbus_connection_get_exit_on_close
|
||||
g_dbus_connection_set_exit_on_close
|
||||
g_dbus_connection_get_stream
|
||||
g_dbus_connection_get_guid
|
||||
g_dbus_connection_get_unique_name
|
||||
g_dbus_connection_get_capabilities
|
||||
g_dbus_connection_get_peer_credentials
|
||||
GDBusCallFlags
|
||||
g_dbus_connection_call
|
||||
g_dbus_connection_call_finish
|
||||
g_dbus_connection_call_sync
|
||||
g_dbus_connection_emit_signal
|
||||
GDBusSignalCallback
|
||||
g_dbus_connection_signal_subscribe
|
||||
g_dbus_connection_signal_unsubscribe
|
||||
g_dbus_connection_send_message
|
||||
g_dbus_connection_send_message_with_reply
|
||||
g_dbus_connection_send_message_with_reply_finish
|
||||
g_dbus_connection_send_message_with_reply_sync
|
||||
GDBusMessageFilterFunction
|
||||
g_dbus_connection_add_filter
|
||||
g_dbus_connection_remove_filter
|
||||
GDBusInterfaceVTable
|
||||
GDBusInterfaceMethodCallFunc
|
||||
GDBusInterfaceGetPropertyFunc
|
||||
GDBusInterfaceSetPropertyFunc
|
||||
g_dbus_connection_register_object
|
||||
g_dbus_connection_unregister_object
|
||||
GDBusSubtreeVTable
|
||||
GDBusSubtreeEnumerateFunc
|
||||
GDBusSubtreeIntrospectFunc
|
||||
GDBusSubtreeDispatchFunc
|
||||
GDBusSubtreeFlags
|
||||
g_dbus_connection_register_subtree
|
||||
g_dbus_connection_unregister_subtree
|
||||
<SUBSECTION Standard>
|
||||
G_DBUS_CONNECTION
|
||||
G_IS_DBUS_CONNECTION
|
||||
G_TYPE_DBUS_CONNECTION
|
||||
g_dbus_connection_get_type
|
||||
G_DBUS_CONNECTION_CLASS
|
||||
G_IS_DBUS_CONNECTION_CLASS
|
||||
G_DBUS_CONNECTION_GET_CLASS
|
||||
</SECTION>
|
||||
|
||||
<SECTION>
|
||||
<FILE>gdbusmethodinvocation</FILE>
|
||||
<TITLE>GDBusMethodInvocation</TITLE>
|
||||
GDBusMethodInvocation
|
||||
GDBusMethodInvocationClass
|
||||
g_dbus_method_invocation_new
|
||||
g_dbus_method_invocation_get_sender
|
||||
g_dbus_method_invocation_get_object_path
|
||||
g_dbus_method_invocation_get_interface_name
|
||||
g_dbus_method_invocation_get_method_name
|
||||
g_dbus_method_invocation_get_method_info
|
||||
g_dbus_method_invocation_get_connection
|
||||
g_dbus_method_invocation_get_message
|
||||
g_dbus_method_invocation_get_parameters
|
||||
g_dbus_method_invocation_get_user_data
|
||||
g_dbus_method_invocation_return_value
|
||||
g_dbus_method_invocation_return_error
|
||||
g_dbus_method_invocation_return_error_valist
|
||||
g_dbus_method_invocation_return_error_literal
|
||||
g_dbus_method_invocation_return_gerror
|
||||
g_dbus_method_invocation_return_dbus_error
|
||||
<SUBSECTION Standard>
|
||||
G_DBUS_METHOD_INVOCATION
|
||||
G_IS_DBUS_METHOD_INVOCATION
|
||||
G_TYPE_DBUS_METHOD_INVOCATION
|
||||
g_dbus_method_invocation_get_type
|
||||
G_DBUS_METHOD_INVOCATION_CLASS
|
||||
G_IS_DBUS_METHOD_INVOCATION_CLASS
|
||||
G_DBUS_METHOD_INVOCATION_GET_CLASS
|
||||
</SECTION>
|
||||
|
||||
<SECTION>
|
||||
<FILE>gdbusnameowning</FILE>
|
||||
GBusAcquiredCallback
|
||||
GBusNameAcquiredCallback
|
||||
GBusNameLostCallback
|
||||
GBusNameOwnerFlags
|
||||
g_bus_own_name
|
||||
g_bus_own_name_on_connection
|
||||
g_bus_unown_name
|
||||
</SECTION>
|
||||
|
||||
<SECTION>
|
||||
<FILE>gdbusnamewatching</FILE>
|
||||
GBusNameAppearedCallback
|
||||
GBusNameVanishedCallback
|
||||
GBusNameWatcherFlags
|
||||
g_bus_watch_name
|
||||
g_bus_watch_name_on_connection
|
||||
g_bus_unwatch_name
|
||||
</SECTION>
|
||||
|
||||
<SECTION>
|
||||
<FILE>gdbusproxywatching</FILE>
|
||||
GBusProxyAppearedCallback
|
||||
GBusProxyVanishedCallback
|
||||
g_bus_watch_proxy
|
||||
g_bus_watch_proxy_on_connection
|
||||
g_bus_unwatch_proxy
|
||||
</SECTION>
|
||||
|
||||
<SECTION>
|
||||
<FILE>gdbuserror</FILE>
|
||||
GDBusError
|
||||
G_DBUS_ERROR
|
||||
g_dbus_error_is_remote_error
|
||||
g_dbus_error_get_remote_error
|
||||
g_dbus_error_strip_remote_error
|
||||
GDBusErrorEntry
|
||||
g_dbus_error_register_error_domain
|
||||
g_dbus_error_register_error
|
||||
g_dbus_error_unregister_error
|
||||
g_dbus_error_new_for_dbus_error
|
||||
g_dbus_error_set_dbus_error
|
||||
g_dbus_error_set_dbus_error_valist
|
||||
g_dbus_error_encode_gerror
|
||||
</SECTION>
|
||||
|
||||
<SECTION>
|
||||
<FILE>gdbusproxy</FILE>
|
||||
<TITLE>GDBusProxy</TITLE>
|
||||
GDBusProxyFlags
|
||||
GDBusProxy
|
||||
GDBusProxyClass
|
||||
g_dbus_proxy_new
|
||||
g_dbus_proxy_new_finish
|
||||
g_dbus_proxy_new_sync
|
||||
g_dbus_proxy_get_flags
|
||||
g_dbus_proxy_get_connection
|
||||
g_dbus_proxy_get_unique_bus_name
|
||||
g_dbus_proxy_get_object_path
|
||||
g_dbus_proxy_get_interface_name
|
||||
g_dbus_proxy_get_default_timeout
|
||||
g_dbus_proxy_set_default_timeout
|
||||
g_dbus_proxy_get_cached_property
|
||||
g_dbus_proxy_set_cached_property
|
||||
g_dbus_proxy_get_cached_property_names
|
||||
g_dbus_proxy_set_interface_info
|
||||
g_dbus_proxy_get_interface_info
|
||||
g_dbus_proxy_call
|
||||
g_dbus_proxy_call_finish
|
||||
g_dbus_proxy_call_sync
|
||||
<SUBSECTION Standard>
|
||||
G_DBUS_PROXY
|
||||
G_IS_DBUS_PROXY
|
||||
G_TYPE_DBUS_PROXY
|
||||
g_dbus_proxy_get_type
|
||||
G_DBUS_PROXY_CLASS
|
||||
G_IS_DBUS_PROXY_CLASS
|
||||
G_DBUS_PROXY_GET_CLASS
|
||||
</SECTION>
|
||||
|
||||
<SECTION>
|
||||
<FILE>gdbusintrospection</FILE>
|
||||
GDBusAnnotationInfo
|
||||
GDBusArgInfo
|
||||
GDBusMethodInfo
|
||||
GDBusSignalInfo
|
||||
GDBusPropertyInfoFlags
|
||||
GDBusPropertyInfo
|
||||
GDBusInterfaceInfo
|
||||
GDBusNodeInfo
|
||||
g_dbus_annotation_info_lookup
|
||||
g_dbus_interface_info_lookup_method
|
||||
g_dbus_interface_info_lookup_signal
|
||||
g_dbus_interface_info_lookup_property
|
||||
g_dbus_interface_info_generate_xml
|
||||
g_dbus_node_info_new_for_xml
|
||||
g_dbus_node_info_lookup_interface
|
||||
g_dbus_node_info_generate_xml
|
||||
G_TYPE_DBUS_NODE_INFO
|
||||
G_TYPE_DBUS_INTERFACE_INFO
|
||||
G_TYPE_DBUS_METHOD_INFO
|
||||
G_TYPE_DBUS_SIGNAL_INFO
|
||||
G_TYPE_DBUS_PROPERTY_INFO
|
||||
G_TYPE_DBUS_ARG_INFO
|
||||
G_TYPE_DBUS_ANNOTATION_INFO
|
||||
g_dbus_node_info_ref
|
||||
g_dbus_interface_info_ref
|
||||
g_dbus_method_info_ref
|
||||
g_dbus_signal_info_ref
|
||||
g_dbus_property_info_ref
|
||||
g_dbus_arg_info_ref
|
||||
g_dbus_annotation_info_ref
|
||||
g_dbus_node_info_unref
|
||||
g_dbus_interface_info_unref
|
||||
g_dbus_method_info_unref
|
||||
g_dbus_signal_info_unref
|
||||
g_dbus_property_info_unref
|
||||
g_dbus_arg_info_unref
|
||||
g_dbus_annotation_info_unref
|
||||
</SECTION>
|
||||
|
@ -107,3 +107,14 @@ g_volume_monitor_get_type
|
||||
g_zlib_compressor_get_type
|
||||
g_zlib_compressor_format_get_type
|
||||
g_zlib_decompressor_get_type
|
||||
g_dbus_message_get_type
|
||||
g_dbus_connection_get_type
|
||||
g_bus_type_get_type
|
||||
g_bus_name_owner_flags_get_type
|
||||
g_dbus_error_get_type
|
||||
g_dbus_proxy_get_type
|
||||
g_dbus_method_invocation_get_type
|
||||
g_dbus_server_get_type
|
||||
g_dbus_auth_observer_get_type
|
||||
g_credentials_get_type
|
||||
g_unix_credentials_message_get_type
|
||||
|
418
docs/reference/gio/migrating-gconf.xml
Normal file
418
docs/reference/gio/migrating-gconf.xml
Normal file
@ -0,0 +1,418 @@
|
||||
<chapter>
|
||||
<title>Migrating from GConf to GSettings</title>
|
||||
|
||||
<section>
|
||||
<title>Before you start</title>
|
||||
|
||||
<para>
|
||||
Converting individual applications and their settings from GConf to
|
||||
GSettings can be done at will. But desktop-wide settings like font or
|
||||
theme settings often have consumers in multiple modules. Therefore,
|
||||
some consideration has to go into making sure that all users of a setting
|
||||
are converted to GSettings at the same time or that the program
|
||||
responsible for configuring that setting continues to update the value in
|
||||
both places.
|
||||
</para>
|
||||
<para>
|
||||
It is always a good idea to have a look at how others have handled
|
||||
similar problems before. An examplaric conversion can be found e.g.
|
||||
in the <ulink url="http://git.gnome.org/browse/gnome-utils/log/?h=gsettings-tutorial">gsettings-tutorial</ulink> branch of gnome-utils.
|
||||
</para>
|
||||
</section>
|
||||
|
||||
<section>
|
||||
<title>Conceptual differences</title>
|
||||
|
||||
<para>
|
||||
Conceptually, GConf and GSettings are fairly similar. Both
|
||||
have a concept of pluggable backends. Both keep information
|
||||
about keys and their types in schemas. Both have a concept of
|
||||
mandatory values, which lets you implement lock-down.
|
||||
</para>
|
||||
<para>
|
||||
There are some differences in the approach to schemas. GConf
|
||||
installs the schemas into the database and has API to handle
|
||||
schema information (gconf_client_get_default_from_schema(),
|
||||
gconf_value_get_schema(), etc). GSettings on the other hand
|
||||
assumes that an application knows its own schemas, and does
|
||||
not provide API to handle schema information at runtime.
|
||||
GSettings is also more strict about requiring a schema whenever
|
||||
you want to read or write a key. To deal with more free-form
|
||||
information that would appear in schema-less entries in GConf,
|
||||
GSettings allows for schemas to be 'relocatable'.
|
||||
</para>
|
||||
<para>
|
||||
One difference in the way applications interact with their
|
||||
settings is that with GConf you interact with a tree of
|
||||
settings (ie the keys you pass to functions when reading
|
||||
or writing values are actually paths with the actual name
|
||||
of the key as the last element. With GSettings, you create
|
||||
a GSettings object which has an implicit prefix that determines
|
||||
where the settings get stored in the global tree of settings,
|
||||
but the keys you pass when reading or writing values are just
|
||||
the key names, not the full path.
|
||||
</para>
|
||||
</section>
|
||||
|
||||
<section>
|
||||
<title>GConfClient (and GConfBridge) API conversion</title>
|
||||
|
||||
<para>
|
||||
Most people use GConf via the high-level #GConfClient API.
|
||||
The corresponding API is the #GSettings object. While not
|
||||
every GConfClient function has a direct GSettings equivalent,
|
||||
many do:
|
||||
<table id="gconf-client-vs-gsettings">
|
||||
<tgroup cols="2">
|
||||
<thead>
|
||||
<row><entry>GConfClient</entry><entry>GSettings</entry></row>
|
||||
</thead>
|
||||
<tbody>
|
||||
<row><entry>gconf_client_get_default()</entry><entry>no direct equivalent,
|
||||
instead you call g_settings_new() for the schemas you use</entry></row>
|
||||
<row><entry>gconf_client_set()</entry><entry>g_settings_set()</entry></row>
|
||||
<row><entry>gconf_client_get()</entry><entry>g_settings_get()</entry></row>
|
||||
<row><entry>gconf_client_get_bool()</entry><entry>g_settings_get_boolean()</entry></row>
|
||||
<row><entry>gconf_client_set_bool()</entry><entry>g_settings_set_boolean()</entry></row>
|
||||
<row><entry>gconf_client_get_int()</entry><entry>g_settings_get_int()</entry></row>
|
||||
<row><entry>gconf_client_set_int()</entry><entry>g_settings_set_int()</entry></row>
|
||||
<row><entry>gconf_client_get_float()</entry><entry>g_settings_get_double()</entry></row>
|
||||
<row><entry>gconf_client_set_float()</entry><entry>g_settings_set_double()</entry></row>
|
||||
<row><entry>gconf_client_get_string()</entry><entry>g_settings_get_string()</entry></row>
|
||||
<row><entry>gconf_client_set_string()</entry><entry>g_settings_set_string()</entry></row>
|
||||
<row><entry>gconf_client_get_list()</entry><entry>for string lists, see g_settings_get_strv(), else see g_settings_get_value() and #GVariant API</entry></row>
|
||||
<row><entry>gconf_client_set_list()</entry><entry>for string lists, see g_settings_set_strv(), else see g_settings_set_value() and #GVariant API</entry></row>
|
||||
<row><entry>gconf_entry_get_is_writable()</entry><entry>g_settings_is_writable()</entry></row>
|
||||
<row><entry>gconf_client_notify_add()</entry><entry>not required, the #GSettings::changed signal is emitted automatically</entry></row>
|
||||
<row><entry>gconf_client_add_dir()</entry><entry>not required, each GSettings instance automatically watches all keys in its path</entry></row>
|
||||
<row><entry>#GConfChangeSet</entry><entry>g_settings_delay(), g_settings_apply()</entry></row>
|
||||
<row><entry>gconf_client_get_default_from_schema()</entry><entry>no equivalent, applications are expected to know their schema</entry></row>
|
||||
<row><entry>gconf_client_all_entries()</entry><entry>no equivalent, applications are expected to know their schema, and GSettings does not allow schema-less entries</entry></row>
|
||||
<row><entry>gconf_client_get_without_default()</entry><entry>no equivalent</entry></row>
|
||||
<row><entry>gconf_bridge_bind_property()</entry><entry>g_settings_bind()</entry></row>
|
||||
<row><entry>gconf_bridge_bind_property_full()</entry><entry>g_settings_bind_with_mapping()</entry></row>
|
||||
</tbody>
|
||||
</tgroup>
|
||||
</table>
|
||||
</para>
|
||||
<para>
|
||||
GConfBridge was a third-party library that used GConf to bind an object property
|
||||
to a particular configuration key. GSettings offers this service itself.
|
||||
</para>
|
||||
<para>
|
||||
There is a pattern that is sometimes used for GConf, where a setting can have
|
||||
explicit 'value A', explicit 'value B' or 'use the system default'. With GConf,
|
||||
'use the system default' is sometimes implemented by unsetting the user value.
|
||||
</para>
|
||||
<para>
|
||||
This is not possible in GSettings, since it does not have API to determine if a value
|
||||
is the default and does not let you unset values. The recommended way (and much
|
||||
clearer) way in which this can be implemented in GSettings is to have a separate
|
||||
'use-system-default' boolean setting.
|
||||
</para>
|
||||
</section>
|
||||
|
||||
<section>
|
||||
<title>Change notification</title>
|
||||
|
||||
<para>
|
||||
GConf requires you to call gconf_client_add_dir() and
|
||||
gconf_client_notify_add() to get change notification. With
|
||||
GSettings, this is not necessary; signals get emitted automatically
|
||||
for every change.
|
||||
</para>
|
||||
<para>
|
||||
The #GSettings::changed signal is emitted for each changed key.
|
||||
There is also a #GSettings::change-event signal that you can handle
|
||||
if you need to see groups of keys that get changed at the same time.
|
||||
</para>
|
||||
<para>
|
||||
GSettings also notifies you about changes in writability of keys,
|
||||
with the #GSettings::writable-changed signal (and the
|
||||
#GSettings::writable-change-event signal).
|
||||
</para>
|
||||
</section>
|
||||
|
||||
<section><title>Change sets</title>
|
||||
<para>
|
||||
GConf has a a concept of a set of changes which can be applied or reverted
|
||||
at once: #GConfChangeSet (GConf doesn't actually apply changes atomically,
|
||||
which is one of its shortcomings).
|
||||
</para>
|
||||
<para>
|
||||
Instead of a separate object to represent a change set, GSettings has a
|
||||
'delayed-apply' mode, which can be turned on for a GSettings object by
|
||||
calling g_settings_delay(). In this mode, changes done to the GSettings
|
||||
object are not applied - they are still visible when calling g_settings_get()
|
||||
<emphasis>on the same object</emphasis>, but not to other GSettings instances
|
||||
or even other processes.
|
||||
</para>
|
||||
<para>
|
||||
To apply the pending changes all at once (GSettings <emphasis>does</emphasis>
|
||||
atomicity here), call g_settings_apply(). To revert the pending changes,
|
||||
call g_settings_revert() or just drop the reference to the #GSettings object.
|
||||
</para>
|
||||
</section>
|
||||
|
||||
<section>
|
||||
<title>Schema conversion</title>
|
||||
|
||||
<para>
|
||||
If you are porting your application from GConf, most likely you already
|
||||
have a GConf schema. GIO comes with a commandline tool
|
||||
<link linkend="gsettings-schema-convert">gsettings-schema-convert</link>
|
||||
that can help with the task of converting a GConf schema into
|
||||
an equivalent GSettings schema. The tool is not perfect and
|
||||
may need assistence in some cases.
|
||||
</para>
|
||||
<example><title>An example for using gsettings-schema-convert</title>
|
||||
<para>Running <userinput>gsettings-schema-convert --gconf --xml --schema-id "org.gnome.font-rendering" --output org.gnome.font-rendering.gschema.xml destop_gnome_font_rendering.schemas</userinput> on the following <filename>desktop_gnome_font_rendering.schemas</filename> file:
|
||||
<programlisting>
|
||||
<![CDATA[
|
||||
<?xml version="1.0"?>
|
||||
<gconfschemafile>
|
||||
<schemalist>
|
||||
<schema>
|
||||
<key>/schemas/desktop/gnome/font_rendering/dpi</key>
|
||||
<applyto>/desktop/gnome/font_rendering/dpi</applyto>
|
||||
<owner>gnome</owner>
|
||||
<type>int</type>
|
||||
<default>96</default>
|
||||
<locale name="C">
|
||||
<short>DPI</short>
|
||||
<long>The resolution used for converting font sizes to pixel sizes, in dots per inch.</long>
|
||||
</locale>
|
||||
</schema>
|
||||
</schemalist>
|
||||
</gconfschemafile>
|
||||
]]>
|
||||
</programlisting>
|
||||
produces a <filename>org.gnome.font-rendering.gschema.xml</filename> file with the following content:
|
||||
<programlisting>
|
||||
<![CDATA[
|
||||
<schemalist>
|
||||
<schema id="org.gnome.font-rendering" path="/desktop/gnome/font_rendering/">
|
||||
<key name="dpi" type="i">
|
||||
<default>96</default>
|
||||
<summary>DPI</summary>
|
||||
<description>The resolution used for converting font sizes to pixel sizes, in dots per inch.</description>
|
||||
</key>
|
||||
</schema>
|
||||
</schemalist>
|
||||
]]>
|
||||
</programlisting>
|
||||
</para>
|
||||
</example>
|
||||
|
||||
<para>
|
||||
GSettings schemas are identified at runtime by their id (as specified
|
||||
in the XML source file). It is recommended to use a dotted name as schema
|
||||
id, similar in style to a DBus bus name, e.g. "org.gnome.font-rendering".
|
||||
The filename used for the XML schema source is immaterial, but
|
||||
schema compiler expects the files to have the extension
|
||||
<filename>.gschema.xml</filename>. It is recommended to simply
|
||||
use the schema id as the filename, followed by this extension,
|
||||
e.g. <filename>org.gnome.font-rendering.gschema.xml</filename>.
|
||||
</para>
|
||||
|
||||
<para>
|
||||
The XML source file for your GSettings schema needs to get installed
|
||||
into <filename>$datadir/glib-2.0/schemas</filename>, and needs to be
|
||||
compiled into a binary form. At runtime, GSettings looks for compiled
|
||||
schemas in the <filename>glib-2.0/schemas</filename> subdirectories
|
||||
of all <envar>XDG_DATA_DIRS</envar> directories, so if you install
|
||||
your schema in a different location, you need to set the
|
||||
<envar>XDG_DATA_DIRS</envar> environment variable appropriately.
|
||||
</para>
|
||||
<para>
|
||||
Schemas are compiled into binary form by the
|
||||
<link linkend="glib-compile-schemas">glib-compile-schemas</link> utility.
|
||||
GIO provides a <literal>gschema_compile</literal>
|
||||
variable for the schema compiler, which can be used in
|
||||
<filename>configure.in</filename> as follows:
|
||||
<programlisting>
|
||||
GLIB_GSETTINGS
|
||||
</programlisting>
|
||||
The corresponding <filename>Makefile.am</filename> fragment looks like
|
||||
this:
|
||||
<programlisting>
|
||||
# gsettingsschemadir and gschema_compile are defined by the GLIB_GSETTINGS
|
||||
# macro in configure.ac
|
||||
gsettingsschema_DATA = my.app.gschema.xml
|
||||
# This rule will check your schemas for validity before installation
|
||||
@GSETTINGS_CHECK_RULE@
|
||||
if GSETTINGS_SCHEMAS_INSTALL
|
||||
install-data-hook:
|
||||
$(GLIB_COMPILE_SCHEMAS) $(DESTDIR)$(gsettingsschemadir)
|
||||
endif
|
||||
</programlisting>
|
||||
</para>
|
||||
|
||||
<para>
|
||||
One possible pitfall in doing schema conversion is that the default
|
||||
values in GSettings schemas are parsed by the #GVariant parser.
|
||||
This means that strings need to include quotes in the XML. Also note
|
||||
that the types are now specified as #GVariant type strings.
|
||||
<programlisting>
|
||||
<![CDATA[
|
||||
<type>string</type>
|
||||
<default>rgb</default>
|
||||
]]>
|
||||
</programlisting>
|
||||
becomes
|
||||
<programlisting>
|
||||
<![CDATA[
|
||||
<key name="rgba-order" type="s">
|
||||
<default>'rgb'</default> <!-- note quotes -->
|
||||
</key>
|
||||
]]>
|
||||
</programlisting>
|
||||
</para>
|
||||
<para>
|
||||
Another possible complication is that GConf specifies full paths
|
||||
for each key, while a GSettings schema has a 'path' attribute that
|
||||
contains the prefix for all the keys in the schema, and individual
|
||||
keys just have a simple name. So
|
||||
<programlisting>
|
||||
<![CDATA[
|
||||
<key>/schemas/desktop/gnome/font_rendering/antialiasing</key>
|
||||
]]>
|
||||
</programlisting>
|
||||
becomes
|
||||
<programlisting>
|
||||
<![CDATA[
|
||||
<schema id="org.gnome.font" path="/desktop/gnome/font_rendering/">
|
||||
<key name="antialiasing" type="s">
|
||||
]]>
|
||||
</programlisting>
|
||||
</para>
|
||||
<para>
|
||||
Default values can be localized in both GConf and GSettings schemas,
|
||||
but GSettings uses gettext for the localization. You can specify
|
||||
the gettext domain to use in the <tag class="attribute">gettext-domain</tag>
|
||||
attribute. Therefore, when converting localized defaults in GConf,
|
||||
<programlisting>
|
||||
<![CDATA[
|
||||
<key>/schemas/apps/my_app/font_size</key>
|
||||
<locale name="C">
|
||||
<default>18</default>
|
||||
</locale>
|
||||
<locale name="be">
|
||||
<default>24</default>
|
||||
</locale>
|
||||
</key>
|
||||
]]>
|
||||
</programlisting>
|
||||
becomes
|
||||
<programlisting>
|
||||
<![CDATA[
|
||||
<schema id="..." gettext-domain="your-domain">
|
||||
...
|
||||
<key name="font-size" type="i">
|
||||
<default l10n="messages" context="font_size">18</default>
|
||||
</key>
|
||||
]]>
|
||||
</programlisting>
|
||||
Note how we used the context attribute to add msgctxt - "18" is not a
|
||||
good string to look up in gettext by itself. Also note that the value
|
||||
24 is not present in the schema anymore. It has to be added to the
|
||||
gettext catalog for "be" instead.
|
||||
</para>
|
||||
<para>
|
||||
GSettings schemas have optional <tag class="starttag">summary</tag> and
|
||||
<tag class="starttag">description</tag> elements for each key which
|
||||
correspond to the <tag class="starttag">short</tag> and
|
||||
<tag class="starttag">long</tag> elements in the GConf schema and
|
||||
will be used in similar ways by a future gsettings-editor, so you
|
||||
should use the same conventions for them: The summary is just a short
|
||||
label with no punctuation, the description can be one or more complete
|
||||
sentences. Translations for these strings will also be handled
|
||||
via gettext, so you should arrange for these strings to be
|
||||
extracted into your gettext catalog.
|
||||
</para>
|
||||
<para>
|
||||
GSettings is a bit more restrictive about key names than GConf. Key
|
||||
names in GSettings can be at most 32 characters long, and must only
|
||||
consist of lowercase characters, numbers and dashes, with no
|
||||
consecutive dashes. The first character must not be a number or dash,
|
||||
and the last character cannot be '-'.
|
||||
</para>
|
||||
<para>
|
||||
If you are using the GConf backend for GSettings during the
|
||||
transition, you may want to keep your key names the same they
|
||||
were in GConf, so that existing settings in the users GConf
|
||||
database are preserved. You can achieve this by using the
|
||||
<option>--allow-any-name</option> with the
|
||||
<link linkend="glib-compile-schemas">glib-compile-schemas</link> schema
|
||||
compiler. Note that this option is only meant
|
||||
to ease the process of porting your application, allowing parts
|
||||
of your application to continue to access GConf and parts to use
|
||||
GSettings. By the time you have finished porting your application
|
||||
you must ensure that all key names are valid.
|
||||
</para>
|
||||
</section>
|
||||
|
||||
<section><title>Data conversion</title>
|
||||
<para>
|
||||
GConf comes with a GSettings backend that can be used to
|
||||
facility the transition to the GSettings API until you are
|
||||
ready to make the jump to a different backend (most likely
|
||||
dconf). To use it, you need to set the <envar>GSETTINGS_BACKEND</envar>
|
||||
to 'gconf', e.g. by using
|
||||
<programlisting>
|
||||
g_setenv ("GSETTINGS_BACKEND", "gconf", TRUE);
|
||||
</programlisting>
|
||||
early on in your program. Note that this backend is meant purely
|
||||
as a transition tool, and should not be used in production.
|
||||
</para>
|
||||
<para>
|
||||
GConf also comes with a utility called
|
||||
<command>gsettings-data-convert</command>, which is designed to help
|
||||
with the task of migrating user settings from GConf into another
|
||||
GSettings backend. It can be run manually, but it is designed to be
|
||||
executed automatically, every time a user logs in. It keeps track of
|
||||
the data migrations that it has already done, and it is harmless to
|
||||
run it more than once.
|
||||
</para>
|
||||
<para>
|
||||
To make use of this utility, you must install a keyfile in the
|
||||
directory <filename>/usr/share/GConf/gsettings</filename> which
|
||||
lists the GSettings keys and GConf paths to map to each other, for
|
||||
each schema that you want to migrate user data for.
|
||||
</para>
|
||||
<para>
|
||||
Here is an example:
|
||||
<programlisting>
|
||||
<![CDATA[
|
||||
[org.gnome.fonts]
|
||||
antialiasing = /desktop/gnome/font_rendering/antialiasing
|
||||
dpi = /desktop/gnome/font_rendering/dpi
|
||||
hinting = /desktop/gnome/font_rendering/hinting
|
||||
rgba-order = /desktop/gnome/font_rendering/rgba_order
|
||||
|
||||
[apps.myapp:/path/to/myapps/]
|
||||
some-odd-key1 = /apps/myapp/some_ODD-key1
|
||||
]]>
|
||||
</programlisting>
|
||||
The last key demonstrates that it may be necessary to modify the key
|
||||
name to comply with stricter GSettings key name rules. Of course,
|
||||
that means your application must use the new key names when looking
|
||||
up settings in GSettings.
|
||||
</para>
|
||||
<para>
|
||||
The last group in the example also shows how to handle the case
|
||||
of 'relocatable' schemas, which don't have a fixed path. You can
|
||||
specify the path to use in the group name, separated by a colon.
|
||||
</para>
|
||||
<para>
|
||||
There are some limitations: <command>gsettings-data-convert</command>
|
||||
does not do any transformation of the values. And it does not handle
|
||||
complex GConf types other than lists of strings or integers.
|
||||
</para>
|
||||
<para>
|
||||
Don't forget to require GConf 2.31.1 or newer in your configure
|
||||
script if you are making use of the GConf backend or the conversion
|
||||
utility.
|
||||
</para>
|
||||
</section>
|
||||
</chapter>
|
358
docs/reference/gio/migrating-gdbus.xml
Normal file
358
docs/reference/gio/migrating-gdbus.xml
Normal file
@ -0,0 +1,358 @@
|
||||
<chapter>
|
||||
<title>Migrating from dbus-glib to GDBus</title>
|
||||
|
||||
<section>
|
||||
<title>Conceptual differences</title>
|
||||
|
||||
<para>
|
||||
The central concepts of D-Bus are modelled in a very similar way
|
||||
in dbus-glib and GDBus. Both have a objects representing connections,
|
||||
proxies and method invocations. But there are some important
|
||||
differences:
|
||||
<itemizedlist>
|
||||
<listitem><para>
|
||||
dbus-glib uses libdbus, GDBus doesn't. Instead, it relies on GIO
|
||||
streams as transport layer, and has its own implementation for the
|
||||
the D-Bus connection setup and authentication. Apart from using
|
||||
streams as transport, avoiding libdbus also lets GDBus avoid some
|
||||
thorny multithreading issues.
|
||||
</para></listitem>
|
||||
<listitem><para>
|
||||
dbus-glib uses the GObject type system for method arguments and
|
||||
return values, including a homegrown container specialization
|
||||
mechanism. GDBus relies uses the #GVariant type system which is
|
||||
explicitly designed to match D-Bus types.
|
||||
</para></listitem>
|
||||
<listitem><para>
|
||||
The typical way to export an object in dbus-glib involves generating
|
||||
glue code from XML introspection data using <command>dbus-binding-tool</command>. GDBus does not (yet?) use code generation; you are expected to
|
||||
embed the introspection data in your application code.
|
||||
</para></listitem>
|
||||
</itemizedlist>
|
||||
</para>
|
||||
</section>
|
||||
|
||||
<section>
|
||||
<title>API comparison</title>
|
||||
|
||||
<table id="dbus-glib-vs-gdbus">
|
||||
<title>dbus-glib APIs and their GDBus counterparts</title>
|
||||
<tgroup cols="2">
|
||||
<thead>
|
||||
<row><entry>dbus-glib</entry><entry>GDBus</entry></row>
|
||||
</thead>
|
||||
<tbody>
|
||||
<row><entry>#DBusGConnection</entry><entry>#GDBusConnection</entry></row>
|
||||
<row><entry>#DBusGProxy</entry><entry>#GDBusProxy</entry></row>
|
||||
<row><entry>#DBusGMethodInvocation</entry><entry>#GDBusMethodInvocation</entry></row>
|
||||
<row><entry>dbus_g_bus_get()</entry><entry>g_bus_get_sync(), also see
|
||||
g_bus_get()</entry></row>
|
||||
<row><entry>dbus_g_proxy_new_for_name()</entry><entry>g_dbus_proxy_new_sync(), also see
|
||||
g_dbus_proxy_new()</entry></row>
|
||||
<row><entry>dbus_g_proxy_add_signal()</entry><entry>not needed, use the generic #GDBusProxy::g-signal</entry></row>
|
||||
<row><entry>dbus_g_proxy_connect_signal()</entry><entry>use g_signal_connect() with #GDBusProxy::g-signal</entry></row>
|
||||
<row><entry>dbus_g_connection_register_g_object()</entry><entry>g_dbus_connection_register_object()</entry></row>
|
||||
<row><entry>dbus_g_connection_unregister_g_object()</entry><entry>g_dbus_connection_unregister_object()</entry></row>
|
||||
<row><entry>dbus_g_object_type_install_info()</entry><entry>introspection data is installed while registering
|
||||
an object, see g_dbus_connection_register_object()</entry></row>
|
||||
<row><entry>dbus_g_proxy_begin_call()</entry><entry>g_dbus_proxy_call()</entry></row>
|
||||
<row><entry>dbus_g_proxy_end_call()</entry><entry>g_dbus_proxy_call_finish()</entry></row>
|
||||
<row><entry>dbus_g_proxy_call()</entry><entry>g_dbus_proxy_call_sync()</entry></row>
|
||||
<row><entry>dbus_g_error_domain_register()</entry><entry>g_dbus_error_register_error_domain()</entry></row>
|
||||
<row><entry>dbus_g_error_has_name()</entry><entry>no direct equivalent, see g_dbus_error_get_remote_error()</entry></row>
|
||||
<row><entry>dbus_g_method_return()</entry><entry>g_dbus_method_invocation_return_value()</entry></row>
|
||||
<row><entry>dbus_g_method_return_error()</entry><entry>g_dbus_method_invocation_return_error() and variants</entry></row>
|
||||
<row><entry>dbus_g_method_get_sender()</entry><entry>g_dbus_method_invocation_get_sender()</entry></row>
|
||||
</tbody>
|
||||
</tgroup>
|
||||
</table>
|
||||
</section>
|
||||
|
||||
<section>
|
||||
<title>Owning bus names</title>
|
||||
<para>
|
||||
Using dbus-glib, you typically call RequestName manually
|
||||
to own a name, like in the following excerpt:
|
||||
<informalexample><programlisting><![CDATA[
|
||||
error = NULL;
|
||||
res = dbus_g_proxy_call (system_bus_proxy,
|
||||
"RequestName",
|
||||
&error,
|
||||
G_TYPE_STRING, NAME_TO_CLAIM,
|
||||
G_TYPE_UINT, DBUS_NAME_FLAG_ALLOW_REPLACEMENT,
|
||||
G_TYPE_INVALID,
|
||||
G_TYPE_UINT, &result,
|
||||
G_TYPE_INVALID);
|
||||
if (!res)
|
||||
{
|
||||
if (error != NULL)
|
||||
{
|
||||
g_warning ("Failed to acquire %s: %s",
|
||||
NAME_TO_CLAIM, error->message);
|
||||
g_error_free (error);
|
||||
}
|
||||
else
|
||||
{
|
||||
g_warning ("Failed to acquire %s", NAME_TO_CLAIM);
|
||||
}
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (result != DBUS_REQUEST_NAME_REPLY_PRIMARY_OWNER)
|
||||
{
|
||||
if (error != NULL)
|
||||
{
|
||||
g_warning ("Failed to acquire %s: %s",
|
||||
NAME_TO_CLAIM, error->message);
|
||||
g_error_free (error);
|
||||
}
|
||||
else
|
||||
{
|
||||
g_warning ("Failed to acquire %s", NAME_TO_CLAIM);
|
||||
}
|
||||
exit (1);
|
||||
}
|
||||
|
||||
dbus_g_proxy_add_signal (system_bus_proxy, "NameLost",
|
||||
G_TYPE_STRING, G_TYPE_INVALID);
|
||||
dbus_g_proxy_connect_signal (system_bus_proxy, "NameLost",
|
||||
G_CALLBACK (on_name_lost), NULL, NULL);
|
||||
|
||||
/* further setup ... */
|
||||
]]>
|
||||
</programlisting></informalexample>
|
||||
</para>
|
||||
<para>
|
||||
While you can do things this way with GDBus too, using
|
||||
g_dbus_proxy_call_sync(), it is much nicer to use the high-level API
|
||||
for this:
|
||||
<informalexample><programlisting><![CDATA[
|
||||
static void
|
||||
on_name_acquired (GDBusConnection *connection,
|
||||
const gchar *name,
|
||||
gpointer user_data)
|
||||
{
|
||||
/* further setup ... */
|
||||
}
|
||||
|
||||
/* ... */
|
||||
|
||||
owner_id = g_bus_own_name (G_BUS_TYPE_SYSTEM,
|
||||
NAME_TO_CLAIM,
|
||||
G_BUS_NAME_OWNER_FLAGS_ALLOW_REPLACEMENT,
|
||||
on_bus_acquired,
|
||||
on_name_acquired,
|
||||
on_name_lost,
|
||||
NULL,
|
||||
NULL);
|
||||
|
||||
g_main_loop_run (loop);
|
||||
|
||||
g_bus_unown_name (owner_id);
|
||||
]]>
|
||||
</programlisting></informalexample>
|
||||
Note that g_bus_own_name() works asynchronously and requires
|
||||
you to enter your mainloop to await the on_name_aquired()
|
||||
callback. Also note that in order to avoid race conditions (e.g.
|
||||
when your service is activated by a method call), you have to export
|
||||
your manager object <emphasis>before</emphasis> acquiring the
|
||||
name. The on_bus_acquired() callback is the right place to do
|
||||
such preparations.
|
||||
</para>
|
||||
</section>
|
||||
|
||||
<section>
|
||||
<title>Creating proxies for well-known names</title>
|
||||
<para>
|
||||
dbus-glib lets you create proxy objects for well-known names, like the
|
||||
following example:
|
||||
<informalexample><programlisting><![CDATA[
|
||||
proxy = dbus_g_proxy_new_for_name (system_bus_connection,
|
||||
"org.freedesktop.Accounts",
|
||||
"/org/freedesktop/Accounts",
|
||||
"org.freedesktop.Accounts");
|
||||
]]>
|
||||
</programlisting></informalexample>
|
||||
For a #DBusGProxy constructed like this, method calls will be sent to
|
||||
the current owner of the name, and that owner can change over time.
|
||||
</para>
|
||||
<para>
|
||||
In contrast, #GDBusProxy instances are always bound to a unique name.
|
||||
To get a proxy for a well-known name, you either have to call
|
||||
GetNameOwner yourself and construct a proxy for the unique name
|
||||
of the current name owner, or use the high-level API. The latter
|
||||
option is highly recommended:
|
||||
<informalexample><programlisting><![CDATA[
|
||||
static void
|
||||
on_proxy_appeared (GDBusConnection *connection,
|
||||
const gchar *name,
|
||||
const gchar *name_owner,
|
||||
GDBusProxy *proxy,
|
||||
gpointer user_data)
|
||||
{
|
||||
/* start to use proxy */
|
||||
}
|
||||
|
||||
/* ... */
|
||||
|
||||
watcher_id = g_bus_watch_proxy (G_BUS_TYPE_SYSTEM,
|
||||
"org.freedesktop.Accounts",
|
||||
G_BUS_NAME_WATCHER_FLAGS_NONE,
|
||||
"/org/freedesktop/Accounts",
|
||||
"org.freedesktop.Accounts",
|
||||
G_TYPE_DBUS_PROXY,
|
||||
G_BUS_PROXY_FLAGS_NONE,
|
||||
on_proxy_appeared,
|
||||
on_proxy_vanished,
|
||||
NULL,
|
||||
NULL);
|
||||
|
||||
g_main_loop_run (loop);
|
||||
|
||||
g_bus_unwatch_proxy (watcher_id);
|
||||
]]>
|
||||
</programlisting></informalexample>
|
||||
Like g_bus_own_name(), g_bus_watch_proxy() is asynchronous and
|
||||
you are expected to enter your mainloop to await the on_proxy_appeared()
|
||||
callback. Note that GDBus also does all the setup operations for the
|
||||
proxy asynchronously, and only calls your callback when the proxy
|
||||
is ready for use.
|
||||
</para>
|
||||
</section>
|
||||
<section>
|
||||
<title>Client-side GObject bindings</title>
|
||||
|
||||
<para>
|
||||
dbus-glib comes with <command>dbus-binding-tool</command>, which
|
||||
can produce somewhat nice client-side wrappers for a D-Bus interface.
|
||||
GDBus does not have code-generation at this point, but #GDBusProxy
|
||||
is designed to allow the creating of client-side wrappers by
|
||||
subclassing #GDBusProxy.
|
||||
</para>
|
||||
<para>
|
||||
For an example of a #GDBusProxy-derived class that wraps a D-Bus
|
||||
interface in a type-safe way, see <xref
|
||||
linkend="gdbus-example-proxy-subclass"/>. The comparison is as
|
||||
follows:
|
||||
<table id="gdbus-example-type-safe-proxy">
|
||||
<title>Wrapping the org.freedesktop.Accounts.User D-Bus interface in the AccountUser GObject type</title>
|
||||
<tgroup cols="2">
|
||||
<thead>
|
||||
<row><entry>D-Bus concept</entry><entry>GObject concept</entry></row>
|
||||
</thead>
|
||||
<tbody>
|
||||
<row>
|
||||
<entry>AutomaticLogin property</entry>
|
||||
<entry>
|
||||
<para><literal>AccountsUser:automatic-login</literal> GObject property</para>
|
||||
<para>C getter: accounts_user_get_automatic_login()</para>
|
||||
<para>Watch changes via the <literal>notify::automatic-login</literal> signal</para>
|
||||
</entry>
|
||||
</row>
|
||||
<row>
|
||||
<entry>RealName property</entry>
|
||||
<entry>
|
||||
<para><literal>AccountsUser:real-name</literal> GObject property</para>
|
||||
<para>C getter: accounts_user_get_real_name()</para>
|
||||
<para>Watch changes via the <literal>notify::real-name signal</literal></para>
|
||||
</entry>
|
||||
</row>
|
||||
<row>
|
||||
<entry>UserName property</entry>
|
||||
<entry>
|
||||
<para><literal>AccountsUser:user-name</literal> GObject property</para>
|
||||
<para>C getter: accounts_user_get_user_name()</para>
|
||||
<para>Watch changes via the <literal>notify::user-name</literal> signal</para>
|
||||
</entry>
|
||||
</row>
|
||||
<row>
|
||||
<entry>Changed signal</entry>
|
||||
<entry>
|
||||
<para><literal>AccountsUser::changed</literal> GObject signal</para>
|
||||
<para>Watch via e.g. g_signal_connect()</para>
|
||||
</entry>
|
||||
</row>
|
||||
<row>
|
||||
<entry>Frobnicate method</entry>
|
||||
<entry>
|
||||
<para>Use accounts_user_frobnicate() + accounts_user_frobnicate_finish() or accounts_user_frobnicate_sync() to invoke</para>
|
||||
</entry>
|
||||
</row>
|
||||
</tbody>
|
||||
</tgroup>
|
||||
</table>
|
||||
</para>
|
||||
<example id="gdbus-example-proxy-subclass"><title>GDBusProxy subclass example</title><programlisting><xi:include xmlns:xi="http://www.w3.org/2001/XInclude" parse="text" href="../../../../gio/tests/gdbus-example-proxy-subclass.c"><xi:fallback>FIXME: MISSING XINCLUDE CONTENT</xi:fallback></xi:include></programlisting></example>
|
||||
</section>
|
||||
|
||||
<section>
|
||||
<title>Exporting objects</title>
|
||||
|
||||
<para>
|
||||
With dbus-glib, exporting an object over D-Bus works by generating
|
||||
a bunch of glue code from your introspection XML with
|
||||
<command>dbus-binding-tool</command>. The glue code gets included in
|
||||
your source, and you need to call
|
||||
<informalexample><programlisting>
|
||||
dbus_g_object_type_install_info (TYPE_MYOBJECT,
|
||||
&dbus_glib_myobject_object_info);
|
||||
</programlisting></informalexample>
|
||||
in your class_init() function to tell dbus-glib about your type.
|
||||
To actually export an instance, you call
|
||||
<informalexample><programlisting>
|
||||
dbus_g_connection_register_g_object (system_bus_connection,
|
||||
my_object_path,
|
||||
G_OBJECT (my_object));
|
||||
</programlisting></informalexample>
|
||||
|
||||
</para>
|
||||
<para>
|
||||
The GDBus way of exporting an object works by embedding the
|
||||
introspection XML in the source, creating introspection data
|
||||
structures from it with g_dbus_node_info_new_for_xml(), and
|
||||
passing that along when you register the object:
|
||||
<informalexample><programlisting><![CDATA[
|
||||
|
||||
static const gchar introspection_xml[] =
|
||||
"<node>"
|
||||
" <interface name='org.gtk.GDBus.TestPeerInterface'>"
|
||||
" <method name='HelloWorld'>"
|
||||
" <arg type='s' name='greeting' direction='in'/>"
|
||||
" <arg type='s' name='response' direction='out'/>"
|
||||
" </method>"
|
||||
" </interface>"
|
||||
"</node>";
|
||||
|
||||
/* parse introspection data */
|
||||
introspection_data = g_dbus_node_info_new_for_xml (introspection_xml, NULL);
|
||||
|
||||
/
|
||||
id = g_dbus_connection_register_object (connection,
|
||||
"/org/gtk/GDBus/TestObject",
|
||||
"org.gtk.GDBus.TestPeerInterface",
|
||||
introspection_data->interfaces[0],
|
||||
&interface_vtable,
|
||||
NULL, /* user_data */
|
||||
NULL, /* user_data_free_func */
|
||||
NULL); /* GError** */
|
||||
|
||||
]]>
|
||||
</programlisting></informalexample>
|
||||
</para>
|
||||
<para>
|
||||
The actual implementation of the exported object is done by specifying
|
||||
a #GDBusInterfaceVTable that has method_call(), get_property() and
|
||||
set_property() methods. There is no direct support beyond that for
|
||||
exporting #GObjects, so there is quite a bit of manual work involved,
|
||||
as you can see in the following example.
|
||||
</para>
|
||||
<para>
|
||||
Since the VTable methods don't have any direct #GObject support, we
|
||||
pass the exported object as @user_data. Also note that we have to handle
|
||||
the emission of the PropertiesChanged signal ourselves, by connecting
|
||||
to ::notify.
|
||||
</para>
|
||||
<example id="gdbus-export"><title>Exporting a GObject</title><programlisting><xi:include xmlns:xi="http://www.w3.org/2001/XInclude" parse="text" href="../../../../gio/tests/gdbus-example-export.c"><xi:fallback>FIXME: MISSING XINCLUDE CONTENT</xi:fallback></xi:include></programlisting></example>
|
||||
</section>
|
||||
|
||||
</chapter>
|
133
docs/reference/gio/migrating-gnome-vfs.xml
Normal file
133
docs/reference/gio/migrating-gnome-vfs.xml
Normal file
@ -0,0 +1,133 @@
|
||||
<chapter>
|
||||
<title>Migrating from GnomeVFS to GIO</title>
|
||||
|
||||
<table id="gnome-vfs-vs-gio">
|
||||
<title>Comparison of GnomeVFS and GIO concepts</title>
|
||||
<tgroup cols="2">
|
||||
<thead>
|
||||
<row><entry>GnomeVFS</entry><entry>GIO</entry></row>
|
||||
</thead>
|
||||
<tbody>
|
||||
<row><entry>GnomeVFSURI</entry><entry>GFile</entry></row>
|
||||
<row><entry>GnomeVFSFileInfo</entry><entry>GFileInfo</entry></row>
|
||||
<row><entry>GnomeVFSResult</entry><entry>GError, with G_IO_ERROR values</entry></row>
|
||||
<row><entry>GnomeVFSHandle & GnomeVFSAsyncHandle</entry><entry>GInputStream or GOutputStream</entry></row>
|
||||
<row><entry>GnomeVFSDirectoryHandle</entry><entry>GFileEnumerator</entry></row>
|
||||
<row><entry>mime type</entry><entry>content type</entry></row>
|
||||
<row><entry>GnomeVFSMonitor</entry><entry>GFileMonitor</entry></row>
|
||||
<row><entry>GnomeVFSVolumeMonitor</entry><entry>GVolumeMonitor</entry></row>
|
||||
<row><entry>GnomeVFSVolume</entry><entry>GMount</entry></row>
|
||||
<row><entry>GnomeVFSDrive</entry><entry>GVolume</entry></row>
|
||||
<row><entry>-</entry><entry>GDrive</entry></row>
|
||||
<row><entry>GnomeVFSContext</entry><entry>GCancellable</entry></row>
|
||||
<row><entry>gnome_vfs_async_cancel</entry><entry>g_cancellable_cancel</entry></row>
|
||||
</tbody>
|
||||
</tgroup>
|
||||
</table>
|
||||
|
||||
<section>
|
||||
<title>Trash handling</title>
|
||||
|
||||
<para>
|
||||
The handling of trashed files has been changed in GIO, compared
|
||||
to gnome-vfs. gnome-vfs has a home-grown trash implementation that
|
||||
predates the freedesktop.org <ulink url="http://www.freedesktop.org/wiki/Specifications/trash-spec">Desktop Trash Can</ulink> specification
|
||||
that is implemented in GIO. The location for storing trashed files
|
||||
has changed from <filename>$HOME/.Trash</filename> to
|
||||
<filename>$HOME/.local/share/Trash</filename> (or more correctly
|
||||
<filename>$XDG_DATA_HOME/Trash</filename>), which means that
|
||||
there is a need for migrating files that have been trashed by
|
||||
gnome-vfs to the new location.
|
||||
</para>
|
||||
<para>
|
||||
In gnome-vfs, the <filename>trash://</filename> scheme offering a
|
||||
merged view of all trash directories was implemented in nautilus,
|
||||
and trash-handling applications had to find and monitor all trash
|
||||
directories themselves. With GIO, the <filename>trash://</filename>
|
||||
implementation has been moved to gvfs and applications can simply
|
||||
monitor that location:
|
||||
</para>
|
||||
<informalexample><programlisting>
|
||||
static void
|
||||
file_changed (GFileMonitor *file_monitor,
|
||||
GFile *child,
|
||||
GFile *other_file,
|
||||
GFileMonitorEvent event_type,
|
||||
gpointer user_data)
|
||||
{
|
||||
switch (event_type)
|
||||
{
|
||||
case G_FILE_MONITOR_EVENT_DELETED:
|
||||
g_print ("'%s' removed from trash\n", g_file_get_basename (child));
|
||||
break;
|
||||
case G_FILE_MONITOR_EVENT_CREATED:
|
||||
g_print ("'%s' added to trash\n", g_file_get_basename (child));
|
||||
break;
|
||||
default: ;
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
start_monitoring_trash (void)
|
||||
{
|
||||
GFile *file;
|
||||
GFileMonitor *monitor;
|
||||
|
||||
file = g_file_new_for_uri ("trash://");
|
||||
monitor = g_file_monitor_directory (file, 0, NULL, NULL);
|
||||
g_object_unref (file);
|
||||
|
||||
g_signal_connect (monitor, "changed", G_CALLBACK (file_changed), NULL);
|
||||
|
||||
/* ... */
|
||||
|
||||
}
|
||||
</programlisting></informalexample>
|
||||
<para>
|
||||
GIO exposes some useful metadata about trashed files. There are
|
||||
trash::orig-path and trash::deletion-date attributes. The
|
||||
standard::icon attribute of the <filename>trash://</filename>
|
||||
itself provides a suitable icon for displaying the trash can on
|
||||
the desktop. If you are using this icon, make sure to monitor
|
||||
this attribute for changes, since the icon may be updated to
|
||||
reflect that state of the trash can.
|
||||
</para>
|
||||
<para>
|
||||
Moving a file to the trash is much simpler with GIO. Instead of
|
||||
using gnome_vfs_find_directory() with %GNOME_VFS_DIRECTORY_KIND_TRASH
|
||||
to find out where to move the trashed file, just use the g_file_trash()
|
||||
function.
|
||||
</para>
|
||||
</section>
|
||||
|
||||
<section>
|
||||
<title>Operations on multiple files</title>
|
||||
|
||||
<para>
|
||||
gnome-vfs has the dreaded gnome_vfs_xfer_uri_list() function which
|
||||
has tons of options and offers the equivalent of cp, mv, ln, mkdir
|
||||
and rm at the same time.
|
||||
</para>
|
||||
<para>
|
||||
GIO offers a much simpler I/O scheduler functionality instead, that
|
||||
lets you schedule a function to be called in a separate thread, or
|
||||
if threads are not available, as an idle in the mainloop.
|
||||
See g_io_scheduler_push_job().
|
||||
</para>
|
||||
|
||||
</section>
|
||||
|
||||
<section>
|
||||
<title>Mime monitoring</title>
|
||||
|
||||
<para>
|
||||
gnome-vfs offered a way to monitor the association between mime types
|
||||
and default handlers for changes, with the #GnomeVFSMIMEMonitor object.
|
||||
GIO does not offer a replacement for this functionality at this time,
|
||||
since we have not found a compelling use case where
|
||||
#GnomeVFSMIMEMonitor was used. If you think you have such a use
|
||||
case, please report it at
|
||||
<ulink url="http://bugzilla.gnome.org">bugzilla.gnome.org</ulink>.
|
||||
</para>
|
||||
</section>
|
||||
</chapter>
|
@ -105,6 +105,31 @@
|
||||
<listitem><para>network connection stream</para></listitem>
|
||||
</varlistentry>
|
||||
</variablelist>
|
||||
There is support for connecting to <link linkend="http://www.freedesktop.org/wiki/Software/dbus">D-Bus</link>,
|
||||
sending and receiving messages, owning and watching bus names,
|
||||
and making objects available on the bus:
|
||||
<variablelist>
|
||||
<varlistentry>
|
||||
<term>GDBusConnection</term>
|
||||
<listitem><para>a D-Bus connection</para></listitem>
|
||||
</varlistentry>
|
||||
|
||||
<varlistentry>
|
||||
<term>GDBusMethodInvocation</term>
|
||||
<listitem><para>for handling remove calls</para></listitem>
|
||||
</varlistentry>
|
||||
|
||||
<varlistentry>
|
||||
<term>GDBusServer</term>
|
||||
<listitem><para>helper for accepting connections</para></listitem>
|
||||
</varlistentry>
|
||||
|
||||
<varlistentry>
|
||||
<term>GDBusProxy</term>
|
||||
<listitem><para>proxy to access D-Bus interfaces on a remote object</para></listitem>
|
||||
</varlistentry>
|
||||
|
||||
</variablelist>
|
||||
Beyond these, GIO provides facilities for file monitoring,
|
||||
asynchronous I/O and filename completion. In addition to the
|
||||
interfaces, GIO provides implementations for the local case.
|
||||
@ -254,8 +279,8 @@
|
||||
<para>
|
||||
This variable can be set to the name of a #GSettingsBackend
|
||||
implementation to override the default for debugging purposes.
|
||||
The keyfile-based implementation that is included in GIO has
|
||||
the name "keyfile", the one in dconf has the name "dconf-settings".
|
||||
The memory-based implementation that is included in GIO has
|
||||
the name "memory", the one in dconf has the name "dconf-settings".
|
||||
</para>
|
||||
</formalpara>
|
||||
|
||||
@ -270,15 +295,86 @@
|
||||
</para>
|
||||
</formalpara>
|
||||
|
||||
<formalpara>
|
||||
<title><envar>GSETTINGS_KEYFILE_BACKEND_STORE</envar></title>
|
||||
<formalpara>
|
||||
<title><envar>DBUS_SYSTEM_BUS_ADDRESS</envar></title>
|
||||
|
||||
<para>
|
||||
This variable can be set to the path where the keyfile #GSettings
|
||||
backend stores its data. By default, the keyfile is stored in
|
||||
<filename>$HOME/.config/gsettings/store</filename>.
|
||||
This variable is consulted to find the address of the D-Bus system
|
||||
bus. For the format of D-Bus addresses, see the D-Bus
|
||||
<ulink url="http://dbus.freedesktop.org/doc/dbus-specification.html#addresses">specification</ulink>.
|
||||
</para>
|
||||
</formalpara>
|
||||
<para>
|
||||
Setting this variable overrides platform-specific ways of determining
|
||||
the system bus address.
|
||||
</para>
|
||||
</formalpara>
|
||||
|
||||
<formalpara>
|
||||
<title><envar>DBUS_SESSION_BUS_ADDRESS</envar></title>
|
||||
|
||||
<para>
|
||||
This variable is consulted to find the address of the D-Bus session bus.
|
||||
</para>
|
||||
<para>
|
||||
Setting this variable overrides platform-specific ways of determining
|
||||
the session bus address.
|
||||
</para>
|
||||
</formalpara>
|
||||
|
||||
<formalpara>
|
||||
<title><envar>DBUS_STARTER_BUS_TYPE</envar></title>
|
||||
|
||||
<para>
|
||||
This variable is consulted to find out the 'starter' bus for an
|
||||
application that has been started via D-Bus activation. The possible
|
||||
values are 'system' or 'session'.
|
||||
</para>
|
||||
</formalpara>
|
||||
|
||||
<formalpara>
|
||||
<title><envar>G_DBUS_DEBUG</envar></title>
|
||||
|
||||
<para>
|
||||
This variable can be set to a list of debug options, which
|
||||
cause GLib to print out different types of debugging
|
||||
information when using the D-Bus routines.
|
||||
<variablelist>
|
||||
<varlistentry>
|
||||
<term>message</term>
|
||||
<listitem><para>Show all sent and received D-Bus messages</para></listitem>
|
||||
</varlistentry>
|
||||
<varlistentry>
|
||||
<term>authentication</term>
|
||||
<listitem><para>Information about authentication</para></listitem>
|
||||
</varlistentry>
|
||||
</variablelist>
|
||||
The special value <literal>all</literal> can be used to turn on
|
||||
all debug options.
|
||||
</para>
|
||||
</formalpara>
|
||||
|
||||
<formalpara>
|
||||
<title><envar>G_DBUS_COOKIE_SHA1_KEYRING_DIR</envar></title>
|
||||
|
||||
<para>
|
||||
Can be used to override the directory used to store the
|
||||
keyring used in the <literal>DBUS_COOKIE_SHA1</literal>
|
||||
authentication mechanism. Normally the directory used is
|
||||
<filename>.dbus-keyrings</filename> in the user's home
|
||||
directory.
|
||||
</para>
|
||||
</formalpara>
|
||||
|
||||
<formalpara>
|
||||
<title><envar>G_DBUS_COOKIE_SHA1_KEYRING_DIR_IGNORE_PERMISSION</envar></title>
|
||||
|
||||
<para>
|
||||
If set, the permissions of the directory used to store the
|
||||
keyring used in the <literal>DBUS_COOKIE_SHA1</literal>
|
||||
authentication mechanism won't be checked. Normally the
|
||||
directory must be readable only by the user.
|
||||
</para>
|
||||
</formalpara>
|
||||
</chapter>
|
||||
|
||||
<chapter id="extending-gio">
|
||||
|
@ -365,6 +365,30 @@ Flags which influence the parsing.
|
||||
@Returns:
|
||||
|
||||
|
||||
<!-- ##### FUNCTION g_key_file_get_int64 ##### -->
|
||||
<para>
|
||||
|
||||
</para>
|
||||
|
||||
@key_file:
|
||||
@group_name:
|
||||
@key:
|
||||
@error:
|
||||
@Returns:
|
||||
|
||||
|
||||
<!-- ##### FUNCTION g_key_file_get_uint64 ##### -->
|
||||
<para>
|
||||
|
||||
</para>
|
||||
|
||||
@key_file:
|
||||
@group_name:
|
||||
@key:
|
||||
@error:
|
||||
@Returns:
|
||||
|
||||
|
||||
<!-- ##### FUNCTION g_key_file_get_double ##### -->
|
||||
<para>
|
||||
|
||||
@ -511,6 +535,28 @@ Flags which influence the parsing.
|
||||
@value:
|
||||
|
||||
|
||||
<!-- ##### FUNCTION g_key_file_set_int64 ##### -->
|
||||
<para>
|
||||
|
||||
</para>
|
||||
|
||||
@key_file:
|
||||
@group_name:
|
||||
@key:
|
||||
@value:
|
||||
|
||||
|
||||
<!-- ##### FUNCTION g_key_file_set_uint64 ##### -->
|
||||
<para>
|
||||
|
||||
</para>
|
||||
|
||||
@key_file:
|
||||
@group_name:
|
||||
@key:
|
||||
@value:
|
||||
|
||||
|
||||
<!-- ##### FUNCTION g_key_file_set_double ##### -->
|
||||
<para>
|
||||
|
||||
|
@ -2,21 +2,12 @@
|
||||
.\" Title: glib-mkenums
|
||||
.\" Author: [FIXME: author] [see http://docbook.sf.net/el/author]
|
||||
.\" Generator: DocBook XSL Stylesheets v1.75.2 <http://docbook.sf.net/>
|
||||
.\" Date: 05/14/2010
|
||||
.\" Date: 05/13/2010
|
||||
.\" Manual: User Commands
|
||||
.\" Source: User Commands
|
||||
.\" Language: English
|
||||
.\"
|
||||
.TH "GLIB\-MKENUMS" "1" "05/14/2010" "User Commands" "User Commands"
|
||||
.\" -----------------------------------------------------------------
|
||||
.\" * Define some portability stuff
|
||||
.\" -----------------------------------------------------------------
|
||||
.\" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
.\" http://bugs.debian.org/507673
|
||||
.\" http://lists.gnu.org/archive/html/groff/2009-02/msg00013.html
|
||||
.\" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
.ie \n(.g .ds Aq \(aq
|
||||
.el .ds Aq '
|
||||
.TH "GLIB\-MKENUMS" "1" "05/13/2010" "User Commands" "User Commands"
|
||||
.\" -----------------------------------------------------------------
|
||||
.\" * set default formatting
|
||||
.\" -----------------------------------------------------------------
|
||||
|
@ -79,6 +79,45 @@ gio-marshal.c: gio-marshal.h gio-marshal.list
|
||||
$(glib_genmarshal) --prefix=_gio_marshal $(srcdir)/gio-marshal.list --body --internal) > $@.tmp && \
|
||||
mv $@.tmp $@
|
||||
|
||||
gdbus_headers = \
|
||||
gdbusauthobserver.h \
|
||||
gcredentials.h \
|
||||
gdbusutils.h \
|
||||
gdbuserror.h \
|
||||
gdbusaddress.h \
|
||||
gdbusconnection.h \
|
||||
gdbusmessage.h \
|
||||
gdbusnameowning.h \
|
||||
gdbusnamewatching.h \
|
||||
gdbusproxywatching.h \
|
||||
gdbusproxy.h \
|
||||
gdbusintrospection.h \
|
||||
gdbusmethodinvocation.h \
|
||||
gdbusserver.h \
|
||||
$(NULL)
|
||||
|
||||
gdbus_sources = \
|
||||
gdbusutils.h gdbusutils.c \
|
||||
gdbusaddress.h gdbusaddress.c \
|
||||
gdbusauthobserver.h gdbusauthobserver.c \
|
||||
gdbusauth.h gdbusauth.c \
|
||||
gdbusauthmechanism.h gdbusauthmechanism.c \
|
||||
gdbusauthmechanismanon.h gdbusauthmechanismanon.c \
|
||||
gdbusauthmechanismexternal.h gdbusauthmechanismexternal.c \
|
||||
gdbusauthmechanismsha1.h gdbusauthmechanismsha1.c \
|
||||
gdbuserror.h gdbuserror.c \
|
||||
gdbusconnection.h gdbusconnection.c \
|
||||
gdbusmessage.h gdbusmessage.c \
|
||||
gdbusnameowning.h gdbusnameowning.c \
|
||||
gdbusnamewatching.h gdbusnamewatching.c \
|
||||
gdbusproxywatching.h gdbusproxywatching.c \
|
||||
gdbusproxy.h gdbusproxy.c \
|
||||
gdbusprivate.h gdbusprivate.c \
|
||||
gdbusintrospection.h gdbusintrospection.c \
|
||||
gdbusmethodinvocation.h gdbusmethodinvocation.c \
|
||||
gdbusserver.h gdbusserver.c \
|
||||
$(NULL)
|
||||
|
||||
settings_headers = \
|
||||
gsettingsbackend.h \
|
||||
gsettings.h
|
||||
@ -155,17 +194,18 @@ SUBDIRS += fam
|
||||
endif
|
||||
|
||||
if OS_UNIX
|
||||
appinfo_sources += gdesktopappinfo.c gdesktopappinfo.h
|
||||
appinfo_sources += gdesktopappinfo.c
|
||||
platform_libadd += libasyncns/libasyncns.la xdgmime/libxdgmime.la
|
||||
platform_deps += libasyncns/libasyncns.la xdgmime/libxdgmime.la
|
||||
unix_sources = \
|
||||
gfiledescriptorbased.c \
|
||||
gunixconnection.c \
|
||||
gunixcredentialsmessage.c \
|
||||
gunixfdlist.c \
|
||||
gunixfdmessage.c \
|
||||
gunixmount.c \
|
||||
gunixmount.h \
|
||||
gunixmounts.c \
|
||||
gunixmounts.h \
|
||||
gunixresolver.c \
|
||||
gunixresolver.h \
|
||||
gunixsocketaddress.c \
|
||||
@ -183,6 +223,7 @@ giounixinclude_HEADERS = \
|
||||
gdesktopappinfo.h \
|
||||
gfiledescriptorbased.h \
|
||||
gunixconnection.h \
|
||||
gunixcredentialsmessage.h \
|
||||
gunixmounts.h \
|
||||
gunixfdlist.h \
|
||||
gunixfdmessage.h \
|
||||
@ -240,6 +281,7 @@ libgio_2_0_la_SOURCES = \
|
||||
gconverter.c \
|
||||
gconverterinputstream.c \
|
||||
gconverteroutputstream.c \
|
||||
gcredentials.c \
|
||||
gdatainputstream.c \
|
||||
gdataoutputstream.c \
|
||||
gdrive.c \
|
||||
@ -252,8 +294,6 @@ libgio_2_0_la_SOURCES = \
|
||||
gfile.c \
|
||||
gfileattribute.c \
|
||||
gfileattribute-priv.h \
|
||||
gfiledescriptorbased.h \
|
||||
gfiledescriptorbased.c \
|
||||
gfileenumerator.c \
|
||||
gfileicon.c \
|
||||
gfileinfo.c \
|
||||
@ -327,6 +367,7 @@ libgio_2_0_la_SOURCES = \
|
||||
$(unix_sources) \
|
||||
$(win32_sources) \
|
||||
$(settings_sources) \
|
||||
$(gdbus_sources) \
|
||||
$(local_sources) \
|
||||
$(marshal_sources) \
|
||||
$(NULL)
|
||||
@ -454,6 +495,7 @@ gio_headers = \
|
||||
gzlibcompressor.h \
|
||||
gzlibdecompressor.h \
|
||||
$(settings_headers) \
|
||||
$(gdbus_headers) \
|
||||
$(NULL)
|
||||
|
||||
gioincludedir=$(includedir)/glib-2.0/gio/
|
||||
@ -528,10 +570,22 @@ gsettings_LDADD = \
|
||||
libgio-2.0.la
|
||||
gsettings_SOURCES = gsettings-tool.c
|
||||
|
||||
|
||||
schemadir = $(datadir)/glib-2.0/schemas
|
||||
dist_schema_DATA = gschema.dtd
|
||||
|
||||
# ------------------------------------------------------------------------
|
||||
# gdbus(1) tool
|
||||
|
||||
bin_PROGRAMS += gdbus
|
||||
gdbus_SOURCES = gdbus-tool.c
|
||||
gdbus_LDADD = libgio-2.0.la
|
||||
|
||||
completiondir = $(sysconfdir)/bash_completion.d
|
||||
completion_SCRIPTS = gdbus-bash-completion.sh
|
||||
EXTRA_DIST += $(completion_SCRIPTS)
|
||||
|
||||
# ------------------------------------------------------------------------
|
||||
|
||||
dist-hook: $(BUILT_EXTRA_DIST) ../build/win32/vs9/gio.vcproj
|
||||
files='$(BUILT_EXTRA_DIST)'; \
|
||||
for f in $$files; do \
|
||||
|
345
gio/gcredentials.c
Normal file
345
gio/gcredentials.c
Normal file
@ -0,0 +1,345 @@
|
||||
/* GDBus - GLib D-Bus Library
|
||||
*
|
||||
* Copyright (C) 2008-2010 Red Hat, Inc.
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General
|
||||
* Public License along with this library; if not, write to the
|
||||
* Free Software Foundation, Inc., 59 Temple Place, Suite 330,
|
||||
* Boston, MA 02111-1307, USA.
|
||||
*
|
||||
* Author: David Zeuthen <davidz@redhat.com>
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <gobject/gvaluecollector.h>
|
||||
|
||||
#include "gcredentials.h"
|
||||
#include "gioerror.h"
|
||||
|
||||
#ifdef __linux__
|
||||
#define __USE_GNU
|
||||
#include <sys/types.h>
|
||||
#include <sys/socket.h>
|
||||
#include <unistd.h>
|
||||
#include <string.h>
|
||||
#endif
|
||||
|
||||
#include "glibintl.h"
|
||||
#include "gioalias.h"
|
||||
|
||||
/**
|
||||
* SECTION:gcredentials
|
||||
* @short_description: An object containing credentials
|
||||
* @include: gio/gio.h
|
||||
*
|
||||
* The #GCredentials type is a reference-counted wrapper for the
|
||||
* native credentials type. This information is typically used for
|
||||
* identifying, authenticating and authorizing other processes.
|
||||
*
|
||||
* Some operating systems supports looking up the credentials of the
|
||||
* remote peer of a communication endpoint - see e.g.
|
||||
* g_socket_get_credentials().
|
||||
*
|
||||
* Some operating systems supports securely sending and receiving
|
||||
* credentials over a Unix Domain Socket, see
|
||||
* #GUnixCredentialsMessage, g_unix_connection_send_credentials() and
|
||||
* g_unix_connection_receive_credentials() for details.
|
||||
*
|
||||
* On Linux, the native credential type is a <literal>struct ucred</literal> - see
|
||||
* the <literal>unix(7)</literal> man page for details.
|
||||
*/
|
||||
|
||||
struct _GCredentialsPrivate
|
||||
{
|
||||
#ifdef __linux__
|
||||
struct ucred native;
|
||||
#else
|
||||
#warning Please add GCredentials support for your OS
|
||||
guint foo;
|
||||
#endif
|
||||
};
|
||||
|
||||
G_DEFINE_TYPE (GCredentials, g_credentials, G_TYPE_OBJECT);
|
||||
|
||||
static void
|
||||
g_credentials_finalize (GObject *object)
|
||||
{
|
||||
G_GNUC_UNUSED GCredentials *credentials = G_CREDENTIALS (object);
|
||||
|
||||
if (G_OBJECT_CLASS (g_credentials_parent_class)->finalize != NULL)
|
||||
G_OBJECT_CLASS (g_credentials_parent_class)->finalize (object);
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
g_credentials_class_init (GCredentialsClass *klass)
|
||||
{
|
||||
GObjectClass *gobject_class;
|
||||
|
||||
g_type_class_add_private (klass, sizeof (GCredentialsPrivate));
|
||||
|
||||
gobject_class = G_OBJECT_CLASS (klass);
|
||||
gobject_class->finalize = g_credentials_finalize;
|
||||
}
|
||||
|
||||
static void
|
||||
g_credentials_init (GCredentials *credentials)
|
||||
{
|
||||
credentials->priv = G_TYPE_INSTANCE_GET_PRIVATE (credentials, G_TYPE_CREDENTIALS, GCredentialsPrivate);
|
||||
#ifdef __linux__
|
||||
credentials->priv->native.pid = getpid ();
|
||||
credentials->priv->native.uid = getuid ();
|
||||
credentials->priv->native.gid = getgid ();
|
||||
#endif
|
||||
}
|
||||
|
||||
/* ---------------------------------------------------------------------------------------------------- */
|
||||
|
||||
/**
|
||||
* g_credentials_new:
|
||||
*
|
||||
* Creates a new #GCredentials object with credentials matching the
|
||||
* the current process.
|
||||
*
|
||||
* Returns: A #GCredentials. Free with g_object_unref().
|
||||
*
|
||||
* Since: 2.26
|
||||
*/
|
||||
GCredentials *
|
||||
g_credentials_new (void)
|
||||
{
|
||||
return g_object_new (G_TYPE_CREDENTIALS, NULL);
|
||||
}
|
||||
|
||||
/* ---------------------------------------------------------------------------------------------------- */
|
||||
|
||||
/**
|
||||
* g_credentials_to_string:
|
||||
* @credentials: A #GCredentials object.
|
||||
*
|
||||
* Creates a human-readable textual representation of @credentials
|
||||
* that can be used in logging and debug messages. The format of the
|
||||
* returned string may change in future GLib release.
|
||||
*
|
||||
* Returns: A string that should be freed with g_free().
|
||||
*
|
||||
* Since: 2.26
|
||||
*/
|
||||
gchar *
|
||||
g_credentials_to_string (GCredentials *credentials)
|
||||
{
|
||||
GString *ret;
|
||||
|
||||
g_return_val_if_fail (G_IS_CREDENTIALS (credentials), NULL);
|
||||
|
||||
ret = g_string_new ("GCredentials:");
|
||||
#ifdef __linux__
|
||||
g_string_append (ret, "linux:");
|
||||
if (credentials->priv->native.pid != -1)
|
||||
g_string_append_printf (ret, "pid=%" G_GINT64_FORMAT ",", (gint64) credentials->priv->native.pid);
|
||||
if (credentials->priv->native.uid != -1)
|
||||
g_string_append_printf (ret, "uid=%" G_GINT64_FORMAT ",", (gint64) credentials->priv->native.uid);
|
||||
if (credentials->priv->native.gid != -1)
|
||||
g_string_append_printf (ret, "gid=%" G_GINT64_FORMAT ",", (gint64) credentials->priv->native.gid);
|
||||
if (ret->str[ret->len - 1] == ',')
|
||||
ret->str[ret->len - 1] = '\0';
|
||||
#else
|
||||
g_string_append (ret, "unknown");
|
||||
#endif
|
||||
|
||||
return g_string_free (ret, FALSE);
|
||||
}
|
||||
|
||||
/* ---------------------------------------------------------------------------------------------------- */
|
||||
|
||||
/**
|
||||
* g_credentials_is_same_user:
|
||||
* @credentials: A #GCredentials.
|
||||
* @other_credentials: A #GCredentials.
|
||||
* @error: Return location for error or %NULL.
|
||||
*
|
||||
* Checks if @credentials and @other_credentials is the same user.
|
||||
*
|
||||
* This operation can fail if #GCredentials is not supported on the
|
||||
* the OS.
|
||||
*
|
||||
* Returns: %TRUE if @credentials and @other_credentials has the same
|
||||
* user, %FALSE otherwise or if @error is set.
|
||||
*
|
||||
* Since: 2.26
|
||||
*/
|
||||
gboolean
|
||||
g_credentials_is_same_user (GCredentials *credentials,
|
||||
GCredentials *other_credentials,
|
||||
GError **error)
|
||||
{
|
||||
gboolean ret;
|
||||
|
||||
g_return_val_if_fail (G_IS_CREDENTIALS (credentials), FALSE);
|
||||
g_return_val_if_fail (G_IS_CREDENTIALS (other_credentials), FALSE);
|
||||
g_return_val_if_fail (error == NULL || *error == NULL, FALSE);
|
||||
|
||||
ret = FALSE;
|
||||
#ifdef __linux__
|
||||
if (credentials->priv->native.uid == other_credentials->priv->native.uid)
|
||||
ret = TRUE;
|
||||
#else
|
||||
g_set_error_literal (error,
|
||||
G_IO_ERROR,
|
||||
G_IO_ERROR_NOT_SUPPORTED,
|
||||
_("GCredentials is not implemented on this OS"));
|
||||
#endif
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/**
|
||||
* g_credentials_get_native:
|
||||
* @credentials: A #GCredentials.
|
||||
*
|
||||
* Gets a pointer to the native credentials structure.
|
||||
*
|
||||
* Returns: The pointer or %NULL if there is no #GCredentials support
|
||||
* for the OS. Do not free the returned data, it is owned by
|
||||
* @credentials.
|
||||
*
|
||||
* Since: 2.26
|
||||
*/
|
||||
gpointer
|
||||
g_credentials_get_native (GCredentials *credentials)
|
||||
{
|
||||
gpointer ret;
|
||||
g_return_val_if_fail (G_IS_CREDENTIALS (credentials), NULL);
|
||||
|
||||
#ifdef __linux__
|
||||
ret = &credentials->priv->native;
|
||||
#else
|
||||
ret = NULL;
|
||||
#endif
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/**
|
||||
* g_credentials_set_native:
|
||||
* @credentials: A #GCredentials.
|
||||
* @native: A pointer to native credentials.
|
||||
*
|
||||
* Copies the native credentials from @native into @credentials.
|
||||
*
|
||||
* It is a programming error (which will cause an warning to be
|
||||
* logged) to use this method if there is no #GCredentials support for
|
||||
* the OS.
|
||||
*
|
||||
* Since: 2.26
|
||||
*/
|
||||
void
|
||||
g_credentials_set_native (GCredentials *credentials,
|
||||
gpointer native)
|
||||
{
|
||||
#ifdef __linux__
|
||||
memcpy (&credentials->priv->native, native, sizeof (struct ucred));
|
||||
#else
|
||||
g_warning ("g_credentials_set_native: Trying to set credentials but GLib has no support "
|
||||
"for the native credentials type. Please add support.");
|
||||
#endif
|
||||
}
|
||||
|
||||
/* ---------------------------------------------------------------------------------------------------- */
|
||||
|
||||
#ifdef G_OS_UNIX
|
||||
/**
|
||||
* g_credentials_get_unix_user:
|
||||
* @credentials: A #GCredentials
|
||||
* @error: Return location for error or %NULL.
|
||||
*
|
||||
* Tries to get the UNIX user identifier from @credentials. This
|
||||
* method is only available on UNIX platforms.
|
||||
*
|
||||
* This operation can fail if #GCredentials is not supported on the
|
||||
* OS or if the native credentials type does not contain information
|
||||
* about the UNIX user.
|
||||
*
|
||||
* Returns: The UNIX user identifier or -1 if @error is set.
|
||||
*
|
||||
* Since: 2.26
|
||||
*/
|
||||
uid_t
|
||||
g_credentials_get_unix_user (GCredentials *credentials,
|
||||
GError **error)
|
||||
{
|
||||
uid_t ret;
|
||||
|
||||
g_return_val_if_fail (G_IS_CREDENTIALS (credentials), -1);
|
||||
g_return_val_if_fail (error == NULL || *error == NULL, -1);
|
||||
|
||||
#ifdef __linux__
|
||||
ret = credentials->priv->native.uid;
|
||||
#else
|
||||
ret = -1;
|
||||
g_set_error_literal (error,
|
||||
G_IO_ERROR,
|
||||
G_IO_ERROR_NOT_SUPPORTED,
|
||||
_("There no GCredentials support for your your platform"));
|
||||
#endif
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/**
|
||||
* g_credentials_set_unix_user:
|
||||
* @credentials: A #GCredentials.
|
||||
* @uid: The UNIX user identifier to set.
|
||||
* @error: Return location for error or %NULL.
|
||||
*
|
||||
* Tries to set the UNIX user identifier on @credentials. This method
|
||||
* is only available on UNIX platforms.
|
||||
*
|
||||
* This operation can fail if #GCredentials is not supported on the
|
||||
* OS or if the native credentials type does not contain information
|
||||
* about the UNIX user.
|
||||
*
|
||||
* Returns: %TRUE if @uid was set, %FALSE if error is set.
|
||||
*
|
||||
* Since: 2.26
|
||||
*/
|
||||
gboolean
|
||||
g_credentials_set_unix_user (GCredentials *credentials,
|
||||
uid_t uid,
|
||||
GError **error)
|
||||
{
|
||||
gboolean ret;
|
||||
|
||||
g_return_val_if_fail (G_IS_CREDENTIALS (credentials), FALSE);
|
||||
g_return_val_if_fail (uid != -1, FALSE);
|
||||
g_return_val_if_fail (error == NULL || *error == NULL, FALSE);
|
||||
|
||||
ret = FALSE;
|
||||
#ifdef __linux__
|
||||
credentials->priv->native.uid = uid;
|
||||
ret = TRUE;
|
||||
#else
|
||||
g_set_error_literal (error,
|
||||
G_IO_ERROR,
|
||||
G_IO_ERROR_NOT_SUPPORTED,
|
||||
_("GCredentials is not implemented on this OS"));
|
||||
#endif
|
||||
|
||||
return ret;
|
||||
}
|
||||
#endif /* G_OS_UNIX */
|
||||
|
||||
#define __G_CREDENTIALS_C__
|
||||
#include "gioaliasdef.c"
|
108
gio/gcredentials.h
Normal file
108
gio/gcredentials.h
Normal file
@ -0,0 +1,108 @@
|
||||
/* GDBus - GLib D-Bus Library
|
||||
*
|
||||
* Copyright (C) 2008-2010 Red Hat, Inc.
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General
|
||||
* Public License along with this library; if not, write to the
|
||||
* Free Software Foundation, Inc., 59 Temple Place, Suite 330,
|
||||
* Boston, MA 02111-1307, USA.
|
||||
*
|
||||
* Author: David Zeuthen <davidz@redhat.com>
|
||||
*/
|
||||
|
||||
#ifndef __G_CREDENTIALS_H__
|
||||
#define __G_CREDENTIALS_H__
|
||||
|
||||
#include <gio/giotypes.h>
|
||||
|
||||
#ifdef G_OS_UNIX
|
||||
/* To get the uid_t type */
|
||||
#include <unistd.h>
|
||||
#include <sys/types.h>
|
||||
#endif
|
||||
|
||||
G_BEGIN_DECLS
|
||||
|
||||
#define G_TYPE_CREDENTIALS (g_credentials_get_type ())
|
||||
#define G_CREDENTIALS(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), G_TYPE_CREDENTIALS, GCredentials))
|
||||
#define G_CREDENTIALS_CLASS(k) (G_TYPE_CHECK_CLASS_CAST((k), G_TYPE_CREDENTIALS, GCredentialsClass))
|
||||
#define G_CREDENTIALS_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS ((o), G_TYPE_CREDENTIALS, GCredentialsClass))
|
||||
#define G_IS_CREDENTIALS(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), G_TYPE_CREDENTIALS))
|
||||
#define G_IS_CREDENTIALS_CLASS(k) (G_TYPE_CHECK_CLASS_TYPE ((k), G_TYPE_CREDENTIALS))
|
||||
|
||||
typedef struct _GCredentialsClass GCredentialsClass;
|
||||
typedef struct _GCredentialsPrivate GCredentialsPrivate;
|
||||
|
||||
/**
|
||||
* GCredentials:
|
||||
*
|
||||
* The #GCredentials structure contains only private data and
|
||||
* should only be accessed using the provided API.
|
||||
*
|
||||
* Since: 2.26
|
||||
*/
|
||||
struct _GCredentials
|
||||
{
|
||||
/*< private >*/
|
||||
GObject parent_instance;
|
||||
GCredentialsPrivate *priv;
|
||||
};
|
||||
|
||||
/**
|
||||
* GCredentialsClass:
|
||||
*
|
||||
* Class structure for #GCredentials.
|
||||
*
|
||||
* Since: 2.26
|
||||
*/
|
||||
struct _GCredentialsClass
|
||||
{
|
||||
/*< private >*/
|
||||
GObjectClass parent_class;
|
||||
|
||||
/* Padding for future expansion */
|
||||
void (*_g_reserved1) (void);
|
||||
void (*_g_reserved2) (void);
|
||||
void (*_g_reserved3) (void);
|
||||
void (*_g_reserved4) (void);
|
||||
void (*_g_reserved5) (void);
|
||||
void (*_g_reserved6) (void);
|
||||
void (*_g_reserved7) (void);
|
||||
void (*_g_reserved8) (void);
|
||||
};
|
||||
|
||||
GType g_credentials_get_type (void) G_GNUC_CONST;
|
||||
|
||||
GCredentials *g_credentials_new (void);
|
||||
|
||||
gchar *g_credentials_to_string (GCredentials *credentials);
|
||||
|
||||
gpointer g_credentials_get_native (GCredentials *credentials);
|
||||
void g_credentials_set_native (GCredentials *credentials,
|
||||
gpointer native);
|
||||
|
||||
gboolean g_credentials_is_same_user (GCredentials *credentials,
|
||||
GCredentials *other_credentials,
|
||||
GError **error);
|
||||
|
||||
#ifdef G_OS_UNIX
|
||||
uid_t g_credentials_get_unix_user (GCredentials *credentials,
|
||||
GError **error);
|
||||
gboolean g_credentials_set_unix_user (GCredentials *credentials,
|
||||
uid_t uid,
|
||||
GError **error);
|
||||
#endif
|
||||
|
||||
G_END_DECLS
|
||||
|
||||
#endif /* __G_DBUS_PROXY_H__ */
|
33
gio/gdbus-bash-completion.sh
Normal file
33
gio/gdbus-bash-completion.sh
Normal file
@ -0,0 +1,33 @@
|
||||
|
||||
# Check for bash
|
||||
[ -z "$BASH_VERSION" ] && return
|
||||
|
||||
####################################################################################################
|
||||
|
||||
|
||||
__gdbus() {
|
||||
local IFS=$'\n'
|
||||
local cur=`_get_cword :`
|
||||
|
||||
local suggestions=$(gdbus complete "${COMP_LINE}" ${COMP_POINT})
|
||||
COMPREPLY=($(compgen -W "$suggestions" -- "$cur"))
|
||||
|
||||
# Remove colon-word prefix from COMPREPLY items
|
||||
case "$cur" in
|
||||
*:*)
|
||||
case "$COMP_WORDBREAKS" in
|
||||
*:*)
|
||||
local colon_word=${cur%${cur##*:}}
|
||||
local i=${#COMPREPLY[*]}
|
||||
while [ $((--i)) -ge 0 ]; do
|
||||
COMPREPLY[$i]=${COMPREPLY[$i]#"$colon_word"}
|
||||
done
|
||||
;;
|
||||
esac
|
||||
;;
|
||||
esac
|
||||
}
|
||||
|
||||
####################################################################################################
|
||||
|
||||
complete -o nospace -F __gdbus gdbus
|
1816
gio/gdbus-tool.c
Normal file
1816
gio/gdbus-tool.c
Normal file
File diff suppressed because it is too large
Load Diff
1023
gio/gdbusaddress.c
Normal file
1023
gio/gdbusaddress.c
Normal file
File diff suppressed because it is too large
Load Diff
54
gio/gdbusaddress.h
Normal file
54
gio/gdbusaddress.h
Normal file
@ -0,0 +1,54 @@
|
||||
/* GDBus - GLib D-Bus Library
|
||||
*
|
||||
* Copyright (C) 2008-2010 Red Hat, Inc.
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General
|
||||
* Public License along with this library; if not, write to the
|
||||
* Free Software Foundation, Inc., 59 Temple Place, Suite 330,
|
||||
* Boston, MA 02111-1307, USA.
|
||||
*
|
||||
* Author: David Zeuthen <davidz@redhat.com>
|
||||
*/
|
||||
|
||||
#ifndef __G_DBUS_ADDRESS_H__
|
||||
#define __G_DBUS_ADDRESS_H__
|
||||
|
||||
#include <gio/giotypes.h>
|
||||
|
||||
G_BEGIN_DECLS
|
||||
|
||||
gboolean g_dbus_is_address (const gchar *string);
|
||||
gboolean g_dbus_is_supported_address (const gchar *string,
|
||||
GError **error);
|
||||
|
||||
void g_dbus_address_get_stream (const gchar *address,
|
||||
GCancellable *cancellable,
|
||||
GAsyncReadyCallback callback,
|
||||
gpointer user_data);
|
||||
|
||||
GIOStream *g_dbus_address_get_stream_finish (GAsyncResult *res,
|
||||
gchar **out_guid,
|
||||
GError **error);
|
||||
|
||||
GIOStream *g_dbus_address_get_stream_sync (const gchar *address,
|
||||
gchar **out_guid,
|
||||
GCancellable *cancellable,
|
||||
GError **error);
|
||||
|
||||
gchar *g_dbus_address_get_for_bus_sync (GBusType bus_type,
|
||||
GCancellable *cancellable,
|
||||
GError **error);
|
||||
|
||||
G_END_DECLS
|
||||
|
||||
#endif /* __G_DBUS_ADDRESS_H__ */
|
1352
gio/gdbusauth.c
Normal file
1352
gio/gdbusauth.c
Normal file
File diff suppressed because it is too large
Load Diff
86
gio/gdbusauth.h
Normal file
86
gio/gdbusauth.h
Normal file
@ -0,0 +1,86 @@
|
||||
/* GDBus - GLib D-Bus Library
|
||||
*
|
||||
* Copyright (C) 2008-2010 Red Hat, Inc.
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General
|
||||
* Public License along with this library; if not, write to the
|
||||
* Free Software Foundation, Inc., 59 Temple Place, Suite 330,
|
||||
* Boston, MA 02111-1307, USA.
|
||||
*
|
||||
* Author: David Zeuthen <davidz@redhat.com>
|
||||
*/
|
||||
|
||||
#if !defined (GIO_COMPILATION)
|
||||
#error "gdbusauth.h is a private header file."
|
||||
#endif
|
||||
|
||||
#ifndef __G_DBUS_AUTH_H__
|
||||
#define __G_DBUS_AUTH_H__
|
||||
|
||||
#include <gio/giotypes.h>
|
||||
|
||||
G_BEGIN_DECLS
|
||||
|
||||
#define G_TYPE_DBUS_AUTH (_g_dbus_auth_get_type ())
|
||||
#define G_DBUS_AUTH(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), G_TYPE_DBUS_AUTH, GDBusAuth))
|
||||
#define G_DBUS_AUTH_CLASS(k) (G_TYPE_CHECK_CLASS_CAST((k), G_TYPE_DBUS_AUTH, GDBusAuthClass))
|
||||
#define G_DBUS_AUTH_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS ((o), G_TYPE_DBUS_AUTH, GDBusAuthClass))
|
||||
#define G_IS_DBUS_AUTH(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), G_TYPE_DBUS_AUTH))
|
||||
#define G_IS_DBUS_AUTH_CLASS(k) (G_TYPE_CHECK_CLASS_TYPE ((k), G_TYPE_DBUS_AUTH))
|
||||
|
||||
typedef struct _GDBusAuth GDBusAuth;
|
||||
typedef struct _GDBusAuthClass GDBusAuthClass;
|
||||
typedef struct _GDBusAuthPrivate GDBusAuthPrivate;
|
||||
|
||||
struct _GDBusAuthClass
|
||||
{
|
||||
/*< private >*/
|
||||
GObjectClass parent_class;
|
||||
};
|
||||
|
||||
struct _GDBusAuth
|
||||
{
|
||||
GObject parent_instance;
|
||||
GDBusAuthPrivate *priv;
|
||||
};
|
||||
|
||||
GType _g_dbus_auth_get_type (void) G_GNUC_CONST;
|
||||
GDBusAuth *_g_dbus_auth_new (GIOStream *stream);
|
||||
|
||||
/* TODO: need a way to set allowed authentication mechanisms */
|
||||
|
||||
/* TODO: need a way to convey credentials etc. */
|
||||
|
||||
/* TODO: need a way to convey negotiated features (e.g. returning flags from e.g. GDBusConnectionFeatures) */
|
||||
|
||||
/* TODO: need to expose encode()/decode() from the AuthMechanism (and whether it is needed at all) */
|
||||
|
||||
gboolean _g_dbus_auth_run_server (GDBusAuth *auth,
|
||||
GDBusAuthObserver *observer,
|
||||
const gchar *guid,
|
||||
gboolean allow_anonymous,
|
||||
GDBusCapabilityFlags offered_capabilities,
|
||||
GDBusCapabilityFlags *out_negotiated_capabilities,
|
||||
GCredentials **out_received_credentials,
|
||||
GCancellable *cancellable,
|
||||
GError **error);
|
||||
|
||||
gchar *_g_dbus_auth_run_client (GDBusAuth *auth,
|
||||
GDBusCapabilityFlags offered_capabilities,
|
||||
GDBusCapabilityFlags *out_negotiated_capabilities,
|
||||
GCancellable *cancellable,
|
||||
GError **error);
|
||||
|
||||
G_END_DECLS
|
||||
|
||||
#endif /* __G_DBUS_AUTH_H__ */
|
345
gio/gdbusauthmechanism.c
Normal file
345
gio/gdbusauthmechanism.c
Normal file
@ -0,0 +1,345 @@
|
||||
/* GDBus - GLib D-Bus Library
|
||||
*
|
||||
* Copyright (C) 2008-2010 Red Hat, Inc.
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General
|
||||
* Public License along with this library; if not, write to the
|
||||
* Free Software Foundation, Inc., 59 Temple Place, Suite 330,
|
||||
* Boston, MA 02111-1307, USA.
|
||||
*
|
||||
* Author: David Zeuthen <davidz@redhat.com>
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include "gdbusauthmechanism.h"
|
||||
#include "gcredentials.h"
|
||||
#include "gdbuserror.h"
|
||||
#include "gioenumtypes.h"
|
||||
#include "giostream.h"
|
||||
|
||||
#include "glibintl.h"
|
||||
#include "gioalias.h"
|
||||
|
||||
/* ---------------------------------------------------------------------------------------------------- */
|
||||
|
||||
struct _GDBusAuthMechanismPrivate
|
||||
{
|
||||
GIOStream *stream;
|
||||
GCredentials *credentials;
|
||||
};
|
||||
|
||||
enum
|
||||
{
|
||||
PROP_0,
|
||||
PROP_STREAM,
|
||||
PROP_CREDENTIALS
|
||||
};
|
||||
|
||||
G_DEFINE_ABSTRACT_TYPE (GDBusAuthMechanism, _g_dbus_auth_mechanism, G_TYPE_OBJECT);
|
||||
|
||||
/* ---------------------------------------------------------------------------------------------------- */
|
||||
|
||||
static void
|
||||
_g_dbus_auth_mechanism_finalize (GObject *object)
|
||||
{
|
||||
GDBusAuthMechanism *mechanism = G_DBUS_AUTH_MECHANISM (object);
|
||||
|
||||
if (mechanism->priv->stream != NULL)
|
||||
g_object_unref (mechanism->priv->stream);
|
||||
if (mechanism->priv->credentials != NULL)
|
||||
g_object_unref (mechanism->priv->credentials);
|
||||
|
||||
G_OBJECT_CLASS (_g_dbus_auth_mechanism_parent_class)->finalize (object);
|
||||
}
|
||||
|
||||
static void
|
||||
_g_dbus_auth_mechanism_get_property (GObject *object,
|
||||
guint prop_id,
|
||||
GValue *value,
|
||||
GParamSpec *pspec)
|
||||
{
|
||||
GDBusAuthMechanism *mechanism = G_DBUS_AUTH_MECHANISM (object);
|
||||
|
||||
switch (prop_id)
|
||||
{
|
||||
case PROP_STREAM:
|
||||
g_value_set_object (value, mechanism->priv->stream);
|
||||
break;
|
||||
|
||||
case PROP_CREDENTIALS:
|
||||
g_value_set_object (value, mechanism->priv->credentials);
|
||||
break;
|
||||
|
||||
default:
|
||||
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
_g_dbus_auth_mechanism_set_property (GObject *object,
|
||||
guint prop_id,
|
||||
const GValue *value,
|
||||
GParamSpec *pspec)
|
||||
{
|
||||
GDBusAuthMechanism *mechanism = G_DBUS_AUTH_MECHANISM (object);
|
||||
|
||||
switch (prop_id)
|
||||
{
|
||||
case PROP_STREAM:
|
||||
mechanism->priv->stream = g_value_dup_object (value);
|
||||
break;
|
||||
|
||||
case PROP_CREDENTIALS:
|
||||
mechanism->priv->credentials = g_value_dup_object (value);
|
||||
break;
|
||||
|
||||
default:
|
||||
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
_g_dbus_auth_mechanism_class_init (GDBusAuthMechanismClass *klass)
|
||||
{
|
||||
GObjectClass *gobject_class;
|
||||
|
||||
g_type_class_add_private (klass, sizeof (GDBusAuthMechanismPrivate));
|
||||
|
||||
gobject_class = G_OBJECT_CLASS (klass);
|
||||
gobject_class->get_property = _g_dbus_auth_mechanism_get_property;
|
||||
gobject_class->set_property = _g_dbus_auth_mechanism_set_property;
|
||||
gobject_class->finalize = _g_dbus_auth_mechanism_finalize;
|
||||
|
||||
g_object_class_install_property (gobject_class,
|
||||
PROP_STREAM,
|
||||
g_param_spec_object ("stream",
|
||||
P_("IO Stream"),
|
||||
P_("The underlying GIOStream used for I/O"),
|
||||
G_TYPE_IO_STREAM,
|
||||
G_PARAM_READABLE |
|
||||
G_PARAM_WRITABLE |
|
||||
G_PARAM_CONSTRUCT_ONLY |
|
||||
G_PARAM_STATIC_NAME |
|
||||
G_PARAM_STATIC_BLURB |
|
||||
G_PARAM_STATIC_NICK));
|
||||
|
||||
/**
|
||||
* GDBusAuthMechanism:credentials:
|
||||
*
|
||||
* If authenticating as a server, this property contains the
|
||||
* received credentials, if any.
|
||||
*
|
||||
* If authenticating as a client, the property contains the
|
||||
* credentials that were sent, if any.
|
||||
*/
|
||||
g_object_class_install_property (gobject_class,
|
||||
PROP_CREDENTIALS,
|
||||
g_param_spec_object ("credentials",
|
||||
P_("Credentials"),
|
||||
P_("The credentials of the remote peer"),
|
||||
G_TYPE_CREDENTIALS,
|
||||
G_PARAM_READABLE |
|
||||
G_PARAM_WRITABLE |
|
||||
G_PARAM_CONSTRUCT_ONLY |
|
||||
G_PARAM_STATIC_NAME |
|
||||
G_PARAM_STATIC_BLURB |
|
||||
G_PARAM_STATIC_NICK));
|
||||
}
|
||||
|
||||
static void
|
||||
_g_dbus_auth_mechanism_init (GDBusAuthMechanism *mechanism)
|
||||
{
|
||||
/* not used for now */
|
||||
mechanism->priv = G_TYPE_INSTANCE_GET_PRIVATE (mechanism,
|
||||
G_TYPE_DBUS_AUTH_MECHANISM,
|
||||
GDBusAuthMechanismPrivate);
|
||||
}
|
||||
|
||||
/* ---------------------------------------------------------------------------------------------------- */
|
||||
|
||||
GIOStream *
|
||||
_g_dbus_auth_mechanism_get_stream (GDBusAuthMechanism *mechanism)
|
||||
{
|
||||
g_return_val_if_fail (G_IS_DBUS_AUTH_MECHANISM (mechanism), NULL);
|
||||
return mechanism->priv->stream;
|
||||
}
|
||||
|
||||
GCredentials *
|
||||
_g_dbus_auth_mechanism_get_credentials (GDBusAuthMechanism *mechanism)
|
||||
{
|
||||
g_return_val_if_fail (G_IS_DBUS_AUTH_MECHANISM (mechanism), NULL);
|
||||
return mechanism->priv->credentials;
|
||||
}
|
||||
|
||||
/* ---------------------------------------------------------------------------------------------------- */
|
||||
|
||||
const gchar *
|
||||
_g_dbus_auth_mechanism_get_name (GType mechanism_type)
|
||||
{
|
||||
const gchar *name;
|
||||
GDBusAuthMechanismClass *klass;
|
||||
|
||||
g_return_val_if_fail (g_type_is_a (mechanism_type, G_TYPE_DBUS_AUTH_MECHANISM), NULL);
|
||||
|
||||
klass = g_type_class_ref (mechanism_type);
|
||||
g_assert (klass != NULL);
|
||||
name = klass->get_name ();
|
||||
//g_type_class_unref (klass);
|
||||
|
||||
return name;
|
||||
}
|
||||
|
||||
gint
|
||||
_g_dbus_auth_mechanism_get_priority (GType mechanism_type)
|
||||
{
|
||||
gint priority;
|
||||
GDBusAuthMechanismClass *klass;
|
||||
|
||||
g_return_val_if_fail (g_type_is_a (mechanism_type, G_TYPE_DBUS_AUTH_MECHANISM), 0);
|
||||
|
||||
klass = g_type_class_ref (mechanism_type);
|
||||
g_assert (klass != NULL);
|
||||
priority = klass->get_priority ();
|
||||
//g_type_class_unref (klass);
|
||||
|
||||
return priority;
|
||||
}
|
||||
|
||||
/* ---------------------------------------------------------------------------------------------------- */
|
||||
|
||||
gboolean
|
||||
_g_dbus_auth_mechanism_is_supported (GDBusAuthMechanism *mechanism)
|
||||
{
|
||||
g_return_val_if_fail (G_IS_DBUS_AUTH_MECHANISM (mechanism), FALSE);
|
||||
return G_DBUS_AUTH_MECHANISM_GET_CLASS (mechanism)->is_supported (mechanism);
|
||||
}
|
||||
|
||||
gchar *
|
||||
_g_dbus_auth_mechanism_encode_data (GDBusAuthMechanism *mechanism,
|
||||
const gchar *data,
|
||||
gsize data_len,
|
||||
gsize *out_data_len)
|
||||
{
|
||||
g_return_val_if_fail (G_IS_DBUS_AUTH_MECHANISM (mechanism), NULL);
|
||||
return G_DBUS_AUTH_MECHANISM_GET_CLASS (mechanism)->encode_data (mechanism, data, data_len, out_data_len);
|
||||
}
|
||||
|
||||
|
||||
gchar *
|
||||
_g_dbus_auth_mechanism_decode_data (GDBusAuthMechanism *mechanism,
|
||||
const gchar *data,
|
||||
gsize data_len,
|
||||
gsize *out_data_len)
|
||||
{
|
||||
g_return_val_if_fail (G_IS_DBUS_AUTH_MECHANISM (mechanism), NULL);
|
||||
return G_DBUS_AUTH_MECHANISM_GET_CLASS (mechanism)->decode_data (mechanism, data, data_len, out_data_len);
|
||||
}
|
||||
|
||||
/* ---------------------------------------------------------------------------------------------------- */
|
||||
|
||||
GDBusAuthMechanismState
|
||||
_g_dbus_auth_mechanism_server_get_state (GDBusAuthMechanism *mechanism)
|
||||
{
|
||||
g_return_val_if_fail (G_IS_DBUS_AUTH_MECHANISM (mechanism), G_DBUS_AUTH_MECHANISM_STATE_INVALID);
|
||||
return G_DBUS_AUTH_MECHANISM_GET_CLASS (mechanism)->server_get_state (mechanism);
|
||||
}
|
||||
|
||||
void
|
||||
_g_dbus_auth_mechanism_server_initiate (GDBusAuthMechanism *mechanism,
|
||||
const gchar *initial_response,
|
||||
gsize initial_response_len)
|
||||
{
|
||||
g_return_if_fail (G_IS_DBUS_AUTH_MECHANISM (mechanism));
|
||||
G_DBUS_AUTH_MECHANISM_GET_CLASS (mechanism)->server_initiate (mechanism, initial_response, initial_response_len);
|
||||
}
|
||||
|
||||
void
|
||||
_g_dbus_auth_mechanism_server_data_receive (GDBusAuthMechanism *mechanism,
|
||||
const gchar *data,
|
||||
gsize data_len)
|
||||
{
|
||||
g_return_if_fail (G_IS_DBUS_AUTH_MECHANISM (mechanism));
|
||||
G_DBUS_AUTH_MECHANISM_GET_CLASS (mechanism)->server_data_receive (mechanism, data, data_len);
|
||||
}
|
||||
|
||||
gchar *
|
||||
_g_dbus_auth_mechanism_server_data_send (GDBusAuthMechanism *mechanism,
|
||||
gsize *out_data_len)
|
||||
{
|
||||
g_return_val_if_fail (G_IS_DBUS_AUTH_MECHANISM (mechanism), NULL);
|
||||
return G_DBUS_AUTH_MECHANISM_GET_CLASS (mechanism)->server_data_send (mechanism, out_data_len);
|
||||
}
|
||||
|
||||
gchar *
|
||||
_g_dbus_auth_mechanism_server_get_reject_reason (GDBusAuthMechanism *mechanism)
|
||||
{
|
||||
g_return_val_if_fail (G_IS_DBUS_AUTH_MECHANISM (mechanism), NULL);
|
||||
return G_DBUS_AUTH_MECHANISM_GET_CLASS (mechanism)->server_get_reject_reason (mechanism);
|
||||
}
|
||||
|
||||
void
|
||||
_g_dbus_auth_mechanism_server_shutdown (GDBusAuthMechanism *mechanism)
|
||||
{
|
||||
g_return_if_fail (G_IS_DBUS_AUTH_MECHANISM (mechanism));
|
||||
G_DBUS_AUTH_MECHANISM_GET_CLASS (mechanism)->server_shutdown (mechanism);
|
||||
}
|
||||
|
||||
/* ---------------------------------------------------------------------------------------------------- */
|
||||
|
||||
GDBusAuthMechanismState
|
||||
_g_dbus_auth_mechanism_client_get_state (GDBusAuthMechanism *mechanism)
|
||||
{
|
||||
g_return_val_if_fail (G_IS_DBUS_AUTH_MECHANISM (mechanism), G_DBUS_AUTH_MECHANISM_STATE_INVALID);
|
||||
return G_DBUS_AUTH_MECHANISM_GET_CLASS (mechanism)->client_get_state (mechanism);
|
||||
}
|
||||
|
||||
gchar *
|
||||
_g_dbus_auth_mechanism_client_initiate (GDBusAuthMechanism *mechanism,
|
||||
gsize *out_initial_response_len)
|
||||
{
|
||||
g_return_val_if_fail (G_IS_DBUS_AUTH_MECHANISM (mechanism), NULL);
|
||||
return G_DBUS_AUTH_MECHANISM_GET_CLASS (mechanism)->client_initiate (mechanism,
|
||||
out_initial_response_len);
|
||||
}
|
||||
|
||||
void
|
||||
_g_dbus_auth_mechanism_client_data_receive (GDBusAuthMechanism *mechanism,
|
||||
const gchar *data,
|
||||
gsize data_len)
|
||||
{
|
||||
g_return_if_fail (G_IS_DBUS_AUTH_MECHANISM (mechanism));
|
||||
G_DBUS_AUTH_MECHANISM_GET_CLASS (mechanism)->client_data_receive (mechanism, data, data_len);
|
||||
}
|
||||
|
||||
gchar *
|
||||
_g_dbus_auth_mechanism_client_data_send (GDBusAuthMechanism *mechanism,
|
||||
gsize *out_data_len)
|
||||
{
|
||||
g_return_val_if_fail (G_IS_DBUS_AUTH_MECHANISM (mechanism), NULL);
|
||||
return G_DBUS_AUTH_MECHANISM_GET_CLASS (mechanism)->client_data_send (mechanism, out_data_len);
|
||||
}
|
||||
|
||||
void
|
||||
_g_dbus_auth_mechanism_client_shutdown (GDBusAuthMechanism *mechanism)
|
||||
{
|
||||
g_return_if_fail (G_IS_DBUS_AUTH_MECHANISM (mechanism));
|
||||
G_DBUS_AUTH_MECHANISM_GET_CLASS (mechanism)->client_shutdown (mechanism);
|
||||
}
|
||||
|
||||
/* ---------------------------------------------------------------------------------------------------- */
|
||||
|
||||
#define __G_DBUS_AUTH_MECHANISM_C__
|
||||
#include "gioaliasdef.c"
|
174
gio/gdbusauthmechanism.h
Normal file
174
gio/gdbusauthmechanism.h
Normal file
@ -0,0 +1,174 @@
|
||||
/* GDBus - GLib D-Bus Library
|
||||
*
|
||||
* Copyright (C) 2008-2010 Red Hat, Inc.
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General
|
||||
* Public License along with this library; if not, write to the
|
||||
* Free Software Foundation, Inc., 59 Temple Place, Suite 330,
|
||||
* Boston, MA 02111-1307, USA.
|
||||
*
|
||||
* Author: David Zeuthen <davidz@redhat.com>
|
||||
*/
|
||||
|
||||
#if !defined (GIO_COMPILATION)
|
||||
#error "gdbusauthmechanism.h is a private header file."
|
||||
#endif
|
||||
|
||||
#ifndef __G_DBUS_AUTH_MECHANISM_H__
|
||||
#define __G_DBUS_AUTH_MECHANISM_H__
|
||||
|
||||
#include <gio/giotypes.h>
|
||||
|
||||
G_BEGIN_DECLS
|
||||
|
||||
#define G_TYPE_DBUS_AUTH_MECHANISM (_g_dbus_auth_mechanism_get_type ())
|
||||
#define G_DBUS_AUTH_MECHANISM(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), G_TYPE_DBUS_AUTH_MECHANISM, GDBusAuthMechanism))
|
||||
#define G_DBUS_AUTH_MECHANISM_CLASS(k) (G_TYPE_CHECK_CLASS_CAST((k), G_TYPE_DBUS_AUTH_MECHANISM, GDBusAuthMechanismClass))
|
||||
#define G_DBUS_AUTH_MECHANISM_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS ((o), G_TYPE_DBUS_AUTH_MECHANISM, GDBusAuthMechanismClass))
|
||||
#define G_IS_DBUS_AUTH_MECHANISM(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), G_TYPE_DBUS_AUTH_MECHANISM))
|
||||
#define G_IS_DBUS_AUTH_MECHANISM_CLASS(k) (G_TYPE_CHECK_CLASS_TYPE ((k), G_TYPE_DBUS_AUTH_MECHANISM))
|
||||
|
||||
typedef struct _GDBusAuthMechanism GDBusAuthMechanism;
|
||||
typedef struct _GDBusAuthMechanismClass GDBusAuthMechanismClass;
|
||||
typedef struct _GDBusAuthMechanismPrivate GDBusAuthMechanismPrivate;
|
||||
|
||||
typedef enum {
|
||||
G_DBUS_AUTH_MECHANISM_STATE_INVALID,
|
||||
G_DBUS_AUTH_MECHANISM_STATE_WAITING_FOR_DATA,
|
||||
G_DBUS_AUTH_MECHANISM_STATE_HAVE_DATA_TO_SEND,
|
||||
G_DBUS_AUTH_MECHANISM_STATE_REJECTED,
|
||||
G_DBUS_AUTH_MECHANISM_STATE_ACCEPTED,
|
||||
} GDBusAuthMechanismState;
|
||||
|
||||
struct _GDBusAuthMechanismClass
|
||||
{
|
||||
/*< private >*/
|
||||
GObjectClass parent_class;
|
||||
|
||||
/*< public >*/
|
||||
|
||||
/* VTable */
|
||||
|
||||
/* TODO: server_initiate and client_initiate probably needs to have a
|
||||
* GCredentials parameter...
|
||||
*/
|
||||
|
||||
gint (*get_priority) (void);
|
||||
const gchar *(*get_name) (void);
|
||||
|
||||
/* functions shared by server/client */
|
||||
gboolean (*is_supported) (GDBusAuthMechanism *mechanism);
|
||||
gchar *(*encode_data) (GDBusAuthMechanism *mechanism,
|
||||
const gchar *data,
|
||||
gsize data_len,
|
||||
gsize *out_data_len);
|
||||
gchar *(*decode_data) (GDBusAuthMechanism *mechanism,
|
||||
const gchar *data,
|
||||
gsize data_len,
|
||||
gsize *out_data_len);
|
||||
|
||||
/* functions for server-side authentication */
|
||||
GDBusAuthMechanismState (*server_get_state) (GDBusAuthMechanism *mechanism);
|
||||
void (*server_initiate) (GDBusAuthMechanism *mechanism,
|
||||
const gchar *initial_response,
|
||||
gsize initial_response_len);
|
||||
void (*server_data_receive) (GDBusAuthMechanism *mechanism,
|
||||
const gchar *data,
|
||||
gsize data_len);
|
||||
gchar *(*server_data_send) (GDBusAuthMechanism *mechanism,
|
||||
gsize *out_data_len);
|
||||
gchar *(*server_get_reject_reason) (GDBusAuthMechanism *mechanism);
|
||||
void (*server_shutdown) (GDBusAuthMechanism *mechanism);
|
||||
|
||||
/* functions for client-side authentication */
|
||||
GDBusAuthMechanismState (*client_get_state) (GDBusAuthMechanism *mechanism);
|
||||
gchar *(*client_initiate) (GDBusAuthMechanism *mechanism,
|
||||
gsize *out_initial_response_len);
|
||||
void (*client_data_receive) (GDBusAuthMechanism *mechanism,
|
||||
const gchar *data,
|
||||
gsize data_len);
|
||||
gchar *(*client_data_send) (GDBusAuthMechanism *mechanism,
|
||||
gsize *out_data_len);
|
||||
void (*client_shutdown) (GDBusAuthMechanism *mechanism);
|
||||
|
||||
|
||||
/*< private >*/
|
||||
/* Padding for future expansion */
|
||||
void (*_g_reserved1) (void);
|
||||
void (*_g_reserved2) (void);
|
||||
void (*_g_reserved3) (void);
|
||||
void (*_g_reserved4) (void);
|
||||
void (*_g_reserved5) (void);
|
||||
void (*_g_reserved6) (void);
|
||||
void (*_g_reserved7) (void);
|
||||
void (*_g_reserved8) (void);
|
||||
void (*_g_reserved9) (void);
|
||||
void (*_g_reserved10) (void);
|
||||
void (*_g_reserved11) (void);
|
||||
void (*_g_reserved12) (void);
|
||||
void (*_g_reserved13) (void);
|
||||
void (*_g_reserved14) (void);
|
||||
void (*_g_reserved15) (void);
|
||||
void (*_g_reserved16) (void);
|
||||
};
|
||||
|
||||
struct _GDBusAuthMechanism
|
||||
{
|
||||
GObject parent_instance;
|
||||
GDBusAuthMechanismPrivate *priv;
|
||||
};
|
||||
|
||||
GType _g_dbus_auth_mechanism_get_type (void) G_GNUC_CONST;
|
||||
|
||||
gint _g_dbus_auth_mechanism_get_priority (GType mechanism_type);
|
||||
const gchar *_g_dbus_auth_mechanism_get_name (GType mechanism_type);
|
||||
|
||||
GIOStream *_g_dbus_auth_mechanism_get_stream (GDBusAuthMechanism *mechanism);
|
||||
GCredentials *_g_dbus_auth_mechanism_get_credentials (GDBusAuthMechanism *mechanism);
|
||||
|
||||
gboolean _g_dbus_auth_mechanism_is_supported (GDBusAuthMechanism *mechanism);
|
||||
gchar *_g_dbus_auth_mechanism_encode_data (GDBusAuthMechanism *mechanism,
|
||||
const gchar *data,
|
||||
gsize data_len,
|
||||
gsize *out_data_len);
|
||||
gchar *_g_dbus_auth_mechanism_decode_data (GDBusAuthMechanism *mechanism,
|
||||
const gchar *data,
|
||||
gsize data_len,
|
||||
gsize *out_data_len);
|
||||
|
||||
GDBusAuthMechanismState _g_dbus_auth_mechanism_server_get_state (GDBusAuthMechanism *mechanism);
|
||||
void _g_dbus_auth_mechanism_server_initiate (GDBusAuthMechanism *mechanism,
|
||||
const gchar *initial_response,
|
||||
gsize initial_response_len);
|
||||
void _g_dbus_auth_mechanism_server_data_receive (GDBusAuthMechanism *mechanism,
|
||||
const gchar *data,
|
||||
gsize data_len);
|
||||
gchar *_g_dbus_auth_mechanism_server_data_send (GDBusAuthMechanism *mechanism,
|
||||
gsize *out_data_len);
|
||||
gchar *_g_dbus_auth_mechanism_server_get_reject_reason (GDBusAuthMechanism *mechanism);
|
||||
void _g_dbus_auth_mechanism_server_shutdown (GDBusAuthMechanism *mechanism);
|
||||
|
||||
GDBusAuthMechanismState _g_dbus_auth_mechanism_client_get_state (GDBusAuthMechanism *mechanism);
|
||||
gchar *_g_dbus_auth_mechanism_client_initiate (GDBusAuthMechanism *mechanism,
|
||||
gsize *out_initial_response_len);
|
||||
void _g_dbus_auth_mechanism_client_data_receive (GDBusAuthMechanism *mechanism,
|
||||
const gchar *data,
|
||||
gsize data_len);
|
||||
gchar *_g_dbus_auth_mechanism_client_data_send (GDBusAuthMechanism *mechanism,
|
||||
gsize *out_data_len);
|
||||
void _g_dbus_auth_mechanism_client_shutdown (GDBusAuthMechanism *mechanism);
|
||||
|
||||
|
||||
G_END_DECLS
|
||||
|
||||
#endif /* __G_DBUS_AUTH_MECHANISM_H__ */
|
331
gio/gdbusauthmechanismanon.c
Normal file
331
gio/gdbusauthmechanismanon.c
Normal file
@ -0,0 +1,331 @@
|
||||
/* GDBus - GLib D-Bus Library
|
||||
*
|
||||
* Copyright (C) 2008-2010 Red Hat, Inc.
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General
|
||||
* Public License along with this library; if not, write to the
|
||||
* Free Software Foundation, Inc., 59 Temple Place, Suite 330,
|
||||
* Boston, MA 02111-1307, USA.
|
||||
*
|
||||
* Author: David Zeuthen <davidz@redhat.com>
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include "gdbusauthmechanismanon.h"
|
||||
#include "gdbuserror.h"
|
||||
#include "gioenumtypes.h"
|
||||
|
||||
#include "glibintl.h"
|
||||
#include "gioalias.h"
|
||||
|
||||
struct _GDBusAuthMechanismAnonPrivate
|
||||
{
|
||||
gboolean is_client;
|
||||
gboolean is_server;
|
||||
GDBusAuthMechanismState state;
|
||||
};
|
||||
|
||||
static gint mechanism_get_priority (void);
|
||||
static const gchar *mechanism_get_name (void);
|
||||
|
||||
static gboolean mechanism_is_supported (GDBusAuthMechanism *mechanism);
|
||||
static gchar *mechanism_encode_data (GDBusAuthMechanism *mechanism,
|
||||
const gchar *data,
|
||||
gsize data_len,
|
||||
gsize *out_data_len);
|
||||
static gchar *mechanism_decode_data (GDBusAuthMechanism *mechanism,
|
||||
const gchar *data,
|
||||
gsize data_len,
|
||||
gsize *out_data_len);
|
||||
static GDBusAuthMechanismState mechanism_server_get_state (GDBusAuthMechanism *mechanism);
|
||||
static void mechanism_server_initiate (GDBusAuthMechanism *mechanism,
|
||||
const gchar *initial_response,
|
||||
gsize initial_response_len);
|
||||
static void mechanism_server_data_receive (GDBusAuthMechanism *mechanism,
|
||||
const gchar *data,
|
||||
gsize data_len);
|
||||
static gchar *mechanism_server_data_send (GDBusAuthMechanism *mechanism,
|
||||
gsize *out_data_len);
|
||||
static gchar *mechanism_server_get_reject_reason (GDBusAuthMechanism *mechanism);
|
||||
static void mechanism_server_shutdown (GDBusAuthMechanism *mechanism);
|
||||
static GDBusAuthMechanismState mechanism_client_get_state (GDBusAuthMechanism *mechanism);
|
||||
static gchar *mechanism_client_initiate (GDBusAuthMechanism *mechanism,
|
||||
gsize *out_initial_response_len);
|
||||
static void mechanism_client_data_receive (GDBusAuthMechanism *mechanism,
|
||||
const gchar *data,
|
||||
gsize data_len);
|
||||
static gchar *mechanism_client_data_send (GDBusAuthMechanism *mechanism,
|
||||
gsize *out_data_len);
|
||||
static void mechanism_client_shutdown (GDBusAuthMechanism *mechanism);
|
||||
|
||||
/* ---------------------------------------------------------------------------------------------------- */
|
||||
|
||||
G_DEFINE_TYPE (GDBusAuthMechanismAnon, _g_dbus_auth_mechanism_anon, G_TYPE_DBUS_AUTH_MECHANISM);
|
||||
|
||||
/* ---------------------------------------------------------------------------------------------------- */
|
||||
|
||||
static void
|
||||
_g_dbus_auth_mechanism_anon_finalize (GObject *object)
|
||||
{
|
||||
//GDBusAuthMechanismAnon *mechanism = G_DBUS_AUTH_MECHANISM_ANON (object);
|
||||
|
||||
if (G_OBJECT_CLASS (_g_dbus_auth_mechanism_anon_parent_class)->finalize != NULL)
|
||||
G_OBJECT_CLASS (_g_dbus_auth_mechanism_anon_parent_class)->finalize (object);
|
||||
}
|
||||
|
||||
static void
|
||||
_g_dbus_auth_mechanism_anon_class_init (GDBusAuthMechanismAnonClass *klass)
|
||||
{
|
||||
GObjectClass *gobject_class;
|
||||
GDBusAuthMechanismClass *mechanism_class;
|
||||
|
||||
g_type_class_add_private (klass, sizeof (GDBusAuthMechanismAnonPrivate));
|
||||
|
||||
gobject_class = G_OBJECT_CLASS (klass);
|
||||
gobject_class->finalize = _g_dbus_auth_mechanism_anon_finalize;
|
||||
|
||||
mechanism_class = G_DBUS_AUTH_MECHANISM_CLASS (klass);
|
||||
mechanism_class->get_priority = mechanism_get_priority;
|
||||
mechanism_class->get_name = mechanism_get_name;
|
||||
mechanism_class->is_supported = mechanism_is_supported;
|
||||
mechanism_class->encode_data = mechanism_encode_data;
|
||||
mechanism_class->decode_data = mechanism_decode_data;
|
||||
mechanism_class->server_get_state = mechanism_server_get_state;
|
||||
mechanism_class->server_initiate = mechanism_server_initiate;
|
||||
mechanism_class->server_data_receive = mechanism_server_data_receive;
|
||||
mechanism_class->server_data_send = mechanism_server_data_send;
|
||||
mechanism_class->server_get_reject_reason = mechanism_server_get_reject_reason;
|
||||
mechanism_class->server_shutdown = mechanism_server_shutdown;
|
||||
mechanism_class->client_get_state = mechanism_client_get_state;
|
||||
mechanism_class->client_initiate = mechanism_client_initiate;
|
||||
mechanism_class->client_data_receive = mechanism_client_data_receive;
|
||||
mechanism_class->client_data_send = mechanism_client_data_send;
|
||||
mechanism_class->client_shutdown = mechanism_client_shutdown;
|
||||
}
|
||||
|
||||
static void
|
||||
_g_dbus_auth_mechanism_anon_init (GDBusAuthMechanismAnon *mechanism)
|
||||
{
|
||||
mechanism->priv = G_TYPE_INSTANCE_GET_PRIVATE (mechanism,
|
||||
G_TYPE_DBUS_AUTH_MECHANISM_ANON,
|
||||
GDBusAuthMechanismAnonPrivate);
|
||||
}
|
||||
|
||||
/* ---------------------------------------------------------------------------------------------------- */
|
||||
|
||||
|
||||
static gint
|
||||
mechanism_get_priority (void)
|
||||
{
|
||||
/* We prefer ANONYMOUS to most other mechanism (such as DBUS_COOKIE_SHA1) but not to EXTERNAL */
|
||||
return 50;
|
||||
}
|
||||
|
||||
|
||||
static const gchar *
|
||||
mechanism_get_name (void)
|
||||
{
|
||||
return "ANONYMOUS";
|
||||
}
|
||||
|
||||
static gboolean
|
||||
mechanism_is_supported (GDBusAuthMechanism *mechanism)
|
||||
{
|
||||
g_return_val_if_fail (G_IS_DBUS_AUTH_MECHANISM_ANON (mechanism), FALSE);
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static gchar *
|
||||
mechanism_encode_data (GDBusAuthMechanism *mechanism,
|
||||
const gchar *data,
|
||||
gsize data_len,
|
||||
gsize *out_data_len)
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
static gchar *
|
||||
mechanism_decode_data (GDBusAuthMechanism *mechanism,
|
||||
const gchar *data,
|
||||
gsize data_len,
|
||||
gsize *out_data_len)
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* ---------------------------------------------------------------------------------------------------- */
|
||||
|
||||
static GDBusAuthMechanismState
|
||||
mechanism_server_get_state (GDBusAuthMechanism *mechanism)
|
||||
{
|
||||
GDBusAuthMechanismAnon *m = G_DBUS_AUTH_MECHANISM_ANON (mechanism);
|
||||
|
||||
g_return_val_if_fail (G_IS_DBUS_AUTH_MECHANISM_ANON (mechanism), G_DBUS_AUTH_MECHANISM_STATE_INVALID);
|
||||
g_return_val_if_fail (m->priv->is_server && !m->priv->is_client, G_DBUS_AUTH_MECHANISM_STATE_INVALID);
|
||||
|
||||
return m->priv->state;
|
||||
}
|
||||
|
||||
static void
|
||||
mechanism_server_initiate (GDBusAuthMechanism *mechanism,
|
||||
const gchar *initial_response,
|
||||
gsize initial_response_len)
|
||||
{
|
||||
GDBusAuthMechanismAnon *m = G_DBUS_AUTH_MECHANISM_ANON (mechanism);
|
||||
|
||||
g_return_if_fail (G_IS_DBUS_AUTH_MECHANISM_ANON (mechanism));
|
||||
g_return_if_fail (!m->priv->is_server && !m->priv->is_client);
|
||||
|
||||
if (initial_response != NULL)
|
||||
g_debug ("ANONYMOUS: initial_response was `%s'", initial_response);
|
||||
|
||||
m->priv->is_server = TRUE;
|
||||
m->priv->state = G_DBUS_AUTH_MECHANISM_STATE_ACCEPTED;
|
||||
}
|
||||
|
||||
static void
|
||||
mechanism_server_data_receive (GDBusAuthMechanism *mechanism,
|
||||
const gchar *data,
|
||||
gsize data_len)
|
||||
{
|
||||
GDBusAuthMechanismAnon *m = G_DBUS_AUTH_MECHANISM_ANON (mechanism);
|
||||
|
||||
g_return_if_fail (G_IS_DBUS_AUTH_MECHANISM_ANON (mechanism));
|
||||
g_return_if_fail (m->priv->is_server && !m->priv->is_client);
|
||||
g_return_if_fail (m->priv->state == G_DBUS_AUTH_MECHANISM_STATE_WAITING_FOR_DATA);
|
||||
|
||||
/* can never end up here because we are never in the WAITING_FOR_DATA state */
|
||||
g_assert_not_reached ();
|
||||
}
|
||||
|
||||
static gchar *
|
||||
mechanism_server_data_send (GDBusAuthMechanism *mechanism,
|
||||
gsize *out_data_len)
|
||||
{
|
||||
GDBusAuthMechanismAnon *m = G_DBUS_AUTH_MECHANISM_ANON (mechanism);
|
||||
|
||||
g_return_val_if_fail (G_IS_DBUS_AUTH_MECHANISM_ANON (mechanism), NULL);
|
||||
g_return_val_if_fail (m->priv->is_server && !m->priv->is_client, NULL);
|
||||
g_return_val_if_fail (m->priv->state == G_DBUS_AUTH_MECHANISM_STATE_HAVE_DATA_TO_SEND, NULL);
|
||||
|
||||
/* can never end up here because we are never in the HAVE_DATA_TO_SEND state */
|
||||
g_assert_not_reached ();
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static gchar *
|
||||
mechanism_server_get_reject_reason (GDBusAuthMechanism *mechanism)
|
||||
{
|
||||
GDBusAuthMechanismAnon *m = G_DBUS_AUTH_MECHANISM_ANON (mechanism);
|
||||
|
||||
g_return_val_if_fail (G_IS_DBUS_AUTH_MECHANISM_ANON (mechanism), NULL);
|
||||
g_return_val_if_fail (m->priv->is_server && !m->priv->is_client, NULL);
|
||||
g_return_val_if_fail (m->priv->state == G_DBUS_AUTH_MECHANISM_STATE_REJECTED, NULL);
|
||||
|
||||
/* can never end up here because we are never in the REJECTED state */
|
||||
g_assert_not_reached ();
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static void
|
||||
mechanism_server_shutdown (GDBusAuthMechanism *mechanism)
|
||||
{
|
||||
GDBusAuthMechanismAnon *m = G_DBUS_AUTH_MECHANISM_ANON (mechanism);
|
||||
|
||||
g_return_if_fail (G_IS_DBUS_AUTH_MECHANISM_ANON (mechanism));
|
||||
g_return_if_fail (m->priv->is_server && !m->priv->is_client);
|
||||
|
||||
m->priv->is_server = FALSE;
|
||||
}
|
||||
|
||||
/* ---------------------------------------------------------------------------------------------------- */
|
||||
|
||||
static GDBusAuthMechanismState
|
||||
mechanism_client_get_state (GDBusAuthMechanism *mechanism)
|
||||
{
|
||||
GDBusAuthMechanismAnon *m = G_DBUS_AUTH_MECHANISM_ANON (mechanism);
|
||||
|
||||
g_return_val_if_fail (G_IS_DBUS_AUTH_MECHANISM_ANON (mechanism), G_DBUS_AUTH_MECHANISM_STATE_INVALID);
|
||||
g_return_val_if_fail (m->priv->is_client && !m->priv->is_server, G_DBUS_AUTH_MECHANISM_STATE_INVALID);
|
||||
|
||||
return m->priv->state;
|
||||
}
|
||||
|
||||
static gchar *
|
||||
mechanism_client_initiate (GDBusAuthMechanism *mechanism,
|
||||
gsize *out_initial_response_len)
|
||||
{
|
||||
GDBusAuthMechanismAnon *m = G_DBUS_AUTH_MECHANISM_ANON (mechanism);
|
||||
|
||||
g_return_val_if_fail (G_IS_DBUS_AUTH_MECHANISM_ANON (mechanism), NULL);
|
||||
g_return_val_if_fail (!m->priv->is_server && !m->priv->is_client, NULL);
|
||||
|
||||
m->priv->is_client = TRUE;
|
||||
m->priv->state = G_DBUS_AUTH_MECHANISM_STATE_ACCEPTED;
|
||||
|
||||
*out_initial_response_len = -1;
|
||||
|
||||
/* just return our library name and version */
|
||||
return g_strdup ("GDBus 0.1");
|
||||
}
|
||||
|
||||
static void
|
||||
mechanism_client_data_receive (GDBusAuthMechanism *mechanism,
|
||||
const gchar *data,
|
||||
gsize data_len)
|
||||
{
|
||||
GDBusAuthMechanismAnon *m = G_DBUS_AUTH_MECHANISM_ANON (mechanism);
|
||||
|
||||
g_return_if_fail (G_IS_DBUS_AUTH_MECHANISM_ANON (mechanism));
|
||||
g_return_if_fail (m->priv->is_client && !m->priv->is_server);
|
||||
g_return_if_fail (m->priv->state == G_DBUS_AUTH_MECHANISM_STATE_WAITING_FOR_DATA);
|
||||
|
||||
/* can never end up here because we are never in the WAITING_FOR_DATA state */
|
||||
g_assert_not_reached ();
|
||||
}
|
||||
|
||||
static gchar *
|
||||
mechanism_client_data_send (GDBusAuthMechanism *mechanism,
|
||||
gsize *out_data_len)
|
||||
{
|
||||
GDBusAuthMechanismAnon *m = G_DBUS_AUTH_MECHANISM_ANON (mechanism);
|
||||
|
||||
g_return_val_if_fail (G_IS_DBUS_AUTH_MECHANISM_ANON (mechanism), NULL);
|
||||
g_return_val_if_fail (m->priv->is_client && !m->priv->is_server, NULL);
|
||||
g_return_val_if_fail (m->priv->state == G_DBUS_AUTH_MECHANISM_STATE_HAVE_DATA_TO_SEND, NULL);
|
||||
|
||||
/* can never end up here because we are never in the HAVE_DATA_TO_SEND state */
|
||||
g_assert_not_reached ();
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static void
|
||||
mechanism_client_shutdown (GDBusAuthMechanism *mechanism)
|
||||
{
|
||||
GDBusAuthMechanismAnon *m = G_DBUS_AUTH_MECHANISM_ANON (mechanism);
|
||||
|
||||
g_return_if_fail (G_IS_DBUS_AUTH_MECHANISM_ANON (mechanism));
|
||||
g_return_if_fail (m->priv->is_client && !m->priv->is_server);
|
||||
|
||||
m->priv->is_client = FALSE;
|
||||
}
|
||||
|
||||
/* ---------------------------------------------------------------------------------------------------- */
|
||||
|
||||
#define __G_DBUS_AUTH_MECHANISM_ANON_C__
|
||||
#include "gioaliasdef.c"
|
82
gio/gdbusauthmechanismanon.h
Normal file
82
gio/gdbusauthmechanismanon.h
Normal file
@ -0,0 +1,82 @@
|
||||
/* GDBus - GLib D-Bus Library
|
||||
*
|
||||
* Copyright (C) 2008-2010 Red Hat, Inc.
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General
|
||||
* Public License along with this library; if not, write to the
|
||||
* Free Software Foundation, Inc., 59 Temple Place, Suite 330,
|
||||
* Boston, MA 02111-1307, USA.
|
||||
*
|
||||
* Author: David Zeuthen <davidz@redhat.com>
|
||||
*/
|
||||
|
||||
#if !defined (GIO_COMPILATION)
|
||||
#error "gdbusauthmechanismanon.h is a private header file."
|
||||
#endif
|
||||
|
||||
#ifndef __G_DBUS_AUTH_MECHANISM_ANON_H__
|
||||
#define __G_DBUS_AUTH_MECHANISM_ANON_H__
|
||||
|
||||
#include <gio/giotypes.h>
|
||||
#include <gio/gdbusauthmechanism.h>
|
||||
|
||||
G_BEGIN_DECLS
|
||||
|
||||
#define G_TYPE_DBUS_AUTH_MECHANISM_ANON (_g_dbus_auth_mechanism_anon_get_type ())
|
||||
#define G_DBUS_AUTH_MECHANISM_ANON(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), G_TYPE_DBUS_AUTH_MECHANISM_ANON, GDBusAuthMechanismAnon))
|
||||
#define G_DBUS_AUTH_MECHANISM_ANON_CLASS(k) (G_TYPE_CHECK_CLASS_CAST((k), G_TYPE_DBUS_AUTH_MECHANISM_ANON, GDBusAuthMechanismAnonClass))
|
||||
#define G_DBUS_AUTH_MECHANISM_ANON_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS ((o), G_TYPE_DBUS_AUTH_MECHANISM_ANON, GDBusAuthMechanismAnonClass))
|
||||
#define G_IS_DBUS_AUTH_MECHANISM_ANON(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), G_TYPE_DBUS_AUTH_MECHANISM_ANON))
|
||||
#define G_IS_DBUS_AUTH_MECHANISM_ANON_CLASS(k) (G_TYPE_CHECK_CLASS_TYPE ((k), G_TYPE_DBUS_AUTH_MECHANISM_ANON))
|
||||
|
||||
typedef struct _GDBusAuthMechanismAnon GDBusAuthMechanismAnon;
|
||||
typedef struct _GDBusAuthMechanismAnonClass GDBusAuthMechanismAnonClass;
|
||||
typedef struct _GDBusAuthMechanismAnonPrivate GDBusAuthMechanismAnonPrivate;
|
||||
|
||||
struct _GDBusAuthMechanismAnonClass
|
||||
{
|
||||
/*< private >*/
|
||||
GDBusAuthMechanismClass parent_class;
|
||||
|
||||
/*< private >*/
|
||||
/* Padding for future expansion */
|
||||
void (*_g_reserved1) (void);
|
||||
void (*_g_reserved2) (void);
|
||||
void (*_g_reserved3) (void);
|
||||
void (*_g_reserved4) (void);
|
||||
void (*_g_reserved5) (void);
|
||||
void (*_g_reserved6) (void);
|
||||
void (*_g_reserved7) (void);
|
||||
void (*_g_reserved8) (void);
|
||||
void (*_g_reserved9) (void);
|
||||
void (*_g_reserved10) (void);
|
||||
void (*_g_reserved11) (void);
|
||||
void (*_g_reserved12) (void);
|
||||
void (*_g_reserved13) (void);
|
||||
void (*_g_reserved14) (void);
|
||||
void (*_g_reserved15) (void);
|
||||
void (*_g_reserved16) (void);
|
||||
};
|
||||
|
||||
struct _GDBusAuthMechanismAnon
|
||||
{
|
||||
GDBusAuthMechanism parent_instance;
|
||||
GDBusAuthMechanismAnonPrivate *priv;
|
||||
};
|
||||
|
||||
GType _g_dbus_auth_mechanism_anon_get_type (void) G_GNUC_CONST;
|
||||
|
||||
|
||||
G_END_DECLS
|
||||
|
||||
#endif /* __G_DBUS_AUTH_MECHANISM_ANON_H__ */
|
409
gio/gdbusauthmechanismexternal.c
Normal file
409
gio/gdbusauthmechanismexternal.c
Normal file
@ -0,0 +1,409 @@
|
||||
/* GDBus - GLib D-Bus Library
|
||||
*
|
||||
* Copyright (C) 2008-2010 Red Hat, Inc.
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General
|
||||
* Public License along with this library; if not, write to the
|
||||
* Free Software Foundation, Inc., 59 Temple Place, Suite 330,
|
||||
* Boston, MA 02111-1307, USA.
|
||||
*
|
||||
* Author: David Zeuthen <davidz@redhat.com>
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include <string.h>
|
||||
|
||||
#include "gdbusauthmechanismexternal.h"
|
||||
#include "gcredentials.h"
|
||||
#include "gdbuserror.h"
|
||||
#include "gioenumtypes.h"
|
||||
|
||||
#ifdef G_OS_UNIX
|
||||
#include <sys/types.h>
|
||||
#include <unistd.h>
|
||||
#endif
|
||||
|
||||
#include "glibintl.h"
|
||||
#include "gioalias.h"
|
||||
|
||||
struct _GDBusAuthMechanismExternalPrivate
|
||||
{
|
||||
gboolean is_client;
|
||||
gboolean is_server;
|
||||
GDBusAuthMechanismState state;
|
||||
};
|
||||
|
||||
static gint mechanism_get_priority (void);
|
||||
static const gchar *mechanism_get_name (void);
|
||||
|
||||
static gboolean mechanism_is_supported (GDBusAuthMechanism *mechanism);
|
||||
static gchar *mechanism_encode_data (GDBusAuthMechanism *mechanism,
|
||||
const gchar *data,
|
||||
gsize data_len,
|
||||
gsize *out_data_len);
|
||||
static gchar *mechanism_decode_data (GDBusAuthMechanism *mechanism,
|
||||
const gchar *data,
|
||||
gsize data_len,
|
||||
gsize *out_data_len);
|
||||
static GDBusAuthMechanismState mechanism_server_get_state (GDBusAuthMechanism *mechanism);
|
||||
static void mechanism_server_initiate (GDBusAuthMechanism *mechanism,
|
||||
const gchar *initial_response,
|
||||
gsize initial_response_len);
|
||||
static void mechanism_server_data_receive (GDBusAuthMechanism *mechanism,
|
||||
const gchar *data,
|
||||
gsize data_len);
|
||||
static gchar *mechanism_server_data_send (GDBusAuthMechanism *mechanism,
|
||||
gsize *out_data_len);
|
||||
static gchar *mechanism_server_get_reject_reason (GDBusAuthMechanism *mechanism);
|
||||
static void mechanism_server_shutdown (GDBusAuthMechanism *mechanism);
|
||||
static GDBusAuthMechanismState mechanism_client_get_state (GDBusAuthMechanism *mechanism);
|
||||
static gchar *mechanism_client_initiate (GDBusAuthMechanism *mechanism,
|
||||
gsize *out_initial_response_len);
|
||||
static void mechanism_client_data_receive (GDBusAuthMechanism *mechanism,
|
||||
const gchar *data,
|
||||
gsize data_len);
|
||||
static gchar *mechanism_client_data_send (GDBusAuthMechanism *mechanism,
|
||||
gsize *out_data_len);
|
||||
static void mechanism_client_shutdown (GDBusAuthMechanism *mechanism);
|
||||
|
||||
/* ---------------------------------------------------------------------------------------------------- */
|
||||
|
||||
G_DEFINE_TYPE (GDBusAuthMechanismExternal, _g_dbus_auth_mechanism_external, G_TYPE_DBUS_AUTH_MECHANISM);
|
||||
|
||||
/* ---------------------------------------------------------------------------------------------------- */
|
||||
|
||||
static void
|
||||
_g_dbus_auth_mechanism_external_finalize (GObject *object)
|
||||
{
|
||||
//GDBusAuthMechanismExternal *mechanism = G_DBUS_AUTH_MECHANISM_EXTERNAL (object);
|
||||
|
||||
if (G_OBJECT_CLASS (_g_dbus_auth_mechanism_external_parent_class)->finalize != NULL)
|
||||
G_OBJECT_CLASS (_g_dbus_auth_mechanism_external_parent_class)->finalize (object);
|
||||
}
|
||||
|
||||
static void
|
||||
_g_dbus_auth_mechanism_external_class_init (GDBusAuthMechanismExternalClass *klass)
|
||||
{
|
||||
GObjectClass *gobject_class;
|
||||
GDBusAuthMechanismClass *mechanism_class;
|
||||
|
||||
g_type_class_add_private (klass, sizeof (GDBusAuthMechanismExternalPrivate));
|
||||
|
||||
gobject_class = G_OBJECT_CLASS (klass);
|
||||
gobject_class->finalize = _g_dbus_auth_mechanism_external_finalize;
|
||||
|
||||
mechanism_class = G_DBUS_AUTH_MECHANISM_CLASS (klass);
|
||||
mechanism_class->get_name = mechanism_get_name;
|
||||
mechanism_class->get_priority = mechanism_get_priority;
|
||||
mechanism_class->is_supported = mechanism_is_supported;
|
||||
mechanism_class->encode_data = mechanism_encode_data;
|
||||
mechanism_class->decode_data = mechanism_decode_data;
|
||||
mechanism_class->server_get_state = mechanism_server_get_state;
|
||||
mechanism_class->server_initiate = mechanism_server_initiate;
|
||||
mechanism_class->server_data_receive = mechanism_server_data_receive;
|
||||
mechanism_class->server_data_send = mechanism_server_data_send;
|
||||
mechanism_class->server_get_reject_reason = mechanism_server_get_reject_reason;
|
||||
mechanism_class->server_shutdown = mechanism_server_shutdown;
|
||||
mechanism_class->client_get_state = mechanism_client_get_state;
|
||||
mechanism_class->client_initiate = mechanism_client_initiate;
|
||||
mechanism_class->client_data_receive = mechanism_client_data_receive;
|
||||
mechanism_class->client_data_send = mechanism_client_data_send;
|
||||
mechanism_class->client_shutdown = mechanism_client_shutdown;
|
||||
}
|
||||
|
||||
static void
|
||||
_g_dbus_auth_mechanism_external_init (GDBusAuthMechanismExternal *mechanism)
|
||||
{
|
||||
mechanism->priv = G_TYPE_INSTANCE_GET_PRIVATE (mechanism,
|
||||
G_TYPE_DBUS_AUTH_MECHANISM_EXTERNAL,
|
||||
GDBusAuthMechanismExternalPrivate);
|
||||
}
|
||||
|
||||
/* ---------------------------------------------------------------------------------------------------- */
|
||||
|
||||
static gboolean
|
||||
mechanism_is_supported (GDBusAuthMechanism *mechanism)
|
||||
{
|
||||
g_return_val_if_fail (G_IS_DBUS_AUTH_MECHANISM_EXTERNAL (mechanism), FALSE);
|
||||
/* This mechanism is only available if credentials has been exchanged */
|
||||
if (_g_dbus_auth_mechanism_get_credentials (mechanism) != NULL)
|
||||
return TRUE;
|
||||
else
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
static gint
|
||||
mechanism_get_priority (void)
|
||||
{
|
||||
/* We prefer EXTERNAL to most other mechanism (DBUS_COOKIE_SHA1 and ANONYMOUS) */
|
||||
return 100;
|
||||
}
|
||||
|
||||
static const gchar *
|
||||
mechanism_get_name (void)
|
||||
{
|
||||
return "EXTERNAL";
|
||||
}
|
||||
|
||||
static gchar *
|
||||
mechanism_encode_data (GDBusAuthMechanism *mechanism,
|
||||
const gchar *data,
|
||||
gsize data_len,
|
||||
gsize *out_data_len)
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
static gchar *
|
||||
mechanism_decode_data (GDBusAuthMechanism *mechanism,
|
||||
const gchar *data,
|
||||
gsize data_len,
|
||||
gsize *out_data_len)
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* ---------------------------------------------------------------------------------------------------- */
|
||||
|
||||
static GDBusAuthMechanismState
|
||||
mechanism_server_get_state (GDBusAuthMechanism *mechanism)
|
||||
{
|
||||
GDBusAuthMechanismExternal *m = G_DBUS_AUTH_MECHANISM_EXTERNAL (mechanism);
|
||||
|
||||
g_return_val_if_fail (G_IS_DBUS_AUTH_MECHANISM_EXTERNAL (mechanism), G_DBUS_AUTH_MECHANISM_STATE_INVALID);
|
||||
g_return_val_if_fail (m->priv->is_server && !m->priv->is_client, G_DBUS_AUTH_MECHANISM_STATE_INVALID);
|
||||
|
||||
return m->priv->state;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
data_matches_credentials (const gchar *data,
|
||||
GCredentials *credentials)
|
||||
{
|
||||
gboolean match;
|
||||
|
||||
match = FALSE;
|
||||
|
||||
if (credentials == NULL)
|
||||
goto out;
|
||||
|
||||
if (data == NULL || strlen (data) == 0)
|
||||
goto out;
|
||||
|
||||
#if defined(G_OS_UNIX)
|
||||
{
|
||||
gint64 alleged_uid;
|
||||
gchar *endp;
|
||||
|
||||
/* on UNIX, this is the uid as a string in base 10 */
|
||||
alleged_uid = g_ascii_strtoll (data, &endp, 10);
|
||||
if (*endp == '\0')
|
||||
{
|
||||
if (g_credentials_get_unix_user (credentials, NULL) == alleged_uid)
|
||||
{
|
||||
match = TRUE;
|
||||
}
|
||||
}
|
||||
}
|
||||
#else
|
||||
/* TODO: Dont know how to compare credentials on this OS. Please implement. */
|
||||
#endif
|
||||
|
||||
out:
|
||||
return match;
|
||||
}
|
||||
|
||||
static void
|
||||
mechanism_server_initiate (GDBusAuthMechanism *mechanism,
|
||||
const gchar *initial_response,
|
||||
gsize initial_response_len)
|
||||
{
|
||||
GDBusAuthMechanismExternal *m = G_DBUS_AUTH_MECHANISM_EXTERNAL (mechanism);
|
||||
|
||||
g_return_if_fail (G_IS_DBUS_AUTH_MECHANISM_EXTERNAL (mechanism));
|
||||
g_return_if_fail (!m->priv->is_server && !m->priv->is_client);
|
||||
|
||||
m->priv->is_server = TRUE;
|
||||
|
||||
if (initial_response != NULL)
|
||||
{
|
||||
if (data_matches_credentials (initial_response, _g_dbus_auth_mechanism_get_credentials (mechanism)))
|
||||
{
|
||||
m->priv->state = G_DBUS_AUTH_MECHANISM_STATE_ACCEPTED;
|
||||
}
|
||||
else
|
||||
{
|
||||
m->priv->state = G_DBUS_AUTH_MECHANISM_STATE_REJECTED;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
m->priv->state = G_DBUS_AUTH_MECHANISM_STATE_WAITING_FOR_DATA;
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
mechanism_server_data_receive (GDBusAuthMechanism *mechanism,
|
||||
const gchar *data,
|
||||
gsize data_len)
|
||||
{
|
||||
GDBusAuthMechanismExternal *m = G_DBUS_AUTH_MECHANISM_EXTERNAL (mechanism);
|
||||
|
||||
g_return_if_fail (G_IS_DBUS_AUTH_MECHANISM_EXTERNAL (mechanism));
|
||||
g_return_if_fail (m->priv->is_server && !m->priv->is_client);
|
||||
g_return_if_fail (m->priv->state == G_DBUS_AUTH_MECHANISM_STATE_WAITING_FOR_DATA);
|
||||
|
||||
if (data_matches_credentials (data, _g_dbus_auth_mechanism_get_credentials (mechanism)))
|
||||
{
|
||||
m->priv->state = G_DBUS_AUTH_MECHANISM_STATE_ACCEPTED;
|
||||
}
|
||||
else
|
||||
{
|
||||
m->priv->state = G_DBUS_AUTH_MECHANISM_STATE_REJECTED;
|
||||
}
|
||||
}
|
||||
|
||||
static gchar *
|
||||
mechanism_server_data_send (GDBusAuthMechanism *mechanism,
|
||||
gsize *out_data_len)
|
||||
{
|
||||
GDBusAuthMechanismExternal *m = G_DBUS_AUTH_MECHANISM_EXTERNAL (mechanism);
|
||||
|
||||
g_return_val_if_fail (G_IS_DBUS_AUTH_MECHANISM_EXTERNAL (mechanism), NULL);
|
||||
g_return_val_if_fail (m->priv->is_server && !m->priv->is_client, NULL);
|
||||
g_return_val_if_fail (m->priv->state == G_DBUS_AUTH_MECHANISM_STATE_HAVE_DATA_TO_SEND, NULL);
|
||||
|
||||
/* can never end up here because we are never in the HAVE_DATA_TO_SEND state */
|
||||
g_assert_not_reached ();
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static gchar *
|
||||
mechanism_server_get_reject_reason (GDBusAuthMechanism *mechanism)
|
||||
{
|
||||
GDBusAuthMechanismExternal *m = G_DBUS_AUTH_MECHANISM_EXTERNAL (mechanism);
|
||||
|
||||
g_return_val_if_fail (G_IS_DBUS_AUTH_MECHANISM_EXTERNAL (mechanism), NULL);
|
||||
g_return_val_if_fail (m->priv->is_server && !m->priv->is_client, NULL);
|
||||
g_return_val_if_fail (m->priv->state == G_DBUS_AUTH_MECHANISM_STATE_REJECTED, NULL);
|
||||
|
||||
/* can never end up here because we are never in the REJECTED state */
|
||||
g_assert_not_reached ();
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static void
|
||||
mechanism_server_shutdown (GDBusAuthMechanism *mechanism)
|
||||
{
|
||||
GDBusAuthMechanismExternal *m = G_DBUS_AUTH_MECHANISM_EXTERNAL (mechanism);
|
||||
|
||||
g_return_if_fail (G_IS_DBUS_AUTH_MECHANISM_EXTERNAL (mechanism));
|
||||
g_return_if_fail (m->priv->is_server && !m->priv->is_client);
|
||||
|
||||
m->priv->is_server = FALSE;
|
||||
}
|
||||
|
||||
/* ---------------------------------------------------------------------------------------------------- */
|
||||
|
||||
static GDBusAuthMechanismState
|
||||
mechanism_client_get_state (GDBusAuthMechanism *mechanism)
|
||||
{
|
||||
GDBusAuthMechanismExternal *m = G_DBUS_AUTH_MECHANISM_EXTERNAL (mechanism);
|
||||
|
||||
g_return_val_if_fail (G_IS_DBUS_AUTH_MECHANISM_EXTERNAL (mechanism), G_DBUS_AUTH_MECHANISM_STATE_INVALID);
|
||||
g_return_val_if_fail (m->priv->is_client && !m->priv->is_server, G_DBUS_AUTH_MECHANISM_STATE_INVALID);
|
||||
|
||||
return m->priv->state;
|
||||
}
|
||||
|
||||
static gchar *
|
||||
mechanism_client_initiate (GDBusAuthMechanism *mechanism,
|
||||
gsize *out_initial_response_len)
|
||||
{
|
||||
GDBusAuthMechanismExternal *m = G_DBUS_AUTH_MECHANISM_EXTERNAL (mechanism);
|
||||
gchar *initial_response;
|
||||
GCredentials *credentials;
|
||||
|
||||
g_return_val_if_fail (G_IS_DBUS_AUTH_MECHANISM_EXTERNAL (mechanism), NULL);
|
||||
g_return_val_if_fail (!m->priv->is_server && !m->priv->is_client, NULL);
|
||||
|
||||
m->priv->is_client = TRUE;
|
||||
m->priv->state = G_DBUS_AUTH_MECHANISM_STATE_ACCEPTED;
|
||||
|
||||
*out_initial_response_len = -1;
|
||||
|
||||
credentials = _g_dbus_auth_mechanism_get_credentials (mechanism);
|
||||
g_assert (credentials != NULL);
|
||||
|
||||
/* return the uid */
|
||||
#if defined(G_OS_UNIX)
|
||||
initial_response = g_strdup_printf ("%" G_GINT64_FORMAT, (gint64) g_credentials_get_unix_user (credentials, NULL));
|
||||
#elif defined(G_OS_WIN32)
|
||||
initial_response = g_strdup_printf ("%s", g_credentials_get_windows_user ());
|
||||
#else
|
||||
#warning Dont know how to send credentials on this OS. Please implement.
|
||||
m->priv->state = G_DBUS_AUTH_MECHANISM_STATE_REJECTED;
|
||||
#endif
|
||||
return initial_response;
|
||||
}
|
||||
|
||||
static void
|
||||
mechanism_client_data_receive (GDBusAuthMechanism *mechanism,
|
||||
const gchar *data,
|
||||
gsize data_len)
|
||||
{
|
||||
GDBusAuthMechanismExternal *m = G_DBUS_AUTH_MECHANISM_EXTERNAL (mechanism);
|
||||
|
||||
g_return_if_fail (G_IS_DBUS_AUTH_MECHANISM_EXTERNAL (mechanism));
|
||||
g_return_if_fail (m->priv->is_client && !m->priv->is_server);
|
||||
g_return_if_fail (m->priv->state == G_DBUS_AUTH_MECHANISM_STATE_WAITING_FOR_DATA);
|
||||
|
||||
/* can never end up here because we are never in the WAITING_FOR_DATA state */
|
||||
g_assert_not_reached ();
|
||||
}
|
||||
|
||||
static gchar *
|
||||
mechanism_client_data_send (GDBusAuthMechanism *mechanism,
|
||||
gsize *out_data_len)
|
||||
{
|
||||
GDBusAuthMechanismExternal *m = G_DBUS_AUTH_MECHANISM_EXTERNAL (mechanism);
|
||||
|
||||
g_return_val_if_fail (G_IS_DBUS_AUTH_MECHANISM_EXTERNAL (mechanism), NULL);
|
||||
g_return_val_if_fail (m->priv->is_client && !m->priv->is_server, NULL);
|
||||
g_return_val_if_fail (m->priv->state == G_DBUS_AUTH_MECHANISM_STATE_HAVE_DATA_TO_SEND, NULL);
|
||||
|
||||
/* can never end up here because we are never in the HAVE_DATA_TO_SEND state */
|
||||
g_assert_not_reached ();
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static void
|
||||
mechanism_client_shutdown (GDBusAuthMechanism *mechanism)
|
||||
{
|
||||
GDBusAuthMechanismExternal *m = G_DBUS_AUTH_MECHANISM_EXTERNAL (mechanism);
|
||||
|
||||
g_return_if_fail (G_IS_DBUS_AUTH_MECHANISM_EXTERNAL (mechanism));
|
||||
g_return_if_fail (m->priv->is_client && !m->priv->is_server);
|
||||
|
||||
m->priv->is_client = FALSE;
|
||||
}
|
||||
|
||||
/* ---------------------------------------------------------------------------------------------------- */
|
||||
|
||||
#define __G_DBUS_AUTH_MECHANISM_EXTERNAL_C__
|
||||
#include "gioaliasdef.c"
|
82
gio/gdbusauthmechanismexternal.h
Normal file
82
gio/gdbusauthmechanismexternal.h
Normal file
@ -0,0 +1,82 @@
|
||||
/* GDBus - GLib D-Bus Library
|
||||
*
|
||||
* Copyright (C) 2008-2010 Red Hat, Inc.
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General
|
||||
* Public License along with this library; if not, write to the
|
||||
* Free Software Foundation, Inc., 59 Temple Place, Suite 330,
|
||||
* Boston, MA 02111-1307, USA.
|
||||
*
|
||||
* Author: David Zeuthen <davidz@redhat.com>
|
||||
*/
|
||||
|
||||
#if !defined (GIO_COMPILATION)
|
||||
#error "gdbusauthmechanismexternal.h is a private header file."
|
||||
#endif
|
||||
|
||||
#ifndef __G_DBUS_AUTH_MECHANISM_EXTERNAL_H__
|
||||
#define __G_DBUS_AUTH_MECHANISM_EXTERNAL_H__
|
||||
|
||||
#include <gio/giotypes.h>
|
||||
#include <gio/gdbusauthmechanism.h>
|
||||
|
||||
G_BEGIN_DECLS
|
||||
|
||||
#define G_TYPE_DBUS_AUTH_MECHANISM_EXTERNAL (_g_dbus_auth_mechanism_external_get_type ())
|
||||
#define G_DBUS_AUTH_MECHANISM_EXTERNAL(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), G_TYPE_DBUS_AUTH_MECHANISM_EXTERNAL, GDBusAuthMechanismExternal))
|
||||
#define G_DBUS_AUTH_MECHANISM_EXTERNAL_CLASS(k) (G_TYPE_CHECK_CLASS_CAST((k), G_TYPE_DBUS_AUTH_MECHANISM_EXTERNAL, GDBusAuthMechanismExternalClass))
|
||||
#define G_DBUS_AUTH_MECHANISM_EXTERNAL_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS ((o), G_TYPE_DBUS_AUTH_MECHANISM_EXTERNAL, GDBusAuthMechanismExternalClass))
|
||||
#define G_IS_DBUS_AUTH_MECHANISM_EXTERNAL(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), G_TYPE_DBUS_AUTH_MECHANISM_EXTERNAL))
|
||||
#define G_IS_DBUS_AUTH_MECHANISM_EXTERNAL_CLASS(k) (G_TYPE_CHECK_CLASS_TYPE ((k), G_TYPE_DBUS_AUTH_MECHANISM_EXTERNAL))
|
||||
|
||||
typedef struct _GDBusAuthMechanismExternal GDBusAuthMechanismExternal;
|
||||
typedef struct _GDBusAuthMechanismExternalClass GDBusAuthMechanismExternalClass;
|
||||
typedef struct _GDBusAuthMechanismExternalPrivate GDBusAuthMechanismExternalPrivate;
|
||||
|
||||
struct _GDBusAuthMechanismExternalClass
|
||||
{
|
||||
/*< private >*/
|
||||
GDBusAuthMechanismClass parent_class;
|
||||
|
||||
/*< private >*/
|
||||
/* Padding for future expansion */
|
||||
void (*_g_reserved1) (void);
|
||||
void (*_g_reserved2) (void);
|
||||
void (*_g_reserved3) (void);
|
||||
void (*_g_reserved4) (void);
|
||||
void (*_g_reserved5) (void);
|
||||
void (*_g_reserved6) (void);
|
||||
void (*_g_reserved7) (void);
|
||||
void (*_g_reserved8) (void);
|
||||
void (*_g_reserved9) (void);
|
||||
void (*_g_reserved10) (void);
|
||||
void (*_g_reserved11) (void);
|
||||
void (*_g_reserved12) (void);
|
||||
void (*_g_reserved13) (void);
|
||||
void (*_g_reserved14) (void);
|
||||
void (*_g_reserved15) (void);
|
||||
void (*_g_reserved16) (void);
|
||||
};
|
||||
|
||||
struct _GDBusAuthMechanismExternal
|
||||
{
|
||||
GDBusAuthMechanism parent_instance;
|
||||
GDBusAuthMechanismExternalPrivate *priv;
|
||||
};
|
||||
|
||||
GType _g_dbus_auth_mechanism_external_get_type (void) G_GNUC_CONST;
|
||||
|
||||
|
||||
G_END_DECLS
|
||||
|
||||
#endif /* __G_DBUS_AUTH_MECHANISM_EXTERNAL_H__ */
|
1222
gio/gdbusauthmechanismsha1.c
Normal file
1222
gio/gdbusauthmechanismsha1.c
Normal file
File diff suppressed because it is too large
Load Diff
82
gio/gdbusauthmechanismsha1.h
Normal file
82
gio/gdbusauthmechanismsha1.h
Normal file
@ -0,0 +1,82 @@
|
||||
/* GDBus - GLib D-Bus Library
|
||||
*
|
||||
* Copyright (C) 2008-2010 Red Hat, Inc.
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General
|
||||
* Public License along with this library; if not, write to the
|
||||
* Free Software Foundation, Inc., 59 Temple Place, Suite 330,
|
||||
* Boston, MA 02111-1307, USA.
|
||||
*
|
||||
* Author: David Zeuthen <davidz@redhat.com>
|
||||
*/
|
||||
|
||||
#if !defined (GIO_COMPILATION)
|
||||
#error "gdbusauthmechanismsha1.h is a private header file."
|
||||
#endif
|
||||
|
||||
#ifndef __G_DBUS_AUTH_MECHANISM_SHA1_H__
|
||||
#define __G_DBUS_AUTH_MECHANISM_SHA1_H__
|
||||
|
||||
#include <gio/giotypes.h>
|
||||
#include <gio/gdbusauthmechanism.h>
|
||||
|
||||
G_BEGIN_DECLS
|
||||
|
||||
#define G_TYPE_DBUS_AUTH_MECHANISM_SHA1 (_g_dbus_auth_mechanism_sha1_get_type ())
|
||||
#define G_DBUS_AUTH_MECHANISM_SHA1(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), G_TYPE_DBUS_AUTH_MECHANISM_SHA1, GDBusAuthMechanismSha1))
|
||||
#define G_DBUS_AUTH_MECHANISM_SHA1_CLASS(k) (G_TYPE_CHECK_CLASS_CAST((k), G_TYPE_DBUS_AUTH_MECHANISM_SHA1, GDBusAuthMechanismSha1Class))
|
||||
#define G_DBUS_AUTH_MECHANISM_SHA1_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS ((o), G_TYPE_DBUS_AUTH_MECHANISM_SHA1, GDBusAuthMechanismSha1Class))
|
||||
#define G_IS_DBUS_AUTH_MECHANISM_SHA1(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), G_TYPE_DBUS_AUTH_MECHANISM_SHA1))
|
||||
#define G_IS_DBUS_AUTH_MECHANISM_SHA1_CLASS(k) (G_TYPE_CHECK_CLASS_TYPE ((k), G_TYPE_DBUS_AUTH_MECHANISM_SHA1))
|
||||
|
||||
typedef struct _GDBusAuthMechanismSha1 GDBusAuthMechanismSha1;
|
||||
typedef struct _GDBusAuthMechanismSha1Class GDBusAuthMechanismSha1Class;
|
||||
typedef struct _GDBusAuthMechanismSha1Private GDBusAuthMechanismSha1Private;
|
||||
|
||||
struct _GDBusAuthMechanismSha1Class
|
||||
{
|
||||
/*< private >*/
|
||||
GDBusAuthMechanismClass parent_class;
|
||||
|
||||
/*< private >*/
|
||||
/* Padding for future expansion */
|
||||
void (*_g_reserved1) (void);
|
||||
void (*_g_reserved2) (void);
|
||||
void (*_g_reserved3) (void);
|
||||
void (*_g_reserved4) (void);
|
||||
void (*_g_reserved5) (void);
|
||||
void (*_g_reserved6) (void);
|
||||
void (*_g_reserved7) (void);
|
||||
void (*_g_reserved8) (void);
|
||||
void (*_g_reserved9) (void);
|
||||
void (*_g_reserved10) (void);
|
||||
void (*_g_reserved11) (void);
|
||||
void (*_g_reserved12) (void);
|
||||
void (*_g_reserved13) (void);
|
||||
void (*_g_reserved14) (void);
|
||||
void (*_g_reserved15) (void);
|
||||
void (*_g_reserved16) (void);
|
||||
};
|
||||
|
||||
struct _GDBusAuthMechanismSha1
|
||||
{
|
||||
GDBusAuthMechanism parent_instance;
|
||||
GDBusAuthMechanismSha1Private *priv;
|
||||
};
|
||||
|
||||
GType _g_dbus_auth_mechanism_sha1_get_type (void) G_GNUC_CONST;
|
||||
|
||||
|
||||
G_END_DECLS
|
||||
|
||||
#endif /* __G_DBUS_AUTH_MECHANISM_SHA1_H__ */
|
247
gio/gdbusauthobserver.c
Normal file
247
gio/gdbusauthobserver.c
Normal file
@ -0,0 +1,247 @@
|
||||
/* GDBus - GLib D-Bus Library
|
||||
*
|
||||
* Copyright (C) 2008-2010 Red Hat, Inc.
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General
|
||||
* Public License along with this library; if not, write to the
|
||||
* Free Software Foundation, Inc., 59 Temple Place, Suite 330,
|
||||
* Boston, MA 02111-1307, USA.
|
||||
*
|
||||
* Author: David Zeuthen <davidz@redhat.com>
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include "gdbusauthobserver.h"
|
||||
#include "gio-marshal.h"
|
||||
#include "gcredentials.h"
|
||||
#include "gioenumtypes.h"
|
||||
#include "giostream.h"
|
||||
|
||||
#include "glibintl.h"
|
||||
#include "gioalias.h"
|
||||
|
||||
/**
|
||||
* SECTION:gdbusauthobserver
|
||||
* @short_description: Object used for authenticating connections
|
||||
* @include: gio/gio.h
|
||||
*
|
||||
* The #GDBusAuthObserver type provides a mechanism for participating
|
||||
* in how a #GDBusServer (or a #GDBusConnection) authenticates remote
|
||||
* peers. Simply instantiate a #GDBusAuthObserver and connect to the
|
||||
* signals you are interested in. Note that new signals may be added
|
||||
* in the future
|
||||
*
|
||||
* For example, if you only want to allow D-Bus connections from
|
||||
* processes owned by the same uid as the server, you would do this:
|
||||
* <example id="auth-observer"><title>Controlling Authentication</title><programlisting>
|
||||
* static gboolean
|
||||
* on_authorize_authenticated_peer (GDBusAuthObserver *observer,
|
||||
* GIOStream *stream,
|
||||
* GCredentials *credentials,
|
||||
* gpointer user_data)
|
||||
* {
|
||||
* GCredentials *me;
|
||||
* gboolean authorized;
|
||||
*
|
||||
* authorized = FALSE;
|
||||
* me = g_credentials_new ();
|
||||
*
|
||||
* if (credentials != NULL &&
|
||||
* !g_credentials_is_same_user (credentials, me))
|
||||
* authorized = TRUE;
|
||||
*
|
||||
* g_object_unref (me);
|
||||
*
|
||||
* return authorized;
|
||||
* }
|
||||
*
|
||||
* static gboolean
|
||||
* on_new_connection (GDBusServer *server,
|
||||
* GDBusConnection *connection,
|
||||
* gpointer user_data)
|
||||
* {
|
||||
* /<!-- -->* Guaranteed here that @connection is from a process owned by the same user *<!-- -->/
|
||||
* }
|
||||
*
|
||||
* [...]
|
||||
*
|
||||
* GDBusAuthObserver *observer;
|
||||
* GDBusServer *server;
|
||||
* GError *error;
|
||||
*
|
||||
* error = NULL;
|
||||
* observer = g_dbus_auth_observer_new ();
|
||||
* server = g_dbus_server_new_sync ("unix:tmpdir=/tmp/my-app-name",
|
||||
* G_DBUS_SERVER_FLAGS_NONE,
|
||||
* observer,
|
||||
* NULL, /<!-- -->* GCancellable *<!-- -->/
|
||||
* &error);
|
||||
* g_signal_connect (observer,
|
||||
* "authorize-authenticated-peer",
|
||||
* G_CALLBACK (on_authorize_authenticated_peer),
|
||||
* NULL);
|
||||
* g_signal_connect (server,
|
||||
* "new-connection",
|
||||
* G_CALLBACK (on_new_connection),
|
||||
* NULL);
|
||||
* g_object_unref (observer);
|
||||
* g_dbus_server_start (server);
|
||||
* </programlisting></example>
|
||||
*/
|
||||
|
||||
struct _GDBusAuthObserverPrivate
|
||||
{
|
||||
gint foo;
|
||||
};
|
||||
|
||||
enum
|
||||
{
|
||||
AUTHORIZE_AUTHENTICATED_PEER_SIGNAL,
|
||||
LAST_SIGNAL,
|
||||
};
|
||||
|
||||
static guint signals[LAST_SIGNAL] = { 0 };
|
||||
|
||||
G_DEFINE_TYPE (GDBusAuthObserver, g_dbus_auth_observer, G_TYPE_OBJECT);
|
||||
|
||||
/* ---------------------------------------------------------------------------------------------------- */
|
||||
|
||||
static void
|
||||
g_dbus_auth_observer_finalize (GObject *object)
|
||||
{
|
||||
G_OBJECT_CLASS (g_dbus_auth_observer_parent_class)->finalize (object);
|
||||
}
|
||||
|
||||
static gboolean
|
||||
g_dbus_auth_observer_authorize_authenticated_peer_real (GDBusAuthObserver *observer,
|
||||
GIOStream *stream,
|
||||
GCredentials *credentials)
|
||||
{
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
gboolean
|
||||
_g_signal_accumulator_false_handled (GSignalInvocationHint *ihint,
|
||||
GValue *return_accu,
|
||||
const GValue *handler_return,
|
||||
gpointer dummy)
|
||||
{
|
||||
gboolean continue_emission;
|
||||
gboolean signal_handled;
|
||||
|
||||
signal_handled = g_value_get_boolean (handler_return);
|
||||
g_value_set_boolean (return_accu, signal_handled);
|
||||
continue_emission = signal_handled;
|
||||
|
||||
return continue_emission;
|
||||
}
|
||||
|
||||
static void
|
||||
g_dbus_auth_observer_class_init (GDBusAuthObserverClass *klass)
|
||||
{
|
||||
GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
|
||||
|
||||
gobject_class->finalize = g_dbus_auth_observer_finalize;
|
||||
|
||||
klass->authorize_authenticated_peer = g_dbus_auth_observer_authorize_authenticated_peer_real;
|
||||
|
||||
/**
|
||||
* GDBusAuthObserver::authorize-authenticated-peer:
|
||||
* @observer: The #GDBusAuthObserver emitting the signal.
|
||||
* @stream: A #GIOStream for the #GDBusConnection.
|
||||
* @credentials: Credentials received from the peer or %NULL.
|
||||
*
|
||||
* Emitted to check if a peer that is successfully authenticated
|
||||
* is authorized.
|
||||
*
|
||||
* Returns: %TRUE if the peer is authorized, %FALSE if not.
|
||||
*
|
||||
* Since: 2.26
|
||||
*/
|
||||
signals[AUTHORIZE_AUTHENTICATED_PEER_SIGNAL] =
|
||||
g_signal_new ("authorize-authenticated-peer",
|
||||
G_TYPE_DBUS_AUTH_OBSERVER,
|
||||
G_SIGNAL_RUN_LAST,
|
||||
G_STRUCT_OFFSET (GDBusAuthObserverClass, authorize_authenticated_peer),
|
||||
_g_signal_accumulator_false_handled,
|
||||
NULL, /* accu_data */
|
||||
_gio_marshal_BOOLEAN__OBJECT_OBJECT,
|
||||
G_TYPE_BOOLEAN,
|
||||
2,
|
||||
G_TYPE_IO_STREAM,
|
||||
G_TYPE_CREDENTIALS);
|
||||
|
||||
|
||||
g_type_class_add_private (klass, sizeof (GDBusAuthObserverPrivate));
|
||||
}
|
||||
|
||||
static void
|
||||
g_dbus_auth_observer_init (GDBusAuthObserver *observer)
|
||||
{
|
||||
/* not used for now */
|
||||
observer->priv = G_TYPE_INSTANCE_GET_PRIVATE (observer,
|
||||
G_TYPE_DBUS_AUTH_OBSERVER,
|
||||
GDBusAuthObserverPrivate);;
|
||||
}
|
||||
|
||||
/**
|
||||
* g_dbus_auth_observer_new:
|
||||
*
|
||||
* Creates a new #GDBusAuthObserver object.
|
||||
*
|
||||
* Returns: A #GDBusAuthObserver. Free with g_object_unref().
|
||||
*
|
||||
* Since: 2.26
|
||||
*/
|
||||
GDBusAuthObserver *
|
||||
g_dbus_auth_observer_new (void)
|
||||
{
|
||||
return g_object_new (G_TYPE_DBUS_AUTH_OBSERVER, NULL);
|
||||
}
|
||||
|
||||
/* ---------------------------------------------------------------------------------------------------- */
|
||||
|
||||
/**
|
||||
* g_dbus_auth_observer_authorize_authenticated_peer:
|
||||
* @observer: A #GDBusAuthObserver.
|
||||
* @stream: A #GIOStream for the #GDBusConnection.
|
||||
* @credentials: Credentials received from the peer or %NULL.
|
||||
*
|
||||
* Emits the #GDBusAuthObserver::authorize-authenticated-peer signal on @observer.
|
||||
*
|
||||
* Returns: %TRUE if the peer should be denied, %FALSE otherwise.
|
||||
*
|
||||
* Since: 2.26
|
||||
*/
|
||||
gboolean
|
||||
g_dbus_auth_observer_authorize_authenticated_peer (GDBusAuthObserver *observer,
|
||||
GIOStream *stream,
|
||||
GCredentials *credentials)
|
||||
{
|
||||
gboolean denied;
|
||||
|
||||
denied = FALSE;
|
||||
g_signal_emit (observer,
|
||||
signals[AUTHORIZE_AUTHENTICATED_PEER_SIGNAL],
|
||||
0,
|
||||
stream,
|
||||
credentials,
|
||||
&denied);
|
||||
return denied;
|
||||
}
|
||||
|
||||
|
||||
|
||||
#define __G_DBUS_AUTH_OBSERVER_C__
|
||||
#include "gioaliasdef.c"
|
104
gio/gdbusauthobserver.h
Normal file
104
gio/gdbusauthobserver.h
Normal file
@ -0,0 +1,104 @@
|
||||
/* GDBus - GLib D-Bus Library
|
||||
*
|
||||
* Copyright (C) 2008-2010 Red Hat, Inc.
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General
|
||||
* Public License along with this library; if not, write to the
|
||||
* Free Software Foundation, Inc., 59 Temple Place, Suite 330,
|
||||
* Boston, MA 02111-1307, USA.
|
||||
*
|
||||
* Author: David Zeuthen <davidz@redhat.com>
|
||||
*/
|
||||
|
||||
#ifndef __G_DBUS_AUTH_OBSERVER_H__
|
||||
#define __G_DBUS_AUTH_OBSERVER_H__
|
||||
|
||||
#include <gio/giotypes.h>
|
||||
|
||||
G_BEGIN_DECLS
|
||||
|
||||
#define G_TYPE_DBUS_AUTH_OBSERVER (g_dbus_auth_observer_get_type ())
|
||||
#define G_DBUS_AUTH_OBSERVER(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), G_TYPE_DBUS_AUTH_OBSERVER, GDBusAuthObserver))
|
||||
#define G_DBUS_AUTH_OBSERVER_CLASS(k) (G_TYPE_CHECK_CLASS_CAST((k), G_TYPE_DBUS_AUTH_OBSERVER, GDBusAuthObserverClass))
|
||||
#define G_DBUS_AUTH_OBSERVER_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS ((o), G_TYPE_DBUS_AUTH_OBSERVER, GDBusAuthObserverClass))
|
||||
#define G_IS_DBUS_AUTH_OBSERVER(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), G_TYPE_DBUS_AUTH_OBSERVER))
|
||||
#define G_IS_DBUS_AUTH_OBSERVER_CLASS(k) (G_TYPE_CHECK_CLASS_TYPE ((k), G_TYPE_DBUS_AUTH_OBSERVER))
|
||||
|
||||
typedef struct _GDBusAuthObserverClass GDBusAuthObserverClass;
|
||||
typedef struct _GDBusAuthObserverPrivate GDBusAuthObserverPrivate;
|
||||
|
||||
|
||||
/**
|
||||
* GDBusAuthObserverClass:
|
||||
* @authorize_authenticated_peer: Signal class handler for the #GDBusAuthObserver::authorize-authenticated-peer signal.
|
||||
*
|
||||
* Class structure for #GDBusAuthObserverClass.
|
||||
*
|
||||
* Since: 2.26
|
||||
*/
|
||||
struct _GDBusAuthObserverClass
|
||||
{
|
||||
/*< private >*/
|
||||
GObjectClass parent_class;
|
||||
|
||||
/*< public >*/
|
||||
|
||||
/* Signals */
|
||||
gboolean (*authorize_authenticated_peer) (GDBusAuthObserver *observer,
|
||||
GIOStream *stream,
|
||||
GCredentials *credentials);
|
||||
|
||||
|
||||
/*< private >*/
|
||||
/* Padding for future expansion */
|
||||
void (*_g_reserved1) (void);
|
||||
void (*_g_reserved2) (void);
|
||||
void (*_g_reserved3) (void);
|
||||
void (*_g_reserved4) (void);
|
||||
void (*_g_reserved5) (void);
|
||||
void (*_g_reserved6) (void);
|
||||
void (*_g_reserved7) (void);
|
||||
void (*_g_reserved8) (void);
|
||||
void (*_g_reserved9) (void);
|
||||
void (*_g_reserved10) (void);
|
||||
void (*_g_reserved11) (void);
|
||||
void (*_g_reserved12) (void);
|
||||
void (*_g_reserved13) (void);
|
||||
void (*_g_reserved14) (void);
|
||||
void (*_g_reserved15) (void);
|
||||
void (*_g_reserved16) (void);
|
||||
};
|
||||
|
||||
/**
|
||||
* GDBusAuthObserver:
|
||||
*
|
||||
* The #GDBusAuthObserver structure contains only private data and
|
||||
* should only be accessed using the provided API.
|
||||
*
|
||||
* Since: 2.26
|
||||
*/
|
||||
struct _GDBusAuthObserver
|
||||
{
|
||||
GObject parent_instance;
|
||||
GDBusAuthObserverPrivate *priv;
|
||||
};
|
||||
|
||||
GType g_dbus_auth_observer_get_type (void) G_GNUC_CONST;
|
||||
GDBusAuthObserver *g_dbus_auth_observer_new (void);
|
||||
gboolean g_dbus_auth_observer_authorize_authenticated_peer (GDBusAuthObserver *observer,
|
||||
GIOStream *stream,
|
||||
GCredentials *credentials);
|
||||
|
||||
G_END_DECLS
|
||||
|
||||
#endif /* _G_DBUS_AUTH_OBSERVER_H__ */
|
5448
gio/gdbusconnection.c
Normal file
5448
gio/gdbusconnection.c
Normal file
File diff suppressed because it is too large
Load Diff
492
gio/gdbusconnection.h
Normal file
492
gio/gdbusconnection.h
Normal file
@ -0,0 +1,492 @@
|
||||
/* GDBus - GLib D-Bus Library
|
||||
*
|
||||
* Copyright (C) 2008-2010 Red Hat, Inc.
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General
|
||||
* Public License along with this library; if not, write to the
|
||||
* Free Software Foundation, Inc., 59 Temple Place, Suite 330,
|
||||
* Boston, MA 02111-1307, USA.
|
||||
*
|
||||
* Author: David Zeuthen <davidz@redhat.com>
|
||||
*/
|
||||
|
||||
#ifndef __G_DBUS_CONNECTION_H__
|
||||
#define __G_DBUS_CONNECTION_H__
|
||||
|
||||
#include <gio/giotypes.h>
|
||||
|
||||
G_BEGIN_DECLS
|
||||
|
||||
#define G_TYPE_DBUS_CONNECTION (g_dbus_connection_get_type ())
|
||||
#define G_DBUS_CONNECTION(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), G_TYPE_DBUS_CONNECTION, GDBusConnection))
|
||||
#define G_DBUS_CONNECTION_CLASS(k) (G_TYPE_CHECK_CLASS_CAST((k), G_TYPE_DBUS_CONNECTION, GDBusConnectionClass))
|
||||
#define G_DBUS_CONNECTION_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS ((o), G_TYPE_DBUS_CONNECTION, GDBusConnectionClass))
|
||||
#define G_IS_DBUS_CONNECTION(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), G_TYPE_DBUS_CONNECTION))
|
||||
#define G_IS_DBUS_CONNECTION_CLASS(k) (G_TYPE_CHECK_CLASS_TYPE ((k), G_TYPE_DBUS_CONNECTION))
|
||||
|
||||
typedef struct _GDBusConnectionClass GDBusConnectionClass;
|
||||
typedef struct _GDBusConnectionPrivate GDBusConnectionPrivate;
|
||||
|
||||
/**
|
||||
* GDBusConnection:
|
||||
*
|
||||
* The #GDBusConnection structure contains only private data and
|
||||
* should only be accessed using the provided API.
|
||||
*
|
||||
* Since: 2.26
|
||||
*/
|
||||
struct _GDBusConnection
|
||||
{
|
||||
/*< private >*/
|
||||
GObject parent_instance;
|
||||
GDBusConnectionPrivate *priv;
|
||||
};
|
||||
|
||||
/**
|
||||
* GDBusConnectionClass:
|
||||
* @closed: Signal class handler for the #GDBusConnection::closed signal.
|
||||
*
|
||||
* Class structure for #GDBusConnection.
|
||||
*
|
||||
* Since: 2.26
|
||||
*/
|
||||
struct _GDBusConnectionClass
|
||||
{
|
||||
/*< private >*/
|
||||
GObjectClass parent_class;
|
||||
|
||||
/*< public >*/
|
||||
/* Signals */
|
||||
void (*closed) (GDBusConnection *connection,
|
||||
gboolean remote_peer_vanished,
|
||||
GError *error);
|
||||
|
||||
/*< private >*/
|
||||
/* Padding for future expansion */
|
||||
void (*_g_reserved1) (void);
|
||||
void (*_g_reserved2) (void);
|
||||
void (*_g_reserved3) (void);
|
||||
void (*_g_reserved4) (void);
|
||||
void (*_g_reserved5) (void);
|
||||
void (*_g_reserved6) (void);
|
||||
void (*_g_reserved7) (void);
|
||||
void (*_g_reserved8) (void);
|
||||
};
|
||||
|
||||
GType g_dbus_connection_get_type (void) G_GNUC_CONST;
|
||||
|
||||
/* ---------------------------------------------------------------------------------------------------- */
|
||||
|
||||
void g_bus_get (GBusType bus_type,
|
||||
GCancellable *cancellable,
|
||||
GAsyncReadyCallback callback,
|
||||
gpointer user_data);
|
||||
GDBusConnection *g_bus_get_finish (GAsyncResult *res,
|
||||
GError **error);
|
||||
GDBusConnection *g_bus_get_sync (GBusType bus_type,
|
||||
GCancellable *cancellable,
|
||||
GError **error);
|
||||
|
||||
/* ---------------------------------------------------------------------------------------------------- */
|
||||
|
||||
void g_dbus_connection_new (GIOStream *stream,
|
||||
const gchar *guid,
|
||||
GDBusConnectionFlags flags,
|
||||
GDBusAuthObserver *observer,
|
||||
GCancellable *cancellable,
|
||||
GAsyncReadyCallback callback,
|
||||
gpointer user_data);
|
||||
GDBusConnection *g_dbus_connection_new_finish (GAsyncResult *res,
|
||||
GError **error);
|
||||
GDBusConnection *g_dbus_connection_new_sync (GIOStream *stream,
|
||||
const gchar *guid,
|
||||
GDBusConnectionFlags flags,
|
||||
GDBusAuthObserver *observer,
|
||||
GCancellable *cancellable,
|
||||
GError **error);
|
||||
|
||||
void g_dbus_connection_new_for_address (const gchar *address,
|
||||
GDBusConnectionFlags flags,
|
||||
GDBusAuthObserver *observer,
|
||||
GCancellable *cancellable,
|
||||
GAsyncReadyCallback callback,
|
||||
gpointer user_data);
|
||||
GDBusConnection *g_dbus_connection_new_for_address_finish (GAsyncResult *res,
|
||||
GError **error);
|
||||
GDBusConnection *g_dbus_connection_new_for_address_sync (const gchar *address,
|
||||
GDBusConnectionFlags flags,
|
||||
GDBusAuthObserver *observer,
|
||||
GCancellable *cancellable,
|
||||
GError **error);
|
||||
|
||||
/* ---------------------------------------------------------------------------------------------------- */
|
||||
|
||||
gboolean g_dbus_connection_is_closed (GDBusConnection *connection);
|
||||
void g_dbus_connection_close (GDBusConnection *connection);
|
||||
GIOStream *g_dbus_connection_get_stream (GDBusConnection *connection);
|
||||
const gchar *g_dbus_connection_get_guid (GDBusConnection *connection);
|
||||
const gchar *g_dbus_connection_get_unique_name (GDBusConnection *connection);
|
||||
GCredentials *g_dbus_connection_get_peer_credentials (GDBusConnection *connection);
|
||||
gboolean g_dbus_connection_get_exit_on_close (GDBusConnection *connection);
|
||||
void g_dbus_connection_set_exit_on_close (GDBusConnection *connection,
|
||||
gboolean exit_on_close);
|
||||
GDBusCapabilityFlags g_dbus_connection_get_capabilities (GDBusConnection *connection);
|
||||
/* ---------------------------------------------------------------------------------------------------- */
|
||||
|
||||
gboolean g_dbus_connection_send_message (GDBusConnection *connection,
|
||||
GDBusMessage *message,
|
||||
volatile guint32 *out_serial,
|
||||
GError **error);
|
||||
void g_dbus_connection_send_message_with_reply (GDBusConnection *connection,
|
||||
GDBusMessage *message,
|
||||
gint timeout_msec,
|
||||
volatile guint32 *out_serial,
|
||||
GCancellable *cancellable,
|
||||
GAsyncReadyCallback callback,
|
||||
gpointer user_data);
|
||||
GDBusMessage *g_dbus_connection_send_message_with_reply_finish (GDBusConnection *connection,
|
||||
GAsyncResult *res,
|
||||
GError **error);
|
||||
GDBusMessage *g_dbus_connection_send_message_with_reply_sync (GDBusConnection *connection,
|
||||
GDBusMessage *message,
|
||||
gint timeout_msec,
|
||||
volatile guint32 *out_serial,
|
||||
GCancellable *cancellable,
|
||||
GError **error);
|
||||
|
||||
/* ---------------------------------------------------------------------------------------------------- */
|
||||
|
||||
gboolean g_dbus_connection_emit_signal (GDBusConnection *connection,
|
||||
const gchar *destination_bus_name,
|
||||
const gchar *object_path,
|
||||
const gchar *interface_name,
|
||||
const gchar *signal_name,
|
||||
GVariant *parameters,
|
||||
GError **error);
|
||||
void g_dbus_connection_call (GDBusConnection *connection,
|
||||
const gchar *bus_name,
|
||||
const gchar *object_path,
|
||||
const gchar *interface_name,
|
||||
const gchar *method_name,
|
||||
GVariant *parameters,
|
||||
GDBusCallFlags flags,
|
||||
gint timeout_msec,
|
||||
GCancellable *cancellable,
|
||||
GAsyncReadyCallback callback,
|
||||
gpointer user_data);
|
||||
GVariant *g_dbus_connection_call_finish (GDBusConnection *connection,
|
||||
GAsyncResult *res,
|
||||
GError **error);
|
||||
GVariant *g_dbus_connection_call_sync (GDBusConnection *connection,
|
||||
const gchar *bus_name,
|
||||
const gchar *object_path,
|
||||
const gchar *interface_name,
|
||||
const gchar *method_name,
|
||||
GVariant *parameters,
|
||||
GDBusCallFlags flags,
|
||||
gint timeout_msec,
|
||||
GCancellable *cancellable,
|
||||
GError **error);
|
||||
|
||||
/* ---------------------------------------------------------------------------------------------------- */
|
||||
|
||||
|
||||
/**
|
||||
* GDBusInterfaceMethodCallFunc:
|
||||
* @connection: A #GDBusConnection.
|
||||
* @sender: The unique bus name of the remote caller.
|
||||
* @object_path: The object path that the method was invoked on.
|
||||
* @interface_name: The D-Bus interface name the method was invoked on.
|
||||
* @method_name: The name of the method that was invoked.
|
||||
* @parameters: A #GVariant tuple with parameters.
|
||||
* @invocation: A #GDBusMethodInvocation object that can be used to return a value or error.
|
||||
* @user_data: The @user_data #gpointer passed to g_dbus_connection_register_object().
|
||||
*
|
||||
* The type of the @method_call function in #GDBusInterfaceVTable.
|
||||
*
|
||||
* Since: 2.26
|
||||
*/
|
||||
typedef void (*GDBusInterfaceMethodCallFunc) (GDBusConnection *connection,
|
||||
const gchar *sender,
|
||||
const gchar *object_path,
|
||||
const gchar *interface_name,
|
||||
const gchar *method_name,
|
||||
GVariant *parameters,
|
||||
GDBusMethodInvocation *invocation,
|
||||
gpointer user_data);
|
||||
|
||||
/**
|
||||
* GDBusInterfaceGetPropertyFunc:
|
||||
* @connection: A #GDBusConnection.
|
||||
* @sender: The unique bus name of the remote caller.
|
||||
* @object_path: The object path that the method was invoked on.
|
||||
* @interface_name: The D-Bus interface name for the property.
|
||||
* @property_name: The name of the property to get the value of.
|
||||
* @error: Return location for error.
|
||||
* @user_data: The @user_data #gpointer passed to g_dbus_connection_register_object().
|
||||
*
|
||||
* The type of the @get_property function in #GDBusInterfaceVTable.
|
||||
*
|
||||
* Returns: A newly-allocated #GVariant with the value for @property_name or %NULL if @error is set.
|
||||
*
|
||||
* Since: 2.26
|
||||
*/
|
||||
typedef GVariant *(*GDBusInterfaceGetPropertyFunc) (GDBusConnection *connection,
|
||||
const gchar *sender,
|
||||
const gchar *object_path,
|
||||
const gchar *interface_name,
|
||||
const gchar *property_name,
|
||||
GError **error,
|
||||
gpointer user_data);
|
||||
|
||||
/**
|
||||
* GDBusInterfaceSetPropertyFunc:
|
||||
* @connection: A #GDBusConnection.
|
||||
* @sender: The unique bus name of the remote caller.
|
||||
* @object_path: The object path that the method was invoked on.
|
||||
* @interface_name: The D-Bus interface name for the property.
|
||||
* @property_name: The name of the property to get the value of.
|
||||
* @value: The value to set the property to.
|
||||
* @error: Return location for error.
|
||||
* @user_data: The @user_data #gpointer passed to g_dbus_connection_register_object().
|
||||
*
|
||||
* The type of the @set_property function in #GDBusInterfaceVTable.
|
||||
*
|
||||
* Returns: %TRUE if the property was set to @value, %FALSE if @error is set.
|
||||
*
|
||||
* Since: 2.26
|
||||
*/
|
||||
typedef gboolean (*GDBusInterfaceSetPropertyFunc) (GDBusConnection *connection,
|
||||
const gchar *sender,
|
||||
const gchar *object_path,
|
||||
const gchar *interface_name,
|
||||
const gchar *property_name,
|
||||
GVariant *value,
|
||||
GError **error,
|
||||
gpointer user_data);
|
||||
|
||||
/**
|
||||
* GDBusInterfaceVTable:
|
||||
* @method_call: Function for handling incoming method calls.
|
||||
* @get_property: Function for getting a property.
|
||||
* @set_property: Function for setting a property.
|
||||
*
|
||||
* Virtual table for handling properties and method calls for a D-Bus
|
||||
* interface.
|
||||
*
|
||||
* If you want to handle getting/setting D-Bus properties asynchronously, simply
|
||||
* register an object with the <literal>org.freedesktop.DBus.Properties</literal>
|
||||
* D-Bus interface using g_dbus_connection_register_object().
|
||||
*
|
||||
* Since: 2.26
|
||||
*/
|
||||
struct _GDBusInterfaceVTable
|
||||
{
|
||||
GDBusInterfaceMethodCallFunc method_call;
|
||||
GDBusInterfaceGetPropertyFunc get_property;
|
||||
GDBusInterfaceSetPropertyFunc set_property;
|
||||
|
||||
/*< private >*/
|
||||
/* Padding for future expansion */
|
||||
void (*_g_reserved1) (void);
|
||||
void (*_g_reserved2) (void);
|
||||
void (*_g_reserved3) (void);
|
||||
void (*_g_reserved4) (void);
|
||||
void (*_g_reserved5) (void);
|
||||
void (*_g_reserved6) (void);
|
||||
void (*_g_reserved7) (void);
|
||||
void (*_g_reserved8) (void);
|
||||
};
|
||||
|
||||
guint g_dbus_connection_register_object (GDBusConnection *connection,
|
||||
const gchar *object_path,
|
||||
const GDBusInterfaceInfo *introspection_data,
|
||||
const GDBusInterfaceVTable *vtable,
|
||||
gpointer user_data,
|
||||
GDestroyNotify user_data_free_func,
|
||||
GError **error);
|
||||
gboolean g_dbus_connection_unregister_object (GDBusConnection *connection,
|
||||
guint registration_id);
|
||||
|
||||
/* ---------------------------------------------------------------------------------------------------- */
|
||||
|
||||
/**
|
||||
* GDBusSubtreeEnumerateFunc:
|
||||
* @connection: A #GDBusConnection.
|
||||
* @sender: The unique bus name of the remote caller.
|
||||
* @object_path: The object path that was registered with g_dbus_connection_register_subtree().
|
||||
* @user_data: The @user_data #gpointer passed to g_dbus_connection_register_subtree().
|
||||
*
|
||||
* The type of the @enumerate function in #GDBusSubtreeVTable.
|
||||
*
|
||||
* Returns: A newly allocated array of strings for node names that are children of @object_path.
|
||||
*
|
||||
* Since: 2.26
|
||||
*/
|
||||
typedef gchar** (*GDBusSubtreeEnumerateFunc) (GDBusConnection *connection,
|
||||
const gchar *sender,
|
||||
const gchar *object_path,
|
||||
gpointer user_data);
|
||||
|
||||
/**
|
||||
* GDBusSubtreeIntrospectFunc:
|
||||
* @connection: A #GDBusConnection.
|
||||
* @sender: The unique bus name of the remote caller.
|
||||
* @object_path: The object path that was registered with g_dbus_connection_register_subtree().
|
||||
* @node: A node that is a child of @object_path (relative to @object_path) or <quote>/</quote> for the root of the subtree.
|
||||
* @user_data: The @user_data #gpointer passed to g_dbus_connection_register_subtree().
|
||||
*
|
||||
* The type of the @introspect function in #GDBusSubtreeVTable.
|
||||
*
|
||||
* Returns: A newly-allocated #GPtrArray with pointers to #GDBusInterfaceInfo describing
|
||||
* the interfaces implemented by @node.
|
||||
*
|
||||
* Since: 2.26
|
||||
*/
|
||||
typedef GPtrArray *(*GDBusSubtreeIntrospectFunc) (GDBusConnection *connection,
|
||||
const gchar *sender,
|
||||
const gchar *object_path,
|
||||
const gchar *node,
|
||||
gpointer user_data);
|
||||
|
||||
/**
|
||||
* GDBusSubtreeDispatchFunc:
|
||||
* @connection: A #GDBusConnection.
|
||||
* @sender: The unique bus name of the remote caller.
|
||||
* @object_path: The object path that was registered with g_dbus_connection_register_subtree().
|
||||
* @interface_name: The D-Bus interface name that the method call or property access is for.
|
||||
* @node: A node that is a child of @object_path (relative to @object_path) or <quote>/</quote> for the root of the subtree.
|
||||
* @out_user_data: Return location for user data to pass to functions in the returned #GDBusInterfaceVTable (never %NULL).
|
||||
* @user_data: The @user_data #gpointer passed to g_dbus_connection_register_subtree().
|
||||
*
|
||||
* The type of the @dispatch function in #GDBusSubtreeVTable.
|
||||
*
|
||||
* Returns: A #GDBusInterfaceVTable or %NULL if you don't want to handle the methods.
|
||||
*
|
||||
* Since: 2.26
|
||||
*/
|
||||
typedef const GDBusInterfaceVTable * (*GDBusSubtreeDispatchFunc) (GDBusConnection *connection,
|
||||
const gchar *sender,
|
||||
const gchar *object_path,
|
||||
const gchar *interface_name,
|
||||
const gchar *node,
|
||||
gpointer *out_user_data,
|
||||
gpointer user_data);
|
||||
|
||||
/**
|
||||
* GDBusSubtreeVTable:
|
||||
* @enumerate: Function for enumerating child nodes.
|
||||
* @introspect: Function for introspecting a child node.
|
||||
* @dispatch: Function for dispatching a remote call on a child node.
|
||||
*
|
||||
* Virtual table for handling subtrees registered with g_dbus_connection_register_subtree().
|
||||
*
|
||||
* Since: 2.26
|
||||
*/
|
||||
struct _GDBusSubtreeVTable
|
||||
{
|
||||
GDBusSubtreeEnumerateFunc enumerate;
|
||||
GDBusSubtreeIntrospectFunc introspect;
|
||||
GDBusSubtreeDispatchFunc dispatch;
|
||||
|
||||
/*< private >*/
|
||||
/* Padding for future expansion */
|
||||
void (*_g_reserved1) (void);
|
||||
void (*_g_reserved2) (void);
|
||||
void (*_g_reserved3) (void);
|
||||
void (*_g_reserved4) (void);
|
||||
void (*_g_reserved5) (void);
|
||||
void (*_g_reserved6) (void);
|
||||
void (*_g_reserved7) (void);
|
||||
void (*_g_reserved8) (void);
|
||||
};
|
||||
|
||||
guint g_dbus_connection_register_subtree (GDBusConnection *connection,
|
||||
const gchar *object_path,
|
||||
const GDBusSubtreeVTable *vtable,
|
||||
GDBusSubtreeFlags flags,
|
||||
gpointer user_data,
|
||||
GDestroyNotify user_data_free_func,
|
||||
GError **error);
|
||||
gboolean g_dbus_connection_unregister_subtree (GDBusConnection *connection,
|
||||
guint registration_id);
|
||||
|
||||
/* ---------------------------------------------------------------------------------------------------- */
|
||||
|
||||
/**
|
||||
* GDBusSignalCallback:
|
||||
* @connection: A #GDBusConnection.
|
||||
* @sender_name: The unique bus name of the sender of the signal.
|
||||
* @object_path: The object path that the signal was emitted on.
|
||||
* @interface_name: The name of the signal.
|
||||
* @signal_name: The name of the signal.
|
||||
* @parameters: A #GVariant tuple with parameters for the signal.
|
||||
* @user_data: User data passed when subscribing to the signal.
|
||||
*
|
||||
* Signature for callback function used in g_dbus_connection_signal_subscribe().
|
||||
*
|
||||
* Since: 2.26
|
||||
*/
|
||||
typedef void (*GDBusSignalCallback) (GDBusConnection *connection,
|
||||
const gchar *sender_name,
|
||||
const gchar *object_path,
|
||||
const gchar *interface_name,
|
||||
const gchar *signal_name,
|
||||
GVariant *parameters,
|
||||
gpointer user_data);
|
||||
|
||||
guint g_dbus_connection_signal_subscribe (GDBusConnection *connection,
|
||||
const gchar *sender,
|
||||
const gchar *interface_name,
|
||||
const gchar *member,
|
||||
const gchar *object_path,
|
||||
const gchar *arg0,
|
||||
GDBusSignalCallback callback,
|
||||
gpointer user_data,
|
||||
GDestroyNotify user_data_free_func);
|
||||
void g_dbus_connection_signal_unsubscribe (GDBusConnection *connection,
|
||||
guint subscription_id);
|
||||
|
||||
/* ---------------------------------------------------------------------------------------------------- */
|
||||
|
||||
/**
|
||||
* GDBusMessageFilterFunction:
|
||||
* @connection: A #GDBusConnection.
|
||||
* @message: A #GDBusMessage.
|
||||
* @user_data: User data passed when adding the filter.
|
||||
*
|
||||
* Signature for function used in g_dbus_connection_add_filter().
|
||||
*
|
||||
* Returns: %TRUE if the filter handled @message, %FALSE to let other
|
||||
* handlers run.
|
||||
*
|
||||
* Since: 2.26
|
||||
*/
|
||||
typedef gboolean (*GDBusMessageFilterFunction) (GDBusConnection *connection,
|
||||
GDBusMessage *message,
|
||||
gpointer user_data);
|
||||
|
||||
guint g_dbus_connection_add_filter (GDBusConnection *connection,
|
||||
GDBusMessageFilterFunction filter_function,
|
||||
gpointer user_data,
|
||||
GDestroyNotify user_data_free_func);
|
||||
|
||||
void g_dbus_connection_remove_filter (GDBusConnection *connection,
|
||||
guint filter_id);
|
||||
|
||||
/* ---------------------------------------------------------------------------------------------------- */
|
||||
|
||||
|
||||
G_END_DECLS
|
||||
|
||||
#endif /* __G_DBUS_CONNECTION_H__ */
|
873
gio/gdbuserror.c
Normal file
873
gio/gdbuserror.c
Normal file
@ -0,0 +1,873 @@
|
||||
/* GDBus - GLib D-Bus Library
|
||||
*
|
||||
* Copyright (C) 2008-2010 Red Hat, Inc.
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General
|
||||
* Public License along with this library; if not, write to the
|
||||
* Free Software Foundation, Inc., 59 Temple Place, Suite 330,
|
||||
* Boston, MA 02111-1307, USA.
|
||||
*
|
||||
* Author: David Zeuthen <davidz@redhat.com>
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "gdbuserror.h"
|
||||
#include "gioenums.h"
|
||||
#include "gioenumtypes.h"
|
||||
#include "gioerror.h"
|
||||
#include "gdbusprivate.h"
|
||||
|
||||
#include "glibintl.h"
|
||||
#include "gioalias.h"
|
||||
|
||||
/**
|
||||
* SECTION:gdbuserror
|
||||
* @title: GDBusError
|
||||
* @short_description: Mapping D-Bus errors to and from #GError
|
||||
* @include: gio/gio.h
|
||||
*
|
||||
* All facilities that return errors from remote methods (such as
|
||||
* g_dbus_connection_call_sync()) use #GError to represent both D-Bus
|
||||
* errors (e.g. errors returned from the other peer) and locally
|
||||
* in-process generated errors.
|
||||
*
|
||||
* To check if a returned #GError is an error from a remote peer, use
|
||||
* g_dbus_error_is_remote_error(). To get the actual D-Bus error name,
|
||||
* use g_dbus_error_get_remote_error(). Before presenting an error,
|
||||
* always use g_dbus_error_strip_remote_error().
|
||||
*
|
||||
* In addition, facilities used to return errors to a remote peer also
|
||||
* use #GError. See g_dbus_method_invocation_return_error() for
|
||||
* discussion about how the D-Bus error name is set.
|
||||
*
|
||||
* Applications can associate a #GError error domain with a set of D-Bus errors in order to
|
||||
* automatically map from D-Bus errors to #GError and back. This
|
||||
* is typically done in the function returning the #GQuark for the
|
||||
* error domain:
|
||||
* <example id="error-registration"><title>Error Registration</title><programlisting>
|
||||
* /<!-- -->* foo-bar-error.h: *<!-- -->/
|
||||
*
|
||||
* #define FOO_BAR_ERROR (foo_bar_error_quark ())
|
||||
* GQuark foo_bar_error_quark (void);
|
||||
*
|
||||
* typedef enum
|
||||
* {
|
||||
* FOO_BAR_ERROR_FAILED,
|
||||
* FOO_BAR_ERROR_ANOTHER_ERROR,
|
||||
* FOO_BAR_ERROR_SOME_THIRD_ERROR,
|
||||
* } FooBarError;
|
||||
*
|
||||
* /<!-- -->* foo-bar-error.c: *<!-- -->/
|
||||
*
|
||||
* static const GDBusErrorEntry foo_bar_error_entries[] =
|
||||
* {
|
||||
* {FOO_BAR_ERROR_FAILED, "org.project.Foo.Bar.Error.Failed"},
|
||||
* {FOO_BAR_ERROR_ANOTHER_ERROR, "org.project.Foo.Bar.Error.AnotherError"},
|
||||
* {FOO_BAR_ERROR_SOME_THIRD_ERROR, "org.project.Foo.Bar.Error.SomeThirdError"},
|
||||
* };
|
||||
*
|
||||
* GQuark
|
||||
* foo_bar_error_quark (void)
|
||||
* {
|
||||
* static volatile gsize quark_volatile = 0;
|
||||
* g_dbus_error_register_error_domain ("foo-bar-error-quark",
|
||||
* &quark_volatile,
|
||||
* foo_bar_error_entries,
|
||||
* G_N_ELEMENTS (foo_bar_error_entries));
|
||||
* G_STATIC_ASSERT (G_N_ELEMENTS (foo_bar_error_entries) - 1 == FOO_BAR_ERROR_SOME_THIRD_ERROR);
|
||||
* return (GQuark) quark_volatile;
|
||||
* }
|
||||
* </programlisting></example>
|
||||
* With this setup, a D-Bus peer can transparently pass e.g. %FOO_BAR_ERROR_ANOTHER_ERROR and
|
||||
* other peers will see the D-Bus error name <literal>org.project.Foo.Bar.Error.AnotherError</literal>.
|
||||
* If the other peer is using GDBus, the peer will see also %FOO_BAR_ERROR_ANOTHER_ERROR instead
|
||||
* of %G_IO_ERROR_DBUS_ERROR. Note that GDBus clients can still recover
|
||||
* <literal>org.project.Foo.Bar.Error.AnotherError</literal> using g_dbus_error_get_remote_error().
|
||||
*
|
||||
* Note that errors in the %G_DBUS_ERROR error domain is intended only
|
||||
* for returning errors from a remote message bus process. Errors
|
||||
* generated locally in-process by e.g. #GDBusConnection is from the
|
||||
* %G_IO_ERROR domain.
|
||||
*/
|
||||
|
||||
static const GDBusErrorEntry g_dbus_error_entries[] =
|
||||
{
|
||||
{G_DBUS_ERROR_FAILED, "org.freedesktop.DBus.Error.Failed"},
|
||||
{G_DBUS_ERROR_NO_MEMORY, "org.freedesktop.DBus.Error.NoMemory"},
|
||||
{G_DBUS_ERROR_SERVICE_UNKNOWN, "org.freedesktop.DBus.Error.ServiceUnknown"},
|
||||
{G_DBUS_ERROR_NAME_HAS_NO_OWNER, "org.freedesktop.DBus.Error.NameHasNoOwner"},
|
||||
{G_DBUS_ERROR_NO_REPLY, "org.freedesktop.DBus.Error.NoReply"},
|
||||
{G_DBUS_ERROR_IO_ERROR, "org.freedesktop.DBus.Error.IOError"},
|
||||
{G_DBUS_ERROR_BAD_ADDRESS, "org.freedesktop.DBus.Error.BadAddress"},
|
||||
{G_DBUS_ERROR_NOT_SUPPORTED, "org.freedesktop.DBus.Error.NotSupported"},
|
||||
{G_DBUS_ERROR_LIMITS_EXCEEDED, "org.freedesktop.DBus.Error.LimitsExceeded"},
|
||||
{G_DBUS_ERROR_ACCESS_DENIED, "org.freedesktop.DBus.Error.AccessDenied"},
|
||||
{G_DBUS_ERROR_AUTH_FAILED, "org.freedesktop.DBus.Error.AuthFailed"},
|
||||
{G_DBUS_ERROR_NO_SERVER, "org.freedesktop.DBus.Error.NoServer"},
|
||||
{G_DBUS_ERROR_TIMEOUT, "org.freedesktop.DBus.Error.Timeout"},
|
||||
{G_DBUS_ERROR_NO_NETWORK, "org.freedesktop.DBus.Error.NoNetwork"},
|
||||
{G_DBUS_ERROR_ADDRESS_IN_USE, "org.freedesktop.DBus.Error.AddressInUse"},
|
||||
{G_DBUS_ERROR_DISCONNECTED, "org.freedesktop.DBus.Error.Disconnected"},
|
||||
{G_DBUS_ERROR_INVALID_ARGS, "org.freedesktop.DBus.Error.InvalidArgs"},
|
||||
{G_DBUS_ERROR_FILE_NOT_FOUND, "org.freedesktop.DBus.Error.FileNotFound"},
|
||||
{G_DBUS_ERROR_FILE_EXISTS, "org.freedesktop.DBus.Error.FileExists"},
|
||||
{G_DBUS_ERROR_UNKNOWN_METHOD, "org.freedesktop.DBus.Error.UnknownMethod"},
|
||||
{G_DBUS_ERROR_TIMED_OUT, "org.freedesktop.DBus.Error.TimedOut"},
|
||||
{G_DBUS_ERROR_MATCH_RULE_NOT_FOUND, "org.freedesktop.DBus.Error.MatchRuleNotFound"},
|
||||
{G_DBUS_ERROR_MATCH_RULE_INVALID, "org.freedesktop.DBus.Error.MatchRuleInvalid"},
|
||||
{G_DBUS_ERROR_SPAWN_EXEC_FAILED, "org.freedesktop.DBus.Error.Spawn.ExecFailed"},
|
||||
{G_DBUS_ERROR_SPAWN_FORK_FAILED, "org.freedesktop.DBus.Error.Spawn.ForkFailed"},
|
||||
{G_DBUS_ERROR_SPAWN_CHILD_EXITED, "org.freedesktop.DBus.Error.Spawn.ChildExited"},
|
||||
{G_DBUS_ERROR_SPAWN_CHILD_SIGNALED, "org.freedesktop.DBus.Error.Spawn.ChildSignaled"},
|
||||
{G_DBUS_ERROR_SPAWN_FAILED, "org.freedesktop.DBus.Error.Spawn.Failed"},
|
||||
{G_DBUS_ERROR_SPAWN_SETUP_FAILED, "org.freedesktop.DBus.Error.Spawn.FailedToSetup"},
|
||||
{G_DBUS_ERROR_SPAWN_CONFIG_INVALID, "org.freedesktop.DBus.Error.Spawn.ConfigInvalid"},
|
||||
{G_DBUS_ERROR_SPAWN_SERVICE_INVALID, "org.freedesktop.DBus.Error.Spawn.ServiceNotValid"},
|
||||
{G_DBUS_ERROR_SPAWN_SERVICE_NOT_FOUND, "org.freedesktop.DBus.Error.Spawn.ServiceNotFound"},
|
||||
{G_DBUS_ERROR_SPAWN_PERMISSIONS_INVALID, "org.freedesktop.DBus.Error.Spawn.PermissionsInvalid"},
|
||||
{G_DBUS_ERROR_SPAWN_FILE_INVALID, "org.freedesktop.DBus.Error.Spawn.FileInvalid"},
|
||||
{G_DBUS_ERROR_SPAWN_NO_MEMORY, "org.freedesktop.DBus.Error.Spawn.NoMemory"},
|
||||
{G_DBUS_ERROR_UNIX_PROCESS_ID_UNKNOWN, "org.freedesktop.DBus.Error.UnixProcessIdUnknown"},
|
||||
{G_DBUS_ERROR_INVALID_SIGNATURE, "org.freedesktop.DBus.Error.InvalidSignature"},
|
||||
{G_DBUS_ERROR_INVALID_FILE_CONTENT, "org.freedesktop.DBus.Error.InvalidFileContent"},
|
||||
{G_DBUS_ERROR_SELINUX_SECURITY_CONTEXT_UNKNOWN, "org.freedesktop.DBus.Error.SELinuxSecurityContextUnknown"},
|
||||
{G_DBUS_ERROR_ADT_AUDIT_DATA_UNKNOWN, "org.freedesktop.DBus.Error.AdtAuditDataUnknown"},
|
||||
{G_DBUS_ERROR_OBJECT_PATH_IN_USE, "org.freedesktop.DBus.Error.ObjectPathInUse"},
|
||||
};
|
||||
|
||||
GQuark
|
||||
g_dbus_error_quark (void)
|
||||
{
|
||||
static volatile gsize quark_volatile = 0;
|
||||
g_dbus_error_register_error_domain ("g-dbus-error-quark",
|
||||
&quark_volatile,
|
||||
g_dbus_error_entries,
|
||||
G_N_ELEMENTS (g_dbus_error_entries));
|
||||
G_STATIC_ASSERT (G_N_ELEMENTS (g_dbus_error_entries) - 1 == G_DBUS_ERROR_OBJECT_PATH_IN_USE);
|
||||
return (GQuark) quark_volatile;
|
||||
}
|
||||
|
||||
/**
|
||||
* g_dbus_error_register_error_domain:
|
||||
* @error_domain_quark_name: The error domain name.
|
||||
* @quark_volatile: A pointer where to store the #GQuark.
|
||||
* @entries: A pointer to @num_entries #GDBusErrorEntry struct items.
|
||||
* @num_entries: Number of items to register.
|
||||
*
|
||||
* Helper function for associating a #GError error domain with D-Bus error names.
|
||||
*
|
||||
* Since: 2.26
|
||||
*/
|
||||
void
|
||||
g_dbus_error_register_error_domain (const gchar *error_domain_quark_name,
|
||||
volatile gsize *quark_volatile,
|
||||
const GDBusErrorEntry *entries,
|
||||
guint num_entries)
|
||||
{
|
||||
g_return_if_fail (error_domain_quark_name != NULL);
|
||||
g_return_if_fail (quark_volatile != NULL);
|
||||
g_return_if_fail (entries != NULL);
|
||||
g_return_if_fail (num_entries > 0);
|
||||
|
||||
if (g_once_init_enter (quark_volatile))
|
||||
{
|
||||
guint n;
|
||||
GQuark quark;
|
||||
|
||||
quark = g_quark_from_static_string (error_domain_quark_name);
|
||||
|
||||
for (n = 0; n < num_entries; n++)
|
||||
{
|
||||
g_warn_if_fail (g_dbus_error_register_error (quark,
|
||||
entries[n].error_code,
|
||||
entries[n].dbus_error_name));
|
||||
}
|
||||
g_once_init_leave (quark_volatile, quark);
|
||||
}
|
||||
}
|
||||
|
||||
static gboolean
|
||||
_g_dbus_error_decode_gerror (const gchar *dbus_name,
|
||||
GQuark *out_error_domain,
|
||||
gint *out_error_code)
|
||||
{
|
||||
gboolean ret;
|
||||
guint n;
|
||||
GString *s;
|
||||
gchar *domain_quark_string;
|
||||
|
||||
ret = FALSE;
|
||||
s = NULL;
|
||||
|
||||
if (g_str_has_prefix (dbus_name, "org.gtk.GDBus.UnmappedGError.Quark._"))
|
||||
{
|
||||
s = g_string_new (NULL);
|
||||
|
||||
for (n = sizeof "org.gtk.GDBus.UnmappedGError.Quark._" - 1;
|
||||
dbus_name[n] != '.' && dbus_name[n] != '\0';
|
||||
n++)
|
||||
{
|
||||
if (g_ascii_isalnum (dbus_name[n]))
|
||||
{
|
||||
g_string_append_c (s, dbus_name[n]);
|
||||
}
|
||||
else if (dbus_name[n] == '_')
|
||||
{
|
||||
guint nibble_top;
|
||||
guint nibble_bottom;
|
||||
|
||||
n++;
|
||||
|
||||
nibble_top = dbus_name[n];
|
||||
if (nibble_top >= '0' && nibble_top <= '9')
|
||||
nibble_top -= '0';
|
||||
else if (nibble_top >= 'a' && nibble_top <= 'f')
|
||||
nibble_top -= ('a' - 10);
|
||||
else
|
||||
goto not_mapped;
|
||||
|
||||
n++;
|
||||
|
||||
nibble_bottom = dbus_name[n];
|
||||
if (nibble_bottom >= '0' && nibble_bottom <= '9')
|
||||
nibble_bottom -= '0';
|
||||
else if (nibble_bottom >= 'a' && nibble_bottom <= 'f')
|
||||
nibble_bottom -= ('a' - 10);
|
||||
else
|
||||
goto not_mapped;
|
||||
|
||||
g_string_append_c (s, (nibble_top<<4) | nibble_bottom);
|
||||
}
|
||||
else
|
||||
{
|
||||
goto not_mapped;
|
||||
}
|
||||
}
|
||||
|
||||
if (!g_str_has_prefix (dbus_name + n, ".Code"))
|
||||
goto not_mapped;
|
||||
|
||||
domain_quark_string = g_string_free (s, FALSE);
|
||||
s = NULL;
|
||||
|
||||
if (out_error_domain != NULL)
|
||||
*out_error_domain = g_quark_from_string (domain_quark_string);
|
||||
g_free (domain_quark_string);
|
||||
|
||||
if (out_error_code != NULL)
|
||||
*out_error_code = atoi (dbus_name + n + sizeof ".Code" - 1);
|
||||
|
||||
ret = TRUE;
|
||||
}
|
||||
|
||||
not_mapped:
|
||||
|
||||
if (s != NULL)
|
||||
g_string_free (s, TRUE);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* ---------------------------------------------------------------------------------------------------- */
|
||||
|
||||
typedef struct
|
||||
{
|
||||
GQuark error_domain;
|
||||
gint error_code;
|
||||
} QuarkCodePair;
|
||||
|
||||
static guint
|
||||
quark_code_pair_hash_func (const QuarkCodePair *pair)
|
||||
{
|
||||
gint val;
|
||||
val = pair->error_domain + pair->error_code;
|
||||
return g_int_hash (&val);
|
||||
}
|
||||
|
||||
static gboolean
|
||||
quark_code_pair_equal_func (const QuarkCodePair *a,
|
||||
const QuarkCodePair *b)
|
||||
{
|
||||
return (a->error_domain == b->error_domain) && (a->error_code == b->error_code);
|
||||
}
|
||||
|
||||
typedef struct
|
||||
{
|
||||
QuarkCodePair pair;
|
||||
gchar *dbus_error_name;
|
||||
} RegisteredError;
|
||||
|
||||
static void
|
||||
registered_error_free (RegisteredError *re)
|
||||
{
|
||||
g_free (re->dbus_error_name);
|
||||
g_free (re);
|
||||
}
|
||||
|
||||
G_LOCK_DEFINE_STATIC (error_lock);
|
||||
|
||||
/* maps from QuarkCodePair* -> RegisteredError* */
|
||||
static GHashTable *quark_code_pair_to_re = NULL;
|
||||
|
||||
/* maps from gchar* -> RegisteredError* */
|
||||
static GHashTable *dbus_error_name_to_re = NULL;
|
||||
|
||||
/**
|
||||
* g_dbus_error_register_error:
|
||||
* @error_domain: A #GQuark for a error domain.
|
||||
* @error_code: An error code.
|
||||
* @dbus_error_name: A D-Bus error name.
|
||||
*
|
||||
* Creates an association to map between @dbus_error_name and
|
||||
* #GError<!-- -->s specified by @error_domain and @error_code.
|
||||
*
|
||||
* This is typically done in the routine that returns the #GQuark for
|
||||
* an error domain.
|
||||
*
|
||||
* Returns: %TRUE if the association was created, %FALSE if it already
|
||||
* exists.
|
||||
*
|
||||
* Since: 2.26
|
||||
*/
|
||||
gboolean
|
||||
g_dbus_error_register_error (GQuark error_domain,
|
||||
gint error_code,
|
||||
const gchar *dbus_error_name)
|
||||
{
|
||||
gboolean ret;
|
||||
QuarkCodePair pair;
|
||||
RegisteredError *re;
|
||||
|
||||
g_return_val_if_fail (dbus_error_name != NULL, FALSE);
|
||||
|
||||
ret = FALSE;
|
||||
|
||||
G_LOCK (error_lock);
|
||||
|
||||
if (quark_code_pair_to_re == NULL)
|
||||
{
|
||||
g_assert (dbus_error_name_to_re == NULL); /* check invariant */
|
||||
quark_code_pair_to_re = g_hash_table_new ((GHashFunc) quark_code_pair_hash_func,
|
||||
(GEqualFunc) quark_code_pair_equal_func);
|
||||
dbus_error_name_to_re = g_hash_table_new_full (g_str_hash,
|
||||
g_str_equal,
|
||||
NULL,
|
||||
(GDestroyNotify) registered_error_free);
|
||||
}
|
||||
|
||||
if (g_hash_table_lookup (dbus_error_name_to_re, dbus_error_name) != NULL)
|
||||
goto out;
|
||||
|
||||
pair.error_domain = error_domain;
|
||||
pair.error_code = error_code;
|
||||
|
||||
if (g_hash_table_lookup (quark_code_pair_to_re, &pair) != NULL)
|
||||
goto out;
|
||||
|
||||
re = g_new0 (RegisteredError, 1);
|
||||
re->pair = pair;
|
||||
re->dbus_error_name = g_strdup (dbus_error_name);
|
||||
|
||||
g_hash_table_insert (quark_code_pair_to_re, &(re->pair), re);
|
||||
g_hash_table_insert (dbus_error_name_to_re, re->dbus_error_name, re);
|
||||
|
||||
ret = TRUE;
|
||||
|
||||
out:
|
||||
G_UNLOCK (error_lock);
|
||||
return ret;
|
||||
}
|
||||
|
||||
/**
|
||||
* g_dbus_error_unregister_error:
|
||||
* @error_domain: A #GQuark for a error domain.
|
||||
* @error_code: An error code.
|
||||
* @dbus_error_name: A D-Bus error name.
|
||||
*
|
||||
* Destroys an association previously set up with g_dbus_error_register_error().
|
||||
*
|
||||
* Returns: %TRUE if the association was destroyed, %FALSE if it wasn't found.
|
||||
*
|
||||
* Since: 2.26
|
||||
*/
|
||||
gboolean
|
||||
g_dbus_error_unregister_error (GQuark error_domain,
|
||||
gint error_code,
|
||||
const gchar *dbus_error_name)
|
||||
{
|
||||
gboolean ret;
|
||||
RegisteredError *re;
|
||||
guint hash_size;
|
||||
|
||||
g_return_val_if_fail (dbus_error_name != NULL, FALSE);
|
||||
|
||||
ret = FALSE;
|
||||
|
||||
G_LOCK (error_lock);
|
||||
|
||||
if (dbus_error_name_to_re == NULL)
|
||||
{
|
||||
g_assert (quark_code_pair_to_re == NULL); /* check invariant */
|
||||
goto out;
|
||||
}
|
||||
|
||||
re = g_hash_table_lookup (dbus_error_name_to_re, dbus_error_name);
|
||||
if (re == NULL)
|
||||
{
|
||||
QuarkCodePair pair;
|
||||
pair.error_domain = error_domain;
|
||||
pair.error_code = error_code;
|
||||
g_warn_if_fail (g_hash_table_lookup (quark_code_pair_to_re, &pair) == NULL); /* check invariant */
|
||||
goto out;
|
||||
}
|
||||
g_warn_if_fail (g_hash_table_lookup (quark_code_pair_to_re, &(re->pair)) == re); /* check invariant */
|
||||
|
||||
g_warn_if_fail (g_hash_table_remove (quark_code_pair_to_re, &(re->pair)));
|
||||
g_warn_if_fail (g_hash_table_remove (dbus_error_name_to_re, re));
|
||||
|
||||
/* destroy hashes if empty */
|
||||
hash_size = g_hash_table_size (dbus_error_name_to_re);
|
||||
if (hash_size == 0)
|
||||
{
|
||||
g_warn_if_fail (g_hash_table_size (quark_code_pair_to_re) == 0); /* check invariant */
|
||||
|
||||
g_hash_table_unref (dbus_error_name_to_re);
|
||||
dbus_error_name_to_re = NULL;
|
||||
g_hash_table_unref (quark_code_pair_to_re);
|
||||
quark_code_pair_to_re = NULL;
|
||||
}
|
||||
else
|
||||
{
|
||||
g_warn_if_fail (g_hash_table_size (quark_code_pair_to_re) == hash_size); /* check invariant */
|
||||
}
|
||||
|
||||
out:
|
||||
G_UNLOCK (error_lock);
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* ---------------------------------------------------------------------------------------------------- */
|
||||
|
||||
/**
|
||||
* g_dbus_error_is_remote_error:
|
||||
* @error: A #GError.
|
||||
*
|
||||
* Checks if @error represents an error received via D-Bus from a remote peer. If so,
|
||||
* use g_dbus_error_get_remote_error() to get the name of the error.
|
||||
*
|
||||
* Returns: %TRUE if @error represents an error from a remote peer,
|
||||
* %FALSE otherwise.
|
||||
*
|
||||
* Since: 2.26
|
||||
*/
|
||||
gboolean
|
||||
g_dbus_error_is_remote_error (const GError *error)
|
||||
{
|
||||
g_return_val_if_fail (error != NULL, FALSE);
|
||||
return g_str_has_prefix (error->message, "GDBus.Error:");
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* g_dbus_error_get_remote_error:
|
||||
* @error: A #GError.
|
||||
*
|
||||
* Gets the D-Bus error name used for @error, if any.
|
||||
*
|
||||
* This function is guaranteed to return a D-Bus error name for all
|
||||
* #GError<!-- -->s returned from functions handling remote method
|
||||
* calls (e.g. g_dbus_connection_call_finish()) unless
|
||||
* g_dbus_error_strip_remote_error() has been used on @error.
|
||||
*
|
||||
* Returns: An allocated string or %NULL if the D-Bus error name could not be found. Free with g_free().
|
||||
*
|
||||
* Since: 2.26
|
||||
*/
|
||||
gchar *
|
||||
g_dbus_error_get_remote_error (const GError *error)
|
||||
{
|
||||
RegisteredError *re;
|
||||
gchar *ret;
|
||||
|
||||
g_return_val_if_fail (error != NULL, NULL);
|
||||
|
||||
/* Ensure that e.g. G_DBUS_ERROR is registered using g_dbus_error_register_error() */
|
||||
_g_dbus_initialize ();
|
||||
|
||||
ret = NULL;
|
||||
|
||||
G_LOCK (error_lock);
|
||||
|
||||
re = NULL;
|
||||
if (quark_code_pair_to_re != NULL)
|
||||
{
|
||||
QuarkCodePair pair;
|
||||
pair.error_domain = error->domain;
|
||||
pair.error_code = error->code;
|
||||
g_assert (dbus_error_name_to_re != NULL); /* check invariant */
|
||||
re = g_hash_table_lookup (quark_code_pair_to_re, &pair);
|
||||
}
|
||||
|
||||
if (re != NULL)
|
||||
{
|
||||
ret = g_strdup (re->dbus_error_name);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (g_str_has_prefix (error->message, "GDBus.Error:"))
|
||||
{
|
||||
const gchar *begin;
|
||||
const gchar *end;
|
||||
begin = error->message + sizeof ("GDBus.Error:") -1;
|
||||
end = strstr (begin, ":");
|
||||
if (end != NULL && end[1] == ' ')
|
||||
{
|
||||
ret = g_strndup (begin, end - begin);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
G_UNLOCK (error_lock);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* ---------------------------------------------------------------------------------------------------- */
|
||||
|
||||
/**
|
||||
* g_dbus_error_new_for_dbus_error:
|
||||
* @dbus_error_name: D-Bus error name.
|
||||
* @dbus_error_message: D-Bus error message.
|
||||
*
|
||||
* Creates a #GError based on the contents of @dbus_error_name and
|
||||
* @dbus_error_message.
|
||||
*
|
||||
* Errors registered with g_dbus_error_register_error() will be looked
|
||||
* up using @dbus_error_name and if a match is found, the error domain
|
||||
* and code is used. Applications can use g_dbus_error_get_remote_error()
|
||||
* to recover @dbus_error_name.
|
||||
*
|
||||
* If a match against a registered error is not found and the D-Bus
|
||||
* error name is in a form as returned by g_dbus_error_encode_gerror()
|
||||
* the error domain and code encoded in the name is used to
|
||||
* create the #GError. Also, @dbus_error_name is added to the error message
|
||||
* such that it can be recovered with g_dbus_error_get_remote_error().
|
||||
*
|
||||
* Otherwise, a #GError with the error code %G_IO_ERROR_DBUS_ERROR
|
||||
* in the #G_IO_ERROR error domain is returned. Also, @dbus_error_name is
|
||||
* added to the error message such that it can be recovered with
|
||||
* g_dbus_error_get_remote_error().
|
||||
*
|
||||
* In all three cases, @dbus_error_name can always be recovered from the
|
||||
* returned #GError using the g_dbus_error_get_remote_error() function
|
||||
* (unless g_dbus_error_strip_remote_error() hasn't been used on the returned error).
|
||||
*
|
||||
* This function is typically only used in object mappings to prepare
|
||||
* #GError instances for applications. Regular applications should not use
|
||||
* it.
|
||||
*
|
||||
* Returns: An allocated #GError. Free with g_error_free().
|
||||
*
|
||||
* Since: 2.26
|
||||
*/
|
||||
GError *
|
||||
g_dbus_error_new_for_dbus_error (const gchar *dbus_error_name,
|
||||
const gchar *dbus_error_message)
|
||||
{
|
||||
GError *error;
|
||||
RegisteredError *re;
|
||||
|
||||
g_return_val_if_fail (dbus_error_name != NULL, NULL);
|
||||
g_return_val_if_fail (dbus_error_message != NULL, NULL);
|
||||
|
||||
/* Ensure that e.g. G_DBUS_ERROR is registered using g_dbus_error_register_error() */
|
||||
_g_dbus_initialize ();
|
||||
|
||||
G_LOCK (error_lock);
|
||||
|
||||
re = NULL;
|
||||
if (dbus_error_name_to_re != NULL)
|
||||
{
|
||||
g_assert (quark_code_pair_to_re != NULL); /* check invariant */
|
||||
re = g_hash_table_lookup (dbus_error_name_to_re, dbus_error_name);
|
||||
}
|
||||
|
||||
if (re != NULL)
|
||||
{
|
||||
error = g_error_new (re->pair.error_domain,
|
||||
re->pair.error_code,
|
||||
"GDBus.Error:%s: %s",
|
||||
dbus_error_name,
|
||||
dbus_error_message);
|
||||
}
|
||||
else
|
||||
{
|
||||
GQuark error_domain = 0;
|
||||
gint error_code = 0;
|
||||
|
||||
if (_g_dbus_error_decode_gerror (dbus_error_name,
|
||||
&error_domain,
|
||||
&error_code))
|
||||
{
|
||||
error = g_error_new (error_domain,
|
||||
error_code,
|
||||
"GDBus.Error:%s: %s",
|
||||
dbus_error_name,
|
||||
dbus_error_message);
|
||||
}
|
||||
else
|
||||
{
|
||||
error = g_error_new (G_IO_ERROR,
|
||||
G_IO_ERROR_DBUS_ERROR,
|
||||
"GDBus.Error:%s: %s",
|
||||
dbus_error_name,
|
||||
dbus_error_message);
|
||||
}
|
||||
}
|
||||
|
||||
G_UNLOCK (error_lock);
|
||||
return error;
|
||||
}
|
||||
|
||||
/**
|
||||
* g_dbus_error_set_dbus_error:
|
||||
* @error: A pointer to a #GError or %NULL.
|
||||
* @dbus_error_name: D-Bus error name.
|
||||
* @dbus_error_message: D-Bus error message.
|
||||
* @format: printf()-style format to prepend to @dbus_error_message or %NULL.
|
||||
* @...: Arguments for @format.
|
||||
*
|
||||
* Does nothing if @error is %NULL. Otherwise sets *@error to
|
||||
* a new #GError created with g_dbus_error_new_for_dbus_error()
|
||||
* with @dbus_error_message prepend with @format (unless %NULL).
|
||||
*
|
||||
* Since: 2.26
|
||||
*/
|
||||
void
|
||||
g_dbus_error_set_dbus_error (GError **error,
|
||||
const gchar *dbus_error_name,
|
||||
const gchar *dbus_error_message,
|
||||
const gchar *format,
|
||||
...)
|
||||
{
|
||||
g_return_if_fail (error == NULL || *error == NULL);
|
||||
g_return_if_fail (dbus_error_name != NULL);
|
||||
g_return_if_fail (dbus_error_message != NULL);
|
||||
|
||||
if (error == NULL)
|
||||
return;
|
||||
|
||||
if (format == NULL)
|
||||
{
|
||||
*error = g_dbus_error_new_for_dbus_error (dbus_error_name, dbus_error_message);
|
||||
}
|
||||
else
|
||||
{
|
||||
va_list var_args;
|
||||
va_start (var_args, format);
|
||||
g_dbus_error_set_dbus_error_valist (error,
|
||||
dbus_error_name,
|
||||
dbus_error_message,
|
||||
format,
|
||||
var_args);
|
||||
va_end (var_args);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* g_dbus_error_set_dbus_error_valist:
|
||||
* @error: A pointer to a #GError or %NULL.
|
||||
* @dbus_error_name: D-Bus error name.
|
||||
* @dbus_error_message: D-Bus error message.
|
||||
* @format: printf()-style format to prepend to @dbus_error_message or %NULL.
|
||||
* @var_args: Arguments for @format.
|
||||
*
|
||||
* Like g_dbus_error_set_dbus_error() but intended for language bindings.
|
||||
*
|
||||
* Since: 2.26
|
||||
*/
|
||||
void
|
||||
g_dbus_error_set_dbus_error_valist (GError **error,
|
||||
const gchar *dbus_error_name,
|
||||
const gchar *dbus_error_message,
|
||||
const gchar *format,
|
||||
va_list var_args)
|
||||
{
|
||||
g_return_if_fail (error == NULL || *error == NULL);
|
||||
g_return_if_fail (dbus_error_name != NULL);
|
||||
g_return_if_fail (dbus_error_message != NULL);
|
||||
|
||||
if (error == NULL)
|
||||
return;
|
||||
|
||||
if (format != NULL)
|
||||
{
|
||||
gchar *message;
|
||||
gchar *s;
|
||||
message = g_strdup_vprintf (format, var_args);
|
||||
s = g_strdup_printf ("%s: %s", message, dbus_error_message);
|
||||
*error = g_dbus_error_new_for_dbus_error (dbus_error_name, s);
|
||||
g_free (s);
|
||||
g_free (message);
|
||||
}
|
||||
else
|
||||
{
|
||||
*error = g_dbus_error_new_for_dbus_error (dbus_error_name, dbus_error_message);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* g_dbus_error_strip_remote_error:
|
||||
* @error: A #GError.
|
||||
*
|
||||
* Looks for extra information in the error message used to recover
|
||||
* the D-Bus error name and strips it if found. If stripped, the
|
||||
* message field in @error will correspond exactly to what was
|
||||
* received on the wire.
|
||||
*
|
||||
* This is typically used when presenting errors to the end user.
|
||||
*
|
||||
* Returns: %TRUE if information was stripped, %FALSE otherwise.
|
||||
*
|
||||
* Since: 2.26
|
||||
*/
|
||||
gboolean
|
||||
g_dbus_error_strip_remote_error (GError *error)
|
||||
{
|
||||
gboolean ret;
|
||||
|
||||
g_return_val_if_fail (error != NULL, FALSE);
|
||||
|
||||
ret = FALSE;
|
||||
|
||||
if (g_str_has_prefix (error->message, "GDBus.Error:"))
|
||||
{
|
||||
const gchar *begin;
|
||||
const gchar *end;
|
||||
gchar *new_message;
|
||||
|
||||
begin = error->message + sizeof ("GDBus.Error:") -1;
|
||||
end = strstr (begin, ":");
|
||||
if (end != NULL && end[1] == ' ')
|
||||
{
|
||||
new_message = g_strdup (end + 2);
|
||||
g_free (error->message);
|
||||
error->message = new_message;
|
||||
ret = TRUE;
|
||||
}
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/**
|
||||
* g_dbus_error_encode_gerror:
|
||||
* @error: A #GError.
|
||||
*
|
||||
* Creates a D-Bus error name to use for @error. If @error matches
|
||||
* a registered error (cf. g_dbus_error_register_error()), the corresponding
|
||||
* D-Bus error name will be returned.
|
||||
*
|
||||
* Otherwise the a name of the form
|
||||
* <literal>org.gtk.GDBus.UnmappedGError.Quark._ESCAPED_QUARK_NAME.Code_ERROR_CODE</literal>
|
||||
* will be used. This allows other GDBus applications to map the error
|
||||
* on the wire back to a #GError using g_dbus_error_new_for_dbus_error().
|
||||
*
|
||||
* This function is typically only used in object mappings to put a
|
||||
* #GError on the wire. Regular applications should not use it.
|
||||
*
|
||||
* Returns: A D-Bus error name (never %NULL). Free with g_free().
|
||||
*
|
||||
* Since: 2.26
|
||||
*/
|
||||
gchar *
|
||||
g_dbus_error_encode_gerror (const GError *error)
|
||||
{
|
||||
RegisteredError *re;
|
||||
gchar *error_name;
|
||||
|
||||
g_return_val_if_fail (error != NULL, NULL);
|
||||
|
||||
/* Ensure that e.g. G_DBUS_ERROR is registered using g_dbus_error_register_error() */
|
||||
_g_dbus_initialize ();
|
||||
|
||||
error_name = NULL;
|
||||
|
||||
G_LOCK (error_lock);
|
||||
re = NULL;
|
||||
if (quark_code_pair_to_re != NULL)
|
||||
{
|
||||
QuarkCodePair pair;
|
||||
pair.error_domain = error->domain;
|
||||
pair.error_code = error->code;
|
||||
g_assert (dbus_error_name_to_re != NULL); /* check invariant */
|
||||
re = g_hash_table_lookup (quark_code_pair_to_re, &pair);
|
||||
}
|
||||
if (re != NULL)
|
||||
{
|
||||
error_name = g_strdup (re->dbus_error_name);
|
||||
G_UNLOCK (error_lock);
|
||||
}
|
||||
else
|
||||
{
|
||||
const gchar *domain_as_string;
|
||||
GString *s;
|
||||
guint n;
|
||||
|
||||
G_UNLOCK (error_lock);
|
||||
|
||||
/* We can't make a lot of assumptions about what domain_as_string
|
||||
* looks like and D-Bus is extremely picky about error names so
|
||||
* hex-encode it for transport across the wire.
|
||||
*/
|
||||
domain_as_string = g_quark_to_string (error->domain);
|
||||
s = g_string_new ("org.gtk.GDBus.UnmappedGError.Quark._");
|
||||
for (n = 0; domain_as_string[n] != 0; n++)
|
||||
{
|
||||
gint c = domain_as_string[n];
|
||||
if (g_ascii_isalnum (c))
|
||||
{
|
||||
g_string_append_c (s, c);
|
||||
}
|
||||
else
|
||||
{
|
||||
guint nibble_top;
|
||||
guint nibble_bottom;
|
||||
g_string_append_c (s, '_');
|
||||
nibble_top = ((int) domain_as_string[n]) >> 4;
|
||||
nibble_bottom = ((int) domain_as_string[n]) & 0x0f;
|
||||
if (nibble_top < 10)
|
||||
nibble_top += '0';
|
||||
else
|
||||
nibble_top += 'a' - 10;
|
||||
if (nibble_bottom < 10)
|
||||
nibble_bottom += '0';
|
||||
else
|
||||
nibble_bottom += 'a' - 10;
|
||||
g_string_append_c (s, nibble_top);
|
||||
g_string_append_c (s, nibble_bottom);
|
||||
}
|
||||
}
|
||||
g_string_append_printf (s, ".Code%d", error->code);
|
||||
error_name = g_string_free (s, FALSE);
|
||||
}
|
||||
|
||||
return error_name;
|
||||
}
|
||||
|
||||
#define __G_DBUS_ERROR_C__
|
||||
#include "gioaliasdef.c"
|
96
gio/gdbuserror.h
Normal file
96
gio/gdbuserror.h
Normal file
@ -0,0 +1,96 @@
|
||||
/* GDBus - GLib D-Bus Library
|
||||
*
|
||||
* Copyright (C) 2008-2010 Red Hat, Inc.
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General
|
||||
* Public License along with this library; if not, write to the
|
||||
* Free Software Foundation, Inc., 59 Temple Place, Suite 330,
|
||||
* Boston, MA 02111-1307, USA.
|
||||
*
|
||||
* Author: David Zeuthen <davidz@redhat.com>
|
||||
*/
|
||||
|
||||
#ifndef __G_DBUS_ERROR_H__
|
||||
#define __G_DBUS_ERROR_H__
|
||||
|
||||
#include <gio/giotypes.h>
|
||||
|
||||
G_BEGIN_DECLS
|
||||
|
||||
/**
|
||||
* G_DBUS_ERROR:
|
||||
*
|
||||
* Error domain for errors generated by a remote message bus. Errors
|
||||
* in this domain will be from the #GDBusError enumeration. See
|
||||
* #GError for more information on error domains.
|
||||
*
|
||||
* Note that errors in this error domain is intended only for
|
||||
* returning errors from a remote message bus process. Errors
|
||||
* generated locally in-process by e.g. #GDBusConnection is from the
|
||||
* %G_IO_ERROR domain.
|
||||
*
|
||||
* Since: 2.26
|
||||
*/
|
||||
#define G_DBUS_ERROR g_dbus_error_quark()
|
||||
|
||||
GQuark g_dbus_error_quark (void);
|
||||
|
||||
/* Used by applications to check, get and strip the D-Bus error name */
|
||||
gboolean g_dbus_error_is_remote_error (const GError *error);
|
||||
gchar *g_dbus_error_get_remote_error (const GError *error);
|
||||
gboolean g_dbus_error_strip_remote_error (GError *error);
|
||||
|
||||
/**
|
||||
* GDBusErrorEntry:
|
||||
* @error_code: An error code.
|
||||
* @dbus_error_name: The D-Bus error name to associate with @error_code.
|
||||
*
|
||||
* Struct used in g_dbus_error_register_error_domain().
|
||||
*
|
||||
* Since: 2.26
|
||||
*/
|
||||
struct _GDBusErrorEntry
|
||||
{
|
||||
gint error_code;
|
||||
const gchar *dbus_error_name;
|
||||
};
|
||||
|
||||
gboolean g_dbus_error_register_error (GQuark error_domain,
|
||||
gint error_code,
|
||||
const gchar *dbus_error_name);
|
||||
gboolean g_dbus_error_unregister_error (GQuark error_domain,
|
||||
gint error_code,
|
||||
const gchar *dbus_error_name);
|
||||
void g_dbus_error_register_error_domain (const gchar *error_domain_quark_name,
|
||||
volatile gsize *quark_volatile,
|
||||
const GDBusErrorEntry *entries,
|
||||
guint num_entries);
|
||||
|
||||
/* Only used by object mappings to map back and forth to GError */
|
||||
GError *g_dbus_error_new_for_dbus_error (const gchar *dbus_error_name,
|
||||
const gchar *dbus_error_message);
|
||||
void g_dbus_error_set_dbus_error (GError **error,
|
||||
const gchar *dbus_error_name,
|
||||
const gchar *dbus_error_message,
|
||||
const gchar *format,
|
||||
...);
|
||||
void g_dbus_error_set_dbus_error_valist (GError **error,
|
||||
const gchar *dbus_error_name,
|
||||
const gchar *dbus_error_message,
|
||||
const gchar *format,
|
||||
va_list var_args);
|
||||
gchar *g_dbus_error_encode_gerror (const GError *error);
|
||||
|
||||
G_END_DECLS
|
||||
|
||||
#endif /* __G_DBUS_ERROR_H__ */
|
2079
gio/gdbusintrospection.c
Normal file
2079
gio/gdbusintrospection.c
Normal file
File diff suppressed because it is too large
Load Diff
283
gio/gdbusintrospection.h
Normal file
283
gio/gdbusintrospection.h
Normal file
@ -0,0 +1,283 @@
|
||||
/* GDBus - GLib D-Bus Library
|
||||
*
|
||||
* Copyright (C) 2008-2010 Red Hat, Inc.
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General
|
||||
* Public License along with this library; if not, write to the
|
||||
* Free Software Foundation, Inc., 59 Temple Place, Suite 330,
|
||||
* Boston, MA 02111-1307, USA.
|
||||
*
|
||||
* Author: David Zeuthen <davidz@redhat.com>
|
||||
*/
|
||||
|
||||
#ifndef __G_DBUS_INTROSPECTION_H__
|
||||
#define __G_DBUS_INTROSPECTION_H__
|
||||
|
||||
#include <gio/giotypes.h>
|
||||
|
||||
G_BEGIN_DECLS
|
||||
|
||||
/**
|
||||
* GDBusAnnotationInfo:
|
||||
* @ref_count: The reference count or -1 if statically allocated.
|
||||
* @key: The name of the annotation, e.g. "org.freedesktop.DBus.Deprecated".
|
||||
* @value: The value of the annotation.
|
||||
* @annotations: A pointer to a %NULL-terminated array of pointers to #GDBusAnnotationInfo structures or %NULL if there are no annotations.
|
||||
*
|
||||
* Information about an annotation.
|
||||
*
|
||||
* Since: 2.26
|
||||
*/
|
||||
struct _GDBusAnnotationInfo
|
||||
{
|
||||
volatile gint ref_count;
|
||||
gchar *key;
|
||||
gchar *value;
|
||||
GDBusAnnotationInfo **annotations;
|
||||
};
|
||||
|
||||
/**
|
||||
* GDBusArgInfo:
|
||||
* @ref_count: The reference count or -1 if statically allocated.
|
||||
* @name: Name of the argument, e.g. @unix_user_id.
|
||||
* @signature: D-Bus signature of the argument (a single complete type).
|
||||
* @annotations: A pointer to a %NULL-terminated array of pointers to #GDBusAnnotationInfo structures or %NULL if there are no annotations.
|
||||
*
|
||||
* Information about an argument for a method or a signal.
|
||||
*
|
||||
* Since: 2.26
|
||||
*/
|
||||
struct _GDBusArgInfo
|
||||
{
|
||||
volatile gint ref_count;
|
||||
gchar *name;
|
||||
gchar *signature;
|
||||
GDBusAnnotationInfo **annotations;
|
||||
};
|
||||
|
||||
/**
|
||||
* GDBusMethodInfo:
|
||||
* @ref_count: The reference count or -1 if statically allocated.
|
||||
* @name: The name of the D-Bus method, e.g. @RequestName.
|
||||
* @in_args: A pointer to a %NULL-terminated array of pointers to #GDBusArgInfo structures or %NULL if there are no in arguments.
|
||||
* @out_args: A pointer to a %NULL-terminated array of pointers to #GDBusArgInfo structures or %NULL if there are no out arguments.
|
||||
* @annotations: A pointer to a %NULL-terminated array of pointers to #GDBusAnnotationInfo structures or %NULL if there are no annotations.
|
||||
*
|
||||
* Information about a method on an D-Bus interface.
|
||||
*
|
||||
* Since: 2.26
|
||||
*/
|
||||
struct _GDBusMethodInfo
|
||||
{
|
||||
volatile gint ref_count;
|
||||
gchar *name;
|
||||
GDBusArgInfo **in_args;
|
||||
GDBusArgInfo **out_args;
|
||||
GDBusAnnotationInfo **annotations;
|
||||
};
|
||||
|
||||
/**
|
||||
* GDBusSignalInfo:
|
||||
* @ref_count: The reference count or -1 if statically allocated.
|
||||
* @name: The name of the D-Bus signal, e.g. "NameOwnerChanged".
|
||||
* @args: A pointer to a %NULL-terminated array of pointers to #GDBusArgInfo structures or %NULL if there are no arguments.
|
||||
* @annotations: A pointer to a %NULL-terminated array of pointers to #GDBusAnnotationInfo structures or %NULL if there are no annotations.
|
||||
*
|
||||
* Information about a signal on a D-Bus interface.
|
||||
*
|
||||
* Since: 2.26
|
||||
*/
|
||||
struct _GDBusSignalInfo
|
||||
{
|
||||
volatile gint ref_count;
|
||||
gchar *name;
|
||||
GDBusArgInfo **args;
|
||||
GDBusAnnotationInfo **annotations;
|
||||
};
|
||||
|
||||
/**
|
||||
* GDBusPropertyInfo:
|
||||
* @ref_count: The reference count or -1 if statically allocated.
|
||||
* @name: The name of the D-Bus property, e.g. "SupportedFilesystems".
|
||||
* @signature: The D-Bus signature of the property (a single complete type).
|
||||
* @flags: Access control flags for the property.
|
||||
* @annotations: A pointer to a %NULL-terminated array of pointers to #GDBusAnnotationInfo structures or %NULL if there are no annotations.
|
||||
*
|
||||
* Information about a D-Bus property on a D-Bus interface.
|
||||
*
|
||||
* Since: 2.26
|
||||
*/
|
||||
struct _GDBusPropertyInfo
|
||||
{
|
||||
volatile gint ref_count;
|
||||
gchar *name;
|
||||
gchar *signature;
|
||||
GDBusPropertyInfoFlags flags;
|
||||
GDBusAnnotationInfo **annotations;
|
||||
};
|
||||
|
||||
/**
|
||||
* GDBusInterfaceInfo:
|
||||
* @ref_count: The reference count or -1 if statically allocated.
|
||||
* @name: The name of the D-Bus interface, e.g. "org.freedesktop.DBus.Properties".
|
||||
* @methods: A pointer to a %NULL-terminated array of pointers to #GDBusMethodInfo structures or %NULL if there are no methods.
|
||||
* @signals: A pointer to a %NULL-terminated array of pointers to #GDBusSignalInfo structures or %NULL if there are no signals.
|
||||
* @properties: A pointer to a %NULL-terminated array of pointers to #GDBusPropertyInfo structures or %NULL if there are no properties.
|
||||
* @annotations: A pointer to a %NULL-terminated array of pointers to #GDBusAnnotationInfo structures or %NULL if there are no annotations.
|
||||
*
|
||||
* Information about a D-Bus interface.
|
||||
*
|
||||
* Since: 2.26
|
||||
*/
|
||||
struct _GDBusInterfaceInfo
|
||||
{
|
||||
volatile gint ref_count;
|
||||
gchar *name;
|
||||
GDBusMethodInfo **methods;
|
||||
GDBusSignalInfo **signals;
|
||||
GDBusPropertyInfo **properties;
|
||||
GDBusAnnotationInfo **annotations;
|
||||
};
|
||||
|
||||
/**
|
||||
* GDBusNodeInfo:
|
||||
* @ref_count: The reference count or -1 if statically allocated.
|
||||
* @path: The path of the node or %NULL if omitted. Note that this may be a relative path. See the D-Bus specification for more details.
|
||||
* @interfaces: A pointer to a %NULL-terminated array of pointers to #GDBusInterfaceInfo structures or %NULL if there are no interfaces.
|
||||
* @nodes: A pointer to a %NULL-terminated array of pointers to #GDBusNodeInfo structures or %NULL if there are no nodes.
|
||||
* @annotations: A pointer to a %NULL-terminated array of pointers to #GDBusAnnotationInfo structures or %NULL if there are no annotations.
|
||||
*
|
||||
* Information about nodes in a remote object hierarchy.
|
||||
*
|
||||
* Since: 2.26
|
||||
*/
|
||||
struct _GDBusNodeInfo
|
||||
{
|
||||
volatile gint ref_count;
|
||||
gchar *path;
|
||||
GDBusInterfaceInfo **interfaces;
|
||||
GDBusNodeInfo **nodes;
|
||||
GDBusAnnotationInfo **annotations;
|
||||
};
|
||||
|
||||
const gchar *g_dbus_annotation_info_lookup (const GDBusAnnotationInfo **annotations,
|
||||
const gchar *name);
|
||||
const GDBusMethodInfo *g_dbus_interface_info_lookup_method (const GDBusInterfaceInfo *info,
|
||||
const gchar *name);
|
||||
const GDBusSignalInfo *g_dbus_interface_info_lookup_signal (const GDBusInterfaceInfo *info,
|
||||
const gchar *name);
|
||||
const GDBusPropertyInfo *g_dbus_interface_info_lookup_property (const GDBusInterfaceInfo *info,
|
||||
const gchar *name);
|
||||
void g_dbus_interface_info_generate_xml (const GDBusInterfaceInfo *info,
|
||||
guint indent,
|
||||
GString *string_builder);
|
||||
|
||||
GDBusNodeInfo *g_dbus_node_info_new_for_xml (const gchar *xml_data,
|
||||
GError **error);
|
||||
const GDBusInterfaceInfo *g_dbus_node_info_lookup_interface (const GDBusNodeInfo *info,
|
||||
const gchar *name);
|
||||
void g_dbus_node_info_generate_xml (const GDBusNodeInfo *info,
|
||||
guint indent,
|
||||
GString *string_builder);
|
||||
|
||||
GDBusNodeInfo *g_dbus_node_info_ref (GDBusNodeInfo *info);
|
||||
GDBusInterfaceInfo *g_dbus_interface_info_ref (GDBusInterfaceInfo *info);
|
||||
GDBusMethodInfo *g_dbus_method_info_ref (GDBusMethodInfo *info);
|
||||
GDBusSignalInfo *g_dbus_signal_info_ref (GDBusSignalInfo *info);
|
||||
GDBusPropertyInfo *g_dbus_property_info_ref (GDBusPropertyInfo *info);
|
||||
GDBusArgInfo *g_dbus_arg_info_ref (GDBusArgInfo *info);
|
||||
GDBusAnnotationInfo *g_dbus_annotation_info_ref (GDBusAnnotationInfo *info);
|
||||
|
||||
void g_dbus_node_info_unref (GDBusNodeInfo *info);
|
||||
void g_dbus_interface_info_unref (GDBusInterfaceInfo *info);
|
||||
void g_dbus_method_info_unref (GDBusMethodInfo *info);
|
||||
void g_dbus_signal_info_unref (GDBusSignalInfo *info);
|
||||
void g_dbus_property_info_unref (GDBusPropertyInfo *info);
|
||||
void g_dbus_arg_info_unref (GDBusArgInfo *info);
|
||||
void g_dbus_annotation_info_unref (GDBusAnnotationInfo *info);
|
||||
|
||||
|
||||
/**
|
||||
* G_TYPE_DBUS_NODE_INFO:
|
||||
*
|
||||
* The #GType for a boxed type holding a #GDBusNodeInfo.
|
||||
*
|
||||
* Since: 2.26
|
||||
*/
|
||||
#define G_TYPE_DBUS_NODE_INFO (g_dbus_node_info_get_type ())
|
||||
|
||||
/**
|
||||
* G_TYPE_DBUS_INTERFACE_INFO:
|
||||
*
|
||||
* The #GType for a boxed type holding a #GDBusInterfaceInfo.
|
||||
*
|
||||
* Since: 2.26
|
||||
*/
|
||||
#define G_TYPE_DBUS_INTERFACE_INFO (g_dbus_interface_info_get_type ())
|
||||
|
||||
/**
|
||||
* G_TYPE_DBUS_METHOD_INFO:
|
||||
*
|
||||
* The #GType for a boxed type holding a #GDBusMethodInfo.
|
||||
*
|
||||
* Since: 2.26
|
||||
*/
|
||||
#define G_TYPE_DBUS_METHOD_INFO (g_dbus_method_info_get_type ())
|
||||
|
||||
/**
|
||||
* G_TYPE_DBUS_SIGNAL_INFO:
|
||||
*
|
||||
* The #GType for a boxed type holding a #GDBusSignalInfo.
|
||||
*
|
||||
* Since: 2.26
|
||||
*/
|
||||
#define G_TYPE_DBUS_SIGNAL_INFO (g_dbus_signal_info_get_type ())
|
||||
|
||||
/**
|
||||
* G_TYPE_DBUS_PROPERTY_INFO:
|
||||
*
|
||||
* The #GType for a boxed type holding a #GDBusPropertyInfo.
|
||||
*
|
||||
* Since: 2.26
|
||||
*/
|
||||
#define G_TYPE_DBUS_PROPERTY_INFO (g_dbus_property_info_get_type ())
|
||||
|
||||
/**
|
||||
* G_TYPE_DBUS_ARG_INFO:
|
||||
*
|
||||
* The #GType for a boxed type holding a #GDBusArgInfo.
|
||||
*
|
||||
* Since: 2.26
|
||||
*/
|
||||
#define G_TYPE_DBUS_ARG_INFO (g_dbus_arg_info_get_type ())
|
||||
|
||||
/**
|
||||
* G_TYPE_DBUS_ANNOTATION_INFO:
|
||||
*
|
||||
* The #GType for a boxed type holding a #GDBusAnnotationInfo.
|
||||
*
|
||||
* Since: 2.26
|
||||
*/
|
||||
#define G_TYPE_DBUS_ANNOTATION_INFO (g_dbus_annotation_info_get_type ())
|
||||
|
||||
GType g_dbus_node_info_get_type (void) G_GNUC_CONST;
|
||||
GType g_dbus_interface_info_get_type (void) G_GNUC_CONST;
|
||||
GType g_dbus_method_info_get_type (void) G_GNUC_CONST;
|
||||
GType g_dbus_signal_info_get_type (void) G_GNUC_CONST;
|
||||
GType g_dbus_property_info_get_type (void) G_GNUC_CONST;
|
||||
GType g_dbus_arg_info_get_type (void) G_GNUC_CONST;
|
||||
GType g_dbus_annotation_info_get_type (void) G_GNUC_CONST;
|
||||
|
||||
G_END_DECLS
|
||||
|
||||
#endif /* __G_DBUS_INTROSPECTION_H__ */
|
2522
gio/gdbusmessage.c
Normal file
2522
gio/gdbusmessage.c
Normal file
File diff suppressed because it is too large
Load Diff
172
gio/gdbusmessage.h
Normal file
172
gio/gdbusmessage.h
Normal file
@ -0,0 +1,172 @@
|
||||
/* GDBus - GLib D-Bus Library
|
||||
*
|
||||
* Copyright (C) 2008-2010 Red Hat, Inc.
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General
|
||||
* Public License along with this library; if not, write to the
|
||||
* Free Software Foundation, Inc., 59 Temple Place, Suite 330,
|
||||
* Boston, MA 02111-1307, USA.
|
||||
*
|
||||
* Author: David Zeuthen <davidz@redhat.com>
|
||||
*/
|
||||
|
||||
#ifndef __G_DBUS_MESSAGE_H__
|
||||
#define __G_DBUS_MESSAGE_H__
|
||||
|
||||
#include <gio/giotypes.h>
|
||||
|
||||
G_BEGIN_DECLS
|
||||
|
||||
#define G_TYPE_DBUS_MESSAGE (g_dbus_message_get_type ())
|
||||
#define G_DBUS_MESSAGE(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), G_TYPE_DBUS_MESSAGE, GDBusMessage))
|
||||
#define G_DBUS_MESSAGE_CLASS(k) (G_TYPE_CHECK_CLASS_CAST((k), G_TYPE_DBUS_MESSAGE, GDBusMessageClass))
|
||||
#define G_DBUS_MESSAGE_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS ((o), G_TYPE_DBUS_MESSAGE, GDBusMessageClass))
|
||||
#define G_IS_DBUS_MESSAGE(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), G_TYPE_DBUS_MESSAGE))
|
||||
#define G_IS_DBUS_MESSAGE_CLASS(k) (G_TYPE_CHECK_CLASS_TYPE ((k), G_TYPE_DBUS_MESSAGE))
|
||||
|
||||
typedef struct _GDBusMessageClass GDBusMessageClass;
|
||||
typedef struct _GDBusMessagePrivate GDBusMessagePrivate;
|
||||
|
||||
/**
|
||||
* GDBusMessageClass:
|
||||
*
|
||||
* Class structure for #GDBusMessage.
|
||||
*
|
||||
* Since: 2.26
|
||||
*/
|
||||
struct _GDBusMessageClass
|
||||
{
|
||||
/*< private >*/
|
||||
GObjectClass parent_class;
|
||||
};
|
||||
|
||||
/**
|
||||
* GDBusMessage:
|
||||
*
|
||||
* The #GDBusMessage structure contains only private data and should
|
||||
* only be accessed using the provided API.
|
||||
*
|
||||
* Since: 2.26
|
||||
*/
|
||||
struct _GDBusMessage
|
||||
{
|
||||
/*< private >*/
|
||||
GObject parent_instance;
|
||||
GDBusMessagePrivate *priv;
|
||||
};
|
||||
|
||||
GType g_dbus_message_get_type (void) G_GNUC_CONST;
|
||||
GDBusMessage *g_dbus_message_new (void);
|
||||
GDBusMessage *g_dbus_message_new_signal (const gchar *path,
|
||||
const gchar *interface,
|
||||
const gchar *signal);
|
||||
GDBusMessage *g_dbus_message_new_method_call (const gchar *name,
|
||||
const gchar *path,
|
||||
const gchar *interface,
|
||||
const gchar *method);
|
||||
GDBusMessage *g_dbus_message_new_method_reply (GDBusMessage *method_call_message);
|
||||
GDBusMessage *g_dbus_message_new_method_error (GDBusMessage *method_call_message,
|
||||
const gchar *error_name,
|
||||
const gchar *error_message_format,
|
||||
...);
|
||||
GDBusMessage *g_dbus_message_new_method_error_valist (GDBusMessage *method_call_message,
|
||||
const gchar *error_name,
|
||||
const gchar *error_message_format,
|
||||
va_list var_args);
|
||||
GDBusMessage *g_dbus_message_new_method_error_literal (GDBusMessage *method_call_message,
|
||||
const gchar *error_name,
|
||||
const gchar *error_message);
|
||||
gchar *g_dbus_message_print (GDBusMessage *message,
|
||||
guint indent);
|
||||
|
||||
GDBusMessageType g_dbus_message_get_message_type (GDBusMessage *message);
|
||||
void g_dbus_message_set_message_type (GDBusMessage *message,
|
||||
GDBusMessageType type);
|
||||
GDBusMessageFlags g_dbus_message_get_flags (GDBusMessage *message);
|
||||
void g_dbus_message_set_flags (GDBusMessage *message,
|
||||
GDBusMessageFlags flags);
|
||||
guint32 g_dbus_message_get_serial (GDBusMessage *message);
|
||||
void g_dbus_message_set_serial (GDBusMessage *message,
|
||||
guint32 serial);
|
||||
GVariant *g_dbus_message_get_header (GDBusMessage *message,
|
||||
GDBusMessageHeaderField header_field);
|
||||
void g_dbus_message_set_header (GDBusMessage *message,
|
||||
GDBusMessageHeaderField header_field,
|
||||
GVariant *value);
|
||||
guchar *g_dbus_message_get_header_fields (GDBusMessage *message);
|
||||
GVariant *g_dbus_message_get_body (GDBusMessage *message);
|
||||
void g_dbus_message_set_body (GDBusMessage *message,
|
||||
GVariant *body);
|
||||
GUnixFDList *g_dbus_message_get_unix_fd_list (GDBusMessage *message);
|
||||
void g_dbus_message_set_unix_fd_list (GDBusMessage *message,
|
||||
GUnixFDList *fd_list);
|
||||
|
||||
guint32 g_dbus_message_get_reply_serial (GDBusMessage *message);
|
||||
void g_dbus_message_set_reply_serial (GDBusMessage *message,
|
||||
guint32 value);
|
||||
|
||||
const gchar *g_dbus_message_get_interface (GDBusMessage *message);
|
||||
void g_dbus_message_set_interface (GDBusMessage *message,
|
||||
const gchar *value);
|
||||
|
||||
const gchar *g_dbus_message_get_member (GDBusMessage *message);
|
||||
void g_dbus_message_set_member (GDBusMessage *message,
|
||||
const gchar *value);
|
||||
|
||||
const gchar *g_dbus_message_get_path (GDBusMessage *message);
|
||||
void g_dbus_message_set_path (GDBusMessage *message,
|
||||
const gchar *value);
|
||||
|
||||
const gchar *g_dbus_message_get_sender (GDBusMessage *message);
|
||||
void g_dbus_message_set_sender (GDBusMessage *message,
|
||||
const gchar *value);
|
||||
|
||||
const gchar *g_dbus_message_get_destination (GDBusMessage *message);
|
||||
void g_dbus_message_set_destination (GDBusMessage *message,
|
||||
const gchar *value);
|
||||
|
||||
const gchar *g_dbus_message_get_error_name (GDBusMessage *message);
|
||||
void g_dbus_message_set_error_name (GDBusMessage *message,
|
||||
const gchar *value);
|
||||
|
||||
const gchar *g_dbus_message_get_signature (GDBusMessage *message);
|
||||
void g_dbus_message_set_signature (GDBusMessage *message,
|
||||
const gchar *value);
|
||||
|
||||
guint32 g_dbus_message_get_num_unix_fds (GDBusMessage *message);
|
||||
void g_dbus_message_set_num_unix_fds (GDBusMessage *message,
|
||||
guint32 value);
|
||||
|
||||
const gchar *g_dbus_message_get_arg0 (GDBusMessage *message);
|
||||
|
||||
|
||||
GDBusMessage *g_dbus_message_new_from_blob (guchar *blob,
|
||||
gsize blob_len,
|
||||
GDBusCapabilityFlags capabilities,
|
||||
GError **error);
|
||||
|
||||
gssize g_dbus_message_bytes_needed (guchar *blob,
|
||||
gsize blob_len,
|
||||
GError **error);
|
||||
|
||||
guchar *g_dbus_message_to_blob (GDBusMessage *message,
|
||||
gsize *out_size,
|
||||
GDBusCapabilityFlags capabilities,
|
||||
GError **error);
|
||||
|
||||
gboolean g_dbus_message_to_gerror (GDBusMessage *message,
|
||||
GError **error);
|
||||
|
||||
G_END_DECLS
|
||||
|
||||
#endif /* __G_DBUS_MESSAGE_H__ */
|
559
gio/gdbusmethodinvocation.c
Normal file
559
gio/gdbusmethodinvocation.c
Normal file
@ -0,0 +1,559 @@
|
||||
/* GDBus - GLib D-Bus Library
|
||||
*
|
||||
* Copyright (C) 2008-2010 Red Hat, Inc.
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General
|
||||
* Public License along with this library; if not, write to the
|
||||
* Free Software Foundation, Inc., 59 Temple Place, Suite 330,
|
||||
* Boston, MA 02111-1307, USA.
|
||||
*
|
||||
* Author: David Zeuthen <davidz@redhat.com>
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include <stdlib.h>
|
||||
|
||||
#include "gdbusutils.h"
|
||||
#include "gdbusconnection.h"
|
||||
#include "gdbusmessage.h"
|
||||
#include "gdbusmethodinvocation.h"
|
||||
#include "gdbusintrospection.h"
|
||||
#include "gdbuserror.h"
|
||||
#include "gdbusprivate.h"
|
||||
|
||||
#include "glibintl.h"
|
||||
#include "gioalias.h"
|
||||
|
||||
/**
|
||||
* SECTION:gdbusmethodinvocation
|
||||
* @short_description: Object for handling remote calls
|
||||
* @include: gio/gio.h
|
||||
*
|
||||
* Instances of the #GDBusMethodInvocation class are used when
|
||||
* handling D-Bus method calls. It provides a way to asynchronously
|
||||
* return results and errors.
|
||||
*
|
||||
* The normal way to obtain a #GDBusMethodInvocation object is to receive
|
||||
* it as an argument to the handle_method_call() function in a
|
||||
* #GDBusInterfaceVTable that was passed to g_dbus_connection_register_object().
|
||||
*/
|
||||
|
||||
struct _GDBusMethodInvocationPrivate
|
||||
{
|
||||
/* construct-only properties */
|
||||
gchar *sender;
|
||||
gchar *object_path;
|
||||
gchar *interface_name;
|
||||
gchar *method_name;
|
||||
const GDBusMethodInfo *method_info;
|
||||
GDBusConnection *connection;
|
||||
GDBusMessage *message;
|
||||
GVariant *parameters;
|
||||
gpointer user_data;
|
||||
};
|
||||
|
||||
G_DEFINE_TYPE (GDBusMethodInvocation, g_dbus_method_invocation, G_TYPE_OBJECT);
|
||||
|
||||
static void
|
||||
g_dbus_method_invocation_finalize (GObject *object)
|
||||
{
|
||||
GDBusMethodInvocation *invocation = G_DBUS_METHOD_INVOCATION (object);
|
||||
|
||||
g_free (invocation->priv->sender);
|
||||
g_free (invocation->priv->object_path);
|
||||
g_free (invocation->priv->interface_name);
|
||||
g_free (invocation->priv->method_name);
|
||||
g_object_unref (invocation->priv->connection);
|
||||
g_object_unref (invocation->priv->message);
|
||||
g_variant_unref (invocation->priv->parameters);
|
||||
|
||||
G_OBJECT_CLASS (g_dbus_method_invocation_parent_class)->finalize (object);
|
||||
}
|
||||
|
||||
static void
|
||||
g_dbus_method_invocation_class_init (GDBusMethodInvocationClass *klass)
|
||||
{
|
||||
GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
|
||||
|
||||
gobject_class->finalize = g_dbus_method_invocation_finalize;
|
||||
|
||||
g_type_class_add_private (klass, sizeof (GDBusMethodInvocationPrivate));
|
||||
}
|
||||
|
||||
static void
|
||||
g_dbus_method_invocation_init (GDBusMethodInvocation *invocation)
|
||||
{
|
||||
invocation->priv = G_TYPE_INSTANCE_GET_PRIVATE (invocation,
|
||||
G_TYPE_DBUS_METHOD_INVOCATION,
|
||||
GDBusMethodInvocationPrivate);
|
||||
}
|
||||
|
||||
/**
|
||||
* g_dbus_method_invocation_get_sender:
|
||||
* @invocation: A #GDBusMethodInvocation.
|
||||
*
|
||||
* Gets the bus name that invoked the method.
|
||||
*
|
||||
* Returns: A string. Do not free, it is owned by @invocation.
|
||||
*
|
||||
* Since: 2.26
|
||||
*/
|
||||
const gchar *
|
||||
g_dbus_method_invocation_get_sender (GDBusMethodInvocation *invocation)
|
||||
{
|
||||
g_return_val_if_fail (G_IS_DBUS_METHOD_INVOCATION (invocation), NULL);
|
||||
return invocation->priv->sender;
|
||||
}
|
||||
|
||||
/**
|
||||
* g_dbus_method_invocation_get_object_path:
|
||||
* @invocation: A #GDBusMethodInvocation.
|
||||
*
|
||||
* Gets the object path the method was invoked on.
|
||||
*
|
||||
* Returns: A string. Do not free, it is owned by @invocation.
|
||||
*
|
||||
* Since: 2.26
|
||||
*/
|
||||
const gchar *
|
||||
g_dbus_method_invocation_get_object_path (GDBusMethodInvocation *invocation)
|
||||
{
|
||||
g_return_val_if_fail (G_IS_DBUS_METHOD_INVOCATION (invocation), NULL);
|
||||
return invocation->priv->object_path;
|
||||
}
|
||||
|
||||
/**
|
||||
* g_dbus_method_invocation_get_interface_name:
|
||||
* @invocation: A #GDBusMethodInvocation.
|
||||
*
|
||||
* Gets the name of the D-Bus interface the method was invoked on.
|
||||
*
|
||||
* Returns: A string. Do not free, it is owned by @invocation.
|
||||
*
|
||||
* Since: 2.26
|
||||
*/
|
||||
const gchar *
|
||||
g_dbus_method_invocation_get_interface_name (GDBusMethodInvocation *invocation)
|
||||
{
|
||||
g_return_val_if_fail (G_IS_DBUS_METHOD_INVOCATION (invocation), NULL);
|
||||
return invocation->priv->interface_name;
|
||||
}
|
||||
|
||||
/**
|
||||
* g_dbus_method_invocation_get_method_info:
|
||||
* @invocation: A #GDBusMethodInvocation.
|
||||
*
|
||||
* Gets information about the method call, if any.
|
||||
*
|
||||
* Returns: A #GDBusMethodInfo or %NULL. Do not free, it is owned by @invocation.
|
||||
*
|
||||
* Since: 2.26
|
||||
*/
|
||||
const GDBusMethodInfo *
|
||||
g_dbus_method_invocation_get_method_info (GDBusMethodInvocation *invocation)
|
||||
{
|
||||
g_return_val_if_fail (G_IS_DBUS_METHOD_INVOCATION (invocation), NULL);
|
||||
return invocation->priv->method_info;
|
||||
}
|
||||
|
||||
/**
|
||||
* g_dbus_method_invocation_get_method_name:
|
||||
* @invocation: A #GDBusMethodInvocation.
|
||||
*
|
||||
* Gets the name of the method that was invoked.
|
||||
*
|
||||
* Returns: A string. Do not free, it is owned by @invocation.
|
||||
*
|
||||
* Since: 2.26
|
||||
*/
|
||||
const gchar *
|
||||
g_dbus_method_invocation_get_method_name (GDBusMethodInvocation *invocation)
|
||||
{
|
||||
g_return_val_if_fail (G_IS_DBUS_METHOD_INVOCATION (invocation), NULL);
|
||||
return invocation->priv->method_name;
|
||||
}
|
||||
|
||||
/**
|
||||
* g_dbus_method_invocation_get_connection:
|
||||
* @invocation: A #GDBusMethodInvocation.
|
||||
*
|
||||
* Gets the #GDBusConnection the method was invoked on.
|
||||
*
|
||||
* Returns: A #GDBusConnection. Do not free, it is owned by @invocation.
|
||||
*
|
||||
* Since: 2.26
|
||||
*/
|
||||
GDBusConnection *
|
||||
g_dbus_method_invocation_get_connection (GDBusMethodInvocation *invocation)
|
||||
{
|
||||
g_return_val_if_fail (G_IS_DBUS_METHOD_INVOCATION (invocation), NULL);
|
||||
return invocation->priv->connection;
|
||||
}
|
||||
|
||||
/**
|
||||
* g_dbus_method_invocation_get_message:
|
||||
* @invocation: A #GDBusMethodInvocation.
|
||||
*
|
||||
* Gets the #GDBusMessage for the method invocation. This is useful if
|
||||
* you need to use low-level protocol features, such as UNIX file
|
||||
* descriptor passing, that cannot be properly expressed in the
|
||||
* #GVariant API.
|
||||
*
|
||||
* See <xref linkend="gdbus-server"/> and <xref
|
||||
* linkend="gdbus-unix-fd-client"/> for an example of how to use this
|
||||
* low-level API to send and receive UNIX file descriptors.
|
||||
*
|
||||
* Returns: A #GDBusMessage. Do not free, it is owned by @invocation.
|
||||
*
|
||||
* Since: 2.26
|
||||
*/
|
||||
GDBusMessage *
|
||||
g_dbus_method_invocation_get_message (GDBusMethodInvocation *invocation)
|
||||
{
|
||||
g_return_val_if_fail (G_IS_DBUS_METHOD_INVOCATION (invocation), NULL);
|
||||
return invocation->priv->message;
|
||||
}
|
||||
|
||||
/**
|
||||
* g_dbus_method_invocation_get_parameters:
|
||||
* @invocation: A #GDBusMethodInvocation.
|
||||
*
|
||||
* Gets the parameters of the method invocation.
|
||||
*
|
||||
* Returns: A #GVariant. Do not free, it is owned by @invocation.
|
||||
*
|
||||
* Since: 2.26
|
||||
*/
|
||||
GVariant *
|
||||
g_dbus_method_invocation_get_parameters (GDBusMethodInvocation *invocation)
|
||||
{
|
||||
g_return_val_if_fail (G_IS_DBUS_METHOD_INVOCATION (invocation), NULL);
|
||||
return invocation->priv->parameters;
|
||||
}
|
||||
|
||||
/**
|
||||
* g_dbus_method_invocation_get_user_data:
|
||||
* @invocation: A #GDBusMethodInvocation.
|
||||
*
|
||||
* Gets the @user_data #gpointer passed to g_dbus_connection_register_object().
|
||||
*
|
||||
* Returns: A #gpointer.
|
||||
*
|
||||
* Since: 2.26
|
||||
*/
|
||||
gpointer
|
||||
g_dbus_method_invocation_get_user_data (GDBusMethodInvocation *invocation)
|
||||
{
|
||||
g_return_val_if_fail (G_IS_DBUS_METHOD_INVOCATION (invocation), NULL);
|
||||
return invocation->priv->user_data;
|
||||
}
|
||||
|
||||
/**
|
||||
* g_dbus_method_invocation_new:
|
||||
* @sender: The bus name that invoked the method or %NULL if @connection is not a bus connection.
|
||||
* @object_path: The object path the method was invoked on.
|
||||
* @interface_name: The name of the D-Bus interface the method was invoked on.
|
||||
* @method_name: The name of the method that was invoked.
|
||||
* @method_info: Information about the method call or %NULL.
|
||||
* @connection: The #GDBusConnection the method was invoked on.
|
||||
* @message: The D-Bus message as a #GDBusMessage.
|
||||
* @parameters: The parameters as a #GVariant tuple.
|
||||
* @user_data: The @user_data #gpointer passed to g_dbus_connection_register_object().
|
||||
*
|
||||
* Creates a new #GDBusMethodInvocation object.
|
||||
*
|
||||
* Returns: A #GDBusMethodInvocation. Free with g_object_unref().
|
||||
*
|
||||
* Since: 2.26
|
||||
*/
|
||||
GDBusMethodInvocation *
|
||||
g_dbus_method_invocation_new (const gchar *sender,
|
||||
const gchar *object_path,
|
||||
const gchar *interface_name,
|
||||
const gchar *method_name,
|
||||
const GDBusMethodInfo *method_info,
|
||||
GDBusConnection *connection,
|
||||
GDBusMessage *message,
|
||||
GVariant *parameters,
|
||||
gpointer user_data)
|
||||
{
|
||||
GDBusMethodInvocation *invocation;
|
||||
GDBusMethodInvocationPrivate *priv;
|
||||
|
||||
g_return_val_if_fail (sender == NULL || g_dbus_is_name (sender), NULL);
|
||||
g_return_val_if_fail (g_variant_is_object_path (object_path), NULL);
|
||||
g_return_val_if_fail (interface_name == NULL || g_dbus_is_interface_name (interface_name), NULL);
|
||||
g_return_val_if_fail (g_dbus_is_member_name (method_name), NULL);
|
||||
g_return_val_if_fail (G_IS_DBUS_CONNECTION (connection), NULL);
|
||||
g_return_val_if_fail (G_IS_DBUS_MESSAGE (message), NULL);
|
||||
g_return_val_if_fail (g_variant_is_of_type (parameters, G_VARIANT_TYPE_TUPLE), NULL);
|
||||
|
||||
invocation = G_DBUS_METHOD_INVOCATION (g_object_new (G_TYPE_DBUS_METHOD_INVOCATION, NULL));
|
||||
|
||||
priv = invocation->priv;
|
||||
priv->sender = g_strdup (sender);
|
||||
priv->object_path = g_strdup (object_path);
|
||||
priv->interface_name = g_strdup (interface_name);
|
||||
priv->method_name = g_strdup (method_name);
|
||||
priv->method_info = g_dbus_method_info_ref ((GDBusMethodInfo *)method_info);
|
||||
priv->connection = g_object_ref (connection);
|
||||
priv->message = g_object_ref (message);
|
||||
priv->parameters = g_variant_ref (parameters);
|
||||
priv->user_data = user_data;
|
||||
|
||||
return invocation;
|
||||
}
|
||||
|
||||
/* ---------------------------------------------------------------------------------------------------- */
|
||||
|
||||
/**
|
||||
* g_dbus_method_invocation_return_value:
|
||||
* @invocation: A #GDBusMethodInvocation.
|
||||
* @parameters: A #GVariant tuple with out parameters for the method or %NULL if not passing any parameters.
|
||||
*
|
||||
* Finishes handling a D-Bus method call by returning @parameters.
|
||||
*
|
||||
* It is an error if @parameters is not of the right format.
|
||||
*
|
||||
* This method will free @invocation, you cannot use it afterwards.
|
||||
*
|
||||
* Since: 2.26
|
||||
*/
|
||||
void
|
||||
g_dbus_method_invocation_return_value (GDBusMethodInvocation *invocation,
|
||||
GVariant *parameters)
|
||||
{
|
||||
GDBusMessage *reply;
|
||||
GError *error;
|
||||
|
||||
g_return_if_fail (G_IS_DBUS_METHOD_INVOCATION (invocation));
|
||||
g_return_if_fail ((parameters == NULL) || g_variant_is_of_type (parameters, G_VARIANT_TYPE_TUPLE));
|
||||
|
||||
if (parameters != NULL)
|
||||
g_variant_ref_sink (parameters);
|
||||
|
||||
/* if we have introspection data, check that the signature of @parameters is correct */
|
||||
if (invocation->priv->method_info != NULL)
|
||||
{
|
||||
gchar *signature;
|
||||
const gchar *type_string;
|
||||
|
||||
type_string = "()";
|
||||
if (parameters != NULL)
|
||||
type_string = g_variant_get_type_string (parameters);
|
||||
signature = _g_dbus_compute_complete_signature (invocation->priv->method_info->out_args, TRUE);
|
||||
|
||||
if (g_strcmp0 (type_string, signature) != 0)
|
||||
{
|
||||
g_warning (_("Type of return value is incorrect, got `%s', expected `%s'"),
|
||||
type_string,
|
||||
signature);
|
||||
g_free (signature);
|
||||
goto out;
|
||||
}
|
||||
g_free (signature);
|
||||
}
|
||||
|
||||
reply = g_dbus_message_new_method_reply (invocation->priv->message);
|
||||
g_dbus_message_set_body (reply, parameters);
|
||||
error = NULL;
|
||||
if (!g_dbus_connection_send_message (g_dbus_method_invocation_get_connection (invocation), reply, NULL, &error))
|
||||
{
|
||||
g_warning (_("Error sending message: %s"), error->message);
|
||||
g_error_free (error);
|
||||
}
|
||||
g_object_unref (reply);
|
||||
|
||||
out:
|
||||
g_object_unref (invocation);
|
||||
if (parameters != NULL)
|
||||
g_variant_unref (parameters);
|
||||
}
|
||||
|
||||
/* ---------------------------------------------------------------------------------------------------- */
|
||||
|
||||
/**
|
||||
* g_dbus_method_invocation_return_error:
|
||||
* @invocation: A #GDBusMethodInvocation.
|
||||
* @domain: A #GQuark for the #GError error domain.
|
||||
* @code: The error code.
|
||||
* @format: printf()-style format.
|
||||
* @...: Parameters for @format.
|
||||
*
|
||||
* Finishes handling a D-Bus method call by returning an error.
|
||||
*
|
||||
* See g_dbus_error_encode_gerror() for details about what error name
|
||||
* will be returned on the wire. In a nutshell, if the given error is
|
||||
* registered using g_dbus_error_register_error() the name given
|
||||
* during registration is used. Otherwise, a name of the form
|
||||
* <literal>org.gtk.GDBus.UnmappedGError.Quark...</literal> is
|
||||
* used. This provides transparent mapping of #GError between
|
||||
* applications using GDBus.
|
||||
*
|
||||
* If you are writing an application intended to be portable,
|
||||
* <emphasis>always</emphasis> register errors with g_dbus_error_register_error()
|
||||
* or use g_dbus_method_invocation_return_dbus_error().
|
||||
*
|
||||
* This method will free @invocation, you cannot use it afterwards.
|
||||
*
|
||||
* Since: 2.26
|
||||
*/
|
||||
void
|
||||
g_dbus_method_invocation_return_error (GDBusMethodInvocation *invocation,
|
||||
GQuark domain,
|
||||
gint code,
|
||||
const gchar *format,
|
||||
...)
|
||||
{
|
||||
va_list var_args;
|
||||
|
||||
g_return_if_fail (G_IS_DBUS_METHOD_INVOCATION (invocation));
|
||||
g_return_if_fail (format != NULL);
|
||||
|
||||
va_start (var_args, format);
|
||||
g_dbus_method_invocation_return_error_valist (invocation,
|
||||
domain,
|
||||
code,
|
||||
format,
|
||||
var_args);
|
||||
va_end (var_args);
|
||||
}
|
||||
|
||||
/**
|
||||
* g_dbus_method_invocation_return_error_valist:
|
||||
* @invocation: A #GDBusMethodInvocation.
|
||||
* @domain: A #GQuark for the #GError error domain.
|
||||
* @code: The error code.
|
||||
* @format: printf()-style format.
|
||||
* @var_args: #va_list of parameters for @format.
|
||||
*
|
||||
* Like g_dbus_method_invocation_return_error() but intended for
|
||||
* language bindings.
|
||||
*
|
||||
* This method will free @invocation, you cannot use it afterwards.
|
||||
*
|
||||
* Since: 2.26
|
||||
*/
|
||||
void
|
||||
g_dbus_method_invocation_return_error_valist (GDBusMethodInvocation *invocation,
|
||||
GQuark domain,
|
||||
gint code,
|
||||
const gchar *format,
|
||||
va_list var_args)
|
||||
{
|
||||
gchar *literal_message;
|
||||
|
||||
g_return_if_fail (G_IS_DBUS_METHOD_INVOCATION (invocation));
|
||||
g_return_if_fail (format != NULL);
|
||||
|
||||
literal_message = g_strdup_vprintf (format, var_args);
|
||||
g_dbus_method_invocation_return_error_literal (invocation,
|
||||
domain,
|
||||
code,
|
||||
literal_message);
|
||||
g_free (literal_message);
|
||||
}
|
||||
|
||||
/**
|
||||
* g_dbus_method_invocation_return_error_literal:
|
||||
* @invocation: A #GDBusMethodInvocation.
|
||||
* @domain: A #GQuark for the #GError error domain.
|
||||
* @code: The error code.
|
||||
* @message: The error message.
|
||||
*
|
||||
* Like g_dbus_method_invocation_return_error() but without printf()-style formatting.
|
||||
*
|
||||
* This method will free @invocation, you cannot use it afterwards.
|
||||
*
|
||||
* Since: 2.26
|
||||
*/
|
||||
void
|
||||
g_dbus_method_invocation_return_error_literal (GDBusMethodInvocation *invocation,
|
||||
GQuark domain,
|
||||
gint code,
|
||||
const gchar *message)
|
||||
{
|
||||
GError *error;
|
||||
|
||||
g_return_if_fail (G_IS_DBUS_METHOD_INVOCATION (invocation));
|
||||
g_return_if_fail (message != NULL);
|
||||
|
||||
error = g_error_new_literal (domain, code, message);
|
||||
g_dbus_method_invocation_return_gerror (invocation, error);
|
||||
g_error_free (error);
|
||||
}
|
||||
|
||||
/**
|
||||
* g_dbus_method_invocation_return_gerror:
|
||||
* @invocation: A #GDBusMethodInvocation.
|
||||
* @error: A #GError.
|
||||
*
|
||||
* Like g_dbus_method_invocation_return_error() but takes a #GError
|
||||
* instead of the error domain, error code and message.
|
||||
*
|
||||
* This method will free @invocation, you cannot use it afterwards.
|
||||
*
|
||||
* Since: 2.26
|
||||
*/
|
||||
void
|
||||
g_dbus_method_invocation_return_gerror (GDBusMethodInvocation *invocation,
|
||||
const GError *error)
|
||||
{
|
||||
gchar *dbus_error_name;
|
||||
|
||||
g_return_if_fail (G_IS_DBUS_METHOD_INVOCATION (invocation));
|
||||
g_return_if_fail (error != NULL);
|
||||
|
||||
dbus_error_name = g_dbus_error_encode_gerror (error);
|
||||
|
||||
g_dbus_method_invocation_return_dbus_error (invocation,
|
||||
dbus_error_name,
|
||||
error->message);
|
||||
g_free (dbus_error_name);
|
||||
}
|
||||
|
||||
/**
|
||||
* g_dbus_method_invocation_return_dbus_error:
|
||||
* @invocation: A #GDBusMethodInvocation.
|
||||
* @error_name: A valid D-Bus error name.
|
||||
* @error_message: A valid D-Bus error message.
|
||||
*
|
||||
* Finishes handling a D-Bus method call by returning an error.
|
||||
*
|
||||
* This method will free @invocation, you cannot use it afterwards.
|
||||
*
|
||||
* Since: 2.26
|
||||
*/
|
||||
void
|
||||
g_dbus_method_invocation_return_dbus_error (GDBusMethodInvocation *invocation,
|
||||
const gchar *error_name,
|
||||
const gchar *error_message)
|
||||
{
|
||||
GDBusMessage *reply;
|
||||
|
||||
g_return_if_fail (G_IS_DBUS_METHOD_INVOCATION (invocation));
|
||||
g_return_if_fail (error_name != NULL && g_dbus_is_name (error_name));
|
||||
g_return_if_fail (error_message != NULL);
|
||||
|
||||
reply = g_dbus_message_new_method_error_literal (invocation->priv->message,
|
||||
error_name,
|
||||
error_message);
|
||||
g_dbus_connection_send_message (g_dbus_method_invocation_get_connection (invocation), reply, NULL, NULL);
|
||||
g_object_unref (reply);
|
||||
|
||||
g_object_unref (invocation);
|
||||
}
|
||||
|
||||
#define __G_DBUS_METHOD_INVOCATION_C__
|
||||
#include "gioaliasdef.c"
|
123
gio/gdbusmethodinvocation.h
Normal file
123
gio/gdbusmethodinvocation.h
Normal file
@ -0,0 +1,123 @@
|
||||
/* GDBus - GLib D-Bus Library
|
||||
*
|
||||
* Copyright (C) 2008-2010 Red Hat, Inc.
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General
|
||||
* Public License along with this library; if not, write to the
|
||||
* Free Software Foundation, Inc., 59 Temple Place, Suite 330,
|
||||
* Boston, MA 02111-1307, USA.
|
||||
*
|
||||
* Author: David Zeuthen <davidz@redhat.com>
|
||||
*/
|
||||
|
||||
#ifndef __G_DBUS_METHOD_INVOCATION_H__
|
||||
#define __G_DBUS_METHOD_INVOCATION_H__
|
||||
|
||||
#include <gio/giotypes.h>
|
||||
|
||||
G_BEGIN_DECLS
|
||||
|
||||
#define G_TYPE_DBUS_METHOD_INVOCATION (g_dbus_method_invocation_get_type ())
|
||||
#define G_DBUS_METHOD_INVOCATION(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), G_TYPE_DBUS_METHOD_INVOCATION, GDBusMethodInvocation))
|
||||
#define G_DBUS_METHOD_INVOCATION_CLASS(k) (G_TYPE_CHECK_CLASS_CAST((k), G_TYPE_DBUS_METHOD_INVOCATION, GDBusMethodInvocationClass))
|
||||
#define G_DBUS_METHOD_INVOCATION_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS ((o), G_TYPE_DBUS_METHOD_INVOCATION, GDBusMethodInvocationClass))
|
||||
#define G_IS_DBUS_METHOD_INVOCATION(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), G_TYPE_DBUS_METHOD_INVOCATION))
|
||||
#define G_IS_DBUS_METHOD_INVOCATION_CLASS(k) (G_TYPE_CHECK_CLASS_TYPE ((k), G_TYPE_DBUS_METHOD_INVOCATION))
|
||||
|
||||
typedef struct _GDBusMethodInvocationClass GDBusMethodInvocationClass;
|
||||
typedef struct _GDBusMethodInvocationPrivate GDBusMethodInvocationPrivate;
|
||||
|
||||
/**
|
||||
* GDBusMethodInvocation:
|
||||
*
|
||||
* The #GDBusMethodInvocation structure contains only private data and
|
||||
* should only be accessed using the provided API.
|
||||
*
|
||||
* Since: 2.26
|
||||
*/
|
||||
struct _GDBusMethodInvocation
|
||||
{
|
||||
/*< private >*/
|
||||
GObject parent_instance;
|
||||
GDBusMethodInvocationPrivate *priv;
|
||||
};
|
||||
|
||||
/**
|
||||
* GDBusMethodInvocationClass:
|
||||
*
|
||||
* Class structure for #GDBusMethodInvocation.
|
||||
*
|
||||
* Since: 2.26
|
||||
*/
|
||||
struct _GDBusMethodInvocationClass
|
||||
{
|
||||
/*< private >*/
|
||||
GObjectClass parent_class;
|
||||
|
||||
/*< private >*/
|
||||
/* Padding for future expansion */
|
||||
void (*_g_reserved1) (void);
|
||||
void (*_g_reserved2) (void);
|
||||
void (*_g_reserved3) (void);
|
||||
void (*_g_reserved4) (void);
|
||||
void (*_g_reserved5) (void);
|
||||
void (*_g_reserved6) (void);
|
||||
void (*_g_reserved7) (void);
|
||||
void (*_g_reserved8) (void);
|
||||
};
|
||||
|
||||
GType g_dbus_method_invocation_get_type (void) G_GNUC_CONST;
|
||||
GDBusMethodInvocation *g_dbus_method_invocation_new (const gchar *sender,
|
||||
const gchar *object_path,
|
||||
const gchar *interface_name,
|
||||
const gchar *method_name,
|
||||
const GDBusMethodInfo *method_info,
|
||||
GDBusConnection *connection,
|
||||
GDBusMessage *message,
|
||||
GVariant *parameters,
|
||||
gpointer user_data);
|
||||
const gchar *g_dbus_method_invocation_get_sender (GDBusMethodInvocation *invocation);
|
||||
const gchar *g_dbus_method_invocation_get_object_path (GDBusMethodInvocation *invocation);
|
||||
const gchar *g_dbus_method_invocation_get_interface_name (GDBusMethodInvocation *invocation);
|
||||
const gchar *g_dbus_method_invocation_get_method_name (GDBusMethodInvocation *invocation);
|
||||
const GDBusMethodInfo *g_dbus_method_invocation_get_method_info (GDBusMethodInvocation *invocation);
|
||||
GDBusConnection *g_dbus_method_invocation_get_connection (GDBusMethodInvocation *invocation);
|
||||
GDBusMessage *g_dbus_method_invocation_get_message (GDBusMethodInvocation *invocation);
|
||||
GVariant *g_dbus_method_invocation_get_parameters (GDBusMethodInvocation *invocation);
|
||||
gpointer g_dbus_method_invocation_get_user_data (GDBusMethodInvocation *invocation);
|
||||
|
||||
void g_dbus_method_invocation_return_value (GDBusMethodInvocation *invocation,
|
||||
GVariant *parameters);
|
||||
void g_dbus_method_invocation_return_error (GDBusMethodInvocation *invocation,
|
||||
GQuark domain,
|
||||
gint code,
|
||||
const gchar *format,
|
||||
...);
|
||||
void g_dbus_method_invocation_return_error_valist (GDBusMethodInvocation *invocation,
|
||||
GQuark domain,
|
||||
gint code,
|
||||
const gchar *format,
|
||||
va_list var_args);
|
||||
void g_dbus_method_invocation_return_error_literal (GDBusMethodInvocation *invocation,
|
||||
GQuark domain,
|
||||
gint code,
|
||||
const gchar *message);
|
||||
void g_dbus_method_invocation_return_gerror (GDBusMethodInvocation *invocation,
|
||||
const GError *error);
|
||||
void g_dbus_method_invocation_return_dbus_error (GDBusMethodInvocation *invocation,
|
||||
const gchar *error_name,
|
||||
const gchar *error_message);
|
||||
|
||||
G_END_DECLS
|
||||
|
||||
#endif /* __G_DBUS_METHOD_INVOCATION_H__ */
|
724
gio/gdbusnameowning.c
Normal file
724
gio/gdbusnameowning.c
Normal file
@ -0,0 +1,724 @@
|
||||
/* GDBus - GLib D-Bus Library
|
||||
*
|
||||
* Copyright (C) 2008-2010 Red Hat, Inc.
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General
|
||||
* Public License along with this library; if not, write to the
|
||||
* Free Software Foundation, Inc., 59 Temple Place, Suite 330,
|
||||
* Boston, MA 02111-1307, USA.
|
||||
*
|
||||
* Author: David Zeuthen <davidz@redhat.com>
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include <stdlib.h>
|
||||
|
||||
#include "gdbusutils.h"
|
||||
#include "gdbusnameowning.h"
|
||||
#include "gdbuserror.h"
|
||||
#include "gdbusprivate.h"
|
||||
#include "gdbusconnection.h"
|
||||
|
||||
#include "glibintl.h"
|
||||
#include "gioalias.h"
|
||||
|
||||
/**
|
||||
* SECTION:gdbusnameowning
|
||||
* @title: Owning Bus Names
|
||||
* @short_description: Simple API for owning bus names
|
||||
* @include: gio/gio.h
|
||||
*
|
||||
* Convenience API for owning bus names.
|
||||
*
|
||||
* <example id="gdbus-owning-names"><title>Simple application owning a name</title><programlisting><xi:include xmlns:xi="http://www.w3.org/2001/XInclude" parse="text" href="../../../../gio/tests/gdbus-example-own-name.c"><xi:fallback>FIXME: MISSING XINCLUDE CONTENT</xi:fallback></xi:include></programlisting></example>
|
||||
*/
|
||||
|
||||
G_LOCK_DEFINE_STATIC (lock);
|
||||
|
||||
/* ---------------------------------------------------------------------------------------------------- */
|
||||
|
||||
typedef enum
|
||||
{
|
||||
PREVIOUS_CALL_NONE = 0,
|
||||
PREVIOUS_CALL_ACQUIRED,
|
||||
PREVIOUS_CALL_LOST,
|
||||
} PreviousCall;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
volatile gint ref_count;
|
||||
guint id;
|
||||
GBusNameOwnerFlags flags;
|
||||
gchar *name;
|
||||
GBusAcquiredCallback bus_acquired_handler;
|
||||
GBusNameAcquiredCallback name_acquired_handler;
|
||||
GBusNameLostCallback name_lost_handler;
|
||||
gpointer user_data;
|
||||
GDestroyNotify user_data_free_func;
|
||||
GMainContext *main_context;
|
||||
|
||||
PreviousCall previous_call;
|
||||
|
||||
GDBusConnection *connection;
|
||||
gulong disconnected_signal_handler_id;
|
||||
guint name_acquired_subscription_id;
|
||||
guint name_lost_subscription_id;
|
||||
|
||||
gboolean cancelled;
|
||||
|
||||
gboolean needs_release;
|
||||
} Client;
|
||||
|
||||
static guint next_global_id = 1;
|
||||
static GHashTable *map_id_to_client = NULL;
|
||||
|
||||
|
||||
static Client *
|
||||
client_ref (Client *client)
|
||||
{
|
||||
g_atomic_int_inc (&client->ref_count);
|
||||
return client;
|
||||
}
|
||||
|
||||
static void
|
||||
client_unref (Client *client)
|
||||
{
|
||||
if (g_atomic_int_dec_and_test (&client->ref_count))
|
||||
{
|
||||
if (client->connection != NULL)
|
||||
{
|
||||
if (client->disconnected_signal_handler_id > 0)
|
||||
g_signal_handler_disconnect (client->connection, client->disconnected_signal_handler_id);
|
||||
if (client->name_acquired_subscription_id > 0)
|
||||
g_dbus_connection_signal_unsubscribe (client->connection, client->name_acquired_subscription_id);
|
||||
if (client->name_lost_subscription_id > 0)
|
||||
g_dbus_connection_signal_unsubscribe (client->connection, client->name_lost_subscription_id);
|
||||
g_object_unref (client->connection);
|
||||
}
|
||||
if (client->main_context != NULL)
|
||||
g_main_context_unref (client->main_context);
|
||||
g_free (client->name);
|
||||
if (client->user_data_free_func != NULL)
|
||||
client->user_data_free_func (client->user_data);
|
||||
g_free (client);
|
||||
}
|
||||
}
|
||||
|
||||
/* ---------------------------------------------------------------------------------------------------- */
|
||||
|
||||
|
||||
typedef enum
|
||||
{
|
||||
CALL_TYPE_NAME_ACQUIRED,
|
||||
CALL_TYPE_NAME_LOST
|
||||
} CallType;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
Client *client;
|
||||
|
||||
/* keep this separate because client->connection may
|
||||
* be set to NULL after scheduling the call
|
||||
*/
|
||||
GDBusConnection *connection;
|
||||
|
||||
/* set to TRUE to call acquired */
|
||||
CallType call_type;
|
||||
} CallHandlerData;
|
||||
|
||||
static void
|
||||
call_handler_data_free (CallHandlerData *data)
|
||||
{
|
||||
if (data->connection != NULL)
|
||||
g_object_unref (data->connection);
|
||||
client_unref (data->client);
|
||||
g_free (data);
|
||||
}
|
||||
|
||||
static void
|
||||
actually_do_call (Client *client, GDBusConnection *connection, CallType call_type)
|
||||
{
|
||||
switch (call_type)
|
||||
{
|
||||
case CALL_TYPE_NAME_ACQUIRED:
|
||||
if (client->name_acquired_handler != NULL)
|
||||
{
|
||||
client->name_acquired_handler (connection,
|
||||
client->name,
|
||||
client->user_data);
|
||||
}
|
||||
break;
|
||||
|
||||
case CALL_TYPE_NAME_LOST:
|
||||
if (client->name_lost_handler != NULL)
|
||||
{
|
||||
client->name_lost_handler (connection,
|
||||
client->name,
|
||||
client->user_data);
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
g_assert_not_reached ();
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static gboolean
|
||||
call_in_idle_cb (gpointer _data)
|
||||
{
|
||||
CallHandlerData *data = _data;
|
||||
actually_do_call (data->client, data->connection, data->call_type);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
static void
|
||||
schedule_call_in_idle (Client *client, CallType call_type)
|
||||
{
|
||||
CallHandlerData *data;
|
||||
GSource *idle_source;
|
||||
|
||||
data = g_new0 (CallHandlerData, 1);
|
||||
data->client = client_ref (client);
|
||||
data->connection = client->connection != NULL ? g_object_ref (client->connection) : NULL;
|
||||
data->call_type = call_type;
|
||||
|
||||
idle_source = g_idle_source_new ();
|
||||
g_source_set_priority (idle_source, G_PRIORITY_HIGH);
|
||||
g_source_set_callback (idle_source,
|
||||
call_in_idle_cb,
|
||||
data,
|
||||
(GDestroyNotify) call_handler_data_free);
|
||||
g_source_attach (idle_source, client->main_context);
|
||||
g_source_unref (idle_source);
|
||||
}
|
||||
|
||||
static void
|
||||
do_call (Client *client, CallType call_type)
|
||||
{
|
||||
/* only schedule in idle if we're not in the right thread */
|
||||
if (g_main_context_get_thread_default () != client->main_context)
|
||||
schedule_call_in_idle (client, call_type);
|
||||
else
|
||||
actually_do_call (client, client->connection, call_type);
|
||||
}
|
||||
|
||||
static void
|
||||
call_acquired_handler (Client *client)
|
||||
{
|
||||
if (client->previous_call != PREVIOUS_CALL_ACQUIRED)
|
||||
{
|
||||
client->previous_call = PREVIOUS_CALL_ACQUIRED;
|
||||
if (!client->cancelled)
|
||||
{
|
||||
do_call (client, CALL_TYPE_NAME_ACQUIRED);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
call_lost_handler (Client *client)
|
||||
{
|
||||
if (client->previous_call != PREVIOUS_CALL_LOST)
|
||||
{
|
||||
client->previous_call = PREVIOUS_CALL_LOST;
|
||||
if (!client->cancelled)
|
||||
{
|
||||
do_call (client, CALL_TYPE_NAME_LOST);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* ---------------------------------------------------------------------------------------------------- */
|
||||
|
||||
static void
|
||||
on_name_lost_or_acquired (GDBusConnection *connection,
|
||||
const gchar *sender_name,
|
||||
const gchar *object_path,
|
||||
const gchar *interface_name,
|
||||
const gchar *signal_name,
|
||||
GVariant *parameters,
|
||||
gpointer user_data)
|
||||
{
|
||||
Client *client = user_data;
|
||||
const gchar *name;
|
||||
|
||||
if (g_strcmp0 (object_path, "/org/freedesktop/DBus") != 0 ||
|
||||
g_strcmp0 (interface_name, "org.freedesktop.DBus") != 0 ||
|
||||
g_strcmp0 (sender_name, "org.freedesktop.DBus") != 0)
|
||||
goto out;
|
||||
|
||||
if (g_strcmp0 (signal_name, "NameLost") == 0)
|
||||
{
|
||||
g_variant_get (parameters, "(&s)", &name);
|
||||
if (g_strcmp0 (name, client->name) == 0)
|
||||
{
|
||||
call_lost_handler (client);
|
||||
}
|
||||
}
|
||||
else if (g_strcmp0 (signal_name, "NameAcquired") == 0)
|
||||
{
|
||||
g_variant_get (parameters, "(&s)", &name);
|
||||
if (g_strcmp0 (name, client->name) == 0)
|
||||
{
|
||||
call_acquired_handler (client);
|
||||
}
|
||||
}
|
||||
out:
|
||||
;
|
||||
}
|
||||
|
||||
/* ---------------------------------------------------------------------------------------------------- */
|
||||
|
||||
static void
|
||||
request_name_cb (GObject *source_object,
|
||||
GAsyncResult *res,
|
||||
gpointer user_data)
|
||||
{
|
||||
Client *client = user_data;
|
||||
GVariant *result;
|
||||
guint32 request_name_reply;
|
||||
gboolean subscribe;
|
||||
|
||||
request_name_reply = 0;
|
||||
result = NULL;
|
||||
|
||||
result = g_dbus_connection_call_finish (client->connection,
|
||||
res,
|
||||
NULL);
|
||||
if (result != NULL)
|
||||
{
|
||||
g_variant_get (result, "(u)", &request_name_reply);
|
||||
g_variant_unref (result);
|
||||
}
|
||||
|
||||
subscribe = FALSE;
|
||||
|
||||
switch (request_name_reply)
|
||||
{
|
||||
case 1: /* DBUS_REQUEST_NAME_REPLY_PRIMARY_OWNER */
|
||||
/* We got the name - now listen for NameLost and NameAcquired */
|
||||
call_acquired_handler (client);
|
||||
subscribe = TRUE;
|
||||
client->needs_release = TRUE;
|
||||
break;
|
||||
|
||||
case 2: /* DBUS_REQUEST_NAME_REPLY_IN_QUEUE */
|
||||
/* Waiting in line - listen for NameLost and NameAcquired */
|
||||
call_lost_handler (client);
|
||||
subscribe = TRUE;
|
||||
client->needs_release = TRUE;
|
||||
break;
|
||||
|
||||
default:
|
||||
/* assume we couldn't get the name - explicit fallthrough */
|
||||
case 3: /* DBUS_REQUEST_NAME_REPLY_EXISTS */
|
||||
case 4: /* DBUS_REQUEST_NAME_REPLY_ALREADY_OWNER */
|
||||
/* Some other part of the process is already owning the name */
|
||||
call_lost_handler (client);
|
||||
break;
|
||||
}
|
||||
|
||||
if (subscribe)
|
||||
{
|
||||
/* start listening to NameLost and NameAcquired messages */
|
||||
client->name_lost_subscription_id =
|
||||
g_dbus_connection_signal_subscribe (client->connection,
|
||||
"org.freedesktop.DBus",
|
||||
"org.freedesktop.DBus",
|
||||
"NameLost",
|
||||
"/org/freedesktop/DBus",
|
||||
client->name,
|
||||
on_name_lost_or_acquired,
|
||||
client,
|
||||
NULL);
|
||||
client->name_acquired_subscription_id =
|
||||
g_dbus_connection_signal_subscribe (client->connection,
|
||||
"org.freedesktop.DBus",
|
||||
"org.freedesktop.DBus",
|
||||
"NameAcquired",
|
||||
"/org/freedesktop/DBus",
|
||||
client->name,
|
||||
on_name_lost_or_acquired,
|
||||
client,
|
||||
NULL);
|
||||
}
|
||||
|
||||
client_unref (client);
|
||||
}
|
||||
|
||||
/* ---------------------------------------------------------------------------------------------------- */
|
||||
|
||||
static void
|
||||
on_connection_disconnected (GDBusConnection *connection,
|
||||
gboolean remote_peer_vanished,
|
||||
GError *error,
|
||||
gpointer user_data)
|
||||
{
|
||||
Client *client = user_data;
|
||||
|
||||
if (client->disconnected_signal_handler_id > 0)
|
||||
g_signal_handler_disconnect (client->connection, client->disconnected_signal_handler_id);
|
||||
if (client->name_acquired_subscription_id > 0)
|
||||
g_dbus_connection_signal_unsubscribe (client->connection, client->name_acquired_subscription_id);
|
||||
if (client->name_lost_subscription_id > 0)
|
||||
g_dbus_connection_signal_unsubscribe (client->connection, client->name_lost_subscription_id);
|
||||
g_object_unref (client->connection);
|
||||
client->disconnected_signal_handler_id = 0;
|
||||
client->name_acquired_subscription_id = 0;
|
||||
client->name_lost_subscription_id = 0;
|
||||
client->connection = NULL;
|
||||
|
||||
call_lost_handler (client);
|
||||
}
|
||||
|
||||
/* ---------------------------------------------------------------------------------------------------- */
|
||||
|
||||
static void
|
||||
has_connection (Client *client)
|
||||
{
|
||||
/* listen for disconnection */
|
||||
client->disconnected_signal_handler_id = g_signal_connect (client->connection,
|
||||
"closed",
|
||||
G_CALLBACK (on_connection_disconnected),
|
||||
client);
|
||||
|
||||
/* attempt to acquire the name */
|
||||
g_dbus_connection_call (client->connection,
|
||||
"org.freedesktop.DBus", /* bus name */
|
||||
"/org/freedesktop/DBus", /* object path */
|
||||
"org.freedesktop.DBus", /* interface name */
|
||||
"RequestName", /* method name */
|
||||
g_variant_new ("(su)",
|
||||
client->name,
|
||||
client->flags),
|
||||
G_DBUS_CALL_FLAGS_NONE,
|
||||
-1,
|
||||
NULL,
|
||||
(GAsyncReadyCallback) request_name_cb,
|
||||
client_ref (client));
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
connection_get_cb (GObject *source_object,
|
||||
GAsyncResult *res,
|
||||
gpointer user_data)
|
||||
{
|
||||
Client *client = user_data;
|
||||
|
||||
client->connection = g_bus_get_finish (res, NULL);
|
||||
if (client->connection == NULL)
|
||||
{
|
||||
call_lost_handler (client);
|
||||
goto out;
|
||||
}
|
||||
|
||||
/* No need to schedule this in idle as we're already in the thread
|
||||
* that the user called g_bus_own_name() from. This is because
|
||||
* g_bus_get() guarantees that.
|
||||
*
|
||||
* Also, we need to ensure that the handler is invoked *before*
|
||||
* we call RequestName(). Otherwise there is a race.
|
||||
*/
|
||||
if (client->bus_acquired_handler != NULL)
|
||||
{
|
||||
client->bus_acquired_handler (client->connection,
|
||||
client->name,
|
||||
client->user_data);
|
||||
}
|
||||
|
||||
has_connection (client);
|
||||
|
||||
out:
|
||||
client_unref (client);
|
||||
}
|
||||
|
||||
/* ---------------------------------------------------------------------------------------------------- */
|
||||
|
||||
/**
|
||||
* g_bus_own_name_on_connection:
|
||||
* @connection: A #GDBusConnection that is not closed.
|
||||
* @name: The well-known name to own.
|
||||
* @flags: A set of flags from the #GBusNameOwnerFlags enumeration.
|
||||
* @name_acquired_handler: Handler to invoke when @name is acquired or %NULL.
|
||||
* @name_lost_handler: Handler to invoke when @name is lost or %NULL.
|
||||
* @user_data: User data to pass to handlers.
|
||||
* @user_data_free_func: Function for freeing @user_data or %NULL.
|
||||
*
|
||||
* Like g_bus_own_name() but takes a #GDBusConnection instead of a
|
||||
* #GBusType.
|
||||
*
|
||||
* Returns: An identifier (never 0) that an be used with
|
||||
* g_bus_unown_name() to stop owning the name.
|
||||
*
|
||||
* Since: 2.26
|
||||
*/
|
||||
guint
|
||||
g_bus_own_name_on_connection (GDBusConnection *connection,
|
||||
const gchar *name,
|
||||
GBusNameOwnerFlags flags,
|
||||
GBusNameAcquiredCallback name_acquired_handler,
|
||||
GBusNameLostCallback name_lost_handler,
|
||||
gpointer user_data,
|
||||
GDestroyNotify user_data_free_func)
|
||||
{
|
||||
Client *client;
|
||||
|
||||
g_return_val_if_fail (G_IS_DBUS_CONNECTION (connection), 0);
|
||||
g_return_val_if_fail (!g_dbus_connection_is_closed (connection), 0);
|
||||
g_return_val_if_fail (g_dbus_is_name (name) && !g_dbus_is_unique_name (name), 0);
|
||||
|
||||
G_LOCK (lock);
|
||||
|
||||
client = g_new0 (Client, 1);
|
||||
client->ref_count = 1;
|
||||
client->id = next_global_id++; /* TODO: uh oh, handle overflow */
|
||||
client->name = g_strdup (name);
|
||||
client->flags = flags;
|
||||
client->name_acquired_handler = name_acquired_handler;
|
||||
client->name_lost_handler = name_lost_handler;
|
||||
client->user_data = user_data;
|
||||
client->user_data_free_func = user_data_free_func;
|
||||
client->main_context = g_main_context_get_thread_default ();
|
||||
if (client->main_context != NULL)
|
||||
g_main_context_ref (client->main_context);
|
||||
|
||||
client->connection = g_object_ref (connection);
|
||||
|
||||
if (map_id_to_client == NULL)
|
||||
{
|
||||
map_id_to_client = g_hash_table_new (g_direct_hash, g_direct_equal);
|
||||
}
|
||||
g_hash_table_insert (map_id_to_client,
|
||||
GUINT_TO_POINTER (client->id),
|
||||
client);
|
||||
|
||||
G_UNLOCK (lock);
|
||||
|
||||
has_connection (client);
|
||||
|
||||
return client->id;
|
||||
}
|
||||
|
||||
/**
|
||||
* g_bus_own_name:
|
||||
* @bus_type: The type of bus to own a name on.
|
||||
* @name: The well-known name to own.
|
||||
* @flags: A set of flags from the #GBusNameOwnerFlags enumeration.
|
||||
* @bus_acquired_handler: Handler to invoke when connected to the bus of type @bus_type or %NULL.
|
||||
* @name_acquired_handler: Handler to invoke when @name is acquired or %NULL.
|
||||
* @name_lost_handler: Handler to invoke when @name is lost or %NULL.
|
||||
* @user_data: User data to pass to handlers.
|
||||
* @user_data_free_func: Function for freeing @user_data or %NULL.
|
||||
*
|
||||
* Starts acquiring @name on the bus specified by @bus_type and calls
|
||||
* @name_acquired_handler and @name_lost_handler when the name is
|
||||
* acquired respectively lost. Callbacks will be invoked in the <link
|
||||
* linkend="g-main-context-push-thread-default">thread-default main
|
||||
* loop</link> of the thread you are calling this function from.
|
||||
*
|
||||
* You are guaranteed that one of the @name_acquired_handler and @name_lost_handler
|
||||
* callbacks will be invoked after calling this function - there are three
|
||||
* possible cases:
|
||||
* <itemizedlist>
|
||||
* <listitem><para>
|
||||
* @name_lost_handler with a %NULL connection (if a connection to the bus can't be made).
|
||||
* </para></listitem>
|
||||
* <listitem><para>
|
||||
* @bus_acquired_handler then @name_lost_handler (if the name can't be obtained)
|
||||
* </para></listitem>
|
||||
* <listitem><para>
|
||||
* @bus_acquired_handler then @name_acquired_handler (if the name was obtained).
|
||||
* </para></listitem>
|
||||
* </itemizedlist>
|
||||
* When you are done owning the name, just call g_bus_unown_name()
|
||||
* with the owner id this function returns.
|
||||
*
|
||||
* If the name is acquired or lost (for example another application
|
||||
* could acquire the name if you allow replacement or the application
|
||||
* currently owning the name exits), the handlers are also invoked. If the
|
||||
* #GDBusConnection that is used for attempting to own the name
|
||||
* closes, then @name_lost_handler is invoked since it is no
|
||||
* longer possible for other processes to access the process.
|
||||
*
|
||||
* You cannot use g_bus_own_name() several times for the same name (unless
|
||||
* interleaved with calls to g_bus_unown_name()) - only the first call
|
||||
* will work.
|
||||
*
|
||||
* Another guarantee is that invocations of @name_acquired_handler
|
||||
* and @name_lost_handler are guaranteed to alternate; that
|
||||
* is, if @name_acquired_handler is invoked then you are
|
||||
* guaranteed that the next time one of the handlers is invoked, it
|
||||
* will be @name_lost_handler. The reverse is also true.
|
||||
*
|
||||
* If you plan on exporting objects (using e.g.
|
||||
* g_dbus_connection_register_object()), note that it is generally too late
|
||||
* to export the objects in @name_acquired_handler. Instead, you can do this
|
||||
* in @bus_acquired_handler since you are guaranteed that this will run
|
||||
* before @name is requested from the bus.
|
||||
*
|
||||
* This behavior makes it very simple to write applications that wants
|
||||
* to own names and export objects, see <xref linkend="gdbus-owning-names"/>.
|
||||
* Simply register objects to be exported in @bus_acquired_handler and
|
||||
* unregister the objects (if any) in @name_lost_handler.
|
||||
*
|
||||
* Returns: An identifier (never 0) that an be used with
|
||||
* g_bus_unown_name() to stop owning the name.
|
||||
*
|
||||
* Since: 2.26
|
||||
*/
|
||||
guint
|
||||
g_bus_own_name (GBusType bus_type,
|
||||
const gchar *name,
|
||||
GBusNameOwnerFlags flags,
|
||||
GBusAcquiredCallback bus_acquired_handler,
|
||||
GBusNameAcquiredCallback name_acquired_handler,
|
||||
GBusNameLostCallback name_lost_handler,
|
||||
gpointer user_data,
|
||||
GDestroyNotify user_data_free_func)
|
||||
{
|
||||
Client *client;
|
||||
|
||||
g_return_val_if_fail (g_dbus_is_name (name) && !g_dbus_is_unique_name (name), 0);
|
||||
|
||||
G_LOCK (lock);
|
||||
|
||||
client = g_new0 (Client, 1);
|
||||
client->ref_count = 1;
|
||||
client->id = next_global_id++; /* TODO: uh oh, handle overflow */
|
||||
client->name = g_strdup (name);
|
||||
client->flags = flags;
|
||||
client->bus_acquired_handler = bus_acquired_handler;
|
||||
client->name_acquired_handler = name_acquired_handler;
|
||||
client->name_lost_handler = name_lost_handler;
|
||||
client->user_data = user_data;
|
||||
client->user_data_free_func = user_data_free_func;
|
||||
client->main_context = g_main_context_get_thread_default ();
|
||||
if (client->main_context != NULL)
|
||||
g_main_context_ref (client->main_context);
|
||||
|
||||
if (map_id_to_client == NULL)
|
||||
{
|
||||
map_id_to_client = g_hash_table_new (g_direct_hash, g_direct_equal);
|
||||
}
|
||||
g_hash_table_insert (map_id_to_client,
|
||||
GUINT_TO_POINTER (client->id),
|
||||
client);
|
||||
|
||||
g_bus_get (bus_type,
|
||||
NULL,
|
||||
connection_get_cb,
|
||||
client_ref (client));
|
||||
|
||||
G_UNLOCK (lock);
|
||||
|
||||
return client->id;
|
||||
}
|
||||
|
||||
/**
|
||||
* g_bus_unown_name:
|
||||
* @owner_id: An identifier obtained from g_bus_own_name()
|
||||
*
|
||||
* Stops owning a name.
|
||||
*
|
||||
* Since: 2.26
|
||||
*/
|
||||
void
|
||||
g_bus_unown_name (guint owner_id)
|
||||
{
|
||||
Client *client;
|
||||
|
||||
g_return_if_fail (owner_id > 0);
|
||||
|
||||
client = NULL;
|
||||
|
||||
G_LOCK (lock);
|
||||
if (owner_id == 0 || map_id_to_client == NULL ||
|
||||
(client = g_hash_table_lookup (map_id_to_client, GUINT_TO_POINTER (owner_id))) == NULL)
|
||||
{
|
||||
g_warning ("Invalid id %d passed to g_bus_unown_name()", owner_id);
|
||||
goto out;
|
||||
}
|
||||
|
||||
client->cancelled = TRUE;
|
||||
g_warn_if_fail (g_hash_table_remove (map_id_to_client, GUINT_TO_POINTER (owner_id)));
|
||||
|
||||
out:
|
||||
G_UNLOCK (lock);
|
||||
|
||||
/* do callback without holding lock */
|
||||
if (client != NULL)
|
||||
{
|
||||
/* Release the name if needed */
|
||||
if (client->needs_release && client->connection != NULL)
|
||||
{
|
||||
GVariant *result;
|
||||
GError *error;
|
||||
guint32 release_name_reply;
|
||||
|
||||
/* TODO: it kinda sucks having to do a sync call to release the name - but if
|
||||
* we don't, then a subsequent grab of the name will make the bus daemon return
|
||||
* IN_QUEUE which will trigger name_lost().
|
||||
*
|
||||
* I believe this is a bug in the bus daemon.
|
||||
*/
|
||||
error = NULL;
|
||||
result = g_dbus_connection_call_sync (client->connection,
|
||||
"org.freedesktop.DBus", /* bus name */
|
||||
"/org/freedesktop/DBus", /* object path */
|
||||
"org.freedesktop.DBus", /* interface name */
|
||||
"ReleaseName", /* method name */
|
||||
g_variant_new ("(s)", client->name),
|
||||
G_DBUS_CALL_FLAGS_NONE,
|
||||
-1,
|
||||
NULL,
|
||||
&error);
|
||||
if (result == NULL)
|
||||
{
|
||||
g_warning ("Error releasing name %s: %s", client->name, error->message);
|
||||
g_error_free (error);
|
||||
}
|
||||
else
|
||||
{
|
||||
g_variant_get (result, "(u)", &release_name_reply);
|
||||
if (release_name_reply != 1 /* DBUS_RELEASE_NAME_REPLY_RELEASED */)
|
||||
{
|
||||
g_warning ("Unexpected reply %d when releasing name %s", release_name_reply, client->name);
|
||||
}
|
||||
g_variant_unref (result);
|
||||
}
|
||||
}
|
||||
|
||||
if (client->disconnected_signal_handler_id > 0)
|
||||
g_signal_handler_disconnect (client->connection, client->disconnected_signal_handler_id);
|
||||
if (client->name_acquired_subscription_id > 0)
|
||||
g_dbus_connection_signal_unsubscribe (client->connection, client->name_acquired_subscription_id);
|
||||
if (client->name_lost_subscription_id > 0)
|
||||
g_dbus_connection_signal_unsubscribe (client->connection, client->name_lost_subscription_id);
|
||||
client->disconnected_signal_handler_id = 0;
|
||||
client->name_acquired_subscription_id = 0;
|
||||
client->name_lost_subscription_id = 0;
|
||||
if (client->connection != NULL)
|
||||
{
|
||||
g_object_unref (client->connection);
|
||||
client->connection = NULL;
|
||||
}
|
||||
|
||||
client_unref (client);
|
||||
}
|
||||
}
|
||||
|
||||
#define __G_DBUS_NAME_OWNING_C__
|
||||
#include "gioaliasdef.c"
|
94
gio/gdbusnameowning.h
Normal file
94
gio/gdbusnameowning.h
Normal file
@ -0,0 +1,94 @@
|
||||
/* GDBus - GLib D-Bus Library
|
||||
*
|
||||
* Copyright (C) 2008-2010 Red Hat, Inc.
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General
|
||||
* Public License along with this library; if not, write to the
|
||||
* Free Software Foundation, Inc., 59 Temple Place, Suite 330,
|
||||
* Boston, MA 02111-1307, USA.
|
||||
*
|
||||
* Author: David Zeuthen <davidz@redhat.com>
|
||||
*/
|
||||
|
||||
#ifndef __G_DBUS_NAME_OWNING_H__
|
||||
#define __G_DBUS_NAME_OWNING_H__
|
||||
|
||||
#include <gio/giotypes.h>
|
||||
|
||||
G_BEGIN_DECLS
|
||||
|
||||
/**
|
||||
* GBusAcquiredCallback:
|
||||
* @connection: The #GDBusConnection to a message bus.
|
||||
* @name: The name that is requested to be owned.
|
||||
* @user_data: User data passed to g_bus_own_name().
|
||||
*
|
||||
* Invoked when a connection to a message bus has been obtained.
|
||||
*
|
||||
* Since: 2.26
|
||||
*/
|
||||
typedef void (*GBusAcquiredCallback) (GDBusConnection *connection,
|
||||
const gchar *name,
|
||||
gpointer user_data);
|
||||
|
||||
/**
|
||||
* GBusNameAcquiredCallback:
|
||||
* @connection: The #GDBusConnection on which to acquired the name.
|
||||
* @name: The name being owned.
|
||||
* @user_data: User data passed to g_bus_own_name() or g_bus_own_name_on_connection().
|
||||
*
|
||||
* Invoked when the name is acquired.
|
||||
*
|
||||
* Since: 2.26
|
||||
*/
|
||||
typedef void (*GBusNameAcquiredCallback) (GDBusConnection *connection,
|
||||
const gchar *name,
|
||||
gpointer user_data);
|
||||
|
||||
/**
|
||||
* GBusNameLostCallback:
|
||||
* @connection: The #GDBusConnection on which to acquire the name or %NULL if
|
||||
* the connection was disconnected.
|
||||
* @name: The name being owned.
|
||||
* @user_data: User data passed to g_bus_own_name() or g_bus_own_name_on_connection().
|
||||
*
|
||||
* Invoked when the name is lost or @connection has been closed.
|
||||
*
|
||||
* Since: 2.26
|
||||
*/
|
||||
typedef void (*GBusNameLostCallback) (GDBusConnection *connection,
|
||||
const gchar *name,
|
||||
gpointer user_data);
|
||||
|
||||
guint g_bus_own_name (GBusType bus_type,
|
||||
const gchar *name,
|
||||
GBusNameOwnerFlags flags,
|
||||
GBusAcquiredCallback bus_acquired_handler,
|
||||
GBusNameAcquiredCallback name_acquired_handler,
|
||||
GBusNameLostCallback name_lost_handler,
|
||||
gpointer user_data,
|
||||
GDestroyNotify user_data_free_func);
|
||||
|
||||
guint g_bus_own_name_on_connection (GDBusConnection *connection,
|
||||
const gchar *name,
|
||||
GBusNameOwnerFlags flags,
|
||||
GBusNameAcquiredCallback name_acquired_handler,
|
||||
GBusNameLostCallback name_lost_handler,
|
||||
gpointer user_data,
|
||||
GDestroyNotify user_data_free_func);
|
||||
|
||||
void g_bus_unown_name (guint owner_id);
|
||||
|
||||
G_END_DECLS
|
||||
|
||||
#endif /* __G_DBUS_NAME_OWNING_H__ */
|
691
gio/gdbusnamewatching.c
Normal file
691
gio/gdbusnamewatching.c
Normal file
@ -0,0 +1,691 @@
|
||||
/* GDBus - GLib D-Bus Library
|
||||
*
|
||||
* Copyright (C) 2008-2010 Red Hat, Inc.
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General
|
||||
* Public License along with this library; if not, write to the
|
||||
* Free Software Foundation, Inc., 59 Temple Place, Suite 330,
|
||||
* Boston, MA 02111-1307, USA.
|
||||
*
|
||||
* Author: David Zeuthen <davidz@redhat.com>
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "gdbusutils.h"
|
||||
#include "gdbusnamewatching.h"
|
||||
#include "gdbuserror.h"
|
||||
#include "gdbusprivate.h"
|
||||
#include "gdbusconnection.h"
|
||||
|
||||
#include "glibintl.h"
|
||||
#include "gioalias.h"
|
||||
|
||||
/**
|
||||
* SECTION:gdbusnamewatching
|
||||
* @title: Watching Bus Names
|
||||
* @short_description: Simple API for watching bus names
|
||||
* @include: gio/gio.h
|
||||
*
|
||||
* Convenience API for watching bus names.
|
||||
*
|
||||
* <example id="gdbus-watching-names"><title>Simple application watching a name</title><programlisting><xi:include xmlns:xi="http://www.w3.org/2001/XInclude" parse="text" href="../../../../gio/tests/gdbus-example-watch-name.c"><xi:fallback>FIXME: MISSING XINCLUDE CONTENT</xi:fallback></xi:include></programlisting></example>
|
||||
*/
|
||||
|
||||
G_LOCK_DEFINE_STATIC (lock);
|
||||
|
||||
/* ---------------------------------------------------------------------------------------------------- */
|
||||
|
||||
typedef enum
|
||||
{
|
||||
PREVIOUS_CALL_NONE = 0,
|
||||
PREVIOUS_CALL_APPEARED,
|
||||
PREVIOUS_CALL_VANISHED,
|
||||
} PreviousCall;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
volatile gint ref_count;
|
||||
guint id;
|
||||
gchar *name;
|
||||
GBusNameWatcherFlags flags;
|
||||
gchar *name_owner;
|
||||
GBusNameAppearedCallback name_appeared_handler;
|
||||
GBusNameVanishedCallback name_vanished_handler;
|
||||
gpointer user_data;
|
||||
GDestroyNotify user_data_free_func;
|
||||
GMainContext *main_context;
|
||||
|
||||
GDBusConnection *connection;
|
||||
gulong disconnected_signal_handler_id;
|
||||
guint name_owner_changed_subscription_id;
|
||||
|
||||
PreviousCall previous_call;
|
||||
|
||||
gboolean cancelled;
|
||||
gboolean initialized;
|
||||
} Client;
|
||||
|
||||
static guint next_global_id = 1;
|
||||
static GHashTable *map_id_to_client = NULL;
|
||||
|
||||
static Client *
|
||||
client_ref (Client *client)
|
||||
{
|
||||
g_atomic_int_inc (&client->ref_count);
|
||||
return client;
|
||||
}
|
||||
|
||||
static void
|
||||
client_unref (Client *client)
|
||||
{
|
||||
if (g_atomic_int_dec_and_test (&client->ref_count))
|
||||
{
|
||||
if (client->connection != NULL)
|
||||
{
|
||||
if (client->name_owner_changed_subscription_id > 0)
|
||||
g_dbus_connection_signal_unsubscribe (client->connection, client->name_owner_changed_subscription_id);
|
||||
if (client->disconnected_signal_handler_id > 0)
|
||||
g_signal_handler_disconnect (client->connection, client->disconnected_signal_handler_id);
|
||||
g_object_unref (client->connection);
|
||||
}
|
||||
g_free (client->name);
|
||||
g_free (client->name_owner);
|
||||
if (client->main_context != NULL)
|
||||
g_main_context_unref (client->main_context);
|
||||
if (client->user_data_free_func != NULL)
|
||||
client->user_data_free_func (client->user_data);
|
||||
g_free (client);
|
||||
}
|
||||
}
|
||||
|
||||
/* ---------------------------------------------------------------------------------------------------- */
|
||||
|
||||
typedef enum
|
||||
{
|
||||
CALL_TYPE_NAME_APPEARED,
|
||||
CALL_TYPE_NAME_VANISHED
|
||||
} CallType;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
Client *client;
|
||||
|
||||
/* keep this separate because client->connection may
|
||||
* be set to NULL after scheduling the call
|
||||
*/
|
||||
GDBusConnection *connection;
|
||||
|
||||
/* ditto */
|
||||
gchar *name_owner;
|
||||
|
||||
CallType call_type;
|
||||
} CallHandlerData;
|
||||
|
||||
static void
|
||||
call_handler_data_free (CallHandlerData *data)
|
||||
{
|
||||
if (data->connection != NULL)
|
||||
g_object_unref (data->connection);
|
||||
g_free (data->name_owner);
|
||||
client_unref (data->client);
|
||||
g_free (data);
|
||||
}
|
||||
|
||||
static void
|
||||
actually_do_call (Client *client, GDBusConnection *connection, const gchar *name_owner, CallType call_type)
|
||||
{
|
||||
switch (call_type)
|
||||
{
|
||||
case CALL_TYPE_NAME_APPEARED:
|
||||
if (client->name_appeared_handler != NULL)
|
||||
{
|
||||
client->name_appeared_handler (connection,
|
||||
client->name,
|
||||
name_owner,
|
||||
client->user_data);
|
||||
}
|
||||
break;
|
||||
|
||||
case CALL_TYPE_NAME_VANISHED:
|
||||
if (client->name_vanished_handler != NULL)
|
||||
{
|
||||
client->name_vanished_handler (connection,
|
||||
client->name,
|
||||
client->user_data);
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
g_assert_not_reached ();
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static gboolean
|
||||
call_in_idle_cb (gpointer _data)
|
||||
{
|
||||
CallHandlerData *data = _data;
|
||||
actually_do_call (data->client, data->connection, data->name_owner, data->call_type);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
static void
|
||||
schedule_call_in_idle (Client *client, CallType call_type)
|
||||
{
|
||||
CallHandlerData *data;
|
||||
GSource *idle_source;
|
||||
|
||||
data = g_new0 (CallHandlerData, 1);
|
||||
data->client = client_ref (client);
|
||||
data->connection = client->connection != NULL ? g_object_ref (client->connection) : NULL;
|
||||
data->name_owner = g_strdup (client->name_owner);
|
||||
data->call_type = call_type;
|
||||
|
||||
idle_source = g_idle_source_new ();
|
||||
g_source_set_priority (idle_source, G_PRIORITY_HIGH);
|
||||
g_source_set_callback (idle_source,
|
||||
call_in_idle_cb,
|
||||
data,
|
||||
(GDestroyNotify) call_handler_data_free);
|
||||
g_source_attach (idle_source, client->main_context);
|
||||
g_source_unref (idle_source);
|
||||
}
|
||||
|
||||
static void
|
||||
do_call (Client *client, CallType call_type)
|
||||
{
|
||||
/* only schedule in idle if we're not in the right thread */
|
||||
if (g_main_context_get_thread_default () != client->main_context)
|
||||
schedule_call_in_idle (client, call_type);
|
||||
else
|
||||
actually_do_call (client, client->connection, client->name_owner, call_type);
|
||||
}
|
||||
|
||||
static void
|
||||
call_appeared_handler (Client *client)
|
||||
{
|
||||
if (client->previous_call != PREVIOUS_CALL_APPEARED)
|
||||
{
|
||||
client->previous_call = PREVIOUS_CALL_APPEARED;
|
||||
if (!client->cancelled && client->name_appeared_handler != NULL)
|
||||
{
|
||||
do_call (client, CALL_TYPE_NAME_APPEARED);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
call_vanished_handler (Client *client,
|
||||
gboolean ignore_cancelled)
|
||||
{
|
||||
if (client->previous_call != PREVIOUS_CALL_VANISHED)
|
||||
{
|
||||
client->previous_call = PREVIOUS_CALL_VANISHED;
|
||||
if (((!client->cancelled) || ignore_cancelled) && client->name_vanished_handler != NULL)
|
||||
{
|
||||
do_call (client, CALL_TYPE_NAME_VANISHED);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* ---------------------------------------------------------------------------------------------------- */
|
||||
|
||||
static void
|
||||
on_connection_disconnected (GDBusConnection *connection,
|
||||
gboolean remote_peer_vanished,
|
||||
GError *error,
|
||||
gpointer user_data)
|
||||
{
|
||||
Client *client = user_data;
|
||||
|
||||
if (client->name_owner_changed_subscription_id > 0)
|
||||
g_dbus_connection_signal_unsubscribe (client->connection, client->name_owner_changed_subscription_id);
|
||||
if (client->disconnected_signal_handler_id > 0)
|
||||
g_signal_handler_disconnect (client->connection, client->disconnected_signal_handler_id);
|
||||
g_object_unref (client->connection);
|
||||
client->disconnected_signal_handler_id = 0;
|
||||
client->name_owner_changed_subscription_id = 0;
|
||||
client->connection = NULL;
|
||||
|
||||
call_vanished_handler (client, FALSE);
|
||||
}
|
||||
|
||||
/* ---------------------------------------------------------------------------------------------------- */
|
||||
|
||||
static void
|
||||
on_name_owner_changed (GDBusConnection *connection,
|
||||
const gchar *sender_name,
|
||||
const gchar *object_path,
|
||||
const gchar *interface_name,
|
||||
const gchar *signal_name,
|
||||
GVariant *parameters,
|
||||
gpointer user_data)
|
||||
{
|
||||
Client *client = user_data;
|
||||
const gchar *name;
|
||||
const gchar *old_owner;
|
||||
const gchar *new_owner;
|
||||
|
||||
if (!client->initialized)
|
||||
goto out;
|
||||
|
||||
if (g_strcmp0 (object_path, "/org/freedesktop/DBus") != 0 ||
|
||||
g_strcmp0 (interface_name, "org.freedesktop.DBus") != 0 ||
|
||||
g_strcmp0 (sender_name, "org.freedesktop.DBus") != 0)
|
||||
goto out;
|
||||
|
||||
g_variant_get (parameters,
|
||||
"(&s&s&s)",
|
||||
&name,
|
||||
&old_owner,
|
||||
&new_owner);
|
||||
|
||||
/* we only care about a specific name */
|
||||
if (g_strcmp0 (name, client->name) != 0)
|
||||
goto out;
|
||||
|
||||
if ((old_owner != NULL && strlen (old_owner) > 0) && client->name_owner != NULL)
|
||||
{
|
||||
g_free (client->name_owner);
|
||||
client->name_owner = NULL;
|
||||
call_vanished_handler (client, FALSE);
|
||||
}
|
||||
|
||||
if (new_owner != NULL && strlen (new_owner) > 0)
|
||||
{
|
||||
g_warn_if_fail (client->name_owner == NULL);
|
||||
g_free (client->name_owner);
|
||||
client->name_owner = g_strdup (new_owner);
|
||||
call_appeared_handler (client);
|
||||
}
|
||||
|
||||
out:
|
||||
;
|
||||
}
|
||||
|
||||
/* ---------------------------------------------------------------------------------------------------- */
|
||||
|
||||
static void
|
||||
get_name_owner_cb (GObject *source_object,
|
||||
GAsyncResult *res,
|
||||
gpointer user_data)
|
||||
{
|
||||
Client *client = user_data;
|
||||
GVariant *result;
|
||||
const char *name_owner;
|
||||
|
||||
name_owner = NULL;
|
||||
result = NULL;
|
||||
|
||||
result = g_dbus_connection_call_finish (client->connection,
|
||||
res,
|
||||
NULL);
|
||||
if (result != NULL)
|
||||
{
|
||||
g_variant_get (result, "(&s)", &name_owner);
|
||||
}
|
||||
|
||||
if (name_owner != NULL)
|
||||
{
|
||||
g_warn_if_fail (client->name_owner == NULL);
|
||||
client->name_owner = g_strdup (name_owner);
|
||||
call_appeared_handler (client);
|
||||
}
|
||||
else
|
||||
{
|
||||
call_vanished_handler (client, FALSE);
|
||||
}
|
||||
|
||||
client->initialized = TRUE;
|
||||
|
||||
if (result != NULL)
|
||||
g_variant_unref (result);
|
||||
client_unref (client);
|
||||
}
|
||||
|
||||
/* ---------------------------------------------------------------------------------------------------- */
|
||||
|
||||
static void
|
||||
invoke_get_name_owner (Client *client)
|
||||
{
|
||||
g_dbus_connection_call (client->connection,
|
||||
"org.freedesktop.DBus", /* bus name */
|
||||
"/org/freedesktop/DBus", /* object path */
|
||||
"org.freedesktop.DBus", /* interface name */
|
||||
"GetNameOwner", /* method name */
|
||||
g_variant_new ("(s)", client->name),
|
||||
G_DBUS_CALL_FLAGS_NONE,
|
||||
-1,
|
||||
NULL,
|
||||
(GAsyncReadyCallback) get_name_owner_cb,
|
||||
client_ref (client));
|
||||
}
|
||||
|
||||
/* ---------------------------------------------------------------------------------------------------- */
|
||||
|
||||
static void
|
||||
start_service_by_name_cb (GObject *source_object,
|
||||
GAsyncResult *res,
|
||||
gpointer user_data)
|
||||
{
|
||||
Client *client = user_data;
|
||||
GVariant *result;
|
||||
|
||||
result = NULL;
|
||||
|
||||
result = g_dbus_connection_call_finish (client->connection,
|
||||
res,
|
||||
NULL);
|
||||
if (result != NULL)
|
||||
{
|
||||
guint32 start_service_result;
|
||||
g_variant_get (result, "(u)", &start_service_result);
|
||||
|
||||
if (start_service_result == 1) /* DBUS_START_REPLY_SUCCESS */
|
||||
{
|
||||
invoke_get_name_owner (client);
|
||||
}
|
||||
else if (start_service_result == 2) /* DBUS_START_REPLY_ALREADY_RUNNING */
|
||||
{
|
||||
invoke_get_name_owner (client);
|
||||
}
|
||||
else
|
||||
{
|
||||
g_warning ("Unexpected reply %d from StartServiceByName() method", start_service_result);
|
||||
call_vanished_handler (client, FALSE);
|
||||
client->initialized = TRUE;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Errors are not unexpected; the bus will reply e.g.
|
||||
*
|
||||
* org.freedesktop.DBus.Error.ServiceUnknown: The name org.gnome.Epiphany2
|
||||
* was not provided by any .service files
|
||||
*
|
||||
* This doesn't mean that the name doesn't have an owner, just
|
||||
* that it's not provided by a .service file. So proceed to
|
||||
* invoke GetNameOwner().
|
||||
*/
|
||||
invoke_get_name_owner (client);
|
||||
}
|
||||
|
||||
if (result != NULL)
|
||||
g_variant_unref (result);
|
||||
client_unref (client);
|
||||
}
|
||||
|
||||
/* ---------------------------------------------------------------------------------------------------- */
|
||||
|
||||
static void
|
||||
has_connection (Client *client)
|
||||
{
|
||||
/* listen for disconnection */
|
||||
client->disconnected_signal_handler_id = g_signal_connect (client->connection,
|
||||
"closed",
|
||||
G_CALLBACK (on_connection_disconnected),
|
||||
client);
|
||||
|
||||
/* start listening to NameOwnerChanged messages immediately */
|
||||
client->name_owner_changed_subscription_id = g_dbus_connection_signal_subscribe (client->connection,
|
||||
"org.freedesktop.DBus", /* name */
|
||||
"org.freedesktop.DBus", /* if */
|
||||
"NameOwnerChanged", /* signal */
|
||||
"/org/freedesktop/DBus", /* path */
|
||||
client->name,
|
||||
on_name_owner_changed,
|
||||
client,
|
||||
NULL);
|
||||
|
||||
if (client->flags & G_BUS_NAME_WATCHER_FLAGS_AUTO_START)
|
||||
{
|
||||
g_dbus_connection_call (client->connection,
|
||||
"org.freedesktop.DBus", /* bus name */
|
||||
"/org/freedesktop/DBus", /* object path */
|
||||
"org.freedesktop.DBus", /* interface name */
|
||||
"StartServiceByName", /* method name */
|
||||
g_variant_new ("(su)", client->name, 0),
|
||||
G_DBUS_CALL_FLAGS_NONE,
|
||||
-1,
|
||||
NULL,
|
||||
(GAsyncReadyCallback) start_service_by_name_cb,
|
||||
client_ref (client));
|
||||
}
|
||||
else
|
||||
{
|
||||
/* check owner */
|
||||
invoke_get_name_owner (client);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
connection_get_cb (GObject *source_object,
|
||||
GAsyncResult *res,
|
||||
gpointer user_data)
|
||||
{
|
||||
Client *client = user_data;
|
||||
|
||||
client->connection = g_bus_get_finish (res, NULL);
|
||||
if (client->connection == NULL)
|
||||
{
|
||||
call_vanished_handler (client, FALSE);
|
||||
goto out;
|
||||
}
|
||||
|
||||
has_connection (client);
|
||||
|
||||
out:
|
||||
client_unref (client);
|
||||
}
|
||||
|
||||
/* ---------------------------------------------------------------------------------------------------- */
|
||||
|
||||
/**
|
||||
* g_bus_watch_name:
|
||||
* @bus_type: The type of bus to watch a name on.
|
||||
* @name: The name (well-known or unique) to watch.
|
||||
* @flags: Flags from the #GBusNameWatcherFlags enumeration.
|
||||
* @name_appeared_handler: Handler to invoke when @name is known to exist or %NULL.
|
||||
* @name_vanished_handler: Handler to invoke when @name is known to not exist or %NULL.
|
||||
* @user_data: User data to pass to handlers.
|
||||
* @user_data_free_func: Function for freeing @user_data or %NULL.
|
||||
*
|
||||
* Starts watching @name on the bus specified by @bus_type and calls
|
||||
* @name_appeared_handler and @name_vanished_handler when the name is
|
||||
* known to have a owner respectively known to lose its
|
||||
* owner. Callbacks will be invoked in the <link
|
||||
* linkend="g-main-context-push-thread-default">thread-default main
|
||||
* loop</link> of the thread you are calling this function from.
|
||||
*
|
||||
* You are guaranteed that one of the handlers will be invoked after
|
||||
* calling this function. When you are done watching the name, just
|
||||
* call g_bus_unwatch_name() with the watcher id this function
|
||||
* returns.
|
||||
*
|
||||
* If the name vanishes or appears (for example the application owning
|
||||
* the name could restart), the handlers are also invoked. If the
|
||||
* #GDBusConnection that is used for watching the name disconnects, then
|
||||
* @name_vanished_handler is invoked since it is no longer
|
||||
* possible to access the name.
|
||||
*
|
||||
* Another guarantee is that invocations of @name_appeared_handler
|
||||
* and @name_vanished_handler are guaranteed to alternate; that
|
||||
* is, if @name_appeared_handler is invoked then you are
|
||||
* guaranteed that the next time one of the handlers is invoked, it
|
||||
* will be @name_vanished_handler. The reverse is also true.
|
||||
*
|
||||
* This behavior makes it very simple to write applications that wants
|
||||
* to take action when a certain name exists, see <xref
|
||||
* linkend="gdbus-watching-names"/>. Basically, the application
|
||||
* should create object proxies in @name_appeared_handler and destroy
|
||||
* them again (if any) in @name_vanished_handler.
|
||||
*
|
||||
* Returns: An identifier (never 0) that an be used with
|
||||
* g_bus_unwatch_name() to stop watching the name.
|
||||
*
|
||||
* Since: 2.26
|
||||
*/
|
||||
guint
|
||||
g_bus_watch_name (GBusType bus_type,
|
||||
const gchar *name,
|
||||
GBusNameWatcherFlags flags,
|
||||
GBusNameAppearedCallback name_appeared_handler,
|
||||
GBusNameVanishedCallback name_vanished_handler,
|
||||
gpointer user_data,
|
||||
GDestroyNotify user_data_free_func)
|
||||
{
|
||||
Client *client;
|
||||
|
||||
g_return_val_if_fail (g_dbus_is_name (name), 0);
|
||||
|
||||
G_LOCK (lock);
|
||||
|
||||
client = g_new0 (Client, 1);
|
||||
client->ref_count = 1;
|
||||
client->id = next_global_id++; /* TODO: uh oh, handle overflow */
|
||||
client->name = g_strdup (name);
|
||||
client->flags = flags;
|
||||
client->name_appeared_handler = name_appeared_handler;
|
||||
client->name_vanished_handler = name_vanished_handler;
|
||||
client->user_data = user_data;
|
||||
client->user_data_free_func = user_data_free_func;
|
||||
client->main_context = g_main_context_get_thread_default ();
|
||||
if (client->main_context != NULL)
|
||||
g_main_context_ref (client->main_context);
|
||||
|
||||
if (map_id_to_client == NULL)
|
||||
{
|
||||
map_id_to_client = g_hash_table_new (g_direct_hash, g_direct_equal);
|
||||
}
|
||||
g_hash_table_insert (map_id_to_client,
|
||||
GUINT_TO_POINTER (client->id),
|
||||
client);
|
||||
|
||||
g_bus_get (bus_type,
|
||||
NULL,
|
||||
connection_get_cb,
|
||||
client_ref (client));
|
||||
|
||||
G_UNLOCK (lock);
|
||||
|
||||
return client->id;
|
||||
}
|
||||
|
||||
/**
|
||||
* g_bus_watch_name_on_connection:
|
||||
* @connection: A #GDBusConnection that is not closed.
|
||||
* @name: The name (well-known or unique) to watch.
|
||||
* @flags: Flags from the #GBusNameWatcherFlags enumeration.
|
||||
* @name_appeared_handler: Handler to invoke when @name is known to exist or %NULL.
|
||||
* @name_vanished_handler: Handler to invoke when @name is known to not exist or %NULL.
|
||||
* @user_data: User data to pass to handlers.
|
||||
* @user_data_free_func: Function for freeing @user_data or %NULL.
|
||||
*
|
||||
* Like g_bus_watch_name() but takes a #GDBusConnection instead of a
|
||||
* #GBusType.
|
||||
*
|
||||
* Returns: An identifier (never 0) that an be used with
|
||||
* g_bus_unwatch_name() to stop watching the name.
|
||||
*
|
||||
* Since: 2.26
|
||||
*/
|
||||
guint g_bus_watch_name_on_connection (GDBusConnection *connection,
|
||||
const gchar *name,
|
||||
GBusNameWatcherFlags flags,
|
||||
GBusNameAppearedCallback name_appeared_handler,
|
||||
GBusNameVanishedCallback name_vanished_handler,
|
||||
gpointer user_data,
|
||||
GDestroyNotify user_data_free_func)
|
||||
{
|
||||
Client *client;
|
||||
|
||||
g_return_val_if_fail (G_IS_DBUS_CONNECTION (connection), 0);
|
||||
g_return_val_if_fail (g_dbus_is_name (name), 0);
|
||||
|
||||
G_LOCK (lock);
|
||||
|
||||
client = g_new0 (Client, 1);
|
||||
client->ref_count = 1;
|
||||
client->id = next_global_id++; /* TODO: uh oh, handle overflow */
|
||||
client->name = g_strdup (name);
|
||||
client->flags = flags;
|
||||
client->name_appeared_handler = name_appeared_handler;
|
||||
client->name_vanished_handler = name_vanished_handler;
|
||||
client->user_data = user_data;
|
||||
client->user_data_free_func = user_data_free_func;
|
||||
client->main_context = g_main_context_get_thread_default ();
|
||||
if (client->main_context != NULL)
|
||||
g_main_context_ref (client->main_context);
|
||||
|
||||
if (map_id_to_client == NULL)
|
||||
{
|
||||
map_id_to_client = g_hash_table_new (g_direct_hash, g_direct_equal);
|
||||
}
|
||||
g_hash_table_insert (map_id_to_client,
|
||||
GUINT_TO_POINTER (client->id),
|
||||
client);
|
||||
|
||||
client->connection = g_object_ref (connection);
|
||||
G_UNLOCK (lock);
|
||||
|
||||
has_connection (client);
|
||||
|
||||
return client->id;
|
||||
}
|
||||
|
||||
/**
|
||||
* g_bus_unwatch_name:
|
||||
* @watcher_id: An identifier obtained from g_bus_watch_name()
|
||||
*
|
||||
* Stops watching a name.
|
||||
*
|
||||
* Since: 2.26
|
||||
*/
|
||||
void
|
||||
g_bus_unwatch_name (guint watcher_id)
|
||||
{
|
||||
Client *client;
|
||||
|
||||
g_return_if_fail (watcher_id > 0);
|
||||
|
||||
client = NULL;
|
||||
|
||||
G_LOCK (lock);
|
||||
if (watcher_id == 0 ||
|
||||
map_id_to_client == NULL ||
|
||||
(client = g_hash_table_lookup (map_id_to_client, GUINT_TO_POINTER (watcher_id))) == NULL)
|
||||
{
|
||||
g_warning ("Invalid id %d passed to g_bus_unwatch_name()", watcher_id);
|
||||
goto out;
|
||||
}
|
||||
|
||||
client->cancelled = TRUE;
|
||||
g_warn_if_fail (g_hash_table_remove (map_id_to_client, GUINT_TO_POINTER (watcher_id)));
|
||||
|
||||
out:
|
||||
G_UNLOCK (lock);
|
||||
|
||||
/* do callback without holding lock */
|
||||
if (client != NULL)
|
||||
{
|
||||
client_unref (client);
|
||||
}
|
||||
}
|
||||
|
||||
#define __G_DBUS_NAME_WATCHING_C__
|
||||
#include "gioaliasdef.c"
|
79
gio/gdbusnamewatching.h
Normal file
79
gio/gdbusnamewatching.h
Normal file
@ -0,0 +1,79 @@
|
||||
/* GDBus - GLib D-Bus Library
|
||||
*
|
||||
* Copyright (C) 2008-2010 Red Hat, Inc.
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General
|
||||
* Public License along with this library; if not, write to the
|
||||
* Free Software Foundation, Inc., 59 Temple Place, Suite 330,
|
||||
* Boston, MA 02111-1307, USA.
|
||||
*
|
||||
* Author: David Zeuthen <davidz@redhat.com>
|
||||
*/
|
||||
|
||||
#ifndef __G_DBUS_NAME_WATCHING_H__
|
||||
#define __G_DBUS_NAME_WATCHING_H__
|
||||
|
||||
#include <gio/giotypes.h>
|
||||
|
||||
G_BEGIN_DECLS
|
||||
|
||||
/**
|
||||
* GBusNameAppearedCallback:
|
||||
* @connection: The #GDBusConnection the name is being watched on.
|
||||
* @name: The name being watched.
|
||||
* @name_owner: Unique name of the owner of the name being watched.
|
||||
* @user_data: User data passed to g_bus_watch_name().
|
||||
*
|
||||
* Invoked when the name being watched is known to have to have a owner.
|
||||
*
|
||||
* Since: 2.26
|
||||
*/
|
||||
typedef void (*GBusNameAppearedCallback) (GDBusConnection *connection,
|
||||
const gchar *name,
|
||||
const gchar *name_owner,
|
||||
gpointer user_data);
|
||||
|
||||
/**
|
||||
* GBusNameVanishedCallback:
|
||||
* @connection: The #GDBusConnection the name is being watched on.
|
||||
* @name: The name being watched.
|
||||
* @user_data: User data passed to g_bus_watch_name().
|
||||
*
|
||||
* Invoked when the name being watched is known not to have to have a owner.
|
||||
*
|
||||
* Since: 2.26
|
||||
*/
|
||||
typedef void (*GBusNameVanishedCallback) (GDBusConnection *connection,
|
||||
const gchar *name,
|
||||
gpointer user_data);
|
||||
|
||||
|
||||
guint g_bus_watch_name (GBusType bus_type,
|
||||
const gchar *name,
|
||||
GBusNameWatcherFlags flags,
|
||||
GBusNameAppearedCallback name_appeared_handler,
|
||||
GBusNameVanishedCallback name_vanished_handler,
|
||||
gpointer user_data,
|
||||
GDestroyNotify user_data_free_func);
|
||||
guint g_bus_watch_name_on_connection (GDBusConnection *connection,
|
||||
const gchar *name,
|
||||
GBusNameWatcherFlags flags,
|
||||
GBusNameAppearedCallback name_appeared_handler,
|
||||
GBusNameVanishedCallback name_vanished_handler,
|
||||
gpointer user_data,
|
||||
GDestroyNotify user_data_free_func);
|
||||
void g_bus_unwatch_name (guint watcher_id);
|
||||
|
||||
G_END_DECLS
|
||||
|
||||
#endif /* __G_DBUS_NAME_WATCHING_H__ */
|
1057
gio/gdbusprivate.c
Normal file
1057
gio/gdbusprivate.c
Normal file
File diff suppressed because it is too large
Load Diff
83
gio/gdbusprivate.h
Normal file
83
gio/gdbusprivate.h
Normal file
@ -0,0 +1,83 @@
|
||||
/* GDBus - GLib D-Bus Library
|
||||
*
|
||||
* Copyright (C) 2008-2010 Red Hat, Inc.
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General
|
||||
* Public License along with this library; if not, write to the
|
||||
* Free Software Foundation, Inc., 59 Temple Place, Suite 330,
|
||||
* Boston, MA 02111-1307, USA.
|
||||
*
|
||||
* Author: David Zeuthen <davidz@redhat.com>
|
||||
*/
|
||||
|
||||
#if !defined (GIO_COMPILATION)
|
||||
#error "gdbusprivate.h is a private header file."
|
||||
#endif
|
||||
|
||||
#ifndef __G_DBUS_PRIVATE_H__
|
||||
#define __G_DBUS_PRIVATE_H__
|
||||
|
||||
#include <gio/giotypes.h>
|
||||
|
||||
G_BEGIN_DECLS
|
||||
|
||||
/* ---------------------------------------------------------------------------------------------------- */
|
||||
|
||||
typedef struct GDBusWorker GDBusWorker;
|
||||
|
||||
typedef void (*GDBusWorkerMessageReceivedCallback) (GDBusWorker *worker,
|
||||
GDBusMessage *message,
|
||||
gpointer user_data);
|
||||
|
||||
typedef void (*GDBusWorkerDisconnectedCallback) (GDBusWorker *worker,
|
||||
gboolean remote_peer_vanished,
|
||||
GError *error,
|
||||
gpointer user_data);
|
||||
|
||||
/* This function may be called from any thread - callbacks will be in the shared private message thread
|
||||
* and must not block.
|
||||
*/
|
||||
GDBusWorker *_g_dbus_worker_new (GIOStream *stream,
|
||||
GDBusCapabilityFlags capabilities,
|
||||
GDBusWorkerMessageReceivedCallback message_received_callback,
|
||||
GDBusWorkerDisconnectedCallback disconnected_callback,
|
||||
gpointer user_data);
|
||||
|
||||
/* can be called from any thread - steals blob */
|
||||
void _g_dbus_worker_send_message (GDBusWorker *worker,
|
||||
GDBusMessage *message,
|
||||
gchar *blob,
|
||||
gsize blob_len);
|
||||
|
||||
/* can be called from any thread */
|
||||
void _g_dbus_worker_stop (GDBusWorker *worker);
|
||||
|
||||
/* ---------------------------------------------------------------------------------------------------- */
|
||||
|
||||
void _g_dbus_initialize (void);
|
||||
gboolean _g_dbus_debug_authentication (void);
|
||||
gboolean _g_dbus_debug_message (void);
|
||||
|
||||
gboolean _g_dbus_address_parse_entry (const gchar *address_entry,
|
||||
gchar **out_transport_name,
|
||||
GHashTable **out_key_value_pairs,
|
||||
GError **error);
|
||||
|
||||
gchar * _g_dbus_compute_complete_signature (GDBusArgInfo **args,
|
||||
gboolean include_parentheses);
|
||||
|
||||
/* ---------------------------------------------------------------------------------------------------- */
|
||||
|
||||
G_END_DECLS
|
||||
|
||||
#endif /* __G_DBUS_PRIVATE_H__ */
|
1714
gio/gdbusproxy.c
Normal file
1714
gio/gdbusproxy.c
Normal file
File diff suppressed because it is too large
Load Diff
152
gio/gdbusproxy.h
Normal file
152
gio/gdbusproxy.h
Normal file
@ -0,0 +1,152 @@
|
||||
/* GDBus - GLib D-Bus Library
|
||||
*
|
||||
* Copyright (C) 2008-2010 Red Hat, Inc.
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General
|
||||
* Public License along with this library; if not, write to the
|
||||
* Free Software Foundation, Inc., 59 Temple Place, Suite 330,
|
||||
* Boston, MA 02111-1307, USA.
|
||||
*
|
||||
* Author: David Zeuthen <davidz@redhat.com>
|
||||
*/
|
||||
|
||||
#ifndef __G_DBUS_PROXY_H__
|
||||
#define __G_DBUS_PROXY_H__
|
||||
|
||||
#include <gio/giotypes.h>
|
||||
#include <gio/gdbusintrospection.h>
|
||||
|
||||
G_BEGIN_DECLS
|
||||
|
||||
#define G_TYPE_DBUS_PROXY (g_dbus_proxy_get_type ())
|
||||
#define G_DBUS_PROXY(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), G_TYPE_DBUS_PROXY, GDBusProxy))
|
||||
#define G_DBUS_PROXY_CLASS(k) (G_TYPE_CHECK_CLASS_CAST((k), G_TYPE_DBUS_PROXY, GDBusProxyClass))
|
||||
#define G_DBUS_PROXY_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS ((o), G_TYPE_DBUS_PROXY, GDBusProxyClass))
|
||||
#define G_IS_DBUS_PROXY(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), G_TYPE_DBUS_PROXY))
|
||||
#define G_IS_DBUS_PROXY_CLASS(k) (G_TYPE_CHECK_CLASS_TYPE ((k), G_TYPE_DBUS_PROXY))
|
||||
|
||||
typedef struct _GDBusProxyClass GDBusProxyClass;
|
||||
typedef struct _GDBusProxyPrivate GDBusProxyPrivate;
|
||||
|
||||
/**
|
||||
* GDBusProxy:
|
||||
*
|
||||
* The #GDBusProxy structure contains only private data and
|
||||
* should only be accessed using the provided API.
|
||||
*
|
||||
* Since: 2.26
|
||||
*/
|
||||
struct _GDBusProxy
|
||||
{
|
||||
/*< private >*/
|
||||
GObject parent_instance;
|
||||
GDBusProxyPrivate *priv;
|
||||
};
|
||||
|
||||
/**
|
||||
* GDBusProxyClass:
|
||||
* @g_properties_changed: Signal class handler for the #GDBusProxy::g-properties-changed signal.
|
||||
* @g_signal: Signal class handler for the #GDBusProxy::g-signal signal.
|
||||
*
|
||||
* Class structure for #GDBusProxy.
|
||||
*
|
||||
* Since: 2.26
|
||||
*/
|
||||
struct _GDBusProxyClass
|
||||
{
|
||||
/*< private >*/
|
||||
GObjectClass parent_class;
|
||||
|
||||
/*< public >*/
|
||||
/* Signals */
|
||||
void (*g_properties_changed) (GDBusProxy *proxy,
|
||||
GVariant *changed_properties,
|
||||
const gchar* const *invalidated_properties);
|
||||
void (*g_signal) (GDBusProxy *proxy,
|
||||
const gchar *sender_name,
|
||||
const gchar *signal_name,
|
||||
GVariant *parameters);
|
||||
|
||||
/*< private >*/
|
||||
/* Padding for future expansion */
|
||||
void (*_g_reserved1) (void);
|
||||
void (*_g_reserved2) (void);
|
||||
void (*_g_reserved3) (void);
|
||||
void (*_g_reserved4) (void);
|
||||
void (*_g_reserved5) (void);
|
||||
void (*_g_reserved6) (void);
|
||||
void (*_g_reserved7) (void);
|
||||
void (*_g_reserved8) (void);
|
||||
};
|
||||
|
||||
GType g_dbus_proxy_get_type (void) G_GNUC_CONST;
|
||||
void g_dbus_proxy_new (GDBusConnection *connection,
|
||||
GType object_type,
|
||||
GDBusProxyFlags flags,
|
||||
GDBusInterfaceInfo *info,
|
||||
const gchar *unique_bus_name,
|
||||
const gchar *object_path,
|
||||
const gchar *interface_name,
|
||||
GCancellable *cancellable,
|
||||
GAsyncReadyCallback callback,
|
||||
gpointer user_data);
|
||||
GDBusProxy *g_dbus_proxy_new_finish (GAsyncResult *res,
|
||||
GError **error);
|
||||
GDBusProxy *g_dbus_proxy_new_sync (GDBusConnection *connection,
|
||||
GType object_type,
|
||||
GDBusProxyFlags flags,
|
||||
GDBusInterfaceInfo *info,
|
||||
const gchar *unique_bus_name,
|
||||
const gchar *object_path,
|
||||
const gchar *interface_name,
|
||||
GCancellable *cancellable,
|
||||
GError **error);
|
||||
GDBusConnection *g_dbus_proxy_get_connection (GDBusProxy *proxy);
|
||||
GDBusProxyFlags g_dbus_proxy_get_flags (GDBusProxy *proxy);
|
||||
const gchar *g_dbus_proxy_get_unique_bus_name (GDBusProxy *proxy);
|
||||
const gchar *g_dbus_proxy_get_object_path (GDBusProxy *proxy);
|
||||
const gchar *g_dbus_proxy_get_interface_name (GDBusProxy *proxy);
|
||||
gint g_dbus_proxy_get_default_timeout (GDBusProxy *proxy);
|
||||
void g_dbus_proxy_set_default_timeout (GDBusProxy *proxy,
|
||||
gint timeout_msec);
|
||||
GDBusInterfaceInfo *g_dbus_proxy_get_interface_info (GDBusProxy *proxy);
|
||||
void g_dbus_proxy_set_interface_info (GDBusProxy *proxy,
|
||||
GDBusInterfaceInfo *info);
|
||||
GVariant *g_dbus_proxy_get_cached_property (GDBusProxy *proxy,
|
||||
const gchar *property_name);
|
||||
void g_dbus_proxy_set_cached_property (GDBusProxy *proxy,
|
||||
const gchar *property_name,
|
||||
GVariant *value);
|
||||
gchar **g_dbus_proxy_get_cached_property_names (GDBusProxy *proxy);
|
||||
void g_dbus_proxy_call (GDBusProxy *proxy,
|
||||
const gchar *method_name,
|
||||
GVariant *parameters,
|
||||
GDBusCallFlags flags,
|
||||
gint timeout_msec,
|
||||
GCancellable *cancellable,
|
||||
GAsyncReadyCallback callback,
|
||||
gpointer user_data);
|
||||
GVariant *g_dbus_proxy_call_finish (GDBusProxy *proxy,
|
||||
GAsyncResult *res,
|
||||
GError **error);
|
||||
GVariant *g_dbus_proxy_call_sync (GDBusProxy *proxy,
|
||||
const gchar *method_name,
|
||||
GVariant *parameters,
|
||||
GDBusCallFlags flags,
|
||||
gint timeout_msec,
|
||||
GCancellable *cancellable,
|
||||
GError **error);
|
||||
|
||||
G_END_DECLS
|
||||
|
||||
#endif /* __G_DBUS_PROXY_H__ */
|
490
gio/gdbusproxywatching.c
Normal file
490
gio/gdbusproxywatching.c
Normal file
@ -0,0 +1,490 @@
|
||||
/* GDBus - GLib D-Bus Library
|
||||
*
|
||||
* Copyright (C) 2008-2010 Red Hat, Inc.
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General
|
||||
* Public License along with this library; if not, write to the
|
||||
* Free Software Foundation, Inc., 59 Temple Place, Suite 330,
|
||||
* Boston, MA 02111-1307, USA.
|
||||
*
|
||||
* Author: David Zeuthen <davidz@redhat.com>
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include <stdlib.h>
|
||||
|
||||
#include "gdbusutils.h"
|
||||
#include "gdbusconnection.h"
|
||||
#include "gdbusnamewatching.h"
|
||||
#include "gdbusproxywatching.h"
|
||||
#include "gdbuserror.h"
|
||||
#include "gdbusprivate.h"
|
||||
#include "gdbusproxy.h"
|
||||
#include "gdbusnamewatching.h"
|
||||
#include "gcancellable.h"
|
||||
|
||||
#include "glibintl.h"
|
||||
#include "gioalias.h"
|
||||
|
||||
/**
|
||||
* SECTION:gdbusproxywatching
|
||||
* @title: Watching Proxies
|
||||
* @short_description: Simple API for watching proxies
|
||||
* @include: gio/gio.h
|
||||
*
|
||||
* Convenience API for watching bus proxies.
|
||||
*
|
||||
* <example id="gdbus-watching-proxy"><title>Simple application watching a proxy</title><programlisting><xi:include xmlns:xi="http://www.w3.org/2001/XInclude" parse="text" href="../../../../gio/tests/gdbus-example-watch-proxy.c"><xi:fallback>FIXME: MISSING XINCLUDE CONTENT</xi:fallback></xi:include></programlisting></example>
|
||||
*/
|
||||
|
||||
/* ---------------------------------------------------------------------------------------------------- */
|
||||
|
||||
G_LOCK_DEFINE_STATIC (lock);
|
||||
|
||||
static guint next_global_id = 1;
|
||||
static GHashTable *map_id_to_client = NULL;
|
||||
|
||||
/* ---------------------------------------------------------------------------------------------------- */
|
||||
|
||||
typedef struct
|
||||
{
|
||||
guint id;
|
||||
GBusProxyAppearedCallback proxy_appeared_handler;
|
||||
GBusProxyVanishedCallback proxy_vanished_handler;
|
||||
gpointer user_data;
|
||||
GDestroyNotify user_data_free_func;
|
||||
GMainContext *main_context;
|
||||
|
||||
gchar *name;
|
||||
gchar *name_owner;
|
||||
GDBusConnection *connection;
|
||||
guint name_watcher_id;
|
||||
|
||||
GCancellable *cancellable;
|
||||
|
||||
gchar *object_path;
|
||||
gchar *interface_name;
|
||||
GType interface_type;
|
||||
GDBusProxyFlags proxy_flags;
|
||||
GDBusProxy *proxy;
|
||||
|
||||
gboolean initial_construction;
|
||||
} Client;
|
||||
|
||||
static void
|
||||
client_unref (Client *client)
|
||||
{
|
||||
/* ensure we're only called from g_bus_unwatch_proxy */
|
||||
g_assert (client->name_watcher_id == 0);
|
||||
|
||||
g_free (client->name_owner);
|
||||
if (client->connection != NULL)
|
||||
g_object_unref (client->connection);
|
||||
if (client->proxy != NULL)
|
||||
g_object_unref (client->proxy);
|
||||
|
||||
g_free (client->name);
|
||||
g_free (client->object_path);
|
||||
g_free (client->interface_name);
|
||||
|
||||
if (client->main_context != NULL)
|
||||
g_main_context_unref (client->main_context);
|
||||
|
||||
if (client->user_data_free_func != NULL)
|
||||
client->user_data_free_func (client->user_data);
|
||||
g_free (client);
|
||||
}
|
||||
|
||||
/* ---------------------------------------------------------------------------------------------------- */
|
||||
|
||||
static void
|
||||
proxy_constructed_cb (GObject *source_object,
|
||||
GAsyncResult *res,
|
||||
gpointer user_data)
|
||||
{
|
||||
Client *client = user_data;
|
||||
GDBusProxy *proxy;
|
||||
GError *error;
|
||||
|
||||
error = NULL;
|
||||
proxy = g_dbus_proxy_new_finish (res, &error);
|
||||
if (proxy == NULL)
|
||||
{
|
||||
/* g_warning ("error while constructing proxy: %s", error->message); */
|
||||
g_error_free (error);
|
||||
|
||||
/* handle initial construction, send out vanished if the name
|
||||
* is there but we constructing a proxy fails
|
||||
*/
|
||||
if (client->initial_construction)
|
||||
{
|
||||
if (client->proxy_vanished_handler != NULL)
|
||||
{
|
||||
client->proxy_vanished_handler (client->connection,
|
||||
client->name,
|
||||
client->user_data);
|
||||
}
|
||||
client->initial_construction = FALSE;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
g_assert (client->proxy == NULL);
|
||||
g_assert (client->cancellable != NULL);
|
||||
client->proxy = G_DBUS_PROXY (proxy);
|
||||
|
||||
g_object_unref (client->cancellable);
|
||||
client->cancellable = NULL;
|
||||
|
||||
/* perform callback */
|
||||
if (client->proxy_appeared_handler != NULL)
|
||||
{
|
||||
client->proxy_appeared_handler (client->connection,
|
||||
client->name,
|
||||
client->name_owner,
|
||||
client->proxy,
|
||||
client->user_data);
|
||||
}
|
||||
client->initial_construction = FALSE;
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
on_name_appeared (GDBusConnection *connection,
|
||||
const gchar *name,
|
||||
const gchar *name_owner,
|
||||
gpointer user_data)
|
||||
{
|
||||
Client *client = user_data;
|
||||
|
||||
//g_debug ("\n\nname appeared (owner `%s')", name_owner);
|
||||
|
||||
/* invariants */
|
||||
g_assert (client->name_owner == NULL);
|
||||
g_assert (client->connection == NULL);
|
||||
g_assert (client->cancellable == NULL);
|
||||
|
||||
client->name_owner = g_strdup (name_owner);
|
||||
client->connection = g_object_ref (connection);
|
||||
client->cancellable = g_cancellable_new ();
|
||||
|
||||
g_dbus_proxy_new (client->connection,
|
||||
client->interface_type,
|
||||
client->proxy_flags,
|
||||
NULL, /* GDBusInterfaceInfo */
|
||||
client->name_owner,
|
||||
client->object_path,
|
||||
client->interface_name,
|
||||
client->cancellable,
|
||||
proxy_constructed_cb,
|
||||
client);
|
||||
}
|
||||
|
||||
static void
|
||||
on_name_vanished (GDBusConnection *connection,
|
||||
const gchar *name,
|
||||
gpointer user_data)
|
||||
{
|
||||
Client *client = user_data;
|
||||
|
||||
/*g_debug ("\n\nname vanished");*/
|
||||
|
||||
g_free (client->name_owner);
|
||||
if (client->connection != NULL)
|
||||
g_object_unref (client->connection);
|
||||
client->name_owner = NULL;
|
||||
client->connection = NULL;
|
||||
|
||||
/* free the proxy if we have it */
|
||||
if (client->proxy != NULL)
|
||||
{
|
||||
g_assert (client->cancellable == NULL);
|
||||
|
||||
g_object_unref (client->proxy);
|
||||
client->proxy = NULL;
|
||||
|
||||
/* if we have the proxy, it means we last sent out a 'appeared'
|
||||
* callback - so send out a 'vanished' callback
|
||||
*/
|
||||
if (client->proxy_vanished_handler != NULL)
|
||||
{
|
||||
client->proxy_vanished_handler (client->connection,
|
||||
client->name,
|
||||
client->user_data);
|
||||
}
|
||||
client->initial_construction = FALSE;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* otherwise cancel construction of the proxy if applicable */
|
||||
if (client->cancellable != NULL)
|
||||
{
|
||||
g_cancellable_cancel (client->cancellable);
|
||||
g_object_unref (client->cancellable);
|
||||
client->cancellable = NULL;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* handle initial construction, send out vanished if
|
||||
* the name isn't there
|
||||
*/
|
||||
if (client->initial_construction)
|
||||
{
|
||||
if (client->proxy_vanished_handler != NULL)
|
||||
{
|
||||
client->proxy_vanished_handler (client->connection,
|
||||
client->name,
|
||||
client->user_data);
|
||||
}
|
||||
client->initial_construction = FALSE;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* g_bus_watch_proxy:
|
||||
* @bus_type: The type of bus to watch a name on.
|
||||
* @name: The name (well-known or unique) to watch.
|
||||
* @flags: Flags from the #GBusNameWatcherFlags enumeration.
|
||||
* @object_path: The object path of the remote object to watch.
|
||||
* @interface_name: The D-Bus interface name for the proxy.
|
||||
* @interface_type: The #GType for the kind of proxy to create. This must be a #GDBusProxy derived type.
|
||||
* @proxy_flags: Flags from #GDBusProxyFlags to use when constructing the proxy.
|
||||
* @proxy_appeared_handler: Handler to invoke when @name is known to exist and the
|
||||
* requested proxy is available.
|
||||
* @proxy_vanished_handler: Handler to invoke when @name is known to not exist
|
||||
* and the previously created proxy is no longer available.
|
||||
* @user_data: User data to pass to handlers.
|
||||
* @user_data_free_func: Function for freeing @user_data or %NULL.
|
||||
*
|
||||
* Starts watching a remote object at @object_path owned by @name on
|
||||
* the bus specified by @bus_type. When the object is available, a
|
||||
* #GDBusProxy (or derived class cf. @interface_type) instance is
|
||||
* constructed for the @interface_name D-Bus interface and then
|
||||
* @proxy_appeared_handler will be called when the proxy is ready and
|
||||
* all properties have been loaded. When @name vanishes,
|
||||
* @proxy_vanished_handler is called.
|
||||
*
|
||||
* This function makes it very simple to write applications that wants
|
||||
* to watch a well-known remote object on a well-known name, see <xref
|
||||
* linkend="gdbus-watching-proxy"/>. Basically, the application simply
|
||||
* starts using the proxy when @proxy_appeared_handler is called and
|
||||
* stops using it when @proxy_vanished_handler is called. Callbacks
|
||||
* will be invoked in the <link
|
||||
* linkend="g-main-context-push-thread-default">thread-default main
|
||||
* loop</link> of the thread you are calling this function from.
|
||||
*
|
||||
* Applications typically use this function to watch the
|
||||
* <quote>manager</quote> object of a well-known name. Upon acquiring
|
||||
* a proxy for the manager object, applications typically construct
|
||||
* additional proxies in response to the result of enumeration methods
|
||||
* on the manager object.
|
||||
*
|
||||
* Many of the comments that apply to g_bus_watch_name() also apply
|
||||
* here. For example, you are guaranteed that one of the handlers will
|
||||
* be invoked (on the main thread) after calling this function and
|
||||
* also that the two handlers alternate. When you are done watching the
|
||||
* proxy, just call g_bus_unwatch_proxy().
|
||||
*
|
||||
* Returns: An identifier (never 0) that can be used with
|
||||
* g_bus_unwatch_proxy() to stop watching the remote object.
|
||||
*
|
||||
* Since: 2.26
|
||||
*/
|
||||
guint
|
||||
g_bus_watch_proxy (GBusType bus_type,
|
||||
const gchar *name,
|
||||
GBusNameWatcherFlags flags,
|
||||
const gchar *object_path,
|
||||
const gchar *interface_name,
|
||||
GType interface_type,
|
||||
GDBusProxyFlags proxy_flags,
|
||||
GBusProxyAppearedCallback proxy_appeared_handler,
|
||||
GBusProxyVanishedCallback proxy_vanished_handler,
|
||||
gpointer user_data,
|
||||
GDestroyNotify user_data_free_func)
|
||||
{
|
||||
Client *client;
|
||||
|
||||
g_return_val_if_fail (g_dbus_is_name (name), 0);
|
||||
g_return_val_if_fail (g_variant_is_object_path (object_path), 0);
|
||||
g_return_val_if_fail (g_dbus_is_interface_name (interface_name), 0);
|
||||
g_return_val_if_fail (g_type_is_a (interface_type, G_TYPE_DBUS_PROXY), 0);
|
||||
|
||||
G_LOCK (lock);
|
||||
|
||||
client = g_new0 (Client, 1);
|
||||
client->id = next_global_id++; /* TODO: uh oh, handle overflow */
|
||||
client->name = g_strdup (name);
|
||||
client->proxy_appeared_handler = proxy_appeared_handler;
|
||||
client->proxy_vanished_handler = proxy_vanished_handler;
|
||||
client->user_data = user_data;
|
||||
client->user_data_free_func = user_data_free_func;
|
||||
client->main_context = g_main_context_get_thread_default ();
|
||||
if (client->main_context != NULL)
|
||||
g_main_context_ref (client->main_context);
|
||||
client->name_watcher_id = g_bus_watch_name (bus_type,
|
||||
name,
|
||||
flags,
|
||||
on_name_appeared,
|
||||
on_name_vanished,
|
||||
client,
|
||||
NULL);
|
||||
|
||||
client->object_path = g_strdup (object_path);
|
||||
client->interface_name = g_strdup (interface_name);
|
||||
client->interface_type = interface_type;
|
||||
client->proxy_flags = proxy_flags;
|
||||
client->initial_construction = TRUE;
|
||||
|
||||
if (map_id_to_client == NULL)
|
||||
{
|
||||
map_id_to_client = g_hash_table_new (g_direct_hash, g_direct_equal);
|
||||
}
|
||||
g_hash_table_insert (map_id_to_client,
|
||||
GUINT_TO_POINTER (client->id),
|
||||
client);
|
||||
|
||||
G_UNLOCK (lock);
|
||||
|
||||
return client->id;
|
||||
}
|
||||
|
||||
/**
|
||||
* g_bus_watch_proxy_on_connection:
|
||||
* @connection: A #GDBusConnection that is not closed.
|
||||
* @name: The name (well-known or unique) to watch.
|
||||
* @flags: Flags from the #GBusNameWatcherFlags enumeration.
|
||||
* @object_path: The object path of the remote object to watch.
|
||||
* @interface_name: The D-Bus interface name for the proxy.
|
||||
* @interface_type: The #GType for the kind of proxy to create. This must be a #GDBusProxy derived type.
|
||||
* @proxy_flags: Flags from #GDBusProxyFlags to use when constructing the proxy.
|
||||
* @proxy_appeared_handler: Handler to invoke when @name is known to exist and the
|
||||
* requested proxy is available.
|
||||
* @proxy_vanished_handler: Handler to invoke when @name is known to not exist
|
||||
* and the previously created proxy is no longer available.
|
||||
* @user_data: User data to pass to handlers.
|
||||
* @user_data_free_func: Function for freeing @user_data or %NULL.
|
||||
*
|
||||
* Like g_bus_watch_proxy() but takes a #GDBusConnection instead of a
|
||||
* #GBusType.
|
||||
*
|
||||
* Returns: An identifier (never 0) that can be used with
|
||||
* g_bus_unwatch_proxy() to stop watching the remote object.
|
||||
*
|
||||
* Since: 2.26
|
||||
*/
|
||||
guint
|
||||
g_bus_watch_proxy_on_connection (GDBusConnection *connection,
|
||||
const gchar *name,
|
||||
GBusNameWatcherFlags flags,
|
||||
const gchar *object_path,
|
||||
const gchar *interface_name,
|
||||
GType interface_type,
|
||||
GDBusProxyFlags proxy_flags,
|
||||
GBusProxyAppearedCallback proxy_appeared_handler,
|
||||
GBusProxyVanishedCallback proxy_vanished_handler,
|
||||
gpointer user_data,
|
||||
GDestroyNotify user_data_free_func)
|
||||
{
|
||||
Client *client;
|
||||
|
||||
g_return_val_if_fail (G_IS_DBUS_CONNECTION (connection), 0);
|
||||
g_return_val_if_fail (g_dbus_is_name (name), 0);
|
||||
g_return_val_if_fail (g_variant_is_object_path (object_path), 0);
|
||||
g_return_val_if_fail (g_dbus_is_interface_name (interface_name), 0);
|
||||
g_return_val_if_fail (g_type_is_a (interface_type, G_TYPE_DBUS_PROXY), 0);
|
||||
|
||||
G_LOCK (lock);
|
||||
|
||||
client = g_new0 (Client, 1);
|
||||
client->id = next_global_id++; /* TODO: uh oh, handle overflow */
|
||||
client->name = g_strdup (name);
|
||||
client->proxy_appeared_handler = proxy_appeared_handler;
|
||||
client->proxy_vanished_handler = proxy_vanished_handler;
|
||||
client->user_data = user_data;
|
||||
client->user_data_free_func = user_data_free_func;
|
||||
client->main_context = g_main_context_get_thread_default ();
|
||||
if (client->main_context != NULL)
|
||||
g_main_context_ref (client->main_context);
|
||||
client->name_watcher_id = g_bus_watch_name_on_connection (connection,
|
||||
name,
|
||||
flags,
|
||||
on_name_appeared,
|
||||
on_name_vanished,
|
||||
client,
|
||||
NULL);
|
||||
|
||||
client->object_path = g_strdup (object_path);
|
||||
client->interface_name = g_strdup (interface_name);
|
||||
client->interface_type = interface_type;
|
||||
client->proxy_flags = proxy_flags;
|
||||
client->initial_construction = TRUE;
|
||||
|
||||
if (map_id_to_client == NULL)
|
||||
{
|
||||
map_id_to_client = g_hash_table_new (g_direct_hash, g_direct_equal);
|
||||
}
|
||||
g_hash_table_insert (map_id_to_client,
|
||||
GUINT_TO_POINTER (client->id),
|
||||
client);
|
||||
|
||||
G_UNLOCK (lock);
|
||||
|
||||
return client->id;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* g_bus_unwatch_proxy:
|
||||
* @watcher_id: An identifier obtained from g_bus_watch_proxy()
|
||||
*
|
||||
* Stops watching proxy.
|
||||
*
|
||||
* Since: 2.26
|
||||
*/
|
||||
void
|
||||
g_bus_unwatch_proxy (guint watcher_id)
|
||||
{
|
||||
Client *client;
|
||||
|
||||
g_return_if_fail (watcher_id > 0);
|
||||
|
||||
client = NULL;
|
||||
|
||||
G_LOCK (lock);
|
||||
if (watcher_id == 0 ||
|
||||
map_id_to_client == NULL ||
|
||||
(client = g_hash_table_lookup (map_id_to_client, GUINT_TO_POINTER (watcher_id))) == NULL)
|
||||
{
|
||||
g_warning ("Invalid id %d passed to g_bus_unwatch_proxy()", watcher_id);
|
||||
goto out;
|
||||
}
|
||||
|
||||
g_warn_if_fail (g_hash_table_remove (map_id_to_client, GUINT_TO_POINTER (watcher_id)));
|
||||
|
||||
out:
|
||||
G_UNLOCK (lock);
|
||||
|
||||
if (client != NULL)
|
||||
{
|
||||
g_bus_unwatch_name (client->name_watcher_id);
|
||||
client->name_watcher_id = 0;
|
||||
client_unref (client);
|
||||
}
|
||||
}
|
||||
|
||||
#define __G_DBUS_PROXY_WATCHING_C__
|
||||
#include "gioaliasdef.c"
|
92
gio/gdbusproxywatching.h
Normal file
92
gio/gdbusproxywatching.h
Normal file
@ -0,0 +1,92 @@
|
||||
/* GDBus - GLib D-Bus Library
|
||||
*
|
||||
* Copyright (C) 2008-2010 Red Hat, Inc.
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General
|
||||
* Public License along with this library; if not, write to the
|
||||
* Free Software Foundation, Inc., 59 Temple Place, Suite 330,
|
||||
* Boston, MA 02111-1307, USA.
|
||||
*
|
||||
* Author: David Zeuthen <davidz@redhat.com>
|
||||
*/
|
||||
|
||||
#ifndef __G_DBUS_PROXY_WATCHING_H__
|
||||
#define __G_DBUS_PROXY_WATCHING_H__
|
||||
|
||||
#include <gio/giotypes.h>
|
||||
|
||||
G_BEGIN_DECLS
|
||||
|
||||
/**
|
||||
* GBusProxyAppearedCallback:
|
||||
* @connection: The #GDBusConnection the proxy is being watched on.
|
||||
* @name: The name being watched.
|
||||
* @name_owner: Unique name of the owner of the name being watched.
|
||||
* @proxy: A #GDBusProxy (or derived) instance with all properties loaded.
|
||||
* @user_data: User data passed to g_bus_watch_proxy().
|
||||
*
|
||||
* Invoked when the proxy being watched is ready for use - the passed
|
||||
* @proxy object is valid until the #GBusProxyVanishedCallback
|
||||
* callback is invoked.
|
||||
*
|
||||
* Since: 2.26
|
||||
*/
|
||||
typedef void (*GBusProxyAppearedCallback) (GDBusConnection *connection,
|
||||
const gchar *name,
|
||||
const gchar *name_owner,
|
||||
GDBusProxy *proxy,
|
||||
gpointer user_data);
|
||||
|
||||
/**
|
||||
* GBusProxyVanishedCallback:
|
||||
* @connection: The #GDBusConnection the proxy is being watched on.
|
||||
* @name: The name being watched.
|
||||
* @user_data: User data passed to g_bus_watch_proxy().
|
||||
*
|
||||
* Invoked when the proxy being watched has vanished. The #GDBusProxy
|
||||
* object passed in the #GBusProxyAppearedCallback callback is no
|
||||
* longer valid.
|
||||
*
|
||||
* Since: 2.26
|
||||
*/
|
||||
typedef void (*GBusProxyVanishedCallback) (GDBusConnection *connection,
|
||||
const gchar *name,
|
||||
gpointer user_data);
|
||||
|
||||
guint g_bus_watch_proxy (GBusType bus_type,
|
||||
const gchar *name,
|
||||
GBusNameWatcherFlags flags,
|
||||
const gchar *object_path,
|
||||
const gchar *interface_name,
|
||||
GType interface_type,
|
||||
GDBusProxyFlags proxy_flags,
|
||||
GBusProxyAppearedCallback proxy_appeared_handler,
|
||||
GBusProxyVanishedCallback proxy_vanished_handler,
|
||||
gpointer user_data,
|
||||
GDestroyNotify user_data_free_func);
|
||||
guint g_bus_watch_proxy_on_connection (GDBusConnection *connection,
|
||||
const gchar *name,
|
||||
GBusNameWatcherFlags flags,
|
||||
const gchar *object_path,
|
||||
const gchar *interface_name,
|
||||
GType interface_type,
|
||||
GDBusProxyFlags proxy_flags,
|
||||
GBusProxyAppearedCallback proxy_appeared_handler,
|
||||
GBusProxyVanishedCallback proxy_vanished_handler,
|
||||
gpointer user_data,
|
||||
GDestroyNotify user_data_free_func);
|
||||
void g_bus_unwatch_proxy (guint watcher_id);
|
||||
|
||||
G_END_DECLS
|
||||
|
||||
#endif /* __G_DBUS_PROXY_WATCHING_H__ */
|
1068
gio/gdbusserver.c
Normal file
1068
gio/gdbusserver.c
Normal file
File diff suppressed because it is too large
Load Diff
101
gio/gdbusserver.h
Normal file
101
gio/gdbusserver.h
Normal file
@ -0,0 +1,101 @@
|
||||
/* GDBus - GLib D-Bus Library
|
||||
*
|
||||
* Copyright (C) 2008-2010 Red Hat, Inc.
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General
|
||||
* Public License along with this library; if not, write to the
|
||||
* Free Software Foundation, Inc., 59 Temple Place, Suite 330,
|
||||
* Boston, MA 02111-1307, USA.
|
||||
*
|
||||
* Author: David Zeuthen <davidz@redhat.com>
|
||||
*/
|
||||
|
||||
#ifndef __G_DBUS_SERVER_H__
|
||||
#define __G_DBUS_SERVER_H__
|
||||
|
||||
#include <gio/giotypes.h>
|
||||
|
||||
G_BEGIN_DECLS
|
||||
|
||||
#define G_TYPE_DBUS_SERVER (g_dbus_server_get_type ())
|
||||
#define G_DBUS_SERVER(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), G_TYPE_DBUS_SERVER, GDBusServer))
|
||||
#define G_DBUS_SERVER_CLASS(k) (G_TYPE_CHECK_CLASS_CAST((k), G_TYPE_DBUS_SERVER, GDBusServerClass))
|
||||
#define G_DBUS_SERVER_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS ((o), G_TYPE_DBUS_SERVER, GDBusServerClass))
|
||||
#define G_IS_DBUS_SERVER(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), G_TYPE_DBUS_SERVER))
|
||||
#define G_IS_DBUS_SERVER_CLASS(k) (G_TYPE_CHECK_CLASS_TYPE ((k), G_TYPE_DBUS_SERVER))
|
||||
|
||||
typedef struct _GDBusServerClass GDBusServerClass;
|
||||
typedef struct _GDBusServerPrivate GDBusServerPrivate;
|
||||
|
||||
/**
|
||||
* GDBusServer:
|
||||
*
|
||||
* The #GDBusServer structure contains only private data and
|
||||
* should only be accessed using the provided API.
|
||||
*
|
||||
* Since: 2.26
|
||||
*/
|
||||
struct _GDBusServer
|
||||
{
|
||||
/*< private >*/
|
||||
GObject parent_instance;
|
||||
GDBusServerPrivate *priv;
|
||||
};
|
||||
|
||||
/**
|
||||
* GDBusServerClass:
|
||||
* @new_connection: Signal class handler for the #GDBusServer::new-connection signal.
|
||||
*
|
||||
* Class structure for #GDBusServer.
|
||||
*
|
||||
* Since: 2.26
|
||||
*/
|
||||
struct _GDBusServerClass
|
||||
{
|
||||
/*< private >*/
|
||||
GObjectClass parent_class;
|
||||
|
||||
/*< public >*/
|
||||
/* Signals */
|
||||
void (*new_connection) (GDBusServer *server,
|
||||
GDBusConnection *connection);
|
||||
|
||||
/*< private >*/
|
||||
/* Padding for future expansion */
|
||||
void (*_g_reserved1) (void);
|
||||
void (*_g_reserved2) (void);
|
||||
void (*_g_reserved3) (void);
|
||||
void (*_g_reserved4) (void);
|
||||
void (*_g_reserved5) (void);
|
||||
void (*_g_reserved6) (void);
|
||||
void (*_g_reserved7) (void);
|
||||
void (*_g_reserved8) (void);
|
||||
};
|
||||
|
||||
GType g_dbus_server_get_type (void) G_GNUC_CONST;
|
||||
GDBusServer *g_dbus_server_new_sync (const gchar *address,
|
||||
GDBusServerFlags flags,
|
||||
const gchar *guid,
|
||||
GDBusAuthObserver *observer,
|
||||
GCancellable *cancellable,
|
||||
GError **error);
|
||||
const gchar *g_dbus_server_get_client_address (GDBusServer *server);
|
||||
const gchar *g_dbus_server_get_guid (GDBusServer *server);
|
||||
GDBusServerFlags g_dbus_server_get_flags (GDBusServer *server);
|
||||
void g_dbus_server_start (GDBusServer *server);
|
||||
void g_dbus_server_stop (GDBusServer *server);
|
||||
gboolean g_dbus_server_is_active (GDBusServer *server);
|
||||
|
||||
G_END_DECLS
|
||||
|
||||
#endif /* __G_DBUS_SERVER_H__ */
|
361
gio/gdbusutils.c
Normal file
361
gio/gdbusutils.c
Normal file
@ -0,0 +1,361 @@
|
||||
/* GDBus - GLib D-Bus Library
|
||||
*
|
||||
* Copyright (C) 2008-2010 Red Hat, Inc.
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General
|
||||
* Public License along with this library; if not, write to the
|
||||
* Free Software Foundation, Inc., 59 Temple Place, Suite 330,
|
||||
* Boston, MA 02111-1307, USA.
|
||||
*
|
||||
* Author: David Zeuthen <davidz@redhat.com>
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "gdbusutils.h"
|
||||
|
||||
#include "glibintl.h"
|
||||
#include "gioalias.h"
|
||||
|
||||
/**
|
||||
* SECTION:gdbusutils
|
||||
* @title: D-Bus Utilities
|
||||
* @short_description: Various utilities related to D-Bus.
|
||||
* @include: gio/gio.h
|
||||
*
|
||||
* Various utility routines related to D-Bus.
|
||||
*/
|
||||
|
||||
static gboolean
|
||||
is_valid_bus_name_character (gint c,
|
||||
gboolean allow_hyphen)
|
||||
{
|
||||
return
|
||||
(c >= '0' && c <= '9') ||
|
||||
(c >= 'A' && c <= 'Z') ||
|
||||
(c >= 'a' && c <= 'z') ||
|
||||
(c == '_') ||
|
||||
(allow_hyphen && c == '-');
|
||||
}
|
||||
|
||||
static gboolean
|
||||
is_valid_initial_bus_name_character (gint c,
|
||||
gboolean allow_initial_digit,
|
||||
gboolean allow_hyphen)
|
||||
{
|
||||
if (allow_initial_digit)
|
||||
return is_valid_bus_name_character (c, allow_hyphen);
|
||||
else
|
||||
return
|
||||
(c >= 'A' && c <= 'Z') ||
|
||||
(c >= 'a' && c <= 'z') ||
|
||||
(c == '_') ||
|
||||
(allow_hyphen && c == '-');
|
||||
}
|
||||
|
||||
static gboolean
|
||||
is_valid_name (const gchar *start,
|
||||
guint len,
|
||||
gboolean allow_initial_digit,
|
||||
gboolean allow_hyphen)
|
||||
{
|
||||
gboolean ret;
|
||||
const gchar *s;
|
||||
const gchar *end;
|
||||
gboolean has_dot;
|
||||
|
||||
ret = FALSE;
|
||||
|
||||
if (len == 0)
|
||||
goto out;
|
||||
|
||||
s = start;
|
||||
end = s + len;
|
||||
has_dot = FALSE;
|
||||
while (s != end)
|
||||
{
|
||||
if (*s == '.')
|
||||
{
|
||||
s += 1;
|
||||
if (G_UNLIKELY (!is_valid_initial_bus_name_character (*s, allow_initial_digit, allow_hyphen)))
|
||||
goto out;
|
||||
has_dot = TRUE;
|
||||
}
|
||||
else if (G_UNLIKELY (!is_valid_bus_name_character (*s, allow_hyphen)))
|
||||
{
|
||||
goto out;
|
||||
}
|
||||
s += 1;
|
||||
}
|
||||
|
||||
if (G_UNLIKELY (!has_dot))
|
||||
goto out;
|
||||
|
||||
ret = TRUE;
|
||||
|
||||
out:
|
||||
return ret;
|
||||
}
|
||||
|
||||
/**
|
||||
* g_dbus_is_name:
|
||||
* @string: The string to check.
|
||||
*
|
||||
* Checks if @string is a valid D-Bus bus name (either unique or well-known).
|
||||
*
|
||||
* Returns: %TRUE if valid, %FALSE otherwise.
|
||||
*
|
||||
* Since: 2.26
|
||||
*/
|
||||
gboolean
|
||||
g_dbus_is_name (const gchar *string)
|
||||
{
|
||||
guint len;
|
||||
gboolean ret;
|
||||
const gchar *s;
|
||||
const gchar *end;
|
||||
|
||||
g_return_val_if_fail (string != NULL, FALSE);
|
||||
|
||||
ret = FALSE;
|
||||
|
||||
len = strlen (string);
|
||||
if (G_UNLIKELY (len == 0 || len > 255))
|
||||
goto out;
|
||||
|
||||
s = string;
|
||||
end = s + len;
|
||||
if (*s == ':')
|
||||
{
|
||||
/* handle unique name */
|
||||
if (!is_valid_name (s + 1, len - 1, TRUE, TRUE))
|
||||
goto out;
|
||||
ret = TRUE;
|
||||
goto out;
|
||||
}
|
||||
else if (G_UNLIKELY (*s == '.'))
|
||||
{
|
||||
/* can't start with a . */
|
||||
goto out;
|
||||
}
|
||||
else if (G_UNLIKELY (!is_valid_initial_bus_name_character (*s, FALSE, TRUE)))
|
||||
goto out;
|
||||
|
||||
ret = is_valid_name (s + 1, len - 1, FALSE, TRUE);
|
||||
|
||||
out:
|
||||
return ret;
|
||||
}
|
||||
|
||||
/**
|
||||
* g_dbus_is_unique_name:
|
||||
* @string: The string to check.
|
||||
*
|
||||
* Checks if @string is a valid D-Bus unique bus name.
|
||||
*
|
||||
* Returns: %TRUE if valid, %FALSE otherwise.
|
||||
*
|
||||
* Since: 2.26
|
||||
*/
|
||||
gboolean
|
||||
g_dbus_is_unique_name (const gchar *string)
|
||||
{
|
||||
gboolean ret;
|
||||
guint len;
|
||||
|
||||
g_return_val_if_fail (string != NULL, FALSE);
|
||||
|
||||
ret = FALSE;
|
||||
|
||||
len = strlen (string);
|
||||
if (G_UNLIKELY (len == 0 || len > 255))
|
||||
goto out;
|
||||
|
||||
if (G_UNLIKELY (*string != ':'))
|
||||
goto out;
|
||||
|
||||
if (G_UNLIKELY (!is_valid_name (string + 1, len - 1, TRUE, TRUE)))
|
||||
goto out;
|
||||
|
||||
ret = TRUE;
|
||||
|
||||
out:
|
||||
return ret;
|
||||
}
|
||||
|
||||
/**
|
||||
* g_dbus_is_member_name:
|
||||
* @string: The string to check.
|
||||
*
|
||||
* Checks if @string is a valid D-Bus member (e.g. signal or method) name.
|
||||
*
|
||||
* Returns: %TRUE if valid, %FALSE otherwise.
|
||||
*
|
||||
* Since: 2.26
|
||||
*/
|
||||
gboolean
|
||||
g_dbus_is_member_name (const gchar *string)
|
||||
{
|
||||
gboolean ret;
|
||||
guint n;
|
||||
|
||||
ret = FALSE;
|
||||
if (G_UNLIKELY (string == NULL))
|
||||
goto out;
|
||||
|
||||
if (G_UNLIKELY (!is_valid_initial_bus_name_character (string[0], FALSE, FALSE)))
|
||||
goto out;
|
||||
|
||||
for (n = 1; string[n] != '\0'; n++)
|
||||
{
|
||||
if (G_UNLIKELY (!is_valid_bus_name_character (string[n], FALSE)))
|
||||
{
|
||||
goto out;
|
||||
}
|
||||
}
|
||||
|
||||
ret = TRUE;
|
||||
|
||||
out:
|
||||
return ret;
|
||||
}
|
||||
|
||||
/**
|
||||
* g_dbus_is_interface_name:
|
||||
* @string: The string to check.
|
||||
*
|
||||
* Checks if @string is a valid D-Bus interface name.
|
||||
*
|
||||
* Returns: %TRUE if valid, %FALSE otherwise.
|
||||
*
|
||||
* Since: 2.26
|
||||
*/
|
||||
gboolean
|
||||
g_dbus_is_interface_name (const gchar *string)
|
||||
{
|
||||
guint len;
|
||||
gboolean ret;
|
||||
const gchar *s;
|
||||
const gchar *end;
|
||||
|
||||
g_return_val_if_fail (string != NULL, FALSE);
|
||||
|
||||
ret = FALSE;
|
||||
|
||||
len = strlen (string);
|
||||
if (G_UNLIKELY (len == 0 || len > 255))
|
||||
goto out;
|
||||
|
||||
s = string;
|
||||
end = s + len;
|
||||
if (G_UNLIKELY (*s == '.'))
|
||||
{
|
||||
/* can't start with a . */
|
||||
goto out;
|
||||
}
|
||||
else if (G_UNLIKELY (!is_valid_initial_bus_name_character (*s, FALSE, FALSE)))
|
||||
goto out;
|
||||
|
||||
ret = is_valid_name (s + 1, len - 1, FALSE, FALSE);
|
||||
|
||||
out:
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* ---------------------------------------------------------------------------------------------------- */
|
||||
|
||||
/* TODO: maybe move to glib? if so, it should conform to http://en.wikipedia.org/wiki/Guid and/or
|
||||
* http://tools.ietf.org/html/rfc4122 - specifically it should have hyphens then.
|
||||
*/
|
||||
|
||||
/**
|
||||
* g_dbus_generate_guid:
|
||||
*
|
||||
* Generate a D-Bus GUID that can be used with
|
||||
* e.g. g_dbus_connection_new().
|
||||
*
|
||||
* See the D-Bus specification regarding what strings are valid D-Bus
|
||||
* GUID (for example, D-Bus GUIDs are not RFC-4122 compliant).
|
||||
*
|
||||
* Returns: A valid D-Bus GUID. Free with g_free().
|
||||
*
|
||||
* Since: 2.26
|
||||
*/
|
||||
gchar *
|
||||
g_dbus_generate_guid (void)
|
||||
{
|
||||
GString *s;
|
||||
GTimeVal now;
|
||||
guint32 r1;
|
||||
guint32 r2;
|
||||
guint32 r3;
|
||||
|
||||
s = g_string_new (NULL);
|
||||
|
||||
r1 = g_random_int ();
|
||||
r2 = g_random_int ();
|
||||
r3 = g_random_int ();
|
||||
g_get_current_time (&now);
|
||||
|
||||
g_string_append_printf (s, "%08x", r1);
|
||||
g_string_append_printf (s, "%08x", r2);
|
||||
g_string_append_printf (s, "%08x", r3);
|
||||
g_string_append_printf (s, "%08x", (guint32) now.tv_sec);
|
||||
|
||||
return g_string_free (s, FALSE);
|
||||
}
|
||||
|
||||
/**
|
||||
* g_dbus_is_guid:
|
||||
* @string: The string to check.
|
||||
*
|
||||
* Checks if @string is a D-Bus GUID.
|
||||
*
|
||||
* See the D-Bus specification regarding what strings are valid D-Bus
|
||||
* GUID (for example, D-Bus GUIDs are not RFC-4122 compliant).
|
||||
*
|
||||
* Returns: %TRUE if @string is a guid, %FALSE otherwise.
|
||||
*
|
||||
* Since: 2.26
|
||||
*/
|
||||
gboolean
|
||||
g_dbus_is_guid (const gchar *string)
|
||||
{
|
||||
gboolean ret;
|
||||
guint n;
|
||||
|
||||
g_return_val_if_fail (string != NULL, FALSE);
|
||||
|
||||
ret = FALSE;
|
||||
|
||||
for (n = 0; n < 32; n++)
|
||||
{
|
||||
if (!g_ascii_isxdigit (string[n]))
|
||||
goto out;
|
||||
}
|
||||
if (string[32] != '\0')
|
||||
goto out;
|
||||
|
||||
ret = TRUE;
|
||||
|
||||
out:
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* ---------------------------------------------------------------------------------------------------- */
|
||||
|
||||
#define __G_DBUS_UTILS_C__
|
||||
#include "gioaliasdef.c"
|
40
gio/gdbusutils.h
Normal file
40
gio/gdbusutils.h
Normal file
@ -0,0 +1,40 @@
|
||||
/* GDBus - GLib D-Bus Library
|
||||
*
|
||||
* Copyright (C) 2008-2010 Red Hat, Inc.
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General
|
||||
* Public License along with this library; if not, write to the
|
||||
* Free Software Foundation, Inc., 59 Temple Place, Suite 330,
|
||||
* Boston, MA 02111-1307, USA.
|
||||
*
|
||||
* Author: David Zeuthen <davidz@redhat.com>
|
||||
*/
|
||||
|
||||
#ifndef __G_DBUS_UTILS_H__
|
||||
#define __G_DBUS_UTILS_H__
|
||||
|
||||
#include <gio/giotypes.h>
|
||||
|
||||
G_BEGIN_DECLS
|
||||
|
||||
gboolean g_dbus_is_guid (const gchar *string);
|
||||
gchar *g_dbus_generate_guid (void);
|
||||
|
||||
gboolean g_dbus_is_name (const gchar *string);
|
||||
gboolean g_dbus_is_unique_name (const gchar *string);
|
||||
gboolean g_dbus_is_member_name (const gchar *string);
|
||||
gboolean g_dbus_is_interface_name (const gchar *string);
|
||||
|
||||
G_END_DECLS
|
||||
|
||||
#endif /* __G_DBUS_UTILS_H__ */
|
@ -6,3 +6,6 @@ BOOLEAN:OBJECT,OBJECT
|
||||
VOID:STRING,BOXED,BOXED
|
||||
BOOL:POINTER,INT
|
||||
BOOL:UINT
|
||||
VOID:STRING,STRING,BOXED
|
||||
VOID:BOOL,BOXED
|
||||
VOID:BOXED,BOXED
|
||||
|
16
gio/gio.h
16
gio/gio.h
@ -97,6 +97,22 @@
|
||||
#include <gio/gzlibcompressor.h>
|
||||
#include <gio/gzlibdecompressor.h>
|
||||
|
||||
#include <gio/gdbusutils.h>
|
||||
#include <gio/gdbusaddress.h>
|
||||
#include <gio/gdbusmessage.h>
|
||||
#include <gio/gdbusconnection.h>
|
||||
#include <gio/gdbuserror.h>
|
||||
#include <gio/gdbusnameowning.h>
|
||||
#include <gio/gdbusnamewatching.h>
|
||||
#include <gio/gdbusproxywatching.h>
|
||||
#include <gio/gdbusproxy.h>
|
||||
#include <gio/gdbusintrospection.h>
|
||||
#include <gio/gdbusmethodinvocation.h>
|
||||
#include <gio/gdbusserver.h>
|
||||
#include <gio/gcredentials.h>
|
||||
#include <gio/gunixcredentialsmessage.h>
|
||||
#include <gio/gdbusauthobserver.h>
|
||||
|
||||
#undef __GIO_GIO_H_INSIDE__
|
||||
|
||||
#endif /* __G_IO_H__ */
|
||||
|
292
gio/gio.symbols
292
gio/gio.symbols
@ -987,6 +987,20 @@ g_unix_socket_address_type_get_type G_GNUC_CONST
|
||||
g_resolver_error_get_type G_GNUC_CONST
|
||||
g_zlib_compressor_format_get_type
|
||||
g_settings_bind_flags_get_type
|
||||
g_dbus_error_get_type G_GNUC_CONST
|
||||
g_bus_type_get_type G_GNUC_CONST
|
||||
g_bus_name_owner_flags_get_type G_GNUC_CONST
|
||||
g_bus_name_watcher_flags_get_type G_GNUC_CONST
|
||||
g_dbus_proxy_flags_get_type G_GNUC_CONST
|
||||
g_dbus_connection_flags_get_type G_GNUC_CONST
|
||||
g_dbus_capability_flags_get_type G_GNUC_CONST
|
||||
g_dbus_call_flags_get_type G_GNUC_CONST
|
||||
g_dbus_message_type_get_type G_GNUC_CONST
|
||||
g_dbus_message_flags_get_type G_GNUC_CONST
|
||||
g_dbus_message_header_field_get_type G_GNUC_CONST
|
||||
g_dbus_property_info_flags_get_type G_GNUC_CONST
|
||||
g_dbus_subtree_flags_get_type G_GNUC_CONST
|
||||
g_dbus_server_flags_get_type G_GNUC_CONST
|
||||
#endif
|
||||
#endif
|
||||
|
||||
@ -1326,6 +1340,8 @@ g_tcp_connection_get_graceful_disconnect
|
||||
g_unix_connection_get_type G_GNUC_CONST
|
||||
g_unix_connection_receive_fd
|
||||
g_unix_connection_send_fd
|
||||
g_unix_connection_receive_credentials
|
||||
g_unix_connection_send_credentials
|
||||
#endif
|
||||
#endif
|
||||
#endif
|
||||
@ -1430,3 +1446,279 @@ g_settings_get_boolean
|
||||
g_settings_set_boolean
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#if IN_HEADER(__G_CREDENTIALS_H__)
|
||||
#if IN_FILE(__G_CREDENTIALS_C__)
|
||||
g_credentials_get_type G_GNUC_CONST
|
||||
g_credentials_new
|
||||
g_credentials_to_string
|
||||
g_credentials_get_native
|
||||
g_credentials_set_native
|
||||
g_credentials_is_same_user
|
||||
g_credentials_get_unix_user
|
||||
g_credentials_set_unix_user
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#if IN_HEADER(__G_DBUS_ADDRESS_H__)
|
||||
#if IN_FILE(__G_DBUS_ADDRESS_C__)
|
||||
g_dbus_is_address
|
||||
g_dbus_is_supported_address
|
||||
g_dbus_address_get_for_bus_sync
|
||||
g_dbus_address_get_stream
|
||||
g_dbus_address_get_stream_finish
|
||||
g_dbus_address_get_stream_sync
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#if IN_HEADER(__G_DBUS_AUTH_OBSERVER_H__)
|
||||
#if IN_FILE(__G_DBUS_AUTH_OBSERVER_C__)
|
||||
g_dbus_auth_observer_get_type G_GNUC_CONST
|
||||
g_dbus_auth_observer_new
|
||||
g_dbus_auth_observer_authorize_authenticated_peer
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#if IN_HEADER(__G_DBUS_CONNECTION_H__)
|
||||
#if IN_FILE(__G_DBUS_CONNECTION_C__)
|
||||
g_dbus_connection_get_type G_GNUC_CONST
|
||||
g_bus_get
|
||||
g_bus_get_finish
|
||||
g_bus_get_sync
|
||||
g_dbus_connection_new
|
||||
g_dbus_connection_new_finish
|
||||
g_dbus_connection_new_for_address
|
||||
g_dbus_connection_new_for_address_finish
|
||||
g_dbus_connection_new_for_address_sync
|
||||
g_dbus_connection_new_sync
|
||||
g_dbus_connection_get_capabilities
|
||||
g_dbus_connection_get_exit_on_close
|
||||
g_dbus_connection_get_guid
|
||||
g_dbus_connection_get_peer_credentials
|
||||
g_dbus_connection_get_stream
|
||||
g_dbus_connection_get_unique_name
|
||||
g_dbus_connection_is_closed
|
||||
g_dbus_connection_set_exit_on_close
|
||||
g_dbus_connection_close
|
||||
g_dbus_connection_emit_signal
|
||||
g_dbus_connection_call
|
||||
g_dbus_connection_call_finish
|
||||
g_dbus_connection_call_sync
|
||||
g_dbus_connection_signal_subscribe
|
||||
g_dbus_connection_signal_unsubscribe
|
||||
g_dbus_connection_add_filter
|
||||
g_dbus_connection_remove_filter
|
||||
g_dbus_connection_send_message
|
||||
g_dbus_connection_send_message_with_reply
|
||||
g_dbus_connection_send_message_with_reply_finish
|
||||
g_dbus_connection_send_message_with_reply_sync
|
||||
g_dbus_connection_register_object
|
||||
g_dbus_connection_unregister_object
|
||||
g_dbus_connection_register_subtree
|
||||
g_dbus_connection_unregister_subtree
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#if IN_HEADER(__G_DBUS_ERROR_H__)
|
||||
#if IN_FILE(__G_DBUS_ERROR_C__)
|
||||
g_dbus_error_quark
|
||||
g_dbus_error_new_for_dbus_error
|
||||
g_dbus_error_is_remote_error
|
||||
g_dbus_error_get_remote_error
|
||||
g_dbus_error_strip_remote_error
|
||||
g_dbus_error_encode_gerror
|
||||
g_dbus_error_register_error
|
||||
g_dbus_error_register_error_domain
|
||||
g_dbus_error_set_dbus_error
|
||||
g_dbus_error_set_dbus_error_valist
|
||||
g_dbus_error_unregister_error
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#if IN_HEADER(__G_DBUS_INTROSPECTION_H__)
|
||||
#if IN_FILE(__G_DBUS_INTROSPECTION_C__)
|
||||
g_dbus_annotation_info_get_type G_GNUC_CONST
|
||||
g_dbus_arg_info_get_type G_GNUC_CONST
|
||||
g_dbus_property_info_get_type G_GNUC_CONST
|
||||
g_dbus_interface_info_get_type G_GNUC_CONST
|
||||
g_dbus_method_info_get_type G_GNUC_CONST
|
||||
g_dbus_signal_info_get_type G_GNUC_CONST
|
||||
g_dbus_node_info_get_type G_GNUC_CONST
|
||||
g_dbus_annotation_info_lookup
|
||||
g_dbus_annotation_info_ref
|
||||
g_dbus_annotation_info_unref
|
||||
g_dbus_interface_info_generate_xml
|
||||
g_dbus_interface_info_lookup_method
|
||||
g_dbus_interface_info_lookup_property
|
||||
g_dbus_interface_info_lookup_signal
|
||||
g_dbus_node_info_new_for_xml
|
||||
g_dbus_node_info_generate_xml
|
||||
g_dbus_node_info_lookup_interface
|
||||
g_dbus_arg_info_ref
|
||||
g_dbus_arg_info_unref
|
||||
g_dbus_property_info_ref
|
||||
g_dbus_property_info_unref
|
||||
g_dbus_signal_info_ref
|
||||
g_dbus_signal_info_unref
|
||||
g_dbus_method_info_ref
|
||||
g_dbus_method_info_unref
|
||||
g_dbus_interface_info_ref
|
||||
g_dbus_interface_info_unref
|
||||
g_dbus_node_info_ref
|
||||
g_dbus_node_info_unref
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#if IN_HEADER(__G_DBUS_MESSAGE_H__)
|
||||
#if IN_FILE(__G_DBUS_MESSAGE_C__)
|
||||
g_dbus_message_get_type G_GNUC_CONST
|
||||
g_dbus_message_new
|
||||
g_dbus_message_new_from_blob
|
||||
g_dbus_message_new_method_call
|
||||
g_dbus_message_new_method_error
|
||||
g_dbus_message_new_method_error_literal
|
||||
g_dbus_message_new_method_error_valist
|
||||
g_dbus_message_new_method_reply
|
||||
g_dbus_message_new_signal
|
||||
g_dbus_message_bytes_needed
|
||||
g_dbus_message_get_arg0
|
||||
g_dbus_message_get_body
|
||||
g_dbus_message_get_destination
|
||||
g_dbus_message_get_error_name
|
||||
g_dbus_message_get_flags
|
||||
g_dbus_message_get_header
|
||||
g_dbus_message_get_header_fields
|
||||
g_dbus_message_get_interface
|
||||
g_dbus_message_get_member
|
||||
g_dbus_message_get_num_unix_fds
|
||||
g_dbus_message_get_path
|
||||
g_dbus_message_get_reply_serial
|
||||
g_dbus_message_get_sender
|
||||
g_dbus_message_get_serial
|
||||
g_dbus_message_get_signature
|
||||
g_dbus_message_get_message_type
|
||||
g_dbus_message_get_unix_fd_list
|
||||
g_dbus_message_print
|
||||
g_dbus_message_set_body
|
||||
g_dbus_message_set_destination
|
||||
g_dbus_message_set_error_name
|
||||
g_dbus_message_set_flags
|
||||
g_dbus_message_set_header
|
||||
g_dbus_message_set_interface
|
||||
g_dbus_message_set_member
|
||||
g_dbus_message_set_num_unix_fds
|
||||
g_dbus_message_set_path
|
||||
g_dbus_message_set_reply_serial
|
||||
g_dbus_message_set_sender
|
||||
g_dbus_message_set_serial
|
||||
g_dbus_message_set_signature
|
||||
g_dbus_message_set_message_type
|
||||
g_dbus_message_set_unix_fd_list
|
||||
g_dbus_message_to_blob
|
||||
g_dbus_message_to_gerror
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#if IN_HEADER(__G_DBUS_METHOD_INVOCATION_H__)
|
||||
#if IN_FILE(__G_DBUS_METHOD_INVOCATION_C__)
|
||||
g_dbus_method_invocation_get_type G_GNUC_CONST
|
||||
g_dbus_method_invocation_new
|
||||
g_dbus_method_invocation_get_connection
|
||||
g_dbus_method_invocation_get_interface_name
|
||||
g_dbus_method_invocation_get_message
|
||||
g_dbus_method_invocation_get_method_info
|
||||
g_dbus_method_invocation_get_method_name
|
||||
g_dbus_method_invocation_get_object_path
|
||||
g_dbus_method_invocation_get_parameters
|
||||
g_dbus_method_invocation_get_sender
|
||||
g_dbus_method_invocation_get_user_data
|
||||
g_dbus_method_invocation_return_dbus_error
|
||||
g_dbus_method_invocation_return_error
|
||||
g_dbus_method_invocation_return_error_literal
|
||||
g_dbus_method_invocation_return_error_valist
|
||||
g_dbus_method_invocation_return_gerror
|
||||
g_dbus_method_invocation_return_value
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#if IN_HEADER(__G_DBUS_NAME_OWNING_H__)
|
||||
#if IN_FILE(__G_DBUS_NAME_OWNING_C__)
|
||||
g_bus_own_name
|
||||
g_bus_own_name_on_connection
|
||||
g_bus_unown_name
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#if IN_HEADER(__G_DBUS_NAME_WATCHING_H__)
|
||||
#if IN_FILE(__G_DBUS_NAME_WATCHING_C__)
|
||||
g_bus_watch_name
|
||||
g_bus_watch_name_on_connection
|
||||
g_bus_unwatch_name
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#if IN_HEADER(__G_DBUS_PROXY_H__)
|
||||
#if IN_FILE(__G_DBUS_PROXY_C__)
|
||||
g_dbus_proxy_get_type G_GNUC_CONST
|
||||
g_dbus_proxy_new
|
||||
g_dbus_proxy_new_finish
|
||||
g_dbus_proxy_new_sync
|
||||
g_dbus_proxy_get_cached_property
|
||||
g_dbus_proxy_set_cached_property
|
||||
g_dbus_proxy_get_cached_property_names
|
||||
g_dbus_proxy_get_connection
|
||||
g_dbus_proxy_get_default_timeout
|
||||
g_dbus_proxy_get_flags
|
||||
g_dbus_proxy_get_interface_info
|
||||
g_dbus_proxy_get_interface_name
|
||||
g_dbus_proxy_get_object_path
|
||||
g_dbus_proxy_get_unique_bus_name
|
||||
g_dbus_proxy_set_default_timeout
|
||||
g_dbus_proxy_set_interface_info
|
||||
g_dbus_proxy_call
|
||||
g_dbus_proxy_call_finish
|
||||
g_dbus_proxy_call_sync
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#if IN_HEADER(__G_DBUS_PROXY_WATCHING_H__)
|
||||
#if IN_FILE(__G_DBUS_PROXY_WATCHING_C__)
|
||||
g_bus_watch_proxy
|
||||
g_bus_watch_proxy_on_connection
|
||||
g_bus_unwatch_proxy
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#if IN_HEADER(__G_DBUS_SERVER_H__)
|
||||
#if IN_FILE(__G_DBUS_SERVER_C__)
|
||||
g_dbus_server_get_type G_GNUC_CONST
|
||||
g_dbus_server_new_sync
|
||||
g_dbus_server_is_active
|
||||
g_dbus_server_start
|
||||
g_dbus_server_stop
|
||||
g_dbus_server_get_client_address
|
||||
g_dbus_server_get_flags
|
||||
g_dbus_server_get_guid
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#if IN_HEADER(__G_DBUS_UTILS_H__)
|
||||
#if IN_FILE(__G_DBUS_UTILS_C__)
|
||||
g_dbus_generate_guid
|
||||
g_dbus_is_guid
|
||||
g_dbus_is_interface_name
|
||||
g_dbus_is_member_name
|
||||
g_dbus_is_name
|
||||
g_dbus_is_unique_name
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#if IN_HEADER(__G_UNIX_CREDENTIALS_MESSAGE_H__)
|
||||
#if IN_FILE(__G_UNIX_CREDENTIALS_MESSAGE_C__)
|
||||
g_unix_credentials_message_get_type G_GNUC_CONST
|
||||
g_unix_credentials_message_new
|
||||
g_unix_credentials_message_new_with_credentials
|
||||
g_unix_credentials_message_get_credentials
|
||||
g_unix_credentials_message_is_supported
|
||||
#endif
|
||||
#endif
|
||||
|
398
gio/gioenums.h
398
gio/gioenums.h
@ -429,6 +429,11 @@ typedef enum {
|
||||
* @G_IO_ERROR_ADDRESS_IN_USE: The requested address is already in use. Since 2.22
|
||||
* @G_IO_ERROR_PARTIAL_INPUT: Need more input to finish operation. Since 2.24
|
||||
* @G_IO_ERROR_INVALID_DATA: There input data was invalid. Since 2.24
|
||||
* @G_IO_ERROR_DBUS_ERROR: A remote object generated an error that
|
||||
* doesn't correspond to a locally registered #GError error
|
||||
* domain. Use g_dbus_error_get_remote_error() to extract the D-Bus
|
||||
* error name and g_dbus_error_strip_remote_error() to fix up the
|
||||
* message so it matches what was received on the wire. Since 2.26.
|
||||
*
|
||||
* Error codes returned by GIO functions.
|
||||
*
|
||||
@ -469,7 +474,8 @@ typedef enum {
|
||||
G_IO_ERROR_NOT_INITIALIZED,
|
||||
G_IO_ERROR_ADDRESS_IN_USE,
|
||||
G_IO_ERROR_PARTIAL_INPUT,
|
||||
G_IO_ERROR_INVALID_DATA
|
||||
G_IO_ERROR_INVALID_DATA,
|
||||
G_IO_ERROR_DBUS_ERROR
|
||||
} GIOErrorEnum;
|
||||
|
||||
|
||||
@ -732,6 +738,396 @@ typedef enum {
|
||||
G_UNIX_SOCKET_ADDRESS_ABSTRACT_PADDED
|
||||
} GUnixSocketAddressType;
|
||||
|
||||
/**
|
||||
* GBusType:
|
||||
* @G_BUS_TYPE_STARTER: An alias for the message bus that activated the process, if any.
|
||||
* @G_BUS_TYPE_SYSTEM: The system-wide message bus.
|
||||
* @G_BUS_TYPE_SESSION: The login session message bus.
|
||||
*
|
||||
* An enumeration for well-known message buses.
|
||||
*
|
||||
* Since: 2.26
|
||||
*/
|
||||
typedef enum
|
||||
{
|
||||
G_BUS_TYPE_STARTER = 0,
|
||||
G_BUS_TYPE_SYSTEM = 1,
|
||||
G_BUS_TYPE_SESSION = 2
|
||||
} GBusType;
|
||||
|
||||
/**
|
||||
* GBusNameOwnerFlags:
|
||||
* @G_BUS_NAME_OWNER_FLAGS_NONE: No flags set.
|
||||
* @G_BUS_NAME_OWNER_FLAGS_ALLOW_REPLACEMENT: Allow another message bus connection to claim the the name.
|
||||
* @G_BUS_NAME_OWNER_FLAGS_REPLACE: If another message bus connection owns the name and have
|
||||
* specified #G_BUS_NAME_OWNER_FLAGS_ALLOW_REPLACEMENT, then take the name from the other connection.
|
||||
*
|
||||
* Flags used in g_bus_own_name().
|
||||
*
|
||||
* Since: 2.26
|
||||
*/
|
||||
typedef enum
|
||||
{
|
||||
G_BUS_NAME_OWNER_FLAGS_NONE = 0, /*< nick=none >*/
|
||||
G_BUS_NAME_OWNER_FLAGS_ALLOW_REPLACEMENT = (1<<0), /*< nick=allow-replacement >*/
|
||||
G_BUS_NAME_OWNER_FLAGS_REPLACE = (1<<1), /*< nick=replace >*/
|
||||
} GBusNameOwnerFlags;
|
||||
|
||||
/**
|
||||
* GBusNameWatcherFlags:
|
||||
* @G_BUS_NAME_WATCHER_FLAGS_NONE: No flags set.
|
||||
* @G_BUS_NAME_WATCHER_FLAGS_AUTO_START: If no-one owns the name when
|
||||
* beginning to watch the name, ask the bus to launch an owner for the
|
||||
* name.
|
||||
*
|
||||
* Flags used in g_bus_watch_name().
|
||||
*
|
||||
* Since: 2.26
|
||||
*/
|
||||
typedef enum
|
||||
{
|
||||
G_BUS_NAME_WATCHER_FLAGS_NONE = 0,
|
||||
G_BUS_NAME_WATCHER_FLAGS_AUTO_START = (1<<0)
|
||||
} GBusNameWatcherFlags;
|
||||
|
||||
/**
|
||||
* GDBusProxyFlags:
|
||||
* @G_DBUS_PROXY_FLAGS_NONE: No flags set.
|
||||
* @G_DBUS_PROXY_FLAGS_DO_NOT_LOAD_PROPERTIES: Don't load properties.
|
||||
* @G_DBUS_PROXY_FLAGS_DO_NOT_CONNECT_SIGNALS: Don't connect to signals on the remote object.
|
||||
*
|
||||
* Flags used when constructing an instance of a #GDBusProxy derived class.
|
||||
*
|
||||
* Since: 2.26
|
||||
*/
|
||||
typedef enum
|
||||
{
|
||||
G_DBUS_PROXY_FLAGS_NONE = 0, /*< nick=none >*/
|
||||
G_DBUS_PROXY_FLAGS_DO_NOT_LOAD_PROPERTIES = (1<<0), /*< nick=do-not-load-properties >*/
|
||||
G_DBUS_PROXY_FLAGS_DO_NOT_CONNECT_SIGNALS = (1<<1), /*< nick=do-not-connect-signals >*/
|
||||
} GDBusProxyFlags;
|
||||
|
||||
/**
|
||||
* GDBusError:
|
||||
* @G_DBUS_ERROR_FAILED:
|
||||
* A generic error; "something went wrong" - see the error message for
|
||||
* more.
|
||||
* @G_DBUS_ERROR_NO_MEMORY:
|
||||
* There was not enough memory to complete an operation.
|
||||
* @G_DBUS_ERROR_SERVICE_UNKNOWN:
|
||||
* The bus doesn't know how to launch a service to supply the bus name
|
||||
* you wanted.
|
||||
* @G_DBUS_ERROR_NAME_HAS_NO_OWNER:
|
||||
* The bus name you referenced doesn't exist (i.e. no application owns
|
||||
* it).
|
||||
* @G_DBUS_ERROR_NO_REPLY:
|
||||
* No reply to a message expecting one, usually means a timeout occurred.
|
||||
* @G_DBUS_ERROR_IO_ERROR:
|
||||
* Something went wrong reading or writing to a socket, for example.
|
||||
* @G_DBUS_ERROR_BAD_ADDRESS:
|
||||
* A D-Bus bus address was malformed.
|
||||
* @G_DBUS_ERROR_NOT_SUPPORTED:
|
||||
* Requested operation isn't supported (like ENOSYS on UNIX).
|
||||
* @G_DBUS_ERROR_LIMITS_EXCEEDED:
|
||||
* Some limited resource is exhausted.
|
||||
* @G_DBUS_ERROR_ACCESS_DENIED:
|
||||
* Security restrictions don't allow doing what you're trying to do.
|
||||
* @G_DBUS_ERROR_AUTH_FAILED:
|
||||
* Authentication didn't work.
|
||||
* @G_DBUS_ERROR_NO_SERVER:
|
||||
* Unable to connect to server (probably caused by ECONNREFUSED on a
|
||||
* socket).
|
||||
* @G_DBUS_ERROR_TIMEOUT:
|
||||
* Certain timeout errors, possibly ETIMEDOUT on a socket. Note that
|
||||
* %G_DBUS_ERROR_NO_REPLY is used for message reply timeouts. Warning:
|
||||
* this is confusingly-named given that %G_DBUS_ERROR_TIMED_OUT also
|
||||
* exists. We can't fix it for compatibility reasons so just be
|
||||
* careful.
|
||||
* @G_DBUS_ERROR_NO_NETWORK:
|
||||
* No network access (probably ENETUNREACH on a socket).
|
||||
* @G_DBUS_ERROR_ADDRESS_IN_USE:
|
||||
* Can't bind a socket since its address is in use (i.e. EADDRINUSE).
|
||||
* @G_DBUS_ERROR_DISCONNECTED:
|
||||
* The connection is disconnected and you're trying to use it.
|
||||
* @G_DBUS_ERROR_INVALID_ARGS:
|
||||
* Invalid arguments passed to a method call.
|
||||
* @G_DBUS_ERROR_FILE_NOT_FOUND:
|
||||
* Missing file.
|
||||
* @G_DBUS_ERROR_FILE_EXISTS:
|
||||
* Existing file and the operation you're using does not silently overwrite.
|
||||
* @G_DBUS_ERROR_UNKNOWN_METHOD:
|
||||
* Method name you invoked isn't known by the object you invoked it on.
|
||||
* @G_DBUS_ERROR_TIMED_OUT:
|
||||
* Certain timeout errors, e.g. while starting a service. Warning: this is
|
||||
* confusingly-named given that %G_DBUS_ERROR_TIMEOUT also exists. We
|
||||
* can't fix it for compatibility reasons so just be careful.
|
||||
* @G_DBUS_ERROR_MATCH_RULE_NOT_FOUND:
|
||||
* Tried to remove or modify a match rule that didn't exist.
|
||||
* @G_DBUS_ERROR_MATCH_RULE_INVALID:
|
||||
* The match rule isn't syntactically valid.
|
||||
* @G_DBUS_ERROR_SPAWN_EXEC_FAILED:
|
||||
* While starting a new process, the exec() call failed.
|
||||
* @G_DBUS_ERROR_SPAWN_FORK_FAILED:
|
||||
* While starting a new process, the fork() call failed.
|
||||
* @G_DBUS_ERROR_SPAWN_CHILD_EXITED:
|
||||
* While starting a new process, the child exited with a status code.
|
||||
* @G_DBUS_ERROR_SPAWN_CHILD_SIGNALED:
|
||||
* While starting a new process, the child exited on a signal.
|
||||
* @G_DBUS_ERROR_SPAWN_FAILED:
|
||||
* While starting a new process, something went wrong.
|
||||
* @G_DBUS_ERROR_SPAWN_SETUP_FAILED:
|
||||
* We failed to setup the environment correctly.
|
||||
* @G_DBUS_ERROR_SPAWN_CONFIG_INVALID:
|
||||
* We failed to setup the config parser correctly.
|
||||
* @G_DBUS_ERROR_SPAWN_SERVICE_INVALID:
|
||||
* Bus name was not valid.
|
||||
* @G_DBUS_ERROR_SPAWN_SERVICE_NOT_FOUND:
|
||||
* Service file not found in system-services directory.
|
||||
* @G_DBUS_ERROR_SPAWN_PERMISSIONS_INVALID:
|
||||
* Permissions are incorrect on the setuid helper.
|
||||
* @G_DBUS_ERROR_SPAWN_FILE_INVALID:
|
||||
* Service file invalid (Name, User or Exec missing).
|
||||
* @G_DBUS_ERROR_SPAWN_NO_MEMORY:
|
||||
* Tried to get a UNIX process ID and it wasn't available.
|
||||
* @G_DBUS_ERROR_UNIX_PROCESS_ID_UNKNOWN:
|
||||
* Tried to get a UNIX process ID and it wasn't available.
|
||||
* @G_DBUS_ERROR_INVALID_SIGNATURE:
|
||||
* A type signature is not valid.
|
||||
* @G_DBUS_ERROR_INVALID_FILE_CONTENT:
|
||||
* A file contains invalid syntax or is otherwise broken.
|
||||
* @G_DBUS_ERROR_SELINUX_SECURITY_CONTEXT_UNKNOWN:
|
||||
* Asked for SELinux security context and it wasn't available.
|
||||
* @G_DBUS_ERROR_ADT_AUDIT_DATA_UNKNOWN:
|
||||
* Asked for ADT audit data and it wasn't available.
|
||||
* @G_DBUS_ERROR_OBJECT_PATH_IN_USE:
|
||||
* There's already an object with the requested object path.
|
||||
*
|
||||
* Error codes for the %G_DBUS_ERROR error domain.
|
||||
*
|
||||
* Since: 2.26
|
||||
*/
|
||||
typedef enum
|
||||
{
|
||||
/* Well-known errors in the org.freedesktop.DBus.Error namespace */
|
||||
G_DBUS_ERROR_FAILED, /* org.freedesktop.DBus.Error.Failed */
|
||||
G_DBUS_ERROR_NO_MEMORY, /* org.freedesktop.DBus.Error.NoMemory */
|
||||
G_DBUS_ERROR_SERVICE_UNKNOWN, /* org.freedesktop.DBus.Error.ServiceUnknown */
|
||||
G_DBUS_ERROR_NAME_HAS_NO_OWNER, /* org.freedesktop.DBus.Error.NameHasNoOwner */
|
||||
G_DBUS_ERROR_NO_REPLY, /* org.freedesktop.DBus.Error.NoReply */
|
||||
G_DBUS_ERROR_IO_ERROR, /* org.freedesktop.DBus.Error.IOError */
|
||||
G_DBUS_ERROR_BAD_ADDRESS, /* org.freedesktop.DBus.Error.BadAddress */
|
||||
G_DBUS_ERROR_NOT_SUPPORTED, /* org.freedesktop.DBus.Error.NotSupported */
|
||||
G_DBUS_ERROR_LIMITS_EXCEEDED, /* org.freedesktop.DBus.Error.LimitsExceeded */
|
||||
G_DBUS_ERROR_ACCESS_DENIED, /* org.freedesktop.DBus.Error.AccessDenied */
|
||||
G_DBUS_ERROR_AUTH_FAILED, /* org.freedesktop.DBus.Error.AuthFailed */
|
||||
G_DBUS_ERROR_NO_SERVER, /* org.freedesktop.DBus.Error.NoServer */
|
||||
G_DBUS_ERROR_TIMEOUT, /* org.freedesktop.DBus.Error.Timeout */
|
||||
G_DBUS_ERROR_NO_NETWORK, /* org.freedesktop.DBus.Error.NoNetwork */
|
||||
G_DBUS_ERROR_ADDRESS_IN_USE, /* org.freedesktop.DBus.Error.AddressInUse */
|
||||
G_DBUS_ERROR_DISCONNECTED, /* org.freedesktop.DBus.Error.Disconnected */
|
||||
G_DBUS_ERROR_INVALID_ARGS, /* org.freedesktop.DBus.Error.InvalidArgs */
|
||||
G_DBUS_ERROR_FILE_NOT_FOUND, /* org.freedesktop.DBus.Error.FileNotFound */
|
||||
G_DBUS_ERROR_FILE_EXISTS, /* org.freedesktop.DBus.Error.FileExists */
|
||||
G_DBUS_ERROR_UNKNOWN_METHOD, /* org.freedesktop.DBus.Error.UnknownMethod */
|
||||
G_DBUS_ERROR_TIMED_OUT, /* org.freedesktop.DBus.Error.TimedOut */
|
||||
G_DBUS_ERROR_MATCH_RULE_NOT_FOUND, /* org.freedesktop.DBus.Error.MatchRuleNotFound */
|
||||
G_DBUS_ERROR_MATCH_RULE_INVALID, /* org.freedesktop.DBus.Error.MatchRuleInvalid */
|
||||
G_DBUS_ERROR_SPAWN_EXEC_FAILED, /* org.freedesktop.DBus.Error.Spawn.ExecFailed */
|
||||
G_DBUS_ERROR_SPAWN_FORK_FAILED, /* org.freedesktop.DBus.Error.Spawn.ForkFailed */
|
||||
G_DBUS_ERROR_SPAWN_CHILD_EXITED, /* org.freedesktop.DBus.Error.Spawn.ChildExited */
|
||||
G_DBUS_ERROR_SPAWN_CHILD_SIGNALED, /* org.freedesktop.DBus.Error.Spawn.ChildSignaled */
|
||||
G_DBUS_ERROR_SPAWN_FAILED, /* org.freedesktop.DBus.Error.Spawn.Failed */
|
||||
G_DBUS_ERROR_SPAWN_SETUP_FAILED, /* org.freedesktop.DBus.Error.Spawn.FailedToSetup */
|
||||
G_DBUS_ERROR_SPAWN_CONFIG_INVALID, /* org.freedesktop.DBus.Error.Spawn.ConfigInvalid */
|
||||
G_DBUS_ERROR_SPAWN_SERVICE_INVALID, /* org.freedesktop.DBus.Error.Spawn.ServiceNotValid */
|
||||
G_DBUS_ERROR_SPAWN_SERVICE_NOT_FOUND, /* org.freedesktop.DBus.Error.Spawn.ServiceNotFound */
|
||||
G_DBUS_ERROR_SPAWN_PERMISSIONS_INVALID, /* org.freedesktop.DBus.Error.Spawn.PermissionsInvalid */
|
||||
G_DBUS_ERROR_SPAWN_FILE_INVALID, /* org.freedesktop.DBus.Error.Spawn.FileInvalid */
|
||||
G_DBUS_ERROR_SPAWN_NO_MEMORY, /* org.freedesktop.DBus.Error.Spawn.NoMemory */
|
||||
G_DBUS_ERROR_UNIX_PROCESS_ID_UNKNOWN, /* org.freedesktop.DBus.Error.UnixProcessIdUnknown */
|
||||
G_DBUS_ERROR_INVALID_SIGNATURE, /* org.freedesktop.DBus.Error.InvalidSignature */
|
||||
G_DBUS_ERROR_INVALID_FILE_CONTENT, /* org.freedesktop.DBus.Error.InvalidFileContent */
|
||||
G_DBUS_ERROR_SELINUX_SECURITY_CONTEXT_UNKNOWN, /* org.freedesktop.DBus.Error.SELinuxSecurityContextUnknown */
|
||||
G_DBUS_ERROR_ADT_AUDIT_DATA_UNKNOWN, /* org.freedesktop.DBus.Error.AdtAuditDataUnknown */
|
||||
G_DBUS_ERROR_OBJECT_PATH_IN_USE, /* org.freedesktop.DBus.Error.ObjectPathInUse */
|
||||
} GDBusError;
|
||||
/* Remember to update g_dbus_error_quark() in gdbuserror.c if you extend this enumeration */
|
||||
|
||||
/**
|
||||
* GDBusConnectionFlags:
|
||||
* @G_DBUS_CONNECTION_FLAGS_NONE: No flags set.
|
||||
* @G_DBUS_CONNECTION_FLAGS_AUTHENTICATION_CLIENT: Perform authentication against server.
|
||||
* @G_DBUS_CONNECTION_FLAGS_AUTHENTICATION_SERVER: Perform authentication against client.
|
||||
* @G_DBUS_CONNECTION_FLAGS_AUTHENTICATION_ALLOW_ANONYMOUS: When
|
||||
* authenticating as a server, allow the anonymous authentication
|
||||
* method.
|
||||
* @G_DBUS_CONNECTION_FLAGS_MESSAGE_BUS_CONNECTION: Pass this flag if connecting to a peer that is a
|
||||
* message bus. This means that the Hello() method will be invoked as part of the connection setup.
|
||||
*
|
||||
* Flags used when creating a new #GDBusConnection.
|
||||
*
|
||||
* Since: 2.26
|
||||
*/
|
||||
typedef enum {
|
||||
G_DBUS_CONNECTION_FLAGS_NONE = 0,
|
||||
G_DBUS_CONNECTION_FLAGS_AUTHENTICATION_CLIENT = (1<<0),
|
||||
G_DBUS_CONNECTION_FLAGS_AUTHENTICATION_SERVER = (1<<1),
|
||||
G_DBUS_CONNECTION_FLAGS_AUTHENTICATION_ALLOW_ANONYMOUS = (1<<2),
|
||||
G_DBUS_CONNECTION_FLAGS_MESSAGE_BUS_CONNECTION = (1<<3)
|
||||
} GDBusConnectionFlags;
|
||||
|
||||
/**
|
||||
* GDBusCapabilityFlags:
|
||||
* @G_DBUS_CAPABILITY_FLAGS_NONE: No flags set.
|
||||
* @G_DBUS_CAPABILITY_FLAGS_UNIX_FD_PASSING: The connection
|
||||
* supports exchanging UNIX file descriptors with the remote peer.
|
||||
*
|
||||
* Capabilities negotiated with the remote peer.
|
||||
*
|
||||
* Since: 2.26
|
||||
*/
|
||||
typedef enum {
|
||||
G_DBUS_CAPABILITY_FLAGS_NONE = 0,
|
||||
G_DBUS_CAPABILITY_FLAGS_UNIX_FD_PASSING = (1<<0),
|
||||
} GDBusCapabilityFlags;
|
||||
|
||||
/**
|
||||
* GDBusCallFlags:
|
||||
* @G_DBUS_CALL_FLAGS_NONE: No flags set.
|
||||
* @G_DBUS_CALL_FLAGS_NO_AUTO_START: The bus must not launch
|
||||
* an owner for the destination name in response to this method
|
||||
* invocation.
|
||||
*
|
||||
* Flags used in g_dbus_connection_call() and similar APIs.
|
||||
*
|
||||
* Since: 2.26
|
||||
*/
|
||||
typedef enum {
|
||||
G_DBUS_CALL_FLAGS_NONE = 0,
|
||||
G_DBUS_CALL_FLAGS_NO_AUTO_START = (1<<0),
|
||||
} GDBusCallFlags;
|
||||
|
||||
/**
|
||||
* GDBusMessageType:
|
||||
* @G_DBUS_MESSAGE_TYPE_INVALID: Message is of invalid type.
|
||||
* @G_DBUS_MESSAGE_TYPE_METHOD_CALL: Method call.
|
||||
* @G_DBUS_MESSAGE_TYPE_METHOD_RETURN: Method reply.
|
||||
* @G_DBUS_MESSAGE_TYPE_ERROR: Error reply.
|
||||
* @G_DBUS_MESSAGE_TYPE_SIGNAL: Signal emission.
|
||||
*
|
||||
* Message types used in #GDBusMessage.
|
||||
*
|
||||
* Since: 2.26
|
||||
*/
|
||||
typedef enum {
|
||||
G_DBUS_MESSAGE_TYPE_INVALID,
|
||||
G_DBUS_MESSAGE_TYPE_METHOD_CALL,
|
||||
G_DBUS_MESSAGE_TYPE_METHOD_RETURN,
|
||||
G_DBUS_MESSAGE_TYPE_ERROR,
|
||||
G_DBUS_MESSAGE_TYPE_SIGNAL
|
||||
} GDBusMessageType;
|
||||
|
||||
/**
|
||||
* GDBusMessageFlags:
|
||||
* @G_DBUS_MESSAGE_FLAGS_NONE: No flags set.
|
||||
* @G_DBUS_MESSAGE_FLAGS_NO_REPLY_EXPECTED: A reply is not expected.
|
||||
* @G_DBUS_MESSAGE_FLAGS_NO_AUTO_START: The bus must not launch an
|
||||
* owner for the destination name in response to this message.
|
||||
*
|
||||
* Message flags used in #GDBusMessage.
|
||||
*
|
||||
* Since: 2.26
|
||||
*/
|
||||
typedef enum {
|
||||
G_DBUS_MESSAGE_FLAGS_NONE = 0,
|
||||
G_DBUS_MESSAGE_FLAGS_NO_REPLY_EXPECTED = (1<<0),
|
||||
G_DBUS_MESSAGE_FLAGS_NO_AUTO_START = (1<<1)
|
||||
} GDBusMessageFlags;
|
||||
|
||||
/**
|
||||
* GDBusMessageHeaderField:
|
||||
* @G_DBUS_MESSAGE_HEADER_FIELD_INVALID: Not a valid header field.
|
||||
* @G_DBUS_MESSAGE_HEADER_FIELD_PATH: The object path.
|
||||
* @G_DBUS_MESSAGE_HEADER_FIELD_INTERFACE: The interface name.
|
||||
* @G_DBUS_MESSAGE_HEADER_FIELD_MEMBER: The method or signal name.
|
||||
* @G_DBUS_MESSAGE_HEADER_FIELD_ERROR_NAME: The name of the error that occurred.
|
||||
* @G_DBUS_MESSAGE_HEADER_FIELD_REPLY_SERIAL: The serial number the message is a reply to.
|
||||
* @G_DBUS_MESSAGE_HEADER_FIELD_DESTINATION: The name the message is intended for.
|
||||
* @G_DBUS_MESSAGE_HEADER_FIELD_SENDER: Unique name of the sender of the message (filled in by the bus).
|
||||
* @G_DBUS_MESSAGE_HEADER_FIELD_SIGNATURE: The signature of the message body.
|
||||
* @G_DBUS_MESSAGE_HEADER_FIELD_NUM_UNIX_FDS: The number of UNIX file descriptors that accompany the message.
|
||||
*
|
||||
* Header fields used in #GDBusMessage.
|
||||
*
|
||||
* Since: 2.26
|
||||
*/
|
||||
typedef enum {
|
||||
G_DBUS_MESSAGE_HEADER_FIELD_INVALID,
|
||||
G_DBUS_MESSAGE_HEADER_FIELD_PATH,
|
||||
G_DBUS_MESSAGE_HEADER_FIELD_INTERFACE,
|
||||
G_DBUS_MESSAGE_HEADER_FIELD_MEMBER,
|
||||
G_DBUS_MESSAGE_HEADER_FIELD_ERROR_NAME,
|
||||
G_DBUS_MESSAGE_HEADER_FIELD_REPLY_SERIAL,
|
||||
G_DBUS_MESSAGE_HEADER_FIELD_DESTINATION,
|
||||
G_DBUS_MESSAGE_HEADER_FIELD_SENDER,
|
||||
G_DBUS_MESSAGE_HEADER_FIELD_SIGNATURE,
|
||||
G_DBUS_MESSAGE_HEADER_FIELD_NUM_UNIX_FDS
|
||||
} GDBusMessageHeaderField;
|
||||
|
||||
/**
|
||||
* GDBusPropertyInfoFlags:
|
||||
* @G_DBUS_PROPERTY_INFO_FLAGS_NONE: No flags set.
|
||||
* @G_DBUS_PROPERTY_INFO_FLAGS_READABLE: Property is readable.
|
||||
* @G_DBUS_PROPERTY_INFO_FLAGS_WRITABLE: Property is writable.
|
||||
*
|
||||
* Flags describing the access control of a D-Bus property.
|
||||
*
|
||||
* Since: 2.26
|
||||
*/
|
||||
typedef enum
|
||||
{
|
||||
G_DBUS_PROPERTY_INFO_FLAGS_NONE = 0,
|
||||
G_DBUS_PROPERTY_INFO_FLAGS_READABLE = (1<<0),
|
||||
G_DBUS_PROPERTY_INFO_FLAGS_WRITABLE = (1<<1),
|
||||
} GDBusPropertyInfoFlags;
|
||||
|
||||
/**
|
||||
* GDBusSubtreeFlags:
|
||||
* @G_DBUS_SUBTREE_FLAGS_NONE: No flags set.
|
||||
* @G_DBUS_SUBTREE_FLAGS_DISPATCH_TO_UNENUMERATED_NODES: Method calls to objects not in the enumerated range
|
||||
* will still be dispatched. This is useful if you want
|
||||
* to dynamically spawn objects in the subtree.
|
||||
*
|
||||
* Flags passed to g_dbus_connection_register_subtree().
|
||||
*
|
||||
* Since: 2.26
|
||||
*/
|
||||
typedef enum
|
||||
{
|
||||
G_DBUS_SUBTREE_FLAGS_NONE = 0,
|
||||
G_DBUS_SUBTREE_FLAGS_DISPATCH_TO_UNENUMERATED_NODES = (1<<0),
|
||||
} GDBusSubtreeFlags;
|
||||
|
||||
/**
|
||||
* GDBusServerFlags:
|
||||
* @G_DBUS_SERVER_FLAGS_NONE: No flags set.
|
||||
* @G_DBUS_SERVER_FLAGS_RUN_IN_THREAD: All #GDBusServer::new-connection
|
||||
* signals will run in separated dedicated threads (see signal for
|
||||
* details).
|
||||
* @G_DBUS_SERVER_FLAGS_AUTHENTICATION_ALLOW_ANONYMOUS: Allow the anonymous
|
||||
* authentication method.
|
||||
*
|
||||
* Flags used when creating a #GDBusServer.
|
||||
*
|
||||
* Since: 2.26
|
||||
*/
|
||||
typedef enum
|
||||
{
|
||||
G_DBUS_SERVER_FLAGS_NONE = 0,
|
||||
G_DBUS_SERVER_FLAGS_RUN_IN_THREAD = (1<<0),
|
||||
G_DBUS_SERVER_FLAGS_AUTHENTICATION_ALLOW_ANONYMOUS = (1<<1)
|
||||
} GDBusServerFlags;
|
||||
|
||||
G_END_DECLS
|
||||
|
||||
#endif /* __GIO_ENUMS_H__ */
|
||||
|
@ -333,6 +333,26 @@ struct _GOutputVector {
|
||||
gsize size;
|
||||
};
|
||||
|
||||
typedef struct _GCredentials GCredentials;
|
||||
typedef struct _GUnixCredentialsMessage GUnixCredentialsMessage;
|
||||
typedef struct _GUnixFDList GUnixFDList;
|
||||
typedef struct _GDBusMessage GDBusMessage;
|
||||
typedef struct _GDBusConnection GDBusConnection;
|
||||
typedef struct _GMessageBusConnection GMessageBusConnection;
|
||||
typedef struct _GDBusProxy GDBusProxy;
|
||||
typedef struct _GDBusMethodInvocation GDBusMethodInvocation;
|
||||
typedef struct _GDBusServer GDBusServer;
|
||||
typedef struct _GDBusAuthObserver GDBusAuthObserver;
|
||||
typedef struct _GDBusErrorEntry GDBusErrorEntry;
|
||||
typedef struct _GDBusInterfaceVTable GDBusInterfaceVTable;
|
||||
typedef struct _GDBusSubtreeVTable GDBusSubtreeVTable;
|
||||
typedef struct _GDBusAnnotationInfo GDBusAnnotationInfo;
|
||||
typedef struct _GDBusArgInfo GDBusArgInfo;
|
||||
typedef struct _GDBusMethodInfo GDBusMethodInfo;
|
||||
typedef struct _GDBusSignalInfo GDBusSignalInfo;
|
||||
typedef struct _GDBusPropertyInfo GDBusPropertyInfo;
|
||||
typedef struct _GDBusInterfaceInfo GDBusInterfaceInfo;
|
||||
typedef struct _GDBusNodeInfo GDBusNodeInfo;
|
||||
|
||||
G_END_DECLS
|
||||
|
||||
|
@ -41,6 +41,14 @@
|
||||
#include <gio/gsocket.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#ifdef __linux__
|
||||
/* for getsockopt() and setsockopt() */
|
||||
#include <sys/types.h> /* See NOTES */
|
||||
#include <sys/socket.h>
|
||||
#include <errno.h>
|
||||
#include <string.h>
|
||||
#endif
|
||||
|
||||
#include "gioalias.h"
|
||||
|
||||
G_DEFINE_TYPE_WITH_CODE (GUnixConnection, g_unix_connection,
|
||||
@ -292,5 +300,253 @@ gboolean g_unix_connection_create_pair (GUnixCo
|
||||
GError **error);
|
||||
*/
|
||||
|
||||
|
||||
/**
|
||||
* g_unix_connection_send_credentials:
|
||||
* @connection: A #GUnixConnection.
|
||||
* @cancellable: A #GCancellable or %NULL.
|
||||
* @error: Return location for error or %NULL.
|
||||
*
|
||||
* Passes the credentials of the current user the receiving side
|
||||
* of the connection. The recieving end has to call
|
||||
* g_unix_connection_receive_credentials() (or similar) to accept the
|
||||
* credentials.
|
||||
*
|
||||
* As well as sending the credentials this also writes a single NUL
|
||||
* byte to the stream, as this is required for credentials passing to
|
||||
* work on some implementations.
|
||||
*
|
||||
* Note that this function only works on Linux, currently.
|
||||
*
|
||||
* Returns: %TRUE on success, %FALSE if @error is set.
|
||||
*
|
||||
* Since: 2.26
|
||||
*/
|
||||
gboolean
|
||||
g_unix_connection_send_credentials (GUnixConnection *connection,
|
||||
GCancellable *cancellable,
|
||||
GError **error)
|
||||
{
|
||||
GCredentials *credentials;
|
||||
GSocketControlMessage *scm;
|
||||
GSocket *socket;
|
||||
gboolean ret;
|
||||
GOutputVector vector;
|
||||
guchar nul_byte[1] = {'\0'};
|
||||
|
||||
g_return_val_if_fail (G_IS_UNIX_CONNECTION (connection), FALSE);
|
||||
g_return_val_if_fail (error == NULL || *error == NULL, FALSE);
|
||||
|
||||
ret = FALSE;
|
||||
|
||||
credentials = g_credentials_new ();
|
||||
|
||||
vector.buffer = &nul_byte;
|
||||
vector.size = 1;
|
||||
scm = g_unix_credentials_message_new_with_credentials (credentials);
|
||||
g_object_get (connection, "socket", &socket, NULL);
|
||||
if (g_socket_send_message (socket,
|
||||
NULL, /* address */
|
||||
&vector,
|
||||
1,
|
||||
&scm,
|
||||
1,
|
||||
G_SOCKET_MSG_NONE,
|
||||
cancellable,
|
||||
error) != 1)
|
||||
{
|
||||
g_prefix_error (error, _("Error sending credentials: "));
|
||||
goto out;
|
||||
}
|
||||
|
||||
ret = TRUE;
|
||||
|
||||
out:
|
||||
g_object_unref (socket);
|
||||
g_object_unref (scm);
|
||||
g_object_unref (credentials);
|
||||
return ret;
|
||||
}
|
||||
|
||||
/**
|
||||
* g_unix_connection_receive_credentials:
|
||||
* @connection: A #GUnixConnection.
|
||||
* @cancellable: A #GCancellable or %NULL.
|
||||
* @error: Return location for error or %NULL.
|
||||
*
|
||||
* Receives credentials from the sending end of the connection. The
|
||||
* sending end has to call g_unix_connection_send_credentials() (or
|
||||
* similar) for this to work.
|
||||
*
|
||||
* As well as reading the credentials this also reads (and discards) a
|
||||
* single byte from the stream, as this is required for credentials
|
||||
* passing to work on some implementations.
|
||||
*
|
||||
* Returns: Received credentials on success (free with
|
||||
* g_object_unref()), %NULL if @error is set.
|
||||
*
|
||||
* Since: 2.26
|
||||
*/
|
||||
GCredentials *
|
||||
g_unix_connection_receive_credentials (GUnixConnection *connection,
|
||||
GCancellable *cancellable,
|
||||
GError **error)
|
||||
{
|
||||
GCredentials *ret;
|
||||
GSocketControlMessage **scms;
|
||||
gint nscm;
|
||||
GSocket *socket;
|
||||
gint n;
|
||||
volatile GType credentials_message_gtype;
|
||||
gssize num_bytes_read;
|
||||
#ifdef __linux__
|
||||
gboolean turn_off_so_passcreds;
|
||||
#endif
|
||||
|
||||
g_return_val_if_fail (G_IS_UNIX_CONNECTION (connection), NULL);
|
||||
g_return_val_if_fail (error == NULL || *error == NULL, NULL);
|
||||
|
||||
ret = NULL;
|
||||
scms = NULL;
|
||||
|
||||
g_object_get (connection, "socket", &socket, NULL);
|
||||
|
||||
/* On Linux, we need to turn on SO_PASSCRED if it isn't enabled
|
||||
* already. We also need to turn it off when we're done. See
|
||||
* #617483 for more discussion.
|
||||
*/
|
||||
#ifdef __linux__
|
||||
{
|
||||
gint opt_val;
|
||||
socklen_t opt_len;
|
||||
|
||||
turn_off_so_passcreds = FALSE;
|
||||
opt_val = 0;
|
||||
opt_len = sizeof (gint);
|
||||
if (getsockopt (g_socket_get_fd (socket),
|
||||
SOL_SOCKET,
|
||||
SO_PASSCRED,
|
||||
&opt_val,
|
||||
&opt_len) != 0)
|
||||
{
|
||||
g_set_error (error,
|
||||
G_IO_ERROR,
|
||||
g_io_error_from_errno (errno),
|
||||
_("Error checking if SO_PASSCRED is enabled for socket: %s"),
|
||||
strerror (errno));
|
||||
goto out;
|
||||
}
|
||||
if (opt_len != sizeof (gint))
|
||||
{
|
||||
g_set_error (error,
|
||||
G_IO_ERROR,
|
||||
G_IO_ERROR_FAILED,
|
||||
_("Unexpected option length while checking if SO_PASSCRED is enabled for socket. "
|
||||
"Expected %d bytes, got %d"),
|
||||
(gint) sizeof (gint), (gint) opt_len);
|
||||
goto out;
|
||||
}
|
||||
if (opt_val == 0)
|
||||
{
|
||||
opt_val = 1;
|
||||
if (setsockopt (g_socket_get_fd (socket),
|
||||
SOL_SOCKET,
|
||||
SO_PASSCRED,
|
||||
&opt_val,
|
||||
sizeof opt_val) != 0)
|
||||
{
|
||||
g_set_error (error,
|
||||
G_IO_ERROR,
|
||||
g_io_error_from_errno (errno),
|
||||
_("Error enabling SO_PASSCRED: %s"),
|
||||
strerror (errno));
|
||||
goto out;
|
||||
}
|
||||
turn_off_so_passcreds = TRUE;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
/* ensure the type of GUnixCredentialsMessage has been registered with the type system */
|
||||
credentials_message_gtype = G_TYPE_UNIX_CREDENTIALS_MESSAGE;
|
||||
num_bytes_read = g_socket_receive_message (socket,
|
||||
NULL, /* GSocketAddress **address */
|
||||
NULL,
|
||||
0,
|
||||
&scms,
|
||||
&nscm,
|
||||
NULL,
|
||||
cancellable,
|
||||
error);
|
||||
if (num_bytes_read != 1)
|
||||
{
|
||||
/* Handle situation where g_socket_receive_message() returns
|
||||
* 0 bytes and not setting @error
|
||||
*/
|
||||
if (num_bytes_read == 0 && error != NULL && *error == NULL)
|
||||
{
|
||||
g_set_error_literal (error,
|
||||
G_IO_ERROR,
|
||||
G_IO_ERROR_FAILED,
|
||||
_("Expecting to read a single byte for receiving credentials but read zero bytes"));
|
||||
}
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (nscm != 1)
|
||||
{
|
||||
g_set_error (error,
|
||||
G_IO_ERROR,
|
||||
G_IO_ERROR_FAILED,
|
||||
_("Expecting 1 control message, got %d"),
|
||||
nscm);
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (!G_IS_UNIX_CREDENTIALS_MESSAGE (scms[0]))
|
||||
{
|
||||
g_set_error_literal (error,
|
||||
G_IO_ERROR,
|
||||
G_IO_ERROR_FAILED,
|
||||
_("Unexpected type of ancillary data"));
|
||||
goto out;
|
||||
}
|
||||
|
||||
ret = g_unix_credentials_message_get_credentials (G_UNIX_CREDENTIALS_MESSAGE (scms[0]));
|
||||
g_object_ref (ret);
|
||||
|
||||
out:
|
||||
|
||||
#ifdef __linux__
|
||||
if (turn_off_so_passcreds)
|
||||
{
|
||||
gint opt_val;
|
||||
opt_val = 0;
|
||||
if (setsockopt (g_socket_get_fd (socket),
|
||||
SOL_SOCKET,
|
||||
SO_PASSCRED,
|
||||
&opt_val,
|
||||
sizeof opt_val) != 0)
|
||||
{
|
||||
g_set_error (error,
|
||||
G_IO_ERROR,
|
||||
g_io_error_from_errno (errno),
|
||||
_("Error while disabling SO_PASSCRED: %s"),
|
||||
strerror (errno));
|
||||
goto out;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
if (scms != NULL)
|
||||
{
|
||||
for (n = 0; n < nscm; n++)
|
||||
g_object_unref (scms[n]);
|
||||
g_free (scms);
|
||||
}
|
||||
g_object_unref (socket);
|
||||
return ret;
|
||||
}
|
||||
|
||||
#define __G_UNIX_CONNECTION_C__
|
||||
#include "gioaliasdef.c"
|
||||
|
@ -71,6 +71,15 @@ gint g_unix_connection_receive_fd (GUnixCo
|
||||
GCancellable *cancellable,
|
||||
GError **error);
|
||||
|
||||
gboolean g_unix_connection_send_credentials (GUnixConnection *connection,
|
||||
GCancellable *cancellable,
|
||||
GError **error);
|
||||
|
||||
GCredentials *g_unix_connection_receive_credentials (GUnixConnection *connection,
|
||||
GCancellable *cancellable,
|
||||
GError **error);
|
||||
|
||||
|
||||
G_END_DECLS
|
||||
|
||||
#endif /* __G_UNIX_CONNECTION_H__ */
|
||||
|
341
gio/gunixcredentialsmessage.c
Normal file
341
gio/gunixcredentialsmessage.c
Normal file
@ -0,0 +1,341 @@
|
||||
/* GIO - GLib Input, Output and Streaming Library
|
||||
*
|
||||
* Copyright (C) 2010 Red Hat, Inc.
|
||||
* Copyright (C) 2009 Codethink Limited
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License as published
|
||||
* by the Free Software Foundation; either version 2 of the licence or (at
|
||||
* your option) any later version.
|
||||
*
|
||||
* See the included COPYING file for more information.
|
||||
*
|
||||
* Authors: David Zeuthen <davidz@redhat.com>
|
||||
*/
|
||||
|
||||
/**
|
||||
* SECTION: gunixcredentialsmessage
|
||||
* @title: GUnixCredentialsMessage
|
||||
* @short_description: A GSocketControlMessage containing credentials
|
||||
* @see_also: #GUnixConnection, #GSocketControlMessage
|
||||
*
|
||||
* This #GSocketControlMessage contains a #GCredentials instance. It
|
||||
* may be sent using g_socket_send_message() and received using
|
||||
* g_socket_receive_message() over UNIX sockets (ie: sockets in the
|
||||
* %G_SOCKET_ADDRESS_UNIX family).
|
||||
*
|
||||
* For an easier way to send and receive credentials over
|
||||
* stream-oriented UNIX sockets, see g_unix_connection_send_credentials() and
|
||||
* g_unix_connection_receive_credentials().
|
||||
**/
|
||||
|
||||
#include "config.h"
|
||||
|
||||
/* ---------------------------------------------------------------------------------------------------- */
|
||||
#ifdef __linux__
|
||||
|
||||
#define _GNU_SOURCE
|
||||
#define __USE_GNU
|
||||
#include <sys/types.h>
|
||||
#include <sys/socket.h>
|
||||
#include <sys/un.h>
|
||||
#include <unistd.h>
|
||||
#include <fcntl.h>
|
||||
#define G_UNIX_CREDENTIALS_MESSAGE_SUPPORTED 1
|
||||
|
||||
#else
|
||||
/* TODO: please add support for your UNIX flavor */
|
||||
#define G_UNIX_CREDENTIALS_MESSAGE_SUPPORTED 0
|
||||
#endif
|
||||
|
||||
/* ---------------------------------------------------------------------------------------------------- */
|
||||
|
||||
#include <string.h>
|
||||
#include <errno.h>
|
||||
|
||||
#include "gunixcredentialsmessage.h"
|
||||
#include "gcredentials.h"
|
||||
|
||||
#include "glibintl.h"
|
||||
#include "gioalias.h"
|
||||
|
||||
struct _GUnixCredentialsMessagePrivate
|
||||
{
|
||||
GCredentials *credentials;
|
||||
};
|
||||
|
||||
enum
|
||||
{
|
||||
PROP_0,
|
||||
PROP_CREDENTIALS
|
||||
};
|
||||
|
||||
G_DEFINE_TYPE (GUnixCredentialsMessage, g_unix_credentials_message, G_TYPE_SOCKET_CONTROL_MESSAGE);
|
||||
|
||||
static gsize
|
||||
g_unix_credentials_message_get_size (GSocketControlMessage *message)
|
||||
{
|
||||
#ifdef __linux__
|
||||
return sizeof (struct ucred);
|
||||
#else
|
||||
return 0;
|
||||
#endif
|
||||
}
|
||||
|
||||
static int
|
||||
g_unix_credentials_message_get_level (GSocketControlMessage *message)
|
||||
{
|
||||
return SOL_SOCKET;
|
||||
}
|
||||
|
||||
static int
|
||||
g_unix_credentials_message_get_msg_type (GSocketControlMessage *message)
|
||||
{
|
||||
#ifdef __linux__
|
||||
return SCM_CREDENTIALS;
|
||||
#else
|
||||
return 0;
|
||||
#endif
|
||||
}
|
||||
|
||||
static GSocketControlMessage *
|
||||
g_unix_credentials_message_deserialize (gint level,
|
||||
gint type,
|
||||
gsize size,
|
||||
gpointer data)
|
||||
{
|
||||
GSocketControlMessage *message;
|
||||
|
||||
message = NULL;
|
||||
|
||||
#ifdef __linux__
|
||||
{
|
||||
GCredentials *credentials;
|
||||
struct ucred *ucred;
|
||||
|
||||
if (level != SOL_SOCKET || type != SCM_CREDENTIALS)
|
||||
goto out;
|
||||
|
||||
if (size != sizeof (struct ucred))
|
||||
{
|
||||
g_warning ("Expected a struct ucred (%" G_GSIZE_FORMAT " bytes) but "
|
||||
"got %" G_GSIZE_FORMAT " bytes of data",
|
||||
sizeof (struct ucred),
|
||||
size);
|
||||
goto out;
|
||||
}
|
||||
|
||||
ucred = data;
|
||||
|
||||
credentials = g_credentials_new ();
|
||||
g_credentials_set_native (credentials, ucred);
|
||||
message = g_unix_credentials_message_new_with_credentials (credentials);
|
||||
g_object_unref (credentials);
|
||||
out:
|
||||
;
|
||||
}
|
||||
#endif
|
||||
|
||||
return message;
|
||||
}
|
||||
|
||||
static void
|
||||
g_unix_credentials_message_serialize (GSocketControlMessage *_message,
|
||||
gpointer data)
|
||||
{
|
||||
GUnixCredentialsMessage *message = G_UNIX_CREDENTIALS_MESSAGE (_message);
|
||||
#ifdef __linux__
|
||||
memcpy (data, g_credentials_get_native (message->priv->credentials), sizeof (struct ucred));
|
||||
#endif
|
||||
}
|
||||
|
||||
static void
|
||||
g_unix_credentials_message_finalize (GObject *object)
|
||||
{
|
||||
GUnixCredentialsMessage *message = G_UNIX_CREDENTIALS_MESSAGE (object);
|
||||
|
||||
if (message->priv->credentials != NULL)
|
||||
g_object_unref (message->priv->credentials);
|
||||
|
||||
G_OBJECT_CLASS (g_unix_credentials_message_parent_class)->finalize (object);
|
||||
}
|
||||
|
||||
static void
|
||||
g_unix_credentials_message_init (GUnixCredentialsMessage *message)
|
||||
{
|
||||
message->priv = G_TYPE_INSTANCE_GET_PRIVATE (message,
|
||||
G_TYPE_UNIX_CREDENTIALS_MESSAGE,
|
||||
GUnixCredentialsMessagePrivate);
|
||||
}
|
||||
|
||||
static void
|
||||
g_unix_credentials_message_get_property (GObject *object,
|
||||
guint prop_id,
|
||||
GValue *value,
|
||||
GParamSpec *pspec)
|
||||
{
|
||||
GUnixCredentialsMessage *message = G_UNIX_CREDENTIALS_MESSAGE (object);
|
||||
|
||||
switch (prop_id)
|
||||
{
|
||||
case PROP_CREDENTIALS:
|
||||
g_value_set_object (value, message->priv->credentials);
|
||||
break;
|
||||
|
||||
default:
|
||||
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
g_unix_credentials_message_set_property (GObject *object,
|
||||
guint prop_id,
|
||||
const GValue *value,
|
||||
GParamSpec *pspec)
|
||||
{
|
||||
GUnixCredentialsMessage *message = G_UNIX_CREDENTIALS_MESSAGE (object);
|
||||
|
||||
switch (prop_id)
|
||||
{
|
||||
case PROP_CREDENTIALS:
|
||||
message->priv->credentials = g_value_dup_object (value);
|
||||
break;
|
||||
|
||||
default:
|
||||
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
g_unix_credentials_message_constructed (GObject *object)
|
||||
{
|
||||
GUnixCredentialsMessage *message = G_UNIX_CREDENTIALS_MESSAGE (object);
|
||||
|
||||
if (message->priv->credentials == NULL)
|
||||
message->priv->credentials = g_credentials_new ();
|
||||
|
||||
if (G_OBJECT_CLASS (g_unix_credentials_message_parent_class)->constructed != NULL)
|
||||
G_OBJECT_CLASS (g_unix_credentials_message_parent_class)->constructed (object);
|
||||
}
|
||||
|
||||
static void
|
||||
g_unix_credentials_message_class_init (GUnixCredentialsMessageClass *class)
|
||||
{
|
||||
GSocketControlMessageClass *scm_class;
|
||||
GObjectClass *gobject_class;
|
||||
|
||||
g_type_class_add_private (class, sizeof (GUnixCredentialsMessagePrivate));
|
||||
|
||||
gobject_class = G_OBJECT_CLASS (class);
|
||||
gobject_class->get_property = g_unix_credentials_message_get_property;
|
||||
gobject_class->set_property = g_unix_credentials_message_set_property;
|
||||
gobject_class->finalize = g_unix_credentials_message_finalize;
|
||||
gobject_class->constructed = g_unix_credentials_message_constructed;
|
||||
|
||||
scm_class = G_SOCKET_CONTROL_MESSAGE_CLASS (class);
|
||||
scm_class->get_size = g_unix_credentials_message_get_size;
|
||||
scm_class->get_level = g_unix_credentials_message_get_level;
|
||||
scm_class->get_type = g_unix_credentials_message_get_msg_type;
|
||||
scm_class->serialize = g_unix_credentials_message_serialize;
|
||||
scm_class->deserialize = g_unix_credentials_message_deserialize;
|
||||
|
||||
/**
|
||||
* GUnixCredentialsMessage:credentials:
|
||||
*
|
||||
* The credentials stored in the message.
|
||||
*
|
||||
* Since: 2.26
|
||||
*/
|
||||
g_object_class_install_property (gobject_class,
|
||||
PROP_CREDENTIALS,
|
||||
g_param_spec_object ("credentials",
|
||||
P_("Credentials"),
|
||||
P_("The credentials stored in the message"),
|
||||
G_TYPE_CREDENTIALS,
|
||||
G_PARAM_READABLE |
|
||||
G_PARAM_WRITABLE |
|
||||
G_PARAM_CONSTRUCT_ONLY |
|
||||
G_PARAM_STATIC_NAME |
|
||||
G_PARAM_STATIC_BLURB |
|
||||
G_PARAM_STATIC_NICK));
|
||||
|
||||
}
|
||||
|
||||
/* ---------------------------------------------------------------------------------------------------- */
|
||||
|
||||
/**
|
||||
* g_unix_credentials_message_is_supported:
|
||||
*
|
||||
* Checks if passing a #GCredential on a #GSocket is supported on this platform.
|
||||
*
|
||||
* Returns: %TRUE if supported, %FALSE otherwise
|
||||
*
|
||||
* Since: 2.26
|
||||
*/
|
||||
gboolean
|
||||
g_unix_credentials_message_is_supported (void)
|
||||
{
|
||||
return G_UNIX_CREDENTIALS_MESSAGE_SUPPORTED;
|
||||
}
|
||||
|
||||
/* ---------------------------------------------------------------------------------------------------- */
|
||||
|
||||
/**
|
||||
* g_unix_credentials_message_new:
|
||||
*
|
||||
* Creates a new #GUnixCredentialsMessage with credentials matching the current processes.
|
||||
*
|
||||
* Returns: a new #GUnixCredentialsMessage
|
||||
*
|
||||
* Since: 2.26
|
||||
*/
|
||||
GSocketControlMessage *
|
||||
g_unix_credentials_message_new (void)
|
||||
{
|
||||
g_return_val_if_fail (g_unix_credentials_message_is_supported (), NULL);
|
||||
return g_object_new (G_TYPE_UNIX_CREDENTIALS_MESSAGE,
|
||||
NULL);
|
||||
}
|
||||
|
||||
/**
|
||||
* g_unix_credentials_message_new_with_credentials:
|
||||
* @credentials: A #GCredentials object.
|
||||
*
|
||||
* Creates a new #GUnixCredentialsMessage holding @credentials.
|
||||
*
|
||||
* Returns: a new #GUnixCredentialsMessage
|
||||
*
|
||||
* Since: 2.26
|
||||
*/
|
||||
GSocketControlMessage *
|
||||
g_unix_credentials_message_new_with_credentials (GCredentials *credentials)
|
||||
{
|
||||
g_return_val_if_fail (G_IS_CREDENTIALS (credentials), NULL);
|
||||
g_return_val_if_fail (g_unix_credentials_message_is_supported (), NULL);
|
||||
return g_object_new (G_TYPE_UNIX_CREDENTIALS_MESSAGE,
|
||||
"credentials", credentials,
|
||||
NULL);
|
||||
}
|
||||
|
||||
/**
|
||||
* g_unix_credentials_message_get_credentials:
|
||||
* @message: A #GUnixCredentialsMessage.
|
||||
*
|
||||
* Gets the credentials stored in @message.
|
||||
*
|
||||
* Returns: A #GCredentials instance. Do not free, it is owned by @message.
|
||||
*
|
||||
* Since: 2.26
|
||||
*/
|
||||
GCredentials *
|
||||
g_unix_credentials_message_get_credentials (GUnixCredentialsMessage *message)
|
||||
{
|
||||
g_return_val_if_fail (G_IS_UNIX_CREDENTIALS_MESSAGE (message), NULL);
|
||||
return message->priv->credentials;
|
||||
}
|
||||
|
||||
|
||||
#define __G_UNIX_CREDENTIALS_MESSAGE_C__
|
||||
#include "gioaliasdef.c"
|
83
gio/gunixcredentialsmessage.h
Normal file
83
gio/gunixcredentialsmessage.h
Normal file
@ -0,0 +1,83 @@
|
||||
/* GIO - GLib Input, Output and Streaming Library
|
||||
*
|
||||
* Copyright (C) 2010 Red Hat, Inc.
|
||||
* Copyright (C) 2009 Codethink Limited
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License as published
|
||||
* by the Free Software Foundation; either version 2 of the licence or (at
|
||||
* your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General
|
||||
* Public License along with this library; if not, write to the
|
||||
* Free Software Foundation, Inc., 59 Temple Place, Suite 330,
|
||||
* Boston, MA 02111-1307, USA.
|
||||
*
|
||||
* Authors: David Zeuthen <davidz@redhat.com>
|
||||
*/
|
||||
|
||||
#ifndef __G_UNIX_CREDENTIALS_MESSAGE_H__
|
||||
#define __G_UNIX_CREDENTIALS_MESSAGE_H__
|
||||
|
||||
#include <gio/giotypes.h>
|
||||
#include <gio/gsocketcontrolmessage.h>
|
||||
|
||||
G_BEGIN_DECLS
|
||||
|
||||
#define G_TYPE_UNIX_CREDENTIALS_MESSAGE (g_unix_credentials_message_get_type ())
|
||||
#define G_UNIX_CREDENTIALS_MESSAGE(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), G_TYPE_UNIX_CREDENTIALS_MESSAGE, GUnixCredentialsMessage))
|
||||
#define G_UNIX_CREDENTIALS_MESSAGE_CLASS(c) (G_TYPE_CHECK_CLASS_CAST ((c), G_TYPE_UNIX_CREDENTIALS_MESSAGE, GUnixCredentialsMessageClass))
|
||||
#define G_IS_UNIX_CREDENTIALS_MESSAGE(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), G_TYPE_UNIX_CREDENTIALS_MESSAGE))
|
||||
#define G_IS_UNIX_CREDENTIALS_MESSAGE_CLASS(c) (G_TYPE_CHECK_CLASS_TYPE ((c), G_TYPE_UNIX_CREDENTIALS_MESSAGE))
|
||||
#define G_UNIX_CREDENTIALS_MESSAGE_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS ((o), G_TYPE_UNIX_CREDENTIALS_MESSAGE, GUnixCredentialsMessageClass))
|
||||
|
||||
typedef struct _GUnixCredentialsMessagePrivate GUnixCredentialsMessagePrivate;
|
||||
typedef struct _GUnixCredentialsMessageClass GUnixCredentialsMessageClass;
|
||||
|
||||
/**
|
||||
* GUnixCredentialsMessageClass:
|
||||
*
|
||||
* Class structure for #GUnixCredentialsMessage.
|
||||
*
|
||||
* Since: 2.26
|
||||
*/
|
||||
struct _GUnixCredentialsMessageClass
|
||||
{
|
||||
GSocketControlMessageClass parent_class;
|
||||
|
||||
/*< private >*/
|
||||
|
||||
/* Padding for future expansion */
|
||||
void (*_g_reserved1) (void);
|
||||
void (*_g_reserved2) (void);
|
||||
};
|
||||
|
||||
/**
|
||||
* GUnixCredentialsMessage:
|
||||
*
|
||||
* The #GUnixCredentialsMessage structure contains only private data
|
||||
* and should only be accessed using the provided API.
|
||||
*
|
||||
* Since: 2.26
|
||||
*/
|
||||
struct _GUnixCredentialsMessage
|
||||
{
|
||||
GSocketControlMessage parent_instance;
|
||||
GUnixCredentialsMessagePrivate *priv;
|
||||
};
|
||||
|
||||
GType g_unix_credentials_message_get_type (void) G_GNUC_CONST;
|
||||
GSocketControlMessage *g_unix_credentials_message_new (void);
|
||||
GSocketControlMessage *g_unix_credentials_message_new_with_credentials (GCredentials *credentials);
|
||||
GCredentials *g_unix_credentials_message_get_credentials (GUnixCredentialsMessage *message);
|
||||
|
||||
gboolean g_unix_credentials_message_is_supported (void);
|
||||
|
||||
G_END_DECLS
|
||||
|
||||
#endif /* __G_UNIX_CREDENTIALS_MESSAGE_H__ */
|
@ -23,7 +23,7 @@
|
||||
#ifndef __G_UNIX_FD_LIST_H__
|
||||
#define __G_UNIX_FD_LIST_H__
|
||||
|
||||
#include <glib-object.h>
|
||||
#include <gio/gio.h>
|
||||
|
||||
G_BEGIN_DECLS
|
||||
|
||||
@ -41,7 +41,6 @@ G_BEGIN_DECLS
|
||||
|
||||
typedef struct _GUnixFDListPrivate GUnixFDListPrivate;
|
||||
typedef struct _GUnixFDListClass GUnixFDListClass;
|
||||
typedef struct _GUnixFDList GUnixFDList;
|
||||
|
||||
struct _GUnixFDListClass
|
||||
{
|
||||
|
@ -44,6 +44,7 @@
|
||||
#include <errno.h>
|
||||
|
||||
#include "gunixfdmessage.h"
|
||||
#include "gunixfdlist.h"
|
||||
#include "gioerror.h"
|
||||
|
||||
#include "gioalias.h"
|
||||
|
@ -23,8 +23,8 @@
|
||||
#ifndef __G_UNIX_FD_MESSAGE_H__
|
||||
#define __G_UNIX_FD_MESSAGE_H__
|
||||
|
||||
#include <gio/gunixfdlist.h>
|
||||
#include <gio/gio.h>
|
||||
#include <gio/gunixfdlist.h>
|
||||
|
||||
G_BEGIN_DECLS
|
||||
|
||||
|
@ -9,7 +9,7 @@ if ! which readelf 2>/dev/null >/dev/null; then
|
||||
exit 0
|
||||
fi
|
||||
|
||||
SKIP='\<g_access\|\<g_array_\|\<g_ascii\|\<g_list_\|\<g_assertion_message\|\<g_warn_message\|\<g_atomic\|\<g_bit_\|\<g_boxed\|\<g_build_filename\|\<g_byte_array\|\<g_checksum\|\<g_child_watch\|\<g_clear_error\|\<g_convert\|\<g_dir_\|\<g_enum_\|\<g_error_\|\<g_prefix_error\|\<g_file_error_quark\|\<g_file_get_contents\|\<g_file_set_contents\|\<g_file_test\|\<g_file_read_link\|\<g_filename_\|\<g_find_program_in_path\|\<g_flags_\|\<g_free\|\<g_get_\|\<g_getenv\|\<g_setenv\|\<g_hash_table_\|\<g_hostname_\|\<g_iconv\|\<g_idle_\|\<g_intern_static_string\|\<g_io_add_watch\|\<g_io_channel_\|\<g_io_create_watch\|\<g_key_file_\|\<g_listenv\|\<g_locale_to_utf8\|\<g_log\|\<g_main_context_\|\<g_main_current_source\|\<g_main_loop_\|\<g_malloc\|\<g_markup_\|\<g_mkdir_\|\<g_mkstemp\|\<g_module_\|\<g_object_\|\<g_once_\|\<g_param_spec_\|\<g_path_\|\<g_poll\|\<g_printerr\|\<g_propagate_error\|\<g_ptr_array_\|\<g_qsort_\|\<g_quark_\|\<g_queue_\|\<g_random_int_range\|\<g_realloc\|\<g_return_if_fail\|\<g_set_error\|\<g_shell_\|\<g_signal_\|\<g_slice_\|\<g_slist_\|\<g_snprintf\|\<g_source_\|\<g_spawn_\|\<g_static_\|\<g_str\|\<g_thread_pool_\|\<g_time_val_add\|\<g_timeout_\|\<g_type_\|\<g_unlink\|\<g_uri_\|\<g_utf8_\|\<g_value_\|\<g_tree_\|\<g_variant_\|\<g_mapped_file_\|\<g_intern_string\>\|\<g_compute_checksum'
|
||||
SKIP='\<g_access\|\<g_array_\|\<g_ascii\|\<g_list_\|\<g_assertion_message\|\<g_warn_message\|\<g_atomic\|\<g_bit_\|\<g_boxed\|\<g_build_filename\|\<g_byte_array\|\<g_checksum\|\<g_child_watch\|\<g_clear_error\|\<g_convert\|\<g_dir_\|\<g_enum_\|\<g_error_\|\<g_prefix_error\|\<g_file_error_quark\|\<g_file_get_contents\|\<g_file_set_contents\|\<g_file_test\|\<g_file_read_link\|\<g_filename_\|\<g_find_program_in_path\|\<g_flags_\|\<g_free\|\<g_get_\|\<g_getenv\|\<g_setenv\|\<g_hash_table_\|\<g_hostname_\|\<g_iconv\|\<g_idle_\|\<g_intern_static_string\|\<g_io_add_watch\|\<g_io_channel_\|\<g_io_create_watch\|\<g_key_file_\|\<g_listenv\|\<g_locale_to_utf8\|\<g_log\|\<g_main_context_\|\<g_main_current_source\|\<g_main_loop_\|\<g_malloc\|\<g_markup_\|\<g_mkdir_\|\<g_mkstemp\|\<g_module_\|\<g_object_\|\<g_once_\|\<g_param_spec_\|\<g_path_\|\<g_poll\|\<g_printerr\|\<g_propagate_error\|\<g_ptr_array_\|\<g_qsort_\|\<g_quark_\|\<g_queue_\|\<g_random_int_range\|\<g_realloc\|\<g_return_if_fail\|\<g_set_error\|\<g_shell_\|\<g_signal_\|\<g_slice_\|\<g_slist_\|\<g_snprintf\|\<g_source_\|\<g_spawn_\|\<g_static_\|\<g_str\|\<g_thread_pool_\|\<g_time_val_add\|\<g_timeout_\|\<g_type_\|\<g_unlink\|\<g_uri_\|\<g_utf8_\|\<g_value_\|\<g_tree_\|\<g_variant_\|\<g_mapped_file_\|\<g_intern_string\>\|\<g_compute_checksum\|\<g_memdup\|\<g_print\|\<g_random_int\|\<g_propagate_prefixed_e\|\<g_thread_create_full\|\<g_int_hash\|\<g_file_open_tmp\|\<g_thread_self\|\<g_usleep'
|
||||
|
||||
for so in .libs/lib*.so; do
|
||||
echo Checking $so for local PLT entries
|
||||
|
@ -1,3 +1,5 @@
|
||||
NULL =
|
||||
|
||||
include $(top_srcdir)/Makefile.decl
|
||||
|
||||
INCLUDES = \
|
||||
@ -36,19 +38,41 @@ TEST_PROGS += \
|
||||
contexts \
|
||||
gsettings \
|
||||
gschema-compile \
|
||||
async-close-output-stream
|
||||
async-close-output-stream \
|
||||
gdbus-addresses \
|
||||
gdbus-connection \
|
||||
gdbus-names \
|
||||
gdbus-proxy \
|
||||
gdbus-introspection \
|
||||
gdbus-threading \
|
||||
gdbus-export \
|
||||
gdbus-error \
|
||||
gdbus-peer \
|
||||
gdbus-exit-on-close \
|
||||
$(NULL)
|
||||
|
||||
SAMPLE_PROGS = \
|
||||
resolver \
|
||||
socket-server \
|
||||
socket-client \
|
||||
echo-server \
|
||||
httpd \
|
||||
send-data \
|
||||
filter-cat \
|
||||
gdbus-example-export \
|
||||
gdbus-example-own-name \
|
||||
gdbus-example-watch-name \
|
||||
gdbus-example-watch-proxy \
|
||||
gdbus-example-server \
|
||||
gdbus-example-subtree \
|
||||
gdbus-example-peer \
|
||||
gdbus-example-proxy-subclass \
|
||||
$(NULL)
|
||||
|
||||
SAMPLE_PROGS = \
|
||||
resolver \
|
||||
socket-server \
|
||||
socket-client \
|
||||
echo-server \
|
||||
httpd \
|
||||
send-data \
|
||||
filter-cat
|
||||
|
||||
if OS_UNIX
|
||||
TEST_PROGS += live-g-file desktop-app-info unix-fd #unix-streams
|
||||
SAMPLE_PROGS += gdbus-example-unix-fd-client
|
||||
endif
|
||||
|
||||
if OS_WIN32
|
||||
@ -154,6 +178,70 @@ gsettings_LDADD = $(progs_ldadd)
|
||||
gschema_compile_SOURCES = gschema-compile.c
|
||||
gschema_compile_LDADD = $(progs_ldadd)
|
||||
|
||||
if HAVE_DBUS1
|
||||
TEST_PROGS += gdbus-serialization
|
||||
gdbus_serialization_SOURCES = gdbus-serialization.c gdbus-tests.h gdbus-tests.c
|
||||
gdbus_serialization_CFLAGS = $(DBUS1_CFLAGS)
|
||||
gdbus_serialization_LDADD = $(progs_ldadd) $(DBUS1_LIBS)
|
||||
endif
|
||||
|
||||
gdbus_addresses_SOURCES = gdbus-addresses.c
|
||||
gdbus_addresses_LDADD = $(progs_ldadd)
|
||||
|
||||
gdbus_connection_SOURCES = gdbus-connection.c gdbus-sessionbus.c gdbus-sessionbus.h gdbus-tests.h gdbus-tests.c
|
||||
gdbus_connection_LDADD = $(progs_ldadd)
|
||||
|
||||
gdbus_names_SOURCES = gdbus-names.c gdbus-sessionbus.c gdbus-sessionbus.h gdbus-tests.h gdbus-tests.c
|
||||
gdbus_names_LDADD = $(progs_ldadd)
|
||||
|
||||
gdbus_proxy_SOURCES = gdbus-proxy.c gdbus-sessionbus.c gdbus-sessionbus.h gdbus-tests.h gdbus-tests.c
|
||||
gdbus_proxy_LDADD = $(progs_ldadd)
|
||||
|
||||
gdbus_introspection_SOURCES = gdbus-introspection.c gdbus-sessionbus.c gdbus-sessionbus.h gdbus-tests.h gdbus-tests.c
|
||||
gdbus_introspection_LDADD = $(progs_ldadd)
|
||||
|
||||
gdbus_threading_SOURCES = gdbus-threading.c gdbus-sessionbus.c gdbus-sessionbus.h gdbus-tests.h gdbus-tests.c
|
||||
gdbus_threading_LDADD = $(progs_ldadd)
|
||||
|
||||
gdbus_export_SOURCES = gdbus-export.c gdbus-sessionbus.c gdbus-sessionbus.h gdbus-tests.h gdbus-tests.c
|
||||
gdbus_export_LDADD = $(progs_ldadd)
|
||||
|
||||
gdbus_error_SOURCES = gdbus-error.c gdbus-sessionbus.c gdbus-sessionbus.h gdbus-tests.h gdbus-tests.c
|
||||
gdbus_error_LDADD = $(progs_ldadd)
|
||||
|
||||
gdbus_peer_SOURCES = gdbus-peer.c gdbus-sessionbus.c gdbus-sessionbus.h gdbus-tests.h gdbus-tests.c
|
||||
gdbus_peer_LDADD = $(progs_ldadd)
|
||||
|
||||
gdbus_exit_on_close_SOURCES = gdbus-exit-on-close.c gdbus-sessionbus.c gdbus-sessionbus.h gdbus-tests.h gdbus-tests.c
|
||||
gdbus_exit_on_close_LDADD = $(progs_ldadd)
|
||||
|
||||
gdbus_example_watch_name_SOURCES = gdbus-example-watch-name.c
|
||||
gdbus_example_watch_name_LDADD = $(progs_ldadd)
|
||||
|
||||
gdbus_example_watch_proxy_SOURCES = gdbus-example-watch-proxy.c
|
||||
gdbus_example_watch_proxy_LDADD = $(progs_ldadd)
|
||||
|
||||
gdbus_example_own_name_SOURCES = gdbus-example-own-name.c
|
||||
gdbus_example_own_name_LDADD = $(progs_ldadd)
|
||||
|
||||
gdbus_example_server_SOURCES = gdbus-example-server.c
|
||||
gdbus_example_server_LDADD = $(progs_ldadd)
|
||||
|
||||
gdbus_example_unix_fd_client_SOURCES = gdbus-example-unix-fd-client.c
|
||||
gdbus_example_unix_fd_client_LDADD = $(progs_ldadd)
|
||||
|
||||
gdbus_example_subtree_SOURCES = gdbus-example-subtree.c
|
||||
gdbus_example_subtree_LDADD = $(progs_ldadd)
|
||||
|
||||
gdbus_example_peer_SOURCES = gdbus-example-peer.c
|
||||
gdbus_example_peer_LDADD = $(progs_ldadd)
|
||||
|
||||
gdbus_example_proxy_subclass_SOURCES = gdbus-example-proxy-subclass.c
|
||||
gdbus_example_proxy_subclass_LDADD = $(progs_ldadd)
|
||||
|
||||
gdbus_example_export_SOURCES = gdbus-example-export.c
|
||||
gdbus_example_export_LDADD = $(progs_ldadd)
|
||||
|
||||
EXTRA_DIST += \
|
||||
socket-common.c \
|
||||
org.gtk.test.gschema \
|
||||
|
77
gio/tests/gdbus-addresses.c
Normal file
77
gio/tests/gdbus-addresses.c
Normal file
@ -0,0 +1,77 @@
|
||||
/* GLib testing framework examples and tests
|
||||
*
|
||||
* Copyright (C) 2008-2010 Red Hat, Inc.
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General
|
||||
* Public License along with this library; if not, write to the
|
||||
* Free Software Foundation, Inc., 59 Temple Place, Suite 330,
|
||||
* Boston, MA 02111-1307, USA.
|
||||
*
|
||||
* Author: David Zeuthen <davidz@redhat.com>
|
||||
*/
|
||||
|
||||
#include <gio/gio.h>
|
||||
|
||||
#ifdef G_OS_UNIX
|
||||
#include <gio/gunixsocketaddress.h>
|
||||
#endif
|
||||
|
||||
/* ---------------------------------------------------------------------------------------------------- */
|
||||
|
||||
#ifdef G_OS_UNIX
|
||||
static void
|
||||
test_unix_address (void)
|
||||
{
|
||||
g_assert (!g_dbus_is_supported_address ("some-imaginary-transport:foo=bar", NULL));
|
||||
g_assert (g_dbus_is_supported_address ("unix:path=/tmp/dbus-test", NULL));
|
||||
g_assert (g_dbus_is_supported_address ("unix:abstract=/tmp/dbus-another-test", NULL));
|
||||
g_assert (g_dbus_is_address ("unix:foo=bar"));
|
||||
g_assert (!g_dbus_is_supported_address ("unix:foo=bar", NULL));
|
||||
g_assert (!g_dbus_is_address ("unix:path=/foo;abstract=/bar"));
|
||||
g_assert (!g_dbus_is_supported_address ("unix:path=/foo;abstract=/bar", NULL));
|
||||
g_assert (g_dbus_is_supported_address ("unix:path=/tmp/concrete;unix:abstract=/tmp/abstract", NULL));
|
||||
g_assert (g_dbus_is_address ("some-imaginary-transport:foo=bar"));
|
||||
|
||||
g_assert (g_dbus_is_address ("some-imaginary-transport:foo=bar;unix:path=/this/is/valid"));
|
||||
g_assert (!g_dbus_is_supported_address ("some-imaginary-transport:foo=bar;unix:path=/this/is/valid", NULL));
|
||||
}
|
||||
#endif
|
||||
|
||||
static void
|
||||
test_nonce_tcp_address (void)
|
||||
{
|
||||
g_assert (g_dbus_is_supported_address ("nonce-tcp:host=localhost,port=42,noncefile=/foo/bar", NULL));
|
||||
g_assert (g_dbus_is_supported_address ("nonce-tcp:host=localhost,port=42,noncefile=/foo/bar,family=ipv6", NULL));
|
||||
g_assert (g_dbus_is_supported_address ("nonce-tcp:host=localhost,port=42,noncefile=/foo/bar,family=ipv4", NULL));
|
||||
|
||||
g_assert (!g_dbus_is_supported_address ("nonce-tcp:host=localhost,port=42,noncefile=/foo/bar,family=blah", NULL));
|
||||
g_assert (!g_dbus_is_supported_address ("nonce-tcp:host=localhost,port=420000,noncefile=/foo/bar,family=ipv4", NULL));
|
||||
g_assert (!g_dbus_is_supported_address ("nonce-tcp:host=,port=x42,noncefile=/foo/bar,family=ipv4", NULL));
|
||||
g_assert (!g_dbus_is_supported_address ("nonce-tcp:host=,port=42x,noncefile=/foo/bar,family=ipv4", NULL));
|
||||
g_assert (!g_dbus_is_supported_address ("nonce-tcp:host=,port=420000,noncefile=/foo/bar,family=ipv4", NULL));
|
||||
}
|
||||
|
||||
int
|
||||
main (int argc,
|
||||
char *argv[])
|
||||
{
|
||||
g_type_init ();
|
||||
g_test_init (&argc, &argv, NULL);
|
||||
|
||||
#ifdef G_OS_UNIX
|
||||
g_test_add_func ("/gdbus/unix-address", test_unix_address);
|
||||
#endif
|
||||
g_test_add_func ("/gdbus/nonce-tcp-address", test_nonce_tcp_address);
|
||||
return g_test_run();
|
||||
}
|
||||
|
653
gio/tests/gdbus-connection.c
Normal file
653
gio/tests/gdbus-connection.c
Normal file
@ -0,0 +1,653 @@
|
||||
/* GLib testing framework examples and tests
|
||||
*
|
||||
* Copyright (C) 2008-2010 Red Hat, Inc.
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General
|
||||
* Public License along with this library; if not, write to the
|
||||
* Free Software Foundation, Inc., 59 Temple Place, Suite 330,
|
||||
* Boston, MA 02111-1307, USA.
|
||||
*
|
||||
* Author: David Zeuthen <davidz@redhat.com>
|
||||
*/
|
||||
|
||||
#include <gio/gio.h>
|
||||
#include <unistd.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "gdbus-tests.h"
|
||||
|
||||
/* all tests rely on a shared mainloop */
|
||||
static GMainLoop *loop = NULL;
|
||||
|
||||
/* ---------------------------------------------------------------------------------------------------- */
|
||||
/* Connection life-cycle testing */
|
||||
/* ---------------------------------------------------------------------------------------------------- */
|
||||
|
||||
static void
|
||||
test_connection_life_cycle (void)
|
||||
{
|
||||
GDBusConnection *c;
|
||||
GDBusConnection *c2;
|
||||
GError *error;
|
||||
|
||||
error = NULL;
|
||||
|
||||
/*
|
||||
* Check for correct behavior when no bus is present
|
||||
*
|
||||
*/
|
||||
c = g_bus_get_sync (G_BUS_TYPE_SESSION, NULL, &error);
|
||||
_g_assert_error_domain (error, G_IO_ERROR);
|
||||
g_assert (!g_dbus_error_is_remote_error (error));
|
||||
g_assert (c == NULL);
|
||||
g_error_free (error);
|
||||
error = NULL;
|
||||
|
||||
/*
|
||||
* Check for correct behavior when a bus is present
|
||||
*/
|
||||
session_bus_up ();
|
||||
/* case 1 */
|
||||
c = g_bus_get_sync (G_BUS_TYPE_SESSION, NULL, &error);
|
||||
g_assert_no_error (error);
|
||||
g_assert (c != NULL);
|
||||
g_assert (!g_dbus_connection_is_closed (c));
|
||||
|
||||
/*
|
||||
* Check that singleton handling work
|
||||
*/
|
||||
c2 = g_bus_get_sync (G_BUS_TYPE_SESSION, NULL, &error);
|
||||
g_assert_no_error (error);
|
||||
g_assert (c2 != NULL);
|
||||
g_assert (c == c2);
|
||||
g_object_unref (c2);
|
||||
|
||||
/*
|
||||
* Check that private connections work
|
||||
*/
|
||||
c2 = _g_bus_get_priv (G_BUS_TYPE_SESSION, NULL, &error);
|
||||
g_assert_no_error (error);
|
||||
g_assert (c2 != NULL);
|
||||
g_assert (c != c2);
|
||||
g_object_unref (c2);
|
||||
|
||||
c2 = _g_bus_get_priv (G_BUS_TYPE_SESSION, NULL, &error);
|
||||
g_assert_no_error (error);
|
||||
g_assert (c2 != NULL);
|
||||
g_assert (!g_dbus_connection_is_closed (c2));
|
||||
g_dbus_connection_close (c2);
|
||||
_g_assert_signal_received (c2, "closed");
|
||||
g_assert (g_dbus_connection_is_closed (c2));
|
||||
g_object_unref (c2);
|
||||
|
||||
/*
|
||||
* Check for correct behavior when the bus goes away
|
||||
*
|
||||
*/
|
||||
g_assert (!g_dbus_connection_is_closed (c));
|
||||
g_dbus_connection_set_exit_on_close (c, FALSE);
|
||||
session_bus_down ();
|
||||
if (!g_dbus_connection_is_closed (c))
|
||||
_g_assert_signal_received (c, "closed");
|
||||
g_assert (g_dbus_connection_is_closed (c));
|
||||
|
||||
_g_object_wait_for_single_ref (c);
|
||||
g_object_unref (c);
|
||||
}
|
||||
|
||||
/* ---------------------------------------------------------------------------------------------------- */
|
||||
/* Test that sending and receiving messages work as expected */
|
||||
/* ---------------------------------------------------------------------------------------------------- */
|
||||
|
||||
static void
|
||||
msg_cb_expect_error_disconnected (GDBusConnection *connection,
|
||||
GAsyncResult *res,
|
||||
gpointer user_data)
|
||||
{
|
||||
GError *error;
|
||||
GVariant *result;
|
||||
|
||||
error = NULL;
|
||||
result = g_dbus_connection_call_finish (connection,
|
||||
res,
|
||||
&error);
|
||||
g_assert_error (error, G_IO_ERROR, G_IO_ERROR_CLOSED);
|
||||
g_assert (!g_dbus_error_is_remote_error (error));
|
||||
g_error_free (error);
|
||||
g_assert (result == NULL);
|
||||
|
||||
g_main_loop_quit (loop);
|
||||
}
|
||||
|
||||
static void
|
||||
msg_cb_expect_error_unknown_method (GDBusConnection *connection,
|
||||
GAsyncResult *res,
|
||||
gpointer user_data)
|
||||
{
|
||||
GError *error;
|
||||
GVariant *result;
|
||||
|
||||
error = NULL;
|
||||
result = g_dbus_connection_call_finish (connection,
|
||||
res,
|
||||
&error);
|
||||
g_assert_error (error, G_DBUS_ERROR, G_DBUS_ERROR_UNKNOWN_METHOD);
|
||||
g_assert (g_dbus_error_is_remote_error (error));
|
||||
g_assert (result == NULL);
|
||||
|
||||
g_main_loop_quit (loop);
|
||||
}
|
||||
|
||||
static void
|
||||
msg_cb_expect_success (GDBusConnection *connection,
|
||||
GAsyncResult *res,
|
||||
gpointer user_data)
|
||||
{
|
||||
GError *error;
|
||||
GVariant *result;
|
||||
|
||||
error = NULL;
|
||||
result = g_dbus_connection_call_finish (connection,
|
||||
res,
|
||||
&error);
|
||||
g_assert_no_error (error);
|
||||
g_assert (result != NULL);
|
||||
g_variant_unref (result);
|
||||
|
||||
g_main_loop_quit (loop);
|
||||
}
|
||||
|
||||
static void
|
||||
msg_cb_expect_error_cancelled (GDBusConnection *connection,
|
||||
GAsyncResult *res,
|
||||
gpointer user_data)
|
||||
{
|
||||
GError *error;
|
||||
GVariant *result;
|
||||
|
||||
error = NULL;
|
||||
result = g_dbus_connection_call_finish (connection,
|
||||
res,
|
||||
&error);
|
||||
g_assert_error (error, G_IO_ERROR, G_IO_ERROR_CANCELLED);
|
||||
g_assert (!g_dbus_error_is_remote_error (error));
|
||||
g_error_free (error);
|
||||
g_assert (result == NULL);
|
||||
|
||||
g_main_loop_quit (loop);
|
||||
}
|
||||
|
||||
static void
|
||||
msg_cb_expect_error_cancelled_2 (GDBusConnection *connection,
|
||||
GAsyncResult *res,
|
||||
gpointer user_data)
|
||||
{
|
||||
GError *error;
|
||||
GVariant *result;
|
||||
|
||||
error = NULL;
|
||||
result = g_dbus_connection_call_finish (connection,
|
||||
res,
|
||||
&error);
|
||||
g_assert_error (error, G_IO_ERROR, G_IO_ERROR_CANCELLED);
|
||||
g_assert (!g_dbus_error_is_remote_error (error));
|
||||
g_error_free (error);
|
||||
g_assert (result == NULL);
|
||||
|
||||
g_main_loop_quit (loop);
|
||||
}
|
||||
|
||||
/* ---------------------------------------------------------------------------------------------------- */
|
||||
|
||||
static void
|
||||
test_connection_send (void)
|
||||
{
|
||||
GDBusConnection *c;
|
||||
GCancellable *ca;
|
||||
|
||||
session_bus_up ();
|
||||
|
||||
/* First, get an unopened connection */
|
||||
c = g_bus_get_sync (G_BUS_TYPE_SESSION, NULL, NULL);
|
||||
g_assert (c != NULL);
|
||||
g_assert (!g_dbus_connection_is_closed (c));
|
||||
|
||||
/*
|
||||
* Check that we never actually send a message if the GCancellable
|
||||
* is already cancelled - i.e. we should get #G_IO_ERROR_CANCELLED
|
||||
* when the actual connection is not up.
|
||||
*/
|
||||
ca = g_cancellable_new ();
|
||||
g_cancellable_cancel (ca);
|
||||
g_dbus_connection_call (c,
|
||||
"org.freedesktop.DBus", /* bus_name */
|
||||
"/org/freedesktop/DBus", /* object path */
|
||||
"org.freedesktop.DBus", /* interface name */
|
||||
"GetId", /* method name */
|
||||
NULL,
|
||||
G_DBUS_CALL_FLAGS_NONE,
|
||||
-1,
|
||||
ca,
|
||||
(GAsyncReadyCallback) msg_cb_expect_error_cancelled,
|
||||
NULL);
|
||||
g_main_loop_run (loop);
|
||||
g_object_unref (ca);
|
||||
|
||||
/*
|
||||
* Check that we get a reply to the GetId() method call.
|
||||
*/
|
||||
g_dbus_connection_call (c,
|
||||
"org.freedesktop.DBus", /* bus_name */
|
||||
"/org/freedesktop/DBus", /* object path */
|
||||
"org.freedesktop.DBus", /* interface name */
|
||||
"GetId", /* method name */
|
||||
NULL,
|
||||
G_DBUS_CALL_FLAGS_NONE,
|
||||
-1,
|
||||
NULL,
|
||||
(GAsyncReadyCallback) msg_cb_expect_success,
|
||||
NULL);
|
||||
g_main_loop_run (loop);
|
||||
|
||||
/*
|
||||
* Check that we get an error reply to the NonExistantMethod() method call.
|
||||
*/
|
||||
g_dbus_connection_call (c,
|
||||
"org.freedesktop.DBus", /* bus_name */
|
||||
"/org/freedesktop/DBus", /* object path */
|
||||
"org.freedesktop.DBus", /* interface name */
|
||||
"NonExistantMethod", /* method name */
|
||||
NULL,
|
||||
G_DBUS_CALL_FLAGS_NONE,
|
||||
-1,
|
||||
NULL,
|
||||
(GAsyncReadyCallback) msg_cb_expect_error_unknown_method,
|
||||
NULL);
|
||||
g_main_loop_run (loop);
|
||||
|
||||
/*
|
||||
* Check that cancellation works when the message is already in flight.
|
||||
*/
|
||||
ca = g_cancellable_new ();
|
||||
g_dbus_connection_call (c,
|
||||
"org.freedesktop.DBus", /* bus_name */
|
||||
"/org/freedesktop/DBus", /* object path */
|
||||
"org.freedesktop.DBus", /* interface name */
|
||||
"GetId", /* method name */
|
||||
NULL,
|
||||
G_DBUS_CALL_FLAGS_NONE,
|
||||
-1,
|
||||
ca,
|
||||
(GAsyncReadyCallback) msg_cb_expect_error_cancelled_2,
|
||||
NULL);
|
||||
g_cancellable_cancel (ca);
|
||||
g_main_loop_run (loop);
|
||||
g_object_unref (ca);
|
||||
|
||||
/*
|
||||
* Check that we get an error when sending to a connection that is disconnected.
|
||||
*/
|
||||
g_dbus_connection_set_exit_on_close (c, FALSE);
|
||||
session_bus_down ();
|
||||
_g_assert_signal_received (c, "closed");
|
||||
g_assert (g_dbus_connection_is_closed (c));
|
||||
|
||||
g_dbus_connection_call (c,
|
||||
"org.freedesktop.DBus", /* bus_name */
|
||||
"/org/freedesktop/DBus", /* object path */
|
||||
"org.freedesktop.DBus", /* interface name */
|
||||
"GetId", /* method name */
|
||||
NULL,
|
||||
G_DBUS_CALL_FLAGS_NONE,
|
||||
-1,
|
||||
NULL,
|
||||
(GAsyncReadyCallback) msg_cb_expect_error_disconnected,
|
||||
NULL);
|
||||
g_main_loop_run (loop);
|
||||
|
||||
_g_object_wait_for_single_ref (c);
|
||||
g_object_unref (c);
|
||||
}
|
||||
|
||||
/* ---------------------------------------------------------------------------------------------------- */
|
||||
/* Connection signal tests */
|
||||
/* ---------------------------------------------------------------------------------------------------- */
|
||||
|
||||
static void
|
||||
test_connection_signal_handler (GDBusConnection *connection,
|
||||
const gchar *sender_name,
|
||||
const gchar *object_path,
|
||||
const gchar *interface_name,
|
||||
const gchar *signal_name,
|
||||
GVariant *parameters,
|
||||
gpointer user_data)
|
||||
{
|
||||
gint *counter = user_data;
|
||||
*counter += 1;
|
||||
|
||||
/*g_debug ("in test_connection_signal_handler (sender=%s path=%s interface=%s member=%s)",
|
||||
sender_name,
|
||||
object_path,
|
||||
interface_name,
|
||||
signal_name);*/
|
||||
|
||||
g_main_loop_quit (loop);
|
||||
}
|
||||
|
||||
static gboolean
|
||||
test_connection_signal_quit_mainloop (gpointer user_data)
|
||||
{
|
||||
gboolean *quit_mainloop_fired = user_data;
|
||||
*quit_mainloop_fired = TRUE;
|
||||
g_main_loop_quit (loop);
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static void
|
||||
test_connection_signals (void)
|
||||
{
|
||||
GDBusConnection *c1;
|
||||
GDBusConnection *c2;
|
||||
GDBusConnection *c3;
|
||||
guint s1;
|
||||
guint s2;
|
||||
guint s3;
|
||||
gint count_s1;
|
||||
gint count_s2;
|
||||
gint count_name_owner_changed;
|
||||
GError *error;
|
||||
gboolean ret;
|
||||
GVariant *result;
|
||||
|
||||
error = NULL;
|
||||
|
||||
/*
|
||||
* Bring up first separate connections
|
||||
*/
|
||||
session_bus_up ();
|
||||
/* if running with dbus-monitor, it claims the name :1.0 - so if we don't run with the monitor
|
||||
* emulate this
|
||||
*/
|
||||
if (g_getenv ("G_DBUS_MONITOR") == NULL)
|
||||
{
|
||||
c1 = _g_bus_get_priv (G_BUS_TYPE_SESSION, NULL, NULL);
|
||||
g_assert (c1 != NULL);
|
||||
g_assert (!g_dbus_connection_is_closed (c1));
|
||||
g_object_unref (c1);
|
||||
}
|
||||
c1 = g_bus_get_sync (G_BUS_TYPE_SESSION, NULL, NULL);
|
||||
g_assert (c1 != NULL);
|
||||
g_assert (!g_dbus_connection_is_closed (c1));
|
||||
g_assert_cmpstr (g_dbus_connection_get_unique_name (c1), ==, ":1.1");
|
||||
|
||||
/*
|
||||
* Install two signal handlers for the first connection
|
||||
*
|
||||
* - Listen to the signal "Foo" from :1.2 (e.g. c2)
|
||||
* - Listen to the signal "Foo" from anyone (e.g. both c2 and c3)
|
||||
*
|
||||
* and then count how many times this signal handler was invoked.
|
||||
*/
|
||||
s1 = g_dbus_connection_signal_subscribe (c1,
|
||||
":1.2",
|
||||
"org.gtk.GDBus.ExampleInterface",
|
||||
"Foo",
|
||||
"/org/gtk/GDBus/ExampleInterface",
|
||||
NULL,
|
||||
test_connection_signal_handler,
|
||||
&count_s1,
|
||||
NULL);
|
||||
s2 = g_dbus_connection_signal_subscribe (c1,
|
||||
NULL, /* match any sender */
|
||||
"org.gtk.GDBus.ExampleInterface",
|
||||
"Foo",
|
||||
"/org/gtk/GDBus/ExampleInterface",
|
||||
NULL,
|
||||
test_connection_signal_handler,
|
||||
&count_s2,
|
||||
NULL);
|
||||
s3 = g_dbus_connection_signal_subscribe (c1,
|
||||
"org.freedesktop.DBus", /* sender */
|
||||
"org.freedesktop.DBus", /* interface */
|
||||
"NameOwnerChanged", /* member */
|
||||
"/org/freedesktop/DBus", /* path */
|
||||
NULL,
|
||||
test_connection_signal_handler,
|
||||
&count_name_owner_changed,
|
||||
NULL);
|
||||
g_assert (s1 != 0);
|
||||
g_assert (s2 != 0);
|
||||
g_assert (s3 != 0);
|
||||
|
||||
count_s1 = 0;
|
||||
count_s2 = 0;
|
||||
count_name_owner_changed = 0;
|
||||
|
||||
/*
|
||||
* Bring up two other connections
|
||||
*/
|
||||
c2 = _g_bus_get_priv (G_BUS_TYPE_SESSION, NULL, NULL);
|
||||
g_assert (c2 != NULL);
|
||||
g_assert (!g_dbus_connection_is_closed (c2));
|
||||
g_assert_cmpstr (g_dbus_connection_get_unique_name (c2), ==, ":1.2");
|
||||
c3 = _g_bus_get_priv (G_BUS_TYPE_SESSION, NULL, NULL);
|
||||
g_assert (c3 != NULL);
|
||||
g_assert (!g_dbus_connection_is_closed (c3));
|
||||
g_assert_cmpstr (g_dbus_connection_get_unique_name (c3), ==, ":1.3");
|
||||
|
||||
/*
|
||||
* Make c2 emit "Foo" - we should catch it twice
|
||||
*
|
||||
* Note that there is no way to be sure that the signal subscriptions
|
||||
* on c1 are effective yet - for all we know, the AddMatch() messages
|
||||
* could sit waiting in a buffer somewhere between this process and
|
||||
* the message bus. And emitting signals on c2 (a completely other
|
||||
* socket!) will not necessarily change this.
|
||||
*
|
||||
* To ensure this is not the case, do a synchronous call on c1.
|
||||
*/
|
||||
result = g_dbus_connection_call_sync (c1,
|
||||
"org.freedesktop.DBus", /* bus name */
|
||||
"/org/freedesktop/DBus", /* object path */
|
||||
"org.freedesktop.DBus", /* interface name */
|
||||
"GetId", /* method name */
|
||||
NULL, /* parameters */
|
||||
G_DBUS_CALL_FLAGS_NONE,
|
||||
-1,
|
||||
NULL,
|
||||
&error);
|
||||
g_assert_no_error (error);
|
||||
g_assert (result != NULL);
|
||||
g_variant_unref (result);
|
||||
/* now, emit the signal on c2 */
|
||||
ret = g_dbus_connection_emit_signal (c2,
|
||||
NULL, /* destination bus name */
|
||||
"/org/gtk/GDBus/ExampleInterface",
|
||||
"org.gtk.GDBus.ExampleInterface",
|
||||
"Foo",
|
||||
NULL,
|
||||
&error);
|
||||
g_assert_no_error (error);
|
||||
g_assert (ret);
|
||||
while (!(count_s1 == 1 && count_s2 == 1))
|
||||
g_main_loop_run (loop);
|
||||
g_assert_cmpint (count_s1, ==, 1);
|
||||
g_assert_cmpint (count_s2, ==, 1);
|
||||
|
||||
/*
|
||||
* Make c3 emit "Foo" - we should catch it only once
|
||||
*/
|
||||
ret = g_dbus_connection_emit_signal (c3,
|
||||
NULL, /* destination bus name */
|
||||
"/org/gtk/GDBus/ExampleInterface",
|
||||
"org.gtk.GDBus.ExampleInterface",
|
||||
"Foo",
|
||||
NULL,
|
||||
&error);
|
||||
g_assert_no_error (error);
|
||||
g_assert (ret);
|
||||
while (!(count_s1 == 1 && count_s2 == 2))
|
||||
g_main_loop_run (loop);
|
||||
g_assert_cmpint (count_s1, ==, 1);
|
||||
g_assert_cmpint (count_s2, ==, 2);
|
||||
|
||||
/*
|
||||
* Also to check the total amount of NameOwnerChanged signals - use a 5 second ceiling
|
||||
* to avoid spinning forever
|
||||
*/
|
||||
gboolean quit_mainloop_fired;
|
||||
guint quit_mainloop_id;
|
||||
quit_mainloop_fired = FALSE;
|
||||
quit_mainloop_id = g_timeout_add (5000, test_connection_signal_quit_mainloop, &quit_mainloop_fired);
|
||||
while (count_name_owner_changed != 2 && !quit_mainloop_fired)
|
||||
g_main_loop_run (loop);
|
||||
g_source_remove (quit_mainloop_id);
|
||||
g_assert_cmpint (count_s1, ==, 1);
|
||||
g_assert_cmpint (count_s2, ==, 2);
|
||||
g_assert_cmpint (count_name_owner_changed, ==, 2);
|
||||
|
||||
g_dbus_connection_signal_unsubscribe (c1, s1);
|
||||
g_dbus_connection_signal_unsubscribe (c1, s2);
|
||||
g_dbus_connection_signal_unsubscribe (c1, s3);
|
||||
|
||||
_g_object_wait_for_single_ref (c1);
|
||||
_g_object_wait_for_single_ref (c2);
|
||||
_g_object_wait_for_single_ref (c3);
|
||||
|
||||
g_object_unref (c1);
|
||||
g_object_unref (c2);
|
||||
g_object_unref (c3);
|
||||
|
||||
session_bus_down ();
|
||||
}
|
||||
|
||||
/* ---------------------------------------------------------------------------------------------------- */
|
||||
|
||||
typedef struct
|
||||
{
|
||||
guint num_handled;
|
||||
guint32 serial;
|
||||
} FilterData;
|
||||
|
||||
static gboolean
|
||||
filter_func (GDBusConnection *connection,
|
||||
GDBusMessage *message,
|
||||
gpointer user_data)
|
||||
{
|
||||
FilterData *data = user_data;
|
||||
guint32 reply_serial;
|
||||
|
||||
reply_serial = g_dbus_message_get_reply_serial (message);
|
||||
if (reply_serial == data->serial)
|
||||
data->num_handled += 1;
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
static void
|
||||
test_connection_filter (void)
|
||||
{
|
||||
GDBusConnection *c;
|
||||
FilterData data;
|
||||
GDBusMessage *m;
|
||||
GDBusMessage *r;
|
||||
GError *error;
|
||||
guint filter_id;
|
||||
|
||||
memset (&data, '\0', sizeof (FilterData));
|
||||
|
||||
session_bus_up ();
|
||||
|
||||
error = NULL;
|
||||
c = g_bus_get_sync (G_BUS_TYPE_SESSION, NULL, &error);
|
||||
g_assert_no_error (error);
|
||||
g_assert (c != NULL);
|
||||
|
||||
filter_id = g_dbus_connection_add_filter (c,
|
||||
filter_func,
|
||||
&data,
|
||||
NULL);
|
||||
|
||||
m = g_dbus_message_new_method_call ("org.freedesktop.DBus", /* name */
|
||||
"/org/freedesktop/DBus", /* path */
|
||||
"org.freedesktop.DBus", /* interface */
|
||||
"GetNameOwner");
|
||||
g_dbus_message_set_body (m, g_variant_new ("(s)", "org.freedesktop.DBus"));
|
||||
error = NULL;
|
||||
g_dbus_connection_send_message (c, m, &data.serial, &error);
|
||||
g_assert_no_error (error);
|
||||
|
||||
while (data.num_handled == 0)
|
||||
g_thread_yield ();
|
||||
|
||||
g_dbus_connection_send_message (c, m, &data.serial, &error);
|
||||
g_assert_no_error (error);
|
||||
|
||||
while (data.num_handled == 1)
|
||||
g_thread_yield ();
|
||||
|
||||
r = g_dbus_connection_send_message_with_reply_sync (c,
|
||||
m,
|
||||
-1,
|
||||
&data.serial,
|
||||
NULL, /* GCancellable */
|
||||
&error);
|
||||
g_assert_no_error (error);
|
||||
g_assert (r != NULL);
|
||||
g_object_unref (r);
|
||||
g_assert_cmpint (data.num_handled, ==, 3);
|
||||
|
||||
g_dbus_connection_remove_filter (c, filter_id);
|
||||
|
||||
r = g_dbus_connection_send_message_with_reply_sync (c,
|
||||
m,
|
||||
-1,
|
||||
&data.serial,
|
||||
NULL, /* GCancellable */
|
||||
&error);
|
||||
g_assert_no_error (error);
|
||||
g_assert (r != NULL);
|
||||
g_object_unref (r);
|
||||
g_assert_cmpint (data.num_handled, ==, 3);
|
||||
|
||||
_g_object_wait_for_single_ref (c);
|
||||
g_object_unref (c);
|
||||
g_object_unref (m);
|
||||
|
||||
session_bus_down ();
|
||||
}
|
||||
|
||||
/* ---------------------------------------------------------------------------------------------------- */
|
||||
|
||||
int
|
||||
main (int argc,
|
||||
char *argv[])
|
||||
{
|
||||
g_type_init ();
|
||||
g_test_init (&argc, &argv, NULL);
|
||||
|
||||
/* all the tests rely on a shared main loop */
|
||||
loop = g_main_loop_new (NULL, FALSE);
|
||||
|
||||
/* all the tests use a session bus with a well-known address that we can bring up and down
|
||||
* using session_bus_up() and session_bus_down().
|
||||
*/
|
||||
g_unsetenv ("DISPLAY");
|
||||
g_setenv ("DBUS_SESSION_BUS_ADDRESS", session_bus_get_temporary_address (), TRUE);
|
||||
|
||||
g_test_add_func ("/gdbus/connection-life-cycle", test_connection_life_cycle);
|
||||
g_test_add_func ("/gdbus/connection-send", test_connection_send);
|
||||
g_test_add_func ("/gdbus/connection-signals", test_connection_signals);
|
||||
g_test_add_func ("/gdbus/connection-filter", test_connection_filter);
|
||||
return g_test_run();
|
||||
}
|
198
gio/tests/gdbus-error.c
Normal file
198
gio/tests/gdbus-error.c
Normal file
@ -0,0 +1,198 @@
|
||||
/* GLib testing framework examples and tests
|
||||
*
|
||||
* Copyright (C) 2008-2010 Red Hat, Inc.
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General
|
||||
* Public License along with this library; if not, write to the
|
||||
* Free Software Foundation, Inc., 59 Temple Place, Suite 330,
|
||||
* Boston, MA 02111-1307, USA.
|
||||
*
|
||||
* Author: David Zeuthen <davidz@redhat.com>
|
||||
*/
|
||||
|
||||
#include <gio/gio.h>
|
||||
#include <unistd.h>
|
||||
#include <string.h>
|
||||
|
||||
/* ---------------------------------------------------------------------------------------------------- */
|
||||
/* Test that registered errors are properly mapped */
|
||||
/* ---------------------------------------------------------------------------------------------------- */
|
||||
|
||||
static void
|
||||
check_registered_error (const gchar *given_dbus_error_name,
|
||||
GQuark error_domain,
|
||||
gint error_code)
|
||||
{
|
||||
GError *error;
|
||||
gchar *dbus_error_name;
|
||||
|
||||
error = g_dbus_error_new_for_dbus_error (given_dbus_error_name, "test message");
|
||||
g_assert_error (error, error_domain, error_code);
|
||||
g_assert (g_dbus_error_is_remote_error (error));
|
||||
g_assert (g_dbus_error_strip_remote_error (error));
|
||||
g_assert_cmpstr (error->message, ==, "test message");
|
||||
dbus_error_name = g_dbus_error_get_remote_error (error);
|
||||
g_assert_cmpstr (dbus_error_name, ==, given_dbus_error_name);
|
||||
g_free (dbus_error_name);
|
||||
g_error_free (error);
|
||||
}
|
||||
|
||||
static void
|
||||
test_registered_errors (void)
|
||||
{
|
||||
/* Here we check that we are able to map to GError and back for registered
|
||||
* errors.
|
||||
*
|
||||
* For example, if "org.freedesktop.DBus.Error.AddressInUse" is
|
||||
* associated with (G_DBUS_ERROR, G_DBUS_ERROR_DBUS_FAILED), check
|
||||
* that
|
||||
*
|
||||
* - Creating a GError for e.g. "org.freedesktop.DBus.Error.AddressInUse"
|
||||
* has (error_domain, code) == (G_DBUS_ERROR, G_DBUS_ERROR_DBUS_FAILED)
|
||||
*
|
||||
* - That it is possible to recover e.g. "org.freedesktop.DBus.Error.AddressInUse"
|
||||
* as the D-Bus error name when dealing with an error with (error_domain, code) ==
|
||||
* (G_DBUS_ERROR, G_DBUS_ERROR_DBUS_FAILED)
|
||||
*
|
||||
* We just check a couple of well-known errors.
|
||||
*/
|
||||
check_registered_error ("org.freedesktop.DBus.Error.Failed",
|
||||
G_DBUS_ERROR,
|
||||
G_DBUS_ERROR_FAILED);
|
||||
check_registered_error ("org.freedesktop.DBus.Error.AddressInUse",
|
||||
G_DBUS_ERROR,
|
||||
G_DBUS_ERROR_ADDRESS_IN_USE);
|
||||
check_registered_error ("org.freedesktop.DBus.Error.UnknownMethod",
|
||||
G_DBUS_ERROR,
|
||||
G_DBUS_ERROR_UNKNOWN_METHOD);
|
||||
}
|
||||
|
||||
/* ---------------------------------------------------------------------------------------------------- */
|
||||
|
||||
static void
|
||||
check_unregistered_error (const gchar *given_dbus_error_name)
|
||||
{
|
||||
GError *error;
|
||||
gchar *dbus_error_name;
|
||||
|
||||
error = g_dbus_error_new_for_dbus_error (given_dbus_error_name, "test message");
|
||||
g_assert_error (error, G_IO_ERROR, G_IO_ERROR_DBUS_ERROR);
|
||||
g_assert (g_dbus_error_is_remote_error (error));
|
||||
dbus_error_name = g_dbus_error_get_remote_error (error);
|
||||
g_assert_cmpstr (dbus_error_name, ==, given_dbus_error_name);
|
||||
g_free (dbus_error_name);
|
||||
|
||||
/* strip the message */
|
||||
g_assert (g_dbus_error_strip_remote_error (error));
|
||||
g_assert_cmpstr (error->message, ==, "test message");
|
||||
|
||||
/* check that we can no longer recover the D-Bus error name */
|
||||
g_assert (g_dbus_error_get_remote_error (error) == NULL);
|
||||
|
||||
g_error_free (error);
|
||||
|
||||
}
|
||||
|
||||
static void
|
||||
test_unregistered_errors (void)
|
||||
{
|
||||
/* Here we check that we are able to map to GError and back for unregistered
|
||||
* errors.
|
||||
*
|
||||
* For example, if "com.example.Error.Failed" is not registered, then check
|
||||
*
|
||||
* - Creating a GError for e.g. "com.example.Error.Failed" has (error_domain, code) ==
|
||||
* (G_IO_ERROR, G_IO_ERROR_DBUS_ERROR)
|
||||
*
|
||||
* - That it is possible to recover e.g. "com.example.Error.Failed" from that
|
||||
* GError.
|
||||
*
|
||||
* We just check a couple of random errors.
|
||||
*/
|
||||
|
||||
check_unregistered_error ("com.example.Error.Failed");
|
||||
check_unregistered_error ("foobar.buh");
|
||||
}
|
||||
|
||||
/* ---------------------------------------------------------------------------------------------------- */
|
||||
|
||||
static void
|
||||
check_transparent_gerror (GQuark error_domain,
|
||||
gint error_code)
|
||||
{
|
||||
GError *error;
|
||||
gchar *given_dbus_error_name;
|
||||
gchar *dbus_error_name;
|
||||
|
||||
error = g_error_new (error_domain, error_code, "test message");
|
||||
given_dbus_error_name = g_dbus_error_encode_gerror (error);
|
||||
g_assert (g_str_has_prefix (given_dbus_error_name, "org.gtk.GDBus.UnmappedGError.Quark"));
|
||||
g_error_free (error);
|
||||
|
||||
error = g_dbus_error_new_for_dbus_error (given_dbus_error_name, "test message");
|
||||
g_assert_error (error, error_domain, error_code);
|
||||
g_assert (g_dbus_error_is_remote_error (error));
|
||||
dbus_error_name = g_dbus_error_get_remote_error (error);
|
||||
g_assert_cmpstr (dbus_error_name, ==, given_dbus_error_name);
|
||||
g_free (dbus_error_name);
|
||||
g_free (given_dbus_error_name);
|
||||
|
||||
/* strip the message */
|
||||
g_assert (g_dbus_error_strip_remote_error (error));
|
||||
g_assert_cmpstr (error->message, ==, "test message");
|
||||
|
||||
/* check that we can no longer recover the D-Bus error name */
|
||||
g_assert (g_dbus_error_get_remote_error (error) == NULL);
|
||||
|
||||
g_error_free (error);
|
||||
}
|
||||
|
||||
static void
|
||||
test_transparent_gerror (void)
|
||||
{
|
||||
/* Here we check that we are able to transparent pass unregistered GError's
|
||||
* over the wire.
|
||||
*
|
||||
* For example, if G_IO_ERROR_FAILED is not registered, then check
|
||||
*
|
||||
* - g_dbus_error_encode_gerror() returns something of the form
|
||||
* org.gtk.GDBus.UnmappedGError.Quark_HEXENCODED_QUARK_NAME_.Code_ERROR_CODE
|
||||
*
|
||||
* - mapping back the D-Bus error name gives us G_IO_ERROR_FAILED
|
||||
*
|
||||
* - That it is possible to recover the D-Bus error name from the
|
||||
* GError.
|
||||
*
|
||||
* We just check a couple of random errors.
|
||||
*/
|
||||
|
||||
check_transparent_gerror (G_IO_ERROR, G_IO_ERROR_FAILED);
|
||||
check_transparent_gerror (G_KEY_FILE_ERROR, G_KEY_FILE_ERROR_PARSE);
|
||||
}
|
||||
|
||||
|
||||
/* ---------------------------------------------------------------------------------------------------- */
|
||||
|
||||
int
|
||||
main (int argc,
|
||||
char *argv[])
|
||||
{
|
||||
g_type_init ();
|
||||
g_test_init (&argc, &argv, NULL);
|
||||
|
||||
g_test_add_func ("/gdbus/registered-errors", test_registered_errors);
|
||||
g_test_add_func ("/gdbus/unregistered-errors", test_unregistered_errors);
|
||||
g_test_add_func ("/gdbus/transparent-gerror", test_transparent_gerror);
|
||||
|
||||
return g_test_run();
|
||||
}
|
335
gio/tests/gdbus-example-export.c
Normal file
335
gio/tests/gdbus-example-export.c
Normal file
@ -0,0 +1,335 @@
|
||||
#include <gio/gio.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
/* ---------------------------------------------------------------------------------------------------- */
|
||||
|
||||
/* The object we want to export */
|
||||
typedef struct _MyObjectClass MyObjectClass;
|
||||
typedef struct _MyObject MyObject;
|
||||
|
||||
struct _MyObjectClass
|
||||
{
|
||||
GObjectClass parent_class;
|
||||
};
|
||||
|
||||
struct _MyObject
|
||||
{
|
||||
GObject parent_instance;
|
||||
|
||||
gint count;
|
||||
gchar *name;
|
||||
};
|
||||
|
||||
enum
|
||||
{
|
||||
PROP_0,
|
||||
PROP_COUNT,
|
||||
PROP_NAME
|
||||
};
|
||||
|
||||
G_DEFINE_TYPE (MyObject, my_object, G_TYPE_OBJECT);
|
||||
|
||||
static void
|
||||
my_object_finalize (GObject *object)
|
||||
{
|
||||
MyObject *myobj = (MyObject*)object;
|
||||
|
||||
g_free (myobj->name);
|
||||
|
||||
G_OBJECT_CLASS (my_object_parent_class)->finalize (object);
|
||||
}
|
||||
|
||||
static void
|
||||
my_object_init (MyObject *object)
|
||||
{
|
||||
object->count = 0;
|
||||
object->name = NULL;
|
||||
}
|
||||
|
||||
static void
|
||||
my_object_get_property (GObject *object,
|
||||
guint prop_id,
|
||||
GValue *value,
|
||||
GParamSpec *pspec)
|
||||
{
|
||||
MyObject *myobj = (MyObject*)object;
|
||||
|
||||
switch (prop_id)
|
||||
{
|
||||
case PROP_COUNT:
|
||||
g_value_set_int (value, myobj->count);
|
||||
break;
|
||||
|
||||
case PROP_NAME:
|
||||
g_value_set_string (value, myobj->name);
|
||||
break;
|
||||
|
||||
default:
|
||||
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
my_object_set_property (GObject *object,
|
||||
guint prop_id,
|
||||
const GValue *value,
|
||||
GParamSpec *pspec)
|
||||
{
|
||||
MyObject *myobj = (MyObject*)object;
|
||||
|
||||
switch (prop_id)
|
||||
{
|
||||
case PROP_COUNT:
|
||||
myobj->count = g_value_get_int (value);
|
||||
break;
|
||||
|
||||
case PROP_NAME:
|
||||
g_free (myobj->name);
|
||||
myobj->name = g_value_dup_string (value);
|
||||
break;
|
||||
|
||||
default:
|
||||
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
my_object_class_init (MyObjectClass *class)
|
||||
{
|
||||
GObjectClass *gobject_class = G_OBJECT_CLASS (class);
|
||||
|
||||
gobject_class->finalize = my_object_finalize;
|
||||
gobject_class->set_property = my_object_set_property;
|
||||
gobject_class->get_property = my_object_get_property;
|
||||
|
||||
g_object_class_install_property (gobject_class,
|
||||
PROP_COUNT,
|
||||
g_param_spec_int ("count",
|
||||
"Count",
|
||||
"Count",
|
||||
0, 99999, 0,
|
||||
G_PARAM_READWRITE));
|
||||
|
||||
g_object_class_install_property (gobject_class,
|
||||
PROP_NAME,
|
||||
g_param_spec_string ("name",
|
||||
"Name",
|
||||
"Name",
|
||||
NULL,
|
||||
G_PARAM_READWRITE));
|
||||
}
|
||||
|
||||
/* A method that we want to export */
|
||||
void
|
||||
my_object_change_count (MyObject *myobj,
|
||||
gint change)
|
||||
{
|
||||
myobj->count = 2 * myobj->count + change;
|
||||
|
||||
g_object_notify (G_OBJECT (myobj), "count");
|
||||
}
|
||||
|
||||
/* ---------------------------------------------------------------------------------------------------- */
|
||||
|
||||
static GDBusNodeInfo *introspection_data = NULL;
|
||||
|
||||
/* Introspection data for the service we are exporting */
|
||||
static const gchar introspection_xml[] =
|
||||
"<node>"
|
||||
" <interface name='org.myorg.MyObject'>"
|
||||
" <method name='ChangeCount'>"
|
||||
" <arg type='i' name='change' direction='in'/>"
|
||||
" </method>"
|
||||
" <property type='i' name='Count' access='read'/>"
|
||||
" <property type='s' name='Name' access='readwrite'/>"
|
||||
" </interface>"
|
||||
"</node>";
|
||||
|
||||
|
||||
static void
|
||||
handle_method_call (GDBusConnection *connection,
|
||||
const gchar *sender,
|
||||
const gchar *object_path,
|
||||
const gchar *interface_name,
|
||||
const gchar *method_name,
|
||||
GVariant *parameters,
|
||||
GDBusMethodInvocation *invocation,
|
||||
gpointer user_data)
|
||||
{
|
||||
MyObject *myobj = user_data;
|
||||
|
||||
if (g_strcmp0 (method_name, "ChangeCount") == 0)
|
||||
{
|
||||
gint change;
|
||||
g_variant_get (parameters, "(i)", &change);
|
||||
|
||||
my_object_change_count (myobj, change);
|
||||
|
||||
g_dbus_method_invocation_return_value (invocation, NULL);
|
||||
}
|
||||
}
|
||||
|
||||
static GVariant *
|
||||
handle_get_property (GDBusConnection *connection,
|
||||
const gchar *sender,
|
||||
const gchar *object_path,
|
||||
const gchar *interface_name,
|
||||
const gchar *property_name,
|
||||
GError **error,
|
||||
gpointer user_data)
|
||||
{
|
||||
GVariant *ret;
|
||||
MyObject *myobj = user_data;
|
||||
|
||||
ret = NULL;
|
||||
if (g_strcmp0 (property_name, "Count") == 0)
|
||||
{
|
||||
ret = g_variant_new_int32 (myobj->count);
|
||||
}
|
||||
else if (g_strcmp0 (property_name, "Name") == 0)
|
||||
{
|
||||
ret = g_variant_new_string (myobj->name ? myobj->name : "");
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
handle_set_property (GDBusConnection *connection,
|
||||
const gchar *sender,
|
||||
const gchar *object_path,
|
||||
const gchar *interface_name,
|
||||
const gchar *property_name,
|
||||
GVariant *value,
|
||||
GError **error,
|
||||
gpointer user_data)
|
||||
{
|
||||
MyObject *myobj = user_data;
|
||||
|
||||
if (g_strcmp0 (property_name, "Count") == 0)
|
||||
{
|
||||
g_object_set (myobj, "count", g_variant_get_int32 (value), NULL);
|
||||
}
|
||||
else if (g_strcmp0 (property_name, "Name") == 0)
|
||||
{
|
||||
g_object_set (myobj, "name", g_variant_get_string (value, NULL), NULL);
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
|
||||
/* for now */
|
||||
static const GDBusInterfaceVTable interface_vtable =
|
||||
{
|
||||
handle_method_call,
|
||||
handle_get_property,
|
||||
handle_set_property
|
||||
};
|
||||
|
||||
static void
|
||||
send_property_change (GObject *obj,
|
||||
GParamSpec *pspec,
|
||||
GDBusConnection *connection)
|
||||
{
|
||||
GVariantBuilder *builder;
|
||||
GVariantBuilder *invalidated_builder;
|
||||
MyObject *myobj = (MyObject *)obj;
|
||||
|
||||
builder = g_variant_builder_new (G_VARIANT_TYPE_ARRAY);
|
||||
invalidated_builder = g_variant_builder_new (G_VARIANT_TYPE ("as"));
|
||||
|
||||
if (g_strcmp0 (pspec->name, "count") == 0)
|
||||
g_variant_builder_add (builder,
|
||||
"{sv}",
|
||||
"Count", g_variant_new_int32 (myobj->count));
|
||||
else if (g_strcmp0 (pspec->name, "name") == 0)
|
||||
g_variant_builder_add (builder,
|
||||
"{sv}",
|
||||
"Name", g_variant_new_string (myobj->name ? myobj->name : ""));
|
||||
|
||||
g_dbus_connection_emit_signal (connection,
|
||||
NULL,
|
||||
"/org/myorg/MyObject",
|
||||
"org.freedesktop.DBus.Properties",
|
||||
"PropertiesChanged",
|
||||
g_variant_new ("(sa{sv}as)",
|
||||
"org.myorg.MyObject",
|
||||
builder,
|
||||
invalidated_builder),
|
||||
NULL);
|
||||
}
|
||||
|
||||
static void
|
||||
on_bus_acquired (GDBusConnection *connection,
|
||||
const gchar *name,
|
||||
gpointer user_data)
|
||||
{
|
||||
MyObject *myobj = user_data;
|
||||
guint registration_id;
|
||||
|
||||
g_signal_connect (myobj, "notify",
|
||||
G_CALLBACK (send_property_change), connection);
|
||||
registration_id = g_dbus_connection_register_object (connection,
|
||||
"/org/myorg/MyObject",
|
||||
introspection_data->interfaces[0],
|
||||
&interface_vtable,
|
||||
myobj,
|
||||
NULL, /* user_data_free_func */
|
||||
NULL); /* GError** */
|
||||
g_assert (registration_id > 0);
|
||||
}
|
||||
|
||||
static void
|
||||
on_name_acquired (GDBusConnection *connection,
|
||||
const gchar *name,
|
||||
gpointer user_data)
|
||||
{
|
||||
}
|
||||
|
||||
static void
|
||||
on_name_lost (GDBusConnection *connection,
|
||||
const gchar *name,
|
||||
gpointer user_data)
|
||||
{
|
||||
exit (1);
|
||||
}
|
||||
|
||||
int
|
||||
main (int argc, char *argv[])
|
||||
{
|
||||
guint owner_id;
|
||||
GMainLoop *loop;
|
||||
MyObject *myobj;
|
||||
|
||||
g_type_init ();
|
||||
|
||||
/* We are lazy here - we don't want to manually provide
|
||||
* the introspection data structures - so we just build
|
||||
* them from XML.
|
||||
*/
|
||||
introspection_data = g_dbus_node_info_new_for_xml (introspection_xml, NULL);
|
||||
g_assert (introspection_data != NULL);
|
||||
|
||||
myobj = g_object_new (my_object_get_type (), NULL);
|
||||
|
||||
owner_id = g_bus_own_name (G_BUS_TYPE_SESSION,
|
||||
"org.myorg.MyObject",
|
||||
G_BUS_NAME_OWNER_FLAGS_NONE,
|
||||
on_bus_acquired,
|
||||
on_name_acquired,
|
||||
on_name_lost,
|
||||
myobj,
|
||||
NULL);
|
||||
|
||||
loop = g_main_loop_new (NULL, FALSE);
|
||||
g_main_loop_run (loop);
|
||||
|
||||
g_bus_unown_name (owner_id);
|
||||
|
||||
g_dbus_node_info_unref (introspection_data);
|
||||
|
||||
g_object_unref (myobj);
|
||||
|
||||
return 0;
|
||||
}
|
86
gio/tests/gdbus-example-own-name.c
Normal file
86
gio/tests/gdbus-example-own-name.c
Normal file
@ -0,0 +1,86 @@
|
||||
#include <gio/gio.h>
|
||||
|
||||
static void
|
||||
on_bus_acquired (GDBusConnection *connection,
|
||||
const gchar *name,
|
||||
gpointer user_data)
|
||||
{
|
||||
/* This is where we'd export some objects on the bus */
|
||||
}
|
||||
|
||||
static void
|
||||
on_name_acquired (GDBusConnection *connection,
|
||||
const gchar *name,
|
||||
gpointer user_data)
|
||||
{
|
||||
g_print ("Acquired the name %s on the session bus\n", name);
|
||||
}
|
||||
|
||||
static void
|
||||
on_name_lost (GDBusConnection *connection,
|
||||
const gchar *name,
|
||||
gpointer user_data)
|
||||
{
|
||||
g_print ("Lost the name %s on the session bus\n", name);
|
||||
}
|
||||
|
||||
int
|
||||
main (int argc, char *argv[])
|
||||
{
|
||||
guint owner_id;
|
||||
GMainLoop *loop;
|
||||
GBusNameOwnerFlags flags;
|
||||
gboolean opt_replace;
|
||||
gboolean opt_allow_replacement;
|
||||
gchar *opt_name;
|
||||
GOptionContext *opt_context;
|
||||
GError *error;
|
||||
GOptionEntry opt_entries[] =
|
||||
{
|
||||
{ "replace", 'r', 0, G_OPTION_ARG_NONE, &opt_replace, "Replace existing name if possible", NULL },
|
||||
{ "allow-replacement", 'a', 0, G_OPTION_ARG_NONE, &opt_allow_replacement, "Allow replacement", NULL },
|
||||
{ "name", 'n', 0, G_OPTION_ARG_STRING, &opt_name, "Name to acquire", NULL },
|
||||
{ NULL}
|
||||
};
|
||||
|
||||
g_type_init ();
|
||||
|
||||
error = NULL;
|
||||
opt_name = NULL;
|
||||
opt_replace = FALSE;
|
||||
opt_allow_replacement = FALSE;
|
||||
opt_context = g_option_context_new ("g_bus_own_name() example");
|
||||
g_option_context_add_main_entries (opt_context, opt_entries, NULL);
|
||||
if (!g_option_context_parse (opt_context, &argc, &argv, &error))
|
||||
{
|
||||
g_printerr ("Error parsing options: %s", error->message);
|
||||
return 1;
|
||||
}
|
||||
if (opt_name == NULL)
|
||||
{
|
||||
g_printerr ("Incorrect usage, try --help.\n");
|
||||
return 1;
|
||||
}
|
||||
|
||||
flags = G_BUS_NAME_OWNER_FLAGS_NONE;
|
||||
if (opt_replace)
|
||||
flags |= G_BUS_NAME_OWNER_FLAGS_REPLACE;
|
||||
if (opt_allow_replacement)
|
||||
flags |= G_BUS_NAME_OWNER_FLAGS_ALLOW_REPLACEMENT;
|
||||
|
||||
owner_id = g_bus_own_name (G_BUS_TYPE_SESSION,
|
||||
opt_name,
|
||||
flags,
|
||||
on_bus_acquired,
|
||||
on_name_acquired,
|
||||
on_name_lost,
|
||||
NULL,
|
||||
NULL);
|
||||
|
||||
loop = g_main_loop_new (NULL, FALSE);
|
||||
g_main_loop_run (loop);
|
||||
|
||||
g_bus_unown_name (owner_id);
|
||||
|
||||
return 0;
|
||||
}
|
305
gio/tests/gdbus-example-peer.c
Normal file
305
gio/tests/gdbus-example-peer.c
Normal file
@ -0,0 +1,305 @@
|
||||
/*
|
||||
|
||||
Usage examples (modulo addresses / credentials).
|
||||
|
||||
UNIX domain socket transport:
|
||||
|
||||
Server:
|
||||
$ ./gdbus-example-peer --server --address unix:abstract=myaddr
|
||||
Server is listening at: unix:abstract=myaddr
|
||||
Client connected.
|
||||
Peer credentials: GCredentials:unix-user=500,unix-group=500,unix-process=13378
|
||||
Negotiated capabilities: unix-fd-passing=1
|
||||
Client said: Hey, it's 1273093080 already!
|
||||
|
||||
Client:
|
||||
$ ./gdbus-example-peer --address unix:abstract=myaddr
|
||||
Connected.
|
||||
Negotiated capabilities: unix-fd-passing=1
|
||||
Server said: You said 'Hey, it's 1273093080 already!'. KTHXBYE!
|
||||
|
||||
Nonce-secured TCP transport on the same host:
|
||||
|
||||
Server:
|
||||
$ ./gdbus-example-peer --server --address nonce-tcp:
|
||||
Server is listening at: nonce-tcp:host=localhost,port=43077,noncefile=/tmp/gdbus-nonce-file-X1ZNCV
|
||||
Client connected.
|
||||
Peer credentials: (no credentials received)
|
||||
Negotiated capabilities: unix-fd-passing=0
|
||||
Client said: Hey, it's 1273093206 already!
|
||||
|
||||
Client:
|
||||
$ ./gdbus-example-peer -address nonce-tcp:host=localhost,port=43077,noncefile=/tmp/gdbus-nonce-file-X1ZNCV
|
||||
Connected.
|
||||
Negotiated capabilities: unix-fd-passing=0
|
||||
Server said: You said 'Hey, it's 1273093206 already!'. KTHXBYE!
|
||||
|
||||
TCP transport on two different hosts with a shared home directory:
|
||||
|
||||
Server:
|
||||
host1 $ ./gdbus-example-peer --server --address tcp:host=0.0.0.0
|
||||
Server is listening at: tcp:host=0.0.0.0,port=46314
|
||||
Client connected.
|
||||
Peer credentials: (no credentials received)
|
||||
Negotiated capabilities: unix-fd-passing=0
|
||||
Client said: Hey, it's 1273093337 already!
|
||||
|
||||
Client:
|
||||
host2 $ ./gdbus-example-peer -a tcp:host=host1,port=46314
|
||||
Connected.
|
||||
Negotiated capabilities: unix-fd-passing=0
|
||||
Server said: You said 'Hey, it's 1273093337 already!'. KTHXBYE!
|
||||
|
||||
TCP transport on two different hosts without authentication:
|
||||
|
||||
Server:
|
||||
host1 $ ./gdbus-example-peer --server --address tcp:host=0.0.0.0 --allow-anonymous
|
||||
Server is listening at: tcp:host=0.0.0.0,port=59556
|
||||
Client connected.
|
||||
Peer credentials: (no credentials received)
|
||||
Negotiated capabilities: unix-fd-passing=0
|
||||
Client said: Hey, it's 1273093652 already!
|
||||
|
||||
Client:
|
||||
host2 $ ./gdbus-example-peer -a tcp:host=host1,port=59556
|
||||
Connected.
|
||||
Negotiated capabilities: unix-fd-passing=0
|
||||
Server said: You said 'Hey, it's 1273093652 already!'. KTHXBYE!
|
||||
|
||||
*/
|
||||
|
||||
#include <gio/gio.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
/* ---------------------------------------------------------------------------------------------------- */
|
||||
|
||||
static GDBusNodeInfo *introspection_data = NULL;
|
||||
|
||||
/* Introspection data for the service we are exporting */
|
||||
static const gchar introspection_xml[] =
|
||||
"<node>"
|
||||
" <interface name='org.gtk.GDBus.TestPeerInterface'>"
|
||||
" <method name='HelloWorld'>"
|
||||
" <arg type='s' name='greeting' direction='in'/>"
|
||||
" <arg type='s' name='response' direction='out'/>"
|
||||
" </method>"
|
||||
" </interface>"
|
||||
"</node>";
|
||||
|
||||
/* ---------------------------------------------------------------------------------------------------- */
|
||||
|
||||
static void
|
||||
handle_method_call (GDBusConnection *connection,
|
||||
const gchar *sender,
|
||||
const gchar *object_path,
|
||||
const gchar *interface_name,
|
||||
const gchar *method_name,
|
||||
GVariant *parameters,
|
||||
GDBusMethodInvocation *invocation,
|
||||
gpointer user_data)
|
||||
{
|
||||
if (g_strcmp0 (method_name, "HelloWorld") == 0)
|
||||
{
|
||||
const gchar *greeting;
|
||||
gchar *response;
|
||||
|
||||
g_variant_get (parameters, "(s)", &greeting);
|
||||
response = g_strdup_printf ("You said '%s'. KTHXBYE!", greeting);
|
||||
g_dbus_method_invocation_return_value (invocation,
|
||||
g_variant_new ("(s)", response));
|
||||
g_free (response);
|
||||
g_print ("Client said: %s\n", greeting);
|
||||
}
|
||||
}
|
||||
|
||||
static const GDBusInterfaceVTable interface_vtable =
|
||||
{
|
||||
handle_method_call,
|
||||
NULL,
|
||||
NULL,
|
||||
};
|
||||
|
||||
/* ---------------------------------------------------------------------------------------------------- */
|
||||
|
||||
static void
|
||||
on_new_connection (GDBusServer *server,
|
||||
GDBusConnection *connection,
|
||||
gpointer user_data)
|
||||
{
|
||||
guint registration_id;
|
||||
GCredentials *credentials;
|
||||
gchar *s;
|
||||
|
||||
credentials = g_dbus_connection_get_peer_credentials (connection);
|
||||
if (credentials == NULL)
|
||||
s = g_strdup ("(no credentials received)");
|
||||
else
|
||||
s = g_credentials_to_string (credentials);
|
||||
|
||||
|
||||
g_print ("Client connected.\n"
|
||||
"Peer credentials: %s\n"
|
||||
"Negotiated capabilities: unix-fd-passing=%d\n",
|
||||
s,
|
||||
g_dbus_connection_get_capabilities (connection) & G_DBUS_CAPABILITY_FLAGS_UNIX_FD_PASSING);
|
||||
|
||||
g_object_ref (connection);
|
||||
registration_id = g_dbus_connection_register_object (connection,
|
||||
"/org/gtk/GDBus/TestObject",
|
||||
introspection_data->interfaces[0],
|
||||
&interface_vtable,
|
||||
NULL, /* user_data */
|
||||
NULL, /* user_data_free_func */
|
||||
NULL); /* GError** */
|
||||
g_assert (registration_id > 0);
|
||||
}
|
||||
|
||||
/* ---------------------------------------------------------------------------------------------------- */
|
||||
|
||||
int
|
||||
main (int argc, char *argv[])
|
||||
{
|
||||
gint ret;
|
||||
gboolean opt_server;
|
||||
gchar *opt_address;
|
||||
GOptionContext *opt_context;
|
||||
gboolean opt_allow_anonymous;
|
||||
GError *error;
|
||||
GOptionEntry opt_entries[] =
|
||||
{
|
||||
{ "server", 's', 0, G_OPTION_ARG_NONE, &opt_server, "Start a server instead of a client", NULL },
|
||||
{ "address", 'a', 0, G_OPTION_ARG_STRING, &opt_address, "D-Bus address to use", NULL },
|
||||
{ "allow-anonymous", 'n', 0, G_OPTION_ARG_NONE, &opt_allow_anonymous, "Allow anonymous authentication", NULL },
|
||||
{ NULL}
|
||||
};
|
||||
|
||||
ret = 1;
|
||||
|
||||
g_type_init ();
|
||||
|
||||
opt_address = NULL;
|
||||
opt_server = FALSE;
|
||||
opt_allow_anonymous = FALSE;
|
||||
|
||||
opt_context = g_option_context_new ("peer-to-peer example");
|
||||
error = NULL;
|
||||
g_option_context_add_main_entries (opt_context, opt_entries, NULL);
|
||||
if (!g_option_context_parse (opt_context, &argc, &argv, &error))
|
||||
{
|
||||
g_printerr ("Error parsing options: %s\n", error->message);
|
||||
g_error_free (error);
|
||||
goto out;
|
||||
}
|
||||
if (opt_address == NULL)
|
||||
{
|
||||
g_printerr ("Incorrect usage, try --help.\n");
|
||||
goto out;
|
||||
}
|
||||
if (!opt_server && opt_allow_anonymous)
|
||||
{
|
||||
g_printerr ("The --allow-anonymous option only makes sense when used with --server.\n");
|
||||
goto out;
|
||||
}
|
||||
|
||||
/* We are lazy here - we don't want to manually provide
|
||||
* the introspection data structures - so we just build
|
||||
* them from XML.
|
||||
*/
|
||||
introspection_data = g_dbus_node_info_new_for_xml (introspection_xml, NULL);
|
||||
g_assert (introspection_data != NULL);
|
||||
|
||||
if (opt_server)
|
||||
{
|
||||
GDBusServer *server;
|
||||
gchar *guid;
|
||||
GMainLoop *loop;
|
||||
GDBusServerFlags server_flags;
|
||||
|
||||
guid = g_dbus_generate_guid ();
|
||||
|
||||
server_flags = G_DBUS_SERVER_FLAGS_NONE;
|
||||
if (opt_allow_anonymous)
|
||||
server_flags |= G_DBUS_SERVER_FLAGS_AUTHENTICATION_ALLOW_ANONYMOUS;
|
||||
|
||||
error = NULL;
|
||||
server = g_dbus_server_new_sync (opt_address,
|
||||
server_flags,
|
||||
guid,
|
||||
NULL, /* GDBusAuthObserver */
|
||||
NULL, /* GCancellable */
|
||||
&error);
|
||||
g_dbus_server_start (server);
|
||||
g_free (guid);
|
||||
|
||||
if (server == NULL)
|
||||
{
|
||||
g_printerr ("Error creating server at address %s: %s\n", opt_address, error->message);
|
||||
g_error_free (error);
|
||||
goto out;
|
||||
}
|
||||
g_print ("Server is listening at: %s\n", g_dbus_server_get_client_address (server));
|
||||
g_signal_connect (server,
|
||||
"new-connection",
|
||||
G_CALLBACK (on_new_connection),
|
||||
NULL);
|
||||
|
||||
loop = g_main_loop_new (NULL, FALSE);
|
||||
g_main_loop_run (loop);
|
||||
|
||||
g_object_unref (server);
|
||||
g_main_loop_unref (loop);
|
||||
}
|
||||
else
|
||||
{
|
||||
GDBusConnection *connection;
|
||||
const gchar *greeting_response;
|
||||
GVariant *value;
|
||||
gchar *greeting;
|
||||
|
||||
error = NULL;
|
||||
connection = g_dbus_connection_new_for_address_sync (opt_address,
|
||||
G_DBUS_CONNECTION_FLAGS_AUTHENTICATION_CLIENT,
|
||||
NULL, /* GDBusAuthObserver */
|
||||
NULL, /* GCancellable */
|
||||
&error);
|
||||
if (connection == NULL)
|
||||
{
|
||||
g_printerr ("Error connecting to D-Bus address %s: %s\n", opt_address, error->message);
|
||||
g_error_free (error);
|
||||
goto out;
|
||||
}
|
||||
|
||||
g_print ("Connected.\n"
|
||||
"Negotiated capabilities: unix-fd-passing=%d\n",
|
||||
g_dbus_connection_get_capabilities (connection) & G_DBUS_CAPABILITY_FLAGS_UNIX_FD_PASSING);
|
||||
|
||||
greeting = g_strdup_printf ("Hey, it's %" G_GUINT64_FORMAT " already!", (guint64) time (NULL));
|
||||
value = g_dbus_connection_call_sync (connection,
|
||||
NULL, /* bus_name */
|
||||
"/org/gtk/GDBus/TestObject",
|
||||
"org.gtk.GDBus.TestPeerInterface",
|
||||
"HelloWorld",
|
||||
g_variant_new ("(s)", greeting),
|
||||
G_DBUS_CALL_FLAGS_NONE,
|
||||
-1,
|
||||
NULL,
|
||||
&error);
|
||||
if (value == NULL)
|
||||
{
|
||||
g_printerr ("Error invoking HelloWorld(): %s\n", error->message);
|
||||
g_error_free (error);
|
||||
goto out;
|
||||
}
|
||||
g_variant_get (value, "(s)", &greeting_response);
|
||||
g_print ("Server said: %s\n", greeting_response);
|
||||
g_variant_unref (value);
|
||||
|
||||
g_object_unref (connection);
|
||||
}
|
||||
g_dbus_node_info_unref (introspection_data);
|
||||
|
||||
ret = 0;
|
||||
|
||||
out:
|
||||
return ret;
|
||||
}
|
447
gio/tests/gdbus-example-proxy-subclass.c
Normal file
447
gio/tests/gdbus-example-proxy-subclass.c
Normal file
@ -0,0 +1,447 @@
|
||||
|
||||
#include <gio/gio.h>
|
||||
|
||||
/* ---------------------------------------------------------------------------------------------------- */
|
||||
/* The D-Bus interface definition we want to create a GDBusProxy-derived type for: */
|
||||
/* ---------------------------------------------------------------------------------------------------- */
|
||||
|
||||
static const gchar introspection_xml[] =
|
||||
"<node>"
|
||||
" <interface name='org.freedesktop.Accounts.User'>"
|
||||
" <method name='Frobnicate'>"
|
||||
" <arg name='flux' type='s' direction='in'/>"
|
||||
" <arg name='baz' type='s' direction='in'/>"
|
||||
" <arg name='result' type='s' direction='out'/>"
|
||||
" </method>"
|
||||
" <signal name='Changed'/>"
|
||||
" <property name='AutomaticLogin' type='b' access='readwrite'/>"
|
||||
" <property name='RealName' type='s' access='read'/>"
|
||||
" <property name='UserName' type='s' access='read'/>"
|
||||
" </interface>"
|
||||
"</node>";
|
||||
|
||||
/* ---------------------------------------------------------------------------------------------------- */
|
||||
/* Definition of the AccountsUser type */
|
||||
/* ---------------------------------------------------------------------------------------------------- */
|
||||
|
||||
#define ACCOUNTS_TYPE_USER (accounts_user_get_type ())
|
||||
#define ACCOUNTS_USER(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), ACCOUNTS_TYPE_USER, AccountsUser))
|
||||
#define ACCOUNTS_USER_CLASS(k) (G_TYPE_CHECK_CLASS_CAST((k), ACCOUNTS_TYPE_USER, AccountsUserClass))
|
||||
#define ACCOUNTS_USER_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS ((o), ACCOUNTS_TYPE_USER, AccountsUserClass))
|
||||
#define ACCOUNTS_IS_USER(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), ACCOUNTS_TYPE_USER))
|
||||
#define ACCOUNTS_IS_USER_CLASS(k) (G_TYPE_CHECK_CLASS_TYPE ((k), ACCOUNTS_TYPE_USER))
|
||||
|
||||
typedef struct _AccountsUser AccountsUser;
|
||||
typedef struct _AccountsUserClass AccountsUserClass;
|
||||
typedef struct _AccountsUserPrivate AccountsUserPrivate;
|
||||
|
||||
struct _AccountsUser
|
||||
{
|
||||
/*< private >*/
|
||||
GDBusProxy parent_instance;
|
||||
AccountsUserPrivate *priv;
|
||||
};
|
||||
|
||||
struct _AccountsUserClass
|
||||
{
|
||||
/*< private >*/
|
||||
GDBusProxyClass parent_class;
|
||||
void (*changed) (AccountsUser *user);
|
||||
};
|
||||
|
||||
GType accounts_user_get_type (void) G_GNUC_CONST;
|
||||
|
||||
const gchar *accounts_user_get_user_name (AccountsUser *user);
|
||||
const gchar *accounts_user_get_real_name (AccountsUser *user);
|
||||
gboolean accounts_user_get_automatic_login (AccountsUser *user);
|
||||
|
||||
void accounts_user_frobnicate (AccountsUser *user,
|
||||
const gchar *flux,
|
||||
gint baz,
|
||||
GCancellable *cancellable,
|
||||
GAsyncReadyCallback callback,
|
||||
gpointer user_data);
|
||||
gchar *accounts_user_frobnicate_finish (AccountsUser *user,
|
||||
GAsyncResult *res,
|
||||
GError **error);
|
||||
gchar *accounts_user_frobnicate_sync (AccountsUser *user,
|
||||
const gchar *flux,
|
||||
gint baz,
|
||||
GCancellable *cancellable,
|
||||
GError **error);
|
||||
|
||||
/* ---------------------------------------------------------------------------------------------------- */
|
||||
/* Implementation of the AccountsUser type */
|
||||
/* ---------------------------------------------------------------------------------------------------- */
|
||||
|
||||
/* A more efficient approach than parsing XML is to use const static
|
||||
* GDBusInterfaceInfo, GDBusMethodInfo, ... structures
|
||||
*/
|
||||
static GDBusInterfaceInfo *
|
||||
accounts_user_get_interface_info (void)
|
||||
{
|
||||
static gsize has_info = 0;
|
||||
static GDBusInterfaceInfo *info = NULL;
|
||||
if (g_once_init_enter (&has_info))
|
||||
{
|
||||
GDBusNodeInfo *introspection_data;
|
||||
introspection_data = g_dbus_node_info_new_for_xml (introspection_xml, NULL);
|
||||
info = introspection_data->interfaces[0];
|
||||
g_once_init_leave (&has_info, 1);
|
||||
}
|
||||
return info;
|
||||
}
|
||||
|
||||
enum
|
||||
{
|
||||
PROP_0,
|
||||
PROP_USER_NAME,
|
||||
PROP_REAL_NAME,
|
||||
PROP_AUTOMATIC_LOGIN,
|
||||
};
|
||||
|
||||
enum
|
||||
{
|
||||
CHANGED_SIGNAL,
|
||||
LAST_SIGNAL
|
||||
};
|
||||
|
||||
static guint signals[LAST_SIGNAL] = {0};
|
||||
|
||||
G_DEFINE_TYPE (AccountsUser, accounts_user, G_TYPE_DBUS_PROXY);
|
||||
|
||||
static void
|
||||
accounts_user_finalize (GObject *object)
|
||||
{
|
||||
G_GNUC_UNUSED AccountsUser *user = ACCOUNTS_USER (object);
|
||||
|
||||
if (G_OBJECT_CLASS (accounts_user_parent_class)->finalize != NULL)
|
||||
G_OBJECT_CLASS (accounts_user_parent_class)->finalize (object);
|
||||
}
|
||||
|
||||
static void
|
||||
accounts_user_init (AccountsUser *user)
|
||||
{
|
||||
/* Sets the expected interface */
|
||||
g_dbus_proxy_set_interface_info (G_DBUS_PROXY (user), accounts_user_get_interface_info ());
|
||||
}
|
||||
|
||||
static void
|
||||
accounts_user_get_property (GObject *object,
|
||||
guint prop_id,
|
||||
GValue *value,
|
||||
GParamSpec *pspec)
|
||||
{
|
||||
AccountsUser *user = ACCOUNTS_USER (object);
|
||||
|
||||
switch (prop_id)
|
||||
{
|
||||
case PROP_USER_NAME:
|
||||
g_value_set_string (value, accounts_user_get_user_name (user));
|
||||
break;
|
||||
|
||||
case PROP_REAL_NAME:
|
||||
g_value_set_string (value, accounts_user_get_real_name (user));
|
||||
break;
|
||||
|
||||
case PROP_AUTOMATIC_LOGIN:
|
||||
g_value_set_boolean (value, accounts_user_get_automatic_login (user));
|
||||
break;
|
||||
|
||||
default:
|
||||
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
const gchar *
|
||||
accounts_user_get_user_name (AccountsUser *user)
|
||||
{
|
||||
GVariant *value;
|
||||
const gchar *ret;
|
||||
g_return_val_if_fail (ACCOUNTS_IS_USER (user), NULL);
|
||||
value = g_dbus_proxy_get_cached_property (G_DBUS_PROXY (user), "UserName");
|
||||
ret = g_variant_get_string (value, NULL);
|
||||
g_variant_unref (value);
|
||||
return ret;
|
||||
}
|
||||
|
||||
const gchar *
|
||||
accounts_user_get_real_name (AccountsUser *user)
|
||||
{
|
||||
GVariant *value;
|
||||
const gchar *ret;
|
||||
g_return_val_if_fail (ACCOUNTS_IS_USER (user), NULL);
|
||||
value = g_dbus_proxy_get_cached_property (G_DBUS_PROXY (user), "RealName");
|
||||
ret = g_variant_get_string (value, NULL);
|
||||
g_variant_unref (value);
|
||||
return ret;
|
||||
}
|
||||
|
||||
gboolean
|
||||
accounts_user_get_automatic_login (AccountsUser *user)
|
||||
{
|
||||
GVariant *value;
|
||||
gboolean ret;
|
||||
g_return_val_if_fail (ACCOUNTS_IS_USER (user), FALSE);
|
||||
value = g_dbus_proxy_get_cached_property (G_DBUS_PROXY (user), "AutomaticLogin");
|
||||
ret = g_variant_get_boolean (value);
|
||||
g_variant_unref (value);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void
|
||||
accounts_user_g_signal (GDBusProxy *proxy,
|
||||
const gchar *sender_name,
|
||||
const gchar *signal_name,
|
||||
GVariant *parameters)
|
||||
{
|
||||
AccountsUser *user = ACCOUNTS_USER (proxy);
|
||||
if (g_strcmp0 (signal_name, "Changed") == 0)
|
||||
g_signal_emit (user, signals[CHANGED_SIGNAL], 0);
|
||||
}
|
||||
|
||||
static void
|
||||
accounts_user_g_properties_changed (GDBusProxy *proxy,
|
||||
GVariant *changed_properties,
|
||||
const gchar* const *invalidated_properties)
|
||||
{
|
||||
AccountsUser *user = ACCOUNTS_USER (proxy);
|
||||
GVariantIter *iter;
|
||||
GVariant *item;
|
||||
|
||||
if (changed_properties != NULL)
|
||||
{
|
||||
g_variant_get (changed_properties, "a{sv}", &iter);
|
||||
while ((item = g_variant_iter_next_value (iter)) != NULL)
|
||||
{
|
||||
const gchar *key;
|
||||
g_variant_get (item,
|
||||
"{sv}",
|
||||
&key,
|
||||
NULL);
|
||||
if (g_strcmp0 (key, "AutomaticLogin") == 0)
|
||||
g_object_notify (G_OBJECT (user), "automatic-login");
|
||||
else if (g_strcmp0 (key, "RealName") == 0)
|
||||
g_object_notify (G_OBJECT (user), "real-name");
|
||||
else if (g_strcmp0 (key, "UserName") == 0)
|
||||
g_object_notify (G_OBJECT (user), "user-name");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
accounts_user_class_init (AccountsUserClass *klass)
|
||||
{
|
||||
GObjectClass *gobject_class;
|
||||
GDBusProxyClass *proxy_class;
|
||||
|
||||
gobject_class = G_OBJECT_CLASS (klass);
|
||||
gobject_class->get_property = accounts_user_get_property;
|
||||
gobject_class->finalize = accounts_user_finalize;
|
||||
|
||||
proxy_class = G_DBUS_PROXY_CLASS (klass);
|
||||
proxy_class->g_signal = accounts_user_g_signal;
|
||||
proxy_class->g_properties_changed = accounts_user_g_properties_changed;
|
||||
|
||||
g_object_class_install_property (gobject_class,
|
||||
PROP_USER_NAME,
|
||||
g_param_spec_string ("user-name",
|
||||
"User Name",
|
||||
"The user name of the user",
|
||||
NULL,
|
||||
G_PARAM_READABLE |
|
||||
G_PARAM_STATIC_STRINGS));
|
||||
|
||||
g_object_class_install_property (gobject_class,
|
||||
PROP_REAL_NAME,
|
||||
g_param_spec_string ("real-name",
|
||||
"Real Name",
|
||||
"The real name of the user",
|
||||
NULL,
|
||||
G_PARAM_READABLE |
|
||||
G_PARAM_STATIC_STRINGS));
|
||||
|
||||
g_object_class_install_property (gobject_class,
|
||||
PROP_AUTOMATIC_LOGIN,
|
||||
g_param_spec_boolean ("automatic-login",
|
||||
"Automatic Login",
|
||||
"Whether the user is automatically logged in",
|
||||
FALSE,
|
||||
G_PARAM_READABLE |
|
||||
G_PARAM_STATIC_STRINGS));
|
||||
|
||||
signals[CHANGED_SIGNAL] = g_signal_new ("changed",
|
||||
ACCOUNTS_TYPE_USER,
|
||||
G_SIGNAL_RUN_LAST,
|
||||
G_STRUCT_OFFSET (AccountsUserClass, changed),
|
||||
NULL,
|
||||
NULL,
|
||||
g_cclosure_marshal_VOID__VOID,
|
||||
G_TYPE_NONE,
|
||||
0);
|
||||
}
|
||||
|
||||
gchar *
|
||||
accounts_user_frobnicate_sync (AccountsUser *user,
|
||||
const gchar *flux,
|
||||
gint baz,
|
||||
GCancellable *cancellable,
|
||||
GError **error)
|
||||
{
|
||||
gchar *ret;
|
||||
GVariant *value;
|
||||
|
||||
g_return_val_if_fail (ACCOUNTS_IS_USER (user), NULL);
|
||||
|
||||
ret = NULL;
|
||||
|
||||
value = g_dbus_proxy_call_sync (G_DBUS_PROXY (user),
|
||||
"Frobnicate",
|
||||
g_variant_new ("(si)",
|
||||
flux,
|
||||
baz),
|
||||
G_DBUS_CALL_FLAGS_NONE,
|
||||
-1,
|
||||
cancellable,
|
||||
error);
|
||||
if (value != NULL)
|
||||
{
|
||||
g_variant_get (value, "(s)", &ret);
|
||||
ret = g_strdup (ret);
|
||||
g_variant_unref (value);
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
void
|
||||
accounts_user_frobnicate (AccountsUser *user,
|
||||
const gchar *flux,
|
||||
gint baz,
|
||||
GCancellable *cancellable,
|
||||
GAsyncReadyCallback callback,
|
||||
gpointer user_data)
|
||||
{
|
||||
g_return_if_fail (ACCOUNTS_IS_USER (user));
|
||||
g_dbus_proxy_call (G_DBUS_PROXY (user),
|
||||
"Frobnicate",
|
||||
g_variant_new ("(si)",
|
||||
flux,
|
||||
baz),
|
||||
G_DBUS_CALL_FLAGS_NONE,
|
||||
-1,
|
||||
cancellable,
|
||||
callback,
|
||||
user_data);
|
||||
}
|
||||
|
||||
|
||||
gchar *
|
||||
accounts_user_frobnicate_finish (AccountsUser *user,
|
||||
GAsyncResult *res,
|
||||
GError **error)
|
||||
{
|
||||
gchar *ret;
|
||||
GVariant *value;
|
||||
|
||||
ret = NULL;
|
||||
value = g_dbus_proxy_call_finish (G_DBUS_PROXY (user), res, error);
|
||||
if (value != NULL)
|
||||
{
|
||||
g_variant_get (value, "(s)", &ret);
|
||||
ret = g_strdup (ret);
|
||||
g_variant_unref (value);
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* ---------------------------------------------------------------------------------------------------- */
|
||||
/* Example usage of the AccountsUser type */
|
||||
/* ---------------------------------------------------------------------------------------------------- */
|
||||
|
||||
static void
|
||||
print_user (AccountsUser *user)
|
||||
{
|
||||
g_print (" user-name = `%s'\n", accounts_user_get_user_name (user));
|
||||
g_print (" real-name = `%s'\n", accounts_user_get_real_name (user));
|
||||
g_print (" automatic-login = %s\n", accounts_user_get_automatic_login (user) ? "true" : "false");
|
||||
}
|
||||
|
||||
static void
|
||||
on_changed (AccountsUser *user,
|
||||
gpointer user_data)
|
||||
{
|
||||
g_print ("+++ Received the AccountsUser::changed signal\n");
|
||||
print_user (user);
|
||||
}
|
||||
|
||||
static void
|
||||
on_notify (GObject *object,
|
||||
GParamSpec *pspec,
|
||||
gpointer user_data)
|
||||
{
|
||||
AccountsUser *user = ACCOUNTS_USER (object);
|
||||
g_print ("+++ Received the GObject::notify signal for property `%s'\n",
|
||||
pspec->name);
|
||||
print_user (user);
|
||||
}
|
||||
|
||||
static void
|
||||
on_proxy_appeared (GDBusConnection *connection,
|
||||
const gchar *name,
|
||||
const gchar *name_owner,
|
||||
GDBusProxy *proxy,
|
||||
gpointer user_data)
|
||||
{
|
||||
AccountsUser *user = ACCOUNTS_USER (proxy);
|
||||
|
||||
g_print ("+++ Acquired proxy for user\n");
|
||||
print_user (user);
|
||||
|
||||
g_signal_connect (proxy,
|
||||
"notify",
|
||||
G_CALLBACK (on_notify),
|
||||
NULL);
|
||||
g_signal_connect (user,
|
||||
"changed",
|
||||
G_CALLBACK (on_changed),
|
||||
NULL);
|
||||
}
|
||||
|
||||
static void
|
||||
on_proxy_vanished (GDBusConnection *connection,
|
||||
const gchar *name,
|
||||
gpointer user_data)
|
||||
{
|
||||
g_print ("--- Cannot create proxy for user: no remote object\n");
|
||||
}
|
||||
|
||||
/* ---------------------------------------------------------------------------------------------------- */
|
||||
|
||||
gint
|
||||
main (gint argc, gchar *argv[])
|
||||
{
|
||||
guint watcher_id;
|
||||
GMainLoop *loop;
|
||||
|
||||
g_type_init ();
|
||||
|
||||
watcher_id = g_bus_watch_proxy (G_BUS_TYPE_SYSTEM,
|
||||
"org.freedesktop.Accounts",
|
||||
G_BUS_NAME_WATCHER_FLAGS_AUTO_START,
|
||||
"/org/freedesktop/Accounts/User500",
|
||||
"org.freedesktop.Accounts.User",
|
||||
ACCOUNTS_TYPE_USER,
|
||||
G_DBUS_PROXY_FLAGS_NONE,
|
||||
on_proxy_appeared,
|
||||
on_proxy_vanished,
|
||||
NULL,
|
||||
NULL);
|
||||
|
||||
loop = g_main_loop_new (NULL, FALSE);
|
||||
g_main_loop_run (loop);
|
||||
g_main_loop_unref (loop);
|
||||
g_bus_unwatch_proxy (watcher_id);
|
||||
|
||||
return 0;
|
||||
}
|
390
gio/tests/gdbus-example-server.c
Normal file
390
gio/tests/gdbus-example-server.c
Normal file
@ -0,0 +1,390 @@
|
||||
#include <gio/gio.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#ifdef G_OS_UNIX
|
||||
/* For STDOUT_FILENO */
|
||||
#include <unistd.h>
|
||||
#endif
|
||||
|
||||
/* ---------------------------------------------------------------------------------------------------- */
|
||||
|
||||
static GDBusNodeInfo *introspection_data = NULL;
|
||||
|
||||
/* Introspection data for the service we are exporting */
|
||||
static const gchar introspection_xml[] =
|
||||
"<node>"
|
||||
" <interface name='org.gtk.GDBus.TestInterface'>"
|
||||
" <annotation name='org.gtk.GDBus.Annotation' value='OnInterface'/>"
|
||||
" <annotation name='org.gtk.GDBus.Annotation' value='AlsoOnInterface'/>"
|
||||
" <method name='HelloWorld'>"
|
||||
" <annotation name='org.gtk.GDBus.Annotation' value='OnMethod'/>"
|
||||
" <arg type='s' name='greeting' direction='in'/>"
|
||||
" <arg type='s' name='response' direction='out'/>"
|
||||
" </method>"
|
||||
" <method name='EmitSignal'>"
|
||||
" <arg type='d' name='speed_in_mph' direction='in'>"
|
||||
" <annotation name='org.gtk.GDBus.Annotation' value='OnArg'/>"
|
||||
" </arg>"
|
||||
" </method>"
|
||||
" <method name='GimmeStdout'/>"
|
||||
" <signal name='VelocityChanged'>"
|
||||
" <annotation name='org.gtk.GDBus.Annotation' value='Onsignal'/>"
|
||||
" <arg type='d' name='speed_in_mph'/>"
|
||||
" <arg type='s' name='speed_as_string'>"
|
||||
" <annotation name='org.gtk.GDBus.Annotation' value='OnArg_NonFirst'/>"
|
||||
" </arg>"
|
||||
" </signal>"
|
||||
" <property type='s' name='FluxCapicitorName' access='read'>"
|
||||
" <annotation name='org.gtk.GDBus.Annotation' value='OnProperty'>"
|
||||
" <annotation name='org.gtk.GDBus.Annotation' value='OnAnnotation_YesThisIsCrazy'/>"
|
||||
" </annotation>"
|
||||
" </property>"
|
||||
" <property type='s' name='Title' access='readwrite'/>"
|
||||
" <property type='s' name='ReadingAlwaysThrowsError' access='read'/>"
|
||||
" <property type='s' name='WritingAlwaysThrowsError' access='readwrite'/>"
|
||||
" <property type='s' name='OnlyWritable' access='write'/>"
|
||||
" <property type='s' name='Foo' access='read'/>"
|
||||
" <property type='s' name='Bar' access='read'/>"
|
||||
" </interface>"
|
||||
"</node>";
|
||||
|
||||
/* ---------------------------------------------------------------------------------------------------- */
|
||||
|
||||
static void
|
||||
handle_method_call (GDBusConnection *connection,
|
||||
const gchar *sender,
|
||||
const gchar *object_path,
|
||||
const gchar *interface_name,
|
||||
const gchar *method_name,
|
||||
GVariant *parameters,
|
||||
GDBusMethodInvocation *invocation,
|
||||
gpointer user_data)
|
||||
{
|
||||
if (g_strcmp0 (method_name, "HelloWorld") == 0)
|
||||
{
|
||||
const gchar *greeting;
|
||||
|
||||
g_variant_get (parameters, "(s)", &greeting);
|
||||
|
||||
if (g_strcmp0 (greeting, "Return Unregistered") == 0)
|
||||
{
|
||||
g_dbus_method_invocation_return_error (invocation,
|
||||
G_IO_ERROR,
|
||||
G_IO_ERROR_FAILED_HANDLED,
|
||||
"As requested, here's a GError not registered (G_IO_ERROR_FAILED_HANDLED)");
|
||||
}
|
||||
else if (g_strcmp0 (greeting, "Return Registered") == 0)
|
||||
{
|
||||
g_dbus_method_invocation_return_error (invocation,
|
||||
G_DBUS_ERROR,
|
||||
G_DBUS_ERROR_MATCH_RULE_NOT_FOUND,
|
||||
"As requested, here's a GError that is registered (G_DBUS_ERROR_MATCH_RULE_NOT_FOUND)");
|
||||
}
|
||||
else if (g_strcmp0 (greeting, "Return Raw") == 0)
|
||||
{
|
||||
g_dbus_method_invocation_return_dbus_error (invocation,
|
||||
"org.gtk.GDBus.SomeErrorName",
|
||||
"As requested, here's a raw D-Bus error");
|
||||
}
|
||||
else
|
||||
{
|
||||
gchar *response;
|
||||
response = g_strdup_printf ("You greeted me with '%s'. Thanks!", greeting);
|
||||
g_dbus_method_invocation_return_value (invocation,
|
||||
g_variant_new ("(s)", response));
|
||||
g_free (response);
|
||||
}
|
||||
}
|
||||
else if (g_strcmp0 (method_name, "EmitSignal") == 0)
|
||||
{
|
||||
GError *local_error;
|
||||
gdouble speed_in_mph;
|
||||
gchar *speed_as_string;
|
||||
|
||||
g_variant_get (parameters, "(d)", &speed_in_mph);
|
||||
speed_as_string = g_strdup_printf ("%g mph!", speed_in_mph);
|
||||
|
||||
local_error = NULL;
|
||||
g_dbus_connection_emit_signal (connection,
|
||||
NULL,
|
||||
object_path,
|
||||
interface_name,
|
||||
"VelocityChanged",
|
||||
g_variant_new ("(ds)",
|
||||
speed_in_mph,
|
||||
speed_as_string),
|
||||
&local_error);
|
||||
g_assert_no_error (local_error);
|
||||
g_free (speed_as_string);
|
||||
|
||||
g_dbus_method_invocation_return_value (invocation, NULL);
|
||||
}
|
||||
else if (g_strcmp0 (method_name, "GimmeStdout") == 0)
|
||||
{
|
||||
#ifdef G_OS_UNIX
|
||||
if (g_dbus_connection_get_capabilities (connection) & G_DBUS_CAPABILITY_FLAGS_UNIX_FD_PASSING)
|
||||
{
|
||||
GDBusMessage *reply;
|
||||
GUnixFDList *fd_list;
|
||||
GError *error;
|
||||
|
||||
fd_list = g_unix_fd_list_new ();
|
||||
error = NULL;
|
||||
g_unix_fd_list_append (fd_list, STDOUT_FILENO, &error);
|
||||
g_assert_no_error (error);
|
||||
|
||||
reply = g_dbus_message_new_method_reply (g_dbus_method_invocation_get_message (invocation));
|
||||
g_dbus_message_set_unix_fd_list (reply, fd_list);
|
||||
|
||||
error = NULL;
|
||||
g_dbus_connection_send_message (connection,
|
||||
reply,
|
||||
NULL, /* out_serial */
|
||||
&error);
|
||||
g_assert_no_error (error);
|
||||
|
||||
g_object_unref (invocation);
|
||||
g_object_unref (fd_list);
|
||||
g_object_unref (reply);
|
||||
}
|
||||
else
|
||||
{
|
||||
g_dbus_method_invocation_return_dbus_error (invocation,
|
||||
"org.gtk.GDBus.Failed",
|
||||
"Your message bus daemon does not support file descriptor passing (need D-Bus >= 1.3.0)");
|
||||
}
|
||||
#else
|
||||
g_dbus_method_invocation_return_dbus_error (invocation,
|
||||
"org.gtk.GDBus.NotOnUnix",
|
||||
"Your OS does not support file descriptor passing");
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
static gchar *_global_title = NULL;
|
||||
|
||||
static gboolean swap_a_and_b = FALSE;
|
||||
|
||||
static GVariant *
|
||||
handle_get_property (GDBusConnection *connection,
|
||||
const gchar *sender,
|
||||
const gchar *object_path,
|
||||
const gchar *interface_name,
|
||||
const gchar *property_name,
|
||||
GError **error,
|
||||
gpointer user_data)
|
||||
{
|
||||
GVariant *ret;
|
||||
|
||||
ret = NULL;
|
||||
if (g_strcmp0 (property_name, "FluxCapicitorName") == 0)
|
||||
{
|
||||
ret = g_variant_new_string ("DeLorean");
|
||||
}
|
||||
else if (g_strcmp0 (property_name, "Title") == 0)
|
||||
{
|
||||
if (_global_title == NULL)
|
||||
_global_title = g_strdup ("Back To C!");
|
||||
ret = g_variant_new_string (_global_title);
|
||||
}
|
||||
else if (g_strcmp0 (property_name, "ReadingAlwaysThrowsError") == 0)
|
||||
{
|
||||
g_set_error (error,
|
||||
G_IO_ERROR,
|
||||
G_IO_ERROR_FAILED,
|
||||
"Hello %s. I thought I said reading this property "
|
||||
"always results in an error. kthxbye",
|
||||
sender);
|
||||
}
|
||||
else if (g_strcmp0 (property_name, "WritingAlwaysThrowsError") == 0)
|
||||
{
|
||||
ret = g_variant_new_string ("There's no home like home");
|
||||
}
|
||||
else if (g_strcmp0 (property_name, "Foo") == 0)
|
||||
{
|
||||
ret = g_variant_new_string (swap_a_and_b ? "Tock" : "Tick");
|
||||
}
|
||||
else if (g_strcmp0 (property_name, "Bar") == 0)
|
||||
{
|
||||
ret = g_variant_new_string (swap_a_and_b ? "Tick" : "Tock");
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
handle_set_property (GDBusConnection *connection,
|
||||
const gchar *sender,
|
||||
const gchar *object_path,
|
||||
const gchar *interface_name,
|
||||
const gchar *property_name,
|
||||
GVariant *value,
|
||||
GError **error,
|
||||
gpointer user_data)
|
||||
{
|
||||
if (g_strcmp0 (property_name, "Title") == 0)
|
||||
{
|
||||
if (g_strcmp0 (_global_title, g_variant_get_string (value, NULL)) != 0)
|
||||
{
|
||||
GVariantBuilder *builder;
|
||||
GError *local_error;
|
||||
|
||||
g_free (_global_title);
|
||||
_global_title = g_variant_dup_string (value, NULL);
|
||||
|
||||
local_error = NULL;
|
||||
builder = g_variant_builder_new (G_VARIANT_TYPE_ARRAY);
|
||||
g_variant_builder_add (builder,
|
||||
"{sv}",
|
||||
"Title",
|
||||
g_variant_new_string (_global_title));
|
||||
g_dbus_connection_emit_signal (connection,
|
||||
NULL,
|
||||
object_path,
|
||||
"org.freedesktop.DBus.Properties",
|
||||
"PropertiesChanged",
|
||||
g_variant_new ("(sa{sv}as)",
|
||||
interface_name,
|
||||
builder,
|
||||
NULL),
|
||||
&local_error);
|
||||
g_assert_no_error (local_error);
|
||||
}
|
||||
}
|
||||
else if (g_strcmp0 (property_name, "ReadingAlwaysThrowsError") == 0)
|
||||
{
|
||||
/* do nothing - they can't read it after all! */
|
||||
}
|
||||
else if (g_strcmp0 (property_name, "WritingAlwaysThrowsError") == 0)
|
||||
{
|
||||
g_set_error (error,
|
||||
G_IO_ERROR,
|
||||
G_IO_ERROR_FAILED,
|
||||
"Hello AGAIN %s. I thought I said writing this property "
|
||||
"always results in an error. kthxbye",
|
||||
sender);
|
||||
}
|
||||
|
||||
return *error == NULL;
|
||||
}
|
||||
|
||||
|
||||
/* for now */
|
||||
static const GDBusInterfaceVTable interface_vtable =
|
||||
{
|
||||
handle_method_call,
|
||||
handle_get_property,
|
||||
handle_set_property
|
||||
};
|
||||
|
||||
/* ---------------------------------------------------------------------------------------------------- */
|
||||
|
||||
static gboolean
|
||||
on_timeout_cb (gpointer user_data)
|
||||
{
|
||||
GDBusConnection *connection = G_DBUS_CONNECTION (user_data);
|
||||
GVariantBuilder *builder;
|
||||
GVariantBuilder *invalidated_builder;
|
||||
GError *error;
|
||||
|
||||
swap_a_and_b = !swap_a_and_b;
|
||||
|
||||
error = NULL;
|
||||
builder = g_variant_builder_new (G_VARIANT_TYPE_ARRAY);
|
||||
invalidated_builder = g_variant_builder_new (G_VARIANT_TYPE ("as"));
|
||||
g_variant_builder_add (builder,
|
||||
"{sv}",
|
||||
"Foo",
|
||||
g_variant_new_string (swap_a_and_b ? "Tock" : "Tick"));
|
||||
g_variant_builder_add (builder,
|
||||
"{sv}",
|
||||
"Bar",
|
||||
g_variant_new_string (swap_a_and_b ? "Tick" : "Tock"));
|
||||
g_dbus_connection_emit_signal (connection,
|
||||
NULL,
|
||||
"/org/gtk/GDBus/TestObject",
|
||||
"org.freedesktop.DBus.Properties",
|
||||
"PropertiesChanged",
|
||||
g_variant_new ("(sa{sv}as)",
|
||||
"org.gtk.GDBus.TestInterface",
|
||||
builder,
|
||||
invalidated_builder),
|
||||
&error);
|
||||
g_assert_no_error (error);
|
||||
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
/* ---------------------------------------------------------------------------------------------------- */
|
||||
|
||||
static void
|
||||
on_bus_acquired (GDBusConnection *connection,
|
||||
const gchar *name,
|
||||
gpointer user_data)
|
||||
{
|
||||
guint registration_id;
|
||||
|
||||
registration_id = g_dbus_connection_register_object (connection,
|
||||
"/org/gtk/GDBus/TestObject",
|
||||
introspection_data->interfaces[0],
|
||||
&interface_vtable,
|
||||
NULL, /* user_data */
|
||||
NULL, /* user_data_free_func */
|
||||
NULL); /* GError** */
|
||||
g_assert (registration_id > 0);
|
||||
|
||||
/* swap value of properties Foo and Bar every two seconds */
|
||||
g_timeout_add_seconds (2,
|
||||
on_timeout_cb,
|
||||
connection);
|
||||
}
|
||||
|
||||
static void
|
||||
on_name_acquired (GDBusConnection *connection,
|
||||
const gchar *name,
|
||||
gpointer user_data)
|
||||
{
|
||||
}
|
||||
|
||||
static void
|
||||
on_name_lost (GDBusConnection *connection,
|
||||
const gchar *name,
|
||||
gpointer user_data)
|
||||
{
|
||||
exit (1);
|
||||
}
|
||||
|
||||
int
|
||||
main (int argc, char *argv[])
|
||||
{
|
||||
guint owner_id;
|
||||
GMainLoop *loop;
|
||||
|
||||
g_type_init ();
|
||||
|
||||
/* We are lazy here - we don't want to manually provide
|
||||
* the introspection data structures - so we just build
|
||||
* them from XML.
|
||||
*/
|
||||
introspection_data = g_dbus_node_info_new_for_xml (introspection_xml, NULL);
|
||||
g_assert (introspection_data != NULL);
|
||||
|
||||
owner_id = g_bus_own_name (G_BUS_TYPE_SESSION,
|
||||
"org.gtk.GDBus.TestServer",
|
||||
G_BUS_NAME_OWNER_FLAGS_NONE,
|
||||
on_bus_acquired,
|
||||
on_name_acquired,
|
||||
on_name_lost,
|
||||
NULL,
|
||||
NULL);
|
||||
|
||||
loop = g_main_loop_new (NULL, FALSE);
|
||||
g_main_loop_run (loop);
|
||||
|
||||
g_bus_unown_name (owner_id);
|
||||
|
||||
g_dbus_node_info_unref (introspection_data);
|
||||
|
||||
return 0;
|
||||
}
|
397
gio/tests/gdbus-example-subtree.c
Normal file
397
gio/tests/gdbus-example-subtree.c
Normal file
@ -0,0 +1,397 @@
|
||||
#include <gio/gio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
/* ---------------------------------------------------------------------------------------------------- */
|
||||
|
||||
static GDBusNodeInfo *introspection_data = NULL;
|
||||
static const GDBusInterfaceInfo *manager_interface_info = NULL;
|
||||
static const GDBusInterfaceInfo *block_interface_info = NULL;
|
||||
static const GDBusInterfaceInfo *partition_interface_info = NULL;
|
||||
|
||||
/* Introspection data for the service we are exporting */
|
||||
static const gchar introspection_xml[] =
|
||||
"<node>"
|
||||
" <interface name='org.gtk.GDBus.Example.Manager'>"
|
||||
" <method name='Hello'>"
|
||||
" <arg type='s' name='greeting' direction='in'/>"
|
||||
" <arg type='s' name='response' direction='out'/>"
|
||||
" </method>"
|
||||
" </interface>"
|
||||
" <interface name='org.gtk.GDBus.Example.Block'>"
|
||||
" <method name='Hello'>"
|
||||
" <arg type='s' name='greeting' direction='in'/>"
|
||||
" <arg type='s' name='response' direction='out'/>"
|
||||
" </method>"
|
||||
" <property type='i' name='Major' access='read'/>"
|
||||
" <property type='i' name='Minor' access='read'/>"
|
||||
" <property type='s' name='Notes' access='readwrite'/>"
|
||||
" </interface>"
|
||||
" <interface name='org.gtk.GDBus.Example.Partition'>"
|
||||
" <method name='Hello'>"
|
||||
" <arg type='s' name='greeting' direction='in'/>"
|
||||
" <arg type='s' name='response' direction='out'/>"
|
||||
" </method>"
|
||||
" <property type='i' name='PartitionNumber' access='read'/>"
|
||||
" <property type='s' name='Notes' access='readwrite'/>"
|
||||
" </interface>"
|
||||
"</node>";
|
||||
|
||||
/* ---------------------------------------------------------------------------------------------------- */
|
||||
|
||||
static void
|
||||
manager_method_call (GDBusConnection *connection,
|
||||
const gchar *sender,
|
||||
const gchar *object_path,
|
||||
const gchar *interface_name,
|
||||
const gchar *method_name,
|
||||
GVariant *parameters,
|
||||
GDBusMethodInvocation *invocation,
|
||||
gpointer user_data)
|
||||
{
|
||||
const gchar *greeting;
|
||||
gchar *response;
|
||||
|
||||
g_assert_cmpstr (interface_name, ==, "org.gtk.GDBus.Example.Manager");
|
||||
g_assert_cmpstr (method_name, ==, "Hello");
|
||||
|
||||
g_variant_get (parameters, "(s)", &greeting);
|
||||
|
||||
response = g_strdup_printf ("Method %s.%s with user_data `%s' on object path %s called with arg '%s'",
|
||||
interface_name,
|
||||
method_name,
|
||||
(const gchar *) user_data,
|
||||
object_path,
|
||||
greeting);
|
||||
g_dbus_method_invocation_return_value (invocation,
|
||||
g_variant_new ("(s)", response));
|
||||
g_free (response);
|
||||
}
|
||||
|
||||
const GDBusInterfaceVTable manager_vtable =
|
||||
{
|
||||
manager_method_call,
|
||||
NULL, /* get_property */
|
||||
NULL /* set_property */
|
||||
};
|
||||
|
||||
/* ---------------------------------------------------------------------------------------------------- */
|
||||
|
||||
static void
|
||||
block_method_call (GDBusConnection *connection,
|
||||
const gchar *sender,
|
||||
const gchar *object_path,
|
||||
const gchar *interface_name,
|
||||
const gchar *method_name,
|
||||
GVariant *parameters,
|
||||
GDBusMethodInvocation *invocation,
|
||||
gpointer user_data)
|
||||
{
|
||||
g_assert_cmpstr (interface_name, ==, "org.gtk.GDBus.Example.Block");
|
||||
|
||||
if (g_strcmp0 (method_name, "Hello") == 0)
|
||||
{
|
||||
const gchar *greeting;
|
||||
gchar *response;
|
||||
|
||||
g_variant_get (parameters, "(s)", &greeting);
|
||||
|
||||
response = g_strdup_printf ("Method %s.%s with user_data `%s' on object path %s called with arg '%s'",
|
||||
interface_name,
|
||||
method_name,
|
||||
(const gchar *) user_data,
|
||||
object_path,
|
||||
greeting);
|
||||
g_dbus_method_invocation_return_value (invocation,
|
||||
g_variant_new ("(s)", response));
|
||||
g_free (response);
|
||||
}
|
||||
else if (g_strcmp0 (method_name, "DoStuff") == 0)
|
||||
{
|
||||
g_dbus_method_invocation_return_dbus_error (invocation,
|
||||
"org.gtk.GDBus.TestSubtree.Error.Failed",
|
||||
"This method intentionally always fails");
|
||||
}
|
||||
else
|
||||
{
|
||||
g_assert_not_reached ();
|
||||
}
|
||||
}
|
||||
|
||||
static GVariant *
|
||||
block_get_property (GDBusConnection *connection,
|
||||
const gchar *sender,
|
||||
const gchar *object_path,
|
||||
const gchar *interface_name,
|
||||
const gchar *property_name,
|
||||
GError **error,
|
||||
gpointer user_data)
|
||||
{
|
||||
GVariant *ret;
|
||||
const gchar *node;
|
||||
gint major;
|
||||
gint minor;
|
||||
|
||||
node = strrchr (object_path, '/') + 1;
|
||||
if (g_str_has_prefix (node, "sda"))
|
||||
major = 8;
|
||||
else
|
||||
major = 9;
|
||||
if (strlen (node) == 4)
|
||||
minor = node[3] - '0';
|
||||
else
|
||||
minor = 0;
|
||||
|
||||
ret = NULL;
|
||||
if (g_strcmp0 (property_name, "Major") == 0)
|
||||
{
|
||||
ret = g_variant_new_int32 (major);
|
||||
}
|
||||
else if (g_strcmp0 (property_name, "Minor") == 0)
|
||||
{
|
||||
ret = g_variant_new_int32 (minor);
|
||||
}
|
||||
else if (g_strcmp0 (property_name, "Notes") == 0)
|
||||
{
|
||||
g_set_error (error,
|
||||
G_IO_ERROR,
|
||||
G_IO_ERROR_FAILED,
|
||||
"Hello %s. I thought I said reading this property "
|
||||
"always results in an error. kthxbye",
|
||||
sender);
|
||||
}
|
||||
else
|
||||
{
|
||||
g_assert_not_reached ();
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
block_set_property (GDBusConnection *connection,
|
||||
const gchar *sender,
|
||||
const gchar *object_path,
|
||||
const gchar *interface_name,
|
||||
const gchar *property_name,
|
||||
GVariant *value,
|
||||
GError **error,
|
||||
gpointer user_data)
|
||||
{
|
||||
/* TODO */
|
||||
g_assert_not_reached ();
|
||||
}
|
||||
|
||||
const GDBusInterfaceVTable block_vtable =
|
||||
{
|
||||
block_method_call,
|
||||
block_get_property,
|
||||
block_set_property,
|
||||
};
|
||||
|
||||
/* ---------------------------------------------------------------------------------------------------- */
|
||||
|
||||
static void
|
||||
partition_method_call (GDBusConnection *connection,
|
||||
const gchar *sender,
|
||||
const gchar *object_path,
|
||||
const gchar *interface_name,
|
||||
const gchar *method_name,
|
||||
GVariant *parameters,
|
||||
GDBusMethodInvocation *invocation,
|
||||
gpointer user_data)
|
||||
{
|
||||
const gchar *greeting;
|
||||
gchar *response;
|
||||
|
||||
g_assert_cmpstr (interface_name, ==, "org.gtk.GDBus.Example.Partition");
|
||||
g_assert_cmpstr (method_name, ==, "Hello");
|
||||
|
||||
g_variant_get (parameters, "(s)", &greeting);
|
||||
|
||||
response = g_strdup_printf ("Method %s.%s with user_data `%s' on object path %s called with arg '%s'",
|
||||
interface_name,
|
||||
method_name,
|
||||
(const gchar *) user_data,
|
||||
object_path,
|
||||
greeting);
|
||||
g_dbus_method_invocation_return_value (invocation,
|
||||
g_variant_new ("(s)", response));
|
||||
g_free (response);
|
||||
}
|
||||
|
||||
const GDBusInterfaceVTable partition_vtable =
|
||||
{
|
||||
partition_method_call,
|
||||
//partition_get_property,
|
||||
//partition_set_property
|
||||
};
|
||||
|
||||
/* ---------------------------------------------------------------------------------------------------- */
|
||||
|
||||
static gchar **
|
||||
subtree_enumerate (GDBusConnection *connection,
|
||||
const gchar *sender,
|
||||
const gchar *object_path,
|
||||
gpointer user_data)
|
||||
{
|
||||
gchar **nodes;
|
||||
GPtrArray *p;
|
||||
|
||||
p = g_ptr_array_new ();
|
||||
g_ptr_array_add (p, g_strdup ("sda"));
|
||||
g_ptr_array_add (p, g_strdup ("sda1"));
|
||||
g_ptr_array_add (p, g_strdup ("sda2"));
|
||||
g_ptr_array_add (p, g_strdup ("sda3"));
|
||||
g_ptr_array_add (p, g_strdup ("sdb"));
|
||||
g_ptr_array_add (p, g_strdup ("sdb1"));
|
||||
g_ptr_array_add (p, g_strdup ("sdc"));
|
||||
g_ptr_array_add (p, g_strdup ("sdc1"));
|
||||
g_ptr_array_add (p, NULL);
|
||||
nodes = (gchar **) g_ptr_array_free (p, FALSE);
|
||||
|
||||
return nodes;
|
||||
}
|
||||
|
||||
static GPtrArray *
|
||||
subtree_introspect (GDBusConnection *connection,
|
||||
const gchar *sender,
|
||||
const gchar *object_path,
|
||||
const gchar *node,
|
||||
gpointer user_data)
|
||||
{
|
||||
GPtrArray *p;
|
||||
|
||||
p = g_ptr_array_new ();
|
||||
if (g_strcmp0 (node, "/") == 0)
|
||||
{
|
||||
g_ptr_array_add (p, (gpointer) manager_interface_info);
|
||||
}
|
||||
else
|
||||
{
|
||||
g_ptr_array_add (p, (gpointer) block_interface_info);
|
||||
if (strlen (node) == 4)
|
||||
g_ptr_array_add (p, (gpointer) partition_interface_info);
|
||||
}
|
||||
|
||||
return p;
|
||||
}
|
||||
|
||||
static const GDBusInterfaceVTable *
|
||||
subtree_dispatch (GDBusConnection *connection,
|
||||
const gchar *sender,
|
||||
const gchar *object_path,
|
||||
const gchar *interface_name,
|
||||
const gchar *node,
|
||||
gpointer *out_user_data,
|
||||
gpointer user_data)
|
||||
{
|
||||
const GDBusInterfaceVTable *vtable_to_return;
|
||||
gpointer user_data_to_return;
|
||||
|
||||
if (g_strcmp0 (interface_name, "org.gtk.GDBus.Example.Manager") == 0)
|
||||
{
|
||||
user_data_to_return = "The Root";
|
||||
vtable_to_return = &manager_vtable;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (strlen (node) == 4)
|
||||
user_data_to_return = "A partition";
|
||||
else
|
||||
user_data_to_return = "A block device";
|
||||
|
||||
if (g_strcmp0 (interface_name, "org.gtk.GDBus.Example.Block") == 0)
|
||||
vtable_to_return = &block_vtable;
|
||||
else if (g_strcmp0 (interface_name, "org.gtk.GDBus.Example.Partition") == 0)
|
||||
vtable_to_return = &partition_vtable;
|
||||
else
|
||||
g_assert_not_reached ();
|
||||
}
|
||||
|
||||
*out_user_data = user_data_to_return;
|
||||
|
||||
return vtable_to_return;
|
||||
}
|
||||
|
||||
const GDBusSubtreeVTable subtree_vtable =
|
||||
{
|
||||
subtree_enumerate,
|
||||
subtree_introspect,
|
||||
subtree_dispatch
|
||||
};
|
||||
|
||||
/* ---------------------------------------------------------------------------------------------------- */
|
||||
|
||||
static void
|
||||
on_bus_acquired (GDBusConnection *connection,
|
||||
const gchar *name,
|
||||
gpointer user_data)
|
||||
{
|
||||
guint registration_id;
|
||||
|
||||
registration_id = g_dbus_connection_register_subtree (connection,
|
||||
"/org/gtk/GDBus/TestSubtree/Devices",
|
||||
&subtree_vtable,
|
||||
G_DBUS_SUBTREE_FLAGS_NONE,
|
||||
NULL, /* user_data */
|
||||
NULL, /* user_data_free_func */
|
||||
NULL); /* GError** */
|
||||
g_assert (registration_id > 0);
|
||||
}
|
||||
|
||||
static void
|
||||
on_name_acquired (GDBusConnection *connection,
|
||||
const gchar *name,
|
||||
gpointer user_data)
|
||||
{
|
||||
}
|
||||
|
||||
static void
|
||||
on_name_lost (GDBusConnection *connection,
|
||||
const gchar *name,
|
||||
gpointer user_data)
|
||||
{
|
||||
exit (1);
|
||||
}
|
||||
|
||||
int
|
||||
main (int argc, char *argv[])
|
||||
{
|
||||
guint owner_id;
|
||||
GMainLoop *loop;
|
||||
|
||||
g_type_init ();
|
||||
|
||||
/* We are lazy here - we don't want to manually provide
|
||||
* the introspection data structures - so we just build
|
||||
* them from XML.
|
||||
*/
|
||||
introspection_data = g_dbus_node_info_new_for_xml (introspection_xml, NULL);
|
||||
g_assert (introspection_data != NULL);
|
||||
|
||||
manager_interface_info = g_dbus_node_info_lookup_interface (introspection_data, "org.gtk.GDBus.Example.Manager");
|
||||
block_interface_info = g_dbus_node_info_lookup_interface (introspection_data, "org.gtk.GDBus.Example.Block");
|
||||
partition_interface_info = g_dbus_node_info_lookup_interface (introspection_data, "org.gtk.GDBus.Example.Partition");
|
||||
g_assert (manager_interface_info != NULL);
|
||||
g_assert (block_interface_info != NULL);
|
||||
g_assert (partition_interface_info != NULL);
|
||||
|
||||
owner_id = g_bus_own_name (G_BUS_TYPE_SESSION,
|
||||
"org.gtk.GDBus.TestSubtree",
|
||||
G_BUS_NAME_OWNER_FLAGS_NONE,
|
||||
on_bus_acquired,
|
||||
on_name_acquired,
|
||||
on_name_lost,
|
||||
NULL,
|
||||
NULL);
|
||||
|
||||
loop = g_main_loop_new (NULL, FALSE);
|
||||
g_main_loop_run (loop);
|
||||
|
||||
g_bus_unown_name (owner_id);
|
||||
|
||||
g_dbus_node_info_unref (introspection_data);
|
||||
|
||||
return 0;
|
||||
}
|
133
gio/tests/gdbus-example-unix-fd-client.c
Normal file
133
gio/tests/gdbus-example-unix-fd-client.c
Normal file
@ -0,0 +1,133 @@
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#include <sys/types.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include <time.h>
|
||||
|
||||
#include <gio/gio.h>
|
||||
#include <gio/gunixfdlist.h>
|
||||
|
||||
/* see gdbus-example-server.c for the server implementation */
|
||||
static gint
|
||||
get_server_stdout (GDBusConnection *connection,
|
||||
const gchar *name_owner,
|
||||
GError **error)
|
||||
{
|
||||
GDBusMessage *method_call_message;
|
||||
GDBusMessage *method_reply_message;
|
||||
GUnixFDList *fd_list;
|
||||
gint fd;
|
||||
|
||||
fd = -1;
|
||||
method_call_message = NULL;
|
||||
method_reply_message = NULL;
|
||||
|
||||
method_call_message = g_dbus_message_new_method_call (name_owner,
|
||||
"/org/gtk/GDBus/TestObject",
|
||||
"org.gtk.GDBus.TestInterface",
|
||||
"GimmeStdout");
|
||||
method_reply_message = g_dbus_connection_send_message_with_reply_sync (connection,
|
||||
method_call_message,
|
||||
-1,
|
||||
NULL, /* out_serial */
|
||||
NULL, /* cancellable */
|
||||
error);
|
||||
if (method_reply_message == NULL)
|
||||
goto out;
|
||||
|
||||
if (g_dbus_message_get_message_type (method_reply_message) == G_DBUS_MESSAGE_TYPE_ERROR)
|
||||
{
|
||||
g_dbus_message_to_gerror (method_reply_message, error);
|
||||
goto out;
|
||||
}
|
||||
|
||||
fd_list = g_dbus_message_get_unix_fd_list (method_reply_message);
|
||||
fd = g_unix_fd_list_get (fd_list, 0, error);
|
||||
|
||||
out:
|
||||
g_object_unref (method_call_message);
|
||||
g_object_unref (method_reply_message);
|
||||
|
||||
return fd;
|
||||
}
|
||||
|
||||
static void
|
||||
on_name_appeared (GDBusConnection *connection,
|
||||
const gchar *name,
|
||||
const gchar *name_owner,
|
||||
gpointer user_data)
|
||||
{
|
||||
gint fd;
|
||||
GError *error;
|
||||
|
||||
error = NULL;
|
||||
fd = get_server_stdout (connection, name_owner, &error);
|
||||
if (fd == -1)
|
||||
{
|
||||
g_printerr ("Error invoking GimmeStdout(): %s\n",
|
||||
error->message);
|
||||
g_error_free (error);
|
||||
exit (1);
|
||||
}
|
||||
else
|
||||
{
|
||||
gchar now_buf[256];
|
||||
time_t now;
|
||||
gssize len;
|
||||
gchar *str;
|
||||
|
||||
now = time (NULL);
|
||||
strftime (now_buf,
|
||||
sizeof now_buf,
|
||||
"%c",
|
||||
localtime (&now));
|
||||
|
||||
str = g_strdup_printf ("On %s, gdbus-example-unix-fd-client with pid %d was here!\n",
|
||||
now_buf,
|
||||
(gint) getpid ());
|
||||
len = strlen (str);
|
||||
g_warn_if_fail (write (fd, str, len) == len);
|
||||
close (fd);
|
||||
|
||||
g_print ("Wrote the following on server's stdout:\n%s", str);
|
||||
|
||||
g_free (str);
|
||||
exit (0);
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
on_name_vanished (GDBusConnection *connection,
|
||||
const gchar *name,
|
||||
gpointer user_data)
|
||||
{
|
||||
g_printerr ("Failed to get name owner for %s\n"
|
||||
"Is ./gdbus-example-server running?\n",
|
||||
name);
|
||||
exit (1);
|
||||
}
|
||||
|
||||
int
|
||||
main (int argc, char *argv[])
|
||||
{
|
||||
guint watcher_id;
|
||||
GMainLoop *loop;
|
||||
|
||||
g_type_init ();
|
||||
|
||||
watcher_id = g_bus_watch_name (G_BUS_TYPE_SESSION,
|
||||
"org.gtk.GDBus.TestServer",
|
||||
G_BUS_NAME_WATCHER_FLAGS_NONE,
|
||||
on_name_appeared,
|
||||
on_name_vanished,
|
||||
NULL,
|
||||
NULL);
|
||||
|
||||
loop = g_main_loop_new (NULL, FALSE);
|
||||
g_main_loop_run (loop);
|
||||
|
||||
g_bus_unwatch_name (watcher_id);
|
||||
return 0;
|
||||
}
|
88
gio/tests/gdbus-example-watch-name.c
Normal file
88
gio/tests/gdbus-example-watch-name.c
Normal file
@ -0,0 +1,88 @@
|
||||
#include <gio/gio.h>
|
||||
|
||||
static gchar *opt_name = NULL;
|
||||
static gboolean opt_system_bus = FALSE;
|
||||
static gboolean opt_auto_start = FALSE;
|
||||
|
||||
static GOptionEntry opt_entries[] =
|
||||
{
|
||||
{ "name", 'n', 0, G_OPTION_ARG_STRING, &opt_name, "Name to watch", NULL },
|
||||
{ "system-bus", 's', 0, G_OPTION_ARG_NONE, &opt_system_bus, "Use the system-bus instead of the session-bus", NULL },
|
||||
{ "auto-start", 'a', 0, G_OPTION_ARG_NONE, &opt_auto_start, "Instruct the bus to launch an owner for the name", NULL},
|
||||
{ NULL}
|
||||
};
|
||||
|
||||
static void
|
||||
on_name_appeared (GDBusConnection *connection,
|
||||
const gchar *name,
|
||||
const gchar *name_owner,
|
||||
gpointer user_data)
|
||||
{
|
||||
g_print ("Name %s on %s is owned by %s\n",
|
||||
name,
|
||||
opt_system_bus ? "the system bus" : "the session bus",
|
||||
name_owner);
|
||||
}
|
||||
|
||||
static void
|
||||
on_name_vanished (GDBusConnection *connection,
|
||||
const gchar *name,
|
||||
gpointer user_data)
|
||||
{
|
||||
g_print ("Name %s does not exist on %s\n",
|
||||
name,
|
||||
opt_system_bus ? "the system bus" : "the session bus");
|
||||
}
|
||||
|
||||
int
|
||||
main (int argc, char *argv[])
|
||||
{
|
||||
guint watcher_id;
|
||||
GMainLoop *loop;
|
||||
GOptionContext *opt_context;
|
||||
GError *error;
|
||||
GBusNameWatcherFlags flags;
|
||||
|
||||
g_type_init ();
|
||||
|
||||
error = NULL;
|
||||
opt_context = g_option_context_new ("g_bus_watch_name() example");
|
||||
g_option_context_set_summary (opt_context,
|
||||
"Example: to watch the power manager on the session bus, use:\n"
|
||||
"\n"
|
||||
" ./example-watch-name -n org.gnome.PowerManager");
|
||||
g_option_context_add_main_entries (opt_context, opt_entries, NULL);
|
||||
if (!g_option_context_parse (opt_context, &argc, &argv, &error))
|
||||
{
|
||||
g_printerr ("Error parsing options: %s", error->message);
|
||||
goto out;
|
||||
}
|
||||
if (opt_name == NULL)
|
||||
{
|
||||
g_printerr ("Incorrect usage, try --help.\n");
|
||||
goto out;
|
||||
}
|
||||
|
||||
flags = G_BUS_NAME_WATCHER_FLAGS_NONE;
|
||||
if (opt_auto_start)
|
||||
flags |= G_BUS_NAME_WATCHER_FLAGS_AUTO_START;
|
||||
|
||||
watcher_id = g_bus_watch_name (opt_system_bus ? G_BUS_TYPE_SYSTEM : G_BUS_TYPE_SESSION,
|
||||
opt_name,
|
||||
flags,
|
||||
on_name_appeared,
|
||||
on_name_vanished,
|
||||
NULL,
|
||||
NULL);
|
||||
|
||||
loop = g_main_loop_new (NULL, FALSE);
|
||||
g_main_loop_run (loop);
|
||||
|
||||
g_bus_unwatch_name (watcher_id);
|
||||
|
||||
out:
|
||||
g_option_context_free (opt_context);
|
||||
g_free (opt_name);
|
||||
|
||||
return 0;
|
||||
}
|
217
gio/tests/gdbus-example-watch-proxy.c
Normal file
217
gio/tests/gdbus-example-watch-proxy.c
Normal file
@ -0,0 +1,217 @@
|
||||
#include <gio/gio.h>
|
||||
|
||||
static gchar *opt_name = NULL;
|
||||
static gchar *opt_object_path = NULL;
|
||||
static gchar *opt_interface = NULL;
|
||||
static gboolean opt_system_bus = FALSE;
|
||||
static gboolean opt_auto_start = FALSE;
|
||||
static gboolean opt_no_properties = FALSE;
|
||||
|
||||
static GOptionEntry opt_entries[] =
|
||||
{
|
||||
{ "name", 'n', 0, G_OPTION_ARG_STRING, &opt_name, "Name of the remote object to watch", NULL },
|
||||
{ "object-path", 'o', 0, G_OPTION_ARG_STRING, &opt_object_path, "Object path of the remote object", NULL },
|
||||
{ "interface", 'i', 0, G_OPTION_ARG_STRING, &opt_interface, "D-Bus interface of remote object", NULL },
|
||||
{ "system-bus", 's', 0, G_OPTION_ARG_NONE, &opt_system_bus, "Use the system-bus instead of the session-bus", NULL },
|
||||
{ "auto-start", 'a', 0, G_OPTION_ARG_NONE, &opt_auto_start, "Instruct the bus to launch an owner for the name", NULL},
|
||||
{ "no-properties", 'p', 0, G_OPTION_ARG_NONE, &opt_no_properties, "Do not load properties", NULL},
|
||||
{ NULL}
|
||||
};
|
||||
|
||||
static void
|
||||
print_properties (GDBusProxy *proxy)
|
||||
{
|
||||
gchar **property_names;
|
||||
guint n;
|
||||
|
||||
g_print (" properties:\n");
|
||||
|
||||
property_names = g_dbus_proxy_get_cached_property_names (proxy);
|
||||
for (n = 0; property_names != NULL && property_names[n] != NULL; n++)
|
||||
{
|
||||
const gchar *key = property_names[n];
|
||||
GVariant *value;
|
||||
gchar *value_str;
|
||||
value = g_dbus_proxy_get_cached_property (proxy, key);
|
||||
value_str = g_variant_print (value, TRUE);
|
||||
g_print (" %s -> %s\n", key, value_str);
|
||||
g_variant_unref (value);
|
||||
g_free (value_str);
|
||||
}
|
||||
g_strfreev (property_names);
|
||||
}
|
||||
|
||||
static void
|
||||
on_properties_changed (GDBusProxy *proxy,
|
||||
GVariant *changed_properties,
|
||||
const gchar* const *invalidated_properties,
|
||||
gpointer user_data)
|
||||
{
|
||||
/* Note that we are guaranteed that changed_properties and
|
||||
* invalidated_properties are never NULL
|
||||
*/
|
||||
|
||||
if (g_variant_n_children (changed_properties) > 0)
|
||||
{
|
||||
GVariantIter *iter;
|
||||
GVariant *item;
|
||||
|
||||
g_print (" *** Properties Changed:\n");
|
||||
g_variant_get (changed_properties,
|
||||
"a{sv}",
|
||||
&iter);
|
||||
while ((item = g_variant_iter_next_value (iter)))
|
||||
{
|
||||
const gchar *key;
|
||||
GVariant *value;
|
||||
gchar *value_str;
|
||||
g_variant_get (item,
|
||||
"{sv}",
|
||||
&key,
|
||||
&value);
|
||||
value_str = g_variant_print (value, TRUE);
|
||||
g_print (" %s -> %s\n", key, value_str);
|
||||
g_free (value_str);
|
||||
}
|
||||
}
|
||||
|
||||
if (g_strv_length ((GStrv) invalidated_properties) > 0)
|
||||
{
|
||||
guint n;
|
||||
g_print (" *** Properties Invalidated:\n");
|
||||
for (n = 0; invalidated_properties[n] != NULL; n++)
|
||||
{
|
||||
const gchar *key = invalidated_properties[n];
|
||||
g_print (" %s\n", key);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
on_signal (GDBusProxy *proxy,
|
||||
gchar *sender_name,
|
||||
gchar *signal_name,
|
||||
GVariant *parameters,
|
||||
gpointer user_data)
|
||||
{
|
||||
gchar *parameters_str;
|
||||
|
||||
parameters_str = g_variant_print (parameters, TRUE);
|
||||
g_print (" *** Received Signal: %s: %s\n",
|
||||
signal_name,
|
||||
parameters_str);
|
||||
g_free (parameters_str);
|
||||
}
|
||||
|
||||
static void
|
||||
on_proxy_appeared (GDBusConnection *connection,
|
||||
const gchar *name,
|
||||
const gchar *name_owner,
|
||||
GDBusProxy *proxy,
|
||||
gpointer user_data)
|
||||
{
|
||||
g_print ("+++ Acquired proxy object for remote object owned by %s\n"
|
||||
" bus: %s\n"
|
||||
" name: %s\n"
|
||||
" object path: %s\n"
|
||||
" interface: %s\n",
|
||||
name_owner,
|
||||
opt_system_bus ? "System Bus" : "Session Bus",
|
||||
opt_name,
|
||||
opt_object_path,
|
||||
opt_interface);
|
||||
|
||||
print_properties (proxy);
|
||||
|
||||
g_signal_connect (proxy,
|
||||
"g-properties-changed",
|
||||
G_CALLBACK (on_properties_changed),
|
||||
NULL);
|
||||
|
||||
g_signal_connect (proxy,
|
||||
"g-signal",
|
||||
G_CALLBACK (on_signal),
|
||||
NULL);
|
||||
}
|
||||
|
||||
static void
|
||||
on_proxy_vanished (GDBusConnection *connection,
|
||||
const gchar *name,
|
||||
gpointer user_data)
|
||||
{
|
||||
g_print ("--- Cannot create proxy object for\n"
|
||||
" bus: %s\n"
|
||||
" name: %s\n"
|
||||
" object path: %s\n"
|
||||
" interface: %s\n",
|
||||
opt_system_bus ? "System Bus" : "Session Bus",
|
||||
opt_name,
|
||||
opt_object_path,
|
||||
opt_interface);
|
||||
}
|
||||
|
||||
int
|
||||
main (int argc, char *argv[])
|
||||
{
|
||||
guint watcher_id;
|
||||
GMainLoop *loop;
|
||||
GOptionContext *opt_context;
|
||||
GError *error;
|
||||
GBusNameWatcherFlags flags;
|
||||
GDBusProxyFlags proxy_flags;
|
||||
|
||||
g_type_init ();
|
||||
|
||||
opt_context = g_option_context_new ("g_bus_watch_proxy() example");
|
||||
g_option_context_set_summary (opt_context,
|
||||
"Example: to watch the object of gdbus-example-server, use:\n"
|
||||
"\n"
|
||||
" ./gdbus-example-watch-proxy -n org.gtk.GDBus.TestServer \\\n"
|
||||
" -o /org/gtk/GDBus/TestObject \\\n"
|
||||
" -i org.gtk.GDBus.TestInterface");
|
||||
g_option_context_add_main_entries (opt_context, opt_entries, NULL);
|
||||
error = NULL;
|
||||
if (!g_option_context_parse (opt_context, &argc, &argv, &error))
|
||||
{
|
||||
g_printerr ("Error parsing options: %s", error->message);
|
||||
goto out;
|
||||
}
|
||||
if (opt_name == NULL || opt_object_path == NULL || opt_interface == NULL)
|
||||
{
|
||||
g_printerr ("Incorrect usage, try --help.\n");
|
||||
goto out;
|
||||
}
|
||||
|
||||
flags = G_BUS_NAME_WATCHER_FLAGS_NONE;
|
||||
if (opt_auto_start)
|
||||
flags |= G_BUS_NAME_WATCHER_FLAGS_AUTO_START;
|
||||
|
||||
proxy_flags = G_DBUS_PROXY_FLAGS_NONE;
|
||||
if (opt_no_properties)
|
||||
proxy_flags |= G_DBUS_PROXY_FLAGS_DO_NOT_LOAD_PROPERTIES;
|
||||
|
||||
watcher_id = g_bus_watch_proxy (opt_system_bus ? G_BUS_TYPE_SYSTEM : G_BUS_TYPE_SESSION,
|
||||
opt_name,
|
||||
flags,
|
||||
opt_object_path,
|
||||
opt_interface,
|
||||
G_TYPE_DBUS_PROXY,
|
||||
proxy_flags,
|
||||
on_proxy_appeared,
|
||||
on_proxy_vanished,
|
||||
NULL,
|
||||
NULL);
|
||||
|
||||
loop = g_main_loop_new (NULL, FALSE);
|
||||
g_main_loop_run (loop);
|
||||
|
||||
g_bus_unwatch_proxy (watcher_id);
|
||||
|
||||
out:
|
||||
g_option_context_free (opt_context);
|
||||
g_free (opt_name);
|
||||
g_free (opt_object_path);
|
||||
g_free (opt_interface);
|
||||
|
||||
return 0;
|
||||
}
|
82
gio/tests/gdbus-exit-on-close.c
Normal file
82
gio/tests/gdbus-exit-on-close.c
Normal file
@ -0,0 +1,82 @@
|
||||
/* GLib testing framework examples and tests
|
||||
*
|
||||
* Copyright (C) 2008-2010 Red Hat, Inc.
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General
|
||||
* Public License along with this library; if not, write to the
|
||||
* Free Software Foundation, Inc., 59 Temple Place, Suite 330,
|
||||
* Boston, MA 02111-1307, USA.
|
||||
*
|
||||
* Author: David Zeuthen <davidz@redhat.com>
|
||||
*/
|
||||
|
||||
#include <gio/gio.h>
|
||||
#include <unistd.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "gdbus-tests.h"
|
||||
|
||||
/* all tests rely on a shared mainloop */
|
||||
static GMainLoop *loop = NULL;
|
||||
|
||||
/* ---------------------------------------------------------------------------------------------------- */
|
||||
|
||||
static gboolean
|
||||
nuke_session_bus_cb (gpointer data)
|
||||
{
|
||||
g_main_loop_quit (loop);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
static void
|
||||
test_exit_on_close (void)
|
||||
{
|
||||
if (g_test_trap_fork (0, G_TEST_TRAP_SILENCE_STDOUT | G_TEST_TRAP_SILENCE_STDERR))
|
||||
{
|
||||
GDBusConnection *c;
|
||||
session_bus_up ();
|
||||
c = g_bus_get_sync (G_BUS_TYPE_SESSION, NULL, NULL);
|
||||
g_assert (c != NULL);
|
||||
g_assert (!g_dbus_connection_is_closed (c));
|
||||
g_timeout_add (50,
|
||||
nuke_session_bus_cb,
|
||||
NULL);
|
||||
g_main_loop_run (loop);
|
||||
session_bus_down ();
|
||||
g_main_loop_run (loop);
|
||||
}
|
||||
g_test_trap_assert_stdout ("*Remote peer vanished. Exiting.*");
|
||||
g_test_trap_assert_failed();
|
||||
}
|
||||
|
||||
/* ---------------------------------------------------------------------------------------------------- */
|
||||
|
||||
int
|
||||
main (int argc,
|
||||
char *argv[])
|
||||
{
|
||||
g_type_init ();
|
||||
g_test_init (&argc, &argv, NULL);
|
||||
|
||||
/* all the tests rely on a shared main loop */
|
||||
loop = g_main_loop_new (NULL, FALSE);
|
||||
|
||||
/* all the tests use a session bus with a well-known address that we can bring up and down
|
||||
* using session_bus_up() and session_bus_down().
|
||||
*/
|
||||
g_unsetenv ("DISPLAY");
|
||||
g_setenv ("DBUS_SESSION_BUS_ADDRESS", session_bus_get_temporary_address (), TRUE);
|
||||
|
||||
g_test_add_func ("/gdbus/exit-on-close", test_exit_on_close);
|
||||
return g_test_run();
|
||||
}
|
1398
gio/tests/gdbus-export.c
Normal file
1398
gio/tests/gdbus-export.c
Normal file
File diff suppressed because it is too large
Load Diff
169
gio/tests/gdbus-introspection.c
Normal file
169
gio/tests/gdbus-introspection.c
Normal file
@ -0,0 +1,169 @@
|
||||
/* GLib testing framework examples and tests
|
||||
*
|
||||
* Copyright (C) 2008-2010 Red Hat, Inc.
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General
|
||||
* Public License along with this library; if not, write to the
|
||||
* Free Software Foundation, Inc., 59 Temple Place, Suite 330,
|
||||
* Boston, MA 02111-1307, USA.
|
||||
*
|
||||
* Author: David Zeuthen <davidz@redhat.com>
|
||||
*/
|
||||
|
||||
#include <gio/gio.h>
|
||||
#include <unistd.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "gdbus-tests.h"
|
||||
|
||||
/* all tests rely on a shared mainloop */
|
||||
static GMainLoop *loop = NULL;
|
||||
|
||||
/* ---------------------------------------------------------------------------------------------------- */
|
||||
/* Test introspection parser */
|
||||
/* ---------------------------------------------------------------------------------------------------- */
|
||||
|
||||
static void
|
||||
introspection_on_proxy_appeared (GDBusConnection *connection,
|
||||
const gchar *name,
|
||||
const gchar *name_owner,
|
||||
GDBusProxy *proxy,
|
||||
gpointer user_data)
|
||||
{
|
||||
GError *error;
|
||||
const gchar *xml_data;
|
||||
GDBusNodeInfo *node_info;
|
||||
const GDBusInterfaceInfo *interface_info;
|
||||
const GDBusMethodInfo *method_info;
|
||||
const GDBusSignalInfo *signal_info;
|
||||
GVariant *result;
|
||||
|
||||
error = NULL;
|
||||
|
||||
/*
|
||||
* Invoke Introspect(), then parse the output.
|
||||
*/
|
||||
result = g_dbus_proxy_call_sync (proxy,
|
||||
"org.freedesktop.DBus.Introspectable.Introspect",
|
||||
NULL,
|
||||
G_DBUS_CALL_FLAGS_NONE,
|
||||
-1,
|
||||
NULL,
|
||||
&error);
|
||||
g_assert_no_error (error);
|
||||
g_assert (result != NULL);
|
||||
g_variant_get (result, "(s)", &xml_data);
|
||||
|
||||
node_info = g_dbus_node_info_new_for_xml (xml_data, &error);
|
||||
g_assert_no_error (error);
|
||||
g_assert (node_info != NULL);
|
||||
|
||||
/* for now we only check a couple of things. TODO: check more things */
|
||||
|
||||
interface_info = g_dbus_node_info_lookup_interface (node_info, "com.example.NonExistantInterface");
|
||||
g_assert (interface_info == NULL);
|
||||
|
||||
interface_info = g_dbus_node_info_lookup_interface (node_info, "org.freedesktop.DBus.Introspectable");
|
||||
g_assert (interface_info != NULL);
|
||||
method_info = g_dbus_interface_info_lookup_method (interface_info, "NonExistantMethod");
|
||||
g_assert (method_info == NULL);
|
||||
method_info = g_dbus_interface_info_lookup_method (interface_info, "Introspect");
|
||||
g_assert (method_info != NULL);
|
||||
g_assert (method_info->in_args == NULL);
|
||||
g_assert (method_info->out_args != NULL);
|
||||
g_assert (method_info->out_args[0] != NULL);
|
||||
g_assert (method_info->out_args[1] == NULL);
|
||||
g_assert_cmpstr (method_info->out_args[0]->signature, ==, "s");
|
||||
|
||||
interface_info = g_dbus_node_info_lookup_interface (node_info, "com.example.Frob");
|
||||
g_assert (interface_info != NULL);
|
||||
signal_info = g_dbus_interface_info_lookup_signal (interface_info, "TestSignal");
|
||||
g_assert (signal_info != NULL);
|
||||
g_assert (signal_info->args != NULL);
|
||||
g_assert (signal_info->args[0] != NULL);
|
||||
g_assert_cmpstr (signal_info->args[0]->signature, ==, "s");
|
||||
g_assert (signal_info->args[1] != NULL);
|
||||
g_assert_cmpstr (signal_info->args[1]->signature, ==, "o");
|
||||
g_assert (signal_info->args[2] != NULL);
|
||||
g_assert_cmpstr (signal_info->args[2]->signature, ==, "v");
|
||||
g_assert (signal_info->args[3] == NULL);
|
||||
|
||||
g_dbus_node_info_unref (node_info);
|
||||
g_variant_unref (result);
|
||||
|
||||
g_main_loop_quit (loop);
|
||||
}
|
||||
|
||||
static void
|
||||
introspection_on_proxy_vanished (GDBusConnection *connection,
|
||||
const gchar *name,
|
||||
gpointer user_data)
|
||||
{
|
||||
}
|
||||
|
||||
static void
|
||||
test_introspection_parser (void)
|
||||
{
|
||||
guint watcher_id;
|
||||
|
||||
session_bus_up ();
|
||||
|
||||
watcher_id = g_bus_watch_proxy (G_BUS_TYPE_SESSION,
|
||||
"com.example.TestService",
|
||||
G_BUS_NAME_WATCHER_FLAGS_NONE,
|
||||
"/com/example/TestObject",
|
||||
"com.example.Frob",
|
||||
G_TYPE_DBUS_PROXY,
|
||||
G_DBUS_PROXY_FLAGS_NONE,
|
||||
introspection_on_proxy_appeared,
|
||||
introspection_on_proxy_vanished,
|
||||
NULL,
|
||||
NULL);
|
||||
|
||||
/* TODO: wait a bit for the bus to come up.. ideally session_bus_up() won't return
|
||||
* until one can connect to the bus but that's not how things work right now
|
||||
*/
|
||||
usleep (500 * 1000);
|
||||
/* this is safe; testserver will exit once the bus goes away */
|
||||
g_assert (g_spawn_command_line_async ("./gdbus-testserver.py", NULL));
|
||||
|
||||
g_main_loop_run (loop);
|
||||
|
||||
g_bus_unwatch_proxy (watcher_id);
|
||||
|
||||
/* tear down bus */
|
||||
session_bus_down ();
|
||||
}
|
||||
|
||||
|
||||
/* ---------------------------------------------------------------------------------------------------- */
|
||||
|
||||
int
|
||||
main (int argc,
|
||||
char *argv[])
|
||||
{
|
||||
g_type_init ();
|
||||
g_test_init (&argc, &argv, NULL);
|
||||
|
||||
/* all the tests rely on a shared main loop */
|
||||
loop = g_main_loop_new (NULL, FALSE);
|
||||
|
||||
/* all the tests use a session bus with a well-known address that we can bring up and down
|
||||
* using session_bus_up() and session_bus_down().
|
||||
*/
|
||||
g_unsetenv ("DISPLAY");
|
||||
g_setenv ("DBUS_SESSION_BUS_ADDRESS", session_bus_get_temporary_address (), TRUE);
|
||||
|
||||
g_test_add_func ("/gdbus/introspection-parser", test_introspection_parser);
|
||||
return g_test_run();
|
||||
}
|
749
gio/tests/gdbus-names.c
Normal file
749
gio/tests/gdbus-names.c
Normal file
@ -0,0 +1,749 @@
|
||||
/* GLib testing framework examples and tests
|
||||
*
|
||||
* Copyright (C) 2008-2010 Red Hat, Inc.
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General
|
||||
* Public License along with this library; if not, write to the
|
||||
* Free Software Foundation, Inc., 59 Temple Place, Suite 330,
|
||||
* Boston, MA 02111-1307, USA.
|
||||
*
|
||||
* Author: David Zeuthen <davidz@redhat.com>
|
||||
*/
|
||||
|
||||
#include <gio/gio.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include "gdbus-tests.h"
|
||||
|
||||
/* all tests rely on a shared mainloop */
|
||||
static GMainLoop *loop;
|
||||
|
||||
/* ---------------------------------------------------------------------------------------------------- */
|
||||
/* Test that g_bus_own_name() works correctly */
|
||||
/* ---------------------------------------------------------------------------------------------------- */
|
||||
|
||||
typedef struct
|
||||
{
|
||||
GMainLoop *loop;
|
||||
gboolean expect_null_connection;
|
||||
guint num_bus_acquired;
|
||||
guint num_acquired;
|
||||
guint num_lost;
|
||||
guint num_free_func;
|
||||
} OwnNameData;
|
||||
|
||||
static void
|
||||
own_name_data_free_func (OwnNameData *data)
|
||||
{
|
||||
data->num_free_func++;
|
||||
g_main_loop_quit (loop);
|
||||
}
|
||||
|
||||
static void
|
||||
bus_acquired_handler (GDBusConnection *connection,
|
||||
const gchar *name,
|
||||
gpointer user_data)
|
||||
{
|
||||
OwnNameData *data = user_data;
|
||||
g_dbus_connection_set_exit_on_close (connection, FALSE);
|
||||
data->num_bus_acquired += 1;
|
||||
g_main_loop_quit (loop);
|
||||
}
|
||||
|
||||
static void
|
||||
name_acquired_handler (GDBusConnection *connection,
|
||||
const gchar *name,
|
||||
gpointer user_data)
|
||||
{
|
||||
OwnNameData *data = user_data;
|
||||
data->num_acquired += 1;
|
||||
g_main_loop_quit (loop);
|
||||
}
|
||||
|
||||
static void
|
||||
name_lost_handler (GDBusConnection *connection,
|
||||
const gchar *name,
|
||||
gpointer user_data)
|
||||
{
|
||||
OwnNameData *data = user_data;
|
||||
if (data->expect_null_connection)
|
||||
{
|
||||
g_assert (connection == NULL);
|
||||
}
|
||||
else
|
||||
{
|
||||
g_assert (connection != NULL);
|
||||
g_dbus_connection_set_exit_on_close (connection, FALSE);
|
||||
}
|
||||
data->num_lost += 1;
|
||||
g_main_loop_quit (loop);
|
||||
}
|
||||
|
||||
static void
|
||||
test_bus_own_name (void)
|
||||
{
|
||||
guint id;
|
||||
guint id2;
|
||||
OwnNameData data;
|
||||
OwnNameData data2;
|
||||
const gchar *name;
|
||||
GDBusConnection *c;
|
||||
GError *error;
|
||||
gboolean name_has_owner_reply;
|
||||
GDBusConnection *c2;
|
||||
GVariant *result;
|
||||
|
||||
error = NULL;
|
||||
name = "org.gtk.GDBus.Name1";
|
||||
|
||||
/*
|
||||
* First check that name_lost_handler() is invoked if there is no bus.
|
||||
*
|
||||
* Also make sure name_lost_handler() isn't invoked when unowning the name.
|
||||
*/
|
||||
data.num_bus_acquired = 0;
|
||||
data.num_free_func = 0;
|
||||
data.num_acquired = 0;
|
||||
data.num_lost = 0;
|
||||
data.expect_null_connection = TRUE;
|
||||
id = g_bus_own_name (G_BUS_TYPE_SESSION,
|
||||
name,
|
||||
G_BUS_NAME_OWNER_FLAGS_NONE,
|
||||
bus_acquired_handler,
|
||||
name_acquired_handler,
|
||||
name_lost_handler,
|
||||
&data,
|
||||
(GDestroyNotify) own_name_data_free_func);
|
||||
g_assert_cmpint (data.num_bus_acquired, ==, 0);
|
||||
g_assert_cmpint (data.num_acquired, ==, 0);
|
||||
g_assert_cmpint (data.num_lost, ==, 0);
|
||||
g_main_loop_run (loop);
|
||||
g_assert_cmpint (data.num_bus_acquired, ==, 0);
|
||||
g_assert_cmpint (data.num_acquired, ==, 0);
|
||||
g_assert_cmpint (data.num_lost, ==, 1);
|
||||
g_bus_unown_name (id);
|
||||
g_assert_cmpint (data.num_acquired, ==, 0);
|
||||
g_assert_cmpint (data.num_lost, ==, 1);
|
||||
g_assert_cmpint (data.num_free_func, ==, 1);
|
||||
|
||||
/*
|
||||
* Bring up a bus, then own a name and check bus_acquired_handler() then name_acquired_handler() is invoked.
|
||||
*/
|
||||
session_bus_up ();
|
||||
data.num_bus_acquired = 0;
|
||||
data.num_acquired = 0;
|
||||
data.num_lost = 0;
|
||||
data.expect_null_connection = FALSE;
|
||||
id = g_bus_own_name (G_BUS_TYPE_SESSION,
|
||||
name,
|
||||
G_BUS_NAME_OWNER_FLAGS_NONE,
|
||||
bus_acquired_handler,
|
||||
name_acquired_handler,
|
||||
name_lost_handler,
|
||||
&data,
|
||||
(GDestroyNotify) own_name_data_free_func);
|
||||
g_assert_cmpint (data.num_bus_acquired, ==, 0);
|
||||
g_assert_cmpint (data.num_acquired, ==, 0);
|
||||
g_assert_cmpint (data.num_lost, ==, 0);
|
||||
g_main_loop_run (loop);
|
||||
g_assert_cmpint (data.num_bus_acquired, ==, 1);
|
||||
g_assert_cmpint (data.num_acquired, ==, 0);
|
||||
g_assert_cmpint (data.num_lost, ==, 0);
|
||||
g_main_loop_run (loop);
|
||||
g_assert_cmpint (data.num_bus_acquired, ==, 1);
|
||||
g_assert_cmpint (data.num_acquired, ==, 1);
|
||||
g_assert_cmpint (data.num_lost, ==, 0);
|
||||
|
||||
/*
|
||||
* Check that the name was actually acquired.
|
||||
*/
|
||||
c = g_bus_get_sync (G_BUS_TYPE_SESSION, NULL, NULL);
|
||||
g_assert (c != NULL);
|
||||
g_assert (!g_dbus_connection_is_closed (c));
|
||||
result = g_dbus_connection_call_sync (c,
|
||||
"org.freedesktop.DBus", /* bus name */
|
||||
"/org/freedesktop/DBus", /* object path */
|
||||
"org.freedesktop.DBus", /* interface name */
|
||||
"NameHasOwner", /* method name */
|
||||
g_variant_new ("(s)", name),
|
||||
G_DBUS_CALL_FLAGS_NONE,
|
||||
-1,
|
||||
NULL,
|
||||
&error);
|
||||
g_assert_no_error (error);
|
||||
g_assert (result != NULL);
|
||||
g_variant_get (result, "(b)", &name_has_owner_reply);
|
||||
g_assert (name_has_owner_reply);
|
||||
g_variant_unref (result);
|
||||
|
||||
/*
|
||||
* Stop owning the name - this should invoke our free func
|
||||
*/
|
||||
g_bus_unown_name (id);
|
||||
g_assert_cmpint (data.num_free_func, ==, 2);
|
||||
|
||||
/*
|
||||
* Check that the name was actually released.
|
||||
*/
|
||||
result = g_dbus_connection_call_sync (c,
|
||||
"org.freedesktop.DBus", /* bus name */
|
||||
"/org/freedesktop/DBus", /* object path */
|
||||
"org.freedesktop.DBus", /* interface name */
|
||||
"NameHasOwner", /* method name */
|
||||
g_variant_new ("(s)", name),
|
||||
G_DBUS_CALL_FLAGS_NONE,
|
||||
-1,
|
||||
NULL,
|
||||
&error);
|
||||
g_assert_no_error (error);
|
||||
g_assert (result != NULL);
|
||||
g_variant_get (result, "(b)", &name_has_owner_reply);
|
||||
g_assert (!name_has_owner_reply);
|
||||
g_variant_unref (result);
|
||||
|
||||
/*
|
||||
* Own the name again.
|
||||
*/
|
||||
data.num_bus_acquired = 0;
|
||||
data.num_acquired = 0;
|
||||
data.num_lost = 0;
|
||||
data.expect_null_connection = FALSE;
|
||||
id = g_bus_own_name (G_BUS_TYPE_SESSION,
|
||||
name,
|
||||
G_BUS_NAME_OWNER_FLAGS_NONE,
|
||||
bus_acquired_handler,
|
||||
name_acquired_handler,
|
||||
name_lost_handler,
|
||||
&data,
|
||||
(GDestroyNotify) own_name_data_free_func);
|
||||
g_assert_cmpint (data.num_bus_acquired, ==, 0);
|
||||
g_assert_cmpint (data.num_acquired, ==, 0);
|
||||
g_assert_cmpint (data.num_lost, ==, 0);
|
||||
g_main_loop_run (loop);
|
||||
g_assert_cmpint (data.num_bus_acquired, ==, 1);
|
||||
g_assert_cmpint (data.num_acquired, ==, 0);
|
||||
g_assert_cmpint (data.num_lost, ==, 0);
|
||||
g_main_loop_run (loop);
|
||||
g_assert_cmpint (data.num_bus_acquired, ==, 1);
|
||||
g_assert_cmpint (data.num_acquired, ==, 1);
|
||||
g_assert_cmpint (data.num_lost, ==, 0);
|
||||
|
||||
/*
|
||||
* Try owning the name with another object on the same connection - this should
|
||||
* fail because we already own the name.
|
||||
*/
|
||||
data2.num_free_func = 0;
|
||||
data2.num_bus_acquired = 0;
|
||||
data2.num_acquired = 0;
|
||||
data2.num_lost = 0;
|
||||
data2.expect_null_connection = FALSE;
|
||||
id2 = g_bus_own_name (G_BUS_TYPE_SESSION,
|
||||
name,
|
||||
G_BUS_NAME_OWNER_FLAGS_NONE,
|
||||
bus_acquired_handler,
|
||||
name_acquired_handler,
|
||||
name_lost_handler,
|
||||
&data2,
|
||||
(GDestroyNotify) own_name_data_free_func);
|
||||
g_assert_cmpint (data2.num_bus_acquired, ==, 0);
|
||||
g_assert_cmpint (data2.num_acquired, ==, 0);
|
||||
g_assert_cmpint (data2.num_lost, ==, 0);
|
||||
g_main_loop_run (loop);
|
||||
g_assert_cmpint (data2.num_bus_acquired, ==, 1);
|
||||
g_assert_cmpint (data2.num_acquired, ==, 0);
|
||||
g_assert_cmpint (data2.num_lost, ==, 0);
|
||||
g_main_loop_run (loop);
|
||||
g_assert_cmpint (data2.num_bus_acquired, ==, 1);
|
||||
g_assert_cmpint (data2.num_acquired, ==, 0);
|
||||
g_assert_cmpint (data2.num_lost, ==, 1);
|
||||
g_bus_unown_name (id2);
|
||||
g_assert_cmpint (data2.num_bus_acquired, ==, 1);
|
||||
g_assert_cmpint (data2.num_acquired, ==, 0);
|
||||
g_assert_cmpint (data2.num_lost, ==, 1);
|
||||
g_assert_cmpint (data2.num_free_func, ==, 1);
|
||||
|
||||
/*
|
||||
* Create a secondary (e.g. private) connection and try owning the name on that
|
||||
* connection. This should fail both with and without _REPLACE because we
|
||||
* didn't specify ALLOW_REPLACEMENT.
|
||||
*/
|
||||
c2 = _g_bus_get_priv (G_BUS_TYPE_SESSION, NULL, NULL);
|
||||
g_assert (c2 != NULL);
|
||||
g_assert (!g_dbus_connection_is_closed (c2));
|
||||
/* first without _REPLACE */
|
||||
data2.num_bus_acquired = 0;
|
||||
data2.num_acquired = 0;
|
||||
data2.num_lost = 0;
|
||||
data2.expect_null_connection = FALSE;
|
||||
data2.num_free_func = 0;
|
||||
id2 = g_bus_own_name_on_connection (c2,
|
||||
name,
|
||||
G_BUS_NAME_OWNER_FLAGS_NONE,
|
||||
name_acquired_handler,
|
||||
name_lost_handler,
|
||||
&data2,
|
||||
(GDestroyNotify) own_name_data_free_func);
|
||||
g_assert_cmpint (data2.num_bus_acquired, ==, 0);
|
||||
g_assert_cmpint (data2.num_acquired, ==, 0);
|
||||
g_assert_cmpint (data2.num_lost, ==, 0);
|
||||
g_main_loop_run (loop);
|
||||
g_assert_cmpint (data2.num_bus_acquired, ==, 0);
|
||||
g_assert_cmpint (data2.num_acquired, ==, 0);
|
||||
g_assert_cmpint (data2.num_lost, ==, 1);
|
||||
g_bus_unown_name (id2);
|
||||
g_assert_cmpint (data2.num_bus_acquired, ==, 0);
|
||||
g_assert_cmpint (data2.num_acquired, ==, 0);
|
||||
g_assert_cmpint (data2.num_lost, ==, 1);
|
||||
g_assert_cmpint (data2.num_free_func, ==, 1);
|
||||
/* then with _REPLACE */
|
||||
data2.num_bus_acquired = 0;
|
||||
data2.num_acquired = 0;
|
||||
data2.num_lost = 0;
|
||||
data2.expect_null_connection = FALSE;
|
||||
data2.num_free_func = 0;
|
||||
id2 = g_bus_own_name_on_connection (c2,
|
||||
name,
|
||||
G_BUS_NAME_OWNER_FLAGS_REPLACE,
|
||||
name_acquired_handler,
|
||||
name_lost_handler,
|
||||
&data2,
|
||||
(GDestroyNotify) own_name_data_free_func);
|
||||
g_assert_cmpint (data2.num_bus_acquired, ==, 0);
|
||||
g_assert_cmpint (data2.num_acquired, ==, 0);
|
||||
g_assert_cmpint (data2.num_lost, ==, 0);
|
||||
g_main_loop_run (loop);
|
||||
g_assert_cmpint (data2.num_bus_acquired, ==, 0);
|
||||
g_assert_cmpint (data2.num_acquired, ==, 0);
|
||||
g_assert_cmpint (data2.num_lost, ==, 1);
|
||||
g_bus_unown_name (id2);
|
||||
g_assert_cmpint (data2.num_bus_acquired, ==, 0);
|
||||
g_assert_cmpint (data2.num_acquired, ==, 0);
|
||||
g_assert_cmpint (data2.num_lost, ==, 1);
|
||||
g_assert_cmpint (data2.num_free_func, ==, 1);
|
||||
|
||||
/*
|
||||
* Stop owning the name and grab it again with _ALLOW_REPLACEMENT.
|
||||
*/
|
||||
data.expect_null_connection = FALSE;
|
||||
g_bus_unown_name (id);
|
||||
g_assert_cmpint (data.num_bus_acquired, ==, 1);
|
||||
g_assert_cmpint (data.num_acquired, ==, 1);
|
||||
g_assert_cmpint (data.num_free_func, ==, 3);
|
||||
/* grab it again */
|
||||
data.num_bus_acquired = 0;
|
||||
data.num_acquired = 0;
|
||||
data.num_lost = 0;
|
||||
data.expect_null_connection = FALSE;
|
||||
id = g_bus_own_name (G_BUS_TYPE_SESSION,
|
||||
name,
|
||||
G_BUS_NAME_OWNER_FLAGS_ALLOW_REPLACEMENT,
|
||||
bus_acquired_handler,
|
||||
name_acquired_handler,
|
||||
name_lost_handler,
|
||||
&data,
|
||||
(GDestroyNotify) own_name_data_free_func);
|
||||
g_assert_cmpint (data.num_bus_acquired, ==, 0);
|
||||
g_assert_cmpint (data.num_acquired, ==, 0);
|
||||
g_assert_cmpint (data.num_lost, ==, 0);
|
||||
g_main_loop_run (loop);
|
||||
g_assert_cmpint (data.num_bus_acquired, ==, 1);
|
||||
g_assert_cmpint (data.num_acquired, ==, 0);
|
||||
g_assert_cmpint (data.num_lost, ==, 0);
|
||||
g_main_loop_run (loop);
|
||||
g_assert_cmpint (data.num_bus_acquired, ==, 1);
|
||||
g_assert_cmpint (data.num_acquired, ==, 1);
|
||||
g_assert_cmpint (data.num_lost, ==, 0);
|
||||
|
||||
/*
|
||||
* Now try to grab the name from the secondary connection.
|
||||
*
|
||||
*/
|
||||
/* first without _REPLACE - this won't make us acquire the name */
|
||||
data2.num_bus_acquired = 0;
|
||||
data2.num_acquired = 0;
|
||||
data2.num_lost = 0;
|
||||
data2.expect_null_connection = FALSE;
|
||||
data2.num_free_func = 0;
|
||||
id2 = g_bus_own_name_on_connection (c2,
|
||||
name,
|
||||
G_BUS_NAME_OWNER_FLAGS_NONE,
|
||||
name_acquired_handler,
|
||||
name_lost_handler,
|
||||
&data2,
|
||||
(GDestroyNotify) own_name_data_free_func);
|
||||
g_assert_cmpint (data2.num_bus_acquired, ==, 0);
|
||||
g_assert_cmpint (data2.num_acquired, ==, 0);
|
||||
g_assert_cmpint (data2.num_lost, ==, 0);
|
||||
g_main_loop_run (loop);
|
||||
g_assert_cmpint (data2.num_bus_acquired, ==, 0);
|
||||
g_assert_cmpint (data2.num_acquired, ==, 0);
|
||||
g_assert_cmpint (data2.num_lost, ==, 1);
|
||||
g_bus_unown_name (id2);
|
||||
g_assert_cmpint (data2.num_bus_acquired, ==, 0);
|
||||
g_assert_cmpint (data2.num_acquired, ==, 0);
|
||||
g_assert_cmpint (data2.num_lost, ==, 1);
|
||||
g_assert_cmpint (data2.num_free_func, ==, 1);
|
||||
/* then with _REPLACE - here we should acquire the name - e.g. owner should lose it
|
||||
* and owner2 should acquire it */
|
||||
data2.num_bus_acquired = 0;
|
||||
data2.num_acquired = 0;
|
||||
data2.num_lost = 0;
|
||||
data2.expect_null_connection = FALSE;
|
||||
data2.num_free_func = 0;
|
||||
id2 = g_bus_own_name_on_connection (c2,
|
||||
name,
|
||||
G_BUS_NAME_OWNER_FLAGS_REPLACE,
|
||||
name_acquired_handler,
|
||||
name_lost_handler,
|
||||
&data2,
|
||||
(GDestroyNotify) own_name_data_free_func);
|
||||
g_assert_cmpint (data.num_acquired, ==, 1);
|
||||
g_assert_cmpint (data.num_lost, ==, 0);
|
||||
g_assert_cmpint (data2.num_acquired, ==, 0);
|
||||
g_assert_cmpint (data2.num_lost, ==, 0);
|
||||
/* wait for handlers for both owner and owner2 to fire */
|
||||
while (data.num_lost == 0 || data2.num_acquired == 0)
|
||||
g_main_loop_run (loop);
|
||||
g_assert_cmpint (data.num_acquired, ==, 1);
|
||||
g_assert_cmpint (data.num_lost, ==, 1);
|
||||
g_assert_cmpint (data2.num_acquired, ==, 1);
|
||||
g_assert_cmpint (data2.num_lost, ==, 0);
|
||||
g_assert_cmpint (data2.num_bus_acquired, ==, 0);
|
||||
/* ok, make owner2 release the name - then wait for owner to automagically reacquire it */
|
||||
g_bus_unown_name (id2);
|
||||
g_assert_cmpint (data2.num_free_func, ==, 1);
|
||||
g_main_loop_run (loop);
|
||||
g_assert_cmpint (data.num_acquired, ==, 2);
|
||||
g_assert_cmpint (data.num_lost, ==, 1);
|
||||
|
||||
/*
|
||||
* Finally, nuke the bus and check name_lost_handler() is invoked.
|
||||
*
|
||||
*/
|
||||
data.expect_null_connection = TRUE;
|
||||
session_bus_down ();
|
||||
while (data.num_lost != 2)
|
||||
g_main_loop_run (loop);
|
||||
g_assert_cmpint (data.num_acquired, ==, 2);
|
||||
g_assert_cmpint (data.num_lost, ==, 2);
|
||||
g_bus_unown_name (id);
|
||||
g_assert_cmpint (data.num_free_func, ==, 4);
|
||||
|
||||
g_object_unref (c);
|
||||
g_object_unref (c2);
|
||||
}
|
||||
|
||||
/* ---------------------------------------------------------------------------------------------------- */
|
||||
/* Test that g_bus_watch_name() works correctly */
|
||||
/* ---------------------------------------------------------------------------------------------------- */
|
||||
|
||||
typedef struct
|
||||
{
|
||||
gboolean expect_null_connection;
|
||||
guint num_acquired;
|
||||
guint num_lost;
|
||||
guint num_appeared;
|
||||
guint num_vanished;
|
||||
guint num_free_func;
|
||||
} WatchNameData;
|
||||
|
||||
static void
|
||||
watch_name_data_free_func (WatchNameData *data)
|
||||
{
|
||||
data->num_free_func++;
|
||||
g_main_loop_quit (loop);
|
||||
}
|
||||
|
||||
static void
|
||||
w_bus_acquired_handler (GDBusConnection *connection,
|
||||
const gchar *name,
|
||||
gpointer user_data)
|
||||
{
|
||||
}
|
||||
|
||||
static void
|
||||
w_name_acquired_handler (GDBusConnection *connection,
|
||||
const gchar *name,
|
||||
gpointer user_data)
|
||||
{
|
||||
WatchNameData *data = user_data;
|
||||
data->num_acquired += 1;
|
||||
g_main_loop_quit (loop);
|
||||
}
|
||||
|
||||
static void
|
||||
w_name_lost_handler (GDBusConnection *connection,
|
||||
const gchar *name,
|
||||
gpointer user_data)
|
||||
{
|
||||
WatchNameData *data = user_data;
|
||||
data->num_lost += 1;
|
||||
g_main_loop_quit (loop);
|
||||
}
|
||||
|
||||
static void
|
||||
name_appeared_handler (GDBusConnection *connection,
|
||||
const gchar *name,
|
||||
const gchar *name_owner,
|
||||
gpointer user_data)
|
||||
{
|
||||
WatchNameData *data = user_data;
|
||||
if (data->expect_null_connection)
|
||||
{
|
||||
g_assert (connection == NULL);
|
||||
}
|
||||
else
|
||||
{
|
||||
g_assert (connection != NULL);
|
||||
g_dbus_connection_set_exit_on_close (connection, FALSE);
|
||||
}
|
||||
data->num_appeared += 1;
|
||||
g_main_loop_quit (loop);
|
||||
}
|
||||
|
||||
static void
|
||||
name_vanished_handler (GDBusConnection *connection,
|
||||
const gchar *name,
|
||||
gpointer user_data)
|
||||
{
|
||||
WatchNameData *data = user_data;
|
||||
if (data->expect_null_connection)
|
||||
{
|
||||
g_assert (connection == NULL);
|
||||
}
|
||||
else
|
||||
{
|
||||
g_assert (connection != NULL);
|
||||
g_dbus_connection_set_exit_on_close (connection, FALSE);
|
||||
}
|
||||
data->num_vanished += 1;
|
||||
g_main_loop_quit (loop);
|
||||
}
|
||||
|
||||
static void
|
||||
test_bus_watch_name (void)
|
||||
{
|
||||
WatchNameData data;
|
||||
guint id;
|
||||
guint owner_id;
|
||||
|
||||
/*
|
||||
* First check that name_vanished_handler() is invoked if there is no bus.
|
||||
*
|
||||
* Also make sure name_vanished_handler() isn't invoked when unwatching the name.
|
||||
*/
|
||||
data.num_free_func = 0;
|
||||
data.num_appeared = 0;
|
||||
data.num_vanished = 0;
|
||||
data.expect_null_connection = TRUE;
|
||||
id = g_bus_watch_name (G_BUS_TYPE_SESSION,
|
||||
"org.gtk.GDBus.Name1",
|
||||
G_BUS_NAME_WATCHER_FLAGS_NONE,
|
||||
name_appeared_handler,
|
||||
name_vanished_handler,
|
||||
&data,
|
||||
(GDestroyNotify) watch_name_data_free_func);
|
||||
g_assert_cmpint (data.num_appeared, ==, 0);
|
||||
g_assert_cmpint (data.num_vanished, ==, 0);
|
||||
g_main_loop_run (loop);
|
||||
g_assert_cmpint (data.num_appeared, ==, 0);
|
||||
g_assert_cmpint (data.num_vanished, ==, 1);
|
||||
g_bus_unwatch_name (id);
|
||||
g_assert_cmpint (data.num_appeared, ==, 0);
|
||||
g_assert_cmpint (data.num_vanished, ==, 1);
|
||||
g_assert_cmpint (data.num_free_func, ==, 1);
|
||||
|
||||
/*
|
||||
* Now bring up a bus, own a name, and then start watching it.
|
||||
*/
|
||||
session_bus_up ();
|
||||
/* own the name */
|
||||
data.num_free_func = 0;
|
||||
data.num_acquired = 0;
|
||||
data.num_lost = 0;
|
||||
data.expect_null_connection = FALSE;
|
||||
owner_id = g_bus_own_name (G_BUS_TYPE_SESSION,
|
||||
"org.gtk.GDBus.Name1",
|
||||
G_BUS_NAME_OWNER_FLAGS_NONE,
|
||||
w_bus_acquired_handler,
|
||||
w_name_acquired_handler,
|
||||
w_name_lost_handler,
|
||||
&data,
|
||||
(GDestroyNotify) watch_name_data_free_func);
|
||||
g_main_loop_run (loop);
|
||||
g_assert_cmpint (data.num_acquired, ==, 1);
|
||||
g_assert_cmpint (data.num_lost, ==, 0);
|
||||
/* now watch the name */
|
||||
data.num_appeared = 0;
|
||||
data.num_vanished = 0;
|
||||
id = g_bus_watch_name (G_BUS_TYPE_SESSION,
|
||||
"org.gtk.GDBus.Name1",
|
||||
G_BUS_NAME_WATCHER_FLAGS_NONE,
|
||||
name_appeared_handler,
|
||||
name_vanished_handler,
|
||||
&data,
|
||||
(GDestroyNotify) watch_name_data_free_func);
|
||||
g_assert_cmpint (data.num_appeared, ==, 0);
|
||||
g_assert_cmpint (data.num_vanished, ==, 0);
|
||||
g_main_loop_run (loop);
|
||||
g_assert_cmpint (data.num_appeared, ==, 1);
|
||||
g_assert_cmpint (data.num_vanished, ==, 0);
|
||||
|
||||
/*
|
||||
* Unwatch the name.
|
||||
*/
|
||||
g_bus_unwatch_name (id);
|
||||
g_assert_cmpint (data.num_free_func, ==, 1);
|
||||
|
||||
/* unown the name */
|
||||
g_bus_unown_name (owner_id);
|
||||
g_assert_cmpint (data.num_acquired, ==, 1);
|
||||
g_assert_cmpint (data.num_free_func, ==, 2);
|
||||
|
||||
/*
|
||||
* Create a watcher and then make a name be owned.
|
||||
*
|
||||
* This should trigger name_appeared_handler() ...
|
||||
*/
|
||||
/* watch the name */
|
||||
data.num_appeared = 0;
|
||||
data.num_vanished = 0;
|
||||
data.num_free_func = 0;
|
||||
id = g_bus_watch_name (G_BUS_TYPE_SESSION,
|
||||
"org.gtk.GDBus.Name1",
|
||||
G_BUS_NAME_WATCHER_FLAGS_NONE,
|
||||
name_appeared_handler,
|
||||
name_vanished_handler,
|
||||
&data,
|
||||
(GDestroyNotify) watch_name_data_free_func);
|
||||
g_assert_cmpint (data.num_appeared, ==, 0);
|
||||
g_assert_cmpint (data.num_vanished, ==, 0);
|
||||
g_main_loop_run (loop);
|
||||
g_assert_cmpint (data.num_appeared, ==, 0);
|
||||
g_assert_cmpint (data.num_vanished, ==, 1);
|
||||
|
||||
/* own the name */
|
||||
data.num_acquired = 0;
|
||||
data.num_lost = 0;
|
||||
data.expect_null_connection = FALSE;
|
||||
owner_id = g_bus_own_name (G_BUS_TYPE_SESSION,
|
||||
"org.gtk.GDBus.Name1",
|
||||
G_BUS_NAME_OWNER_FLAGS_NONE,
|
||||
w_bus_acquired_handler,
|
||||
w_name_acquired_handler,
|
||||
w_name_lost_handler,
|
||||
&data,
|
||||
(GDestroyNotify) watch_name_data_free_func);
|
||||
while (data.num_acquired == 0 || data.num_appeared == 0)
|
||||
g_main_loop_run (loop);
|
||||
g_assert_cmpint (data.num_acquired, ==, 1);
|
||||
g_assert_cmpint (data.num_lost, ==, 0);
|
||||
g_assert_cmpint (data.num_appeared, ==, 1);
|
||||
g_assert_cmpint (data.num_vanished, ==, 1);
|
||||
|
||||
/*
|
||||
* Nuke the bus and check that the name vanishes and is lost.
|
||||
*/
|
||||
data.expect_null_connection = TRUE;
|
||||
session_bus_down ();
|
||||
g_main_loop_run (loop);
|
||||
g_assert_cmpint (data.num_lost, ==, 1);
|
||||
g_assert_cmpint (data.num_vanished, ==, 2);
|
||||
|
||||
g_bus_unwatch_name (id);
|
||||
g_assert_cmpint (data.num_free_func, ==, 1);
|
||||
|
||||
g_bus_unown_name (owner_id);
|
||||
g_assert_cmpint (data.num_free_func, ==, 2);
|
||||
|
||||
}
|
||||
|
||||
/* ---------------------------------------------------------------------------------------------------- */
|
||||
|
||||
static void
|
||||
test_validate_names (void)
|
||||
{
|
||||
guint n;
|
||||
static const struct
|
||||
{
|
||||
gboolean name;
|
||||
gboolean unique;
|
||||
gboolean interface;
|
||||
const gchar *string;
|
||||
} names[] = {
|
||||
{ 1, 0, 1, "valid.well_known.name"},
|
||||
{ 1, 0, 0, "valid.well-known.name"},
|
||||
{ 1, 1, 0, ":valid.unique.name"},
|
||||
{ 0, 0, 0, "invalid.5well_known.name"},
|
||||
{ 0, 0, 0, "4invalid.5well_known.name"},
|
||||
{ 1, 1, 0, ":4valid.5unique.name"},
|
||||
{ 0, 0, 0, ""},
|
||||
{ 1, 0, 1, "very.long.very.long.very.long.very.long.very.long.very.long.very.long.very.long.very.long.very.long.very.long.very.long.very.long.very.long.very.long.very.long.very.long.very.long.very.long.very.long.very.long.very.long.very.long.very.long.very.long.name1"}, /* 255 */
|
||||
{ 0, 0, 0, "very.long.very.long.very.long.very.long.very.long.very.long.very.long.very.long.very.long.very.long.very.long.very.long.very.long.very.long.very.long.very.long.very.long.very.long.very.long.very.long.very.long.very.long.very.long.very.long.very.long.name12"}, /* 256 - too long! */
|
||||
{ 0, 0, 0, ".starts.with.a.dot"},
|
||||
{ 0, 0, 0, "contains.invalid;.characters"},
|
||||
{ 0, 0, 0, "contains.inva/lid.characters"},
|
||||
{ 0, 0, 0, "contains.inva[lid.characters"},
|
||||
{ 0, 0, 0, "contains.inva]lid.characters"},
|
||||
{ 0, 0, 0, "contains.inva_æøå_lid.characters"},
|
||||
{ 1, 1, 0, ":1.1"},
|
||||
};
|
||||
|
||||
for (n = 0; n < G_N_ELEMENTS (names); n++)
|
||||
{
|
||||
if (names[n].name)
|
||||
g_assert (g_dbus_is_name (names[n].string));
|
||||
else
|
||||
g_assert (!g_dbus_is_name (names[n].string));
|
||||
|
||||
if (names[n].unique)
|
||||
g_assert (g_dbus_is_unique_name (names[n].string));
|
||||
else
|
||||
g_assert (!g_dbus_is_unique_name (names[n].string));
|
||||
|
||||
if (names[n].interface)
|
||||
g_assert (g_dbus_is_interface_name (names[n].string));
|
||||
else
|
||||
g_assert (!g_dbus_is_interface_name (names[n].string));
|
||||
}
|
||||
}
|
||||
|
||||
/* ---------------------------------------------------------------------------------------------------- */
|
||||
|
||||
int
|
||||
main (int argc,
|
||||
char *argv[])
|
||||
{
|
||||
gint ret;
|
||||
|
||||
g_type_init ();
|
||||
g_test_init (&argc, &argv, NULL);
|
||||
|
||||
loop = g_main_loop_new (NULL, FALSE);
|
||||
|
||||
/* all the tests use a session bus with a well-known address that we can bring up and down
|
||||
* using session_bus_up() and session_bus_down().
|
||||
*/
|
||||
g_unsetenv ("DISPLAY");
|
||||
g_setenv ("DBUS_SESSION_BUS_ADDRESS", session_bus_get_temporary_address (), TRUE);
|
||||
|
||||
g_test_add_func ("/gdbus/validate-names", test_validate_names);
|
||||
g_test_add_func ("/gdbus/bus-own-name", test_bus_own_name);
|
||||
g_test_add_func ("/gdbus/bus-watch-name", test_bus_watch_name);
|
||||
|
||||
ret = g_test_run();
|
||||
|
||||
g_main_loop_unref (loop);
|
||||
|
||||
return ret;
|
||||
}
|
747
gio/tests/gdbus-peer.c
Normal file
747
gio/tests/gdbus-peer.c
Normal file
@ -0,0 +1,747 @@
|
||||
/* GLib testing framework examples and tests
|
||||
*
|
||||
* Copyright (C) 2008-2010 Red Hat, Inc.
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General
|
||||
* Public License along with this library; if not, write to the
|
||||
* Free Software Foundation, Inc., 59 Temple Place, Suite 330,
|
||||
* Boston, MA 02111-1307, USA.
|
||||
*
|
||||
* Author: David Zeuthen <davidz@redhat.com>
|
||||
*/
|
||||
|
||||
#include <gio/gio.h>
|
||||
#include <unistd.h>
|
||||
#include <string.h>
|
||||
|
||||
/* for open(2) */
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
#include <fcntl.h>
|
||||
|
||||
#include <gio/gunixsocketaddress.h>
|
||||
#include <gio/gunixfdlist.h>
|
||||
|
||||
#include "gdbus-tests.h"
|
||||
|
||||
|
||||
#ifdef G_OS_UNIX
|
||||
static gboolean is_unix = TRUE;
|
||||
#else
|
||||
static gboolean is_unix = FALSE;
|
||||
#endif
|
||||
|
||||
static gchar *test_guid = NULL;
|
||||
static GMainLoop *service_loop = NULL;
|
||||
static GDBusServer *server = NULL;
|
||||
static GMainLoop *loop = NULL;
|
||||
|
||||
/* ---------------------------------------------------------------------------------------------------- */
|
||||
/* Test that peer-to-peer connections work */
|
||||
/* ---------------------------------------------------------------------------------------------------- */
|
||||
|
||||
|
||||
typedef struct
|
||||
{
|
||||
gboolean accept_connection;
|
||||
gint num_connection_attempts;
|
||||
GPtrArray *current_connections;
|
||||
guint num_method_calls;
|
||||
gboolean signal_received;
|
||||
} PeerData;
|
||||
|
||||
static const gchar *test_interface_introspection_xml =
|
||||
"<node>"
|
||||
" <interface name='org.gtk.GDBus.PeerTestInterface'>"
|
||||
" <method name='HelloPeer'>"
|
||||
" <arg type='s' name='greeting' direction='in'/>"
|
||||
" <arg type='s' name='response' direction='out'/>"
|
||||
" </method>"
|
||||
" <method name='EmitSignal'/>"
|
||||
" <method name='OpenFile'>"
|
||||
" <arg type='s' name='path' direction='in'/>"
|
||||
" </method>"
|
||||
" <signal name='PeerSignal'>"
|
||||
" <arg type='s' name='a_string'/>"
|
||||
" </signal>"
|
||||
" <property type='s' name='PeerProperty' access='read'/>"
|
||||
" </interface>"
|
||||
"</node>";
|
||||
static const GDBusInterfaceInfo *test_interface_introspection_data = NULL;
|
||||
|
||||
static void
|
||||
test_interface_method_call (GDBusConnection *connection,
|
||||
const gchar *sender,
|
||||
const gchar *object_path,
|
||||
const gchar *interface_name,
|
||||
const gchar *method_name,
|
||||
GVariant *parameters,
|
||||
GDBusMethodInvocation *invocation,
|
||||
gpointer user_data)
|
||||
{
|
||||
PeerData *data = user_data;
|
||||
|
||||
data->num_method_calls++;
|
||||
|
||||
g_assert_cmpstr (object_path, ==, "/org/gtk/GDBus/PeerTestObject");
|
||||
g_assert_cmpstr (interface_name, ==, "org.gtk.GDBus.PeerTestInterface");
|
||||
|
||||
if (g_strcmp0 (method_name, "HelloPeer") == 0)
|
||||
{
|
||||
const gchar *greeting;
|
||||
gchar *response;
|
||||
|
||||
g_variant_get (parameters, "(s)", &greeting);
|
||||
|
||||
response = g_strdup_printf ("You greeted me with '%s'.",
|
||||
greeting);
|
||||
g_dbus_method_invocation_return_value (invocation,
|
||||
g_variant_new ("(s)", response));
|
||||
g_free (response);
|
||||
}
|
||||
else if (g_strcmp0 (method_name, "EmitSignal") == 0)
|
||||
{
|
||||
GError *error;
|
||||
|
||||
error = NULL;
|
||||
g_dbus_connection_emit_signal (connection,
|
||||
NULL,
|
||||
"/org/gtk/GDBus/PeerTestObject",
|
||||
"org.gtk.GDBus.PeerTestInterface",
|
||||
"PeerSignal",
|
||||
NULL,
|
||||
&error);
|
||||
g_assert_no_error (error);
|
||||
g_dbus_method_invocation_return_value (invocation, NULL);
|
||||
}
|
||||
else if (g_strcmp0 (method_name, "OpenFile") == 0)
|
||||
{
|
||||
const gchar *path;
|
||||
GDBusMessage *reply;
|
||||
GError *error;
|
||||
gint fd;
|
||||
GUnixFDList *fd_list;
|
||||
|
||||
g_variant_get (parameters, "(s)", &path);
|
||||
|
||||
fd_list = g_unix_fd_list_new ();
|
||||
|
||||
error = NULL;
|
||||
|
||||
fd = open (path, O_RDONLY);
|
||||
g_unix_fd_list_append (fd_list, fd, &error);
|
||||
g_assert_no_error (error);
|
||||
close (fd);
|
||||
|
||||
reply = g_dbus_message_new_method_reply (g_dbus_method_invocation_get_message (invocation));
|
||||
g_dbus_message_set_unix_fd_list (reply, fd_list);
|
||||
g_object_unref (invocation);
|
||||
|
||||
error = NULL;
|
||||
g_dbus_connection_send_message (connection,
|
||||
reply,
|
||||
NULL, /* out_serial */
|
||||
&error);
|
||||
g_assert_no_error (error);
|
||||
g_object_unref (reply);
|
||||
}
|
||||
else
|
||||
{
|
||||
g_assert_not_reached ();
|
||||
}
|
||||
}
|
||||
|
||||
static GVariant *
|
||||
test_interface_get_property (GDBusConnection *connection,
|
||||
const gchar *sender,
|
||||
const gchar *object_path,
|
||||
const gchar *interface_name,
|
||||
const gchar *property_name,
|
||||
GError **error,
|
||||
gpointer user_data)
|
||||
{
|
||||
g_assert_cmpstr (object_path, ==, "/org/gtk/GDBus/PeerTestObject");
|
||||
g_assert_cmpstr (interface_name, ==, "org.gtk.GDBus.PeerTestInterface");
|
||||
g_assert_cmpstr (property_name, ==, "PeerProperty");
|
||||
|
||||
return g_variant_new_string ("ThePropertyValue");
|
||||
}
|
||||
|
||||
|
||||
static const GDBusInterfaceVTable test_interface_vtable =
|
||||
{
|
||||
test_interface_method_call,
|
||||
test_interface_get_property,
|
||||
NULL /* set_property */
|
||||
};
|
||||
|
||||
static void
|
||||
on_proxy_signal_received (GDBusProxy *proxy,
|
||||
gchar *sender_name,
|
||||
gchar *signal_name,
|
||||
GVariant *parameters,
|
||||
gpointer user_data)
|
||||
{
|
||||
PeerData *data = user_data;
|
||||
|
||||
data->signal_received = TRUE;
|
||||
|
||||
g_assert (sender_name == NULL);
|
||||
g_assert_cmpstr (signal_name, ==, "PeerSignal");
|
||||
g_main_loop_quit (loop);
|
||||
}
|
||||
|
||||
/* ---------------------------------------------------------------------------------------------------- */
|
||||
|
||||
static gboolean
|
||||
on_authorize_authenticated_peer (GDBusAuthObserver *observer,
|
||||
GIOStream *stream,
|
||||
GCredentials *credentials,
|
||||
gpointer user_data)
|
||||
{
|
||||
PeerData *data = user_data;
|
||||
gboolean authorized;
|
||||
|
||||
data->num_connection_attempts++;
|
||||
|
||||
authorized = TRUE;
|
||||
if (!data->accept_connection)
|
||||
{
|
||||
authorized = FALSE;
|
||||
g_main_loop_quit (loop);
|
||||
}
|
||||
|
||||
return authorized;
|
||||
}
|
||||
|
||||
/* Runs in thread we created GDBusServer in (since we didn't pass G_DBUS_SERVER_FLAGS_RUN_IN_THREAD) */
|
||||
static void
|
||||
on_new_connection (GDBusServer *server,
|
||||
GDBusConnection *connection,
|
||||
gpointer user_data)
|
||||
{
|
||||
PeerData *data = user_data;
|
||||
GError *error;
|
||||
guint reg_id;
|
||||
|
||||
//g_print ("Client connected.\n"
|
||||
// "Negotiated capabilities: unix-fd-passing=%d\n",
|
||||
// g_dbus_connection_get_capabilities (connection) & G_DBUS_CAPABILITY_FLAGS_UNIX_FD_PASSING);
|
||||
|
||||
g_ptr_array_add (data->current_connections, g_object_ref (connection));
|
||||
|
||||
/* export object on the newly established connection */
|
||||
error = NULL;
|
||||
reg_id = g_dbus_connection_register_object (connection,
|
||||
"/org/gtk/GDBus/PeerTestObject",
|
||||
test_interface_introspection_data,
|
||||
&test_interface_vtable,
|
||||
data,
|
||||
NULL, /* GDestroyNotify for data */
|
||||
&error);
|
||||
g_assert_no_error (error);
|
||||
g_assert (reg_id > 0);
|
||||
|
||||
g_main_loop_quit (loop);
|
||||
}
|
||||
|
||||
static gpointer
|
||||
service_thread_func (gpointer user_data)
|
||||
{
|
||||
PeerData *data = user_data;
|
||||
GMainContext *service_context;
|
||||
GDBusAuthObserver *observer;
|
||||
GError *error;
|
||||
|
||||
service_context = g_main_context_new ();
|
||||
g_main_context_push_thread_default (service_context);
|
||||
|
||||
error = NULL;
|
||||
observer = g_dbus_auth_observer_new ();
|
||||
server = g_dbus_server_new_sync (is_unix ? "unix:tmpdir=/tmp/gdbus-test-" : "nonce-tcp:",
|
||||
G_DBUS_SERVER_FLAGS_NONE,
|
||||
test_guid,
|
||||
observer,
|
||||
NULL, /* cancellable */
|
||||
&error);
|
||||
g_assert_no_error (error);
|
||||
|
||||
g_signal_connect (server,
|
||||
"new-connection",
|
||||
G_CALLBACK (on_new_connection),
|
||||
data);
|
||||
g_signal_connect (observer,
|
||||
"authorize-authenticated-peer",
|
||||
G_CALLBACK (on_authorize_authenticated_peer),
|
||||
data);
|
||||
g_object_unref (observer);
|
||||
|
||||
g_dbus_server_start (server);
|
||||
|
||||
service_loop = g_main_loop_new (service_context, FALSE);
|
||||
g_main_loop_run (service_loop);
|
||||
|
||||
g_main_context_pop_thread_default (service_context);
|
||||
|
||||
g_main_loop_unref (service_loop);
|
||||
g_main_context_unref (service_context);
|
||||
|
||||
/* test code specifically unrefs the server - see below */
|
||||
g_assert (server == NULL);
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
#if 0
|
||||
static gboolean
|
||||
on_incoming_connection (GSocketService *service,
|
||||
GSocketConnection *socket_connection,
|
||||
GObject *source_object,
|
||||
gpointer user_data)
|
||||
{
|
||||
PeerData *data = user_data;
|
||||
|
||||
if (data->accept_connection)
|
||||
{
|
||||
GError *error;
|
||||
guint reg_id;
|
||||
GDBusConnection *connection;
|
||||
|
||||
error = NULL;
|
||||
connection = g_dbus_connection_new_sync (G_IO_STREAM (socket_connection),
|
||||
test_guid,
|
||||
G_DBUS_CONNECTION_FLAGS_AUTHENTICATION_SERVER,
|
||||
NULL, /* cancellable */
|
||||
&error);
|
||||
g_assert_no_error (error);
|
||||
|
||||
g_ptr_array_add (data->current_connections, connection);
|
||||
|
||||
/* export object on the newly established connection */
|
||||
error = NULL;
|
||||
reg_id = g_dbus_connection_register_object (connection,
|
||||
"/org/gtk/GDBus/PeerTestObject",
|
||||
&test_interface_introspection_data,
|
||||
&test_interface_vtable,
|
||||
data,
|
||||
NULL, /* GDestroyNotify for data */
|
||||
&error);
|
||||
g_assert_no_error (error);
|
||||
g_assert (reg_id > 0);
|
||||
|
||||
}
|
||||
else
|
||||
{
|
||||
/* don't do anything */
|
||||
}
|
||||
|
||||
data->num_connection_attempts++;
|
||||
|
||||
g_main_loop_quit (loop);
|
||||
|
||||
/* stops other signal handlers from being invoked */
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static gpointer
|
||||
service_thread_func (gpointer data)
|
||||
{
|
||||
GMainContext *service_context;
|
||||
gchar *socket_path;
|
||||
GSocketAddress *address;
|
||||
GError *error;
|
||||
|
||||
service_context = g_main_context_new ();
|
||||
g_main_context_push_thread_default (service_context);
|
||||
|
||||
socket_path = g_strdup_printf ("/tmp/gdbus-test-pid-%d", getpid ());
|
||||
address = g_unix_socket_address_new (socket_path);
|
||||
|
||||
service = g_socket_service_new ();
|
||||
error = NULL;
|
||||
g_socket_listener_add_address (G_SOCKET_LISTENER (service),
|
||||
address,
|
||||
G_SOCKET_TYPE_STREAM,
|
||||
G_SOCKET_PROTOCOL_DEFAULT,
|
||||
NULL, /* source_object */
|
||||
NULL, /* effective_address */
|
||||
&error);
|
||||
g_assert_no_error (error);
|
||||
g_signal_connect (service,
|
||||
"incoming",
|
||||
G_CALLBACK (on_incoming_connection),
|
||||
data);
|
||||
g_socket_service_start (service);
|
||||
|
||||
service_loop = g_main_loop_new (service_context, FALSE);
|
||||
g_main_loop_run (service_loop);
|
||||
|
||||
g_main_context_pop_thread_default (service_context);
|
||||
|
||||
g_main_loop_unref (service_loop);
|
||||
g_main_context_unref (service_context);
|
||||
|
||||
g_object_unref (address);
|
||||
g_free (socket_path);
|
||||
return NULL;
|
||||
}
|
||||
#endif
|
||||
|
||||
/* ---------------------------------------------------------------------------------------------------- */
|
||||
|
||||
#if 0
|
||||
static gboolean
|
||||
check_connection (gpointer user_data)
|
||||
{
|
||||
PeerData *data = user_data;
|
||||
guint n;
|
||||
|
||||
for (n = 0; n < data->current_connections->len; n++)
|
||||
{
|
||||
GDBusConnection *c;
|
||||
GIOStream *stream;
|
||||
|
||||
c = G_DBUS_CONNECTION (data->current_connections->pdata[n]);
|
||||
stream = g_dbus_connection_get_stream (c);
|
||||
|
||||
g_debug ("In check_connection for %d: connection %p, stream %p", n, c, stream);
|
||||
g_debug ("closed = %d", g_io_stream_is_closed (stream));
|
||||
|
||||
GSocket *socket;
|
||||
socket = g_socket_connection_get_socket (G_SOCKET_CONNECTION (stream));
|
||||
g_debug ("socket_closed = %d", g_socket_is_closed (socket));
|
||||
g_debug ("socket_condition_check = %d", g_socket_condition_check (socket, G_IO_IN|G_IO_OUT|G_IO_ERR|G_IO_HUP));
|
||||
|
||||
gchar buf[128];
|
||||
GError *error;
|
||||
gssize num_read;
|
||||
error = NULL;
|
||||
num_read = g_input_stream_read (g_io_stream_get_input_stream (stream),
|
||||
buf,
|
||||
128,
|
||||
NULL,
|
||||
&error);
|
||||
if (num_read < 0)
|
||||
{
|
||||
g_debug ("error: %s", error->message);
|
||||
g_error_free (error);
|
||||
}
|
||||
else
|
||||
{
|
||||
g_debug ("no error, read %d bytes", (gint) num_read);
|
||||
}
|
||||
}
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
on_do_disconnect_in_idle (gpointer data)
|
||||
{
|
||||
GDBusConnection *c = G_DBUS_CONNECTION (data);
|
||||
g_debug ("GDC %p has ref_count %d", c, G_OBJECT (c)->ref_count);
|
||||
g_dbus_connection_disconnect (c);
|
||||
g_object_unref (c);
|
||||
return FALSE;
|
||||
}
|
||||
#endif
|
||||
|
||||
static void
|
||||
test_peer (void)
|
||||
{
|
||||
GDBusConnection *c;
|
||||
GDBusConnection *c2;
|
||||
GDBusProxy *proxy;
|
||||
GError *error;
|
||||
PeerData data;
|
||||
GVariant *value;
|
||||
GVariant *result;
|
||||
const gchar *s;
|
||||
GThread *service_thread;
|
||||
|
||||
memset (&data, '\0', sizeof (PeerData));
|
||||
data.current_connections = g_ptr_array_new_with_free_func (g_object_unref);
|
||||
|
||||
/* first try to connect when there is no server */
|
||||
error = NULL;
|
||||
c = g_dbus_connection_new_for_address_sync (is_unix ? "unix:path=/tmp/gdbus-test-does-not-exist-pid" :
|
||||
/* NOTE: Even if something is listening on port 12345 the connection
|
||||
* will fail because the nonce file doesn't exist */
|
||||
"nonce-tcp:host=localhost,port=12345,noncefile=this-does-not-exist-gdbus",
|
||||
G_DBUS_CONNECTION_FLAGS_AUTHENTICATION_CLIENT,
|
||||
NULL, /* GDBusAuthObserver */
|
||||
NULL, /* cancellable */
|
||||
&error);
|
||||
_g_assert_error_domain (error, G_IO_ERROR);
|
||||
g_assert (!g_dbus_error_is_remote_error (error));
|
||||
g_clear_error (&error);
|
||||
g_assert (c == NULL);
|
||||
|
||||
/* bring up a server - we run the server in a different thread to avoid deadlocks */
|
||||
error = NULL;
|
||||
service_thread = g_thread_create (service_thread_func,
|
||||
&data,
|
||||
TRUE,
|
||||
&error);
|
||||
while (service_loop == NULL)
|
||||
g_thread_yield ();
|
||||
g_assert (server != NULL);
|
||||
|
||||
/* bring up a connection and accept it */
|
||||
data.accept_connection = TRUE;
|
||||
error = NULL;
|
||||
c = g_dbus_connection_new_for_address_sync (g_dbus_server_get_client_address (server),
|
||||
G_DBUS_CONNECTION_FLAGS_AUTHENTICATION_CLIENT,
|
||||
NULL, /* GDBusAuthObserver */
|
||||
NULL, /* cancellable */
|
||||
&error);
|
||||
g_assert_no_error (error);
|
||||
g_assert (c != NULL);
|
||||
while (data.current_connections->len < 1)
|
||||
g_main_loop_run (loop);
|
||||
g_assert_cmpint (data.current_connections->len, ==, 1);
|
||||
g_assert_cmpint (data.num_connection_attempts, ==, 1);
|
||||
g_assert (g_dbus_connection_get_unique_name (c) == NULL);
|
||||
g_assert_cmpstr (g_dbus_connection_get_guid (c), ==, test_guid);
|
||||
|
||||
/* check that we create a proxy, read properties, receive signals and invoke
|
||||
* the HelloPeer() method. Since the server runs in another thread it's fine
|
||||
* to use synchronous blocking API here.
|
||||
*/
|
||||
error = NULL;
|
||||
proxy = g_dbus_proxy_new_sync (c,
|
||||
G_TYPE_DBUS_PROXY,
|
||||
G_DBUS_PROXY_FLAGS_NONE,
|
||||
NULL,
|
||||
NULL, /* bus_name */
|
||||
"/org/gtk/GDBus/PeerTestObject",
|
||||
"org.gtk.GDBus.PeerTestInterface",
|
||||
NULL, /* GCancellable */
|
||||
&error);
|
||||
g_assert_no_error (error);
|
||||
g_assert (proxy != NULL);
|
||||
error = NULL;
|
||||
value = g_dbus_proxy_get_cached_property (proxy, "PeerProperty");
|
||||
g_assert_cmpstr (g_variant_get_string (value, NULL), ==, "ThePropertyValue");
|
||||
|
||||
/* try invoking a method */
|
||||
error = NULL;
|
||||
result = g_dbus_proxy_call_sync (proxy,
|
||||
"HelloPeer",
|
||||
g_variant_new ("(s)", "Hey Peer!"),
|
||||
G_DBUS_CALL_FLAGS_NONE,
|
||||
-1,
|
||||
NULL, /* GCancellable */
|
||||
&error);
|
||||
g_assert_no_error (error);
|
||||
g_variant_get (result, "(s)", &s);
|
||||
g_assert_cmpstr (s, ==, "You greeted me with 'Hey Peer!'.");
|
||||
g_variant_unref (result);
|
||||
g_assert_cmpint (data.num_method_calls, ==, 1);
|
||||
|
||||
/* make the other peer emit a signal - catch it */
|
||||
g_signal_connect (proxy,
|
||||
"g-signal",
|
||||
G_CALLBACK (on_proxy_signal_received),
|
||||
&data);
|
||||
g_assert (!data.signal_received);
|
||||
g_dbus_proxy_call (proxy,
|
||||
"EmitSignal",
|
||||
NULL, /* no arguments */
|
||||
G_DBUS_CALL_FLAGS_NONE,
|
||||
-1,
|
||||
NULL, /* GCancellable */
|
||||
NULL, /* GAsyncReadyCallback - we don't care about the result */
|
||||
NULL); /* user_data */
|
||||
g_main_loop_run (loop);
|
||||
g_assert (data.signal_received);
|
||||
g_assert_cmpint (data.num_method_calls, ==, 2);
|
||||
|
||||
/* check for UNIX fd passing */
|
||||
#ifdef G_OS_UNIX
|
||||
{
|
||||
GDBusMessage *method_call_message;
|
||||
GDBusMessage *method_reply_message;
|
||||
GUnixFDList *fd_list;
|
||||
gint fd;
|
||||
gchar buf[1024];
|
||||
gssize len;
|
||||
gchar *buf2;
|
||||
gsize len2;
|
||||
|
||||
method_call_message = g_dbus_message_new_method_call (NULL, /* name */
|
||||
"/org/gtk/GDBus/PeerTestObject",
|
||||
"org.gtk.GDBus.PeerTestInterface",
|
||||
"OpenFile");
|
||||
g_dbus_message_set_body (method_call_message, g_variant_new ("(s)", "/etc/hosts"));
|
||||
error = NULL;
|
||||
method_reply_message = g_dbus_connection_send_message_with_reply_sync (c,
|
||||
method_call_message,
|
||||
-1,
|
||||
NULL, /* out_serial */
|
||||
NULL, /* cancellable */
|
||||
&error);
|
||||
g_assert_no_error (error);
|
||||
g_assert (g_dbus_message_get_message_type (method_reply_message) == G_DBUS_MESSAGE_TYPE_METHOD_RETURN);
|
||||
fd_list = g_dbus_message_get_unix_fd_list (method_reply_message);
|
||||
g_assert (fd_list != NULL);
|
||||
g_assert_cmpint (g_unix_fd_list_get_length (fd_list), ==, 1);
|
||||
error = NULL;
|
||||
fd = g_unix_fd_list_get (fd_list, 0, &error);
|
||||
g_assert_no_error (error);
|
||||
g_object_unref (method_call_message);
|
||||
g_object_unref (method_reply_message);
|
||||
|
||||
memset (buf, '\0', sizeof (buf));
|
||||
len = read (fd, buf, sizeof (buf) - 1);
|
||||
close (fd);
|
||||
|
||||
error = NULL;
|
||||
g_file_get_contents ("/etc/hosts",
|
||||
&buf2,
|
||||
&len2,
|
||||
&error);
|
||||
g_assert_no_error (error);
|
||||
if (len2 > sizeof (buf))
|
||||
buf2[sizeof (buf)] = '\0';
|
||||
g_assert_cmpstr (buf, ==, buf2);
|
||||
g_free (buf2);
|
||||
}
|
||||
#endif /* G_OS_UNIX */
|
||||
|
||||
|
||||
/* bring up a connection - don't accept it - this should fail
|
||||
*/
|
||||
data.accept_connection = FALSE;
|
||||
error = NULL;
|
||||
c2 = g_dbus_connection_new_for_address_sync (g_dbus_server_get_client_address (server),
|
||||
G_DBUS_CONNECTION_FLAGS_AUTHENTICATION_CLIENT,
|
||||
NULL, /* GDBusAuthObserver */
|
||||
NULL, /* cancellable */
|
||||
&error);
|
||||
_g_assert_error_domain (error, G_IO_ERROR);
|
||||
g_assert (c2 == NULL);
|
||||
|
||||
#if 0
|
||||
/* TODO: THIS TEST DOESN'T WORK YET */
|
||||
|
||||
/* bring up a connection - accept it.. then disconnect from the client side - check
|
||||
* that the server side gets the disconnect signal.
|
||||
*/
|
||||
error = NULL;
|
||||
data.accept_connection = TRUE;
|
||||
c2 = g_dbus_connection_new_for_address_sync (g_dbus_server_get_client_address (server),
|
||||
G_DBUS_CONNECTION_FLAGS_AUTHENTICATION_CLIENT,
|
||||
NULL, /* GDBusAuthObserver */
|
||||
NULL, /* cancellable */
|
||||
&error);
|
||||
g_assert_no_error (error);
|
||||
g_assert (c2 != NULL);
|
||||
g_assert (!g_dbus_connection_get_is_disconnected (c2));
|
||||
while (data.num_connection_attempts < 3)
|
||||
g_main_loop_run (loop);
|
||||
g_assert_cmpint (data.current_connections->len, ==, 2);
|
||||
g_assert_cmpint (data.num_connection_attempts, ==, 3);
|
||||
g_assert (!g_dbus_connection_get_is_disconnected (G_DBUS_CONNECTION (data.current_connections->pdata[1])));
|
||||
g_idle_add (on_do_disconnect_in_idle, c2);
|
||||
g_debug ("==================================================");
|
||||
g_debug ("==================================================");
|
||||
g_debug ("==================================================");
|
||||
g_debug ("waiting for disconnect on connection %p, stream %p",
|
||||
data.current_connections->pdata[1],
|
||||
g_dbus_connection_get_stream (data.current_connections->pdata[1]));
|
||||
|
||||
g_timeout_add (2000, check_connection, &data);
|
||||
//_g_assert_signal_received (G_DBUS_CONNECTION (data.current_connections->pdata[1]), "closed");
|
||||
g_main_loop_run (loop);
|
||||
g_assert (g_dbus_connection_get_is_disconnected (G_DBUS_CONNECTION (data.current_connections->pdata[1])));
|
||||
g_ptr_array_set_size (data.current_connections, 1); /* remove disconnected connection object */
|
||||
#endif
|
||||
|
||||
/* unref the server and stop listening for new connections
|
||||
*
|
||||
* This won't bring down the established connections - check that c is still connected
|
||||
* by invoking a method
|
||||
*/
|
||||
//g_socket_service_stop (service);
|
||||
//g_object_unref (service);
|
||||
g_dbus_server_stop (server);
|
||||
g_object_unref (server);
|
||||
server = NULL;
|
||||
|
||||
error = NULL;
|
||||
result = g_dbus_proxy_call_sync (proxy,
|
||||
"HelloPeer",
|
||||
g_variant_new ("(s)", "Hey Again Peer!"),
|
||||
G_DBUS_CALL_FLAGS_NONE,
|
||||
-1,
|
||||
NULL, /* GCancellable */
|
||||
&error);
|
||||
g_assert_no_error (error);
|
||||
g_variant_get (result, "(s)", &s);
|
||||
g_assert_cmpstr (s, ==, "You greeted me with 'Hey Again Peer!'.");
|
||||
g_variant_unref (result);
|
||||
g_assert_cmpint (data.num_method_calls, ==, 4);
|
||||
|
||||
#if 0
|
||||
/* TODO: THIS TEST DOESN'T WORK YET */
|
||||
|
||||
/* now disconnect from the server side - check that the client side gets the signal */
|
||||
g_assert_cmpint (data.current_connections->len, ==, 1);
|
||||
g_assert (G_DBUS_CONNECTION (data.current_connections->pdata[0]) != c);
|
||||
g_dbus_connection_disconnect (G_DBUS_CONNECTION (data.current_connections->pdata[0]));
|
||||
if (!g_dbus_connection_get_is_disconnected (c))
|
||||
_g_assert_signal_received (c, "closed");
|
||||
g_assert (g_dbus_connection_get_is_disconnected (c));
|
||||
#endif
|
||||
|
||||
g_object_unref (c);
|
||||
g_ptr_array_unref (data.current_connections);
|
||||
g_object_unref (proxy);
|
||||
|
||||
g_main_loop_quit (service_loop);
|
||||
g_thread_join (service_thread);
|
||||
}
|
||||
|
||||
/* ---------------------------------------------------------------------------------------------------- */
|
||||
|
||||
int
|
||||
main (int argc,
|
||||
char *argv[])
|
||||
{
|
||||
gint ret;
|
||||
GDBusNodeInfo *introspection_data = NULL;
|
||||
|
||||
g_type_init ();
|
||||
g_thread_init (NULL);
|
||||
g_test_init (&argc, &argv, NULL);
|
||||
|
||||
introspection_data = g_dbus_node_info_new_for_xml (test_interface_introspection_xml, NULL);
|
||||
g_assert (introspection_data != NULL);
|
||||
test_interface_introspection_data = introspection_data->interfaces[0];
|
||||
|
||||
test_guid = g_dbus_generate_guid ();
|
||||
|
||||
/* all the tests rely on a shared main loop */
|
||||
loop = g_main_loop_new (NULL, FALSE);
|
||||
|
||||
g_test_add_func ("/gdbus/peer-to-peer", test_peer);
|
||||
|
||||
ret = g_test_run();
|
||||
|
||||
g_main_loop_unref (loop);
|
||||
g_free (test_guid);
|
||||
g_dbus_node_info_unref (introspection_data);
|
||||
|
||||
return ret;
|
||||
}
|
487
gio/tests/gdbus-proxy.c
Normal file
487
gio/tests/gdbus-proxy.c
Normal file
@ -0,0 +1,487 @@
|
||||
/* GLib testing framework examples and tests
|
||||
*
|
||||
* Copyright (C) 2008-2010 Red Hat, Inc.
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General
|
||||
* Public License along with this library; if not, write to the
|
||||
* Free Software Foundation, Inc., 59 Temple Place, Suite 330,
|
||||
* Boston, MA 02111-1307, USA.
|
||||
*
|
||||
* Author: David Zeuthen <davidz@redhat.com>
|
||||
*/
|
||||
|
||||
#include <gio/gio.h>
|
||||
#include <unistd.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "gdbus-tests.h"
|
||||
|
||||
/* all tests rely on a shared mainloop */
|
||||
static GMainLoop *loop = NULL;
|
||||
|
||||
/* ---------------------------------------------------------------------------------------------------- */
|
||||
/* Test that the method aspects of GDBusProxy works */
|
||||
/* ---------------------------------------------------------------------------------------------------- */
|
||||
|
||||
static void
|
||||
test_methods (GDBusConnection *connection,
|
||||
const gchar *name,
|
||||
const gchar *name_owner,
|
||||
GDBusProxy *proxy)
|
||||
{
|
||||
GVariant *result;
|
||||
GError *error;
|
||||
const gchar *str;
|
||||
gchar *dbus_error_name;
|
||||
|
||||
/* check that we can invoke a method */
|
||||
error = NULL;
|
||||
result = g_dbus_proxy_call_sync (proxy,
|
||||
"HelloWorld",
|
||||
g_variant_new ("(s)", "Hey"),
|
||||
G_DBUS_CALL_FLAGS_NONE,
|
||||
-1,
|
||||
NULL,
|
||||
&error);
|
||||
g_assert_no_error (error);
|
||||
g_assert (result != NULL);
|
||||
g_assert_cmpstr (g_variant_get_type_string (result), ==, "(s)");
|
||||
g_variant_get (result, "(s)", &str);
|
||||
g_assert_cmpstr (str, ==, "You greeted me with 'Hey'. Thanks!");
|
||||
g_variant_unref (result);
|
||||
|
||||
/* Check that we can completely recover the returned error */
|
||||
result = g_dbus_proxy_call_sync (proxy,
|
||||
"HelloWorld",
|
||||
g_variant_new ("(s)", "Yo"),
|
||||
G_DBUS_CALL_FLAGS_NONE,
|
||||
-1,
|
||||
NULL,
|
||||
&error);
|
||||
g_assert_error (error, G_IO_ERROR, G_IO_ERROR_DBUS_ERROR);
|
||||
g_assert (g_dbus_error_is_remote_error (error));
|
||||
g_assert (g_dbus_error_is_remote_error (error));
|
||||
g_assert (result == NULL);
|
||||
dbus_error_name = g_dbus_error_get_remote_error (error);
|
||||
g_assert_cmpstr (dbus_error_name, ==, "com.example.TestException");
|
||||
g_free (dbus_error_name);
|
||||
g_assert (g_dbus_error_strip_remote_error (error));
|
||||
g_assert_cmpstr (error->message, ==, "Yo is not a proper greeting");
|
||||
g_clear_error (&error);
|
||||
|
||||
/* Check that we get a timeout if the method handling is taking longer than timeout */
|
||||
error = NULL;
|
||||
result = g_dbus_proxy_call_sync (proxy,
|
||||
"Sleep",
|
||||
g_variant_new ("(i)", 500 /* msec */),
|
||||
G_DBUS_CALL_FLAGS_NONE,
|
||||
100 /* msec */,
|
||||
NULL,
|
||||
&error);
|
||||
g_assert_error (error, G_IO_ERROR, G_IO_ERROR_TIMED_OUT);
|
||||
g_assert (!g_dbus_error_is_remote_error (error));
|
||||
g_assert (result == NULL);
|
||||
g_clear_error (&error);
|
||||
|
||||
/* Check that proxy-default timeouts work. */
|
||||
g_assert_cmpint (g_dbus_proxy_get_default_timeout (proxy), ==, -1);
|
||||
|
||||
/* the default timeout is 25000 msec so this should work */
|
||||
result = g_dbus_proxy_call_sync (proxy,
|
||||
"Sleep",
|
||||
g_variant_new ("(i)", 500 /* msec */),
|
||||
G_DBUS_CALL_FLAGS_NONE,
|
||||
-1, /* use proxy default (e.g. -1 -> e.g. 25000 msec) */
|
||||
NULL,
|
||||
&error);
|
||||
g_assert_no_error (error);
|
||||
g_assert (result != NULL);
|
||||
g_assert_cmpstr (g_variant_get_type_string (result), ==, "()");
|
||||
g_variant_unref (result);
|
||||
|
||||
/* now set the proxy-default timeout to 250 msec and try the 500 msec call - this should FAIL */
|
||||
g_dbus_proxy_set_default_timeout (proxy, 250);
|
||||
g_assert_cmpint (g_dbus_proxy_get_default_timeout (proxy), ==, 250);
|
||||
result = g_dbus_proxy_call_sync (proxy,
|
||||
"Sleep",
|
||||
g_variant_new ("(i)", 500 /* msec */),
|
||||
G_DBUS_CALL_FLAGS_NONE,
|
||||
-1, /* use proxy default (e.g. 250 msec) */
|
||||
NULL,
|
||||
&error);
|
||||
g_assert_error (error, G_IO_ERROR, G_IO_ERROR_TIMED_OUT);
|
||||
g_assert (!g_dbus_error_is_remote_error (error));
|
||||
g_assert (result == NULL);
|
||||
g_clear_error (&error);
|
||||
|
||||
/* clean up after ourselves */
|
||||
g_dbus_proxy_set_default_timeout (proxy, -1);
|
||||
}
|
||||
|
||||
/* ---------------------------------------------------------------------------------------------------- */
|
||||
/* Test that the property aspects of GDBusProxy works */
|
||||
/* ---------------------------------------------------------------------------------------------------- */
|
||||
|
||||
static void
|
||||
test_properties (GDBusConnection *connection,
|
||||
const gchar *name,
|
||||
const gchar *name_owner,
|
||||
GDBusProxy *proxy)
|
||||
{
|
||||
GError *error;
|
||||
GVariant *variant;
|
||||
GVariant *variant2;
|
||||
GVariant *result;
|
||||
|
||||
error = NULL;
|
||||
|
||||
/*
|
||||
* Check that we can read cached properties.
|
||||
*
|
||||
* No need to test all properties - GVariant has already been tested
|
||||
*/
|
||||
variant = g_dbus_proxy_get_cached_property (proxy, "y");
|
||||
g_assert (variant != NULL);
|
||||
g_assert_cmpint (g_variant_get_byte (variant), ==, 1);
|
||||
g_variant_unref (variant);
|
||||
variant = g_dbus_proxy_get_cached_property (proxy, "o");
|
||||
g_assert (variant != NULL);
|
||||
g_assert_cmpstr (g_variant_get_string (variant, NULL), ==, "/some/path");
|
||||
g_variant_unref (variant);
|
||||
|
||||
/*
|
||||
* Now ask the service to change a property and check that #GDBusProxy::g-property-changed
|
||||
* is received. Also check that the cache is updated.
|
||||
*/
|
||||
variant2 = g_variant_new_byte (42);
|
||||
result = g_dbus_proxy_call_sync (proxy,
|
||||
"FrobSetProperty",
|
||||
g_variant_new ("(sv)",
|
||||
"y",
|
||||
variant2),
|
||||
G_DBUS_CALL_FLAGS_NONE,
|
||||
-1,
|
||||
NULL,
|
||||
&error);
|
||||
g_assert_no_error (error);
|
||||
g_assert (result != NULL);
|
||||
g_assert_cmpstr (g_variant_get_type_string (result), ==, "()");
|
||||
g_variant_unref (result);
|
||||
_g_assert_signal_received (proxy, "g-properties-changed");
|
||||
variant = g_dbus_proxy_get_cached_property (proxy, "y");
|
||||
g_assert (variant != NULL);
|
||||
g_assert_cmpint (g_variant_get_byte (variant), ==, 42);
|
||||
g_variant_unref (variant);
|
||||
|
||||
g_dbus_proxy_set_cached_property (proxy, "y", g_variant_new_byte (142));
|
||||
variant = g_dbus_proxy_get_cached_property (proxy, "y");
|
||||
g_assert (variant != NULL);
|
||||
g_assert_cmpint (g_variant_get_byte (variant), ==, 142);
|
||||
g_variant_unref (variant);
|
||||
|
||||
g_dbus_proxy_set_cached_property (proxy, "y", NULL);
|
||||
variant = g_dbus_proxy_get_cached_property (proxy, "y");
|
||||
g_assert (variant == NULL);
|
||||
}
|
||||
|
||||
/* ---------------------------------------------------------------------------------------------------- */
|
||||
/* Test that the signal aspects of GDBusProxy works */
|
||||
/* ---------------------------------------------------------------------------------------------------- */
|
||||
|
||||
static void
|
||||
test_proxy_signals_on_signal (GDBusProxy *proxy,
|
||||
const gchar *sender_name,
|
||||
const gchar *signal_name,
|
||||
GVariant *parameters,
|
||||
gpointer user_data)
|
||||
{
|
||||
GString *s = user_data;
|
||||
|
||||
g_assert_cmpstr (signal_name, ==, "TestSignal");
|
||||
g_assert_cmpstr (g_variant_get_type_string (parameters), ==, "(sov)");
|
||||
|
||||
g_variant_print_string (parameters, s, TRUE);
|
||||
}
|
||||
|
||||
typedef struct
|
||||
{
|
||||
GMainLoop *internal_loop;
|
||||
GString *s;
|
||||
} TestSignalData;
|
||||
|
||||
static void
|
||||
test_proxy_signals_on_emit_signal_cb (GDBusProxy *proxy,
|
||||
GAsyncResult *res,
|
||||
gpointer user_data)
|
||||
{
|
||||
TestSignalData *data = user_data;
|
||||
GError *error;
|
||||
GVariant *result;
|
||||
|
||||
error = NULL;
|
||||
result = g_dbus_proxy_call_finish (proxy,
|
||||
res,
|
||||
&error);
|
||||
g_assert_no_error (error);
|
||||
g_assert (result != NULL);
|
||||
g_assert_cmpstr (g_variant_get_type_string (result), ==, "()");
|
||||
g_variant_unref (result);
|
||||
|
||||
/* check that the signal was recieved before we got the method result */
|
||||
g_assert (strlen (data->s->str) > 0);
|
||||
|
||||
/* break out of the loop */
|
||||
g_main_loop_quit (data->internal_loop);
|
||||
}
|
||||
|
||||
static void
|
||||
test_signals (GDBusConnection *connection,
|
||||
const gchar *name,
|
||||
const gchar *name_owner,
|
||||
GDBusProxy *proxy)
|
||||
{
|
||||
GError *error;
|
||||
GString *s;
|
||||
gulong signal_handler_id;
|
||||
TestSignalData data;
|
||||
GVariant *result;
|
||||
|
||||
error = NULL;
|
||||
|
||||
/*
|
||||
* Ask the service to emit a signal and check that we receive it.
|
||||
*
|
||||
* Note that blocking calls don't block in the mainloop so wait for the signal (which
|
||||
* is dispatched before the method reply)
|
||||
*/
|
||||
s = g_string_new (NULL);
|
||||
signal_handler_id = g_signal_connect (proxy,
|
||||
"g-signal",
|
||||
G_CALLBACK (test_proxy_signals_on_signal),
|
||||
s);
|
||||
|
||||
result = g_dbus_proxy_call_sync (proxy,
|
||||
"EmitSignal",
|
||||
g_variant_new ("(so)",
|
||||
"Accept the next proposition you hear",
|
||||
"/some/path"),
|
||||
G_DBUS_CALL_FLAGS_NONE,
|
||||
-1,
|
||||
NULL,
|
||||
&error);
|
||||
g_assert_no_error (error);
|
||||
g_assert (result != NULL);
|
||||
g_assert_cmpstr (g_variant_get_type_string (result), ==, "()");
|
||||
g_variant_unref (result);
|
||||
/* check that we haven't received the signal just yet */
|
||||
g_assert (strlen (s->str) == 0);
|
||||
/* and now wait for the signal */
|
||||
_g_assert_signal_received (proxy, "g-signal");
|
||||
g_assert_cmpstr (s->str,
|
||||
==,
|
||||
"('Accept the next proposition you hear .. in bed!', objectpath '/some/path/in/bed', <'a variant'>)");
|
||||
g_signal_handler_disconnect (proxy, signal_handler_id);
|
||||
g_string_free (s, TRUE);
|
||||
|
||||
/*
|
||||
* Now do this async to check the signal is received before the method returns.
|
||||
*/
|
||||
s = g_string_new (NULL);
|
||||
data.internal_loop = g_main_loop_new (NULL, FALSE);
|
||||
data.s = s;
|
||||
signal_handler_id = g_signal_connect (proxy,
|
||||
"g-signal",
|
||||
G_CALLBACK (test_proxy_signals_on_signal),
|
||||
s);
|
||||
g_dbus_proxy_call (proxy,
|
||||
"EmitSignal",
|
||||
g_variant_new ("(so)",
|
||||
"You will make a great programmer",
|
||||
"/some/other/path"),
|
||||
G_DBUS_CALL_FLAGS_NONE,
|
||||
-1,
|
||||
NULL,
|
||||
(GAsyncReadyCallback) test_proxy_signals_on_emit_signal_cb,
|
||||
&data);
|
||||
g_main_loop_run (data.internal_loop);
|
||||
g_main_loop_unref (data.internal_loop);
|
||||
g_assert_cmpstr (s->str,
|
||||
==,
|
||||
"('You will make a great programmer .. in bed!', objectpath '/some/other/path/in/bed', <'a variant'>)");
|
||||
g_signal_handler_disconnect (proxy, signal_handler_id);
|
||||
g_string_free (s, TRUE);
|
||||
}
|
||||
|
||||
static void
|
||||
test_bogus_method_return (GDBusConnection *connection,
|
||||
const gchar *name,
|
||||
const gchar *name_owner,
|
||||
GDBusProxy *proxy)
|
||||
{
|
||||
GError *error = NULL;
|
||||
GVariant *result;
|
||||
|
||||
result = g_dbus_proxy_call_sync (proxy,
|
||||
"PairReturn",
|
||||
NULL,
|
||||
G_DBUS_CALL_FLAGS_NONE,
|
||||
-1,
|
||||
NULL,
|
||||
&error);
|
||||
g_assert_error (error, G_IO_ERROR, G_IO_ERROR_INVALID_ARGUMENT);
|
||||
g_assert (result == NULL);
|
||||
}
|
||||
|
||||
/* ---------------------------------------------------------------------------------------------------- */
|
||||
|
||||
static const gchar *frob_dbus_interface_xml =
|
||||
"<node>"
|
||||
" <interface name='com.example.Frob'>"
|
||||
/* Deliberately different from gdbus-testserver.py's definition */
|
||||
" <method name='PairReturn'>"
|
||||
" <arg type='u' name='somenumber' direction='in'/>"
|
||||
" <arg type='s' name='somestring' direction='out'/>"
|
||||
" </method>"
|
||||
" <method name='HelloWorld'>"
|
||||
" <arg type='s' name='somestring' direction='in'/>"
|
||||
" <arg type='s' name='somestring' direction='out'/>"
|
||||
" </method>"
|
||||
" <method name='Sleep'>"
|
||||
" <arg type='i' name='timeout' direction='in'/>"
|
||||
" </method>"
|
||||
" <property name='y' type='y' access='readwrite'/>"
|
||||
" </interface>"
|
||||
"</node>";
|
||||
static GDBusInterfaceInfo *frob_dbus_interface_info;
|
||||
|
||||
static void
|
||||
on_proxy_appeared (GDBusConnection *connection,
|
||||
const gchar *name,
|
||||
const gchar *name_owner,
|
||||
GDBusProxy *proxy,
|
||||
gpointer user_data)
|
||||
{
|
||||
test_methods (connection, name, name_owner, proxy);
|
||||
test_properties (connection, name, name_owner, proxy);
|
||||
test_signals (connection, name, name_owner, proxy);
|
||||
|
||||
/* This is obviously wrong but expected interface is not set so we don't fail... */
|
||||
g_dbus_proxy_set_cached_property (proxy, "y", g_variant_new_string ("error_me_out!"));
|
||||
g_dbus_proxy_set_cached_property (proxy, "y", g_variant_new_byte (42));
|
||||
g_dbus_proxy_set_cached_property (proxy, "does-not-exist", g_variant_new_string ("something"));
|
||||
g_dbus_proxy_set_cached_property (proxy, "does-not-exist", NULL);
|
||||
|
||||
/* Now repeat the method tests, with an expected interface set */
|
||||
g_dbus_proxy_set_interface_info (proxy, frob_dbus_interface_info);
|
||||
test_methods (connection, name, name_owner, proxy);
|
||||
|
||||
/* And now one more test where we deliberately set the expected
|
||||
* interface definition incorrectly
|
||||
*/
|
||||
test_bogus_method_return (connection, name, name_owner, proxy);
|
||||
|
||||
/* Also check that we complain if setting a cached property of the wrong type */
|
||||
if (g_test_trap_fork (0, G_TEST_TRAP_SILENCE_STDOUT | G_TEST_TRAP_SILENCE_STDERR))
|
||||
{
|
||||
g_dbus_proxy_set_cached_property (proxy, "y", g_variant_new_string ("error_me_out!"));
|
||||
}
|
||||
g_test_trap_assert_stderr ("*Trying to set property y of type s but according to the expected interface the type is y*");
|
||||
g_test_trap_assert_failed();
|
||||
|
||||
if (g_test_trap_fork (0, G_TEST_TRAP_SILENCE_STDOUT | G_TEST_TRAP_SILENCE_STDERR))
|
||||
{
|
||||
g_dbus_proxy_set_cached_property (proxy, "does-not-exist", g_variant_new_string ("something"));
|
||||
}
|
||||
g_test_trap_assert_stderr ("*Trying to lookup property does-not-exist which isn't in expected interface com.example.Frob*");
|
||||
g_test_trap_assert_failed();
|
||||
|
||||
/* this should work, however (since the type is correct) */
|
||||
g_dbus_proxy_set_cached_property (proxy, "y", g_variant_new_byte (42));
|
||||
|
||||
g_main_loop_quit (loop);
|
||||
}
|
||||
|
||||
static void
|
||||
on_proxy_vanished (GDBusConnection *connection,
|
||||
const gchar *name,
|
||||
gpointer user_data)
|
||||
{
|
||||
}
|
||||
|
||||
static void
|
||||
test_proxy (void)
|
||||
{
|
||||
guint watcher_id;
|
||||
|
||||
session_bus_up ();
|
||||
|
||||
/* TODO: wait a bit for the bus to come up.. ideally session_bus_up() won't return
|
||||
* until one can connect to the bus but that's not how things work right now
|
||||
*/
|
||||
usleep (500 * 1000);
|
||||
|
||||
watcher_id = g_bus_watch_proxy (G_BUS_TYPE_SESSION,
|
||||
"com.example.TestService",
|
||||
G_BUS_NAME_WATCHER_FLAGS_NONE,
|
||||
"/com/example/TestObject",
|
||||
"com.example.Frob",
|
||||
G_TYPE_DBUS_PROXY,
|
||||
G_DBUS_PROXY_FLAGS_NONE,
|
||||
on_proxy_appeared,
|
||||
on_proxy_vanished,
|
||||
NULL,
|
||||
NULL);
|
||||
|
||||
/* this is safe; testserver will exit once the bus goes away */
|
||||
g_assert (g_spawn_command_line_async ("./gdbus-testserver.py", NULL));
|
||||
|
||||
g_main_loop_run (loop);
|
||||
|
||||
g_bus_unwatch_proxy (watcher_id);
|
||||
|
||||
/* tear down bus */
|
||||
session_bus_down ();
|
||||
}
|
||||
|
||||
/* ---------------------------------------------------------------------------------------------------- */
|
||||
|
||||
int
|
||||
main (int argc,
|
||||
char *argv[])
|
||||
{
|
||||
gint ret;
|
||||
GDBusNodeInfo *introspection_data = NULL;
|
||||
|
||||
g_type_init ();
|
||||
g_test_init (&argc, &argv, NULL);
|
||||
|
||||
introspection_data = g_dbus_node_info_new_for_xml (frob_dbus_interface_xml, NULL);
|
||||
g_assert (introspection_data != NULL);
|
||||
frob_dbus_interface_info = introspection_data->interfaces[0];
|
||||
|
||||
/* all the tests rely on a shared main loop */
|
||||
loop = g_main_loop_new (NULL, FALSE);
|
||||
|
||||
/* all the tests use a session bus with a well-known address that we can bring up and down
|
||||
* using session_bus_up() and session_bus_down().
|
||||
*/
|
||||
g_unsetenv ("DISPLAY");
|
||||
g_setenv ("DBUS_SESSION_BUS_ADDRESS", session_bus_get_temporary_address (), TRUE);
|
||||
|
||||
g_test_add_func ("/gdbus/proxy", test_proxy);
|
||||
|
||||
ret = g_test_run();
|
||||
|
||||
g_dbus_node_info_unref (introspection_data);
|
||||
return ret;
|
||||
}
|
654
gio/tests/gdbus-serialization.c
Normal file
654
gio/tests/gdbus-serialization.c
Normal file
@ -0,0 +1,654 @@
|
||||
/* GLib testing framework examples and tests
|
||||
*
|
||||
* Copyright (C) 2008-2010 Red Hat, Inc.
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General
|
||||
* Public License along with this library; if not, write to the
|
||||
* Free Software Foundation, Inc., 59 Temple Place, Suite 330,
|
||||
* Boston, MA 02111-1307, USA.
|
||||
*
|
||||
* Author: David Zeuthen <davidz@redhat.com>
|
||||
*/
|
||||
|
||||
#include <gio/gio.h>
|
||||
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
#include <dbus/dbus.h>
|
||||
|
||||
/* ---------------------------------------------------------------------------------------------------- */
|
||||
|
||||
static void
|
||||
hexdump (const guchar *str, gsize len)
|
||||
{
|
||||
const guchar *data = (const guchar *) str;
|
||||
guint n, m;
|
||||
|
||||
for (n = 0; n < len; n += 16)
|
||||
{
|
||||
g_printerr ("%04x: ", n);
|
||||
|
||||
for (m = n; m < n + 16; m++)
|
||||
{
|
||||
if (m > n && (m%4) == 0)
|
||||
g_printerr (" ");
|
||||
if (m < len)
|
||||
g_printerr ("%02x ", data[m]);
|
||||
else
|
||||
g_printerr (" ");
|
||||
}
|
||||
|
||||
g_printerr (" ");
|
||||
|
||||
for (m = n; m < len && m < n + 16; m++)
|
||||
g_printerr ("%c", g_ascii_isprint (data[m]) ? data[m] : '.');
|
||||
|
||||
g_printerr ("\n");
|
||||
}
|
||||
}
|
||||
|
||||
/* ---------------------------------------------------------------------------------------------------- */
|
||||
|
||||
static gboolean
|
||||
append_gv_to_dbus_iter (DBusMessageIter *iter,
|
||||
GVariant *value,
|
||||
GError **error)
|
||||
{
|
||||
const GVariantType *type;
|
||||
|
||||
type = g_variant_get_type (value);
|
||||
if (g_variant_type_equal (type, G_VARIANT_TYPE_BOOLEAN))
|
||||
{
|
||||
dbus_bool_t v = g_variant_get_boolean (value);
|
||||
dbus_message_iter_append_basic (iter, DBUS_TYPE_BOOLEAN, &v);
|
||||
}
|
||||
else if (g_variant_type_equal (type, G_VARIANT_TYPE_BYTE))
|
||||
{
|
||||
guint8 v = g_variant_get_byte (value);
|
||||
dbus_message_iter_append_basic (iter, DBUS_TYPE_BYTE, &v);
|
||||
}
|
||||
else if (g_variant_type_equal (type, G_VARIANT_TYPE_INT16))
|
||||
{
|
||||
gint16 v = g_variant_get_int16 (value);
|
||||
dbus_message_iter_append_basic (iter, DBUS_TYPE_INT16, &v);
|
||||
}
|
||||
else if (g_variant_type_equal (type, G_VARIANT_TYPE_UINT16))
|
||||
{
|
||||
guint16 v = g_variant_get_uint16 (value);
|
||||
dbus_message_iter_append_basic (iter, DBUS_TYPE_UINT16, &v);
|
||||
}
|
||||
else if (g_variant_type_equal (type, G_VARIANT_TYPE_INT32))
|
||||
{
|
||||
gint32 v = g_variant_get_int32 (value);
|
||||
dbus_message_iter_append_basic (iter, DBUS_TYPE_INT32, &v);
|
||||
}
|
||||
else if (g_variant_type_equal (type, G_VARIANT_TYPE_UINT32))
|
||||
{
|
||||
guint32 v = g_variant_get_uint32 (value);
|
||||
dbus_message_iter_append_basic (iter, DBUS_TYPE_UINT32, &v);
|
||||
}
|
||||
else if (g_variant_type_equal (type, G_VARIANT_TYPE_INT64))
|
||||
{
|
||||
gint64 v = g_variant_get_int64 (value);
|
||||
dbus_message_iter_append_basic (iter, DBUS_TYPE_INT64, &v);
|
||||
}
|
||||
else if (g_variant_type_equal (type, G_VARIANT_TYPE_UINT64))
|
||||
{
|
||||
guint64 v = g_variant_get_uint64 (value);
|
||||
dbus_message_iter_append_basic (iter, DBUS_TYPE_UINT64, &v);
|
||||
}
|
||||
else if (g_variant_type_equal (type, G_VARIANT_TYPE_DOUBLE))
|
||||
{
|
||||
gdouble v = g_variant_get_double (value);
|
||||
dbus_message_iter_append_basic (iter, DBUS_TYPE_DOUBLE, &v);
|
||||
}
|
||||
else if (g_variant_type_equal (type, G_VARIANT_TYPE_STRING))
|
||||
{
|
||||
const gchar *v = g_variant_get_string (value, NULL);
|
||||
dbus_message_iter_append_basic (iter, DBUS_TYPE_STRING, &v);
|
||||
}
|
||||
else if (g_variant_type_equal (type, G_VARIANT_TYPE_OBJECT_PATH))
|
||||
{
|
||||
const gchar *v = g_variant_get_string (value, NULL);
|
||||
dbus_message_iter_append_basic (iter, DBUS_TYPE_OBJECT_PATH, &v);
|
||||
}
|
||||
else if (g_variant_type_equal (type, G_VARIANT_TYPE_SIGNATURE))
|
||||
{
|
||||
const gchar *v = g_variant_get_string (value, NULL);
|
||||
dbus_message_iter_append_basic (iter, DBUS_TYPE_SIGNATURE, &v);
|
||||
}
|
||||
else if (g_variant_type_is_variant (type))
|
||||
{
|
||||
DBusMessageIter sub;
|
||||
GVariant *child;
|
||||
|
||||
child = g_variant_get_child_value (value, 0);
|
||||
dbus_message_iter_open_container (iter, DBUS_TYPE_VARIANT,
|
||||
g_variant_get_type_string (child),
|
||||
&sub);
|
||||
if (!append_gv_to_dbus_iter (&sub, child, error))
|
||||
{
|
||||
g_variant_unref (child);
|
||||
goto fail;
|
||||
}
|
||||
dbus_message_iter_close_container (iter, &sub);
|
||||
g_variant_unref (child);
|
||||
}
|
||||
else if (g_variant_type_is_array (type))
|
||||
{
|
||||
DBusMessageIter dbus_iter;
|
||||
const gchar *type_string;
|
||||
GVariantIter gv_iter;
|
||||
GVariant *item;
|
||||
|
||||
type_string = g_variant_get_type_string (value);
|
||||
type_string++; /* skip the 'a' */
|
||||
|
||||
dbus_message_iter_open_container (iter, DBUS_TYPE_ARRAY,
|
||||
type_string, &dbus_iter);
|
||||
g_variant_iter_init (&gv_iter, value);
|
||||
|
||||
while ((item = g_variant_iter_next_value (&gv_iter)))
|
||||
{
|
||||
if (!append_gv_to_dbus_iter (&dbus_iter, item, error))
|
||||
{
|
||||
goto fail;
|
||||
}
|
||||
}
|
||||
|
||||
dbus_message_iter_close_container (iter, &dbus_iter);
|
||||
}
|
||||
else if (g_variant_type_is_tuple (type))
|
||||
{
|
||||
DBusMessageIter dbus_iter;
|
||||
GVariantIter gv_iter;
|
||||
GVariant *item;
|
||||
|
||||
dbus_message_iter_open_container (iter, DBUS_TYPE_STRUCT,
|
||||
NULL, &dbus_iter);
|
||||
g_variant_iter_init (&gv_iter, value);
|
||||
|
||||
while ((item = g_variant_iter_next_value (&gv_iter)))
|
||||
{
|
||||
if (!append_gv_to_dbus_iter (&dbus_iter, item, error))
|
||||
goto fail;
|
||||
}
|
||||
|
||||
dbus_message_iter_close_container (iter, &dbus_iter);
|
||||
}
|
||||
else if (g_variant_type_is_dict_entry (type))
|
||||
{
|
||||
DBusMessageIter dbus_iter;
|
||||
GVariant *key, *val;
|
||||
|
||||
dbus_message_iter_open_container (iter, DBUS_TYPE_DICT_ENTRY,
|
||||
NULL, &dbus_iter);
|
||||
key = g_variant_get_child_value (value, 0);
|
||||
if (!append_gv_to_dbus_iter (&dbus_iter, key, error))
|
||||
{
|
||||
g_variant_unref (key);
|
||||
goto fail;
|
||||
}
|
||||
g_variant_unref (key);
|
||||
|
||||
val = g_variant_get_child_value (value, 1);
|
||||
if (!append_gv_to_dbus_iter (&dbus_iter, val, error))
|
||||
{
|
||||
g_variant_unref (val);
|
||||
goto fail;
|
||||
}
|
||||
g_variant_unref (val);
|
||||
|
||||
dbus_message_iter_close_container (iter, &dbus_iter);
|
||||
}
|
||||
else
|
||||
{
|
||||
g_set_error (error,
|
||||
G_IO_ERROR,
|
||||
G_IO_ERROR_INVALID_ARGUMENT,
|
||||
"Error serializing GVariant with type-string `%s' to a D-Bus message",
|
||||
g_variant_get_type_string (value));
|
||||
goto fail;
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
|
||||
fail:
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
append_gv_to_dbus_message (DBusMessage *message,
|
||||
GVariant *value,
|
||||
GError **error)
|
||||
{
|
||||
gboolean ret;
|
||||
guint n;
|
||||
|
||||
ret = FALSE;
|
||||
|
||||
if (value != NULL)
|
||||
{
|
||||
DBusMessageIter iter;
|
||||
GVariantIter gv_iter;
|
||||
GVariant *item;
|
||||
|
||||
dbus_message_iter_init_append (message, &iter);
|
||||
|
||||
g_variant_iter_init (&gv_iter, value);
|
||||
n = 0;
|
||||
while ((item = g_variant_iter_next_value (&gv_iter)))
|
||||
{
|
||||
if (!append_gv_to_dbus_iter (&iter, item, error))
|
||||
{
|
||||
g_prefix_error (error,
|
||||
"Error encoding in-arg %d: ",
|
||||
n);
|
||||
goto out;
|
||||
}
|
||||
n++;
|
||||
}
|
||||
}
|
||||
|
||||
ret = TRUE;
|
||||
|
||||
out:
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void
|
||||
print_gv_dbus_message (GVariant *value)
|
||||
{
|
||||
DBusMessage *message;
|
||||
char *blob;
|
||||
int blob_len;
|
||||
GError *error;
|
||||
|
||||
message = dbus_message_new (DBUS_MESSAGE_TYPE_METHOD_CALL);
|
||||
dbus_message_set_serial (message, 0x41);
|
||||
dbus_message_set_path (message, "/foo/bar");
|
||||
dbus_message_set_member (message, "Member");
|
||||
|
||||
error = NULL;
|
||||
if (!append_gv_to_dbus_message (message, value, &error))
|
||||
{
|
||||
g_printerr ("Error printing GVariant as DBusMessage: %s", error->message);
|
||||
g_error_free (error);
|
||||
goto out;
|
||||
}
|
||||
|
||||
dbus_message_marshal (message, &blob, &blob_len);
|
||||
g_printerr ("\n");
|
||||
hexdump ((guchar *) blob, blob_len);
|
||||
out:
|
||||
dbus_message_unref (message);
|
||||
}
|
||||
|
||||
/* ---------------------------------------------------------------------------------------------------- */
|
||||
|
||||
static void
|
||||
dbus_1_message_append (GString *s,
|
||||
guint indent,
|
||||
DBusMessageIter *iter)
|
||||
{
|
||||
gint arg_type;
|
||||
DBusMessageIter sub;
|
||||
|
||||
g_string_append_printf (s, "%*s", indent, "");
|
||||
|
||||
arg_type = dbus_message_iter_get_arg_type (iter);
|
||||
switch (arg_type)
|
||||
{
|
||||
case DBUS_TYPE_BOOLEAN:
|
||||
{
|
||||
dbus_bool_t value;
|
||||
dbus_message_iter_get_basic (iter, &value);
|
||||
g_string_append_printf (s, "bool: %s\n", value ? "true" : "false");
|
||||
break;
|
||||
}
|
||||
|
||||
case DBUS_TYPE_BYTE:
|
||||
{
|
||||
guchar value;
|
||||
dbus_message_iter_get_basic (iter, &value);
|
||||
g_string_append_printf (s, "byte: 0x%02x\n", (guint) value);
|
||||
break;
|
||||
}
|
||||
|
||||
case DBUS_TYPE_INT16:
|
||||
{
|
||||
gint16 value;
|
||||
dbus_message_iter_get_basic (iter, &value);
|
||||
g_string_append_printf (s, "int16: %" G_GINT16_FORMAT "\n", value);
|
||||
break;
|
||||
}
|
||||
|
||||
case DBUS_TYPE_UINT16:
|
||||
{
|
||||
guint16 value;
|
||||
dbus_message_iter_get_basic (iter, &value);
|
||||
g_string_append_printf (s, "uint16: %" G_GUINT16_FORMAT "\n", value);
|
||||
break;
|
||||
}
|
||||
|
||||
case DBUS_TYPE_INT32:
|
||||
{
|
||||
gint32 value;
|
||||
dbus_message_iter_get_basic (iter, &value);
|
||||
g_string_append_printf (s, "int32: %" G_GINT32_FORMAT "\n", value);
|
||||
break;
|
||||
}
|
||||
|
||||
case DBUS_TYPE_UINT32:
|
||||
{
|
||||
guint32 value;
|
||||
dbus_message_iter_get_basic (iter, &value);
|
||||
g_string_append_printf (s, "uint32: %" G_GUINT32_FORMAT "\n", value);
|
||||
break;
|
||||
}
|
||||
|
||||
case DBUS_TYPE_INT64:
|
||||
{
|
||||
gint64 value;
|
||||
dbus_message_iter_get_basic (iter, &value);
|
||||
g_string_append_printf (s, "int64: %" G_GINT64_FORMAT "\n", value);
|
||||
break;
|
||||
}
|
||||
|
||||
case DBUS_TYPE_UINT64:
|
||||
{
|
||||
guint64 value;
|
||||
dbus_message_iter_get_basic (iter, &value);
|
||||
g_string_append_printf (s, "uint64: %" G_GUINT64_FORMAT "\n", value);
|
||||
break;
|
||||
}
|
||||
|
||||
case DBUS_TYPE_DOUBLE:
|
||||
{
|
||||
gdouble value;
|
||||
dbus_message_iter_get_basic (iter, &value);
|
||||
g_string_append_printf (s, "double: %f\n", value);
|
||||
break;
|
||||
}
|
||||
|
||||
case DBUS_TYPE_STRING:
|
||||
{
|
||||
const gchar *value;
|
||||
dbus_message_iter_get_basic (iter, &value);
|
||||
g_string_append_printf (s, "string: `%s'\n", value);
|
||||
break;
|
||||
}
|
||||
|
||||
case DBUS_TYPE_OBJECT_PATH:
|
||||
{
|
||||
const gchar *value;
|
||||
dbus_message_iter_get_basic (iter, &value);
|
||||
g_string_append_printf (s, "object_path: `%s'\n", value);
|
||||
break;
|
||||
}
|
||||
|
||||
case DBUS_TYPE_SIGNATURE:
|
||||
{
|
||||
const gchar *value;
|
||||
dbus_message_iter_get_basic (iter, &value);
|
||||
g_string_append_printf (s, "signature: `%s'\n", value);
|
||||
break;
|
||||
}
|
||||
|
||||
case DBUS_TYPE_VARIANT:
|
||||
g_string_append_printf (s, "variant:\n");
|
||||
dbus_message_iter_recurse (iter, &sub);
|
||||
while (dbus_message_iter_get_arg_type (&sub))
|
||||
{
|
||||
dbus_1_message_append (s, indent + 2, &sub);
|
||||
dbus_message_iter_next (&sub);
|
||||
}
|
||||
break;
|
||||
|
||||
case DBUS_TYPE_ARRAY:
|
||||
g_string_append_printf (s, "array:\n");
|
||||
dbus_message_iter_recurse (iter, &sub);
|
||||
while (dbus_message_iter_get_arg_type (&sub))
|
||||
{
|
||||
dbus_1_message_append (s, indent + 2, &sub);
|
||||
dbus_message_iter_next (&sub);
|
||||
}
|
||||
break;
|
||||
|
||||
case DBUS_TYPE_STRUCT:
|
||||
g_string_append_printf (s, "struct:\n");
|
||||
dbus_message_iter_recurse (iter, &sub);
|
||||
while (dbus_message_iter_get_arg_type (&sub))
|
||||
{
|
||||
dbus_1_message_append (s, indent + 2, &sub);
|
||||
dbus_message_iter_next (&sub);
|
||||
}
|
||||
break;
|
||||
|
||||
case DBUS_TYPE_DICT_ENTRY:
|
||||
g_string_append_printf (s, "dict_entry:\n");
|
||||
dbus_message_iter_recurse (iter, &sub);
|
||||
while (dbus_message_iter_get_arg_type (&sub))
|
||||
{
|
||||
dbus_1_message_append (s, indent + 2, &sub);
|
||||
dbus_message_iter_next (&sub);
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
g_printerr ("Error serializing D-Bus message to GVariant. Unsupported arg type `%c' (%d)",
|
||||
arg_type,
|
||||
arg_type);
|
||||
g_assert_not_reached ();
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static gchar *
|
||||
dbus_1_message_print (DBusMessage *message)
|
||||
{
|
||||
GString *s;
|
||||
guint n;
|
||||
DBusMessageIter iter;
|
||||
|
||||
s = g_string_new (NULL);
|
||||
n = 0;
|
||||
dbus_message_iter_init (message, &iter);
|
||||
while (dbus_message_iter_get_arg_type (&iter) != DBUS_TYPE_INVALID)
|
||||
{
|
||||
g_string_append_printf (s, "value %d: ", n);
|
||||
dbus_1_message_append (s, 2, &iter);
|
||||
dbus_message_iter_next (&iter);
|
||||
n++;
|
||||
}
|
||||
|
||||
return g_string_free (s, FALSE);
|
||||
}
|
||||
|
||||
/* ---------------------------------------------------------------------------------------------------- */
|
||||
|
||||
static gchar *
|
||||
get_body_signature (GVariant *value)
|
||||
{
|
||||
const gchar *s;
|
||||
gsize len;
|
||||
gchar *ret;
|
||||
|
||||
s = g_variant_get_type_string (value);
|
||||
len = strlen (s);
|
||||
g_assert (len>=2);
|
||||
|
||||
ret = g_strndup (s + 1, len - 2);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void
|
||||
check_serialization (GVariant *value,
|
||||
const gchar *expected_dbus_1_output)
|
||||
{
|
||||
guchar *blob;
|
||||
gsize blob_size;
|
||||
DBusMessage *dbus_1_message;
|
||||
GDBusMessage *message;
|
||||
GDBusMessage *recovered_message;
|
||||
GError *error;
|
||||
DBusError dbus_error;
|
||||
gchar *s;
|
||||
gchar *s1;
|
||||
|
||||
message = g_dbus_message_new ();
|
||||
g_dbus_message_set_body (message, value);
|
||||
g_dbus_message_set_message_type (message, G_DBUS_MESSAGE_TYPE_METHOD_CALL);
|
||||
g_dbus_message_set_serial (message, 0x41);
|
||||
s = get_body_signature (value);
|
||||
g_dbus_message_set_header (message, G_DBUS_MESSAGE_HEADER_FIELD_PATH, g_variant_new_object_path ("/foo/bar"));
|
||||
g_dbus_message_set_header (message, G_DBUS_MESSAGE_HEADER_FIELD_MEMBER, g_variant_new_string ("Member"));
|
||||
g_dbus_message_set_header (message, G_DBUS_MESSAGE_HEADER_FIELD_SIGNATURE, g_variant_new_signature (s));
|
||||
g_free (s);
|
||||
|
||||
/* First check that the serialization to the D-Bus wire format is correct */
|
||||
|
||||
error = NULL;
|
||||
blob = g_dbus_message_to_blob (message,
|
||||
&blob_size,
|
||||
G_DBUS_CAPABILITY_FLAGS_NONE,
|
||||
&error);
|
||||
g_assert_no_error (error);
|
||||
g_assert (blob != NULL);
|
||||
|
||||
dbus_error_init (&dbus_error);
|
||||
dbus_1_message = dbus_message_demarshal ((char *) blob, blob_size, &dbus_error);
|
||||
if (dbus_error_is_set (&dbus_error))
|
||||
{
|
||||
g_printerr ("Error calling dbus_message_demarshal() on this blob: %s: %s\n",
|
||||
dbus_error.name,
|
||||
dbus_error.message);
|
||||
hexdump (blob, blob_size);
|
||||
dbus_error_free (&dbus_error);
|
||||
|
||||
s = g_variant_print (value, TRUE);
|
||||
g_printerr ("\nThe blob was generated from the following GVariant value:\n%s\n\n", s);
|
||||
g_free (s);
|
||||
|
||||
g_printerr ("If the blob was encoded using DBusMessageIter, the payload would have been:\n");
|
||||
print_gv_dbus_message (value);
|
||||
|
||||
g_assert_not_reached ();
|
||||
}
|
||||
|
||||
s = dbus_1_message_print (dbus_1_message);
|
||||
dbus_message_unref (dbus_1_message);
|
||||
|
||||
g_assert_cmpstr (s, ==, expected_dbus_1_output);
|
||||
g_free (s);
|
||||
|
||||
/* Then serialize back and check that the body is identical */
|
||||
|
||||
error = NULL;
|
||||
recovered_message = g_dbus_message_new_from_blob (blob,
|
||||
blob_size,
|
||||
G_DBUS_CAPABILITY_FLAGS_NONE,
|
||||
&error);
|
||||
g_assert_no_error (error);
|
||||
g_assert (recovered_message != NULL);
|
||||
g_assert (g_dbus_message_get_body (recovered_message) != NULL);
|
||||
|
||||
if (!g_variant_equal (g_dbus_message_get_body (recovered_message), value))
|
||||
{
|
||||
s = g_variant_print (g_dbus_message_get_body (recovered_message), TRUE);
|
||||
s1 = g_variant_print (value, TRUE);
|
||||
g_printerr ("Recovered value:\n%s\ndoes not match given value\n%s\n",
|
||||
s,
|
||||
s1);
|
||||
g_free (s);
|
||||
g_free (s1);
|
||||
g_assert_not_reached ();
|
||||
}
|
||||
g_object_unref (message);
|
||||
g_object_unref (recovered_message);
|
||||
}
|
||||
|
||||
static void
|
||||
message_serialize_basic (void)
|
||||
{
|
||||
check_serialization (g_variant_new ("(sogybnqiuxtd)",
|
||||
"this is a string",
|
||||
"/this/is/a/path",
|
||||
"sad",
|
||||
42,
|
||||
TRUE,
|
||||
-42,
|
||||
60000,
|
||||
-44,
|
||||
100000,
|
||||
-G_GINT64_CONSTANT(2)<<34,
|
||||
G_GUINT64_CONSTANT(0xffffffffffffffff),
|
||||
42.5),
|
||||
"value 0: string: `this is a string'\n"
|
||||
"value 1: object_path: `/this/is/a/path'\n"
|
||||
"value 2: signature: `sad'\n"
|
||||
"value 3: byte: 0x2a\n"
|
||||
"value 4: bool: true\n"
|
||||
"value 5: int16: -42\n"
|
||||
"value 6: uint16: 60000\n"
|
||||
"value 7: int32: -44\n"
|
||||
"value 8: uint32: 100000\n"
|
||||
"value 9: int64: -34359738368\n"
|
||||
"value 10: uint64: 18446744073709551615\n"
|
||||
"value 11: double: 42.500000\n");
|
||||
}
|
||||
|
||||
/* ---------------------------------------------------------------------------------------------------- */
|
||||
|
||||
static void
|
||||
message_serialize_complex (void)
|
||||
{
|
||||
GError *error;
|
||||
GVariant *value;
|
||||
|
||||
error = NULL;
|
||||
value = g_variant_parse (G_VARIANT_TYPE ("(aia{ss})"),
|
||||
"([1, 2, 3], {'one': 'white', 'two': 'black'})",
|
||||
NULL, NULL, &error);
|
||||
g_assert_no_error (error);
|
||||
g_assert (value != NULL);
|
||||
check_serialization (value,
|
||||
"value 0: array:\n"
|
||||
" int32: 1\n"
|
||||
" int32: 2\n"
|
||||
" int32: 3\n"
|
||||
"value 1: array:\n"
|
||||
" dict_entry:\n"
|
||||
" string: `one'\n"
|
||||
" string: `white'\n"
|
||||
" dict_entry:\n"
|
||||
" string: `two'\n"
|
||||
" string: `black'\n");
|
||||
}
|
||||
|
||||
|
||||
/* ---------------------------------------------------------------------------------------------------- */
|
||||
|
||||
int
|
||||
main (int argc,
|
||||
char *argv[])
|
||||
{
|
||||
g_type_init ();
|
||||
g_test_init (&argc, &argv, NULL);
|
||||
|
||||
g_test_add_func ("/gdbus/message-serialize-basic", message_serialize_basic);
|
||||
g_test_add_func ("/gdbus/message-serialize-complex", message_serialize_complex);
|
||||
return g_test_run();
|
||||
}
|
||||
|
342
gio/tests/gdbus-sessionbus.c
Normal file
342
gio/tests/gdbus-sessionbus.c
Normal file
@ -0,0 +1,342 @@
|
||||
/* GLib testing framework examples and tests
|
||||
*
|
||||
* Copyright (C) 2008-2010 Red Hat, Inc.
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General
|
||||
* Public License along with this library; if not, write to the
|
||||
* Free Software Foundation, Inc., 59 Temple Place, Suite 330,
|
||||
* Boston, MA 02111-1307, USA.
|
||||
*
|
||||
* Author: David Zeuthen <davidz@redhat.com>
|
||||
*/
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
#include <errno.h>
|
||||
#include <sys/types.h>
|
||||
#include <signal.h>
|
||||
#include <stdio.h>
|
||||
|
||||
#include "gdbus-sessionbus.h"
|
||||
|
||||
/* ---------------------------------------------------------------------------------------------------- */
|
||||
/* Utilities for bringing up and tearing down session message bus instances */
|
||||
|
||||
static void
|
||||
watch_parent (gint fd)
|
||||
{
|
||||
GPollFD fds[1];
|
||||
gint num_events;
|
||||
gchar buf[512];
|
||||
guint bytes_read;
|
||||
GArray *buses_to_kill_array;
|
||||
|
||||
fds[0].fd = fd;
|
||||
fds[0].events = G_IO_HUP | G_IO_IN;
|
||||
fds[0].revents = 0;
|
||||
|
||||
buses_to_kill_array = g_array_new (FALSE, TRUE, sizeof (guint));
|
||||
|
||||
do
|
||||
{
|
||||
guint pid;
|
||||
guint n;
|
||||
|
||||
num_events = g_poll (fds, 1, -1);
|
||||
if (num_events == 0)
|
||||
continue;
|
||||
|
||||
if (fds[0].revents == G_IO_HUP)
|
||||
{
|
||||
for (n = 0; n < buses_to_kill_array->len; n++)
|
||||
{
|
||||
pid = g_array_index (buses_to_kill_array, guint, n);
|
||||
g_print ("cleaning up bus with pid %d\n", pid);
|
||||
kill (pid, SIGTERM);
|
||||
}
|
||||
g_array_free (buses_to_kill_array, TRUE);
|
||||
exit (0);
|
||||
}
|
||||
|
||||
//g_debug ("data from parent");
|
||||
|
||||
memset (buf, '\0', sizeof buf);
|
||||
again:
|
||||
bytes_read = read (fds[0].fd, buf, sizeof buf);
|
||||
if (bytes_read < 0 && (errno == EAGAIN || errno == EINTR))
|
||||
goto again;
|
||||
|
||||
if (sscanf (buf, "add %d\n", &pid) == 1)
|
||||
{
|
||||
g_array_append_val (buses_to_kill_array, pid);
|
||||
}
|
||||
else if (sscanf (buf, "remove %d\n", &pid) == 1)
|
||||
{
|
||||
for (n = 0; n < buses_to_kill_array->len; n++)
|
||||
{
|
||||
if (g_array_index (buses_to_kill_array, guint, n) == pid)
|
||||
{
|
||||
g_array_remove_index (buses_to_kill_array, n);
|
||||
pid = 0;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (pid != 0)
|
||||
{
|
||||
g_warning ("unknown pid %d to remove", pid);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
g_warning ("unknown command from parent '%s'", buf);
|
||||
}
|
||||
}
|
||||
while (TRUE);
|
||||
|
||||
}
|
||||
|
||||
static GHashTable *session_bus_address_to_pid = NULL;
|
||||
static gint pipe_fds[2];
|
||||
|
||||
const gchar *
|
||||
session_bus_up_with_address (const gchar *given_address)
|
||||
{
|
||||
gchar *address;
|
||||
int stdout_fd;
|
||||
GError *error;
|
||||
gchar *argv[] = {"dbus-daemon", "--print-address", "--config-file=foo", NULL};
|
||||
GPid pid;
|
||||
gchar buf[512];
|
||||
ssize_t bytes_read;
|
||||
gchar *config_file_name;
|
||||
gint config_file_fd;
|
||||
GString *config_file_contents;
|
||||
|
||||
address = NULL;
|
||||
error = NULL;
|
||||
config_file_name = NULL;
|
||||
config_file_fd = -1;
|
||||
argv[2] = NULL;
|
||||
|
||||
config_file_fd = g_file_open_tmp ("g-dbus-tests-XXXXXX",
|
||||
&config_file_name,
|
||||
&error);
|
||||
if (config_file_fd < 0)
|
||||
{
|
||||
g_warning ("Error creating temporary config file: %s", error->message);
|
||||
g_error_free (error);
|
||||
goto out;
|
||||
}
|
||||
|
||||
config_file_contents = g_string_new (NULL);
|
||||
g_string_append (config_file_contents, "<busconfig>\n");
|
||||
g_string_append (config_file_contents, " <type>session</type>\n");
|
||||
g_string_append_printf (config_file_contents, " <listen>%s</listen>\n", given_address);
|
||||
g_string_append (config_file_contents,
|
||||
" <policy context=\"default\">\n"
|
||||
" <!-- Allow everything to be sent -->\n"
|
||||
" <allow send_destination=\"*\" eavesdrop=\"true\"/>\n"
|
||||
" <!-- Allow everything to be received -->\n"
|
||||
" <allow eavesdrop=\"true\"/>\n"
|
||||
" <!-- Allow anyone to own anything -->\n"
|
||||
" <allow own=\"*\"/>\n"
|
||||
" </policy>\n");
|
||||
g_string_append (config_file_contents, "</busconfig>\n");
|
||||
|
||||
if (write (config_file_fd, config_file_contents->str, config_file_contents->len) != (gssize) config_file_contents->len)
|
||||
{
|
||||
g_warning ("Error writing %d bytes to config file: %m", (gint) config_file_contents->len);
|
||||
g_string_free (config_file_contents, TRUE);
|
||||
goto out;
|
||||
}
|
||||
g_string_free (config_file_contents, TRUE);
|
||||
|
||||
argv[2] = g_strdup_printf ("--config-file=%s", config_file_name);
|
||||
|
||||
if (session_bus_address_to_pid == NULL)
|
||||
{
|
||||
/* keep a mapping from session bus address to the pid */
|
||||
session_bus_address_to_pid = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, NULL);
|
||||
|
||||
/* fork a child to clean up session buses when we are killed */
|
||||
if (pipe (pipe_fds) != 0)
|
||||
{
|
||||
g_warning ("pipe() failed: %m");
|
||||
g_assert_not_reached ();
|
||||
}
|
||||
switch (fork ())
|
||||
{
|
||||
case -1:
|
||||
g_warning ("fork() failed: %m");
|
||||
g_assert_not_reached ();
|
||||
break;
|
||||
|
||||
case 0:
|
||||
/* child */
|
||||
close (pipe_fds[1]);
|
||||
watch_parent (pipe_fds[0]);
|
||||
break;
|
||||
|
||||
default:
|
||||
/* parent */
|
||||
close (pipe_fds[0]);
|
||||
break;
|
||||
}
|
||||
|
||||
//atexit (cleanup_session_buses);
|
||||
/* TODO: need to handle the cases where we crash */
|
||||
}
|
||||
else
|
||||
{
|
||||
/* check if we already have a bus running for this address */
|
||||
if (g_hash_table_lookup (session_bus_address_to_pid, given_address) != NULL)
|
||||
{
|
||||
g_warning ("Already have a bus instance for the given address %s", given_address);
|
||||
goto out;
|
||||
}
|
||||
}
|
||||
|
||||
if (!g_spawn_async_with_pipes (NULL,
|
||||
argv,
|
||||
NULL,
|
||||
G_SPAWN_SEARCH_PATH,
|
||||
NULL,
|
||||
NULL,
|
||||
&pid,
|
||||
NULL,
|
||||
&stdout_fd,
|
||||
NULL,
|
||||
&error))
|
||||
{
|
||||
g_warning ("Error spawning dbus-daemon: %s", error->message);
|
||||
g_error_free (error);
|
||||
goto out;
|
||||
}
|
||||
|
||||
memset (buf, '\0', sizeof buf);
|
||||
again:
|
||||
bytes_read = read (stdout_fd, buf, sizeof buf);
|
||||
if (bytes_read < 0 && (errno == EAGAIN || errno == EINTR))
|
||||
goto again;
|
||||
close (stdout_fd);
|
||||
|
||||
if (bytes_read == 0 || bytes_read == sizeof buf)
|
||||
{
|
||||
g_warning ("Error reading address from dbus daemon, %d bytes read", (gint) bytes_read);
|
||||
kill (SIGTERM, pid);
|
||||
goto out;
|
||||
}
|
||||
|
||||
address = g_strdup (buf);
|
||||
g_strstrip (address);
|
||||
|
||||
/* write the pid to the child so it can kill it when we die */
|
||||
g_snprintf (buf, sizeof buf, "add %d\n", (guint) pid);
|
||||
write (pipe_fds[1], buf, strlen (buf));
|
||||
|
||||
/* start dbus-monitor */
|
||||
if (g_getenv ("G_DBUS_MONITOR") != NULL)
|
||||
{
|
||||
g_spawn_command_line_async ("dbus-monitor --session", NULL);
|
||||
usleep (500 * 1000);
|
||||
}
|
||||
|
||||
g_hash_table_insert (session_bus_address_to_pid, address, GUINT_TO_POINTER (pid));
|
||||
|
||||
out:
|
||||
if (config_file_fd > 0)
|
||||
{
|
||||
if (close (config_file_fd) != 0)
|
||||
{
|
||||
g_warning ("Error closing fd for config file %s: %m", config_file_name);
|
||||
}
|
||||
g_assert (config_file_name != NULL);
|
||||
if (unlink (config_file_name) != 0)
|
||||
{
|
||||
g_warning ("Error unlinking config file %s: %m", config_file_name);
|
||||
}
|
||||
}
|
||||
g_free (argv[2]);
|
||||
g_free (config_file_name);
|
||||
return address;
|
||||
}
|
||||
|
||||
void
|
||||
session_bus_down_with_address (const gchar *address)
|
||||
{
|
||||
gpointer value;
|
||||
GPid pid;
|
||||
gchar buf[512];
|
||||
|
||||
g_assert (address != NULL);
|
||||
g_assert (session_bus_address_to_pid != NULL);
|
||||
|
||||
value = g_hash_table_lookup (session_bus_address_to_pid, address);
|
||||
g_assert (value != NULL);
|
||||
|
||||
pid = GPOINTER_TO_UINT (g_hash_table_lookup (session_bus_address_to_pid, address));
|
||||
|
||||
kill (pid, SIGTERM);
|
||||
|
||||
/* write the pid to the child so it won't kill it when we die */
|
||||
g_snprintf (buf, sizeof buf, "remove %d\n", (guint) pid);
|
||||
write (pipe_fds[1], buf, strlen (buf));
|
||||
|
||||
g_hash_table_remove (session_bus_address_to_pid, address);
|
||||
}
|
||||
|
||||
static gchar *temporary_address = NULL;
|
||||
static gchar *temporary_address_used_by_bus = NULL;
|
||||
|
||||
const gchar *
|
||||
session_bus_get_temporary_address (void)
|
||||
{
|
||||
if (temporary_address == NULL)
|
||||
{
|
||||
/* TODO: maybe use a more random name etc etc */
|
||||
temporary_address = g_strdup_printf ("unix:path=/tmp/g-dbus-tests-pid-%d", getpid ());
|
||||
}
|
||||
|
||||
return temporary_address;
|
||||
}
|
||||
|
||||
const gchar *
|
||||
session_bus_up (void)
|
||||
{
|
||||
if (temporary_address_used_by_bus != NULL)
|
||||
{
|
||||
g_warning ("There is already a session bus up");
|
||||
goto out;
|
||||
}
|
||||
|
||||
temporary_address_used_by_bus = g_strdup (session_bus_up_with_address (session_bus_get_temporary_address ()));
|
||||
|
||||
out:
|
||||
return temporary_address_used_by_bus;
|
||||
}
|
||||
|
||||
void
|
||||
session_bus_down (void)
|
||||
{
|
||||
if (temporary_address_used_by_bus == NULL)
|
||||
{
|
||||
g_warning ("There is not a session bus up");
|
||||
}
|
||||
else
|
||||
{
|
||||
session_bus_down_with_address (temporary_address_used_by_bus);
|
||||
g_free (temporary_address_used_by_bus);
|
||||
temporary_address_used_by_bus = NULL;
|
||||
}
|
||||
}
|
38
gio/tests/gdbus-sessionbus.h
Normal file
38
gio/tests/gdbus-sessionbus.h
Normal file
@ -0,0 +1,38 @@
|
||||
/* GLib testing framework examples and tests
|
||||
*
|
||||
* Copyright (C) 2008-2009 Red Hat, Inc.
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General
|
||||
* Public License along with this library; if not, write to the
|
||||
* Free Software Foundation, Inc., 59 Temple Place, Suite 330,
|
||||
* Boston, MA 02111-1307, USA.
|
||||
*
|
||||
* Author: David Zeuthen <davidz@redhat.com>
|
||||
*/
|
||||
|
||||
#ifndef __SESSION_BUS_H__
|
||||
#define __SESSION_BUS_H__
|
||||
|
||||
#include <gio/gio.h>
|
||||
|
||||
G_BEGIN_DECLS
|
||||
|
||||
const gchar *session_bus_up_with_address (const gchar *given_address);
|
||||
void session_bus_down_with_address (const gchar *address);
|
||||
const gchar *session_bus_get_temporary_address (void);
|
||||
const gchar *session_bus_up (void);
|
||||
void session_bus_down (void);
|
||||
|
||||
G_END_DECLS
|
||||
|
||||
#endif /* __SESSION_BUS_H__ */
|
219
gio/tests/gdbus-tests.c
Normal file
219
gio/tests/gdbus-tests.c
Normal file
@ -0,0 +1,219 @@
|
||||
/* GLib testing framework examples and tests
|
||||
*
|
||||
* Copyright (C) 2008-2010 Red Hat, Inc.
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General
|
||||
* Public License along with this library; if not, write to the
|
||||
* Free Software Foundation, Inc., 59 Temple Place, Suite 330,
|
||||
* Boston, MA 02111-1307, USA.
|
||||
*
|
||||
* Author: David Zeuthen <davidz@redhat.com>
|
||||
*/
|
||||
|
||||
#include <gio/gio.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include "gdbus-tests.h"
|
||||
|
||||
/* ---------------------------------------------------------------------------------------------------- */
|
||||
|
||||
typedef struct
|
||||
{
|
||||
GMainLoop *loop;
|
||||
gboolean timed_out;
|
||||
} PropertyNotifyData;
|
||||
|
||||
static void
|
||||
on_property_notify (GObject *object,
|
||||
GParamSpec *pspec,
|
||||
gpointer user_data)
|
||||
{
|
||||
PropertyNotifyData *data = user_data;
|
||||
g_main_loop_quit (data->loop);
|
||||
}
|
||||
|
||||
static gboolean
|
||||
on_property_notify_timeout (gpointer user_data)
|
||||
{
|
||||
PropertyNotifyData *data = user_data;
|
||||
data->timed_out = TRUE;
|
||||
g_main_loop_quit (data->loop);
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
gboolean
|
||||
_g_assert_property_notify_run (gpointer object,
|
||||
const gchar *property_name)
|
||||
{
|
||||
gchar *s;
|
||||
gulong handler_id;
|
||||
guint timeout_id;
|
||||
PropertyNotifyData data;
|
||||
|
||||
data.loop = g_main_loop_new (NULL, FALSE);
|
||||
data.timed_out = FALSE;
|
||||
s = g_strdup_printf ("notify::%s", property_name);
|
||||
handler_id = g_signal_connect (object,
|
||||
s,
|
||||
G_CALLBACK (on_property_notify),
|
||||
&data);
|
||||
g_free (s);
|
||||
timeout_id = g_timeout_add (5 * 1000,
|
||||
on_property_notify_timeout,
|
||||
&data);
|
||||
g_main_loop_run (data.loop);
|
||||
g_signal_handler_disconnect (object, handler_id);
|
||||
g_source_remove (timeout_id);
|
||||
g_main_loop_unref (data.loop);
|
||||
|
||||
return data.timed_out;
|
||||
}
|
||||
|
||||
/* ---------------------------------------------------------------------------------------------------- */
|
||||
|
||||
typedef struct
|
||||
{
|
||||
GMainLoop *loop;
|
||||
gboolean timed_out;
|
||||
} SignalReceivedData;
|
||||
|
||||
static void
|
||||
on_signal_received (gpointer user_data)
|
||||
{
|
||||
SignalReceivedData *data = user_data;
|
||||
g_main_loop_quit (data->loop);
|
||||
}
|
||||
|
||||
static gboolean
|
||||
on_signal_received_timeout (gpointer user_data)
|
||||
{
|
||||
SignalReceivedData *data = user_data;
|
||||
data->timed_out = TRUE;
|
||||
g_main_loop_quit (data->loop);
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
gboolean
|
||||
_g_assert_signal_received_run (gpointer object,
|
||||
const gchar *signal_name)
|
||||
{
|
||||
gulong handler_id;
|
||||
guint timeout_id;
|
||||
SignalReceivedData data;
|
||||
|
||||
data.loop = g_main_loop_new (NULL, FALSE);
|
||||
data.timed_out = FALSE;
|
||||
handler_id = g_signal_connect_swapped (object,
|
||||
signal_name,
|
||||
G_CALLBACK (on_signal_received),
|
||||
&data);
|
||||
timeout_id = g_timeout_add (5 * 1000,
|
||||
on_signal_received_timeout,
|
||||
&data);
|
||||
g_main_loop_run (data.loop);
|
||||
g_signal_handler_disconnect (object, handler_id);
|
||||
g_source_remove (timeout_id);
|
||||
g_main_loop_unref (data.loop);
|
||||
|
||||
return data.timed_out;
|
||||
}
|
||||
|
||||
/* ---------------------------------------------------------------------------------------------------- */
|
||||
|
||||
GDBusConnection *
|
||||
_g_bus_get_priv (GBusType bus_type,
|
||||
GCancellable *cancellable,
|
||||
GError **error)
|
||||
{
|
||||
gchar *address;
|
||||
GDBusConnection *ret;
|
||||
|
||||
ret = NULL;
|
||||
|
||||
address = g_dbus_address_get_for_bus_sync (bus_type, cancellable, error);
|
||||
if (address == NULL)
|
||||
goto out;
|
||||
|
||||
ret = g_dbus_connection_new_for_address_sync (address,
|
||||
G_DBUS_CONNECTION_FLAGS_AUTHENTICATION_CLIENT |
|
||||
G_DBUS_CONNECTION_FLAGS_MESSAGE_BUS_CONNECTION,
|
||||
NULL, /* GDBusAuthObserver */
|
||||
cancellable,
|
||||
error);
|
||||
g_free (address);
|
||||
|
||||
out:
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* ---------------------------------------------------------------------------------------------------- */
|
||||
|
||||
typedef struct
|
||||
{
|
||||
GMainLoop *loop;
|
||||
gboolean timed_out;
|
||||
} WaitSingleRefData;
|
||||
|
||||
static gboolean
|
||||
on_wait_single_ref_timeout (gpointer user_data)
|
||||
{
|
||||
WaitSingleRefData *data = user_data;
|
||||
data->timed_out = TRUE;
|
||||
g_main_loop_quit (data->loop);
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static void
|
||||
on_wait_for_single_ref_toggled (gpointer user_data,
|
||||
GObject *object,
|
||||
gboolean is_last_ref)
|
||||
{
|
||||
WaitSingleRefData *data = user_data;
|
||||
g_main_loop_quit (data->loop);
|
||||
}
|
||||
|
||||
gboolean
|
||||
_g_object_wait_for_single_ref_do (gpointer object)
|
||||
{
|
||||
WaitSingleRefData data;
|
||||
guint timeout_id;
|
||||
|
||||
data.timed_out = FALSE;
|
||||
|
||||
if (G_OBJECT (object)->ref_count == 1)
|
||||
goto out;
|
||||
|
||||
data.loop = g_main_loop_new (NULL, FALSE);
|
||||
timeout_id = g_timeout_add (5 * 1000,
|
||||
on_wait_single_ref_timeout,
|
||||
&data);
|
||||
|
||||
g_object_add_toggle_ref (G_OBJECT (object),
|
||||
on_wait_for_single_ref_toggled,
|
||||
&data);
|
||||
g_object_unref (object);
|
||||
|
||||
g_main_loop_run (data.loop);
|
||||
|
||||
g_object_ref (object);
|
||||
g_object_remove_toggle_ref (object,
|
||||
on_wait_for_single_ref_toggled,
|
||||
&data);
|
||||
|
||||
g_source_remove (timeout_id);
|
||||
g_main_loop_unref (data.loop);
|
||||
out:
|
||||
return data.timed_out;
|
||||
}
|
||||
|
||||
/* ---------------------------------------------------------------------------------------------------- */
|
146
gio/tests/gdbus-tests.h
Normal file
146
gio/tests/gdbus-tests.h
Normal file
@ -0,0 +1,146 @@
|
||||
/* GLib testing framework examples and tests
|
||||
*
|
||||
* Copyright (C) 2008-2009 Red Hat, Inc.
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General
|
||||
* Public License along with this library; if not, write to the
|
||||
* Free Software Foundation, Inc., 59 Temple Place, Suite 330,
|
||||
* Boston, MA 02111-1307, USA.
|
||||
*
|
||||
* Author: David Zeuthen <davidz@redhat.com>
|
||||
*/
|
||||
|
||||
#ifndef __TESTS_H__
|
||||
#define __TESTS_H__
|
||||
|
||||
#include <gio/gio.h>
|
||||
#include "gdbus-sessionbus.h"
|
||||
|
||||
G_BEGIN_DECLS
|
||||
|
||||
/* TODO: clean up and move to gtestutils.c
|
||||
*
|
||||
* This is needed because libdbus-1 does not give predictable error messages - e.g. you
|
||||
* get a different error message on connecting to a bus if the socket file is there vs
|
||||
* if the socket file is missing.
|
||||
*/
|
||||
|
||||
#define _g_assert_error_domain(err, dom) do { if (!err || (err)->domain != dom) \
|
||||
g_assertion_message_error (G_LOG_DOMAIN, __FILE__, __LINE__, G_STRFUNC, \
|
||||
#err, err, dom, -1); } while (0)
|
||||
|
||||
#define _g_assert_property_notify(object, property_name) \
|
||||
do \
|
||||
{ \
|
||||
if (!G_IS_OBJECT (object)) \
|
||||
{ \
|
||||
g_assertion_message (G_LOG_DOMAIN, \
|
||||
__FILE__, \
|
||||
__LINE__, \
|
||||
G_STRFUNC, \
|
||||
"Not a GObject instance"); \
|
||||
} \
|
||||
if (g_object_class_find_property (G_OBJECT_GET_CLASS (object), \
|
||||
property_name) == NULL) \
|
||||
{ \
|
||||
g_assertion_message (G_LOG_DOMAIN, \
|
||||
__FILE__, \
|
||||
__LINE__, \
|
||||
G_STRFUNC, \
|
||||
"Property " property_name " does not " \
|
||||
"exist on object"); \
|
||||
} \
|
||||
if (_g_assert_property_notify_run (object, property_name)) \
|
||||
{ \
|
||||
g_assertion_message (G_LOG_DOMAIN, \
|
||||
__FILE__, \
|
||||
__LINE__, \
|
||||
G_STRFUNC, \
|
||||
"Timed out waiting for notification " \
|
||||
"on property " property_name); \
|
||||
} \
|
||||
} \
|
||||
while (FALSE)
|
||||
|
||||
#define _g_assert_signal_received(object, signal_name) \
|
||||
do \
|
||||
{ \
|
||||
if (!G_IS_OBJECT (object)) \
|
||||
{ \
|
||||
g_assertion_message (G_LOG_DOMAIN, \
|
||||
__FILE__, \
|
||||
__LINE__, \
|
||||
G_STRFUNC, \
|
||||
"Not a GObject instance"); \
|
||||
} \
|
||||
if (g_signal_lookup (signal_name, \
|
||||
G_TYPE_FROM_INSTANCE (object)) == 0) \
|
||||
{ \
|
||||
g_assertion_message (G_LOG_DOMAIN, \
|
||||
__FILE__, \
|
||||
__LINE__, \
|
||||
G_STRFUNC, \
|
||||
"Signal `" signal_name "' does not " \
|
||||
"exist on object"); \
|
||||
} \
|
||||
if (_g_assert_signal_received_run (object, signal_name)) \
|
||||
{ \
|
||||
g_assertion_message (G_LOG_DOMAIN, \
|
||||
__FILE__, \
|
||||
__LINE__, \
|
||||
G_STRFUNC, \
|
||||
"Timed out waiting for signal `" \
|
||||
signal_name "'"); \
|
||||
} \
|
||||
} \
|
||||
while (FALSE)
|
||||
|
||||
gboolean _g_assert_property_notify_run (gpointer object,
|
||||
const gchar *property_name);
|
||||
|
||||
|
||||
gboolean _g_assert_signal_received_run (gpointer object,
|
||||
const gchar *signal_name);
|
||||
|
||||
GDBusConnection *_g_bus_get_priv (GBusType bus_type,
|
||||
GCancellable *cancellable,
|
||||
GError **error);
|
||||
|
||||
|
||||
#define _g_object_wait_for_single_ref(object) \
|
||||
do \
|
||||
{ \
|
||||
if (!G_IS_OBJECT (object)) \
|
||||
{ \
|
||||
g_assertion_message (G_LOG_DOMAIN, \
|
||||
__FILE__, \
|
||||
__LINE__, \
|
||||
G_STRFUNC, \
|
||||
"Not a GObject instance"); \
|
||||
} \
|
||||
if (_g_object_wait_for_single_ref_do (object)) \
|
||||
{ \
|
||||
g_assertion_message (G_LOG_DOMAIN, \
|
||||
__FILE__, \
|
||||
__LINE__, \
|
||||
G_STRFUNC, \
|
||||
"Timed out waiting for single ref"); \
|
||||
} \
|
||||
} \
|
||||
while (FALSE)
|
||||
|
||||
gboolean _g_object_wait_for_single_ref_do (gpointer object);
|
||||
|
||||
G_END_DECLS
|
||||
|
||||
#endif /* __TESTS_H__ */
|
271
gio/tests/gdbus-testserver.py
Executable file
271
gio/tests/gdbus-testserver.py
Executable file
@ -0,0 +1,271 @@
|
||||
#!/usr/bin/env python
|
||||
|
||||
import gobject
|
||||
import time
|
||||
|
||||
import dbus
|
||||
import dbus.service
|
||||
import dbus.mainloop.glib
|
||||
|
||||
class TestException(dbus.DBusException):
|
||||
_dbus_error_name = 'com.example.TestException'
|
||||
|
||||
|
||||
class TestService(dbus.service.Object):
|
||||
|
||||
# ----------------------------------------------------------------------------------------------------
|
||||
|
||||
@dbus.service.method("com.example.Frob",
|
||||
in_signature='s', out_signature='s')
|
||||
def HelloWorld(self, hello_message):
|
||||
if str(hello_message) == 'Yo':
|
||||
raise TestException('Yo is not a proper greeting')
|
||||
else:
|
||||
return "You greeted me with '%s'. Thanks!"%(str(hello_message))
|
||||
|
||||
@dbus.service.method("com.example.Frob",
|
||||
in_signature='ss', out_signature='ss')
|
||||
def DoubleHelloWorld(self, hello1, hello2):
|
||||
return ("You greeted me with '%s'. Thanks!"%(str(hello1)), "Yo dawg, you uttered '%s'. Thanks!"%(str(hello2)))
|
||||
|
||||
@dbus.service.method("com.example.Frob",
|
||||
in_signature='', out_signature='su')
|
||||
def PairReturn(self):
|
||||
return ("foo", 42)
|
||||
|
||||
# ----------------------------------------------------------------------------------------------------
|
||||
|
||||
@dbus.service.method("com.example.Frob",
|
||||
in_signature='ybnqiuxtdsog', out_signature='ybnqiuxtdsog')
|
||||
def TestPrimitiveTypes(self, val_byte, val_boolean, val_int16, val_uint16, val_int32, val_uint32, val_int64, val_uint64, val_double, val_string, val_objpath, val_signature):
|
||||
return val_byte + 1, not val_boolean, val_int16 + 1, val_uint16 + 1, val_int32 + 1, val_uint32 + 1, val_int64 + 1, val_uint64 + 1, -val_double + 0.123, val_string * 2, val_objpath + "/modified", val_signature * 2
|
||||
|
||||
# ----------------------------------------------------------------------------------------------------
|
||||
|
||||
@dbus.service.method("com.example.Frob",
|
||||
in_signature='ayabanaqaiauaxatad', out_signature='ayabanaqaiauaxatad')
|
||||
def TestArrayOfPrimitiveTypes(self, val_byte, val_boolean, val_int16, val_uint16, val_int32, val_uint32, val_int64, val_uint64, val_double):
|
||||
return val_byte*2, val_boolean*2, val_int16*2, val_uint16*2, val_int32*2, val_uint32*2, val_int64*2, val_uint64*2, val_double*2
|
||||
|
||||
# ----------------------------------------------------------------------------------------------------
|
||||
|
||||
@dbus.service.method("com.example.Frob",
|
||||
in_signature='asaoag', out_signature='asaoag')
|
||||
def TestArrayOfStringTypes(self, val_string, val_objpath, val_signature):
|
||||
return val_string * 2, val_objpath * 2, val_signature * 2
|
||||
|
||||
# ----------------------------------------------------------------------------------------------------
|
||||
|
||||
@dbus.service.method("com.example.Frob",
|
||||
in_signature = 'a{yy}a{bb}a{nn}a{qq}a{ii}a{uu}a{xx}a{tt}a{dd}a{ss}a{oo}a{gg}',
|
||||
out_signature = 'a{yy}a{bb}a{nn}a{qq}a{ii}a{uu}a{xx}a{tt}a{dd}a{ss}a{oo}a{gg}')
|
||||
def TestHashTables(self, hyy, hbb, hnn, hqq, hii, huu, hxx, htt, hdd, hss, hoo, hgg):
|
||||
|
||||
ret_hyy = {}
|
||||
for i in hyy:
|
||||
ret_hyy[i*2] = (hyy[i]*3) & 255
|
||||
|
||||
ret_hbb = {}
|
||||
for i in hbb:
|
||||
ret_hbb[i] = True
|
||||
|
||||
ret_hnn = {}
|
||||
for i in hnn:
|
||||
ret_hnn[i*2] = hnn[i]*3
|
||||
|
||||
ret_hqq = {}
|
||||
for i in hqq:
|
||||
ret_hqq[i*2] = hqq[i]*3
|
||||
|
||||
ret_hii = {}
|
||||
for i in hii:
|
||||
ret_hii[i*2] = hii[i]*3
|
||||
|
||||
ret_huu = {}
|
||||
for i in huu:
|
||||
ret_huu[i*2] = huu[i]*3
|
||||
|
||||
ret_hxx = {}
|
||||
for i in hxx:
|
||||
ret_hxx[i + 2] = hxx[i] + 1
|
||||
|
||||
ret_htt = {}
|
||||
for i in htt:
|
||||
ret_htt[i + 2] = htt[i] + 1
|
||||
|
||||
ret_hdd = {}
|
||||
for i in hdd:
|
||||
ret_hdd[i + 2.5] = hdd[i] + 5.0
|
||||
|
||||
ret_hss = {}
|
||||
for i in hss:
|
||||
ret_hss[i + "mod"] = hss[i]*2
|
||||
|
||||
ret_hoo = {}
|
||||
for i in hoo:
|
||||
ret_hoo[i + "/mod"] = hoo[i] + "/mod2"
|
||||
|
||||
ret_hgg = {}
|
||||
for i in hgg:
|
||||
ret_hgg[i + "assgit"] = hgg[i]*2
|
||||
|
||||
return ret_hyy, ret_hbb, ret_hnn, ret_hqq, ret_hii, ret_huu, ret_hxx, ret_htt, ret_hdd, ret_hss, ret_hoo, ret_hgg
|
||||
|
||||
# ----------------------------------------------------------------------------------------------------
|
||||
|
||||
@dbus.service.method("com.example.Frob",
|
||||
in_signature='(ii)(s(ii)aya{ss})', out_signature='(ii)(s(ii)aya{ss})')
|
||||
def TestStructureTypes(self, s1, s2):
|
||||
(x, y) = s1;
|
||||
(desc, (x1, y1), ay, hss) = s2;
|
||||
ret_hss = {}
|
||||
for i in hss:
|
||||
ret_hss[i] = hss[i] + " ... in bed!"
|
||||
return (x + 1, y + 1), (desc + " ... in bed!", (x1 + 2, y1 + 2), ay * 2, ret_hss)
|
||||
|
||||
# ----------------------------------------------------------------------------------------------------
|
||||
|
||||
@dbus.service.method("com.example.Frob",
|
||||
in_signature='vb', out_signature='v')
|
||||
def TestVariant(self, v, modify):
|
||||
|
||||
if modify:
|
||||
if type(v)==dbus.Boolean:
|
||||
ret = False
|
||||
elif type(v)==dbus.Dictionary:
|
||||
ret = {}
|
||||
for i in v:
|
||||
ret[i] = v[i] * 2
|
||||
elif type(v)==dbus.Struct:
|
||||
ret = ["other struct", dbus.Int16(100)]
|
||||
else:
|
||||
ret = v * 2
|
||||
else:
|
||||
ret = v
|
||||
return (type(v))(ret)
|
||||
|
||||
# ----------------------------------------------------------------------------------------------------
|
||||
|
||||
@dbus.service.method("com.example.Frob",
|
||||
in_signature='a(ii)aa(ii)aasaa{ss}aayavaav', out_signature='a(ii)aa(ii)aasaa{ss}aayavaav')
|
||||
def TestComplexArrays(self, aii, aaii, aas, ahashes, aay, av, aav):
|
||||
return aii * 2, aaii * 2, aas * 2, ahashes * 2, aay * 2, av *2, aav * 2
|
||||
|
||||
# ----------------------------------------------------------------------------------------------------
|
||||
|
||||
@dbus.service.method("com.example.Frob",
|
||||
in_signature='a{s(ii)}a{sv}a{sav}a{saav}a{sa(ii)}a{sa{ss}}',
|
||||
out_signature='a{s(ii)}a{sv}a{sav}a{saav}a{sa(ii)}a{sa{ss}}')
|
||||
def TestComplexHashTables(self, h_str_to_pair, h_str_to_variant, h_str_to_av, h_str_to_aav,
|
||||
h_str_to_array_of_pairs, hash_of_hashes):
|
||||
|
||||
ret_h_str_to_pair = {}
|
||||
for i in h_str_to_pair:
|
||||
ret_h_str_to_pair[i + "_baz"] = h_str_to_pair[i]
|
||||
|
||||
ret_h_str_to_variant = {}
|
||||
for i in h_str_to_variant:
|
||||
ret_h_str_to_variant[i + "_baz"] = h_str_to_variant[i]
|
||||
|
||||
return ret_h_str_to_pair, ret_h_str_to_variant, h_str_to_av, h_str_to_aav, h_str_to_array_of_pairs, hash_of_hashes
|
||||
|
||||
# ----------------------------------------------------------------------------------------------------
|
||||
|
||||
@dbus.service.method("com.example.Frob",
|
||||
in_signature='', out_signature='')
|
||||
def Quit(self):
|
||||
mainloop.quit()
|
||||
|
||||
# ----------------------------------------------------------------------------------------------------
|
||||
|
||||
@dbus.service.method("com.example.Frob",
|
||||
in_signature='sv', out_signature='')
|
||||
def FrobSetProperty(self, prop_name, prop_value):
|
||||
self.frob_props[prop_name] = prop_value
|
||||
message = dbus.lowlevel.SignalMessage("/com/example/TestObject",
|
||||
"org.freedesktop.DBus.Properties",
|
||||
"PropertiesChanged")
|
||||
message.append("com.example.Frob")
|
||||
message.append({prop_name : prop_value})
|
||||
message.append([], signature="as")
|
||||
session_bus.send_message(message)
|
||||
# ----------------------------------------------------------------------------------------------------
|
||||
|
||||
@dbus.service.signal("com.example.Frob",
|
||||
signature="sov")
|
||||
def TestSignal(self, str1, objpath1, variant1):
|
||||
pass
|
||||
|
||||
@dbus.service.method("com.example.Frob",
|
||||
in_signature='so', out_signature='')
|
||||
def EmitSignal(self, str1, objpath1):
|
||||
self.TestSignal (str1 + " .. in bed!", objpath1 + "/in/bed", "a variant")
|
||||
|
||||
# ----------------------------------------------------------------------------------------------------
|
||||
|
||||
@dbus.service.method("com.example.Frob", in_signature='i', out_signature='',
|
||||
async_callbacks=('return_cb', 'raise_cb'))
|
||||
def Sleep(self, msec, return_cb, raise_cb):
|
||||
def return_from_async_wait():
|
||||
return_cb()
|
||||
return False
|
||||
gobject.timeout_add(msec, return_from_async_wait)
|
||||
|
||||
# ----------------------------------------------------------------------------------------------------
|
||||
|
||||
@dbus.service.method("org.freedesktop.DBus.Properties",
|
||||
in_signature = 'ss',
|
||||
out_signature = 'v')
|
||||
def Get(self, interface_name, property_name):
|
||||
|
||||
if interface_name == "com.example.Frob":
|
||||
return self.frob_props[property_name]
|
||||
else:
|
||||
raise TestException("No such interface " + interface_name)
|
||||
|
||||
@dbus.service.method("org.freedesktop.DBus.Properties",
|
||||
in_signature = 's',
|
||||
out_signature = 'a{sv}')
|
||||
def GetAll(self, interface_name):
|
||||
if interface_name == "com.example.Frob":
|
||||
return self.frob_props
|
||||
else:
|
||||
raise TestException("No such interface " + interface_name)
|
||||
|
||||
if __name__ == '__main__':
|
||||
dbus.mainloop.glib.DBusGMainLoop(set_as_default=True)
|
||||
|
||||
session_bus = dbus.SessionBus()
|
||||
name = dbus.service.BusName("com.example.TestService", session_bus)
|
||||
|
||||
obj = TestService(session_bus, '/com/example/TestObject')
|
||||
|
||||
#print "Our unique name is %s"%(session_bus.get_unique_name())
|
||||
|
||||
obj.frob_props = {}
|
||||
obj.frob_props["y"] = dbus.Byte(1)
|
||||
obj.frob_props["b"] = dbus.Boolean(True)
|
||||
obj.frob_props["n"] = dbus.Int16(2)
|
||||
obj.frob_props["q"] = dbus.UInt16(3)
|
||||
obj.frob_props["i"] = dbus.Int32(4)
|
||||
obj.frob_props["u"] = dbus.UInt32(5)
|
||||
obj.frob_props["x"] = dbus.Int64(6)
|
||||
obj.frob_props["t"] = dbus.UInt64(7)
|
||||
obj.frob_props["d"] = dbus.Double(7.5)
|
||||
obj.frob_props["s"] = dbus.String("a string")
|
||||
obj.frob_props["o"] = dbus.ObjectPath("/some/path")
|
||||
obj.frob_props["ay"] = [dbus.Byte(1), dbus.Byte(11)]
|
||||
obj.frob_props["ab"] = [dbus.Boolean(True), dbus.Boolean(False)]
|
||||
obj.frob_props["an"] = [dbus.Int16(2), dbus.Int16(12)]
|
||||
obj.frob_props["aq"] = [dbus.UInt16(3), dbus.UInt16(13)]
|
||||
obj.frob_props["ai"] = [dbus.Int32(4), dbus.Int32(14)]
|
||||
obj.frob_props["au"] = [dbus.UInt32(5), dbus.UInt32(15)]
|
||||
obj.frob_props["ax"] = [dbus.Int64(6), dbus.Int64(16)]
|
||||
obj.frob_props["at"] = [dbus.UInt64(7), dbus.UInt64(17)]
|
||||
obj.frob_props["ad"] = [dbus.Double(7.5), dbus.Double(17.5)]
|
||||
obj.frob_props["as"] = [dbus.String("a string"), dbus.String("another string")]
|
||||
obj.frob_props["ao"] = [dbus.ObjectPath("/some/path"), dbus.ObjectPath("/another/path")]
|
||||
obj.frob_props["foo"] = "a frobbed string"
|
||||
|
||||
mainloop = gobject.MainLoop()
|
||||
mainloop.run()
|
532
gio/tests/gdbus-threading.c
Normal file
532
gio/tests/gdbus-threading.c
Normal file
@ -0,0 +1,532 @@
|
||||
/* GLib testing framework examples and tests
|
||||
*
|
||||
* Copyright (C) 2008-2010 Red Hat, Inc.
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General
|
||||
* Public License along with this library; if not, write to the
|
||||
* Free Software Foundation, Inc., 59 Temple Place, Suite 330,
|
||||
* Boston, MA 02111-1307, USA.
|
||||
*
|
||||
* Author: David Zeuthen <davidz@redhat.com>
|
||||
*/
|
||||
|
||||
#include <gio/gio.h>
|
||||
#include <unistd.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "gdbus-tests.h"
|
||||
|
||||
/* all tests rely on a global connection */
|
||||
static GDBusConnection *c = NULL;
|
||||
|
||||
/* all tests rely on a shared mainloop */
|
||||
static GMainLoop *loop = NULL;
|
||||
|
||||
/* ---------------------------------------------------------------------------------------------------- */
|
||||
/* Ensure that signal and method replies are delivered in the right thread */
|
||||
/* ---------------------------------------------------------------------------------------------------- */
|
||||
|
||||
typedef struct {
|
||||
GThread *thread;
|
||||
GMainLoop *thread_loop;
|
||||
guint signal_count;
|
||||
} DeliveryData;
|
||||
|
||||
static void
|
||||
msg_cb_expect_success (GDBusConnection *connection,
|
||||
GAsyncResult *res,
|
||||
gpointer user_data)
|
||||
{
|
||||
DeliveryData *data = user_data;
|
||||
GError *error;
|
||||
GVariant *result;
|
||||
|
||||
error = NULL;
|
||||
result = g_dbus_connection_call_finish (connection,
|
||||
res,
|
||||
&error);
|
||||
g_assert_no_error (error);
|
||||
g_assert (result != NULL);
|
||||
g_variant_unref (result);
|
||||
|
||||
g_assert (g_thread_self () == data->thread);
|
||||
|
||||
g_main_loop_quit (data->thread_loop);
|
||||
}
|
||||
|
||||
static void
|
||||
msg_cb_expect_error_cancelled (GDBusConnection *connection,
|
||||
GAsyncResult *res,
|
||||
gpointer user_data)
|
||||
{
|
||||
DeliveryData *data = user_data;
|
||||
GError *error;
|
||||
GVariant *result;
|
||||
|
||||
error = NULL;
|
||||
result = g_dbus_connection_call_finish (connection,
|
||||
res,
|
||||
&error);
|
||||
g_assert_error (error, G_IO_ERROR, G_IO_ERROR_CANCELLED);
|
||||
g_assert (!g_dbus_error_is_remote_error (error));
|
||||
g_error_free (error);
|
||||
g_assert (result == NULL);
|
||||
|
||||
g_assert (g_thread_self () == data->thread);
|
||||
|
||||
g_main_loop_quit (data->thread_loop);
|
||||
}
|
||||
|
||||
static void
|
||||
signal_handler (GDBusConnection *connection,
|
||||
const gchar *sender_name,
|
||||
const gchar *object_path,
|
||||
const gchar *interface_name,
|
||||
const gchar *signal_name,
|
||||
GVariant *parameters,
|
||||
gpointer user_data)
|
||||
{
|
||||
DeliveryData *data = user_data;
|
||||
|
||||
g_assert (g_thread_self () == data->thread);
|
||||
|
||||
data->signal_count++;
|
||||
|
||||
g_main_loop_quit (data->thread_loop);
|
||||
}
|
||||
|
||||
static gpointer
|
||||
test_delivery_in_thread_func (gpointer _data)
|
||||
{
|
||||
GMainLoop *thread_loop;
|
||||
GMainContext *thread_context;
|
||||
DeliveryData data;
|
||||
GCancellable *ca;
|
||||
guint subscription_id;
|
||||
GDBusConnection *priv_c;
|
||||
GError *error;
|
||||
|
||||
error = NULL;
|
||||
|
||||
thread_context = g_main_context_new ();
|
||||
thread_loop = g_main_loop_new (thread_context, FALSE);
|
||||
g_main_context_push_thread_default (thread_context);
|
||||
|
||||
data.thread = g_thread_self ();
|
||||
data.thread_loop = thread_loop;
|
||||
data.signal_count = 0;
|
||||
|
||||
/* ---------------------------------------------------------------------------------------------------- */
|
||||
|
||||
/*
|
||||
* Check that we get a reply to the GetId() method call.
|
||||
*/
|
||||
g_dbus_connection_call (c,
|
||||
"org.freedesktop.DBus", /* bus_name */
|
||||
"/org/freedesktop/DBus", /* object path */
|
||||
"org.freedesktop.DBus", /* interface name */
|
||||
"GetId", /* method name */
|
||||
NULL,
|
||||
G_DBUS_CALL_FLAGS_NONE,
|
||||
-1,
|
||||
NULL,
|
||||
(GAsyncReadyCallback) msg_cb_expect_success,
|
||||
&data);
|
||||
g_main_loop_run (thread_loop);
|
||||
|
||||
/*
|
||||
* Check that we never actually send a message if the GCancellable
|
||||
* is already cancelled - i.e. we should get #G_IO_ERROR_CANCELLED
|
||||
* when the actual connection is not up.
|
||||
*/
|
||||
ca = g_cancellable_new ();
|
||||
g_cancellable_cancel (ca);
|
||||
g_dbus_connection_call (c,
|
||||
"org.freedesktop.DBus", /* bus_name */
|
||||
"/org/freedesktop/DBus", /* object path */
|
||||
"org.freedesktop.DBus", /* interface name */
|
||||
"GetId", /* method name */
|
||||
NULL,
|
||||
G_DBUS_CALL_FLAGS_NONE,
|
||||
-1,
|
||||
ca,
|
||||
(GAsyncReadyCallback) msg_cb_expect_error_cancelled,
|
||||
&data);
|
||||
g_main_loop_run (thread_loop);
|
||||
g_object_unref (ca);
|
||||
|
||||
/*
|
||||
* Check that cancellation works when the message is already in flight.
|
||||
*/
|
||||
ca = g_cancellable_new ();
|
||||
g_dbus_connection_call (c,
|
||||
"org.freedesktop.DBus", /* bus_name */
|
||||
"/org/freedesktop/DBus", /* object path */
|
||||
"org.freedesktop.DBus", /* interface name */
|
||||
"GetId", /* method name */
|
||||
NULL,
|
||||
G_DBUS_CALL_FLAGS_NONE,
|
||||
-1,
|
||||
ca,
|
||||
(GAsyncReadyCallback) msg_cb_expect_error_cancelled,
|
||||
&data);
|
||||
g_cancellable_cancel (ca);
|
||||
g_main_loop_run (thread_loop);
|
||||
g_object_unref (ca);
|
||||
|
||||
/*
|
||||
* Check that signals are delivered to the correct thread.
|
||||
*
|
||||
* First we subscribe to the signal, then we create a a private
|
||||
* connection. This should cause a NameOwnerChanged message from
|
||||
* the message bus.
|
||||
*/
|
||||
subscription_id = g_dbus_connection_signal_subscribe (c,
|
||||
"org.freedesktop.DBus", /* sender */
|
||||
"org.freedesktop.DBus", /* interface */
|
||||
"NameOwnerChanged", /* member */
|
||||
"/org/freedesktop/DBus", /* path */
|
||||
NULL,
|
||||
signal_handler,
|
||||
&data,
|
||||
NULL);
|
||||
g_assert (subscription_id != 0);
|
||||
g_assert (data.signal_count == 0);
|
||||
|
||||
priv_c = _g_bus_get_priv (G_BUS_TYPE_SESSION, NULL, &error);
|
||||
g_assert_no_error (error);
|
||||
g_assert (priv_c != NULL);
|
||||
|
||||
g_main_loop_run (thread_loop);
|
||||
g_assert (data.signal_count == 1);
|
||||
|
||||
g_object_unref (priv_c);
|
||||
|
||||
g_dbus_connection_signal_unsubscribe (c, subscription_id);
|
||||
|
||||
/* ---------------------------------------------------------------------------------------------------- */
|
||||
|
||||
g_main_context_pop_thread_default (thread_context);
|
||||
g_main_loop_unref (thread_loop);
|
||||
g_main_context_unref (thread_context);
|
||||
|
||||
g_main_loop_quit (loop);
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static void
|
||||
test_delivery_in_thread (void)
|
||||
{
|
||||
GError *error;
|
||||
GThread *thread;
|
||||
|
||||
error = NULL;
|
||||
thread = g_thread_create (test_delivery_in_thread_func,
|
||||
NULL,
|
||||
TRUE,
|
||||
&error);
|
||||
g_assert_no_error (error);
|
||||
g_assert (thread != NULL);
|
||||
|
||||
/* run the event loop - it is needed to dispatch D-Bus messages */
|
||||
g_main_loop_run (loop);
|
||||
|
||||
g_thread_join (thread);
|
||||
}
|
||||
|
||||
/* ---------------------------------------------------------------------------------------------------- */
|
||||
|
||||
typedef struct {
|
||||
GDBusProxy *proxy;
|
||||
gint msec;
|
||||
guint num;
|
||||
gboolean async;
|
||||
|
||||
GMainLoop *thread_loop;
|
||||
GThread *thread;
|
||||
|
||||
gboolean done;
|
||||
} SyncThreadData;
|
||||
|
||||
static void
|
||||
sleep_cb (GDBusProxy *proxy,
|
||||
GAsyncResult *res,
|
||||
gpointer user_data)
|
||||
{
|
||||
SyncThreadData *data = user_data;
|
||||
GError *error;
|
||||
GVariant *result;
|
||||
|
||||
error = NULL;
|
||||
result = g_dbus_proxy_call_finish (proxy,
|
||||
res,
|
||||
&error);
|
||||
g_assert_no_error (error);
|
||||
g_assert (result != NULL);
|
||||
g_assert_cmpstr (g_variant_get_type_string (result), ==, "()");
|
||||
g_variant_unref (result);
|
||||
|
||||
g_assert (data->thread == g_thread_self ());
|
||||
|
||||
g_main_loop_quit (data->thread_loop);
|
||||
|
||||
//g_debug ("async cb (%p)", g_thread_self ());
|
||||
}
|
||||
|
||||
static gpointer
|
||||
test_sleep_in_thread_func (gpointer _data)
|
||||
{
|
||||
SyncThreadData *data = _data;
|
||||
GMainContext *thread_context;
|
||||
guint n;
|
||||
|
||||
thread_context = g_main_context_new ();
|
||||
data->thread_loop = g_main_loop_new (thread_context, FALSE);
|
||||
g_main_context_push_thread_default (thread_context);
|
||||
|
||||
data->thread = g_thread_self ();
|
||||
|
||||
for (n = 0; n < data->num; n++)
|
||||
{
|
||||
if (data->async)
|
||||
{
|
||||
//g_debug ("invoking async (%p)", g_thread_self ());
|
||||
g_dbus_proxy_call (data->proxy,
|
||||
"Sleep",
|
||||
g_variant_new ("(i)", data->msec),
|
||||
G_DBUS_CALL_FLAGS_NONE,
|
||||
-1,
|
||||
NULL,
|
||||
(GAsyncReadyCallback) sleep_cb,
|
||||
data);
|
||||
g_main_loop_run (data->thread_loop);
|
||||
g_print ("A");
|
||||
//g_debug ("done invoking async (%p)", g_thread_self ());
|
||||
}
|
||||
else
|
||||
{
|
||||
GError *error;
|
||||
GVariant *result;
|
||||
|
||||
error = NULL;
|
||||
//g_debug ("invoking sync (%p)", g_thread_self ());
|
||||
result = g_dbus_proxy_call_sync (data->proxy,
|
||||
"Sleep",
|
||||
g_variant_new ("(i)", data->msec),
|
||||
G_DBUS_CALL_FLAGS_NONE,
|
||||
-1,
|
||||
NULL,
|
||||
&error);
|
||||
g_print ("S");
|
||||
//g_debug ("done invoking sync (%p)", g_thread_self ());
|
||||
g_assert_no_error (error);
|
||||
g_assert (result != NULL);
|
||||
g_assert_cmpstr (g_variant_get_type_string (result), ==, "()");
|
||||
g_variant_unref (result);
|
||||
}
|
||||
}
|
||||
|
||||
g_main_context_pop_thread_default (thread_context);
|
||||
g_main_loop_unref (data->thread_loop);
|
||||
g_main_context_unref (thread_context);
|
||||
|
||||
data->done = TRUE;
|
||||
g_main_loop_quit (loop);
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static void
|
||||
on_proxy_appeared (GDBusConnection *connection,
|
||||
const gchar *name,
|
||||
const gchar *name_owner,
|
||||
GDBusProxy *proxy,
|
||||
gpointer user_data)
|
||||
{
|
||||
guint n;
|
||||
|
||||
/*
|
||||
* Check that multiple threads can do calls without interferring with
|
||||
* each other. We do this by creating three threads that call the
|
||||
* Sleep() method on the server (which handles it asynchronously, e.g.
|
||||
* it won't block other requests) with different sleep durations and
|
||||
* a number of times. We do this so each set of calls add up to 4000
|
||||
* milliseconds.
|
||||
*
|
||||
* We run this test twice - first with async calls in each thread, then
|
||||
* again with sync calls
|
||||
*/
|
||||
|
||||
for (n = 0; n < 2; n++)
|
||||
{
|
||||
gboolean do_async;
|
||||
GThread *thread1;
|
||||
GThread *thread2;
|
||||
GThread *thread3;
|
||||
SyncThreadData data1;
|
||||
SyncThreadData data2;
|
||||
SyncThreadData data3;
|
||||
GError *error;
|
||||
GTimeVal start_time;
|
||||
GTimeVal end_time;
|
||||
guint elapsed_msec;
|
||||
|
||||
error = NULL;
|
||||
do_async = (n == 0);
|
||||
|
||||
g_get_current_time (&start_time);
|
||||
|
||||
data1.proxy = proxy;
|
||||
data1.msec = 40;
|
||||
data1.num = 100;
|
||||
data1.async = do_async;
|
||||
data1.done = FALSE;
|
||||
thread1 = g_thread_create (test_sleep_in_thread_func,
|
||||
&data1,
|
||||
TRUE,
|
||||
&error);
|
||||
g_assert_no_error (error);
|
||||
g_assert (thread1 != NULL);
|
||||
|
||||
data2.proxy = proxy;
|
||||
data2.msec = 20;
|
||||
data2.num = 200;
|
||||
data2.async = do_async;
|
||||
data2.done = FALSE;
|
||||
thread2 = g_thread_create (test_sleep_in_thread_func,
|
||||
&data2,
|
||||
TRUE,
|
||||
&error);
|
||||
g_assert_no_error (error);
|
||||
g_assert (thread2 != NULL);
|
||||
|
||||
data3.proxy = proxy;
|
||||
data3.msec = 100;
|
||||
data3.num = 40;
|
||||
data3.async = do_async;
|
||||
data3.done = FALSE;
|
||||
thread3 = g_thread_create (test_sleep_in_thread_func,
|
||||
&data3,
|
||||
TRUE,
|
||||
&error);
|
||||
g_assert_no_error (error);
|
||||
g_assert (thread3 != NULL);
|
||||
|
||||
/* we handle messages in the main loop - threads will quit it when they are done */
|
||||
while (!(data1.done && data2.done && data3.done))
|
||||
g_main_loop_run (loop);
|
||||
|
||||
g_thread_join (thread1);
|
||||
g_thread_join (thread2);
|
||||
g_thread_join (thread3);
|
||||
|
||||
g_get_current_time (&end_time);
|
||||
|
||||
elapsed_msec = ((end_time.tv_sec * G_USEC_PER_SEC + end_time.tv_usec) -
|
||||
(start_time.tv_sec * G_USEC_PER_SEC + start_time.tv_usec)) / 1000;
|
||||
|
||||
//g_debug ("Elapsed time for %s = %d msec", n == 0 ? "async" : "sync", elapsed_msec);
|
||||
|
||||
/* elapsed_msec should be 4000 msec + change for overhead */
|
||||
g_assert_cmpint (elapsed_msec, >=, 4000);
|
||||
g_assert_cmpint (elapsed_msec, <, 5000);
|
||||
|
||||
g_print (" ");
|
||||
}
|
||||
|
||||
g_main_loop_quit (loop);
|
||||
}
|
||||
|
||||
static void
|
||||
on_proxy_vanished (GDBusConnection *connection,
|
||||
const gchar *name,
|
||||
gpointer user_data)
|
||||
{
|
||||
}
|
||||
|
||||
static void
|
||||
test_method_calls_in_thread (void)
|
||||
{
|
||||
guint watcher_id;
|
||||
|
||||
watcher_id = g_bus_watch_proxy (G_BUS_TYPE_SESSION,
|
||||
"com.example.TestService",
|
||||
G_BUS_NAME_WATCHER_FLAGS_NONE,
|
||||
"/com/example/TestObject",
|
||||
"com.example.Frob",
|
||||
G_TYPE_DBUS_PROXY,
|
||||
G_DBUS_PROXY_FLAGS_NONE,
|
||||
on_proxy_appeared,
|
||||
on_proxy_vanished,
|
||||
NULL,
|
||||
NULL);
|
||||
|
||||
g_main_loop_run (loop);
|
||||
|
||||
g_bus_unwatch_proxy (watcher_id);
|
||||
}
|
||||
|
||||
/* ---------------------------------------------------------------------------------------------------- */
|
||||
|
||||
int
|
||||
main (int argc,
|
||||
char *argv[])
|
||||
{
|
||||
GError *error;
|
||||
gint ret;
|
||||
|
||||
g_type_init ();
|
||||
g_thread_init (NULL);
|
||||
g_test_init (&argc, &argv, NULL);
|
||||
|
||||
/* all the tests rely on a shared main loop */
|
||||
loop = g_main_loop_new (NULL, FALSE);
|
||||
|
||||
/* all the tests use a session bus with a well-known address that we can bring up and down
|
||||
* using session_bus_up() and session_bus_down().
|
||||
*/
|
||||
g_unsetenv ("DISPLAY");
|
||||
g_setenv ("DBUS_SESSION_BUS_ADDRESS", session_bus_get_temporary_address (), TRUE);
|
||||
|
||||
session_bus_up ();
|
||||
|
||||
/* TODO: wait a bit for the bus to come up.. ideally session_bus_up() won't return
|
||||
* until one can connect to the bus but that's not how things work right now
|
||||
*/
|
||||
usleep (500 * 1000);
|
||||
|
||||
/* this is safe; testserver will exit once the bus goes away */
|
||||
g_assert (g_spawn_command_line_async ("./gdbus-testserver.py", NULL));
|
||||
|
||||
/* wait for the service to come up */
|
||||
usleep (500 * 1000);
|
||||
|
||||
/* Create the connection in the main thread */
|
||||
error = NULL;
|
||||
c = g_bus_get_sync (G_BUS_TYPE_SESSION, NULL, &error);
|
||||
g_assert_no_error (error);
|
||||
g_assert (c != NULL);
|
||||
|
||||
g_test_add_func ("/gdbus/delivery-in-thread", test_delivery_in_thread);
|
||||
g_test_add_func ("/gdbus/method-calls-in-thread", test_method_calls_in_thread);
|
||||
|
||||
ret = g_test_run();
|
||||
|
||||
g_object_unref (c);
|
||||
|
||||
/* tear down bus */
|
||||
session_bus_down ();
|
||||
|
||||
return ret;
|
||||
}
|
Loading…
Reference in New Issue
Block a user