source: trunk/third/bonobo-activation/bonobo-activation/bonobo-activation-base-service.c @ 18311

Revision 18311, 17.9 KB checked in by ghudson, 22 years ago (diff)
This commit was generated by cvs2svn to compensate for changes in r18310, which included commits to RCS files with non-trunk default branches.
Line 
1/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*- */
2/*
3 *  bonobo-activation: A library for accessing bonobo-activation-server.
4 *
5 *  Copyright (C) 1999, 2000 Red Hat, Inc.
6 *  Copyright (C) 2000, 2001 Eazel, Inc.
7 *
8 *  This library is free software; you can redistribute it and/or
9 *  modify it under the terms of the GNU Library General Public
10 *  License as published by the Free Software Foundation; either
11 *  version 2 of the License, or (at your option) any later version.
12 *
13 *  This library is distributed in the hope that it will be useful,
14 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
15 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
16 *  Library General Public License for more details.
17 *
18 *  You should have received a copy of the GNU Library General Public
19 *  License along with this library; if not, write to the Free
20 *  Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
21 *
22 *  Author: Elliot Lee <sopwith@redhat.com>
23 *
24 */
25
26/* This is part of the per-app CORBA bootstrapping - we use this to get
27   hold of a running metaserver and such */
28
29
30#include <bonobo-activation/bonobo-activation-i18n.h>
31#include <bonobo-activation/bonobo-activation-init.h>
32#include <bonobo-activation/bonobo-activation-base-service.h>
33#include <bonobo-activation/bonobo-activation-private.h>
34#include <bonobo-activation/Bonobo_ActivationContext.h>
35#include <bonobo-activation/bonobo-activation-client.h>
36
37#ifndef _GNU_SOURCE
38#define _GNU_SOURCE 1
39#endif
40#include <string.h>
41#include <limits.h>
42#include <errno.h>
43#include <unistd.h>
44#include <time.h>
45#include <stdio.h>
46#include <signal.h>
47#include <sys/types.h>
48#include <sys/wait.h>
49#include <stdlib.h>
50#include <fcntl.h>
51
52/* If you have a strange unix, you get odd hard coded limits */
53#ifndef PATH_MAX
54#  define PATH_MAX 1024
55#endif
56
57static GSList *registries = NULL;
58
59typedef struct {
60        int priority;
61        const BonoboActivationBaseServiceRegistry *registry;
62        gpointer user_data;
63} RegistryInfo;
64
65typedef struct {
66        int priority;
67        BonoboActivationBaseServiceActivator activator;
68} ActivatorInfo;
69
70static gint
71ri_compare (gconstpointer a, gconstpointer b)
72{
73        RegistryInfo *ra = (RegistryInfo *) a;
74        RegistryInfo *rb = (RegistryInfo *) b;
75
76        return (rb->priority - ra->priority);
77}
78
79void
80bonobo_activation_base_service_registry_add
81                      (const BonoboActivationBaseServiceRegistry *registry,
82                       int                                        priority,
83                       gpointer                                   user_data)
84{
85        RegistryInfo *new_ri;
86
87        g_return_if_fail (registry);
88
89        new_ri = g_new (RegistryInfo, 1);
90        new_ri->priority = priority;
91        new_ri->registry = registry;
92        new_ri->user_data = user_data;
93
94        registries = g_slist_insert_sorted (registries, new_ri, ri_compare);
95}
96
97CORBA_Object
98bonobo_activation_base_service_check (const BonoboActivationBaseService *base_service,
99                                      CORBA_Environment                 *ev)
100{
101        GSList *link;
102        CORBA_Object retval = CORBA_OBJECT_NIL;
103        int dist = INT_MAX;
104        char *ior = NULL;
105
106        for (link = registries; link; link = link->next) {
107                RegistryInfo *ri;
108                char *new_ior;
109                int new_dist = dist;
110
111                ri = link->data;
112
113                if (!ri->registry->check)
114                        continue;
115
116                new_ior = ri->registry->check (ri->registry, base_service,
117                                             &new_dist, ri->user_data);
118                if (new_ior && (new_dist < dist)) {
119                        g_free (ior);
120                        ior = new_ior;
121                } else if (new_ior) {
122                        g_free (new_ior);
123                }
124        }
125
126        if (ior) {
127                retval = CORBA_ORB_string_to_object (bonobo_activation_orb_get (), ior, ev);
128                if (ev->_major != CORBA_NO_EXCEPTION)
129                        retval = CORBA_OBJECT_NIL;
130
131                g_free (ior);
132        }
133
134        return retval;
135}
136
137/*dumb marshalling hack */
138static void
139bonobo_activation_registration_iterate (const BonoboActivationBaseService *base_service,
140                          CORBA_Object obj, CORBA_Environment *ev,
141                          gulong offset, int nargs)
142{
143        GSList *link;
144        char *ior = NULL;
145
146        if (nargs == 4)
147                ior = CORBA_ORB_object_to_string (bonobo_activation_orb_get (), obj, ev);
148
149        for (link = registries; link; link = link->next) {
150                RegistryInfo *ri;
151                void (*func_ptr) ();
152
153                ri = link->data;
154
155                func_ptr = *(gpointer *) ((guchar *) ri->registry + offset);
156
157                if (!func_ptr)
158                        continue;
159
160                switch (nargs) {
161                case 4:
162                        func_ptr (ri->registry, ior, base_service, ri->user_data);
163                        break;
164                case 2:
165                        func_ptr (ri->registry, ri->user_data);
166                        break;
167                }
168        }
169
170        if (nargs == 4)
171                CORBA_free (ior);
172}
173
174static int lock_count = 0;
175
176static void
177bonobo_activation_registries_lock (CORBA_Environment *ev)
178{
179        if (lock_count == 0)
180                bonobo_activation_registration_iterate (NULL, CORBA_OBJECT_NIL, ev,
181                                          G_STRUCT_OFFSET
182                                          (BonoboActivationBaseServiceRegistry, lock), 2);
183        lock_count++;
184}
185
186static void
187bonobo_activation_registries_unlock (CORBA_Environment *ev)
188{
189        lock_count--;
190        if (lock_count == 0)
191                bonobo_activation_registration_iterate (NULL, CORBA_OBJECT_NIL, ev,
192                                          G_STRUCT_OFFSET
193                                          (BonoboActivationBaseServiceRegistry, unlock),
194                                          2);
195}
196
197void
198bonobo_activation_base_service_unset (const BonoboActivationBaseService *base_service,
199                        CORBA_Object obj, CORBA_Environment *ev)
200{
201        bonobo_activation_registries_lock (ev);
202        bonobo_activation_registration_iterate (base_service, obj, ev,
203                                  G_STRUCT_OFFSET (BonoboActivationBaseServiceRegistry,
204                                                   unregister), 4);
205        bonobo_activation_registries_unlock (ev);
206}
207
208void
209bonobo_activation_base_service_set (const BonoboActivationBaseService *base_service,
210                      CORBA_Object obj, CORBA_Environment *ev)
211{
212        bonobo_activation_registries_lock (ev);
213        bonobo_activation_registration_iterate (base_service, obj, ev,
214                                  G_STRUCT_OFFSET (BonoboActivationBaseServiceRegistry,
215                                                   register_new), 4);
216        bonobo_activation_registries_unlock (ev);
217}
218
219
220const char *bonobo_activation_ac_cmd[] =
221        { SERVER_LIBEXECDIR "/bonobo-activation-server", "--ac-activate", "--ior-output-fd=%d", NULL };
222const char *bonobo_activation_od_cmd[] =
223        { SERVER_LIBEXECDIR "/bonobo-activation-server", "--ior-output-fd=%d", NULL };
224
225struct SysServerInstance
226{
227        CORBA_Object already_running;
228        char *username, *hostname, *domain;
229};
230
231struct SysServer
232{
233        const char *name;
234        const char **cmd;
235        int fd_arg;
236        GSList *instances;
237}
238activatable_servers[] =
239{
240        {"IDL:Bonobo/ActivationContext:1.0", (const char **) bonobo_activation_ac_cmd,
241         2, CORBA_OBJECT_NIL},
242        { NULL}
243};
244
245#define STRMATCH(x, y) ((!x && !y) || (x && y && !strcmp(x, y)))
246static CORBA_Object
247existing_check (const BonoboActivationBaseService *base_service, struct SysServer *ss)
248{
249        GSList *link;
250
251        for (link = ss->instances; link; link = link->next) {
252                struct SysServerInstance *ssi;
253
254                ssi = link->data;
255                if (
256                    (!ssi->username
257                     || STRMATCH (ssi->username, base_service->username))
258                    && (!ssi->hostname
259                        || STRMATCH (ssi->hostname, base_service->hostname))
260                    && (!ssi->domain
261                        || STRMATCH (ssi->domain,
262                                     base_service->
263                                     domain))) {
264                        return ssi->already_running;
265                }
266        }
267
268        return CORBA_OBJECT_NIL;
269}
270
271void
272bonobo_activation_base_service_debug_shutdown (CORBA_Environment *ev)
273{
274        int     i;
275        GSList *l, *instances;
276        struct SysServerInstance *ssi;
277
278        for (i = 0; activatable_servers[i].name; i++) {
279
280                instances = activatable_servers[i].instances;
281                activatable_servers[i].instances = NULL;
282
283                for (l = instances; l; l = l->next) {
284                        ssi = l->data;
285
286                        CORBA_Object_release (ssi->already_running, ev);
287                        g_free (ssi->username);
288                        g_free (ssi->hostname);
289                        g_free (ssi->domain);
290                        g_free (ssi);
291                }
292                g_slist_free (instances);
293        }
294}
295
296static void
297bonobo_activation_existing_set (const BonoboActivationBaseService *base_service, struct SysServer *ss,
298                                CORBA_Object obj, CORBA_Environment *ev)
299{
300        GSList *link;
301        struct SysServerInstance *ssi;
302
303        ssi = NULL;
304
305        for (link = ss->instances; link; link = link->next) {
306                ssi = link->data;
307                if (
308                    (!ssi->username
309                     || STRMATCH (ssi->username, base_service->username))
310                    && (!ssi->hostname
311                        || STRMATCH (ssi->hostname, base_service->hostname))
312                    && (!ssi->domain
313                        || STRMATCH (ssi->domain, base_service->domain))) break;
314        }
315
316        if (link == NULL) {
317                ssi = g_new0 (struct SysServerInstance, 1);
318                ssi->already_running = obj;
319                ssi->username =
320                        base_service->username ? g_strdup (base_service->username) : NULL;
321                ssi->hostname =
322                        base_service->hostname ? g_strdup (base_service->hostname) : NULL;
323                ssi->domain =
324                        base_service->domain ? g_strdup (base_service->domain) : NULL;
325                ss->instances = g_slist_prepend (ss->instances, ssi);
326        } else {
327                CORBA_Object_release (ssi->already_running, ev);
328                ssi->already_running = obj;
329        }
330
331        /* FIXME: all this code is unneccesarily abstract & buggy with it */
332        if (!strcmp (base_service->name, "IDL:Bonobo/ActivationContext:1.0")) {
333                bonobo_activation_register_client (obj, ev);
334        }
335}
336
337static GSList *activator_list = NULL;
338
339static gint
340ai_compare (gconstpointer a, gconstpointer b)
341{
342        const ActivatorInfo *ra, *rb;
343
344        ra = a;
345        rb = b;
346
347        return (rb->priority - ra->priority);
348}
349
350void
351bonobo_activation_base_service_activator_add (BonoboActivationBaseServiceActivator activator,
352                                int priority)
353{
354        ActivatorInfo *new_act;
355
356        new_act = g_new (ActivatorInfo, 1);
357        new_act->priority = priority;
358        new_act->activator = activator;
359        activator_list =
360                g_slist_insert_sorted (activator_list, new_act, ai_compare);
361}
362
363static CORBA_Object
364bonobo_activation_activators_use (const BonoboActivationBaseService *base_service, const char **cmd,
365                                  int fd_arg, CORBA_Environment *ev)
366{
367        CORBA_Object retval = CORBA_OBJECT_NIL;
368        GSList *link;
369
370        for (link = activator_list; CORBA_Object_is_nil (retval, ev) && link;
371             link = link->next) {
372                ActivatorInfo *actinfo;
373                actinfo = link->data;
374
375                retval = actinfo->activator (base_service, cmd, fd_arg, ev);
376        }
377
378        return retval;
379}
380
381CORBA_Object
382bonobo_activation_internal_service_get_extended (
383        const BonoboActivationBaseService *base_service,
384        gboolean              existing_only,
385        CORBA_Environment    *ev)
386{
387        CORBA_Object retval = CORBA_OBJECT_NIL;
388        int i;
389        CORBA_Environment myev, important_error_ev;
390        gboolean ne;
391
392        g_return_val_if_fail (base_service, CORBA_OBJECT_NIL);
393
394        for (i = 0; activatable_servers[i].name; i++) {
395                if (!strcmp (base_service->name, activatable_servers[i].name))
396                        break;
397        }
398
399        if (!activatable_servers[i].name)
400                return retval;
401
402        CORBA_exception_init (&myev);
403        CORBA_exception_init (&important_error_ev);
404       
405        retval = existing_check (base_service, &activatable_servers[i]);
406        if (!CORBA_Object_non_existent (retval, ev))
407                goto out;
408
409        bonobo_activation_registries_lock (ev);
410
411        retval = bonobo_activation_base_service_check (base_service, &myev);
412        ne = CORBA_Object_non_existent (retval, &myev);
413        if (ne && !existing_only) {
414                CORBA_Object race_condition;
415
416                CORBA_Object_release (retval, &myev);
417               
418                retval =
419                        bonobo_activation_activators_use (base_service,
420                                            activatable_servers[i].cmd,
421                                            activatable_servers[i].fd_arg,
422                                            &important_error_ev);
423
424                race_condition = bonobo_activation_base_service_check (base_service, &myev);
425
426                if (!CORBA_Object_non_existent (race_condition, &myev)) {
427                        CORBA_Object_release (retval, &myev);
428                        retval = race_condition;
429                } else if (!CORBA_Object_is_nil (retval, &myev)) {
430                        bonobo_activation_base_service_set (base_service, retval, &myev);
431                        CORBA_Object_release (race_condition, &myev);
432                }
433        }
434
435        bonobo_activation_registries_unlock (ev);
436
437        if (!CORBA_Object_non_existent (retval, ev))
438                bonobo_activation_existing_set (base_service, &activatable_servers[i], retval, ev);
439
440      out:
441        /* If we overwrote ev with some stupid junk, replace
442         * it with the real error
443         */
444        if (important_error_ev._major != CORBA_NO_EXCEPTION) {
445                CORBA_exception_free (ev);
446                /* This transfers memory ownership */
447                *ev = important_error_ev;
448        }
449       
450        CORBA_exception_free (&myev);
451
452        return retval;
453}
454
455CORBA_Object
456bonobo_activation_service_get (const BonoboActivationBaseService *base_service)
457{
458        CORBA_Environment ev;
459        CORBA_Object obj;
460       
461        CORBA_exception_init (&ev);
462       
463        obj = bonobo_activation_internal_service_get_extended (
464                base_service, FALSE, &ev);
465
466        CORBA_exception_free (&ev);
467
468        return obj;
469}
470
471/*****Implementation of the IOR registration system via plain files ******/
472static int lock_fd = -1;
473
474/*
475 * The linc-tmpdir might not be what we expect,
476 * requires linc >= 0.5.1
477 */
478static const char *
479get_tmpdir (void)
480{
481        static char *tmpdir = NULL;
482
483        if (!tmpdir)
484                tmpdir = linc_get_tmpdir ();
485
486        if (!tmpdir) {
487                g_warning ("very odd tmpdir problem");
488                tmpdir = g_strdup_printf ("/tmp/orbit-%s", g_get_user_name ());
489        }
490
491        return tmpdir;
492}
493
494static char *
495get_lock_fname (void)
496{
497        return g_strconcat (get_tmpdir (), "/bonobo-activation-register.lock", NULL);
498}
499
500static char *
501get_ior_fname (void)
502{
503        return g_strconcat (get_tmpdir (), "/bonobo-activation-server-ior", NULL);
504}
505
506static void
507wait_for_lock (void)
508{
509#ifdef HAVE_USLEEP
510        usleep (10000);
511
512#elif defined(HAVE_NANOSLEEP)
513        struct timespec timewait;
514        timewait.tv_sec = 0;
515        timewait.tv_nsec = 1000000;
516        nanosleep (&timewait, NULL);
517
518#else
519#warning You will have bad performance without usleep
520        sleep (1);
521#endif
522        access ("bonobo-activation lock wait", 0);
523}
524
525static void
526rloc_file_lock (const BonoboActivationBaseServiceRegistry *registry,
527                gpointer                                   user_data)
528{
529        char *fn;
530        struct flock lock;
531        int retval;
532        char *err;
533
534        fn = get_lock_fname ();
535
536        while ((lock_fd = open (fn, O_CREAT | O_RDWR, 0700)) < 0) {
537
538                if (errno == EEXIST)
539                        wait_for_lock ();
540
541                else {
542                        g_warning ("%s locking '%s'", g_strerror (errno), fn);
543                        break;
544                }
545        }
546
547        fcntl (lock_fd, F_SETFD, FD_CLOEXEC);
548
549        if (lock_fd >= 0) {
550                lock.l_type = F_WRLCK;
551                lock.l_whence = SEEK_SET;
552                lock.l_start = 0;
553                lock.l_len = 1;
554                lock.l_pid = getpid ();
555
556                while ((retval = fcntl (lock_fd, F_SETLKW, &lock)) < 0
557                       && errno == EINTR) /**/;
558
559                if (retval < 0) {
560                        /* FIXME: need to report this error in a better way. */
561                        err = strerror (errno);
562                        g_warning ("Failed to acquire lock: %s\n.", err);
563                }
564        }
565
566        g_free (fn);
567}
568
569static void
570rloc_file_unlock (const BonoboActivationBaseServiceRegistry *registry,
571                  gpointer                                   user_data)
572{
573        struct flock lock;
574
575        if (lock_fd >= 0) {
576
577                lock.l_type = F_UNLCK;
578                lock.l_whence = SEEK_SET;
579                lock.l_start = 0;
580                lock.l_len = 1;
581                lock.l_pid = getpid ();
582
583                fcntl (lock_fd, F_SETLKW, &lock);
584                close (lock_fd);
585                lock_fd = -1;
586        }
587}
588
589static char *
590rloc_file_check (const BonoboActivationBaseServiceRegistry *registry,
591                 const BonoboActivationBaseService *base_service, int *ret_distance,
592                 gpointer user_data)
593{
594        FILE *fh;
595        char *fn;
596
597        fn = get_ior_fname ();
598        fh = fopen (fn, "r");
599        g_free (fn);
600
601        if (fh != NULL) {
602                char iorbuf[8192];
603
604                iorbuf[0] = '\0';
605                while (fgets (iorbuf, sizeof (iorbuf), fh)
606                       && strncmp (iorbuf, "IOR:", 4))
607                        /**/;
608                g_strstrip (iorbuf);
609
610                fclose (fh);
611
612                if (!strncmp (iorbuf, "IOR:", 4)) {
613                        *ret_distance = 0;
614                        return g_strdup (iorbuf);
615                }
616        }
617
618        return NULL;
619}
620
621static void
622rloc_file_register (const BonoboActivationBaseServiceRegistry *registry, const char *ior,
623                    const BonoboActivationBaseService *base_service,
624                    gpointer user_data)
625{
626        char *fn;
627        FILE *fh;
628
629        fn = get_ior_fname ();
630        fh = fopen (fn, "w");
631
632        if (fh != NULL) {
633                fprintf (fh, "%s\n", ior);
634                fclose (fh);
635        }       
636
637        g_free (fn);
638}
639
640static void
641rloc_file_unregister (const BonoboActivationBaseServiceRegistry *registry,
642                      const char                                *ior,
643                      const BonoboActivationBaseService         *base_service,
644                      gpointer                                   user_data)
645{
646        char *fn;
647
648        unlink ((fn = get_ior_fname ()));
649        g_free (fn);
650}
651
652static const BonoboActivationBaseServiceRegistry rloc_file = {
653        rloc_file_lock,
654        rloc_file_unlock,
655        rloc_file_check,
656        rloc_file_register,
657        rloc_file_unregister
658};
659
660#define STRMATCH(x, y) ((!x && !y) || (x && y && !strcmp(x, y)))
661
662static CORBA_Object
663local_re_check_fn (const char        *display,
664                   const char        *act_iid,
665                   gpointer           user_data,
666                   CORBA_Environment *ev)
667{
668        return bonobo_activation_internal_service_get_extended (
669                user_data, TRUE, ev);
670}
671
672static CORBA_Object
673local_activator (const BonoboActivationBaseService *base_service,
674                 const char **cmd,
675                 int fd_arg,
676                 CORBA_Environment *ev)
677{
678        if (
679            (!base_service->username
680             || STRMATCH (base_service->username, g_get_user_name ()))
681            && (!base_service->hostname
682                || STRMATCH (base_service->hostname, bonobo_activation_hostname_get ()))
683            && (!base_service->domain
684                || STRMATCH (base_service->domain, bonobo_activation_domain_get ()))) {
685                return bonobo_activation_server_by_forking (
686                        cmd, FALSE, fd_arg, NULL, NULL, base_service->name,
687                        local_re_check_fn, (gpointer)base_service, ev);
688        }
689
690        return CORBA_OBJECT_NIL;
691}
692
693void
694bonobo_activation_base_service_init (void)
695{
696        bonobo_activation_base_service_activator_add (local_activator, 0);
697
698        bonobo_activation_base_service_registry_add (&rloc_file, 0, NULL);
699}
Note: See TracBrowser for help on using the repository browser.