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