1 /**************************************************************************/
2 /* ---------------------------------------------------------------------- */
3 /* Copyright (C) 2006 - 2008 FRESCOR consortium partners: */
5 /* Universidad de Cantabria, SPAIN */
6 /* University of York, UK */
7 /* Scuola Superiore Sant'Anna, ITALY */
8 /* Kaiserslautern University, GERMANY */
9 /* Univ. Politécnica Valencia, SPAIN */
10 /* Czech Technical University in Prague, CZECH REPUBLIC */
12 /* Thales Communication S.A. FRANCE */
13 /* Visual Tools S.A. SPAIN */
14 /* Rapita Systems Ltd UK */
17 /* See http://www.frescor.org for a link to partners' websites */
19 /* FRESCOR project (FP6/2005/IST/5-034026) is funded */
20 /* in part by the European Union Sixth Framework Programme */
21 /* The European Union is not liable of any use that may be */
22 /* made of this code. */
25 /* This file is part of FORB (Frescor Object Request Broker) */
27 /* FORB is free software; you can redistribute it and/or modify it */
28 /* under terms of the GNU General Public License as published by the */
29 /* Free Software Foundation; either version 2, or (at your option) any */
30 /* later version. FORB is distributed in the hope that it will be */
31 /* useful, but WITHOUT ANY WARRANTY; without even the implied warranty */
32 /* of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU */
33 /* General Public License for more details. You should have received a */
34 /* copy of the GNU General Public License along with FORB; see file */
35 /* COPYING. If not, write to the Free Software Foundation, 675 Mass Ave, */
36 /* Cambridge, MA 02139, USA. */
38 /* As a special exception, including FORB header files in a file, */
39 /* instantiating FORB generics or templates, or linking other files */
40 /* with FORB objects to produce an executable application, does not */
41 /* by itself cause the resulting executable application to be covered */
42 /* by the GNU General Public License. This exception does not */
43 /* however invalidate any other reasons why the executable file might be */
44 /* covered by the GNU Public License. */
45 /**************************************************************************/
49 * @author Michal Sojka <sojkam1@fel.cvut.cz>
50 * @date Sun Oct 12 16:57:01 2008
52 * @brief Implementation of basic FORB's functions.
57 #define _BSD_SOURCE /* Because of on_exit() */
62 #include <forb/config.h>
63 #include <forb/forb-internal.h>
67 #include <forb/object.h>
68 #include <forb/uuid.h>
73 #include <sys/types.h>
74 #include <ul_gavlcust.h>
76 #include <ul_logreg.h>
78 #ifdef CONFIG_FORB_PROTO_UNIX
79 #include <forb/proto_unix.h>
83 #define UL_LOGL_DEF UL_LOGL_DEB
85 #define UL_LOGL_DEF UL_LOGL_ERR
87 #include "log_domains.inc"
89 extern UL_LOG_CUST(ulogd_forb);
93 destroy_forb_on_exit(int exitcode, void *arg)
100 forb_is_alive(forb_orb _obj, CORBA_Environment *ev)
102 ul_logdeb("%s called\n", __FUNCTION__);
105 static struct forb_forb_orb_impl forb_implementation = {
106 .is_alive = forb_is_alive,
110 * Prepares #FORB_TMP_DIR directory for use by forb
112 * @return Zero on succes, -1 on error and errno is set appropriately.
115 forb_init_tmp_dir(void)
120 ret = stat(FORB_TMP_DIR, &st);
122 if (ret == 0 && !S_ISDIR(st.st_mode)) {
123 ret = unlink(FORB_TMP_DIR);
125 } else if (ret == 0) {
128 return mkdir(FORB_TMP_DIR, 0777);
132 * Thread for execution of remote requests for a FORB object.
139 forb_execution_thread(void *arg)
143 forb_execute_object(orb);
148 forb_init(int *argc, char **argv[], const char *orb_id)
154 forb = forb_malloc(sizeof(*forb));
156 memset(forb, 0, sizeof(*forb));
158 /* Initialize ULUT logging facility */
159 ul_logreg_domains_static(ul_log_domains_array,
160 sizeof(ul_log_domains_array)/sizeof(ul_log_domains_array[0]));
162 forb_server_id_init(&forb->server_id);
163 forb_server_id_to_string(forb->server_id_str, &forb->server_id,
164 sizeof(forb->server_id_str));
165 ul_logdeb("Initializing forb %s\n", forb->server_id_str);
167 if (fosa_mutex_init(&forb->request_id_mutex, 0) != 0) goto err2;
168 if (fosa_mutex_init(&forb->port_mutex, 0) != 0) goto err2;
169 forb_port_init_head(forb);
171 if (fosa_mutex_init(&forb->request_mutex, 0) != 0) goto err2;
172 forb_request_nolock_init_root_field(forb);
174 if (fosa_mutex_init(&forb->peer_mutex, 0) != 0) goto err2;
175 forb_peer_nolock_init_root_field(forb);
177 if (fosa_mutex_init(&forb->objkey_mutex, 0) != 0) goto err2;
178 forb_objects_nolock_init_root_field(forb);
180 if (fosa_mutex_init(&forb->regref_mutex, 0) != 0) goto err2;
181 forb_regref_nolock_init_root_field(forb);
183 ret = forb_init_tmp_dir();
185 ul_logerr("Cannot prepare " FORB_TMP_DIR "\n");
189 orb = forb_forb_orb_new(NULL, &forb_implementation, forb);
191 /* Server ID must be assigned manualy */
192 orb->server = forb->server_id;
196 /* Insert our object reference to objects tree, so that we
197 * can accept remote request to our new ORB. */
198 forb_objects_nolock_insert(forb, orb);
200 ret = fosa_thread_create(&forb->execution_thread, NULL,
201 forb_execution_thread, orb);
205 on_exit(destroy_forb_on_exit, orb);
207 #ifdef CONFIG_FORB_PROTO_UNIX
209 forb_port_t *port = forb_malloc(sizeof(*port));
211 memset(port, 0, sizeof(*port));
212 ret = forb_unix_port_init(&port->desc, &forb->server_id);
213 if (ret) goto err_free_unix;
214 ret = forb_register_port(orb, port);
215 if (ret) goto err_free_unix; /* TODO: forb_unix_port_done() */
226 err2: forb_free(forb);
230 /* FIXME: forb_destroy is now called automatically on exit. Therefore
231 * forb_destroy() should be either static or should deregister on_exit
232 * handler (how???). */
233 void forb_destroy(forb_orb orb)
235 forb_t *forb = forb_object_to_forb(orb);
237 forb_regref_t *regref;
239 pthread_cancel(forb->execution_thread.pthread_id);
240 pthread_join(forb->execution_thread.pthread_id, NULL);
242 /* Unregister all registered references */
243 while ((regref = forb_regref_first(forb))) {
244 forb_unregister_reference(orb, regref->name.str);
247 ul_list_for_each_cut(forb_port, forb, port) {
248 forb_destroy_port(port);
250 forb_object_release(orb);
255 /* forb_register_interface(const struct forb_interface *interface) */
257 /* gavl_insert(&type_registry, &interface->node); */
261 * Initializes server ID variable.
263 * @param server_id Serer ID to initialize.
266 forb_server_id_init(forb_server_id *server_id)
268 forb_uuid_generate((forb_uuid_t*)server_id->uuid);
272 * Checks whether the @a object is stale. Stale object is an object
273 * reference whose server cannot be contacted to handle requests.
275 * @param object Object reference to check.
277 * @return True if the object is stale, false otherwise.
279 bool forb_object_is_stale(forb_object object)
285 remote_orb = forb_get_orb_of(object);
286 if (!remote_orb) { /* This shohuld never happen */
289 /* TODO: Check not only the ORB, but also whether the object
290 * is still registered with the remote orb. */
291 forb_orb_is_alive(remote_orb, &env);
292 if (env.major == FORB_EX_COMM_FAILURE) {
293 /* Orb is not alive */
296 if (forb_exception_occurred(&env)) {
297 ul_logerr("%s: unexpected exception: %s\n", __FUNCTION__, forb_strerror(&env));
302 forb_object_release(remote_orb);
313 * @return Zero on success, -1 on error.
316 rewrite_regref(int fd, const char *objref)
319 int len = strlen(objref);
320 lseek(fd, 0, SEEK_SET);
324 ret = write(fd, objref, len);
325 if (ret < 0) goto out;
329 ret = 0; /* Success */
338 * @param fn File name
339 * @param objref string form of the object reference
341 * @return -1 on error, 0 if reference was replaced and 1 in the
342 * reference is valid.
345 replace_regref_if_stale(forb_orb orb, const char *fn, const char *objref)
351 fd = open(fn, O_RDWR);
356 ret = lockf(fd, F_LOCK, 0);
357 if (ret < 0) goto close_err;
358 ret = read(fd, str, sizeof(str)-1);
359 if (ret < 0) goto unlock_err;
360 /* TODO: Check that we have read the whole file */
363 object = forb_string_to_object(orb, str);
365 /* reference is unreadable, so we can replace it */
366 ret = rewrite_regref(fd, objref);
367 /* We are done for now */
370 if (forb_object_is_stale(object)) {
371 /* Orb is not alive */
372 ret = rewrite_regref(fd, objref);
374 /* Reference's FORB is alive :-( */
378 forb_object_release(object);
380 lockf(fd, F_ULOCK, 0);
389 * Registers a given object reference so that other FORBs on the same
390 * node can find it by using forb_resolve_reference().
392 * @param object Object reference to register.
393 * @param name Name under which to register the reference.
395 * @return Zero on success, -1 on error.
398 forb_register_reference(forb_object object, const char *name)
400 forb_regref_t *regref;
401 forb_regref_name_t regname;
402 forb_t *forb = forb_object_to_forb(object);
403 char fn[100], fntmp[100];
408 strncpy(regname.str, name, FORB_REGREF_NAME_LEN-1);
409 regname.str[FORB_REGREF_NAME_LEN-1]='\0';
411 regref = forb_regref_new(object, regname);
412 if (!regref) goto err;
414 forb_regref_insert(forb, regref);
416 snprintf(fn, sizeof(fn), FORB_TMP_DIR "/%s", regname.str);
417 snprintf(fntmp, sizeof(fntmp), FORB_TMP_DIR "/%s.%s", regname.str,
418 forb->server_id_str);
420 f = fopen(fntmp, "w");
421 if (!f) goto unalloc_err;
423 objref = forb_object_to_string(object);
424 if (!objref) goto unlink_err;
426 ret = fprintf(f, "%s", objref);
427 if (ret < 0) goto free_objref_err;
430 if (ret == EOF) goto free_objref_err;
432 /* Make the atomic registration in filesystem */
433 ret = link(fntmp, fn);
435 if (ret < 0 && errno == EEXIST) {
436 /* The reference exists. Try whether it is still
438 if (replace_regref_if_stale(object->orb, fn, objref) != 0) {
439 goto free_objref_err;
441 ul_logdeb("Stale registration replaced\n");
442 } else if (ret < 0) {
443 goto free_objref_err;
448 /* Unlink the temporary filename */
462 forb_regref_delete(forb, regref);
463 forb_regref_release(regref);
470 * Unregister reference previously registered by
471 * forb_register_reference().
473 * @param orb forb::orb reference
474 * @param name Name to unregister.
476 * @return Zero on success, -1 on error.
479 forb_unregister_reference(forb_orb orb, const char *name)
481 forb_regref_t *regref;
482 forb_regref_name_t regname;
483 forb_t *forb = forb_object_to_forb(orb);
486 strncpy(regname.str, name, FORB_REGREF_NAME_LEN-1);
487 regname.str[FORB_REGREF_NAME_LEN-1]='\0';
489 regref = forb_regref_find(forb, ®name);
490 if (!regref) goto err;
492 forb_regref_delete(forb, regref);
493 forb_regref_release(regref);
495 snprintf(fn, sizeof(fn), FORB_TMP_DIR "/%s", regname.str);
504 * Returns a named reference previously registered by
505 * forb_register_reference(). This function can be called event if the
506 * reference was registered in a diferent process (but on the same
509 * @param orb Local orb object reference
510 * @param name Name under which the reference was registered.
512 * @return Object reference on NULL in case of error.
515 forb_resolve_reference(const forb_orb orb, const char *name)
517 forb_regref_name_t regname;
523 strncpy(regname.str, name, FORB_REGREF_NAME_LEN-1);
524 regname.str[FORB_REGREF_NAME_LEN-1]='\0';
526 snprintf(fn, sizeof(fn), FORB_TMP_DIR "/%s", regname.str);
532 ret = read(fd, str, sizeof(str)-1);
533 /* TODO: Check that we have read the whole file */
535 object = forb_string_to_object(orb, str);
538 if (forb_object_is_stale(object)) {
539 forb_object_release(object);
547 * Returns object reference of forb::orb object associated with a
555 forb_get_orb_of(const forb_object obj)
559 if (forb_server_id_cmp(&obj->server, &obj->orb->server) == 0) {
560 orb = forb_object_duplicate(obj->orb);
562 orb = forb_object_new(obj->orb, &obj->server, 0);
568 * Returns server ID of an object reference.
574 forb_get_server_id(const forb_object obj, forb_server_id *dest)
583 * Return instance data registered when the object was created by
586 * @param obj Object reference
588 * @return Pointer to the registered data.
591 forb_instance_data(const forb_object obj)
593 return forb_object_instance_data(obj);
597 * Returns error message correspondings FORB exception.
599 * @param env Environemnt
601 * @return Non-NULL pointer to a string.
604 forb_strerror(CORBA_Environment *env)
607 return "Invalid environemnt";
609 #define ex(e) case FORB_EX_##e: return #e; break;
610 switch (env->major) {
631 ex(OBJECT_NOT_EXIST);
636 return "Invalid error number";
640 * Return server id of the requesting application.
642 * This function should be only called from within interface
645 * @param[in] obj Object being requested
646 * @param[out] req_source Server ID of the requesting application
649 forb_get_req_source(const forb_object obj, forb_server_id *req_source)
652 if (obj && obj->exec_req) {
653 *req_source = obj->exec_req->source;
655 memset(req_source, 0, sizeof(*req_source));