/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*- */ /* * oafd: OAF CORBA dameon. * * Copyright (C) 1999, 2000 Red Hat, Inc. * Copyright (C) 1999, 2000 Eazel, Inc. * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU 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 * General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this library; if not, write to the Free Software * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. * * Authors: Elliot Lee , * */ #include "config.h" #include #include #include #include #include #include #include #include "server.h" #include "object-directory.h" #include "bonobo-activation/bonobo-activation-private.h" #include "activation-server-corba-extensions.h" #include /* no longer used. */ #define RESIDUAL_SERVERS 0 static GObjectClass *parent_class = NULL; static gboolean finished_internal_registration = FALSE; typedef struct { char *iid; int n_servers; struct { Bonobo_ActivationEnvironment environment; CORBA_Object server; } servers [1]; /* flexible array */ } ActiveServerList; typedef struct { /* client's environment */ Bonobo_ActivationEnvironment *env; /* "runtime" servers registered by this client */ CORBA_sequence_CORBA_string *runtime_iids; } ClientContext; static void client_context_free (ClientContext *self) { CORBA_free (self->env); if (self->runtime_iids) CORBA_free (self->runtime_iids); g_free (self); } static ObjectDirectory *main_dir = NULL; #ifdef BONOBO_ACTIVATION_DEBUG static void od_dump_list (ObjectDirectory * od) { #if 0 int i, j, k; for (i = 0; i < od->attr_servers->_length; i++) { g_print ("IID %s, type %s, location %s\n", od->attr_servers->_buffer[i].iid, od->attr_servers->_buffer[i].server_type, od->attr_servers->_buffer[i].location_info); for (j = 0; j < od->attr_servers->_buffer[i].props._length; j++) { Bonobo_ActivationProperty *prop = &(od->attr_servers->_buffer[i]. props._buffer[j]); if (strchr (prop->name, '-') != NULL) /* Translated, likely to be annoying garbage value */ continue; g_print (" %s = ", prop->name); switch (prop->v._d) { case Bonobo_ACTIVATION_P_STRING: g_print ("\"%s\"\n", prop->v._u.value_string); break; case Bonobo_ACTIVATION_P_NUMBER: g_print ("%f\n", prop->v._u.value_number); break; case Bonobo_ACTIVATION_P_BOOLEAN: g_print ("%s\n", prop->v. _u.value_boolean ? "TRUE" : "FALSE"); break; case Bonobo_ACTIVATION_P_STRINGV: g_print ("["); for (k = 0; k < prop->v._u.value_stringv._length; k++) { g_print ("\"%s\"", prop->v._u. value_stringv._buffer[k]); if (k < (prop->v._u. value_stringv._length - 1)) g_print (", "); } g_print ("]\n"); break; } } } #endif } #endif static gboolean registry_directory_needs_update (ObjectDirectory *od, const char *directory) { gboolean needs_update; struct stat statbuf; time_t old_mtime; if (g_stat (directory, &statbuf) != 0) { return FALSE; } old_mtime = (time_t) g_hash_table_lookup ( od->registry_directory_mtimes, directory); g_hash_table_insert (od->registry_directory_mtimes, (gpointer) directory, (gpointer) statbuf.st_mtime); needs_update = (old_mtime != statbuf.st_mtime); #ifdef BONOBO_ACTIVATION_DEBUG if (needs_update) g_warning ("Compare old_mtime on '%s' with %ld ==? %ld", directory, (long) old_mtime, (long) statbuf.st_mtime); #endif return needs_update; } static void update_registry (ObjectDirectory *od, gboolean force_reload) { int i; time_t cur_time; gboolean must_load; static gboolean doing_reload = FALSE; if (doing_reload) return; doing_reload = TRUE; #ifdef BONOBO_ACTIVATION_DEBUG g_warning ("Update registry %p", od->by_iid); #endif /* get first time init right */ must_load = (od->by_iid == NULL); cur_time = time (NULL); if (cur_time - 5 > od->time_did_stat) { od->time_did_stat = cur_time; for (i = 0; od->registry_source_directories[i] != NULL; i++) { if (registry_directory_needs_update (od, od->registry_source_directories[i])) must_load = TRUE; } } if (must_load || force_reload) { /* * FIXME bugzilla.eazel.com 2727: we should only reload those * directories that have actually changed instead of reloading * all when any has changed. */ #ifdef BONOBO_ACTIVATION_DEBUG g_warning ("Re-load %d %d", must_load, force_reload); #endif if (od->attr_servers) CORBA_free (od->attr_servers); od->attr_servers = CORBA_sequence_Bonobo_ServerInfo__alloc (); bonobo_server_info_load (od->registry_source_directories, od->attr_servers, od->attr_runtime_servers, &od->by_iid, bonobo_activation_hostname_get ()); od->time_did_stat = od->time_list_changed = time (NULL); #ifdef BONOBO_ACTIVATION_DEBUG od_dump_list (od); #endif if (must_load) activation_clients_cache_notify (); } doing_reload = FALSE; } static gchar ** split_path_unique (const char *colon_delimited_path) { int i, max; gboolean different; gchar **ret, **wrk; GSList *l, *tmp = NULL; g_return_val_if_fail (colon_delimited_path != NULL, NULL); wrk = g_strsplit (colon_delimited_path, G_SEARCHPATH_SEPARATOR_S, -1); g_return_val_if_fail (wrk != NULL, NULL); for (max = i = 0; wrk [i]; i++) { different = TRUE; for (l = tmp; l; l = l->next) { if (!strcmp (l->data, wrk [i])) { different = FALSE; } else if (wrk [i] == '\0') { different = FALSE; } } if (different) { tmp = g_slist_prepend (tmp, g_strdup (wrk [i])); max++; } } tmp = g_slist_reverse (tmp); ret = g_new (char *, max + 1); for (l = tmp, i = 0; l; l = l->next) ret [i++] = l->data; ret [i] = NULL; g_slist_free (tmp); g_strfreev (wrk); return ret; } static Bonobo_ServerInfoListCache * impl_Bonobo_ObjectDirectory__get_servers ( PortableServer_Servant servant, Bonobo_CacheTime only_if_newer, CORBA_Environment *ev) { ObjectDirectory *od; Bonobo_ServerInfoListCache *retval; server_lock (); od = OBJECT_DIRECTORY (servant); update_registry (od, FALSE); retval = Bonobo_ServerInfoListCache__alloc (); retval->_d = (only_if_newer < od->time_list_changed); if (retval->_d) { retval->_u.server_list = *od->attr_servers; CORBA_sequence_set_release (&retval->_u.server_list, CORBA_FALSE); } server_unlock (); return retval; } typedef struct { Bonobo_ImplementationID *seq; int last_used; } StateCollectionInfo; static void collate_active_server (char *key, gpointer value, StateCollectionInfo *sci) { sci->seq [(sci->last_used)++] = CORBA_string_dup (key); } static Bonobo_ServerStateCache * impl_Bonobo_ObjectDirectory_get_active_servers ( PortableServer_Servant servant, Bonobo_CacheTime only_if_newer, CORBA_Environment *ev) { ObjectDirectory *od; Bonobo_ServerStateCache *retval; server_lock (); od = OBJECT_DIRECTORY (servant); retval = Bonobo_ServerStateCache__alloc (); retval->_d = (only_if_newer < od->time_active_changed); if (retval->_d) { StateCollectionInfo sci; retval->_u.active_servers._length = g_hash_table_size (od->active_server_lists); retval->_u.active_servers._buffer = sci.seq = CORBA_sequence_Bonobo_ImplementationID_allocbuf (retval->_u.active_servers._length); sci.last_used = 0; g_hash_table_foreach (od->active_server_lists, (GHFunc) collate_active_server, &sci); CORBA_sequence_set_release (&(retval->_u.active_servers), CORBA_TRUE); } server_unlock (); return retval; } static CORBA_Object od_get_active_server (ObjectDirectory *od, const char *iid, const Bonobo_ActivationEnvironment *environment) { ActiveServerList *servers; CORBA_Object retval; int i; servers = g_hash_table_lookup (od->active_server_lists, iid); if (!servers) return CORBA_OBJECT_NIL; retval = CORBA_OBJECT_NIL; for (i = 0; i < servers->n_servers; i++) { if (Bonobo_ActivationEnvironment_match ( &servers->servers [i].environment, environment)) { retval = servers->servers [i].server; break; } } if (retval != CORBA_OBJECT_NIL && !CORBA_Object_non_existent (retval, NULL)) return CORBA_Object_duplicate (retval, NULL); return CORBA_OBJECT_NIL; } /* * returns (@merged_environment) new environment as result of * merging activation request environment and client registered * environment; the activation supplied environment takes precedence * over the client one */ static void od_merge_client_environment (ObjectDirectory *od, Bonobo_ServerInfo const *server, const Bonobo_ActivationEnvironment *environment, Bonobo_ActivationEnvironment *merged_environment, Bonobo_ActivationClient client) { GArray *array; int i, serverinfo_env_idx; const Bonobo_ActivationEnvironment *client_env; const Bonobo_StringList *serverinfo_env = NULL; ClientContext *client_context; array = g_array_new (FALSE, FALSE, sizeof (Bonobo_ActivationEnvValue)); /* copy all values from @environment */ for (i = 0; i < environment->_length; ++i) g_array_append_val (array, environment->_buffer[i]); if (G_UNLIKELY (client == CORBA_OBJECT_NIL)) goto exit; client_context = ((ClientContext *) g_hash_table_lookup (od->client_contexts, client)); if (G_UNLIKELY (!client_context)) goto exit; client_env = client_context->env; if (G_UNLIKELY (!client_env)) goto exit; /* scan through server properties */ if (!server) goto exit; for (i = 0; i < server->props._length; ++i) { if (strcmp (server->props._buffer[i].name, "bonobo:environment") == 0) { Bonobo_ActivationPropertyValue const *prop = &server->props._buffer[i].v; if (prop->_d == Bonobo_ACTIVATION_P_STRINGV) serverinfo_env = &prop->_u.value_stringv; else g_warning ("bonobo:environment should have type stringv"); break; } } if (!serverinfo_env) goto exit; /* do the actual merging */ for (serverinfo_env_idx = 0; serverinfo_env_idx < serverinfo_env->_length; ++serverinfo_env_idx) { CORBA_char *env = serverinfo_env->_buffer[serverinfo_env_idx]; gboolean duplicated_env = FALSE; /* check if array already has this environment */ for (i = 0; i < environment->_length; ++i) { if (strcmp (environment->_buffer[i].name, env) == 0) { duplicated_env = TRUE; break; } } if (duplicated_env) continue; /* look for environment in client_env */ for (i = 0; i < client_env->_length; ++i) { if (strcmp (client_env->_buffer[i].name, env) == 0) { g_array_append_val (array, client_env->_buffer[i]); break; } } } exit: /* return the resulting environment */ merged_environment->_buffer = (Bonobo_ActivationEnvValue *) array->data; merged_environment->_length = merged_environment->_maximum = array->len; g_array_free (array, FALSE); } static CORBA_Object impl_Bonobo_ObjectDirectory_activate ( PortableServer_Servant servant, const CORBA_char *iid, const Bonobo_ActivationContext ac, const Bonobo_ActivationEnvironment *environment, const Bonobo_ActivationFlags flags, Bonobo_ActivationClient client, CORBA_Context ctx, CORBA_Environment *ev) { ObjectDirectory *od; CORBA_Object retval = NULL; Bonobo_ServerInfo *si; ODActivationInfo ai; Bonobo_ActivationEnvironment merged_environment = { 0, }; server_lock (); od = OBJECT_DIRECTORY (servant); od_merge_client_environment (od, (Bonobo_ServerInfo *) g_hash_table_lookup (od->by_iid, iid), environment, &merged_environment, client); retval = CORBA_OBJECT_NIL; update_registry (od, FALSE); if (!(flags & Bonobo_ACTIVATION_FLAG_PRIVATE)) { retval = od_get_active_server (od, iid, &merged_environment); if (retval != CORBA_OBJECT_NIL) goto act_out; } if (flags & Bonobo_ACTIVATION_FLAG_EXISTING_ONLY) goto act_out; #ifdef BONOBO_ACTIVATION_DEBUG fprintf (stderr, "thread %p start activate '%s'\n", g_thread_self(), iid); #endif ai.ac = ac; ai.flags = flags; ai.ctx = ctx; si = g_hash_table_lookup (od->by_iid, iid); if (si) { retval = od_server_activate ( si, &ai, BONOBO_OBJREF (od), &merged_environment, client, ev); /* NB. si can now be invalid - due to re-enterancy */ /* If we failed to activate - it may be because our * request re-entered _during_ the activation * process resulting in a second process being started * but failing to register - so we'll look up again here * to see if we can get it. * FIXME: we should not be forking redundant processes * while an activation of that same process is on the * stack. * FIXME: we only get away with this hack because we * try and fork another process & thus allow the reply * from the initial process to be handled in the event * loop. */ /* FIXME: this path is theoretically redundant now */ if (ev->_major != CORBA_NO_EXCEPTION || retval == CORBA_OBJECT_NIL) { retval = od_get_active_server (od, iid, &merged_environment); if (retval != CORBA_OBJECT_NIL) CORBA_exception_free (ev); } } #ifdef BONOBO_ACTIVATION_DEBUG fprintf (stderr, "thread %p end activate '%s' = %p ['%s']\n", g_thread_self(), iid, retval, bonobo_exception_get_text (ev) ); #endif act_out: g_free (merged_environment._buffer); server_unlock (); return retval; } extern GMainLoop *main_loop; static gboolean quit_server_timeout (gpointer user_data) { #ifdef BONOBO_ACTIVATION_DEBUG g_warning ("Quit server !"); #endif if (!main_dir || main_dir->n_active_servers > RESIDUAL_SERVERS || !activation_clients_is_empty_scan ()) g_warning ("Serious error handling server count, not quitting"); else g_main_loop_quit (main_loop); main_dir->no_servers_timeout = 0; return FALSE; } void od_finished_internal_registration (void) { finished_internal_registration = TRUE; } void check_quit (void) { ObjectDirectory *od = main_dir; /* We had some activity - so push out the shutdown timeout */ if (od->no_servers_timeout != 0) g_source_remove (od->no_servers_timeout); od->no_servers_timeout = 0; if (od->n_active_servers <= RESIDUAL_SERVERS && activation_clients_is_empty_scan ()) od->no_servers_timeout = g_timeout_add ( SERVER_IDLE_QUIT_TIMEOUT, quit_server_timeout, NULL); od->time_active_changed = time (NULL); } static void remove_active_server_entry (ActiveServerList *servers, int index) { CORBA_Object_release (servers->servers [index].server, NULL); CORBA_free (servers->servers [index].environment._buffer); if (index != servers->n_servers - 1) memcpy (&servers->servers [index], &servers->servers [servers->n_servers - 1], sizeof (servers->servers [index])); servers->n_servers--; } static ActiveServerList * add_active_server_entry (ActiveServerList *servers, const Bonobo_ActivationEnvironment *environment, CORBA_Object object) { int index, i; index = servers->n_servers - 1; if (index != 0) servers = g_realloc (servers, sizeof (*servers) + sizeof (servers->servers [0]) * index); servers->servers [index].server = CORBA_Object_duplicate (object, NULL); servers->servers [index].environment._length = environment->_length; servers->servers [index].environment._maximum = environment->_maximum; servers->servers [index].environment._buffer = Bonobo_ActivationEnvironment_allocbuf (environment->_length); servers->servers [index].environment._release = TRUE; for (i = 0; i < environment->_length; i++) Bonobo_ActivationEnvValue_copy ( &servers->servers [index].environment._buffer [i], &environment->_buffer [i]); return servers; } static gboolean prune_dead_servers (gpointer key, gpointer value, gpointer user_data) { ObjectDirectory *od = user_data; ActiveServerList *servers = value; int i; for (i = 0; i < servers->n_servers; i++) { ORBitConnectionStatus status; gboolean dead; status = ORBit_small_get_connection_status ( servers->servers [i].server); dead = (status == ORBIT_CONNECTION_DISCONNECTED); #ifdef BONOBO_ACTIVATION_DEBUG fprintf (stderr, "IID '%20s' (%p), %s \n", (char *) key, servers->servers [i].server, dead ? "dead" : "alive"); #endif if (dead) { remove_active_server_entry (servers, i); od->n_active_servers--; i--; } } return !servers->n_servers; } static gboolean as_rescan (gpointer data) { ObjectDirectory *od; static gboolean in_rescan = FALSE; static guint idle_id = 0; server_lock (); if (!(od = main_dir)) { /* shutting down */ server_unlock (); return FALSE; } /* We tend to get a lot of 'broken' callbacks at once */ if (in_rescan) { if (!idle_id) idle_id = g_idle_add (as_rescan, NULL); server_unlock (); return FALSE; } in_rescan = TRUE; g_hash_table_foreach_remove (od->active_server_lists, prune_dead_servers, od); #ifdef BONOBO_ACTIVATION_DEBUG g_warning ("After prune: %d live servers", od->n_active_servers - RESIDUAL_SERVERS); #endif check_quit (); in_rescan = FALSE; server_unlock (); return FALSE; } static void active_server_cnx_broken (ORBitConnection *cnx, gpointer dummy) { as_rescan (NULL); } static void add_active_server (ObjectDirectory *od, const char *iid, const Bonobo_ActivationEnvironment *environment, CORBA_Object object) { ActiveServerList *servers; ORBitConnection *cnx; cnx = ORBit_small_get_connection (object); if (cnx) { if (!g_object_get_data (G_OBJECT (cnx), "object_count")) { g_object_set_data ( G_OBJECT (cnx), "object_count", GUINT_TO_POINTER (1)); ORBit_small_listen_for_broken (object, G_CALLBACK (active_server_cnx_broken), NULL); } } else g_assert (!strcmp (iid, NAMING_CONTEXT_IID) || !strcmp(iid, EVENT_SOURCE_IID)); servers = g_hash_table_lookup (od->active_server_lists, iid); if (!servers) { servers = g_new0 (ActiveServerList, 1); servers->iid = g_strdup (iid); servers->n_servers = 1; servers = add_active_server_entry ( servers, environment, object); g_hash_table_insert ( od->active_server_lists, servers->iid, servers); } else { ActiveServerList *new_servers; g_assert (servers->n_servers > 0); servers->n_servers++; new_servers = add_active_server_entry ( servers, environment, object); if (new_servers != servers) { /* Need to reset the pointer */ g_hash_table_steal (od->active_server_lists, new_servers->iid); g_hash_table_insert ( od->active_server_lists, new_servers->iid, new_servers); } } if (finished_internal_registration) od->n_active_servers++; if (cnx) check_quit (); } static void active_server_list_free (gpointer data) { ActiveServerList *servers = data; int i; for (i = 0; i < servers->n_servers; i++) { CORBA_Object_release (servers->servers [i].server, NULL); CORBA_free (servers->servers [i].environment._buffer); } g_free (servers); } static gboolean remove_active_server (ObjectDirectory *od, const char *iid, CORBA_Object object) { ActiveServerList *servers; gboolean removed = FALSE; int i; servers = g_hash_table_lookup (od->active_server_lists, iid); if (!servers) return FALSE; for (i = 0; i < servers->n_servers; i++) if (CORBA_Object_is_equivalent ( servers->servers [i].server, object, NULL)) { remove_active_server_entry (servers, i); removed = TRUE; break; } if (removed) od->n_active_servers--; if (servers->n_servers == 0) g_hash_table_remove (od->active_server_lists, iid); check_quit (); return removed; } /* Parse server description and register it, replacing older * definition if necessary. Returns the regsitered ServerInfo */ static Bonobo_ServerInfo const * od_register_runtime_server_info (ObjectDirectory *od, const char *iid, const CORBA_char *description, Bonobo_ActivationClient client) { Bonobo_ServerInfo *old_serverinfo, *new_serverinfo; GSList *parsed_serverinfo = NULL, *l; int i; ClientContext *context; update_registry (od, FALSE); old_serverinfo = (Bonobo_ServerInfo *) g_hash_table_lookup (od->by_iid, iid); if (old_serverinfo) return old_serverinfo; if (!(*description)) /* empty description? */ return NULL; /* parse description */ bonobo_parse_server_info_memory (description, &parsed_serverinfo, bonobo_activation_hostname_get ()); /* check for zero entries */ if (!parsed_serverinfo) return NULL; /* check for more than one entry */ if (parsed_serverinfo->next) { #ifdef BONOBO_ACTIVATION_DEBUG g_warning ("More than one specified, ignoring all"); #endif for (l = parsed_serverinfo; l; l = l->next) { Bonobo_ServerInfo__freekids (l->data, NULL); g_free (l->data); } g_slist_free (parsed_serverinfo); return NULL; } new_serverinfo = (Bonobo_ServerInfo *) parsed_serverinfo->data; g_slist_free (parsed_serverinfo); g_ptr_array_add (od->attr_runtime_servers, new_serverinfo); ORBit_sequence_append (od->attr_servers, new_serverinfo); /* rebuild od->by_iid hash table, because * ORBit_sequence_append reallocs _buffer, and that * sometimes changes the addresses of the * serverinfo items */ g_hash_table_destroy (od->by_iid); od->by_iid = g_hash_table_new (g_str_hash, g_str_equal); for (i = 0; i < od->attr_servers->_length; ++i) g_hash_table_insert (od->by_iid, od->attr_servers->_buffer[i].iid, od->attr_servers->_buffer + i); /* Take note that this client registered this iid, so that * when the client disconnects we unregister its * corresponding serverinfo's */ context = g_hash_table_lookup (od->client_contexts, client); g_return_val_if_fail (context, new_serverinfo); if (context->runtime_iids) ORBit_sequence_append (context->runtime_iids, iid); else { context->runtime_iids = ORBit_sequence_alloc (TC_CORBA_sequence_CORBA_string, 1); ORBit_sequence_index (context->runtime_iids, 0) = CORBA_string_dup (iid); } od->time_list_changed = time (NULL); activation_clients_cache_notify (); return new_serverinfo; } static Bonobo_RegistrationResult impl_Bonobo_ObjectDirectory_register_new_full ( PortableServer_Servant servant, const CORBA_char *iid, const Bonobo_ActivationEnvironment *environment, const CORBA_Object obj, Bonobo_RegistrationFlags flags, const CORBA_char *description, CORBA_Object *existing, Bonobo_ActivationClient client, CORBA_Environment *ev) { ObjectDirectory *od; CORBA_Object oldobj; Bonobo_ActivationEnvironment merged_environment; Bonobo_ServerInfo const *serverinfo; Bonobo_RegistrationResult retval = Bonobo_ACTIVATION_REG_SUCCESS; server_lock (); od = OBJECT_DIRECTORY (servant); oldobj = od_get_active_server (od, iid, environment); *existing = oldobj; serverinfo = od_register_runtime_server_info (od, iid, description, client); od_merge_client_environment (od, serverinfo, environment, &merged_environment, client); oldobj = od_get_active_server (od, iid, &merged_environment); if (oldobj != CORBA_OBJECT_NIL) { if (!CORBA_Object_non_existent (oldobj, ev)) { if (CORBA_Object_is_equivalent (oldobj, obj, ev)) retval = Bonobo_ACTIVATION_REG_SUCCESS; else retval = Bonobo_ACTIVATION_REG_ALREADY_ACTIVE; goto reg_out; } } if (!serverinfo) { if (!(flags&Bonobo_REGISTRATION_FLAG_NO_SERVERINFO)) { retval = Bonobo_ACTIVATION_REG_NOT_LISTED; goto reg_out; } } #ifdef BONOBO_ACTIVATION_DEBUG g_warning ("Server register. '%s' : %p", iid, obj); #endif add_active_server (od, iid, &merged_environment, obj); bonobo_event_source_notify_listeners (od->event_source, "Bonobo/ObjectDirectory:activation:register", NULL, NULL); reg_out: g_free (merged_environment._buffer); server_unlock (); return retval; } static Bonobo_RegistrationResult impl_Bonobo_ObjectDirectory_register_new ( PortableServer_Servant servant, const CORBA_char *iid, const Bonobo_ActivationEnvironment *environment, const CORBA_Object obj, Bonobo_RegistrationFlags flags, const CORBA_char *description, CORBA_Object *existing, CORBA_Environment *ev) { return impl_Bonobo_ObjectDirectory_register_new_full (servant, iid, environment, obj, flags, description, existing, CORBA_OBJECT_NIL, ev); } static void impl_Bonobo_ObjectDirectory_unregister ( PortableServer_Servant servant, const CORBA_char *iid, const CORBA_Object obj, CORBA_Environment *ev) { ObjectDirectory *od; server_lock (); od = OBJECT_DIRECTORY (servant); if (!remove_active_server (od, iid, obj)) CORBA_exception_set (ev, CORBA_USER_EXCEPTION, ex_Bonobo_ObjectDirectory_NotRegistered, NULL); else bonobo_event_source_notify_listeners (od->event_source, "Bonobo/ObjectDirectory:activation:unregister", NULL, NULL); server_unlock (); } static Bonobo_DynamicPathLoadResult impl_Bonobo_ObjectDirectory_add_path( PortableServer_Servant servant, const CORBA_char * add_path, CORBA_Environment *ev) { ObjectDirectory *od; int i, j, dir_num, max; char **add_directoies, **ret; GSList *l, *tmp = NULL; gboolean different; Bonobo_DynamicPathLoadResult retval = Bonobo_DYNAMIC_LOAD_SUCCESS; server_lock (); od = OBJECT_DIRECTORY (servant); if (!od->registry_source_directories) { od->registry_source_directories = split_path_unique (add_path); goto add_path_out; } else add_directoies = split_path_unique (add_path); if (!add_directoies) { retval = Bonobo_DYNAMIC_LOAD_ERROR; goto add_path_out; } for (max = i = 0; od->registry_source_directories[i]; i++) { tmp = g_slist_append(tmp,g_strdup(od->registry_source_directories[i])); max++; } dir_num = max; for (i = 0; add_directoies[i]; i++) { different = TRUE; for (j = 0; od->registry_source_directories[j]; j++) { if (!strcmp(add_directoies[i], od->registry_source_directories[j])) { different = FALSE; break; } } if (different) { tmp = g_slist_append(tmp, g_strdup(add_directoies[i])); max++; } } if (max == dir_num) { g_strfreev(add_directoies); g_slist_free(tmp); retval = Bonobo_DYNAMIC_LOAD_ALREADY_LISTED; goto add_path_out; } ret = g_new(char *, max + 1); for (l = tmp, i = 0; l; l = l->next) ret[i++]=l->data; ret[i] = NULL; g_slist_free(tmp); g_strfreev(add_directoies); g_strfreev(od->registry_source_directories); od->registry_source_directories = ret; update_registry(od, TRUE); add_path_out: server_unlock (); return retval; } static Bonobo_DynamicPathLoadResult impl_Bonobo_ObjectDirectory_remove_path( PortableServer_Servant servant, const CORBA_char * remove_path, CORBA_Environment *ev) { ObjectDirectory *od; char **remove_directoies, **ret; int i, j, max; GSList *l, *tmp = NULL; gboolean different; Bonobo_DynamicPathLoadResult retval = Bonobo_DYNAMIC_LOAD_SUCCESS; server_lock(); od = OBJECT_DIRECTORY (servant); remove_directoies = split_path_unique (remove_path); if (!remove_directoies) { retval = Bonobo_DYNAMIC_LOAD_ERROR; goto rm_path_out; } for (max = i = 0; od->registry_source_directories[i]; i++) { different = TRUE; for (j = 0; remove_directoies[j]; j++) { if (!strcmp(od->registry_source_directories[i], remove_directoies[j])) { different = FALSE; break; } } if (different) { tmp = g_slist_append(tmp, g_strdup(od->registry_source_directories[i])); max++; } } if (max == i) { g_slist_free(tmp); g_strfreev(remove_directoies); retval = Bonobo_DYNAMIC_LOAD_NOT_LISTED; goto rm_path_out; } ret = g_new(char *, max + 1); for (l = tmp, i = 0; l; l = l->next) ret[i++]=l->data; ret[i] = NULL; g_slist_free(tmp); g_strfreev(remove_directoies); g_strfreev(od->registry_source_directories); od->registry_source_directories = ret; update_registry(od, TRUE); rm_path_out: server_unlock(); return retval; } static void client_cnx_broken (ORBitConnection *cnx, const Bonobo_ActivationClient client) { ObjectDirectory *od; ClientContext *context; int i; server_lock(); if (!(od = main_dir)) { /* shutting down */ server_unlock(); return; } /* unregister runtime server definitions */ context = g_hash_table_lookup (od->client_contexts, client); if (context->runtime_iids) { for (i = 0; i < context->runtime_iids->_length; ++i) { CORBA_char *iid = ORBit_sequence_index (context->runtime_iids, i); int j; #ifdef BONOBO_ACTIVATION_DEBUG fprintf (stderr, "Removing runtime definition '%s' from hash table\n", iid); #endif g_hash_table_remove (od->by_iid, iid); for (j = 0; j < od->attr_runtime_servers->len; ++j) { Bonobo_ServerInfo *server = g_ptr_array_index (od->attr_runtime_servers, j); if (strcmp (server->iid, iid) == 0) { #ifdef BONOBO_ACTIVATION_DEBUG fprintf (stderr, "Removing from od->attr_runtime_servers[%i]\n", j); #endif g_ptr_array_remove_index (od->attr_runtime_servers, j); Bonobo_ServerInfo__freekids (server, NULL); g_free (server); break; } } for (j = 0; j < od->attr_servers->_length; ++j) { Bonobo_ServerInfo *server = &ORBit_sequence_index (od->attr_servers, j); if (strcmp (server->iid, iid) == 0) { #ifdef BONOBO_ACTIVATION_DEBUG fprintf (stderr, "Removing from od->attr_servers[%i]\n", j); #endif ORBit_sequence_remove (od->attr_servers, j); break; } } #ifdef BONOBO_ACTIVATION_DEBUG fprintf (stderr, "Runtime definition '%s' cleaned\n", iid); #endif } } g_hash_table_remove (od->client_contexts, client); od->time_list_changed = time (NULL); activation_clients_cache_notify (); server_unlock(); } static void impl_Bonobo_ObjectDirectory_addClientEnv ( PortableServer_Servant servant, const Bonobo_ActivationClient client, const Bonobo_StringList *client_env, CORBA_Environment *ev) { Bonobo_ActivationEnvironment *env; ObjectDirectory *od; ClientContext *context; int i; server_lock(); od = OBJECT_DIRECTORY (servant); env = Bonobo_ActivationEnvironment__alloc (); env->_length = env->_maximum = client_env->_length; env->_buffer = Bonobo_ActivationEnvironment_allocbuf (env->_length); env->_release = CORBA_TRUE; for (i = 0; i < client_env->_length; ++i) { const char *keyval = client_env->_buffer[i]; const char *equals = strchr (keyval, '='); guint keylen; if (!equals) { g_warning ("Duff env. var '%s'", keyval); continue; } keylen = (guint) (equals - keyval); env->_buffer[i].name = CORBA_string_alloc (keylen + 1); strncpy (env->_buffer[i].name, keyval, keylen); env->_buffer[i].name[keylen] = 0; env->_buffer[i].value = CORBA_string_dup (equals + 1); env->_buffer[i].flags = 0; } context = g_new (ClientContext, 1); context->env = env; context->runtime_iids = NULL; g_hash_table_insert (od->client_contexts, client, context); ORBit_small_listen_for_broken (client, G_CALLBACK (client_cnx_broken), (gpointer) client); server_unlock(); } Bonobo_ObjectDirectory bonobo_object_directory_get (void) { if (!main_dir) return CORBA_OBJECT_NIL; else return BONOBO_OBJREF (main_dir); } Bonobo_EventSource bonobo_object_directory_event_source_get (void) { if (!main_dir) return CORBA_OBJECT_NIL; else return BONOBO_OBJREF (main_dir->event_source); } void bonobo_object_directory_init (PortableServer_POA poa, const char *registry_path, CORBA_Environment *ev) { g_assert (main_dir == NULL); main_dir = g_object_new (OBJECT_TYPE_DIRECTORY, "poa", poa, NULL); main_dir->registry_source_directories = split_path_unique (registry_path); update_registry (main_dir, FALSE); } void bonobo_object_directory_shutdown (PortableServer_POA poa, CORBA_Environment *ev) { bonobo_object_set_immortal (BONOBO_OBJECT (main_dir), FALSE); bonobo_object_unref (BONOBO_OBJECT (main_dir)); } CORBA_Object bonobo_object_directory_re_check_fn (const Bonobo_ActivationEnvironment *environment, const char *act_iid, gpointer user_data) { CORBA_Object retval; server_lock (); retval = od_get_active_server ( main_dir, (Bonobo_ImplementationID) act_iid, environment); server_unlock (); return retval; } void bonobo_object_directory_reload (void) { g_log (G_LOG_DOMAIN, G_LOG_LEVEL_DEBUG, "reloading our object directory!"); update_registry (main_dir, TRUE); } static void object_directory_finalize (GObject *object) { ObjectDirectory *od = (ObjectDirectory *) object; main_dir = NULL; g_hash_table_destroy (od->active_server_lists); g_hash_table_destroy (od->registry_directory_mtimes); g_strfreev (od->registry_source_directories); if (od->client_contexts) { g_hash_table_destroy (od->client_contexts); od->client_contexts = NULL; } parent_class->finalize (object); } static void object_directory_class_init (ObjectDirectoryClass *klass) { GObjectClass *object_class = (GObjectClass *) klass; POA_Bonobo_ObjectDirectory__epv *epv = &klass->epv; parent_class = g_type_class_peek_parent (klass); object_class->finalize = object_directory_finalize; epv->get_servers = impl_Bonobo_ObjectDirectory__get_servers; epv->get_active_servers = impl_Bonobo_ObjectDirectory_get_active_servers; epv->activate = impl_Bonobo_ObjectDirectory_activate; epv->register_new = impl_Bonobo_ObjectDirectory_register_new; epv->register_new_full = impl_Bonobo_ObjectDirectory_register_new_full; epv->unregister = impl_Bonobo_ObjectDirectory_unregister; epv->dynamic_add_path = impl_Bonobo_ObjectDirectory_add_path; epv->dynamic_remove_path = impl_Bonobo_ObjectDirectory_remove_path; epv->addClientEnv = impl_Bonobo_ObjectDirectory_addClientEnv; } static void object_directory_init (ObjectDirectory *od) { bonobo_object_set_immortal (BONOBO_OBJECT (od), TRUE); od->by_iid = NULL; od->registry_directory_mtimes = g_hash_table_new (g_str_hash, g_str_equal); od->active_server_lists = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, active_server_list_free); od->no_servers_timeout = 0; od->attr_runtime_servers = g_ptr_array_new (); od->event_source = bonobo_event_source_new (); od->client_contexts = g_hash_table_new_full (NULL, NULL, NULL, (GDestroyNotify) client_context_free); } BONOBO_TYPE_FUNC_FULL (ObjectDirectory, Bonobo_ObjectDirectory, BONOBO_TYPE_OBJECT, object_directory)