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