]> rtime.felk.cvut.cz Git - frescor/forb.git/blob - src/forb.c
Suppress all g++ warnings
[frescor/forb.git] / src / forb.c
1 /**************************************************************************/
2 /* ---------------------------------------------------------------------- */
3 /* Copyright (C) 2006 - 2008 FRESCOR consortium partners:                 */
4 /*                                                                        */
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                */
11 /*   ENEA                                   SWEDEN                        */
12 /*   Thales Communication S.A.              FRANCE                        */
13 /*   Visual Tools S.A.                      SPAIN                         */
14 /*   Rapita Systems Ltd                     UK                            */
15 /*   Evidence                               ITALY                         */
16 /*                                                                        */
17 /*   See http://www.frescor.org for a link to partners' websites          */
18 /*                                                                        */
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.                                               */
23 /*                                                                        */
24 /*                                                                        */
25 /*  This file is part of FORB (Frescor Object Request Broker)             */
26 /*                                                                        */
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.                                              */
37 /*                                                                        */
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 /**************************************************************************/
46
47 /**
48  * @file   forb.c
49  * @author Michal Sojka <sojkam1@fel.cvut.cz>
50  * @date   Sun Oct 12 16:57:01 2008
51  * 
52  * @brief  Implementation of basic FORB's functions.
53  * 
54  * 
55  */
56
57 #ifndef _BSD_SOURCE
58 #define _BSD_SOURCE             /* Because of on_exit()  */
59 #endif
60 #include "proto.h"
61 #include "regref.h"
62 #include <fcntl.h>
63 #include <forb/config.h>
64 #include <forb/forb-internal.h>
65 #include <forb.h>
66 #include "forb-idl.h"
67 #include <forb/iop.h>
68 #include <forb/object.h>
69 #include <forb/uuid.h>
70 #include <stdio.h>
71 #include <stdlib.h>
72 #include <string.h>
73 #include <sys/stat.h>
74 #include <sys/types.h>
75 #include <ul_gavlcust.h>
76 #include <ul_log.h>
77 #include <ul_logreg.h>
78 #include <unistd.h>
79 #ifdef CONFIG_FORB_PROTO_UNIX
80 #include <forb/proto_unix.h>
81 #endif
82
83 #ifdef DEBUG
84 #define UL_LOGL_DEF UL_LOGL_DEB
85 #else
86 #define UL_LOGL_DEF UL_LOGL_ERR
87 #endif
88 #include "log_domains.inc"
89
90 extern UL_LOG_CUST(ulogd_forb);
91
92
93 static void
94 destroy_forb_on_exit(int exitcode, void *arg)
95 {
96         forb_orb orb = arg;
97         forb_destroy(orb);
98 }
99
100 static void
101 forb_is_alive(forb_orb _obj, CORBA_Environment *ev)
102 {
103         ul_logdeb("%s called\n", __FUNCTION__);
104 }
105
106 static struct forb_forb_orb_impl forb_implementation = {
107         .is_alive = forb_is_alive,
108 };
109
110 /**
111  * Prepares #FORB_TMP_DIR directory for use by forb
112  *
113  * @return Zero on succes, -1 on error and errno is set appropriately.
114  */
115 int
116 forb_init_tmp_dir(void)
117 {
118         struct stat st;
119         int ret;
120
121         ret = stat(FORB_TMP_DIR, &st);
122
123         if (ret == 0 && !S_ISDIR(st.st_mode)) {
124                 ret = unlink(FORB_TMP_DIR);
125                 if (ret) return -1;
126         } else if (ret == 0) {
127                 return 0;
128         }
129         return mkdir(FORB_TMP_DIR, 0777);
130 }
131
132 /** 
133  * Thread for execution of remote requests for a FORB object.
134  * 
135  * @param arg 
136  * 
137  * @return 
138  */
139 static void *
140 forb_execution_thread(void *arg)
141 {
142         forb_orb orb = arg;
143
144         forb_execute_object(orb);
145         return NULL;
146 }
147
148 forb_orb
149 forb_init(int *argc, char **argv[], const struct forb_init_attr *attr)
150 {
151         forb_orb orb;
152         forb_t *forb;
153         int ret;
154
155         forb = forb_malloc(sizeof(*forb));
156         if (!forb) goto err;
157         memset(forb, 0, sizeof(*forb));
158
159         /* Initialize ULUT logging facility */
160         ul_logreg_domains_static(ul_log_domains_array,
161                                  sizeof(ul_log_domains_array)/sizeof(ul_log_domains_array[0]));
162
163         if (attr) {
164                 forb->attr = *attr;
165         } else {
166                 memset(&forb->attr, 0, sizeof(forb->attr));
167         }
168         
169         forb_server_id_init(&forb->server_id);
170         forb_server_id_to_string(forb->server_id_str, &forb->server_id,
171                                  sizeof(forb->server_id_str));
172         ul_logdeb("Initializing forb %s\n", forb->server_id_str);
173
174         if (fosa_mutex_init(&forb->request_id_mutex, 0) != 0) goto err2;
175         if (fosa_mutex_init(&forb->port_mutex, 0) != 0) goto err2;
176         forb_port_init_head(forb);
177         
178         if (fosa_mutex_init(&forb->request_mutex, 0) != 0) goto err2;
179         forb_request_nolock_init_root_field(forb);
180         
181         if (fosa_mutex_init(&forb->peer_mutex, 0) != 0) goto err2;
182         forb_peer_nolock_init_root_field(forb);
183
184         if (fosa_mutex_init(&forb->objkey_mutex, 0) != 0) goto err2;
185         forb_objects_nolock_init_root_field(forb);
186
187         if (fosa_mutex_init(&forb->regref_mutex, 0) != 0) goto err2;
188         forb_regref_nolock_init_root_field(forb);
189
190         ret = forb_init_tmp_dir();
191         if (ret != 0) {
192                 ul_logerr("Cannot prepare " FORB_TMP_DIR "\n");
193                 return NULL;
194         }
195
196         orb = forb_forb_orb_new(NULL, &forb_implementation, forb);
197         if (!orb) goto err2;
198         /* Server ID must be assigned manualy */
199         orb->server = forb->server_id;
200
201         forb->orb = orb;
202
203         /* Insert our object reference to objects tree, so that we
204          * can accept remote request to our new ORB. */
205         forb_objects_nolock_insert(forb, orb);
206
207         ret = fosa_thread_create(&forb->execution_thread, NULL,
208                                  forb_execution_thread, orb);
209         if (ret != 0)
210                 goto err2;
211         
212         on_exit(destroy_forb_on_exit, orb);
213
214 #ifdef CONFIG_FORB_PROTO_UNIX
215         {
216                 forb_port_t *port = forb_malloc(sizeof(*port));
217                 if (port) {
218                         memset(port, 0, sizeof(*port));
219                         ret = forb_unix_port_init(&port->desc, &forb->server_id);
220                         if (ret) goto err_free_unix;
221                         ret = forb_register_port(orb, port);
222                         if (ret) goto err_free_unix; /* TODO: forb_unix_port_done() */
223                         goto unix_ok;
224                 }
225         err_free_unix:
226                 free(port);
227                 goto err2;
228         unix_ok:;
229         }
230 #endif
231         return orb;
232
233 err2:   forb_free(forb);
234 err:    return NULL;
235 }
236
237 /* FIXME: forb_destroy is now called automatically on exit. Therefore
238  * forb_destroy() should be either static or should deregister on_exit
239  * handler (how???).  */
240 void forb_destroy(forb_orb orb)
241 {
242         forb_t *forb = forb_object_to_forb(orb);
243         forb_port_t *port;
244         forb_regref_t *regref;
245
246         pthread_cancel(forb->execution_thread.pthread_id);
247         pthread_join(forb->execution_thread.pthread_id, NULL);
248         
249         /* Unregister all registered references */
250         while ((regref = forb_regref_first(forb))) {
251                 forb_unregister_reference(orb, regref->name.str);
252         }
253         
254         ul_list_for_each_cut(forb_port, forb, port) {
255                 forb_destroy_port(port);
256         }
257         forb_object_release(orb);
258         forb_free(forb);
259 }
260
261 /* void */
262 /* forb_register_interface(const struct forb_interface *interface) */
263 /* { */
264 /*      gavl_insert(&type_registry, &interface->node); */
265 /* } */
266
267 /** 
268  * Initializes server ID variable.
269  * 
270  * @param server_id Serer ID to initialize.
271  */
272 void
273 forb_server_id_init(forb_server_id *server_id)
274 {
275         forb_uuid_generate((forb_uuid_t*)server_id->uuid);
276 }
277
278 /** 
279  * Checks whether the @a object is stale. Stale object is an object
280  * reference whose server cannot be contacted to handle requests.
281  * 
282  * @param object Object reference to check.
283  * 
284  * @return True if the object is stale, false otherwise.
285  */
286 bool forb_object_is_stale(forb_object object)
287 {
288         forb_orb remote_orb;
289         struct forb_env env;
290         bool stale = true;
291         
292         remote_orb = forb_get_orb_of(object);
293         if (!remote_orb) {      /* This shohuld never happen */
294                 goto err;
295         }
296         /* TODO: Check not only the ORB, but also whether the object
297          * is still registered with the remote orb. */
298         forb_orb_is_alive(remote_orb, &env);
299         if (env.major == FORB_EX_COMM_FAILURE) {
300                 /* Orb is not alive */
301                 stale = true;
302         } else {
303                 if (forb_exception_occurred(&env)) {
304                         ul_logerr("%s: unexpected exception: %s\n", __FUNCTION__, forb_strerror(&env));
305                 }
306                 stale = false;  
307         }
308
309         forb_object_release(remote_orb);
310 err:
311         return stale;
312 }
313
314 /** 
315  * 
316  * 
317  * @param fd 
318  * @param objref 
319  * 
320  * @return Zero on success, -1 on error.
321  */
322 static int
323 rewrite_regref(int fd, const char *objref)
324 {
325         int ret;
326         int len = strlen(objref);
327         lseek(fd, 0, SEEK_SET);
328         ftruncate(fd, 0);
329                 
330         while (len > 0) {
331                 ret = write(fd, objref, len);
332                 if (ret < 0) goto out;
333                 len -= ret;
334                 objref += ret;
335         }
336         ret = 0;        /* Success */
337 out:
338         return ret;
339 }
340
341 /** 
342  * 
343  * 
344  * @param orb 
345  * @param fn File name
346  * @param objref string form of the object reference
347  * 
348  * @return -1 on error, 0 if reference was replaced and 1 in the
349  * reference is valid.
350  */
351 static int
352 replace_regref_if_stale(forb_orb orb, const char *fn, const char *objref)
353 {
354         int fd, ret = 0; 
355         char str[100];
356         forb_object object;
357         
358         fd = open(fn, O_RDWR);
359         if (fd < 0) {
360                 ret = -1;
361                 goto out;
362         }
363         ret = lockf(fd, F_LOCK, 0);
364         if (ret < 0) goto close_err;
365         ret = read(fd, str, sizeof(str)-1);
366         if (ret < 0) goto unlock_err;
367         /* TODO: Check that we have read the whole file */
368         
369         str[ret] = '\0';
370         object = forb_string_to_object(orb, str);
371         if (!object) {
372                 /* reference is unreadable, so we can replace it */
373                 ret = rewrite_regref(fd, objref);
374                 /* We are done for now */
375                 goto unlock_err;
376         }
377         if (forb_object_is_stale(object)) {
378                 /* Orb is not alive */
379                 ret = rewrite_regref(fd, objref);
380         } else {
381                 /* Reference's FORB is alive :-( */
382                 ret = 1;        
383         }
384
385         forb_object_release(object);
386 unlock_err:     
387         lockf(fd, F_ULOCK, 0);
388 close_err:
389         close(fd);
390 out:
391         return ret;
392 }
393
394
395 /** 
396  * Registers a given object reference so that other FORBs on the same
397  * node can find it by using forb_resolve_reference().
398  * 
399  * @param object Object reference to register.
400  * @param name Name under which to register the reference.
401  *
402  * @return Zero on success, -1 on error.
403  */
404 int
405 forb_register_reference(forb_object object, const char *name)
406 {
407         forb_regref_t *regref;
408         forb_regref_name_t regname;
409         forb_t *forb = forb_object_to_forb(object);
410         char fn[100], fntmp[100];
411         char *objref;
412         FILE *f;
413         int ret;
414
415         strncpy(regname.str, name, FORB_REGREF_NAME_LEN-1);
416         regname.str[FORB_REGREF_NAME_LEN-1]='\0';
417
418         regref = forb_regref_new(object, regname);
419         if (!regref) goto err;
420
421         forb_regref_insert(forb, regref);
422
423         snprintf(fn,    sizeof(fn),    FORB_TMP_DIR "/%s",    regname.str);
424         snprintf(fntmp, sizeof(fntmp), FORB_TMP_DIR "/%s.%s", regname.str,
425                  forb->server_id_str);
426
427         f = fopen(fntmp, "w");
428         if (!f) goto unalloc_err;
429         
430         objref = forb_object_to_string(object);
431         if (!objref) goto unlink_err;
432
433         ret = fprintf(f, "%s", objref);
434         if (ret < 0) goto free_objref_err;
435
436         ret = fclose(f);
437         if (ret == EOF) goto free_objref_err;
438
439         /* Make the atomic registration in filesystem */
440         ret = link(fntmp, fn);
441         
442         if (ret < 0 && errno == EEXIST) {
443                 /* The reference exists. Try whether it is still
444                  * active. */
445                 if (replace_regref_if_stale(object->orb, fn, objref) != 0) {
446                         goto free_objref_err;
447                 }
448                 ul_logdeb("Stale registration replaced\n");
449         } else if (ret < 0) {
450                 goto free_objref_err;
451         }
452
453         forb_free(objref);
454
455         /* Unlink the temporary filename */
456         unlink(fntmp);
457         
458         return 0;
459 free_objref_err:
460         ret = errno;
461         forb_free(objref);
462         errno = ret;
463 unlink_err:
464         ret = errno;
465         unlink(fntmp);
466         errno = ret;
467 unalloc_err:
468         ret = errno;
469         forb_regref_delete(forb, regref);
470         forb_regref_release(regref);
471         errno = ret;
472 err:
473         return -1;
474 }
475
476 /** 
477  * Unregister reference previously registered by
478  * forb_register_reference().
479  * 
480  * @param orb forb::orb reference
481  * @param name Name to unregister.
482  * 
483  * @return Zero on success, -1 on error.
484  */
485 int
486 forb_unregister_reference(forb_orb orb, const char *name)
487 {
488         forb_regref_t *regref;
489         forb_regref_name_t regname;
490         forb_t *forb = forb_object_to_forb(orb);
491         char fn[100];
492
493         strncpy(regname.str, name, FORB_REGREF_NAME_LEN-1);
494         regname.str[FORB_REGREF_NAME_LEN-1]='\0';
495
496         regref = forb_regref_find(forb, &regname);
497         if (!regref) goto err;
498
499         forb_regref_delete(forb, regref);
500         forb_regref_release(regref);
501
502         snprintf(fn,    sizeof(fn),    FORB_TMP_DIR "/%s",    regname.str);
503         return unlink(fn);
504
505         return 0;
506 err:
507         return -1;
508 }
509
510 /** 
511  * Returns a named reference previously registered by
512  * forb_register_reference(). This function can be called even if the
513  * reference was registered in a diferent process (but on the same
514  * node).
515  * 
516  * @param orb Local orb object reference
517  * @param name Name under which the reference was registered.
518  * 
519  * @return Object reference on NULL in case of error.
520  */
521 forb_object
522 forb_resolve_reference(const forb_orb orb, const char *name)
523 {
524         forb_regref_name_t regname;
525         char fn[100];
526         char str[100];
527         int fd, ret;
528         forb_object object;
529
530         strncpy(regname.str, name, FORB_REGREF_NAME_LEN-1);
531         regname.str[FORB_REGREF_NAME_LEN-1]='\0';
532
533         snprintf(fn,    sizeof(fn),    FORB_TMP_DIR "/%s",    regname.str);
534
535         fd = open(fn, 0);
536         if (fd < 0) {
537                 return NULL;
538         }
539         ret = read(fd, str, sizeof(str)-1);
540         /* TODO: Check that we have read the whole file */
541         str[ret] = '\0';
542         object = forb_string_to_object(orb, str);
543         close(fd);
544
545         if (forb_object_is_stale(object)) {
546                 forb_object_release(object);
547                 object = NULL;
548         }
549         
550         return object;
551 }
552
553 /** 
554  * Returns object reference of forb::orb object associated with the
555  * given object.
556  * 
557  * @param obj 
558  * 
559  * @return 
560  */
561 forb_orb
562 forb_get_orb_of(const forb_object obj)
563 {
564         forb_orb orb;
565
566         if (forb_server_id_cmp(&obj->server, &obj->orb->server) == 0) {
567                 orb = forb_object_duplicate(obj->orb);
568         } else {
569                 orb = forb_object_new(obj->orb, &obj->server, 0);
570         }
571         return orb;
572 }
573
574 /** 
575  * Returns server ID of an object reference.
576  * 
577  * @param obj 
578  * @param dest 
579  */
580 void
581 forb_get_server_id(const forb_object obj, forb_server_id *dest)
582 {
583         if (obj) {
584                 *dest = obj->server;
585         }
586 }
587
588
589 /** 
590  * Return instance data registered when the object was created by
591  * forb_XXX_new().
592  * 
593  * @param obj Object reference
594  * 
595  * @return Pointer to the registered data.
596  */
597 void *
598 forb_instance_data(const forb_object obj)
599 {
600         return forb_object_instance_data(obj);
601 }
602
603 /** 
604  * Returns error message correspondings FORB exception.
605  * 
606  * @param env Environemnt
607  * 
608  * @return Non-NULL pointer to a string.
609  */
610 const char *
611 forb_strerror(CORBA_Environment *env)
612 {
613         if (!env) {
614                 return "Invalid environemnt";
615         }
616 #define ex(e) case FORB_EX_##e: return #e; break;
617         switch (env->major) {
618         ex(NONE);
619         ex(UNKNOWN);
620         ex(BAD_PARAM);
621         ex(NO_MEMORY);
622         ex(IMP_LIMIT);
623         ex(COMM_FAILURE);
624         ex(INV_OBJREF);
625         ex(NO_PERMISSION);
626         ex(INTERNAL);
627         ex(MARSHAL);
628         ex(INITIALIZE);
629         ex(NO_IMPLEMENT);
630         ex(BAD_OPERATION);
631         ex(NO_RESOURCES);
632         ex(NO_RESPONSE);
633         ex(TRANSIENT);
634         ex(FREE_MEM);
635         ex(INV_IDENT);
636         ex(INV_FLAG);
637         ex(DATA_CONVERSION);
638         ex(OBJECT_NOT_EXIST);
639         ex(TIMEOUT);
640         ex(APPLICATION);
641         }
642 #undef ex
643         return "Invalid error number";
644 }
645
646 /** 
647  * Return server id of the requesting application.
648  *
649  * This function should be only called from within interface
650  * implementation,
651  * 
652  * @param[in] obj Object being requested
653  * @param[out] req_source Server ID of the requesting application
654  */
655 void
656 forb_get_req_source(const forb_object obj, forb_server_id *req_source)
657 {
658         if (req_source) {
659                 if (obj && obj->exec_req) {
660                         *req_source = obj->exec_req->source;
661                 } else {
662                         memset(req_source, 0, sizeof(*req_source));
663                 }
664         }
665 }