From: Enlightenment S. <no-...@en...> - 2009-10-31 16:28:27
|
Log: Exalt DBus: start the daemon if it is not running, handle disconnect. Thank you to ethumb for the code Author: watchwolf Date: 2009-10-31 09:28:16 -0700 (Sat, 31 Oct 2009) New Revision: 43375 Added: trunk/exalt/org.e.Exalt.service.in Modified: trunk/exalt/AUTHORS trunk/exalt/Makefile.am trunk/exalt/README trunk/exalt/configure.ac trunk/exalt/src/bin/cb_ethernet.c trunk/exalt/src/bin_client/client.c trunk/exalt/src/bin_command/command.c trunk/exalt/src/doc.h trunk/exalt/src/lib/Exalt.h trunk/exalt/src/lib_dbus/Exalt_DBus.h trunk/exalt/src/lib_dbus/define.h trunk/exalt/src/lib_dbus/libexalt_dbus.c trunk/exalt/src/lib_dbus/libexalt_dbus_private.h Modified: trunk/exalt/AUTHORS =================================================================== --- trunk/exalt/AUTHORS 2009-10-31 15:18:19 UTC (rev 43374) +++ trunk/exalt/AUTHORS 2009-10-31 16:28:16 UTC (rev 43375) @@ -1 +1,5 @@ Atton Jonathan (wat...@wa...) + +The dbus connection code (handle disconnect, start the daeom ...) comes from Ethumb. The author is : +Rafael Antognolli <ant...@pr...> + Modified: trunk/exalt/Makefile.am =================================================================== --- trunk/exalt/Makefile.am 2009-10-31 15:18:19 UTC (rev 43374) +++ trunk/exalt/Makefile.am 2009-10-31 16:28:16 UTC (rev 43375) @@ -5,7 +5,7 @@ MAINTAINERCLEANFILES = Makefile.in aclocal.m4 config.guess \ config.h.in config.h.in~ config.sub configure \ - install-sh \ + install-sh org.e.Exalt.service\ ltconfig ltmain.sh missing mkinstalldirs depcomp \ stamp-h stamp-h.in \ $(MYAPPNAME).c @@ -20,6 +20,8 @@ pkgconfig_DATA = exalt_dbus.pc exalt.pc ACLOCAL_AMFLAGS = -I m4 +#servicedir = $(dbusservicedir) +#service_DATA = org.e.Exalt.service .PHONY: doc Modified: trunk/exalt/README =================================================================== --- trunk/exalt/README 2009-10-31 15:18:19 UTC (rev 43374) +++ trunk/exalt/README 2009-10-31 16:28:16 UTC (rev 43375) @@ -53,9 +53,16 @@ </policy> </busconfig> +If the daemon should be automatically starts by a client if it is not running, copy the file org.e.Exalt.service in /usr/share/dbus-1/system-services/. A example of content : + [D-BUS Service] + Name=org.e.Exalt + Exec=/usr/local/sbin/exalt-daemon + User=root + @endcode + Gentoo If you want add the daemon in your init, you can use the script in daemon/data/init.d/gentoo: @@ -64,3 +71,4 @@ rc-update add exaltd default + Modified: trunk/exalt/configure.ac =================================================================== --- trunk/exalt/configure.ac 2009-10-31 15:18:19 UTC (rev 43374) +++ trunk/exalt/configure.ac 2009-10-31 16:28:16 UTC (rev 43375) @@ -120,6 +120,9 @@ AC_DEFINE_UNQUOTED(HAVE_DHCP, "${have_dhcp}", [have dhcp support]) fi +#can't retrieve the system service dir :/ +#dbusservicedir=`$PKG_CONFIG --variable=session_bus_system-services_dir dbus-1` +#AC_SUBST(dbusservicedir) requirements="elementary ecore eet ecore-file ehal edbus evas dbus-1" @@ -177,9 +180,14 @@ data/icons/Makefile exalt.pc exalt_dbus.pc +org.e.Exalt.service ] ) +txt_strip() { + echo "[$]@" | sed -e 's/^[[ \t]]*\([[^ \t]]*\)[[ \t]]*$/\1/g' +} + ############################################################### #### Informations @@ -196,11 +204,12 @@ echo echo " dhcp support (only dhclient is supported)...: $have_dhcp ($dhcp)" echo " wpa_supplicant support......................: $have_wpa_supplicant ($wpa_supplicant)" +#echo " DBus services dir...........................: $(txt_strip $dbusservicedir))" #echo " vpnc support...................: not yet implemented" echo -echo " Documentation........: ${build_doc}" +echo " Documentation...............................: ${build_doc}" echo -echo " Installation Path..............: $prefix" +echo " Installation Path...........................: $prefix" echo echo "Now type 'make' ('gmake' on some systems) to compile $PACKAGE," echo "and then afterwards as root (or the user who will install this), type" Modified: trunk/exalt/src/bin/cb_ethernet.c =================================================================== --- trunk/exalt/src/bin/cb_ethernet.c 2009-10-31 15:18:19 UTC (rev 43374) +++ trunk/exalt/src/bin/cb_ethernet.c 2009-10-31 16:28:16 UTC (rev 43375) @@ -26,7 +26,6 @@ EXALT_DBUS_INTERFACE_LIST_ERROR); return reply); - dbus_args_valid_append(reply); dbus_message_iter_init_append(reply, &iter); EXALT_ASSERT_CUSTOM_RET( Modified: trunk/exalt/src/bin_client/client.c =================================================================== --- trunk/exalt/src/bin_client/client.c 2009-10-31 15:18:19 UTC (rev 43374) +++ trunk/exalt/src/bin_client/client.c 2009-10-31 16:28:16 UTC (rev 43375) @@ -17,7 +17,7 @@ exalt_dbus_init(); - conn = exalt_dbus_connect(); + conn = exalt_dbus_connect(NULL, NULL, NULL); if(!conn) return -88; setlocale(LC_ALL, ""); Modified: trunk/exalt/src/bin_command/command.c =================================================================== --- trunk/exalt/src/bin_command/command.c 2009-10-31 15:18:19 UTC (rev 43374) +++ trunk/exalt/src/bin_command/command.c 2009-10-31 16:28:16 UTC (rev 43375) @@ -377,7 +377,7 @@ printf("Init failed\n"); return 0; } - conn = exalt_dbus_connect(); + conn = exalt_dbus_connect(NULL, NULL, NULL); if(!exalt_dbus_exalt_service_exists(conn)) { Modified: trunk/exalt/src/doc.h =================================================================== --- trunk/exalt/src/doc.h 2009-10-31 15:18:19 UTC (rev 43374) +++ trunk/exalt/src/doc.h 2009-10-31 16:28:16 UTC (rev 43375) @@ -126,6 +126,15 @@ * </busconfig> * @endcode * + * If the daemon should be automatically starts by a client if it is not running, copy the file org.e.Exalt.service in /usr/share/dbus-1/system-services/. A example of content : + * + * @code + * [D-BUS Service] + * Name=org.e.Exalt + * Exec=/usr/local/sbin/exalt-daemon + * User=root + * @endcode + * * <b>Gentoo</b> * * If you want add the daemon in your init, you can use the script in daemon/data/init.d/gentoo: Modified: trunk/exalt/src/lib/Exalt.h =================================================================== --- trunk/exalt/src/lib/Exalt.h 2009-10-31 15:18:19 UTC (rev 43374) +++ trunk/exalt/src/lib/Exalt.h 2009-10-31 16:28:16 UTC (rev 43375) @@ -25,6 +25,7 @@ #define EXALT_LOG_CRIT(...) EINA_LOG_DOM_CRIT(EXALT_LOG_DOMAIN, __VA_ARGS__) #define EXALT_LOG_INFO(...) EINA_LOG_DOM_INFO(EXALT_LOG_DOMAIN, __VA_ARGS__) #define EXALT_LOG_ERR(...) EINA_LOG_DOM_ERR(EXALT_LOG_DOMAIN, __VA_ARGS__) +#define EXALT_LOG_DBG(...) EINA_LOG_DOM_DBG(EXALT_LOG_DOMAIN, __VA_ARGS__) #define EXALT_ASSERT(test) \ do\ Modified: trunk/exalt/src/lib_dbus/Exalt_DBus.h =================================================================== --- trunk/exalt/src/lib_dbus/Exalt_DBus.h 2009-10-31 15:18:19 UTC (rev 43374) +++ trunk/exalt/src/lib_dbus/Exalt_DBus.h 2009-10-31 16:28:16 UTC (rev 43375) @@ -36,7 +36,11 @@ */ typedef void (exalt_scan_notify_cb) (char* eth, Eina_List* networks, void* user_data); +typedef void (*Exalt_DBus_Connect_Cb)(void *data, Exalt_DBus_Conn *conn, Eina_Bool success); +typedef void (*Exalt_DBus_Die_Cb)(void *data, Exalt_DBus_Conn *conn); + + #include "define.h" #include "exalt_dbus_ethernet.h" #include "exalt_dbus_wireless.h" @@ -49,7 +53,8 @@ EAPI int exalt_dbus_init(); -EAPI Exalt_DBus_Conn* exalt_dbus_connect(); +EAPI Exalt_DBus_Conn* exalt_dbus_connect(Exalt_DBus_Connect_Cb connect_cb, void *data, Eina_Free_Cb free_data_cb); +EAPI void exalt_dbus_on_server_die_callback_set(Exalt_DBus_Conn *conn, Exalt_DBus_Die_Cb server_die_cb, const void *data, Eina_Free_Cb free_data); EAPI int exalt_dbus_exalt_service_exists(Exalt_DBus_Conn *conn); EAPI int exalt_dbus_service_exists(Exalt_DBus_Conn *conn, const char* service_name); Modified: trunk/exalt/src/lib_dbus/define.h =================================================================== --- trunk/exalt/src/lib_dbus/define.h 2009-10-31 15:18:19 UTC (rev 43374) +++ trunk/exalt/src/lib_dbus/define.h 2009-10-31 16:28:16 UTC (rev 43375) @@ -22,15 +22,17 @@ #define EXALTD_PATH "/org/e/Exalt" +#define FDO_SERVICE "org.freedesktop.DBus" +#define FDO_INTERFACE "org.freedesktop.DBus" +#define FDO_PATH "/org/freedesktop/DBus" + /** Print a DBusError message if the flag error is set */ -#define EXALT_DBUS_ERROR_PRINT(error) if(error && dbus_error_is_set(error)) { EXALT_LOG_ERR("%s",error->name);return; } +#define EXALT_DBUS_ERROR_PRINT(error) if(error && dbus_error_is_set(error)) { EXALT_LOG_ERR("%s : %s",error->name, error->message);return; } /** Path of the DBus object which allows to manage the DNS */ #define EXALTD_PATH_DNS "/org/exalt/dns" /** Path of the DBus interface which allows to manage the DNS */ #define EXALTD_INTERFACE_DNS "org.exalt.dns" - - /** Path of the DBus object which allows to manage the list of interfaces */ #define EXALTD_PATH_IFACE "/org/exalt/interface" /** Path of the DBus interface which allows to manage the list of interfaces */ Modified: trunk/exalt/src/lib_dbus/libexalt_dbus.c =================================================================== --- trunk/exalt/src/lib_dbus/libexalt_dbus.c 2009-10-31 15:18:19 UTC (rev 43374) +++ trunk/exalt/src/lib_dbus/libexalt_dbus.c 2009-10-31 16:28:16 UTC (rev 43375) @@ -9,8 +9,12 @@ static int init = 0; +static void _exalt_dbus_start_server_cb(void *data, DBusMessage *msg, DBusError *error); +static void _exalt_dbus_get_name_owner(void *data, DBusMessage *msg, DBusError *err); +static void _exalt_dbus_start_server(Exalt_DBus_Conn *conn); +static void _exalt_dbus_report_connect(Exalt_DBus_Conn *conn, Eina_Bool success); +static void _exalt_dbus_name_owner_changed(void *data, DBusMessage *msg); - /** * @addtogroup General * @{ @@ -18,7 +22,7 @@ /** * @brief Initialise the library - * Don't forget to create a connection with Exalt_DBus_Connect() after + * Don't forget to create a connection with exalt_dbus_connect() after * @return Returns 0 if failed (if the exalt's service doesn't exist), else 1 or more */ int exalt_dbus_init() @@ -81,13 +85,44 @@ /** * @brief Create a connection - * @return Returns a new DBus connection + * + * If exaltd was down, it is tried to start it using DBus activation, + * then the connection is retried. + * + * This call is asynchronous and will not block, instead it will be in + * "not connected" state until @a connect_cb is called with either + * success or failure. On failure, then no methods should be + * called. On success you're now able to communicate with the server. + * + * Usually you should listen for server death/disconenction with + * exalt_dbus_on_server_die_callback_set(). + * + * @param connect_cb function to call to report connection success or + * failure. Do not call any other exalt_dbus method until + * this function returns. The first received parameter is the + * given argument @a data. Must @b not be @c NULL. + * @param data context to give back to @a connect_cb. May be @c NULL. + * @param free_data function used to release @a data resources, if + * any. May be @c NULL. If this function exists, it will be + * explicitly calls exalt_dbus_frr(). + * + * @return client instance or NULL if failed. If @a connect_cb is + * missing it returns @c NULL. If it fail for other + * conditions, @c NULL is also returned. The client instance + * is not ready to be used until @a connect_cb is called. */ -Exalt_DBus_Conn* exalt_dbus_connect() +Exalt_DBus_Conn* exalt_dbus_connect(Exalt_DBus_Connect_Cb connect_cb, void *data, Eina_Free_Cb free_data_cb) { Exalt_DBus_Conn* conn; DBusError err; conn = calloc(1,sizeof(Exalt_DBus_Conn)); + conn->msg_id = 1; + conn->connect.cb = connect_cb; + conn->connect.data = data; + conn->connect.free_data = free_data_cb; + + EXALT_ASSERT_RETURN(connect_cb); + //initialise the errors dbus_error_init(&err); // connect to the bus @@ -99,14 +134,51 @@ EXALT_ASSERT_CUSTOM_RET(conn->e_conn != NULL, EXALT_FREE(conn); return NULL;); - conn->msg_id = 1; + conn->name_owner_changed_handler = e_dbus_signal_handler_add( + conn->e_conn, FDO_SERVICE, FDO_PATH, FDO_INTERFACE, + "NameOwnerChanged", _exalt_dbus_name_owner_changed, conn); conn -> response_notify = calloc(1,sizeof(exalt_dbus_response_data)); + conn->pending_get_name_owner = e_dbus_get_name_owner( + conn->e_conn, EXALTD_SERVICE, _exalt_dbus_get_name_owner, + conn); + return conn; } /** + * Sets the callback to report server died. + * + * When server dies there is nothing you can do, just release + * resources with exalt_dbus_free() and probably try to + * connect again. + * + * Usually you should set this callback and handle this case, it does + * happen! + * + * @param conn the connection to monitor. Must @b not be @c + * NULL. + * @param server_die_cb function to call back when server dies. The + * first parameter will be the argument @a data. May be @c + * NULL. + * @param data context to give back to @a server_die_cb. May be @c + * NULL. + * @param free_data used to release @a data resources after user calls + * exalt_dbus_free(). + */ +void exalt_dbus_on_server_die_callback_set(Exalt_DBus_Conn *conn, Exalt_DBus_Die_Cb server_die_cb, const void *data, Eina_Free_Cb free_data) +{ + EXALT_ASSERT_RETURN_VOID(conn != NULL); + + if (conn->die.free_data) + conn->die.free_data(conn->die.data); + + conn->die.cb = server_die_cb; + conn->die.data = (void *)data; + conn->die.free_data = free_data; +} +/** * @brief Free an exalt DBus connection * @param conn a connection */ @@ -116,8 +188,16 @@ EXALT_ASSERT_RETURN_VOID(*conn != NULL); EXALT_ASSERT_RETURN_VOID( (*conn)->e_conn != NULL); + if ((*conn)->die.free_data) + (*conn)->die.free_data((*conn)->die.data); + + if ((*conn)->connect.free_data) + (*conn)->connect.free_data((*conn)->connect.data); + e_dbus_signal_handler_del((*conn)->e_conn, (*conn)->scan_notify_handler); e_dbus_signal_handler_del((*conn)->e_conn, (*conn)->notify_handler); + if((*conn)->name_owner_changed_handler) + e_dbus_signal_handler_del((*conn)->e_conn, (*conn)->name_owner_changed_handler); e_dbus_connection_close((*conn)->e_conn); EXALT_FREE((*conn)->notify); @@ -212,5 +292,200 @@ } + static inline Eina_Bool +__dbus_iter_type_check(int type, int expected, const char *expected_name) +{ + if (type == expected) + return EINA_TRUE; + + EXALT_LOG_ERR("expected type %s (%c) but got %c instead!", + expected_name, expected, type); + + return EINA_FALSE; +} +#define _dbus_iter_type_check(t, e) __dbus_iter_type_check(t, e, #e) + + + static void +_exalt_dbus_start_server_cb(void *data, DBusMessage *msg, DBusError *error) +{ + Exalt_DBus_Conn *conn = data; + DBusMessageIter iter; + dbus_uint32_t ret; + int t; + + EXALT_ASSERT_RETURN_VOID(conn != NULL); + + EXALT_DBUS_ERROR_PRINT(error); + + EXALT_ASSERT_RETURN_VOID(msg != NULL); + + conn->pending_start_service_by_name = NULL; + + dbus_message_iter_init(msg, &iter); + t = dbus_message_iter_get_arg_type(&iter); + if (!_dbus_iter_type_check(t, DBUS_TYPE_UINT32)) + goto error; + + dbus_message_iter_get_basic(&iter, &ret); + if ((ret != 1) && (ret != 2)) + { + EXALT_LOG_ERR("Error starting Exalt daemon service by its name: retcode %u", + ret); + goto error; + } + + conn->server_started = 1; + EXALT_LOG_DBG("Exalt daemon service started successfully (%d), now request its name", + ret); + + if (conn->pending_get_name_owner) + { + EXALT_LOG_DBG("already requesting name owner, cancel and try again"); + dbus_pending_call_cancel(conn->pending_get_name_owner); + } + + conn->pending_get_name_owner = e_dbus_get_name_owner + (conn->e_conn, EXALTD_SERVICE, _exalt_dbus_get_name_owner, + conn); + if (!conn->pending_get_name_owner) + { + EXALT_LOG_ERR("could not create a get_name_owner request."); + goto error; + } + + return; + +error: + EXALT_LOG_ERR("failed to start Exalt daemon DBus service by its name."); + _exalt_dbus_report_connect(conn, 0); +} + + static void +_exalt_dbus_get_name_owner(void *data, DBusMessage *msg, DBusError *error) +{ + DBusMessageIter iter; + const char *uid; + Exalt_DBus_Conn *conn = data; + int t; + + conn->pending_get_name_owner = NULL; + + if (dbus_error_is_set(error) && (!conn->server_started)) + { + EXALT_LOG_DBG("could not find server (%s), try to start it...", error->message); + _exalt_dbus_start_server(conn); + return; + } + + EXALT_DBUS_ERROR_PRINT(error); + dbus_message_iter_init(msg, &iter); + t = dbus_message_iter_get_arg_type(&iter); + if (!_dbus_iter_type_check(t, DBUS_TYPE_STRING)) + goto error; + + dbus_message_iter_get_basic(&iter, &uid); + if (!uid) + { + EXALT_LOG_ERR("no name owner!"); + goto error; + } + + EXALT_LOG_DBG("unique name = %s", uid); + conn->unique_name = eina_stringshare_add(uid); + + conn->connected = 1; + _exalt_dbus_report_connect(conn, 1); + return; + +error: + _exalt_dbus_report_connect(conn, 0); +} + + + static void +_exalt_dbus_start_server(Exalt_DBus_Conn *conn) +{ + if (conn->pending_start_service_by_name) + { + EXALT_LOG_DBG("already pending start service by name."); + return; + } + + conn->server_started = 0; + conn->pending_start_service_by_name = e_dbus_start_service_by_name + (conn->e_conn, EXALTD_SERVICE, 0, _exalt_dbus_start_server_cb, + conn); + if (!conn->pending_start_service_by_name) + { + EXALT_LOG_ERR("could not start service by name!"); + _exalt_dbus_report_connect(conn, 0); + } +} + + static void +_exalt_dbus_report_connect(Exalt_DBus_Conn *conn, Eina_Bool success) +{ + if (!conn->connect.cb) + { + EXALT_LOG_ERR("already called?!"); + return; + } + + conn->connect.cb(conn->connect.data, conn, success); + if (conn->connect.free_data) + { + conn->connect.free_data(conn->connect.data); + conn->connect.free_data = NULL; + } + conn->connect.cb = NULL; + conn->connect.data = NULL; +} + +static void +_exalt_dbus_name_owner_changed(void *data, DBusMessage *msg) +{ + DBusError err; + const char *name, *from, *to; + Exalt_DBus_Conn *conn = data; + + dbus_error_init(&err); + if (!dbus_message_get_args(msg, &err, + DBUS_TYPE_STRING, &name, + DBUS_TYPE_STRING, &from, + DBUS_TYPE_STRING, &to, + DBUS_TYPE_INVALID)) + { + EXALT_LOG_ERR("could not get NameOwnerChanged arguments: %s: %s", + err.name, err.message); + dbus_error_free(&err); + return; + } + + if(!from || !name) + return ; + if (strcmp(name, EXALTD_SERVICE) != 0) + return; + + EXALT_LOG_DBG("NameOwnerChanged from=[%s] to=[%s]", from, to); + + if (from[0] != '\0' && to[0] == '\0') + { + EXALT_LOG_DBG("exit exaltd at %s", from); + if (conn->unique_name && strcmp(conn->unique_name, from) != 0) + EXALT_LOG_WARN("%s was not the known name %s, ignored.", + from, conn->unique_name); + else + { + EXALT_LOG_ERR("server exit!!!"); + if (conn->die.cb) + conn->die.cb(conn->die.data, conn); + } + } + else + EXALT_LOG_DBG("unknown change from %s to %s", from, to); +} + + /** @} */ Modified: trunk/exalt/src/lib_dbus/libexalt_dbus_private.h =================================================================== --- trunk/exalt/src/lib_dbus/libexalt_dbus_private.h 2009-10-31 15:18:19 UTC (rev 43374) +++ trunk/exalt/src/lib_dbus/libexalt_dbus_private.h 2009-10-31 16:28:16 UTC (rev 43375) @@ -35,6 +35,29 @@ exalt_dbus_response_data* response_notify; //define the next message id int msg_id; + + + E_DBus_Signal_Handler *name_owner_changed_handler; + E_DBus_Signal_Handler *generated_signal; + DBusPendingCall *pending_get_name_owner; + DBusPendingCall *pending_start_service_by_name; + const char *unique_name; + Eina_Bool connected : 1; + Eina_Bool server_started : 1; + + struct + { + Exalt_DBus_Connect_Cb cb; + void *data; + Eina_Free_Cb free_data; + } connect; + + struct + { + Exalt_DBus_Die_Cb cb; + void *data; + Eina_Free_Cb free_data; + } die; }; struct _exalt_dbus_notify_data |