source: pkg/main/libbonobo/trunk/bonobo-activation/bonobo-activation-base-service.c @ 479

Revision 479, 19.8 KB checked in by alanbach-guest, 6 years ago (diff)

Libbonobo 2.18.0 updates

RevLine 
[310]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 "config.h"
41#include <string.h>
42#include <limits.h>
43#include <errno.h>
44#include <unistd.h>
45#include <time.h>
46#include <stdio.h>
47#include <signal.h>
48#include <sys/types.h>
49#ifdef HAVE_SYS_WAIT_H
50#include <sys/wait.h>
51#endif
52#include <stdlib.h>
53#include <fcntl.h>
54
55#ifdef G_OS_WIN32
56#include <share.h>
57#endif
58
59#include <glib/gstdio.h>
60
61/* If you have a strange unix, you get odd hard coded limits */
62#ifndef PATH_MAX
63#  define PATH_MAX 1024
64#endif
65
66static GSList *registries = NULL;
67
68typedef struct {
69        int priority;
70        const BonoboActivationBaseServiceRegistry *registry;
71        gpointer user_data;
72} RegistryInfo;
73
74typedef struct {
75        int priority;
76        BonoboActivationBaseServiceActivator activator;
77} ActivatorInfo;
78
79static gint
80ri_compare (gconstpointer a, gconstpointer b)
81{
82        RegistryInfo *ra = (RegistryInfo *) a;
83        RegistryInfo *rb = (RegistryInfo *) b;
84
85        return (rb->priority - ra->priority);
86}
87
88void
89bonobo_activation_base_service_registry_add
90                      (const BonoboActivationBaseServiceRegistry *registry,
91                       int                                        priority,
92                       gpointer                                   user_data)
93{
94        RegistryInfo *new_ri;
95
96        g_return_if_fail (registry);
97
98        new_ri = g_new (RegistryInfo, 1);
99        new_ri->priority = priority;
100        new_ri->registry = registry;
101        new_ri->user_data = user_data;
102
103        registries = g_slist_insert_sorted (registries, new_ri, ri_compare);
104}
105
106CORBA_Object
107bonobo_activation_base_service_check (const BonoboActivationBaseService *base_service,
108                                      CORBA_Environment                 *ev)
109{
110        GSList *link;
111        CORBA_Object retval = CORBA_OBJECT_NIL;
112        int dist = INT_MAX;
113        char *ior = NULL;
114
115        for (link = registries; link; link = link->next) {
116                RegistryInfo *ri;
117                char *new_ior;
118                int new_dist = dist;
119
120                ri = link->data;
121
122                if (!ri->registry->check)
123                        continue;
124
125                new_ior = ri->registry->check (ri->registry, base_service, 
126                                             &new_dist, ri->user_data);
127                if (new_ior && (new_dist < dist)) {
128                        g_free (ior);
129                        ior = new_ior;
130                } else if (new_ior) {
131                        g_free (new_ior);
132                }
133        }
134
135        if (ior) {
136                retval = CORBA_ORB_string_to_object (bonobo_activation_orb_get (), ior, ev);
137                if (ev->_major != CORBA_NO_EXCEPTION)
138                        retval = CORBA_OBJECT_NIL;
139
140                g_free (ior);
141        }
142
143        return retval;
144}
145
146/*dumb marshalling hack */
147static void
148bonobo_activation_registration_iterate (const BonoboActivationBaseService *base_service,
149                          CORBA_Object obj, CORBA_Environment *ev,
150                          gulong offset, int nargs)
151{
152        GSList *link;
153        char *ior = NULL;
154
155        if (nargs == 4)
156                ior = CORBA_ORB_object_to_string (bonobo_activation_orb_get (), obj, ev);
157
158        for (link = registries; link; link = link->next) {
159                RegistryInfo *ri;
160                void (*func_ptr) ();
161
162                ri = link->data;
163
164                func_ptr = *(gpointer *) ((guchar *) ri->registry + offset);
165
166                if (!func_ptr)
167                        continue;
168
169                switch (nargs) {
170                case 4:
171                        func_ptr (ri->registry, ior, base_service, ri->user_data);
172                        break;
173                case 2:
174                        func_ptr (ri->registry, ri->user_data);
175                        break;
176                }
177        }
178
179        if (nargs == 4)
180                CORBA_free (ior);
181}
182
183static int lock_count = 0;
184
185static void
186bonobo_activation_registries_lock (CORBA_Environment *ev)
187{
188        if (lock_count == 0)
189                bonobo_activation_registration_iterate (NULL, CORBA_OBJECT_NIL, ev,
190                                          G_STRUCT_OFFSET
191                                          (BonoboActivationBaseServiceRegistry, lock), 2);
192        lock_count++;
193}
194
195static void
196bonobo_activation_registries_unlock (CORBA_Environment *ev)
197{
198        lock_count--;
199        if (lock_count == 0)
200                bonobo_activation_registration_iterate (NULL, CORBA_OBJECT_NIL, ev,
201                                          G_STRUCT_OFFSET
202                                          (BonoboActivationBaseServiceRegistry, unlock),
203                                          2);
204}
205
206void
207bonobo_activation_base_service_unset (const BonoboActivationBaseService *base_service,
208                        CORBA_Object obj, CORBA_Environment *ev)
209{
210        bonobo_activation_registries_lock (ev);
211        bonobo_activation_registration_iterate (base_service, obj, ev,
212                                  G_STRUCT_OFFSET (BonoboActivationBaseServiceRegistry,
213                                                   unregister), 4);
214        bonobo_activation_registries_unlock (ev);
215}
216
217void
218bonobo_activation_base_service_set (const BonoboActivationBaseService *base_service,
219                      CORBA_Object obj, CORBA_Environment *ev)
220{
221        bonobo_activation_registries_lock (ev);
222        bonobo_activation_registration_iterate (base_service, obj, ev,
223                                  G_STRUCT_OFFSET (BonoboActivationBaseServiceRegistry,
224                                                   register_new), 4);
225        bonobo_activation_registries_unlock (ev);
226}
227
228struct SysServerInstance
229{
230        CORBA_Object already_running;
231        char *username, *hostname;
232};
233
234struct SysServer
235{
236        const char *name;
237        const char **cmd;
238        int fd_arg;
239        GSList *instances;
240}
241activatable_servers[] =
242{
243                                /* cmd filled in at runtime */
244        {"IDL:Bonobo/ActivationContext:1.0", NULL, 2, CORBA_OBJECT_NIL}, 
245        { NULL}
246};
247
248#define STRMATCH(x, y) ((!x && !y) || (x && y && !strcmp(x, y)))
249static CORBA_Object
250existing_check (const BonoboActivationBaseService *base_service, struct SysServer *ss)
251{
252        GSList *link;
253
254        for (link = ss->instances; link; link = link->next) {
255                struct SysServerInstance *ssi;
256
257                ssi = link->data;
258                if (
259                    (!ssi->username
260                     || STRMATCH (ssi->username, base_service->username))
261                    && (!ssi->hostname
262                        || STRMATCH (ssi->hostname, base_service->hostname)))
263                        return ssi->already_running;
264        }
265
266        return CORBA_OBJECT_NIL;
267}
268
269void
270bonobo_activation_base_service_debug_shutdown (CORBA_Environment *ev)
271{
272        int     i;
273        GSList *l, *instances;
274        struct SysServerInstance *ssi;
275
276        for (i = 0; activatable_servers[i].name; i++) {
277
278                instances = activatable_servers[i].instances;
279                activatable_servers[i].instances = NULL;
280
281                for (l = instances; l; l = l->next) {
282                        ssi = l->data;
283
284                        CORBA_Object_release (ssi->already_running, ev);
285                        g_free (ssi->username);
286                        g_free (ssi->hostname);
287                        g_free (ssi);
288                }
289                g_slist_free (instances);
290        }
291}
292
293static void
294bonobo_activation_existing_set (const BonoboActivationBaseService *base_service,
295                                struct SysServer *ss,
296                                CORBA_Object obj, CORBA_Environment *ev)
297{
298        GSList *link;
299        struct SysServerInstance *ssi;
300
301        ssi = NULL;
302
303        for (link = ss->instances; link; link = link->next) {
304                ssi = link->data;
305                if (
306                    (!ssi->username
307                     || STRMATCH (ssi->username, base_service->username))
308                    && (!ssi->hostname
309                        || STRMATCH (ssi->hostname, base_service->hostname))) break;
310        }
311
312        if (link == NULL) {
313                ssi = g_new0 (struct SysServerInstance, 1);
314                ssi->already_running = obj;
[479]315                ssi->username = g_strdup (base_service->username);
316                ssi->hostname = g_strdup (base_service->hostname);
[310]317                ss->instances = g_slist_prepend (ss->instances, ssi);
318        } else {
319                CORBA_Object_release (ssi->already_running, ev);
320                ssi->already_running = obj;
321        }
322
323        /* FIXME: all this code is unneccesarily abstract & buggy with it */
324        if (!strcmp (base_service->name, "IDL:Bonobo/ActivationContext:1.0")) {
325                bonobo_activation_register_client (obj, ev);
326        }
327}
328
329static GSList *activator_list = NULL;
330
331static gint
332ai_compare (gconstpointer a, gconstpointer b)
333{
334        const ActivatorInfo *ra, *rb;
335
336        ra = a;
337        rb = b;
338
339        return (rb->priority - ra->priority);
340}
341
342void
343bonobo_activation_base_service_activator_add (BonoboActivationBaseServiceActivator activator, 
344                                              int priority)
345{
346        ActivatorInfo *new_act;
347
348        new_act = g_new (ActivatorInfo, 1);
349        new_act->priority = priority;
350        new_act->activator = activator;
351        activator_list =
352                g_slist_insert_sorted (activator_list, new_act, ai_compare);
353}
354
355static CORBA_Object
356bonobo_activation_activators_use (const BonoboActivationBaseService *base_service, const char **cmd,
357                                  int fd_arg, CORBA_Environment *ev)
358{
359        CORBA_Object retval = CORBA_OBJECT_NIL;
360        GSList *link;
361
362        for (link = activator_list; CORBA_Object_is_nil (retval, ev) && link;
363             link = link->next) {
364                ActivatorInfo *actinfo;
365                actinfo = link->data;
366
367                retval = actinfo->activator (base_service, cmd, fd_arg, ev);
368        }
369
370        return retval;
371}
372
373CORBA_Object
374bonobo_activation_internal_service_get_extended (
375        const BonoboActivationBaseService *base_service,
376        gboolean              existing_only,
377        CORBA_Environment    *ev)
378{
379        CORBA_Object retval = CORBA_OBJECT_NIL;
380        int i;
381        CORBA_Environment myev, important_error_ev;
382        gboolean ne;
383
384        g_return_val_if_fail (base_service, CORBA_OBJECT_NIL);
385
386        BONOBO_ACTIVATION_LOCK ();
387
388        for (i = 0; activatable_servers[i].name; i++) {
389                if (!strcmp (base_service->name, activatable_servers[i].name))
390                        break;
391        }
392
393        if (!activatable_servers[i].name) {
394                BONOBO_ACTIVATION_UNLOCK ();
395                return retval;
396        }
397
398        CORBA_exception_init (&myev);
399        CORBA_exception_init (&important_error_ev);
400       
401        retval = existing_check (base_service, &activatable_servers[i]);
402        if (!CORBA_Object_non_existent (retval, ev))
403                goto out;
404
405        bonobo_activation_registries_lock (ev);
406
407        retval = bonobo_activation_base_service_check (base_service, &myev);
408        ne = CORBA_Object_non_existent (retval, &myev);
409        if (ne && !existing_only) {
410                CORBA_Object race_condition;
411
412                CORBA_Object_release (retval, &myev);
413               
414                retval =
415                        bonobo_activation_activators_use (base_service,
416                                            activatable_servers[i].cmd,
417                                            activatable_servers[i].fd_arg,
418                                            &important_error_ev);
419
420                race_condition = bonobo_activation_base_service_check (base_service, &myev);
421
422                if (!CORBA_Object_non_existent (race_condition, &myev)) {
423                        CORBA_Object_release (retval, &myev);
424                        retval = race_condition;
425                } else if (!CORBA_Object_is_nil (retval, &myev)) {
426                        bonobo_activation_base_service_set (base_service, retval, &myev);
427                        CORBA_Object_release (race_condition, &myev);
428                }
429        }
430
431        bonobo_activation_registries_unlock (ev);
432
433        if (!CORBA_Object_non_existent (retval, ev))
434                bonobo_activation_existing_set (base_service, &activatable_servers[i], retval, ev);
435
436      out:
437        /* If we overwrote ev with some stupid junk, replace
438         * it with the real error
439         */
440        if (important_error_ev._major != CORBA_NO_EXCEPTION) {
441                CORBA_exception_free (ev);
442                /* This transfers memory ownership */
443                *ev = important_error_ev;
444        }
445       
446        CORBA_exception_free (&myev);
447
448        BONOBO_ACTIVATION_UNLOCK ();
449
450        return retval;
451}
452
453CORBA_Object
454bonobo_activation_service_get (const BonoboActivationBaseService *base_service)
455{
456        CORBA_Environment ev;
457        CORBA_Object obj;
458       
459        CORBA_exception_init (&ev);
460       
461        obj = bonobo_activation_internal_service_get_extended (
462                base_service, FALSE, &ev);
463
464#ifdef G_ENABLE_DEBUG
465        if (ev._major != CORBA_NO_EXCEPTION) {
466                if (!strcmp (ev._id, "IDL:Bonobo/GeneralError:1.0")) {
467                        Bonobo_GeneralError *err = ev._any._value;
468               
469                        if (!err || !err->description)
470                                g_warning ("General error with no description");
471                        else
472                                g_warning ("Exception '%s' on activate", err->description);
473                } else
474                        g_warning ("Exception on activate\n");
475        }
476#endif
477
478        CORBA_exception_free (&ev);
479
480        return obj;
481}
482
483/*****Implementation of the IOR registration system via plain files ******/
484static int lock_fd = -1;
485
486static const char *
487get_tmpdir (void)
488{
489        static const char *tmpdir = NULL;
490
491        if (!tmpdir)
492                tmpdir = ORBit_get_safe_tmp ();
493
494        if (!tmpdir)
495                g_error ("No secure tmpdir found");
496
497        return tmpdir;
498}
499
500static char *
501get_lock_fname (void)
502{
503        return g_build_filename (get_tmpdir (),
504                                 "bonobo-activation-register.lock",
505                                 NULL);
506}
507
508static char *
509get_ior_fname (void)
510{
511        return g_build_filename (get_tmpdir (),
512                                 "bonobo-activation-server-ior",
513                                 NULL);
514}
515
516static void
517wait_for_lock (void)
518{
519#ifdef HAVE_USLEEP
520        usleep (10000);
521
522#elif defined(HAVE_NANOSLEEP)
523        struct timespec timewait;
524        timewait.tv_sec = 0;
525        timewait.tv_nsec = 1000000;
526        nanosleep (&timewait, NULL);
527
528#else
529#warning You might have bad performance without usleep
530        g_usleep (10000);
531#endif
532        access ("bonobo-activation lock wait", 0);
533}
534
535static void
536rloc_file_lock (const BonoboActivationBaseServiceRegistry *registry, 
537                gpointer                                   user_data)
538{
539#if defined (F_SETFD) && defined (FD_CLOEXEC) && defined (F_SETLKW)
540        char *fn;
541        struct flock lock;
542        int retval;
543        char *err;
544
545        fn = get_lock_fname ();
546
547        while ((lock_fd = open (fn, O_CREAT | O_RDWR, 0700)) < 0) {
548
549                if (errno == EEXIST)
550                        wait_for_lock ();
551
552                else {
553                        g_message ("%s locking '%s'", g_strerror (errno), fn);
554                        break;
555                }
556        }
557
558        fcntl (lock_fd, F_SETFD, FD_CLOEXEC);
559
560        if (lock_fd >= 0) {
561                lock.l_type = F_WRLCK;
562                lock.l_whence = SEEK_SET;
563                lock.l_start = 0;
564                lock.l_len = 1;
565                lock.l_pid = getpid ();
566
567                while ((retval = fcntl (lock_fd, F_SETLKW, &lock)) < 0
568                       && errno == EINTR) /**/;
569
570                if (retval < 0) {
571                        /* FIXME: need to report this error in a better way. */
572                        err = strerror (errno);
573                        g_warning ("Failed to acquire lock: %s\n.", err);
574                }
575        }
576
577        g_free (fn);
578#elif defined (G_OS_WIN32)
579        char *fn = get_lock_fname ();
580        wchar_t *wfn = g_utf8_to_utf16 (fn, -1, NULL, NULL, NULL);
581       
582        while ((lock_fd = _wsopen (wfn, O_CREAT|O_RDWR|_O_SHORT_LIVED|_O_NOINHERIT, _SH_DENYRW, 0700)) < 0) {
583                if (errno == EACCES) {
584                        wait_for_lock ();
585                } else {
586                        g_message ("%s locking '%s'", g_strerror (errno), fn);
587                        break;
588                }
589        }
590        g_free (wfn);
591        g_free (fn);
592#else
593        g_warning ("No locking implemented\n");
594#endif
595}
596
597static void
598rloc_file_unlock (const BonoboActivationBaseServiceRegistry *registry, 
599                  gpointer                                   user_data)
600{
601#if defined (F_SETFD) && defined (FD_CLOEXEC) && defined (F_SETLKW)
602        struct flock lock;
603
604        if (lock_fd >= 0) {
605
606                lock.l_type = F_UNLCK;
607                lock.l_whence = SEEK_SET;
608                lock.l_start = 0;
609                lock.l_len = 1;
610                lock.l_pid = getpid ();
611
612                fcntl (lock_fd, F_SETLKW, &lock);
613                close (lock_fd);
614                lock_fd = -1;
615        }
616#elif defined (G_OS_WIN32)
617        if (lock_fd >= 0) {
618                close (lock_fd);
619                lock_fd = -1;
620        }
621#endif
622}
623
624static char *
625rloc_file_check (const BonoboActivationBaseServiceRegistry *registry,
626                 const BonoboActivationBaseService *base_service, int *ret_distance,
627                 gpointer user_data)
628{
629        FILE *fh;
630        char *fn;
631
632        fn = get_ior_fname ();
633        fh = g_fopen (fn, "r");
634        g_free (fn);
635
636        if (fh != NULL) {
637                char iorbuf[8192];
638
639                iorbuf[0] = '\0';
640                while (fgets (iorbuf, sizeof (iorbuf), fh)
641                       && strncmp (iorbuf, "IOR:", 4))
642                        /**/;
643                g_strstrip (iorbuf);
644
645                fclose (fh);
646
647                if (!strncmp (iorbuf, "IOR:", 4)) {
648                        *ret_distance = 0;
649                        return g_strdup (iorbuf);
650                }
651        }
652
653        return NULL;
654}
655
656static void
657rloc_file_register (const BonoboActivationBaseServiceRegistry *registry, const char *ior,
658                    const BonoboActivationBaseService *base_service,
659                    gpointer user_data)
660{
661        char *fn;
662        FILE *fh;
663
664        fn = get_ior_fname ();
665        fh = g_fopen (fn, "w");
666
667        if (fh != NULL) {
668                fprintf (fh, "%s\n", ior);
669                fclose (fh);
670        }       
671
672        g_free (fn);
673}
674
675static void
676rloc_file_unregister (const BonoboActivationBaseServiceRegistry *registry, 
677                      const char                                *ior,
678                      const BonoboActivationBaseService         *base_service,
679                      gpointer                                   user_data)
680{
681        char *fn;
682
683        g_unlink ((fn = get_ior_fname ()));
684        g_free (fn);
685}
686
687static const BonoboActivationBaseServiceRegistry rloc_file = {
688        rloc_file_lock,
689        rloc_file_unlock,
690        rloc_file_check,
691        rloc_file_register,
692        rloc_file_unregister
693};
694
695static CORBA_Object
696local_re_check_fn (const Bonobo_ActivationEnvironment *environment,
697                   const char                         *act_iid,
698                   gpointer                            user_data)
699{
700        CORBA_Environment ev;
701        CORBA_Object result;
702
703        CORBA_exception_init (&ev);
704        result = bonobo_activation_internal_service_get_extended
705                (user_data, TRUE, &ev);
706        CORBA_exception_free (&ev);
707
708        return result;
709}
710
711static CORBA_Object
712local_activator (const BonoboActivationBaseService *base_service,
713                 const char **cmd,
714                 int fd_arg, 
715                 CORBA_Environment *ev)
716{
717        if (
718            (!base_service->username
719             || STRMATCH (base_service->username, g_get_user_name ()))
720            && (!base_service->hostname
721                || STRMATCH (base_service->hostname, bonobo_activation_hostname_get ()))) {
722
723                return bonobo_activation_server_by_forking (
724                        cmd, FALSE, fd_arg, NULL, NULL, base_service->name,
725                        TRUE, local_re_check_fn, (gpointer)base_service, ev);
726        }
727
728        return CORBA_OBJECT_NIL;
729}
730
731void
732bonobo_activation_base_service_init (void)
733{
734        const char *override_cmd;
735#ifndef G_OS_WIN32
736        static const char *bonobo_activation_ac_cmd[] =
737                { SERVER_LIBEXECDIR "/bonobo-activation-server",
738                  "--ac-activate", "--ior-output-fd=%d", NULL };
739#else
740        static const char *bonobo_activation_ac_cmd[] =
741                { NULL,
742                  "--ac-activate", "--ior-output-fd=%d", NULL };
743        static gboolean beenhere = FALSE;
744
745        if (!beenhere) {
746                bonobo_activation_ac_cmd[0] =
747                        g_build_filename (_bonobo_activation_win32_get_server_libexecdir (),
748                                          "bonobo-activation-server",
749                                          NULL);
750                beenhere = TRUE;
751        }
752#endif
753
754        bonobo_activation_base_service_activator_add (local_activator, 0);
755
756        bonobo_activation_base_service_registry_add (&rloc_file, 0, NULL);
757
758        if ((override_cmd = g_getenv ("BONOBO_ACTIVATION_SERVER")) &&
759            (override_cmd[0] != '\0'))
760                bonobo_activation_ac_cmd [0] = override_cmd;
761
762        activatable_servers[0].cmd = bonobo_activation_ac_cmd;
763}
Note: See TracBrowser for help on using the repository browser.