2 * Connection of captive-vfs interface through CORBA/ORBit
3 * Copyright (C) 2002 Jan Kratochvil <project-captive@jankratochvil.net>
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; exactly version 2 of June 1991 is required
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
14 * You should have received a copy of the GNU General Public License
15 * along with this program; if not, write to the Free Software
16 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
22 #include "split.h" /* self */
24 #include "server-GlibLogFunc.h"
25 #include "captive/macros.h"
26 #include <glib/gmacros.h>
28 #include "captive/rtl-file.h"
31 #include <linc/linc.h> /* for linc_main_get_loop() */
32 #include "server-GlibLogFunc.h"
33 #include "server-Directory.h"
34 #include "server-Vfs.h"
35 #include "../client/vfs.h"
40 #define HEARTBEAT_SOURCE_CHECK_EVENTS (G_IO_IN|G_IO_PRI)
41 #define HEARTBEAT_SOURCE_CHECK_REVENTS (HEARTBEAT_SOURCE_CHECK_EVENTS|G_IO_ERR|G_IO_HUP|G_IO_NVAL)
44 gboolean validate_CORBA_Environment(const CORBA_Environment *evp)
46 g_return_val_if_fail(evp->_major==CORBA_NO_EXCEPTION,FALSE);
51 CORBA_Environment captive_corba_ev;
52 CORBA_ORB captive_corba_orb;
53 PortableServer_POA captive_corba_poa;
55 static void corba_shutdown_atexit(void);
57 static gboolean corba_init(const char *pname,CORBA_Environment *evp,CORBA_ORB *orbp,PortableServer_POA *poap)
59 static gboolean done=FALSE;
62 (gchar *)captive_strdup_alloca(pname),
65 g_return_val_if_fail(evp!=NULL,FALSE);
66 g_return_val_if_fail(orbp!=NULL,FALSE);
67 g_return_val_if_fail(poap!=NULL,FALSE);
73 CORBA_exception_init(evp);
76 *orbp=CORBA_ORB_init(&orb_argc,orb_argv,"orbit-local-orb",evp);
77 g_return_val_if_fail(*orbp!=CORBA_OBJECT_NIL,FALSE);
78 g_return_val_if_fail(validate_CORBA_Environment(evp),FALSE);
81 *poap=(PortableServer_POA)CORBA_ORB_resolve_initial_references(*orbp,"RootPOA",evp);
82 g_return_val_if_fail(validate_CORBA_Environment(evp),FALSE);
84 PortableServer_POAManager poa_mgr;
85 poa_mgr=PortableServer_POA__get_the_POAManager(*poap,evp);
86 g_return_val_if_fail(validate_CORBA_Environment(evp),FALSE);
87 PortableServer_POAManager_activate(poa_mgr,evp);
88 g_return_val_if_fail(validate_CORBA_Environment(evp),FALSE);
89 CORBA_Object_release((CORBA_Object)poa_mgr,evp);
90 g_return_val_if_fail(validate_CORBA_Environment(evp),FALSE);
93 g_atexit(corba_shutdown_atexit);
100 static CORBA_ORB heartbeat_source_callback_orb=CORBA_OBJECT_NIL;
102 gboolean corba_shutdown(CORBA_Environment *evp,CORBA_ORB *orbp,PortableServer_POA *poap)
104 PortableServer_POA poa;
107 g_return_val_if_fail(evp!=NULL,FALSE);
108 g_return_val_if_fail(orbp!=NULL,FALSE);
109 g_return_val_if_fail(poap!=NULL,FALSE);
113 *poap=CORBA_OBJECT_NIL;
114 CORBA_Object_release((CORBA_Object)poa,evp);
115 g_return_val_if_fail(validate_CORBA_Environment(evp),FALSE);
119 *orbp=CORBA_OBJECT_NIL;
120 heartbeat_source_callback_orb=CORBA_OBJECT_NIL;
121 CORBA_ORB_destroy(orb,evp);
122 g_return_val_if_fail(validate_CORBA_Environment(evp),FALSE);
125 CORBA_exception_free(evp);
130 static void corba_shutdown_atexit(void)
134 errbool=corba_shutdown(&captive_corba_ev,&captive_corba_orb,&captive_corba_poa);
135 g_assert(errbool==TRUE);
139 void sandbox_child_shutdown(void)
141 /* Do not fail by passing logging messages to the master. */
142 impl_Captive_Vfs_registerGlibLogFunc_disable();
144 g_main_loop_quit(linc_main_get_loop());
148 static gboolean heartbeat_source_callback(gpointer data /* unused */)
150 g_return_val_if_fail(heartbeat_source_callback_orb!=CORBA_OBJECT_NIL,FALSE); /* the source should be removed */
152 sandbox_child_shutdown();
154 return FALSE; /* the source should be removed */
158 static void sandbox_child(int Vfs_IOR_fd_write,GSource *gsource,CaptiveVfsObject *child_captive_vfs_object) G_GNUC_NORETURN;
159 static void sandbox_child(int Vfs_IOR_fd_write,GSource *gsource,CaptiveVfsObject *child_captive_vfs_object)
161 Captive_Vfs Vfs_object;
166 errint=close(0); /* STDIN */
168 errint=close(1); /* STDOUT */
170 errint=close(2); /* STDERR */
173 g_assert(captive_corba_child_options==NULL);
174 captive_corba_child_options=&child_captive_vfs_object->options;
176 heartbeat_source_callback_orb=captive_corba_orb;
178 /* linc_main_get_loop() makes sense only after corba_init() -> CORBA_ORB_init() */
179 errguint=g_source_attach(
180 gsource, /* source */
181 g_main_loop_get_context(linc_main_get_loop())); /* context; NULL means 'default context' */
182 g_assert(errguint!=0);
184 /* Init 'Vfs_object' */
185 Vfs_object=impl_Captive_Vfs__create(captive_corba_poa,&captive_corba_ev);
186 g_assert(validate_CORBA_Environment(&captive_corba_ev));
188 /* pass IOR to our parent */
191 Vfs_IOR=CORBA_ORB_object_to_string(captive_corba_orb,Vfs_object,&captive_corba_ev);
192 g_assert(validate_CORBA_Environment(&captive_corba_ev));
193 g_assert(Vfs_IOR!=NULL);
194 errint=write(Vfs_IOR_fd_write,Vfs_IOR,strlen(Vfs_IOR)+1);
195 g_assert((unsigned)errint==strlen(Vfs_IOR)+1);
196 errint=close(Vfs_IOR_fd_write);
201 /* CORBA_ORB_run() -> linc_main_loop_run() -> g_main_loop_run()
202 * and therefore we should be safe with glib events handling.
204 CORBA_ORB_run(captive_corba_orb,&captive_corba_ev);
205 g_assert(validate_CORBA_Environment(&captive_corba_ev));
207 /* Shutdown 'Vfs' servant */
208 CORBA_Object_release(Vfs_object,&captive_corba_ev);
209 g_assert(validate_CORBA_Environment(&captive_corba_ev));
211 errbool=corba_shutdown(&captive_corba_ev,&captive_corba_orb,&captive_corba_poa);
212 g_assert(errbool==TRUE);
217 static void sandbox_parent
218 (int Vfs_IOR_fd_read,Captive_Vfs *corba_Vfs_object_return,Captive_GlibLogFunc *corba_GlibLogFunc_object_return)
222 Captive_Vfs Vfs_object;
223 Captive_GlibLogFunc GlibLogFunc_object;
226 g_return_if_fail(Vfs_IOR_fd_read!=-1);
227 g_return_if_fail(corba_Vfs_object_return!=NULL);
228 g_return_if_fail(corba_GlibLogFunc_object_return!=NULL);
230 Vfs_IOR=captive_rtl_file_read(Vfs_IOR_fd_read,&Vfs_IOR_size);
231 g_assert(Vfs_IOR!=NULL);
232 g_assert(Vfs_IOR_size>=1);
233 g_assert(memchr(Vfs_IOR,0,Vfs_IOR_size)==Vfs_IOR+(Vfs_IOR_size-1)); /* check exactly for 0-terminated string */
234 errint=close(Vfs_IOR_fd_read);
237 Vfs_object=CORBA_ORB_string_to_object(captive_corba_orb,Vfs_IOR,&captive_corba_ev);
238 g_assert(validate_CORBA_Environment(&captive_corba_ev));
241 /* Init 'GlibLogFunc_object' */
242 GlibLogFunc_object=impl_Captive_GlibLogFunc__create(captive_corba_poa,&captive_corba_ev);
243 g_assert(validate_CORBA_Environment(&captive_corba_ev));
244 Captive_Vfs_registerGlibLogFunc(Vfs_object,GlibLogFunc_object,&captive_corba_ev);
245 g_assert(validate_CORBA_Environment(&captive_corba_ev));
247 *corba_Vfs_object_return=Vfs_object;
248 *corba_GlibLogFunc_object_return=GlibLogFunc_object;
251 static gboolean heartbeat_source_prepare(GSource *source,gint *timeout)
258 static GPollFD heartbeat_source_check_gpollfd;
260 static gboolean heartbeat_source_check(GSource *source)
262 return !!(heartbeat_source_check_gpollfd.revents & HEARTBEAT_SOURCE_CHECK_REVENTS);
265 static gboolean heartbeat_source_dispatch(GSource *source,GSourceFunc callback,gpointer user_data)
267 g_assert(callback!=NULL);
268 return (*callback)(user_data);
271 static GSourceFuncs heartbeat_source_watch_funcs={
272 heartbeat_source_prepare,
273 heartbeat_source_check,
274 heartbeat_source_dispatch,
279 gboolean captive_sandbox_spawn(CaptiveVfsObject *child_captive_vfs_object,
280 Captive_Vfs *corba_Vfs_object_return,Captive_GlibLogFunc *corba_GlibLogFunc_object_return,int *parentheart_fds_1_return)
282 /* Vfs_IOR_fds[0] for reading by sandbox_parent() - client,
283 * Vfs_IOR_fds[1] for writing by sandbox_child() - server
285 int Vfs_IOR_fds[2],parentheart_fds[2];
289 g_return_val_if_fail(child_captive_vfs_object!=NULL,FALSE);
290 g_return_val_if_fail(corba_Vfs_object_return!=NULL,FALSE);
291 g_return_val_if_fail(corba_GlibLogFunc_object_return!=NULL,FALSE);
292 g_return_val_if_fail(parentheart_fds_1_return!=NULL,FALSE);
294 errint=pipe(Vfs_IOR_fds);
295 g_return_val_if_fail(errint==0,FALSE);
296 errint=pipe(parentheart_fds);
297 g_return_val_if_fail(errint==0,FALSE);
299 /* We cannot initialize 'parent' and 'child' name specifically as
300 * we need to have persistence master and its children will be already
301 * CORBA-initialized during their spawn.
303 errbool=corba_init("captive-sandbox",&captive_corba_ev,&captive_corba_orb,&captive_corba_poa);
304 g_return_val_if_fail(errbool==TRUE,FALSE);
306 /* Currently never called anywhere:
307 * errbool=corba_shutdown(&captive_corba_ev,&captive_corba_orb,&captive_corba_poa);
308 * g_assert(errbool==TRUE);
313 g_return_val_if_reached(FALSE);
315 case 0: { /* child */
318 errint=close(Vfs_IOR_fds[0]); /* close Vfs_IOR_fd_read */
319 g_return_val_if_fail(errint==0,FALSE);
320 errint=close(parentheart_fds[1]); /* close parentheart_fd_write */
321 g_return_val_if_fail(errint==0,FALSE);
323 /* attach heartbeat_source_callback() to watch for any abnormalities
324 * on our open pipe 'parentheart_fds' and terminate the child if parent dies.
326 gsource=g_source_new(&heartbeat_source_watch_funcs,sizeof(GSource));
327 g_return_val_if_fail(gsource!=NULL,FALSE);
328 g_source_set_callback(
329 gsource, /* source */
330 heartbeat_source_callback, /* func */
333 heartbeat_source_check_gpollfd.fd=parentheart_fds[0]; /* parentheart_fd_read */
334 heartbeat_source_check_gpollfd.events=HEARTBEAT_SOURCE_CHECK_EVENTS;
335 heartbeat_source_check_gpollfd.revents=0;
336 g_source_add_poll(gsource,&heartbeat_source_check_gpollfd);
337 sandbox_child(Vfs_IOR_fds[1],gsource,child_captive_vfs_object); /* pass Vfs_IOR_fd_write */
338 g_return_val_if_reached(FALSE);
341 default: /* parent */
342 errint=close(Vfs_IOR_fds[1]); /* close Vfs_IOR_fd_write */
343 g_return_val_if_fail(errint==0,FALSE);
344 errint=close(parentheart_fds[0]); /* close parentheart_fd_read */
345 g_return_val_if_fail(errint==0,FALSE);
346 errint=fcntl(parentheart_fds[1],F_SETFD,FD_CLOEXEC);
347 /* This fcntl(2) may not be enough - some fork(2) may duplicate this
348 * write descriptor and even if we do some process finish the child
349 * may remain alone connected with some unknown fork(2)er from us.
350 * Currently I am not aware such case would occur.
352 g_return_val_if_fail(errint==0,FALSE);
353 *parentheart_fds_1_return=parentheart_fds[1];
355 Vfs_IOR_fds[0], /* Vfs_IOR_fd_read */
356 corba_Vfs_object_return, /* corba_Vfs_object_return */
357 corba_GlibLogFunc_object_return); /* corba_GlibLogFunc_object_return */
358 /* 'parentheart_fds[1]' - parentheart_fd_write - is left open here */
362 g_return_val_if_reached(FALSE);
366 GnomeVFSResult captive_sandbox_parent_return_from_CORBA_Environment(CORBA_Environment *evp)
370 if (evp->_major==CORBA_NO_EXCEPTION)
373 if (!strcmp(ex_Captive_GnomeVFSResultException,CORBA_exception_id(evp)))
374 r=((Captive_GnomeVFSResultException *)CORBA_exception_value(evp))->gnome_vfs_result;
376 r=GNOME_VFS_ERROR_GENERIC;
377 g_warning(_("CORBA Exception occured: id=\"%s\", value=%p"),
378 CORBA_exception_id(evp),CORBA_exception_value(evp));
380 CORBA_exception_free(evp);
386 void captive_sandbox_child_GnomeVFSResultException_throw(CORBA_Environment *evp,GnomeVFSResult errvfsresult)
388 Captive_GnomeVFSResultException *gnome_vfs_result_exception;
390 g_return_if_fail(evp!=NULL);
392 gnome_vfs_result_exception=Captive_GnomeVFSResultException__alloc();
393 gnome_vfs_result_exception->gnome_vfs_result=errvfsresult;
394 CORBA_exception_set(evp,CORBA_USER_EXCEPTION,ex_Captive_GnomeVFSResultException,gnome_vfs_result_exception);