]> rtime.felk.cvut.cz Git - frescor/frsh-forb.git/blob - src/forb/src/forb.c
hack: Add fixed reference to wifi_agent to all FORBs
[frescor/frsh-forb.git] / src / forb / 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 <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 <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 #include "discovery.h"
78 #ifdef CONFIG_FORB_PROTO_UNIX
79 #include <forb/proto_unix.h>
80 #endif
81 #ifdef CONFIG_FORB_PROTO_INET_DEFAULT
82 #include <forb/proto_inet.h>
83 #endif
84 #ifdef CONFIG_FCB
85 #include <fcb.h>
86 #include <fcb_contact_info.h>
87 #include <wifi_agent.h>
88 #endif
89 #include <fcntl.h>
90
91 #ifdef DEBUG
92 #define UL_LOGL_DEF UL_LOGL_DEB
93 #else
94 #define UL_LOGL_DEF UL_LOGL_ERR
95 #endif
96 #include "log_domains.inc"
97
98 extern UL_LOG_CUST(ulogd_forb);
99 static int init_ul_log(void);
100
101 UL_LOGREG_DOMAINS_INIT_FUNCTION(forb_logreg_domains, forb_logreg_domains_array);
102
103 #if 0
104 static void
105 destroy_forb_on_exit(int exitcode, void *arg)
106 {
107         forb_orb orb = arg;
108         forb_destroy(orb);
109 }
110 #endif
111
112 static void
113 forb_is_alive(forb_orb _obj, CORBA_Environment *ev)
114 {
115         ul_logdeb("%s called\n", __FUNCTION__);
116 }
117
118 static struct forb_forb_orb_impl forb_implementation = {
119         .is_alive = forb_is_alive,
120 };
121
122 /**
123  * Prepares #FORB_TMP_DIR directory for use by forb
124  *
125  * @return Zero on succes, -1 on error and errno is set appropriately.
126  */
127 int
128 forb_init_tmp_dir(void)
129 {
130         struct stat st;
131         int ret;
132
133         ret = stat(FORB_TMP_DIR, &st);
134
135         if (ret == 0 && !S_ISDIR(st.st_mode)) {
136                 ret = unlink(FORB_TMP_DIR);
137                 if (ret) return -1;
138         } else if (ret == 0) {
139                 return 0;
140         }
141         return mkdir(FORB_TMP_DIR, 0777);
142 }
143
144 /** 
145  * Thread for execution of remote requests for a FORB object.
146  * 
147  * @param arg 
148  * 
149  * @return 
150  */
151 static void *
152 forb_execution_thread(void *arg)
153 {
154         forb_executor_t *executor = arg;
155         forb_executor_run(executor);
156         return NULL;
157 }
158
159 #ifdef CONFIG_FCB
160 void hack_register_fcb(forb_orb orb, forb_port_t *port)
161 {
162         forb_object fcb = forb_object_new(orb, &FCB_SERVER_ID, 1);
163         if (!fcb) {
164                 ul_logerr("Cannot allocate FCB reference\n");
165                 return;
166         }
167         forb_register_reference(fcb, fres_contract_broker_reg_name);
168         forb_object_release(fcb);
169
170         
171
172         forb_object wai = forb_object_new(orb, &WAI_SERVER_ID, 1);
173         if (!fcb) {
174                 ul_logerr("Cannot allocate WAI reference\n");
175                 return;
176         }
177         forb_register_reference(wai, "net.sourceforge.frsh-forb.wai");
178         forb_object_release(wai);
179 }
180 #else
181 #define hack_register_fcb(orb)
182 #endif
183
184
185
186 forb_orb
187 forb_init(int *argc, char **argv[], const struct forb_init_attr *attr)
188 {
189         forb_orb orb;
190         forb_t *forb;
191         int ret;
192
193         forb = forb_malloc(sizeof(*forb));
194         if (!forb) goto err;
195         memset(forb, 0, sizeof(*forb));
196
197         /* Initialize ULUT logging facility */
198         init_ul_log();
199         forb_logreg_domains();
200
201         if (attr) {
202                 forb->attr = *attr;
203         } else {
204                 memset(&forb->attr, 0, sizeof(forb->attr));
205         }
206
207         sem_init(&forb->server_ready, 0, 0);
208
209         if (forb_server_id_empty(&forb->attr.fixed_server_id)) {
210                 forb_server_id_init(&forb->server_id);
211         } else {
212                 forb->server_id = forb->attr.fixed_server_id;
213         }
214         forb_server_id_to_string(forb->server_id_str, &forb->server_id,
215                                  sizeof(forb->server_id_str));
216         ul_logdeb("Initializing forb %s\n", forb->server_id_str);
217
218         if (fosa_mutex_init(&forb->request_id_mutex, 0) != 0) goto err2;
219         if (fosa_mutex_init(&forb->port_mutex, 0) != 0) goto err2;
220         forb_port_init_head(forb);
221         
222         if (fosa_mutex_init(&forb->request_mutex, 0) != 0) goto err2;
223         forb_request_nolock_init_root_field(forb);
224
225         if (forb_discovery_init(forb) != 0) goto err2;
226
227         if (fosa_mutex_init(&forb->regref_mutex, 0) != 0) goto err2;
228         forb_regref_nolock_init_root_field(forb);
229
230         ret = forb_init_tmp_dir();
231         if (ret != 0) {
232                 ul_logerr("Cannot prepare " FORB_TMP_DIR "\n");
233                 return NULL;
234         }
235
236         forb_executor_prepare();        
237
238         orb = forb_forb_orb_new(NULL, &forb_implementation, forb);
239         if (!orb) goto err2;
240         /* Server ID must be assigned manualy */
241         orb->server = forb->server_id;
242
243         forb->orb = orb;
244
245         /* Insert our object reference to objects tree, so that we
246          * can accept remote request to our new ORB. */
247         forb_objects_nolock_insert(forb, orb);
248
249         ret = forb_executor_init(&forb->default_executor);
250         if (ret) goto err2;
251         ret = forb_executor_register_object(&forb->default_executor, orb);
252         if (ret) goto err3;
253
254         ret = fosa_thread_create(&forb->execution_thread, NULL,
255                                  forb_execution_thread, &forb->default_executor);
256         if (ret != 0)
257                 goto err3;
258
259         /* FIXME: I do not know how to deregister the exit handler if
260          * forb_destroy() is called manually. */
261         /* on_exit(destroy_forb_on_exit, orb); */
262
263 #ifdef CONFIG_FORB_PROTO_UNIX
264         {
265                 forb_port_t *port = forb_malloc(sizeof(*port));
266                 if (port) {
267                         memset(port, 0, sizeof(*port));
268                         ret = forb_unix_port_init(&port->desc, &forb->server_id);
269                         if (ret) goto err_free_unix;
270                         ret = forb_register_port(orb, port);
271                         if (ret) goto err_free_unix; /* TODO: forb_unix_port_done() */
272                         goto unix_ok;
273                 }
274         err_free_unix:
275                 free(port);
276                 goto err3;
277         unix_ok:;
278         }
279 #endif
280 #ifdef CONFIG_FORB_PROTO_INET_DEFAULT
281         {
282                 forb_port_t *port = forb_malloc(sizeof(*port));
283                 if (port) {
284                         struct in_addr listen_on;
285
286                         memset(port, 0, sizeof(*port));
287                         listen_on.s_addr = INADDR_ANY;
288                         ret = forb_inet_port_init(&port->desc, listen_on,
289                                                   forb->attr.fixed_tcp_port);
290                         if (ret) goto err_free_inet;
291                         ret = forb_register_port(orb, port);
292                         if (ret) goto err_free_inet; /* TODO: forb_inet_port_done() */
293                         goto inet_ok;
294                 }
295         err_free_inet:
296                 free(port);
297                 goto err3;
298         inet_ok:;
299                 hack_register_fcb(orb, port);
300         }
301 #endif
302         return orb;
303
304 err3:   forb_executor_destroy(&forb->default_executor);
305 err2:   forb_free(forb);
306 err:    return NULL;
307 }
308
309 void forb_destroy(forb_orb orb)
310 {
311         forb_t *forb = forb_object_to_forb(orb);
312         forb_port_t *port;
313         forb_regref_t *regref;
314         forb_object obj;
315
316         /* Stop ports to prevent remote requests from coming */
317         ul_list_for_each(forb_port, forb, port) {
318                 forb_stop_port(port);
319         }
320
321         /* Wait for executors to finish all requests (and thus drop
322          * all references to peers). This is very inefficient for big
323          * number of objects, but we do not care */
324         gavl_cust_for_each(forb_objects_nolock, forb, obj) {
325                 forb_executor_t *executor;
326                 executor = forb_object_get_executor(obj);
327                 if (executor)
328                         forb_executor_synchronize(executor);
329         }
330
331         /* Destroy ports - this should drop all remaining references
332          * to peers and result in closing of all remote
333          * connections. */
334         ul_list_for_each_cut(forb_port, forb, port) {
335                 forb_destroy_port(port);
336         }
337
338         pthread_cancel(forb->execution_thread.pthread_id);
339         pthread_join(forb->execution_thread.pthread_id, NULL);
340         
341         /* Unregister all registered references */
342         while ((regref = forb_regref_first(forb))) {
343                 forb_unregister_reference(orb, regref->name.str);
344         }
345         
346         forb_object_release(orb);
347         forb_free(forb);
348 }
349
350 /* void */
351 /* forb_register_interface(const struct forb_interface *interface) */
352 /* { */
353 /*      gavl_insert(&type_registry, &interface->node); */
354 /* } */
355
356 /** 
357  * Initializes server ID variable.
358  * 
359  * @param server_id Serer ID to initialize.
360  */
361 void
362 forb_server_id_init(forb_server_id *server_id)
363 {
364         forb_uuid_generate((forb_uuid_t*)server_id->uuid);
365 }
366
367 /** 
368  * Checks whether the @a object is stale. Stale object is an object
369  * reference whose server cannot be contacted to handle requests.
370  * 
371  * @param object Object reference to check.
372  * 
373  * @return True if the object is stale, false otherwise.
374  */
375 bool forb_object_is_stale(forb_object object)
376 {
377         forb_orb remote_orb;
378         struct forb_env env;
379         bool stale = true;
380         
381         remote_orb = forb_get_orb_of(object);
382         if (!remote_orb) {      /* This shohuld never happen */
383                 goto err;
384         }
385         /* TODO: Check not only the ORB, but also whether the object
386          * is still registered with the remote orb. */
387         forb_orb_is_alive(remote_orb, &env);
388         if (env.major == FORB_EX_COMM_FAILURE) {
389                 /* Orb is not alive */
390                 stale = true;
391         } else {
392                 if (forb_exception_occurred(&env)) {
393                         ul_logerr("%s: unexpected exception: %s\n", __FUNCTION__, forb_strerror(&env));
394                 }
395                 stale = false;  
396         }
397
398         forb_object_release(remote_orb);
399 err:
400         return stale;
401 }
402
403
404 /** 
405  * Returns object reference of forb::orb object associated with the
406  * given object.
407  * 
408  * @param obj 
409  * 
410  * @return 
411  */
412 forb_orb
413 forb_get_orb_of(const forb_object obj)
414 {
415         forb_orb orb;
416
417         if (forb_server_id_cmp(&obj->server, &obj->orb->server) == 0) {
418                 orb = forb_object_duplicate(obj->orb);
419         } else {
420                 orb = forb_object_new(obj->orb, &obj->server, 0);
421         }
422         return orb;
423 }
424
425 /** 
426  * Returns server ID of an object reference.
427  * 
428  * @param obj 
429  * @param dest 
430  */
431 void
432 forb_get_server_id(const forb_object obj, forb_server_id *dest)
433 {
434         if (obj) {
435                 *dest = obj->server;
436         }
437 }
438
439
440 /** 
441  * Return instance data registered when the object was created by
442  * forb_XXX_new().
443  * 
444  * @param obj Object reference
445  * 
446  * @return Pointer to the registered data.
447  */
448 void *
449 forb_instance_data(const forb_object obj)
450 {
451         return forb_object_instance_data(obj);
452 }
453
454 /** 
455  * Returns error message correspondings FORB exception.
456  * 
457  * @param env Environemnt
458  * 
459  * @return Non-NULL pointer to a string.
460  */
461 const char *
462 forb_strerror(CORBA_Environment *env)
463 {
464         if (!env) {
465                 return "Invalid environemnt";
466         }
467 #define ex(e) case FORB_EX_##e: return #e; break;
468         switch (env->major) {
469         ex(NONE);
470         ex(UNKNOWN);
471         ex(BAD_PARAM);
472         ex(NO_MEMORY);
473         ex(IMP_LIMIT);
474         ex(COMM_FAILURE);
475         ex(INV_OBJREF);
476         ex(NO_PERMISSION);
477         ex(INTERNAL);
478         ex(MARSHAL);
479         ex(INITIALIZE);
480         ex(NO_IMPLEMENT);
481         ex(BAD_OPERATION);
482         ex(NO_RESOURCES);
483         ex(NO_RESPONSE);
484         ex(TRANSIENT);
485         ex(FREE_MEM);
486         ex(INV_IDENT);
487         ex(INV_FLAG);
488         ex(DATA_CONVERSION);
489         ex(OBJECT_NOT_EXIST);
490         ex(TIMEOUT);
491         ex(APPLICATION);
492         }
493 #undef ex
494         return "Invalid error number";
495 }
496
497 /** 
498  * Return server id of the requesting application.
499  *
500  * This function should be only called from within interface
501  * implementation,
502  * 
503  * @param[in] obj Object being requested
504  * @param[out] req_source Server ID of the requesting application
505  */
506 void
507 forb_get_req_source(const forb_object obj, forb_server_id *req_source)
508 {
509         if (req_source) {
510                 if (obj && obj->exec_req) {
511                         *req_source = obj->exec_req->source;
512                 } else {
513                         memset(req_source, 0, sizeof(*req_source));
514                 }
515         }
516 }
517
518 /**
519  * Internal function for allocation of sequence bufers. Used by
520  * forb_sequence_alloc_buf().
521  *
522  * @param seq
523  * @param seq_size
524  * @param buf_pptr
525  * @param maximum_ptr
526  * @param num_elements
527  * @param elem_size
528  *
529  * @return CORBA_TRUE if the allocation was sucessfull, CORBA_FALSE if
530  * it wasn't.
531  */
532 CORBA_boolean
533 __forb_sequence_alloc_buf_internal(void *seq, size_t seq_size,
534                                    void **buf_pptr, CORBA_unsigned_long *maximum_ptr,
535                                    unsigned num_elements, size_t elem_size)
536 {
537         memset(seq, 0, seq_size);
538         /*(seq)._length = 0;*/
539         if (num_elements && elem_size) *buf_pptr = forb_malloc(num_elements * elem_size);
540         else *buf_pptr = NULL;
541         *maximum_ptr = *buf_pptr ? num_elements : 0;
542         return (*buf_pptr != NULL) || (num_elements == 0);
543 }
544
545 static FILE *forb_ul_log_file;
546 static char progname[64] = "";
547
548 void
549 forb_ul_log_fnc(ul_log_domain_t *domain, int level,
550                 const char *format, va_list ap)
551 {
552         struct timespec now;
553         if(!(level&UL_LOGL_CONT)) {
554                 level&=UL_LOGL_MASK;
555                 clock_gettime(CLOCK_MONOTONIC, &now);
556                 fprintf(forb_ul_log_file,"%ld.%6ld: ", now.tv_sec, now.tv_nsec/1000);
557                 if (progname[0])
558                         fprintf(forb_ul_log_file,"%s: ", progname);
559                 if(domain && domain->name)
560                         fprintf(forb_ul_log_file,"%s: ",domain->name);
561         }
562         vfprintf(forb_ul_log_file, format, ap);
563         fflush(forb_ul_log_file);
564 }
565
566 static int init_ul_log(void)
567 {
568         char *s;
569         char *log_fname;
570         int fd;
571         int flg = 0;
572         char path[128];
573
574 /*      if(ul_log_output != NULL) */
575 /*              return 0; */
576
577         fd = open("/proc/self/cmdline", O_RDONLY);
578         if (fd >= 0) {
579                 int ret;
580                 ret = read(fd, path, sizeof(path)-1);
581                 if (ret > 0) {
582                         path[ret]=0;
583                         s = strrchr(path, '/');
584                         if (s) s++;
585                         else s = path;
586                         strncpy(progname, s, sizeof(progname)-1);
587                 }
588                 close(fd);
589         }
590
591         if((log_fname=getenv("UL_LOG_FILENAME"))!=NULL){
592                 forb_ul_log_file=fopen(log_fname,"a");
593         }
594         if(forb_ul_log_file==NULL)
595                 forb_ul_log_file=stderr;
596         
597         if((s=getenv("UL_DEBUG_FLG")) != NULL){
598                 flg=atoi(s);
599         }
600
601         ul_log_redir(forb_ul_log_fnc, flg);
602
603         if((s = getenv("UL_LOG_LEVELS")) != NULL)
604                 ul_log_domain_arg2levels(s);
605
606         return 0;
607 }
608
609 /** 
610  * Wait for the server to be ready. Internal function intended forb
611  * forbrun.
612  * 
613  * @param orb ORB.
614  * 
615  * @return Zero on success; on error -1 is returned, and errno is set
616  * to indicate the error.
617  */
618 int forb_wait_for_server_ready(forb_orb orb)
619 {
620         forb_t *forb = forb_object_to_forb(orb);
621         return sem_wait(&forb->server_ready);
622 }
623
624 /** 
625  * Signal the the FORB core that the server is ready for accepting
626  * requests.
627  *
628  * This function should be called at the initialization of server
629  * implementation at the time when all objects are registered with
630  * executors. All other servers in the same address space are
631  * initialized after this function is called which allows the other
632  * servers to use the services provided by the calling server.
633  * 
634  * @param orb ORB object.
635  * 
636  * @return Zero on success; on error -1 is returned, and errno is set
637  * to indicate the error.
638  */
639 int forb_signal_server_ready(forb_orb orb)
640 {
641         forb_t *forb = forb_object_to_forb(orb);
642         return sem_post(&forb->server_ready);
643 }