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"
39 #define HEARTBEAT_SOURCE_CHECK_EVENTS (G_IO_IN|G_IO_PRI)
40 #define HEARTBEAT_SOURCE_CHECK_REVENTS (HEARTBEAT_SOURCE_CHECK_EVENTS|G_IO_ERR|G_IO_HUP|G_IO_NVAL)
43 gboolean validate_CORBA_Environment(const CORBA_Environment *evp)
45 g_return_val_if_fail(evp->_major==CORBA_NO_EXCEPTION,FALSE);
51 static gboolean corba_init(const char *pname,CORBA_Environment *evp,CORBA_ORB *orbp,PortableServer_POA *poap)
55 (gchar *)captive_strdup_alloca(pname),
58 g_return_val_if_fail(evp!=NULL,FALSE);
59 g_return_val_if_fail(orbp!=NULL,FALSE);
60 g_return_val_if_fail(poap!=NULL,FALSE);
63 CORBA_exception_init(evp);
66 *orbp=CORBA_ORB_init(&orb_argc,orb_argv,"orbit-local-orb",evp);
67 g_return_val_if_fail(*orbp!=CORBA_OBJECT_NIL,FALSE);
68 g_return_val_if_fail(validate_CORBA_Environment(evp),FALSE);
71 *poap=(PortableServer_POA)CORBA_ORB_resolve_initial_references(*orbp,"RootPOA",evp);
72 g_return_val_if_fail(validate_CORBA_Environment(evp),FALSE);
74 PortableServer_POAManager poa_mgr;
75 poa_mgr=PortableServer_POA__get_the_POAManager(*poap,evp);
76 g_return_val_if_fail(validate_CORBA_Environment(evp),FALSE);
77 PortableServer_POAManager_activate(poa_mgr,evp);
78 g_return_val_if_fail(validate_CORBA_Environment(evp),FALSE);
79 CORBA_Object_release((CORBA_Object)poa_mgr,evp);
80 g_return_val_if_fail(validate_CORBA_Environment(evp),FALSE);
87 static CORBA_ORB heartbeat_source_callback_orb=CORBA_OBJECT_NIL;
89 static gboolean corba_shutdown(CORBA_Environment *evp,CORBA_ORB *orbp,PortableServer_POA *poap)
91 PortableServer_POA poa;
94 g_return_val_if_fail(evp!=NULL,FALSE);
95 g_return_val_if_fail(orbp!=NULL,FALSE);
96 g_return_val_if_fail(poap!=NULL,FALSE);
100 *poap=CORBA_OBJECT_NIL;
101 CORBA_Object_release((CORBA_Object)poa,evp);
102 g_return_val_if_fail(validate_CORBA_Environment(evp),FALSE);
106 *orbp=CORBA_OBJECT_NIL;
107 heartbeat_source_callback_orb=CORBA_OBJECT_NIL;
108 CORBA_ORB_destroy(orb,evp);
109 g_return_val_if_fail(validate_CORBA_Environment(evp),FALSE);
112 CORBA_exception_free(evp);
118 static gboolean corba_servant_object_destroy(PortableServer_POA poa,CORBA_Object reference,CORBA_Environment *evp)
120 PortableServer_ObjectId *objid;
121 PortableServer_Servant servant;
123 g_return_val_if_fail(poa!=CORBA_OBJECT_NIL,FALSE);
124 g_return_val_if_fail(reference!=CORBA_OBJECT_NIL,FALSE);
125 g_return_val_if_fail(evp!=NULL,FALSE);
127 objid=PortableServer_POA_reference_to_id(poa,reference,evp);
128 g_return_val_if_fail(validate_CORBA_Environment(evp),FALSE);
129 servant=PortableServer_POA_reference_to_servant(poa,reference,evp);
130 g_return_val_if_fail(validate_CORBA_Environment(evp),FALSE);
131 PortableServer_POA_deactivate_object(poa,objid,evp);
132 g_return_val_if_fail(validate_CORBA_Environment(evp),FALSE);
134 (*((PortableServer_ServantBase *)servant)->vepv[0]->finalize)(servant,evp);
135 g_return_val_if_fail(validate_CORBA_Environment(evp),FALSE);
142 static gboolean heartbeat_source_callback(gpointer data /* unused */)
144 CORBA_Environment ev;
146 g_return_val_if_fail(heartbeat_source_callback_orb!=CORBA_OBJECT_NIL,FALSE); /* the source should be removed */
148 CORBA_exception_init(&ev);
149 /* CORBA_ORB_shutdown() is not enough as 'init_level' still >0 */
151 heartbeat_source_callback_orb, /* orb */
153 g_assert(validate_CORBA_Environment(&ev));
154 CORBA_exception_free(&ev);
156 return FALSE; /* the source should be removed */
160 static void sandbox_child(int VFS_IOR_fd_write,GSource *gsource) G_GNUC_NORETURN;
161 static void sandbox_child(int VFS_IOR_fd_write,GSource *gsource)
163 CORBA_Environment ev;
165 PortableServer_POA poa;
166 Captive_VFS VFS_object;
171 errbool=corba_init("sandbox_child",&ev,&orb,&poa);
172 g_assert(errbool==TRUE);
173 heartbeat_source_callback_orb=orb;
175 /* linc_main_get_loop() makes sense only after corba_init() -> CORBA_ORB_init() */
176 errguint=g_source_attach(
177 gsource, /* source */
178 g_main_loop_get_context(linc_main_get_loop())); /* context; NULL means 'default context' */
179 g_assert(errguint!=0);
181 /* Init 'VFS_object' */
182 VFS_object=impl_Captive_VFS__create(poa,&ev);
183 g_assert(validate_CORBA_Environment(&ev));
185 /* pass IOR to our parent */
188 VFS_IOR=CORBA_ORB_object_to_string(orb,VFS_object,&ev);
189 g_assert(validate_CORBA_Environment(&ev));
190 g_assert(VFS_IOR!=NULL);
191 errint=write(VFS_IOR_fd_write,VFS_IOR,strlen(VFS_IOR)+1);
192 g_assert((unsigned)errint==strlen(VFS_IOR)+1);
193 errint=close(VFS_IOR_fd_write);
198 /* CORBA_ORB_run() -> linc_main_loop_run() -> g_main_loop_run()
199 * and therefore we should be safe with glib events handling.
201 CORBA_ORB_run(orb,&ev);
202 g_assert(validate_CORBA_Environment(&ev));
204 /* Shutdown 'VFS' servant */
205 errbool=corba_servant_object_destroy(poa,VFS_object,&ev);
206 g_assert(errbool==TRUE);
208 errbool=corba_shutdown(&ev,&orb,&poa);
209 g_assert(errbool==TRUE);
214 static void sandbox_parent(int VFS_IOR_fd_read)
216 CORBA_Environment ev;
218 PortableServer_POA poa;
222 Captive_Directory directory_object;
223 Captive_VFS VFS_object;
224 Captive_GlibLogFunc GlibLogFunc_object;
227 errbool=corba_init("sandbox_parent",&ev,&orb,&poa);
228 g_return_if_fail(errbool==TRUE);
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(orb,VFS_IOR,&ev);
238 g_assert(validate_CORBA_Environment(&ev));
241 /* Init 'GlibLogFunc_object' */
242 GlibLogFunc_object=impl_Captive_GlibLogFunc__create(poa,&ev);
243 g_assert(validate_CORBA_Environment(&ev));
244 Captive_VFS_registerGlibLogFunc(VFS_object,GlibLogFunc_object,&ev);
245 g_assert(validate_CORBA_Environment(&ev));
247 directory_object=Captive_VFS_openDirectory(VFS_object,"/directory",&ev);
248 g_assert(validate_CORBA_Environment(&ev));
251 /* Shutdown 'GlibLogFunc' servant */
252 errbool=corba_servant_object_destroy(poa,GlibLogFunc_object,&ev);
253 g_assert(errbool==TRUE);
255 CORBA_Object_release(VFS_object,&ev);
256 g_assert(validate_CORBA_Environment(&ev));
258 errbool=corba_shutdown(&ev,&orb,&poa);
259 g_assert(errbool==TRUE);
262 static gboolean heartbeat_source_prepare(GSource *source,gint *timeout)
269 static GPollFD heartbeat_source_check_gpollfd;
271 static gboolean heartbeat_source_check(GSource *source)
273 return !!(heartbeat_source_check_gpollfd.revents & HEARTBEAT_SOURCE_CHECK_REVENTS);
276 static gboolean heartbeat_source_dispatch(GSource *source,GSourceFunc callback,gpointer user_data)
278 g_assert(callback!=NULL);
279 return (*callback)(user_data);
282 static GSourceFuncs heartbeat_source_watch_funcs={
283 heartbeat_source_prepare,
284 heartbeat_source_check,
285 heartbeat_source_dispatch,
290 void captive_sandbox_init(void)
292 /* VFS_IOR_fds[0] for reading by sandbox_parent() - client,
293 * VFS_IOR_fds[1] for writing by sandbox_child() - server
295 int VFS_IOR_fds[2],parentheart_fds[2];
298 errint=pipe(VFS_IOR_fds);
300 errint=pipe(parentheart_fds);
304 g_assert_not_reached();
306 case 0: { /* child */
309 errint=close(VFS_IOR_fds[0]); /* close VFS_IOR_fd_read */
311 errint=close(parentheart_fds[1]); /* close parentheart_fd_write */
314 /* attach heartbeat_source_callback() to watch for any abnormalities
315 * on our open pipe 'parentheart_fds' and terminate the child if parent dies.
317 gsource=g_source_new(&heartbeat_source_watch_funcs,sizeof(GSource));
318 g_assert(gsource!=NULL);
319 g_source_set_callback(
320 gsource, /* source */
321 heartbeat_source_callback, /* func */
324 heartbeat_source_check_gpollfd.fd=parentheart_fds[0]; /* parentheart_fd_read */
325 heartbeat_source_check_gpollfd.events=HEARTBEAT_SOURCE_CHECK_EVENTS;
326 heartbeat_source_check_gpollfd.revents=0;
327 g_source_add_poll(gsource,&heartbeat_source_check_gpollfd);
328 sandbox_child(VFS_IOR_fds[1],gsource); /* pass VFS_IOR_fd_write */
331 default: /* parent */
332 errint=close(VFS_IOR_fds[1]); /* close VFS_IOR_fd_write */
334 errint=close(parentheart_fds[0]); /* close parentheart_fd_read */
336 errint=fcntl(parentheart_fds[1],F_SETFD,FD_CLOEXEC);
337 /* This fcntl(2) may not be enough - some fork(2) may duplicate this
338 * write descriptor and even if we do some process finish the child
339 * may remain alone connected with some unknown fork(2)er from us.
340 * Currently I am not aware such case would occur.
343 sandbox_parent(VFS_IOR_fds[0]); /* pass VFS_IOR_fd_read, it will be closed there */
346 /* 'parentheart_fds[1]' - parentheart_fd_write - is left open here */