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