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