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

Revision 18563, 17.5 KB checked in by ghudson, 22 years ago (diff)
This commit was generated by cvs2svn to compensate for changes in r18562, 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;
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                        return ssi->already_running;
261        }
262
263        return CORBA_OBJECT_NIL;
264}
265
266void
267bonobo_activation_base_service_debug_shutdown (CORBA_Environment *ev)
268{
269        int     i;
270        GSList *l, *instances;
271        struct SysServerInstance *ssi;
272
273        for (i = 0; activatable_servers[i].name; i++) {
274
275                instances = activatable_servers[i].instances;
276                activatable_servers[i].instances = NULL;
277
278                for (l = instances; l; l = l->next) {
279                        ssi = l->data;
280
281                        CORBA_Object_release (ssi->already_running, ev);
282                        g_free (ssi->username);
283                        g_free (ssi->hostname);
284                        g_free (ssi);
285                }
286                g_slist_free (instances);
287        }
288}
289
290static void
291bonobo_activation_existing_set (const BonoboActivationBaseService *base_service, struct SysServer *ss,
292                                CORBA_Object obj, CORBA_Environment *ev)
293{
294        GSList *link;
295        struct SysServerInstance *ssi;
296
297        ssi = NULL;
298
299        for (link = ss->instances; link; link = link->next) {
300                ssi = link->data;
301                if (
302                    (!ssi->username
303                     || STRMATCH (ssi->username, base_service->username))
304                    && (!ssi->hostname
305                        || STRMATCH (ssi->hostname, base_service->hostname))) break;
306        }
307
308        if (link == NULL) {
309                ssi = g_new0 (struct SysServerInstance, 1);
310                ssi->already_running = obj;
311                ssi->username =
312                        base_service->username ? g_strdup (base_service->username) : NULL;
313                ssi->hostname =
314                        base_service->hostname ? g_strdup (base_service->hostname) : NULL;
315                ss->instances = g_slist_prepend (ss->instances, ssi);
316        } else {
317                CORBA_Object_release (ssi->already_running, ev);
318                ssi->already_running = obj;
319        }
320
321        /* FIXME: all this code is unneccesarily abstract & buggy with it */
322        if (!strcmp (base_service->name, "IDL:Bonobo/ActivationContext:1.0")) {
323                bonobo_activation_register_client (obj, ev);
324        }
325}
326
327static GSList *activator_list = NULL;
328
329static gint
330ai_compare (gconstpointer a, gconstpointer b)
331{
332        const ActivatorInfo *ra, *rb;
333
334        ra = a;
335        rb = b;
336
337        return (rb->priority - ra->priority);
338}
339
340void
341bonobo_activation_base_service_activator_add (BonoboActivationBaseServiceActivator activator,
342                                int priority)
343{
344        ActivatorInfo *new_act;
345
346        new_act = g_new (ActivatorInfo, 1);
347        new_act->priority = priority;
348        new_act->activator = activator;
349        activator_list =
350                g_slist_insert_sorted (activator_list, new_act, ai_compare);
351}
352
353static CORBA_Object
354bonobo_activation_activators_use (const BonoboActivationBaseService *base_service, const char **cmd,
355                                  int fd_arg, CORBA_Environment *ev)
356{
357        CORBA_Object retval = CORBA_OBJECT_NIL;
358        GSList *link;
359
360        for (link = activator_list; CORBA_Object_is_nil (retval, ev) && link;
361             link = link->next) {
362                ActivatorInfo *actinfo;
363                actinfo = link->data;
364
365                retval = actinfo->activator (base_service, cmd, fd_arg, ev);
366        }
367
368        return retval;
369}
370
371CORBA_Object
372bonobo_activation_internal_service_get_extended (
373        const BonoboActivationBaseService *base_service,
374        gboolean              existing_only,
375        CORBA_Environment    *ev)
376{
377        CORBA_Object retval = CORBA_OBJECT_NIL;
378        int i;
379        CORBA_Environment myev, important_error_ev;
380        gboolean ne;
381
382        g_return_val_if_fail (base_service, CORBA_OBJECT_NIL);
383
384        for (i = 0; activatable_servers[i].name; i++) {
385                if (!strcmp (base_service->name, activatable_servers[i].name))
386                        break;
387        }
388
389        if (!activatable_servers[i].name)
390                return retval;
391
392        CORBA_exception_init (&myev);
393        CORBA_exception_init (&important_error_ev);
394       
395        retval = existing_check (base_service, &activatable_servers[i]);
396        if (!CORBA_Object_non_existent (retval, ev))
397                goto out;
398
399        bonobo_activation_registries_lock (ev);
400
401        retval = bonobo_activation_base_service_check (base_service, &myev);
402        ne = CORBA_Object_non_existent (retval, &myev);
403        if (ne && !existing_only) {
404                CORBA_Object race_condition;
405
406                CORBA_Object_release (retval, &myev);
407               
408                retval =
409                        bonobo_activation_activators_use (base_service,
410                                            activatable_servers[i].cmd,
411                                            activatable_servers[i].fd_arg,
412                                            &important_error_ev);
413
414                race_condition = bonobo_activation_base_service_check (base_service, &myev);
415
416                if (!CORBA_Object_non_existent (race_condition, &myev)) {
417                        CORBA_Object_release (retval, &myev);
418                        retval = race_condition;
419                } else if (!CORBA_Object_is_nil (retval, &myev)) {
420                        bonobo_activation_base_service_set (base_service, retval, &myev);
421                        CORBA_Object_release (race_condition, &myev);
422                }
423        }
424
425        bonobo_activation_registries_unlock (ev);
426
427        if (!CORBA_Object_non_existent (retval, ev))
428                bonobo_activation_existing_set (base_service, &activatable_servers[i], retval, ev);
429
430      out:
431        /* If we overwrote ev with some stupid junk, replace
432         * it with the real error
433         */
434        if (important_error_ev._major != CORBA_NO_EXCEPTION) {
435                CORBA_exception_free (ev);
436                /* This transfers memory ownership */
437                *ev = important_error_ev;
438        }
439       
440        CORBA_exception_free (&myev);
441
442        return retval;
443}
444
445CORBA_Object
446bonobo_activation_service_get (const BonoboActivationBaseService *base_service)
447{
448        CORBA_Environment ev;
449        CORBA_Object obj;
450       
451        CORBA_exception_init (&ev);
452       
453        obj = bonobo_activation_internal_service_get_extended (
454                base_service, FALSE, &ev);
455
456        CORBA_exception_free (&ev);
457
458        return obj;
459}
460
461/*****Implementation of the IOR registration system via plain files ******/
462static int lock_fd = -1;
463
464/*
465 * The linc-tmpdir might not be what we expect,
466 * requires linc >= 0.5.1
467 */
468static const char *
469get_tmpdir (void)
470{
471        static char *tmpdir = NULL;
472
473        if (!tmpdir)
474                tmpdir = linc_get_tmpdir ();
475
476        if (!tmpdir) {
477                g_warning ("very odd tmpdir problem");
478                tmpdir = g_strdup_printf ("/tmp/orbit-%s", g_get_user_name ());
479        }
480
481        return tmpdir;
482}
483
484static char *
485get_lock_fname (void)
486{
487        return g_strconcat (get_tmpdir (), "/bonobo-activation-register.lock", NULL);
488}
489
490static char *
491get_ior_fname (void)
492{
493        return g_strconcat (get_tmpdir (), "/bonobo-activation-server-ior", NULL);
494}
495
496static void
497wait_for_lock (void)
498{
499#ifdef HAVE_USLEEP
500        usleep (10000);
501
502#elif defined(HAVE_NANOSLEEP)
503        struct timespec timewait;
504        timewait.tv_sec = 0;
505        timewait.tv_nsec = 1000000;
506        nanosleep (&timewait, NULL);
507
508#else
509#warning You will have bad performance without usleep
510        sleep (1);
511#endif
512        access ("bonobo-activation lock wait", 0);
513}
514
515static void
516rloc_file_lock (const BonoboActivationBaseServiceRegistry *registry,
517                gpointer                                   user_data)
518{
519        char *fn;
520        struct flock lock;
521        int retval;
522        char *err;
523
524        fn = get_lock_fname ();
525
526        while ((lock_fd = open (fn, O_CREAT | O_RDWR, 0700)) < 0) {
527
528                if (errno == EEXIST)
529                        wait_for_lock ();
530
531                else {
532                        g_warning ("%s locking '%s'", g_strerror (errno), fn);
533                        break;
534                }
535        }
536
537        fcntl (lock_fd, F_SETFD, FD_CLOEXEC);
538
539        if (lock_fd >= 0) {
540                lock.l_type = F_WRLCK;
541                lock.l_whence = SEEK_SET;
542                lock.l_start = 0;
543                lock.l_len = 1;
544                lock.l_pid = getpid ();
545
546                while ((retval = fcntl (lock_fd, F_SETLKW, &lock)) < 0
547                       && errno == EINTR) /**/;
548
549                if (retval < 0) {
550                        /* FIXME: need to report this error in a better way. */
551                        err = strerror (errno);
552                        g_warning ("Failed to acquire lock: %s\n.", err);
553                }
554        }
555
556        g_free (fn);
557}
558
559static void
560rloc_file_unlock (const BonoboActivationBaseServiceRegistry *registry,
561                  gpointer                                   user_data)
562{
563        struct flock lock;
564
565        if (lock_fd >= 0) {
566
567                lock.l_type = F_UNLCK;
568                lock.l_whence = SEEK_SET;
569                lock.l_start = 0;
570                lock.l_len = 1;
571                lock.l_pid = getpid ();
572
573                fcntl (lock_fd, F_SETLKW, &lock);
574                close (lock_fd);
575                lock_fd = -1;
576        }
577}
578
579static char *
580rloc_file_check (const BonoboActivationBaseServiceRegistry *registry,
581                 const BonoboActivationBaseService *base_service, int *ret_distance,
582                 gpointer user_data)
583{
584        FILE *fh;
585        char *fn;
586
587        fn = get_ior_fname ();
588        fh = fopen (fn, "r");
589        g_free (fn);
590
591        if (fh != NULL) {
592                char iorbuf[8192];
593
594                iorbuf[0] = '\0';
595                while (fgets (iorbuf, sizeof (iorbuf), fh)
596                       && strncmp (iorbuf, "IOR:", 4))
597                        /**/;
598                g_strstrip (iorbuf);
599
600                fclose (fh);
601
602                if (!strncmp (iorbuf, "IOR:", 4)) {
603                        *ret_distance = 0;
604                        return g_strdup (iorbuf);
605                }
606        }
607
608        return NULL;
609}
610
611static void
612rloc_file_register (const BonoboActivationBaseServiceRegistry *registry, const char *ior,
613                    const BonoboActivationBaseService *base_service,
614                    gpointer user_data)
615{
616        char *fn;
617        FILE *fh;
618
619        fn = get_ior_fname ();
620        fh = fopen (fn, "w");
621
622        if (fh != NULL) {
623                fprintf (fh, "%s\n", ior);
624                fclose (fh);
625        }       
626
627        g_free (fn);
628}
629
630static void
631rloc_file_unregister (const BonoboActivationBaseServiceRegistry *registry,
632                      const char                                *ior,
633                      const BonoboActivationBaseService         *base_service,
634                      gpointer                                   user_data)
635{
636        char *fn;
637
638        unlink ((fn = get_ior_fname ()));
639        g_free (fn);
640}
641
642static const BonoboActivationBaseServiceRegistry rloc_file = {
643        rloc_file_lock,
644        rloc_file_unlock,
645        rloc_file_check,
646        rloc_file_register,
647        rloc_file_unregister
648};
649
650#define STRMATCH(x, y) ((!x && !y) || (x && y && !strcmp(x, y)))
651
652static CORBA_Object
653local_re_check_fn (const Bonobo_ActivationEnvironment *environment,
654                   const char                         *act_iid,
655                   gpointer                            user_data,
656                   CORBA_Environment                  *ev)
657{
658        return bonobo_activation_internal_service_get_extended (
659                user_data, TRUE, ev);
660}
661
662static CORBA_Object
663local_activator (const BonoboActivationBaseService *base_service,
664                 const char **cmd,
665                 int fd_arg,
666                 CORBA_Environment *ev)
667{
668        if (
669            (!base_service->username
670             || STRMATCH (base_service->username, g_get_user_name ()))
671            && (!base_service->hostname
672                || STRMATCH (base_service->hostname, bonobo_activation_hostname_get ()))) {
673                return bonobo_activation_server_by_forking (
674                        cmd, FALSE, fd_arg, NULL, NULL, base_service->name,
675                        local_re_check_fn, (gpointer)base_service, ev);
676        }
677
678        return CORBA_OBJECT_NIL;
679}
680
681void
682bonobo_activation_base_service_init (void)
683{
684        bonobo_activation_base_service_activator_add (local_activator, 0);
685
686        bonobo_activation_base_service_registry_add (&rloc_file, 0, NULL);
687}
Note: See TracBrowser for help on using the repository browser.