init.c

Go to the documentation of this file.
00001 /**
00002  * @file init.c
00003  * @brief This file implements all initialisation and shutdown of the library.
00004  */
00005 
00006 /*
00007  * This file is part of liberipc.
00008  *
00009  * liberipc is free software: you can redistribute it and/or modify
00010  * it under the terms of the GNU General Public License as published by
00011  * the Free Software Foundation, either version 2 of the License, or
00012  * (at your option) any later version.
00013  *
00014  * liberipc is distributed in the hope that it will be useful,
00015  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00016  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
00017  * GNU General Public License for more details.
00018  *
00019  * You should have received a copy of the GNU General Public License
00020  * along with this program. If not, see <http://www.gnu.org/licenses/>.
00021  */
00022 
00023 /**
00024  * Copyright (C) 2008 iRex Technologies B.V. 
00025  * All rights reserved.
00026  *
00027  * Based on code found in libosso library by Kimmo Hämäläinen <kimmo.hamalainen@nokia.com>
00028  */
00029 
00030 #include "stdio.h"
00031 #include "internal.h"
00032 #include "init.h"
00033 #include <assert.h>
00034 #include "eripc.h"
00035 
00036 #define UNUSED(x) (void)(x)
00037 
00038 static DBusHandlerResult
00039 _filter_session(DBusConnection *conn, DBusMessage *msg, void *data);
00040 
00041 static DBusHandlerResult
00042 _filter_system(DBusConnection *conn, DBusMessage *msg, void *data);
00043 
00044 inline static DBusHandlerResult
00045 _filter(DBusConnection *conn, DBusMessage *msg, void *data,
00046               eripc_bus_t dbus_type);
00047 
00048 static const char *opm_match_all_key = ERIPC_PATH_MATCH_ALL
00049                                        ERIPC_MEMBER_MATCH_ALL;
00050 
00051 inline static void
00052 compose_opm_hash_key(const char *object_path, const char *member,
00053                      char *key)
00054 {
00055     key[0] = '\0';
00056     if (object_path == NULL && member == NULL) {
00057         strncat(key, opm_match_all_key, MAX_OP_LEN + MAX_MEMBER_LEN);
00058     } else if (object_path == NULL) {
00059         strncat(key, ERIPC_PATH_MATCH_ALL, MAX_OP_LEN);
00060         strncat(key, member, MAX_MEMBER_LEN);
00061     } else if (member == NULL) {
00062         strncat(key, object_path, MAX_OP_LEN);
00063         strncat(key, ERIPC_MEMBER_MATCH_ALL, MAX_MEMBER_LEN);
00064     } else {
00065         strncat(key, object_path, MAX_OP_LEN);
00066         strncat(key, member, MAX_MEMBER_LEN);
00067     }
00068 }
00069 
00070 gboolean __attribute__ ((visibility("hidden")))
00071 validate_appname(const gchar *application)
00072 {
00073     if (application == NULL || strstr(application, "/") != NULL) {
00074    return FALSE;
00075     }
00076     return TRUE;
00077 }
00078 
00079 /************************************************************************/
00080 
00081 eripc_context_t *eripc_init(const char *program_name,
00082                             const char *program_version,
00083                             GMainContext *context)
00084 {
00085     osso_context_t *osso;
00086 
00087     char *name = strdup(program_name);
00088     if (name == NULL) {
00089         ULOG_CRIT_F("initialisation failed: out of memory");
00090         return NULL;
00091     }
00092     
00093     // replace dashes (-) with underscores (_) as dbus chokes on dashes
00094     unsigned int i;
00095     for (i=0; i<strlen(name); i++)
00096     {
00097         if (name[i] == '-')
00098             name[i] = '_';
00099     }
00100 
00101     ULOG_DEBUG_F("program '%s', version '%s'", name,
00102                  program_version);
00103 
00104     osso = _init(name, program_version);
00105     free(name);
00106     if (osso == NULL) {
00107         ULOG_CRIT_F("initialisation failed: out of memory");
00108         return NULL;
00109     }
00110 
00111     osso->conn = _dbus_setup(osso, DBUS_BUS_SESSION, context);
00112     if (osso->conn == NULL) {
00113         ULOG_CRIT_F("connecting to the session bus failed");
00114         _deinit(osso);
00115         return NULL;
00116     }
00117     osso->sys_conn = _dbus_setup(osso, DBUS_BUS_SYSTEM, context);
00118     if (osso->sys_conn == NULL) {
00119         ULOG_CRIT_F("connecting to the system bus failed");
00120       _deinit(osso);
00121         return NULL;
00122     }
00123     osso->eripc_filters_setup = TRUE;
00124     osso->cur_conn = NULL;
00125     return (eripc_context_t*)osso;
00126 }
00127 
00128 /************************************************************************/
00129 
00130 static gboolean _validate(const gchar *application, const gchar* version)
00131 {
00132     if (application == NULL || version == NULL) {
00133    return FALSE;
00134     }
00135     if (!validate_appname(application)) {
00136    return FALSE;
00137     }
00138     if (strchr(version, '/') != NULL) {
00139         ULOG_ERR_F("invalid version string '%s'", version);
00140    return FALSE;
00141     }
00142     return TRUE;
00143 }
00144 
00145 void __attribute__ ((visibility("hidden")))
00146 make_default_interface(const char *application, char *interface)
00147 {
00148     assert(application != NULL);
00149     assert(interface != NULL);
00150 
00151     if (g_strrstr(application, ".") != NULL) {
00152         g_snprintf(interface, MAX_IF_LEN, "%s", application);
00153     } else {
00154         g_snprintf(interface, MAX_IF_LEN, OSSO_BUS_ROOT ".%s",
00155                    application);
00156     }
00157 }
00158 
00159 void __attribute__ ((visibility("hidden")))
00160 make_default_error_name(const char *service, const char *name,
00161                         char *ready_name)
00162 {
00163     assert(service != NULL);
00164     assert(name != NULL);
00165     assert(ready_name != NULL);
00166 
00167     if (g_strrstr(name, ".") != NULL) {
00168         g_snprintf(ready_name, MAX_ERROR_LEN, "%s", name);
00169     } else {
00170         g_snprintf(ready_name, MAX_ERROR_LEN, "%s.%s", service, name);
00171     }
00172 }
00173 
00174 void __attribute__ ((visibility("hidden")))
00175 make_default_service(const char *application, char *service)
00176 {
00177     assert(application != NULL);
00178     assert(service != NULL);
00179 
00180     if (g_strrstr(application, ".") != NULL) {
00181         g_snprintf(service, MAX_SVC_LEN, "%s", application);
00182     } else {
00183         g_snprintf(service, MAX_SVC_LEN, OSSO_BUS_ROOT ".%s",
00184                    application);
00185     }
00186 }
00187 
00188 void __attribute__ ((visibility("hidden")))
00189 make_default_object_path(const char *application, char *path)
00190 {
00191     char component[MAX_OP_LEN + 1], *p;
00192 
00193     assert(application != NULL);
00194     assert(path != NULL);
00195 
00196     strncpy(component, application, MAX_OP_LEN);
00197     component[MAX_OP_LEN] = '\0';
00198 
00199     for (p = component; *p != '\0'; ++p) {
00200          if (*p == '.') {
00201              *p = '/';
00202          }
00203     }
00204 
00205     if (strchr(application, '.') != NULL) {
00206         g_snprintf(path, MAX_OP_LEN, "/%s", component);
00207     } else {
00208         g_snprintf(path, MAX_OP_LEN, OSSO_BUS_ROOT_PATH "/%s", component);
00209     }
00210 }
00211 
00212 /************************************************************************/
00213 
00214 static void free_handler(gpointer data, gpointer user_data)
00215 {
00216     UNUSED(user_data);
00217     _osso_handler_t *h = data;
00218 
00219     if (h != NULL) {
00220         if (h->can_free_data) {
00221             free(h->data);
00222             h->data = NULL;
00223         }
00224         free(h);
00225     }
00226 }
00227 
00228 static void free_uniq_hash_value(gpointer data)
00229 {
00230     _osso_hash_value_t *elem = data;
00231 
00232     if (elem != NULL) {
00233         if (elem->handlers != NULL) {
00234             g_slist_foreach(elem->handlers, free_handler, NULL);
00235             g_slist_free(elem->handlers);
00236             elem->handlers = NULL;
00237         }
00238         free(elem);
00239     }
00240 }
00241 
00242 static void free_if_hash_value(gpointer data)
00243 {
00244     _osso_hash_value_t *elem = data;
00245 
00246     if (elem != NULL) {
00247         if (elem->handlers != NULL) {
00248             g_slist_free(elem->handlers);
00249             elem->handlers = NULL;
00250         }
00251         free(elem);
00252     }
00253 }
00254 
00255 static osso_context_t *_init(const char *application,
00256                                    const char *version)
00257 {
00258     osso_context_t *osso;
00259     
00260     if (!_validate(application, version)) {
00261    ULOG_ERR_F("invalid arguments");
00262    return NULL;
00263     }
00264 
00265     osso = calloc(1, sizeof(osso_context_t));
00266     if (osso == NULL) {
00267    ULOG_ERR_F("calloc failed");
00268    return NULL;
00269     } 
00270 
00271     g_snprintf(osso->application, MAX_APP_NAME_LEN, "%s", application);
00272     g_snprintf(osso->version, MAX_VERSION_LEN, "%s", version);
00273     make_default_interface((const char*)application, osso->interface);
00274     make_default_service((const char*)application, osso->service);
00275     make_default_object_path((const char*)application, osso->object_path);
00276 
00277     osso->opm_hash = g_hash_table_new_full(g_str_hash, g_str_equal,
00278                                           free, free_if_hash_value);
00279     osso->id_hash = g_hash_table_new_full(g_direct_hash, g_direct_equal,
00280                                           NULL, free_uniq_hash_value);
00281     if (osso->id_hash == NULL || osso->opm_hash == NULL) {
00282         ULOG_ERR_F("g_hash_table_new_full failed");
00283         free(osso);
00284         return NULL;
00285     }
00286     osso->cp_plugins = g_hash_table_new(g_str_hash, g_str_equal);
00287     osso->timeout_ms = 500; /* ms */
00288     osso->next_handler_id = 1;
00289     return osso;
00290 }
00291 
00292 /*************************************************************************/
00293 
00294 static void _deinit(osso_context_t *osso)
00295 {
00296     if (osso == NULL) {
00297    return;
00298     }
00299     if (osso->uniq_hash != NULL) {
00300         g_hash_table_destroy(osso->uniq_hash);
00301     }
00302     if (osso->if_hash != NULL) {
00303         g_hash_table_destroy(osso->if_hash);
00304     }
00305     if (osso->opm_hash != NULL) {
00306         g_hash_table_destroy(osso->opm_hash);
00307     }
00308     if (osso->id_hash != NULL) {
00309         g_hash_table_destroy(osso->id_hash);
00310     }
00311     if (osso->cp_plugins != NULL) {
00312         g_hash_table_destroy(osso->cp_plugins);
00313     }
00314     
00315     memset(osso, 0, sizeof(osso_context_t));
00316     free(osso);
00317     osso = NULL;
00318 }
00319 
00320 /*************************************************************************/
00321 
00322 static DBusConnection *_dbus_setup(osso_context_t*osso,
00323                                          DBusBusType bus_type,
00324                                          GMainContext *context)
00325 {
00326     DBusConnection *conn;
00327     DBusError err;
00328     int ret;
00329     
00330     dbus_error_init(&err);
00331 
00332     /* TODO: add dbus_connection_unref calls when the fixed D-Bus
00333      * is available */
00334     conn = dbus_bus_get(bus_type, &err);
00335     if (conn == NULL) {
00336         ULOG_ERR_F("Unable to connect to the D-Bus %s bus: %s",
00337                    bus_type == DBUS_BUS_SESSION ? "session" : "system",
00338                    err.message);
00339         dbus_error_free(&err);
00340         return NULL;
00341     }
00342     dbus_connection_setup_with_g_main(conn, context);
00343 
00344     ret = dbus_bus_request_name(conn, osso->service,
00345                                 DBUS_NAME_FLAG_ALLOW_REPLACEMENT, &err);
00346     if (ret == -1) {
00347         ULOG_ERR_F("dbus_bus_request_name failed: %s", err.message);
00348    dbus_error_free(&err);
00349    return NULL;
00350     }
00351 
00352     dbus_connection_set_exit_on_disconnect(conn, FALSE);
00353 
00354     if (bus_type == DBUS_BUS_SESSION) {
00355         if (!dbus_connection_add_filter(conn, _filter_session,
00356                                         osso, NULL)) {
00357             ULOG_ERR_F("dbus_connection_add_filter failed");
00358        return NULL;
00359         }
00360     } else {
00361         if (!dbus_connection_add_filter(conn, _filter_system,
00362                                         osso, NULL)) {
00363             ULOG_ERR_F("dbus_connection_add_filter failed");
00364        return NULL;
00365         }
00366     }
00367 
00368     dprint("My base service is '%s'", dbus_bus_get_unique_name(conn));
00369 
00370     return conn;
00371 }
00372 
00373 /*************************************************************************/
00374 
00375 DBusHandlerResult __attribute__ ((visibility("hidden")))
00376 _msg_handler(DBusConnection *conn, DBusMessage *msg, void *data)
00377 {
00378     osso_context_t *osso;
00379     _osso_hash_value_t *elem;
00380     gboolean is_method;
00381     const char *interface;
00382     gboolean found = FALSE;
00383     
00384     osso = data;
00385 
00386     assert(osso != NULL);
00387 
00388     if (dbus_message_get_type(msg) == DBUS_MESSAGE_TYPE_METHOD_CALL)
00389    is_method = TRUE;
00390     else if (dbus_message_get_type(msg) == DBUS_MESSAGE_TYPE_SIGNAL)
00391    is_method = FALSE;
00392     else
00393    return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
00394 
00395     /* FIXME: this is kind of brain-damaged: only interface is considered
00396      * (would require new API to fix, to keep backwards compatibility) */
00397     interface = dbus_message_get_interface(msg);
00398 
00399     if (interface == NULL) {
00400         ULOG_DEBUG_F("interface of the message was NULL");
00401         return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
00402     }
00403 
00404     ULOG_DEBUG_F("key = '%s'", interface);
00405     elem = g_hash_table_lookup(osso->if_hash, interface);
00406 
00407     if (elem != NULL) {
00408         GSList *list;
00409 
00410         osso->cur_conn = conn;
00411         ULOG_DEBUG_F(" elem");
00412         
00413         list = elem->handlers;
00414         while (list != NULL) {
00415             _osso_handler_t *handler;
00416 
00417             handler = list->data;
00418 
00419             ULOG_DEBUG_F(" list");
00420 
00421             if (handler->method == is_method) {
00422                 ULOG_DEBUG_F("before calling the handler");
00423                 ULOG_DEBUG_F(" handler = %p", handler->handler);
00424                 ULOG_DEBUG_F(" data = %p", handler->data);
00425                 (*handler->handler)(osso, msg, handler->data, 0);
00426                 ULOG_DEBUG_F("after calling the handler");
00427                 found = TRUE;
00428             }
00429 
00430             list = g_slist_next(list);
00431         }
00432     } 
00433     
00434     if (!found) {
00435         ULOG_DEBUG_F("suitable handler not found from the hash table");
00436     }
00437 
00438 #if 0
00439     for(i=0; i<osso->ifs->len; i++) {
00440    _osso_interface_t *intf;
00441    DBusHandlerResult r;
00442    intf = &g_array_index(osso->ifs, _osso_interface_t, i);
00443    if(intf->method == is_method) {
00444 //     dprint("comparing '%s' to '%s'",interface, intf->interface);
00445        if(strcmp(interface, intf->interface) == 0) {
00446 //    dprint("match!, now calling callback at %p", intf->handler);
00447       r = (intf->handler)(osso, msg, intf->data);
00448       if(r == DBUS_HANDLER_RESULT_HANDLED) {
00449           return r;
00450       }
00451        }
00452    }
00453     } 
00454 #endif
00455 
00456     return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
00457 }
00458 
00459 int
00460 eripc_convert_msgtype(int t)
00461 {
00462     switch (t) {
00463             case DBUS_MESSAGE_TYPE_METHOD_CALL:
00464                     return ERIPC_EVENT_MESSAGE;
00465             case DBUS_MESSAGE_TYPE_SIGNAL:
00466                     return ERIPC_EVENT_SIGNAL;
00467             case DBUS_MESSAGE_TYPE_ERROR:
00468                     return ERIPC_EVENT_ERROR;
00469             case DBUS_MESSAGE_TYPE_METHOD_RETURN:
00470                     return ERIPC_EVENT_REPLY;
00471             default:
00472                     ULOG_ERR_F("unknown message type %d", t);
00473                     return ERIPC_EVENT_NONE;
00474     }
00475 }
00476 
00477 inline static int types_match(int a, int b)
00478 {
00479     if (a == b) return 1;
00480 
00481     if (a == ERIPC_EVENT_MESSAGE_OR_SIGNAL &&
00482         (b == ERIPC_EVENT_MESSAGE || b == ERIPC_EVENT_SIGNAL))
00483             return 1;
00484 
00485     if (a == ERIPC_EVENT_REPLY_OR_ERROR &&
00486         (b == ERIPC_EVENT_REPLY || b == ERIPC_EVENT_ERROR))
00487             return 1;
00488 
00489     if (b == ERIPC_EVENT_MESSAGE_OR_SIGNAL &&
00490         (a == ERIPC_EVENT_MESSAGE || a == ERIPC_EVENT_SIGNAL))
00491             return 1;
00492 
00493     if (b == ERIPC_EVENT_REPLY_OR_ERROR &&
00494         (a == ERIPC_EVENT_REPLY || a == ERIPC_EVENT_ERROR))
00495             return 1;
00496 
00497     return 0;
00498 }
00499 
00500 inline static int str_match(const char *a, const char *b)
00501 {
00502     if (a == NULL || b == NULL) return 1;
00503 
00504     if (strcmp(a, b) == 0) return 1;
00505 
00506     return 0;
00507 }
00508 
00509 static DBusHandlerResult
00510 _filter_session(DBusConnection *conn, DBusMessage *msg, void *data)
00511 {
00512     return _filter(conn, msg, data, ERIPC_BUS_SESSION);
00513 }
00514 
00515 static DBusHandlerResult
00516 _filter_system(DBusConnection *conn, DBusMessage *msg, void *data)
00517 {
00518     return _filter(conn, msg, data, ERIPC_BUS_SYSTEM);
00519 }
00520 
00521 inline static void opm_match_helper(const char *object_path,
00522                                     const char *member,
00523                                     char *key)
00524 {
00525     key[0] = '\0';
00526     strncat(key, object_path, MAX_OP_LEN);
00527     strncat(key, member, MAX_MEMBER_LEN);
00528 }
00529 
00530 /* Returns a GSList of _osso_hash_value_t pointers */
00531 inline static GSList *opm_match(osso_context_t *ipc,
00532                                 const char *path,
00533                                 const char *member)
00534 {
00535     GSList *list = NULL;
00536     _osso_hash_value_t *elem;
00537     char opm_key[MAX_OPM_HASH_KEY_LEN + 1];
00538 
00539     if (path != NULL && member != NULL) {
00540         /* direct match? */
00541         opm_match_helper(path, member, opm_key);
00542         elem = g_hash_table_lookup(ipc->opm_hash, opm_key);
00543         if (elem != NULL) list = g_slist_prepend(list, elem);
00544     }
00545 
00546     /* return list of match-'em-all handlers */
00547     elem = g_hash_table_lookup(ipc->opm_hash, opm_match_all_key);
00548     if (elem != NULL) list = g_slist_prepend(list, elem);
00549 
00550     if (member != NULL) {
00551         /* any path + member? */
00552         opm_match_helper(ERIPC_PATH_MATCH_ALL, member, opm_key);
00553         elem = g_hash_table_lookup(ipc->opm_hash, opm_key);
00554         if (elem != NULL) list = g_slist_prepend(list, elem);
00555     }
00556 
00557     if (path != NULL) {
00558         /* path + any member? */
00559         opm_match_helper(path, ERIPC_MEMBER_MATCH_ALL, opm_key);
00560         elem = g_hash_table_lookup(ipc->opm_hash, opm_key);
00561         if (elem != NULL) list = g_slist_prepend(list, elem);
00562     }
00563 
00564     return list;
00565 }
00566 
00567 /* filter function for API */
00568 inline static DBusHandlerResult
00569 _filter(DBusConnection *conn, DBusMessage *msg, void *data,
00570               eripc_bus_t dbus_type)
00571 {
00572     osso_context_t *ipc;
00573     GSList *elem_list, *elem_list_p, *rm_list = NULL, *rm_list_p;
00574     int msgtype;
00575     unsigned int reply_to;
00576     gboolean found = FALSE;
00577     
00578     ipc = data;
00579 
00580     assert(ipc != NULL);
00581     ipc->cur_conn = conn;
00582 
00583     msgtype = eripc_convert_msgtype(dbus_message_get_type(msg));
00584     if (msgtype == ERIPC_EVENT_NONE) {
00585         ULOG_DEBUG_F("_filter: ERIPC_EVENT_NONE");
00586         return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
00587     }
00588     reply_to = dbus_message_get_reply_serial(msg);
00589 
00590     elem_list = opm_match(ipc, dbus_message_get_path(msg),
00591                           dbus_message_get_member(msg));
00592 
00593     elem_list_p = elem_list;
00594     while (elem_list_p != NULL) {
00595         _osso_hash_value_t *elem;
00596 
00597         elem = elem_list_p->data;
00598 
00599         if (elem != NULL) {
00600             GSList *list;
00601             int last_id = 0;
00602 
00603             list = elem->handlers;
00604             while (list != NULL) {
00605                 _osso_handler_t *handler;
00606                 _osso_callback_data_t *cb_data;
00607                 gboolean match_sender = TRUE;
00608 
00609                 handler = list->data;
00610 
00611 /*
00612                 if (handler) {
00613                         ULOG_DEBUG_F("found handler");
00614                         if (handler->data != NULL) {
00615                                 ULOG_DEBUG_F("s/p/n t/i: %s/%s/%s %d/%s",
00616                                     handler->data->service,
00617                                     handler->data->path,
00618                                     handler->data->name,
00619                                     handler->data->event_type,
00620                                     handler->data->interface);
00621 
00622                                 ULOG_DEBUG_F("s/p/n t/i: %s/%s/%s %d/%s",
00623                                     dbus_message_get_sender(msg),
00624                                     dbus_message_get_path(msg),
00625                                     dbus_message_get_member(msg),
00626                                     msgtype,
00627                                     dbus_message_get_interface(msg));
00628 
00629                                 ULOG_DEBUG_F("types: %d %d",
00630                                     handler->data->event_type, msgtype);
00631                         }
00632                 }
00633 */
00634 
00635                 /* Note: this relies on the fact that the handlers with the
00636                  * same id are adjacent in the list */
00637                 if (handler->call_once_per_handler_id
00638                     && handler->handler_id == last_id) {
00639                         /* do not call the callback this time, workaround for
00640                          * ERIPC_EVENT_MESSAGE_OR_SIGNAL etc. implementation */
00641                         ULOG_DEBUG_F("handler already called, skip");
00642                         list = g_slist_next(list);
00643                         continue;
00644                 }
00645 
00646                 cb_data = handler->data;
00647                 
00648                 if (cb_data != NULL && cb_data->message_id != 0
00649                     && cb_data->message_id == reply_to) {
00650                         /* this (one-shot) handler was created for this
00651                          * (reply) message */
00652                         ULOG_DEBUG_F("calling one-shot handler at %p,"
00653                                      " data=%p", handler->handler, cb_data);
00654                         (*handler->handler)(ipc, msg, cb_data, dbus_type);
00655                         ULOG_DEBUG_F("after calling handler at %p",
00656                                      handler->handler);
00657                         found = TRUE;
00658                         /* The handler is one-shot (because the serial is
00659                          * supposed to be unique). Add it to list to remove
00660                          * it later safely outside this loop. */
00661                         rm_list = g_slist_prepend(rm_list,
00662                                       GINT_TO_POINTER(handler->handler_id));
00663 
00664                         list = g_slist_next(list);
00665                         continue;
00666                 }
00667 
00668                 if (cb_data != NULL && cb_data->bus_type != ERIPC_BUS_BOTH
00669                     && cb_data->bus_type != dbus_type) {
00670                         /* handler is not for this bus type */
00671                         ULOG_DEBUG_F("handler is not for this bus type, skip");
00672                         list = g_slist_next(list);
00673                         continue;
00674                 }
00675 
00676                 if (msgtype == ERIPC_EVENT_SIGNAL) {
00677                         /* does not make sense to match sender in case
00678                          * of a D-Bus signal, because D-Bus uses the
00679                          * (practically random) unique bus name as the
00680                          * sender */
00681                         match_sender = FALSE;
00682                 }
00683 
00684                 if (cb_data != NULL &&
00685                     types_match(cb_data->event_type, msgtype) &&
00686                     (!match_sender || str_match(cb_data->service,
00687                                           dbus_message_get_sender(msg))) &&
00688                     str_match(cb_data->interface,
00689                               dbus_message_get_interface(msg))) {
00690                     /* object path and member have matched already */
00691 
00692                     ULOG_DEBUG_F("before calling the handler at %p, data=%p",
00693                                  handler->handler, cb_data);
00694                     (*handler->handler)(ipc, msg, cb_data, dbus_type);
00695                     ULOG_DEBUG_F("after calling handler at %p",
00696                                  handler->handler);
00697                     found = TRUE;
00698                 }
00699 
00700                 last_id = handler->handler_id;
00701                 list = g_slist_next(list);
00702             }
00703         }
00704 
00705         elem_list_p = g_slist_next(elem_list_p);
00706     }
00707     
00708     if (elem_list != NULL) {
00709         g_slist_free(elem_list);
00710     }
00711 
00712     if (rm_list != NULL) {
00713         rm_list_p = rm_list;
00714         do {
00715             gboolean ret;
00716             int handler_id = GPOINTER_TO_INT(rm_list_p->data);
00717 
00718             assert(handler_id != 0);
00719             ret = _unset_handler(ipc, handler_id);
00720             assert(ret);
00721 
00722             rm_list_p = g_slist_next(rm_list_p);
00723         } while (rm_list_p != NULL);
00724         g_slist_free(rm_list);
00725     }
00726 
00727     if (!found) {
00728         ULOG_DEBUG_F("suitable handler not found for '%s/%s'",
00729                      dbus_message_get_path(msg),
00730                      dbus_message_get_member(msg));
00731     }
00732     else {
00733         return DBUS_HANDLER_RESULT_HANDLED;
00734     }
00735     return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
00736 }
00737 
00738 /************************************************************************/
00739 
00740 static gboolean add_to_opm_hash(osso_context_t *osso,
00741                                 const _osso_handler_t *handler,
00742                                 const char *opm_key)
00743 {
00744     _osso_hash_value_t *old;
00745 
00746     old = g_hash_table_lookup(osso->opm_hash, opm_key);
00747     if (old != NULL) {
00748         old->handlers = g_slist_append(old->handlers,
00749                                        (_osso_handler_t*)handler);
00750     } else {
00751         _osso_hash_value_t *new_elem;
00752         char *new_key;
00753 
00754         /* we need to allocate a new hash table element */
00755         new_elem = calloc(1, sizeof(_osso_hash_value_t));
00756         if (new_elem == NULL) {
00757             ULOG_ERR_F("calloc() failed");
00758             return FALSE;
00759         }
00760 
00761         new_key = strdup(opm_key);
00762         if (new_key == NULL) {
00763             ULOG_ERR_F("calloc() failed");
00764             free(new_elem);
00765             return FALSE;
00766         }
00767 
00768         new_elem->handlers = g_slist_append(NULL, (_osso_handler_t*)handler);
00769 
00770         g_hash_table_insert(osso->opm_hash, new_key, new_elem);
00771     }
00772     return TRUE;
00773 }
00774 
00775 gboolean __attribute__ ((visibility("hidden")))
00776 _eripc_set_handler(_eripc_context_t *context,
00777                    _osso_handler_f *handler,
00778                    _osso_callback_data_t *data, 
00779                    int handler_id,
00780                    gboolean call_once_per_handler_id)
00781 {   
00782     char opm_key[MAX_OPM_HASH_KEY_LEN + 1];
00783     _osso_hash_value_t *old;
00784     _osso_handler_t *elem;
00785 
00786     assert(context != NULL && handler != NULL && data != NULL);
00787     assert(handler_id != 0);
00788 
00789     compose_opm_hash_key(data->path, data->name, opm_key);
00790 
00791     elem = calloc(1, sizeof(_osso_handler_t));
00792     if (elem == NULL) {
00793         ULOG_ERR_F("calloc() failed");
00794         return FALSE;
00795     }
00796 
00797     elem->handler = handler;
00798     elem->data = data;
00799     elem->handler_id = handler_id;
00800     elem->call_once_per_handler_id = call_once_per_handler_id;
00801     /* other members are not used and left zero */
00802 
00803     old = g_hash_table_lookup(context->id_hash, GINT_TO_POINTER(handler_id));
00804     if (old != NULL) {
00805         ULOG_DEBUG_F("registering another handler for id %d", handler_id);
00806 
00807         /* add it to the list of handlers */
00808         old->handlers = g_slist_append(old->handlers, elem);
00809 
00810     } else {
00811         _osso_hash_value_t *new_elem;
00812 
00813         ULOG_DEBUG_F("registering first handler for id %d", handler_id);
00814 
00815         /* we need to allocate a new hash table element */
00816         new_elem = calloc(1, sizeof(_osso_hash_value_t));
00817         if (new_elem == NULL) {
00818             ULOG_ERR_F("calloc() failed");
00819             free(elem);
00820             return FALSE;
00821         }
00822 
00823         new_elem->handlers = g_slist_append(NULL, elem);
00824 
00825         g_hash_table_insert(context->id_hash, GINT_TO_POINTER(handler_id),
00826                             new_elem);
00827     }
00828 
00829     return add_to_opm_hash(context, elem, opm_key);
00830 }
00831 
00832 static void remove_from_opm_hash(_eripc_context_t *context,
00833                                  int handler_id,
00834                                  const char *opm_key)
00835 {
00836     _osso_hash_value_t *elem;
00837 
00838     elem = g_hash_table_lookup(context->opm_hash, opm_key);
00839     if (elem != NULL) {
00840         GSList *list;
00841 
00842         list = elem->handlers;
00843         while (list != NULL) {
00844             _osso_handler_t *h = list->data;
00845             GSList *next_elem;
00846 
00847             next_elem = g_slist_next(list);
00848 
00849             if (h->handler_id == handler_id) {
00850                 ULOG_DEBUG_F("found handler_id %d from if_hash", handler_id);
00851                 elem->handlers = g_slist_remove_link(elem->handlers, list);
00852                 g_slist_free_1(list); /* free the removed link */
00853 
00854                 /* if this was the last element in the list, free the
00855                  * list and the hash element */
00856                 if (g_slist_length(elem->handlers) == 0) {
00857                     g_hash_table_remove(context->opm_hash, opm_key);
00858                     return;
00859                 }
00860             }
00861             list = next_elem;
00862         }
00863     }
00864 }
00865 
00866 gboolean __attribute__ ((visibility("hidden")))
00867 _unset_handler(_eripc_context_t *context, int handler_id)
00868 {
00869     _osso_hash_value_t *elem;
00870     GSList *list;
00871 
00872     ULOG_DEBUG_F("context=%p", context);
00873     elem = g_hash_table_lookup(context->id_hash, GINT_TO_POINTER(handler_id));
00874     if (elem == NULL) {
00875         ULOG_ERR_F("couldn't find handler_id %d from id_hash", handler_id);
00876         return FALSE;
00877     }
00878 
00879     /* remove handlers from the interface hash */
00880     list = elem->handlers;
00881     while (list != NULL) {
00882         char opm_key[MAX_OPM_HASH_KEY_LEN + 1];
00883         DBusError err;
00884         _osso_handler_t *h = list->data;
00885 
00886         compose_opm_hash_key(h->data->path, h->data->name, opm_key);
00887         remove_from_opm_hash(context, handler_id, opm_key);
00888 
00889         dbus_error_init(&err);
00890 
00891         if (h->data->match_rule && (h->data->bus_type == ERIPC_BUS_SYSTEM
00892             || h->data->bus_type == ERIPC_BUS_BOTH)) {
00893             dbus_bus_remove_match(context->sys_conn, h->data->match_rule,
00894                                   &err);
00895             if (dbus_error_is_set(&err)) {
00896                 ULOG_WARN_F("dbus_bus_remove_match failed for %s: %s",
00897                             h->data->match_rule, err.message);
00898                 dbus_error_free(&err);
00899                 dbus_error_init(&err);
00900             }
00901         }
00902 
00903         if (h->data->match_rule && (h->data->bus_type == ERIPC_BUS_SESSION
00904             || h->data->bus_type == ERIPC_BUS_BOTH)) {
00905             dbus_bus_remove_match(context->conn, h->data->match_rule,
00906                                   &err);
00907             if (dbus_error_is_set(&err)) {
00908                 ULOG_WARN_F("dbus_bus_remove_match failed for %s: %s",
00909                             h->data->match_rule, err.message);
00910                 dbus_error_free(&err);
00911             }
00912         }
00913 
00914         free(h->data->service); h->data->service = NULL;
00915         if (h->data->path != NULL
00916             && strcmp(ERIPC_PATH_MATCH_ALL, h->data->path) != 0) {
00917             free(h->data->path); h->data->path = NULL;
00918         }
00919         free(h->data->interface); h->data->interface = NULL;
00920         if (h->data->name != NULL
00921             && strcmp(ERIPC_MEMBER_MATCH_ALL, h->data->name) != 0) {
00922             free(h->data->name); h->data->name = NULL;
00923         }
00924         free(h->data); h->data = NULL;
00925 
00926         list = g_slist_next(list);
00927     }
00928 
00929     if (!g_hash_table_remove(context->id_hash, GINT_TO_POINTER(handler_id))) {
00930         ULOG_ERR_F("couldn't find handler_id %d from id_hash", handler_id);
00931         assert(0); /* this is a bug */
00932     }
00933 
00934     return TRUE;
00935 }
Generated by  doxygen 1.6.2-20100208