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