blob: ea7a2a6f094d641b65a8a4b703b58f0d10a41218 [file] [log] [blame]
#include <stdbool.h>
#include <string.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <dbus/dbus.h>
#include <dbus/dbus-glib-lowlevel.h> /* for glib main loop */
const char *version = "0.1";
GMainLoop *mainloop;
/*
* This is the XML string describing the interfaces, methods and
* signals implemented by our 'Server' object. It's used by the
* 'Introspect' method of 'org.freedesktop.DBus.Introspectable'
* interface.
*/
const char *server_introspection_xml =
DBUS_INTROSPECT_1_0_XML_DOCTYPE_DECL_NODE
"<node>\n"
" <interface name='org.freedesktop.DBus.Introspectable'>\n"
" <method name='Introspect'>\n"
" <arg name='data' type='s' direction='out' />\n"
" </method>\n"
" </interface>\n"
" <interface name='org.freedesktop.DBus.Properties'>\n"
" <method name='Get'>\n"
" <arg name='interface' type='s' direction='in' />\n"
" <arg name='property' type='s' direction='in' />\n"
" <arg name='value' type='s' direction='out' />\n"
" </method>\n"
" <method name='GetAll'>\n"
" <arg name='interface' type='s' direction='in'/>\n"
" <arg name='properties' type='a{sv}' direction='out'/>\n"
" </method>\n"
" </interface>\n"
" <interface name='com.Intel.PrmDispatch'>\n"
" <property name='Version' type='s' access='read' />\n"
" <method name='InstallPrmPackage'>\n"
" <arg type='ay' direction='in' name='PrmPackage' />\n"
" <arg type='u' direction='out' name='EfiStatus' />\n"
" </method>\n"
" <method name='EnumerateHandlers'>\n"
" <arg type='u' direction='out' name='EfiStatus'>\n"
" <arg type='a{ss} direction='out' name='PrmHandlerInfo' />\n"
" <entry key='PlatformGuid' value='s'/>\n"
" <entry key='ModuleGuid' value='s'/>\n"
" <entry key='HandlerGuid' value='s'/>\n"
" </arg>\n"
" </method>\n"
" <method name='InvokeHandler'>\n"
" <arg type='s' direction='in' name='HandlerGuid'/>\n"
" <arg type='ay' direction='in' name='ParameterBuffer' optional='true'/>\n"
" <arg type='u' direction='out' name='PrmHandlerReturnStatus'/>\n"
" <arg type='u' direction='out' name='EfiStatus' "
" </method>\n"
" <method name='UninstallPrmModule'>\n"
" <arg type='s' direction='in' name='ModuleGuid'/>\n"
" <arg type='u' direction='out' name='EfiStatus'/>\n"
" </method>\n"
" <method name='GetHandlerDebugInfo'>\n"
" <arg type='s' direction='in' name='HandlerGuid'/>\n"
" <arg type='ay' direction='out' name='AcpiParameterBuffer'/>\n"
" <arg type='s' direction='out' name='HandlerName' />\n"
" <arg type='u' durection='out' name='EfiStatus'/>\n"
" </method>\n"
" <method name='Quit'>\n"
" </method>\n"
" </interface>\n"
"</node>\n";
/*
* This implements 'Get' method of DBUS_INTERFACE_PROPERTIES so a
* client can inspect the properties/attributes of 'TestInterface'.
*/
DBusHandlerResult server_get_properties_handler(const char *property, DBusConnection *conn, DBusMessage *reply)
{
if (!strcmp(property, "Version"))
{
dbus_message_append_args(reply,
DBUS_TYPE_STRING, &version,
DBUS_TYPE_INVALID);
}
else
/* Unknown property */
return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
if (!dbus_connection_send(conn, reply, NULL))
return DBUS_HANDLER_RESULT_NEED_MEMORY;
return DBUS_HANDLER_RESULT_HANDLED;
}
/*
* This implements 'GetAll' method of DBUS_INTERFACE_PROPERTIES. This
* one seems required by g_dbus_proxy_get_cached_property().
*/
DBusHandlerResult server_get_all_properties_handler(DBusConnection *conn, DBusMessage *reply)
{
DBusHandlerResult result;
DBusMessageIter array, dict, iter, variant;
const char *property = "Version";
/*
* All dbus functions used below might fail due to out of
* memory error. If one of them fails, we assume that all
* following functions will fail too, including
* dbus_connection_send().
*/
result = DBUS_HANDLER_RESULT_NEED_MEMORY;
dbus_message_iter_init_append(reply, &iter);
dbus_message_iter_open_container(&iter, DBUS_TYPE_ARRAY, "{sv}", &array);
/* Append all properties name/value pairs */
property = "Version";
dbus_message_iter_open_container(&array, DBUS_TYPE_DICT_ENTRY, NULL, &dict);
dbus_message_iter_append_basic(&dict, DBUS_TYPE_STRING, &property);
dbus_message_iter_open_container(&dict, DBUS_TYPE_VARIANT, "s", &variant);
dbus_message_iter_append_basic(&variant, DBUS_TYPE_STRING, &version);
dbus_message_iter_close_container(&dict, &variant);
dbus_message_iter_close_container(&array, &dict);
dbus_message_iter_close_container(&iter, &array);
if (dbus_connection_send(conn, reply, NULL))
result = DBUS_HANDLER_RESULT_HANDLED;
return result;
}
/*
* This function implements the 'TestInterface' interface for the
* 'Server' DBus object.
*
* It also implements 'Introspect' method of
* 'org.freedesktop.DBus.Introspectable' interface which returns the
* XML string describing the interfaces, methods, and signals
* implemented by 'Server' object. This also can be used by tools such
* as d-feet(1) and can be queried by:
*
* $ gdbus introspect --session --dest org.example.TestServer --object-path /org/example/TestObject
*/
DBusHandlerResult server_message_handler(DBusConnection *conn, DBusMessage *message, void *data)
{
DBusHandlerResult result;
DBusMessage *reply = NULL;
DBusError err;
bool quit = false;
fprintf(stderr, "Got D-Bus request: %s.%s on %s\n",
dbus_message_get_interface(message),
dbus_message_get_member(message),
dbus_message_get_path(message));
/*
* Does not allocate any memory; the error only needs to be
* freed if it is set at some point.
*/
dbus_error_init(&err);
if (dbus_message_is_method_call(message, DBUS_INTERFACE_INTROSPECTABLE, "Introspect"))
{
if (!(reply = dbus_message_new_method_return(message)))
goto fail;
dbus_message_append_args(reply,
DBUS_TYPE_STRING, &server_introspection_xml,
DBUS_TYPE_INVALID);
}
else if (dbus_message_is_method_call(message, DBUS_INTERFACE_PROPERTIES, "Get"))
{
const char *interface, *property;
if (!dbus_message_get_args(message, &err,
DBUS_TYPE_STRING, &interface,
DBUS_TYPE_STRING, &property,
DBUS_TYPE_INVALID))
goto fail;
if (!(reply = dbus_message_new_method_return(message)))
goto fail;
result = server_get_properties_handler(property, conn, reply);
dbus_message_unref(reply);
return result;
}
else if (dbus_message_is_method_call(message, DBUS_INTERFACE_PROPERTIES, "GetAll"))
{
if (!(reply = dbus_message_new_method_return(message)))
goto fail;
result = server_get_all_properties_handler(conn, reply);
dbus_message_unref(reply);
return result;
}
else if (dbus_message_is_method_call(message, "com.Intel.PrmDispatch", "Quit"))
{
/*
* Quit() has no return values but a METHOD_RETURN
* reply is required, so the caller will know the
* method was successfully processed.
*/
reply = dbus_message_new_method_return(message);
quit = true;
}
else
return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
fail:
if (dbus_error_is_set(&err))
{
if (reply)
dbus_message_unref(reply);
reply = dbus_message_new_error(message, err.name, err.message);
dbus_error_free(&err);
}
/*
* In any cases we should have allocated a reply otherwise it
* means that we failed to allocate one.
*/
if (!reply)
return DBUS_HANDLER_RESULT_NEED_MEMORY;
/* Send the reply which might be an error one too. */
result = DBUS_HANDLER_RESULT_HANDLED;
if (!dbus_connection_send(conn, reply, NULL))
result = DBUS_HANDLER_RESULT_NEED_MEMORY;
dbus_message_unref(reply);
if (quit)
{
fprintf(stderr, "Server exiting...\n");
g_main_loop_quit(mainloop);
}
return result;
}
const DBusObjectPathVTable server_vtable = {
.message_function = server_message_handler
};
int run_server(void)
{
DBusConnection *conn;
DBusError err;
int rv;
dbus_error_init(&err);
/* connect to the daemon bus */
conn = dbus_bus_get(DBUS_BUS_SESSION, &err);
if (!conn) {
fprintf(stderr, "Failed to get a session DBus connection: %s\n", err.message);
goto fail;
}
rv = dbus_bus_request_name(conn, "com.Intel.PrmDispatchServer", DBUS_NAME_FLAG_REPLACE_EXISTING , &err);
if (rv != DBUS_REQUEST_NAME_REPLY_PRIMARY_OWNER) {
fprintf(stderr, "Failed to request name on bus: %s\n", err.message);
goto fail;
}
if (!dbus_connection_register_object_path(conn, "/org/Intel/PrmDispatchAPIObject", &server_vtable, NULL)) {
fprintf(stderr, "Failed to register a object path for 'PrmDispatchAPIObject'\n");
goto fail;
}
/*
* For the sake of simplicity we're using glib event loop to
* handle DBus messages. This is the only place where glib is
* used.
*/
printf("Starting demo dbus server v%s\n", version);
mainloop = g_main_loop_new(NULL, false);
/* Set up the DBus connection to work in a GLib event loop */
dbus_connection_setup_with_g_main(conn, NULL);
/* Start the glib event loop */
g_main_loop_run(mainloop);
return EXIT_SUCCESS;
fail:
dbus_error_free(&err);
return EXIT_FAILURE;
}
int main(void){
run_server();
}