nfs-ganesha 1.4

dbus_server.c

Go to the documentation of this file.
00001 /*
00002  * vim:expandtab:shiftwidth=8:tabstop=8:
00003  *
00004  * Copyright (C) 2010, The Linux Box Corporation
00005  * Contributor : Matt Benjamin <matt@linuxbox.com>
00006  *
00007  * Some portions Copyright CEA/DAM/DIF  (2008)
00008  * contributeur : Philippe DENIEL   philippe.deniel@cea.fr
00009  *                Thomas LEIBOVICI  thomas.leibovici@cea.fr
00010  *
00011  *
00012  * This program is free software; you can redistribute it and/or
00013  * modify it under the terms of the GNU Lesser General Public
00014  * License as published by the Free Software Foundation; either
00015  * version 3 of the License, or (at your option) any later version.
00016  *
00017  * This program is distributed in the hope that it will be useful,
00018  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00019  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00020  * Lesser General Public License for more details.
00021  *
00022  * You should have received a copy of the GNU Lesser General Public
00023  * License along with this library; if not, write to the Free Software
00024  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
00025  *
00026  * -------------
00027  */
00028 
00029 #ifdef HAVE_CONFIG_H
00030 #include "config.h"
00031 #endif
00032 
00033 #ifdef _SOLARIS
00034 #include "solaris_port.h"
00035 #endif                          /* _SOLARIS */
00036 
00037 #include <unistd.h>
00038 #include <sys/types.h>
00039 #include <sys/param.h>
00040 #include <time.h>
00041 #include <pthread.h>
00042 #include <assert.h>
00043 #if defined(USE_DBUS)
00044 #include <dbus/dbus.h>
00045 #endif /* USE_DBUS */
00046 #include "nlm_list.h"
00047 #include "fsal.h"
00048 #include "nfs_core.h"
00049 #include "log.h"
00050 #include "nfs_rpc_callback.h"
00051 #include "ganesha_dbus.h"
00052 
00070 #define GSH_DBUS_NONE      0x0000
00071 #define GSH_DBUS_SHUTDOWN  0x0001
00072 #define GSH_DBUS_SLEEPING  0x0002
00073 
00074 struct ganesha_dbus_handler
00075 {
00076     char *name;
00077     struct avltree_node node_k;
00078     DBusObjectPathVTable vtable;
00079 };
00080 typedef struct ganesha_dbus_handler ganesha_dbus_handler_t;
00081 
00082 struct _dbus_thread_state
00083 {
00084     int initialized;
00085     pthread_t thread_id;
00086     wait_entry_t we;
00087     DBusConnection* dbus_conn;
00088     DBusError dbus_err;
00089     uint32_t dbus_serial;
00090     struct avltree callouts;
00091     uint32_t flags;
00092 };
00093 
00094 static struct _dbus_thread_state thread_state;
00095 
00096 static inline int
00097 dbus_callout_cmpf(const struct avltree_node *lhs,
00098                   const struct avltree_node *rhs)
00099 {
00100     ganesha_dbus_handler_t *lk, *rk;
00101 
00102     lk = avltree_container_of(lhs, ganesha_dbus_handler_t, node_k);
00103     rk = avltree_container_of(rhs, ganesha_dbus_handler_t, node_k);
00104 
00105     return (strcmp(lk->name, rk->name));
00106 }
00107 
00108 void gsh_dbus_pkginit(void)
00109 {
00110     char regbuf[128];
00111     int code = 0;
00112 
00113     LogDebug(COMPONENT_DBUS, "init");
00114 
00115     avltree_init(&thread_state.callouts, dbus_callout_cmpf, 0 /* must be 0 */);
00116 
00117     dbus_error_init(&thread_state.dbus_err); /* sigh */
00118     thread_state.dbus_conn = dbus_bus_get(DBUS_BUS_SESSION,
00119                                           &thread_state.dbus_err);
00120     if (dbus_error_is_set(&thread_state.dbus_err)) {
00121         LogCrit(COMPONENT_DBUS,
00122                 "dbus_bus_get failed (%s)", thread_state.dbus_err.message);
00123         dbus_error_free(&thread_state.dbus_err);
00124         goto out;
00125     }
00126 
00127     snprintf(regbuf, 128, "org.ganesha.nfsd");
00128     code = dbus_bus_request_name(thread_state.dbus_conn, regbuf,
00129                                  DBUS_NAME_FLAG_REPLACE_EXISTING ,
00130                                  &thread_state.dbus_err);
00131     if (dbus_error_is_set(&thread_state.dbus_err)) { 
00132         LogCrit(COMPONENT_DBUS, "server bus reg failed (%s, %s)", regbuf,
00133                 thread_state.dbus_err.message); 
00134         dbus_error_free(&thread_state.dbus_err);
00135         if (! code)
00136             code = EINVAL;
00137         goto out;
00138     }
00139     if (code != DBUS_REQUEST_NAME_REPLY_PRIMARY_OWNER) {
00140         LogCrit(COMPONENT_DBUS, "server failed becoming primary bus owner "
00141                 "(%s, %d)", regbuf, code);
00142         goto out;
00143     }
00144 
00145     thread_state.initialized = TRUE;
00146 
00147 out:
00148     return;
00149 }
00150 
00151 static void
00152 path_unregistered_func (DBusConnection  *connection,
00153                         void            *user_data)
00154 {
00155   /* connection was finalized -- do nothing */
00156 }
00157 
00158 int32_t gsh_dbus_register_path(const char *name,
00159                                DBusObjectPathMessageFunction method)
00160 {
00161     ganesha_dbus_handler_t *handler;
00162     struct avltree_node *node;
00163     char path[512];
00164     int code = 0;
00165 
00166     /* XXX if this works, add ifc level */
00167     snprintf(path, 512, "/org/ganesha/nfsd/%s", name);
00168 
00169     handler = (ganesha_dbus_handler_t *)
00170         gsh_malloc(sizeof(ganesha_dbus_handler_t));
00171     handler->name = gsh_strdup(path);
00172     handler->vtable.unregister_function = path_unregistered_func;
00173     handler->vtable.message_function =  method;
00174 
00175     if (!thread_state.dbus_conn) {
00176         LogCrit(COMPONENT_DBUS, "dbus_connection_register_object_path "
00177                 "called with no DBUS connection");
00178         goto out;
00179     }
00180 
00181     code = dbus_connection_register_object_path (thread_state.dbus_conn,
00182                                                  handler->name,
00183                                                  &handler->vtable,
00184                                                  (void*) 0xdeadbeef);
00185     if (! code) {
00186         LogFatal(COMPONENT_DBUS, "dbus_connection_register_object_path "
00187                  "failed");
00188         gsh_free(handler);
00189         goto out;
00190     }
00191 
00192     node = avltree_insert(&handler->node_k, &thread_state.callouts);
00193     if (node) {
00194         LogFatal(COMPONENT_DBUS, "failed inserting method %s", path);
00195         code = EINVAL;
00196     }
00197 
00198     LogDebug(COMPONENT_DBUS, "registered handler for %s", path);
00199 
00200 out:
00201     return (code);
00202 }
00203 
00204 void gsh_dbus_pkgshutdown(void)
00205 {
00206     struct avltree_node *node, *onode;
00207     ganesha_dbus_handler_t *handler;
00208 
00209     LogDebug(COMPONENT_DBUS, "shutdown");
00210 
00211     /* remove and free handlers */
00212     onode = NULL;
00213     node = avltree_first(&thread_state.callouts);
00214     do {
00215         if (onode) {
00216             handler = avltree_container_of(onode, ganesha_dbus_handler_t,
00217                                            node_k);
00218             dbus_bus_release_name(thread_state.dbus_conn, handler->name,
00219                                          &thread_state.dbus_err);
00220             if (dbus_error_is_set(&thread_state.dbus_err)) { 
00221                 LogCrit(COMPONENT_DBUS, "err releasing name (%s, %s)",
00222                         handler->name, thread_state.dbus_err.message);
00223                 dbus_error_free(&thread_state.dbus_err);
00224             }
00225             gsh_free(handler->name);
00226             gsh_free(handler);
00227         }
00228     } while ((onode = node) && (node = avltree_next(node)));
00229     if (onode) {
00230         handler = avltree_container_of(onode, ganesha_dbus_handler_t,
00231                                        node_k);
00232         dbus_bus_release_name(thread_state.dbus_conn, handler->name,
00233                                      &thread_state.dbus_err);
00234         if (dbus_error_is_set(&thread_state.dbus_err)) { 
00235             LogCrit(COMPONENT_DBUS, "err releasing name (%s, %s)",
00236                     handler->name, thread_state.dbus_err.message);
00237             dbus_error_free(&thread_state.dbus_err);
00238         }
00239         gsh_free(handler->name);
00240         gsh_free(handler);
00241     }
00242     avltree_init(&thread_state.callouts, dbus_callout_cmpf, 0);
00243 
00244     /* shutdown bus */
00245     if (thread_state.dbus_conn)
00246         dbus_connection_close(thread_state.dbus_conn);
00247 }
00248 
00249 void *gsh_dbus_thread(void *arg)
00250 {
00251     struct avltree_node *node;
00252     ganesha_dbus_handler_t hk, *handler;
00253     DBusMessage* msg;
00254 
00255     SetNameFunction("gsh_dbus_thread");
00256 
00257     if (! thread_state.dbus_conn) {
00258         LogCrit(COMPONENT_DBUS, "DBUS not initialized, service thread "
00259                 "exiting");
00260         goto out;
00261     }
00262 
00263     while (1) {
00264         if (thread_state.flags & GSH_DBUS_SHUTDOWN)
00265             break;
00266 
00267         LogFullDebug(COMPONENT_DBUS, "top of poll loop");
00268 
00269         /* do stuff */
00270         dbus_connection_read_write_dispatch(thread_state.dbus_conn, 30*1000);
00271 
00272         /* deal with message (ignore timeouts) */
00273         msg = dbus_connection_pop_message(thread_state.dbus_conn);
00274         if (! msg)
00275             continue;
00276 
00277         hk.name = (char *) dbus_message_get_path(msg);
00278         if (! hk.name) {
00279             LogDebug(COMPONENT_DBUS, "dbus_msg_get_path returned NULL");
00280             continue;
00281         }
00282         LogFullDebug(COMPONENT_DBUS, "recv msg: %s", hk.name);
00283         node = avltree_lookup(&hk.node_k, &thread_state.callouts);
00284         if (node) {
00285             handler = avltree_container_of(node, ganesha_dbus_handler_t,
00286                                            node_k);
00287             /* we are serialized by the bus */
00288             /* XXX libdbus call it in this configuration? */
00289             handler->vtable.message_function(thread_state.dbus_conn, msg, 0);
00290         } else {
00291             LogDebug(COMPONENT_DBUS, "msg for unknown handler %s",
00292                      hk.name);
00293         }
00294     } /* 1 */
00295 
00296 out:
00297     LogCrit(COMPONENT_DBUS, "shutdown");
00298 
00299     return (NULL);
00300 }
00301 
00302 void gsh_dbus_wake_thread(uint32_t flags)
00303 {
00304     if (thread_state.flags & GSH_DBUS_SLEEPING)
00305         pthread_cond_signal(&thread_state.we.cv);
00306 }