[Mono-list] [PATCH] robust mono-handle-d?

Dennis Haney davh@davh.dk
06 Jun 2002 22:42:38 +0200


--=-=-=

>>>>> "Miguel" == Miguel de Icaza <miguel@ximian.com> writes:

>> > I am not sure we will run into the malicious case (I have not
>> taken a > look at how it works, so it is hard for me to tell), but
>> in general, I > think that doing things more robustly is important.
>> 
>> There should be a separate daemon per user, which is why I'm less
>> bothered about DOS attempts.

Miguel> Thanks for the explanation Dick.

This is primarily a documentation patch, but it also adds a single
error check (assert if unref is called with refcnt==0) and many
g_warning with a exit(-1) right after was changed to g_critical. The
states a daemon was running in was replaced by an enum to make it more
clean what is what.

-- 
Dennis
use Inline C => qq{void p(char*g){
printf("Just Another %s Hacker\n",g);}};p("Perl");

--=-=-=
Content-Disposition: attachment; filename=mono_handle_d_diff1.diff

--- /dev/null	Thu Jan  1 01:00:00 1970
+++ docs/.cvsignore	Sun Jun  2 00:00:05 2002
@@ -0,0 +1 @@
+Makefile Makefile.in
--- /dev/null	Thu Jan  1 01:00:00 1970
+++ docs/mono_handle_d	Thu Jun  6 21:46:26 2002
@@ -0,0 +1,79 @@
+=pod
+
+=head1 Internal design document for the mono_handle_d
+
+This document is designed to hold the design of the mono_handle_d and
+not as an api reference.
+
+=head2 Primary goal and purpose
+
+The mono_handle_d is a process which takes care of the (de)allocation
+of scratch shared memory and filehandles and refcounts of the
+filehandles. It is designed to be run by a user and to be fast, thus
+minimal error checking on input is done and will most likely crash if
+given a faulty package. No effort has been, or should be, made to have
+the daemon talking to machine of different endianness/size of int.
+
+=head2 How to start the deamon
+
+To start the daemon you either run the mono_handle_d executable or try
+to attach to the shared memory segment via L<_wapi_shm_attach> which
+will start a deamon if one does not exist.
+
+=head1 Internal details
+
+The daemon works by opening a socket and listening to clients. These
+clients send packages over the socket complying to L<struct
+WapiHandleRequest>.
+
+=head2 Possible requests
+
+=over
+
+=item WapiHandleRequest_New
+
+Find a handle in the shared memory segment that is free and allocate
+it to the specified type. To destroy use
+L</WapiHandleRequest_Close>. A L<WapiHandleResponse> with
+.type=WapiHandleResponseType_New will be sent back with .u.new.handle
+set to the handle that was allocated. .u.new.type is the type that was
+requested.
+
+=item WapiHandleRequestType_Open
+
+Increase the ref count of an already created handle. A
+L<WapiHandleResponse> with .type=WapiHandleResponseType_Open will be sent
+back with .u.new.handle set to the handle, .u.new.type is set to the
+type of handle this is.
+
+=item WapiHandleRequestType_Close
+
+Decrease the ref count of an already created handle. A
+L<WapiHandleResponse> with .type=WapiHandleResponseType_Close will be
+sent back with .u.close.destroy set to TRUE if ref count for this
+client reached 0.
+
+=item WapiHandleRequestType_Scratch
+
+Allocate a shared memory area of size .u.scratch.length in bytes. A
+L<WapiHandleResponse> with .type=WapiHandleResponseType_Scratch will be
+sent back with .u.scratch.idx set to the index into the shared
+memory's scratch area where to memory begins. (works just like
+malloc(3))
+
+=item WapiHandleRequestType_Scratch
+
+Deallocate a shared memory area, this must have been allocated before
+deallocating. A L<WapiHandleResponse> with
+.type=WapiHandleResponseType_Scratch Freewill be sent back (works just
+like free(3))
+
+=back
+
+=head1 Authors
+
+Documentaion: Dennis Haney
+
+Implementation: Dick Porter
+
+=cut
Index: daemon-messages.c
===================================================================
RCS file: /mono/mono/mono/io-layer/daemon-messages.c,v
retrieving revision 1.3
diff -u -b -B -r1.3 daemon-messages.c
--- daemon-messages.c	31 May 2002 09:54:14 -0000	1.3
+++ daemon-messages.c	6 Jun 2002 20:42:41 -0000
@@ -25,7 +25,7 @@
 
 /* Send request on fd, wait for response (called by applications, not
  * the daemon)
-*/
+ */
 void _wapi_daemon_request_response (int fd, WapiHandleRequest *req,
 				    WapiHandleResponse *resp)
 {
@@ -41,7 +41,7 @@
 	ret=send (fd, req, sizeof(WapiHandleRequest), MSG_NOSIGNAL);
 	if(ret!=sizeof(WapiHandleRequest)) {
 		if(errno==EPIPE) {
-			g_warning (G_GNUC_PRETTY_FUNCTION ": The handle daemon vanished!");
+			g_critical (G_GNUC_PRETTY_FUNCTION ": The handle daemon vanished!");
 			exit (-1);
 		} else {
 			g_warning (G_GNUC_PRETTY_FUNCTION ": Send error: %s",
@@ -53,7 +53,7 @@
 	ret=recv (fd, resp, sizeof(WapiHandleResponse), MSG_NOSIGNAL);
 	if(ret==-1) {
 		if(errno==EPIPE) {
-			g_warning (G_GNUC_PRETTY_FUNCTION ": The handle daemon vanished!");
+			g_critical (G_GNUC_PRETTY_FUNCTION ": The handle daemon vanished!");
 			exit (-1);
 		} else {
 			g_warning (G_GNUC_PRETTY_FUNCTION ": Send error: %s",
@@ -71,7 +71,11 @@
 	int ret;
 	
 	ret=recv (fd, req, sizeof(WapiHandleRequest), MSG_NOSIGNAL);
+	//we cant check ret != sizeof(WapiHandleRequest) because its a
+	//union
 	if(ret==-1) {
+		//make sure we dont do anything with this response
+		req->type=WapiHandleRequestType_Error;
 #ifdef DEBUG
 		g_warning (G_GNUC_PRETTY_FUNCTION ": Recv error: %s",
 			   strerror (errno));
@@ -86,11 +90,11 @@
 	int ret;
 	
 	ret=send (fd, resp, sizeof(WapiHandleResponse), MSG_NOSIGNAL);
-	if(ret==-1) {
 #ifdef DEBUG
+	if(ret==-1 || ret != sizeof(WapiHandleResponse)) {
 		g_warning (G_GNUC_PRETTY_FUNCTION ": Send error: %s",
 			   strerror (errno));
-#endif
 		/* The next loop around poll() should tidy up */
 	}
+#endif
 }
Index: daemon-messages.h
===================================================================
RCS file: /mono/mono/mono/io-layer/daemon-messages.h,v
retrieving revision 1.2
diff -u -b -B -r1.2 daemon-messages.h
--- daemon-messages.h	9 May 2002 13:10:18 -0000	1.2
+++ daemon-messages.h	6 Jun 2002 20:42:41 -0000
@@ -18,6 +18,7 @@
 	WapiHandleRequestType_Close,
 	WapiHandleRequestType_Scratch,
 	WapiHandleRequestType_ScratchFree,
+	WapiHandleRequestType_Error,
 } WapiHandleRequestType;
 
 typedef struct 
Index: daemon.c
===================================================================
RCS file: /mono/mono/mono/io-layer/daemon.c,v
retrieving revision 1.4
diff -u -b -B -r1.4 daemon.c
--- daemon.c	31 May 2002 10:41:30 -0000	1.4
+++ daemon.c	6 Jun 2002 20:42:41 -0000
@@ -27,9 +27,13 @@
 
 #undef DEBUG
 
+// Array to hold the filehandles we are currently polling
 static struct pollfd *pollfds=NULL;
+// Keep track of the size and usage of pollfds
 static int nfds=0, maxfds=0;
-static gpointer *handle_refs=NULL;
+// Array to keep track of arrays of handles that belong to a given client
+static guint32 **handle_refs=NULL;
+// The sockey which we listen to new connections on
 static int main_sock;
 
 /* Deletes the shared memory segment.  If we're exiting on error,
@@ -40,12 +44,23 @@
 	_wapi_shm_destroy ();
 }
 
+/*
+ * signal_handler:
+ * @unused: unused
+ *
+ * Called if deamon receives a SIGTERM or SIGINT
+ */
 static void signal_handler (int unused)
 {
 	cleanup ();
 	exit (-1);
 }
 
+/*
+ * startup:
+ *
+ * Bind signals and attach to shared memory
+ */
 static void startup (void)
 {
 	struct sigaction sa;
@@ -76,6 +91,15 @@
 		  time (NULL));
 }
 
+
+/*
+ * ref_handle:
+ * @idx: idx into pollfds
+ * @handle: handle to inc refcnt
+ *
+ * Increase ref count of handle for idx's filehandle and the
+ * shm. Handle 0 is ignored.
+ */
 static void ref_handle (guint32 idx, guint32 handle)
 {
 	guint32 *open_handles=handle_refs[idx];
@@ -95,6 +119,15 @@
 #endif
 }
 
+/*
+ * unref_handle:
+ * @idx: idx into pollfds
+ * @handle: handle to inc refcnt
+ *
+ * Decrease ref count of handle for idx's filehandle and the shm. If
+ * global ref count reaches 0 it is free'ed. Return TRUE if the local
+ * ref count is 0. Handle 0 is ignored.
+ */
 static gboolean unref_handle (guint32 idx, guint32 handle)
 {
 	guint32 *open_handles=handle_refs[idx];
@@ -104,6 +137,8 @@
 		return(FALSE);
 	}
 	
+	g_assert(open_handles[handle] != 0);
+
 	_wapi_shared_data->handles[handle].ref--;
 	open_handles[handle]--;
 	
@@ -120,9 +155,7 @@
 	}
 	
 	if(_wapi_shared_data->handles[handle].ref==0) {
-		if (open_handles[handle]!=0) {
-			g_warning (G_GNUC_PRETTY_FUNCTION ": per-process open_handles mismatch, set to %d, should be 0", open_handles[handle]);
-		}
+	        g_assert(open_handles[handle] == 0);
 		
 #ifdef DEBUG
 		g_message (G_GNUC_PRETTY_FUNCTION ": Destroying handle 0x%x",
@@ -140,13 +173,21 @@
 	return(destroy);
 }
 
+/*
+ * add_fd:
+ * @fd: Filehandle to add
+ *
+ * Add fd to the pollfds array, expand if necessary
+ */
 static void add_fd(int fd)
 {
 	if(nfds==maxfds) {
 		/* extend the array */
 		maxfds+=10;
+		/* no need to memset the extra memory, we init it
+		 * before use anyway */
 		pollfds=g_renew (struct pollfd, pollfds, maxfds);
-		handle_refs=g_renew (gpointer, handle_refs, maxfds);
+		handle_refs=g_renew (guint32*, handle_refs, maxfds);
 	}
 
 	pollfds[nfds].fd=fd;
@@ -158,6 +199,14 @@
 	nfds++;
 }
 
+/*
+ * rem_fd:
+ * @idx: idx into pollfds to remove
+ *
+ * Close filehandle and remove it from the pollfds array. Closes all
+ * handles that it may have open. If only main_sock is open, the deamon
+ * is shut down.
+ */
 static void rem_fd(int idx)
 {
 	guint32 *open_handles=handle_refs[idx], handle_count;
@@ -205,12 +254,28 @@
 	}
 }
 
+
+/*
+ * send_reply:
+ * @idx: idx into pollfds.
+ * @rest: Package to send
+ *
+ * Send a package to a client
+ */
 static void send_reply (guint32 idx, WapiHandleResponse *resp)
 {
 	/* send message */
 	_wapi_daemon_response (pollfds[idx].fd, resp);
 }
 
+/*
+ * process_new:
+ * @idx: idx into pollfds.
+ * @type: type to init handle to
+ *
+ * Find a free handle and initialize it to 'type', increase refcnt and
+ * send back a reply to the client.
+ */
 static void process_new (guint32 idx, WapiHandleType type)
 {
 	guint32 handle;
@@ -231,6 +296,14 @@
 	send_reply (idx, &resp);
 }
 
+/*
+ * process_open:
+ * @idx: idx into pollfds.
+ * @handle: handle no.
+ *
+ * Increase refcnt on a previously created handle and send back a
+ * response to the client.
+ */
 static void process_open (guint32 idx, guint32 handle)
 {
 	WapiHandleResponse resp;
@@ -259,6 +332,14 @@
 	send_reply (idx, &resp);
 }
 
+/*
+ * process_close:
+ * @idx: idx into pollfds.
+ * @handle: handle no.
+ *
+ * Decrease refcnt on a previously created handle and send back a
+ * response to the client with notice of it being destroyed.
+ */
 static void process_close (guint32 idx, guint32 handle)
 {
 	WapiHandleResponse resp;
@@ -273,6 +354,13 @@
 	send_reply (idx, &resp);
 }
 
+/*
+ * process_scratch:
+ * @idx: idx into pollfds.
+ * @length: allocate this much scratch space
+ *
+ * Allocate some scratch space and send a reply to the client.
+ */
 static void process_scratch (guint32 idx, guint32 length)
 {
 	WapiHandleResponse resp;
@@ -288,6 +376,13 @@
 	send_reply (idx, &resp);
 }
 
+/*
+ * process_scratch_free:
+ * @idx: idx into pollfds.
+ * @scratch_idx: deallocate this scratch space
+ *
+ * Deallocate scratch space and send a reply to the client.
+ */
 static void process_scratch_free (guint32 idx, guint32 scratch_idx)
 {
 	WapiHandleResponse resp;
@@ -303,6 +398,13 @@
 	send_reply (idx, &resp);
 }
 
+/*
+ * read_message:
+ * @idx: idx into pollfds.
+ *
+ * Read a message (A WapiHandleRequest) from a client and dispatch
+ * whatever it wants to the process_* calls.
+ */
 static void read_message (guint32 idx)
 {
 	WapiHandleRequest req;
@@ -314,9 +416,15 @@
 		process_new (idx, req.u.new.type);
 		break;
 	case WapiHandleRequestType_Open:
+#ifdef DEBUG
+		g_assert(req.u.open.handle < _WAPI_MAX_HANDLES);
+#endif
 		process_open (idx, req.u.open.handle);
 		break;
 	case WapiHandleRequestType_Close:
+#ifdef DEBUG
+		g_assert(req.u.close.handle < _WAPI_MAX_HANDLES);
+#endif
 		process_close (idx, req.u.close.handle);
 		break;
 	case WapiHandleRequestType_Scratch:
@@ -325,9 +433,19 @@
 	case WapiHandleRequestType_ScratchFree:
 		process_scratch_free (idx, req.u.scratch_free.idx);
 		break;
+	case WapiHandleRequestType_Error: /* Falltrough */
+	default:
+		/*FIXME: call rem_fd?*/
+		break;
 	}
 }
 
+/*
+ * main:
+ *
+ * Open socket, create shared mem segment and begin listening for
+ * clients.
+ */
 int main(int argc, char **argv)
 {
 	struct sockaddr_un main_socket_address;
@@ -347,8 +465,8 @@
 	ret=bind(main_sock, (struct sockaddr *)&main_socket_address,
 		 sizeof(struct sockaddr_un));
 	if(ret==-1) {
-		g_warning ("bind failed: %s", strerror (errno));
-		_wapi_shared_data->daemon_running=2;
+		g_critical ("bind failed: %s", strerror (errno));
+		_wapi_shared_data->daemon_running=DAEMON_DIED_AT_STARTUP;
 		exit(-1);
 	}
 
@@ -358,8 +476,8 @@
 
 	ret=listen(main_sock, 5);
 	if(ret==-1) {
-		g_warning ("listen failed: %s", strerror (errno));
-		_wapi_shared_data->daemon_running=2;
+		g_critical ("listen failed: %s", strerror (errno));
+		_wapi_shared_data->daemon_running=DAEMON_DIED_AT_STARTUP;
 		exit(-1);
 	}
 
@@ -373,7 +491,7 @@
 	 * ready.  From now on, it's up to us to delete the shared
 	 * memory segment when appropriate.
 	 */
-	_wapi_shared_data->daemon_running=1;
+	_wapi_shared_data->daemon_running=DAEMON_RUNNING;
 
 	while(TRUE) {
 		int i;
@@ -385,21 +503,29 @@
 		/* Block until something happens */
 		ret=poll(pollfds, nfds, -1);
 		if(ret==-1) {
-			g_message ("poll error: %s", strerror (errno));
+			g_critical ("poll error: %s", strerror (errno));
 			cleanup ();
 			exit(-1);
 		}
 
 		for(i=0; i<nfds; i++) {
-			if(((pollfds[i].revents&POLLHUP)==POLLHUP) ||
-			   ((pollfds[i].revents&POLLERR)==POLLERR) ||
-			   ((pollfds[i].revents&POLLNVAL)==POLLNVAL)) {
+			if(((pollfds[i].revents & POLLHUP)  == POLLHUP) ||
+			   ((pollfds[i].revents & POLLERR)  == POLLERR) ||
+			   ((pollfds[i].revents & POLLNVAL) == POLLNVAL)) {
 #ifdef DEBUG
 			   	g_message ("fd[%d] %d error", i,
 					   pollfds[i].fd);
 #endif
 				rem_fd(i);
 			} else if((pollfds[i].revents&POLLIN)==POLLIN) {
+				/* If a client is connecting, accept
+				 * it and begin listening to that
+				 * socket too otherwise it must be a
+				 * client we already have that wants
+				 * something
+				 */
+
+				/* FIXME: Isn't this only true for i==0??? */
 				if(pollfds[i].fd==main_sock) {
 					int newsock;
 					struct sockaddr addr;
@@ -407,7 +533,7 @@
 					newsock=accept(main_sock, &addr,
 						       &addrlen);
 					if(newsock==-1) {
-						g_message("accept error: %s",
+						g_critical("accept error: %s",
 							  strerror (errno));
 						cleanup ();
 						exit(-1);
Index: handles.c
===================================================================
RCS file: /mono/mono/mono/io-layer/handles.c,v
retrieving revision 1.12
diff -u -b -B -r1.12 handles.c
--- handles.c	31 May 2002 10:41:30 -0000	1.12
+++ handles.c	6 Jun 2002 20:42:42 -0000
@@ -136,6 +136,13 @@
 	thread_handle=_wapi_handle_new (WAPI_HANDLE_THREAD);
 }
 
+/*
+ * _wapi_handle_new_internal:
+ * @type: Init handle to this type
+ *
+ * Search for a free handle and initialize it. Return the handle on
+ * succes and 0 on failure.
+ */
 guint32 _wapi_handle_new_internal (WapiHandleType type)
 {
 	guint32 i;
@@ -150,7 +157,7 @@
 		struct _WapiHandleShared *shared=&_wapi_shared_data->handles[i];
 		
 		if(shared->type==WAPI_HANDLE_UNUSED) {
-			last=i;
+			last=i+1;
 			shared->type=type;
 			shared->signalled=FALSE;
 			mono_mutex_init (&_wapi_shared_data->handles[i].signal_mutex, &mutex_shared_attr);
@@ -350,6 +357,13 @@
 
 #define HDRSIZE sizeof(struct _WapiScratchHeader)
 
+/*
+ * _wapi_handle_scratch_store_internal:
+ * @bytes: Allocate no. bytes
+ *
+ * Like malloc(3) except its for the shared memory segment's scratch
+ * part. Memory block returned is zeroed out.
+ */
 guint32 _wapi_handle_scratch_store_internal (guint32 bytes)
 {
 	guint32 idx=0, last_idx=0;
@@ -400,6 +414,10 @@
 			g_message (G_GNUC_PRETTY_FUNCTION ": new header at %d, length %d", idx+bytes, hdr->length);
 #endif
 			
+			/*
+			 * It was memset(0..) when free/made so no need to do it here
+			 */
+
 			return(idx);
 		} else if(hdr->flags & WAPI_SHM_SCRATCH_FREE &&
 			  last_was_free == FALSE) {
@@ -516,6 +534,13 @@
 	return(str);
 }
 
+/*
+ * _wapi_handle_scratch_delete_internal:
+ * @idx: Index to free block
+ *
+ * Like free(3) except its for the shared memory segment's scratch
+ * part.
+ */
 void _wapi_handle_scratch_delete_internal (guint32 idx)
 {
 	struct _WapiScratchHeader *hdr;
Index: shared.c
===================================================================
RCS file: /mono/mono/mono/io-layer/shared.c,v
retrieving revision 1.4
diff -u -b -B -r1.4 shared.c
--- shared.c	9 May 2002 13:10:18 -0000	1.4
+++ shared.c	6 Jun 2002 20:42:42 -0000
@@ -56,6 +56,17 @@
 
 #undef DEBUG
 
+/*
+ * _wapi_shm_attach:
+ * @deamon: Is it the deamon trying to attach to the segment
+ * @success: Was it a success
+ * @shm_id: The ID of the segment created/attached to
+ *
+ * Attach to the shared memory segment or create it if it did not
+ * exist. If it was created and daemon was FALSE a new daemon is
+ * forked into existence. Returns the memory area the segment was
+ * attached to.
+ */
 gpointer _wapi_shm_attach (gboolean daemon, gboolean *success, int *shm_id)
 {
 	gpointer shm_seg;
@@ -99,7 +110,7 @@
 		 */
 	} else {
 		/* Some error other than EEXIST */
-		g_message (G_GNUC_PRETTY_FUNCTION ": shmget error: %s",
+		g_critical (G_GNUC_PRETTY_FUNCTION ": shmget error: %s",
 			   strerror (errno));
 		exit (-1);
 	}
@@ -110,7 +121,7 @@
 	 */
 	shm_seg=shmat (*shm_id, NULL, 0);
 	if(shm_seg==(gpointer)-1) {
-		g_message (G_GNUC_PRETTY_FUNCTION ": shmat error: %s",
+		g_critical (G_GNUC_PRETTY_FUNCTION ": shmat error: %s",
 			   strerror (errno));
 		if(fork_daemon==TRUE) {
 			_wapi_shm_destroy ();
@@ -131,7 +142,7 @@
 			
 		pid=fork ();
 		if(pid==-1) {
-			g_message (G_GNUC_PRETTY_FUNCTION ": fork error: %s",
+			g_critical (G_GNUC_PRETTY_FUNCTION ": fork error: %s",
 				   strerror (errno));
 			_wapi_shm_destroy ();
 			exit (-1);
@@ -140,9 +151,9 @@
 			setsid ();
 			execl (MONO_BINDIR "/mono-handle-d", "mono-handle-d",
 			       NULL);
-			g_warning (": exec of %s/mono-handle-d failed: %s",
+			g_critical (": exec of %s/mono-handle-d failed: %s",
 				   MONO_BINDIR, strerror (errno));
-			data->daemon_running=2;
+			data->daemon_running=DAEMON_DIED_AT_STARTUP;
 			exit (-1);
 		}
 		/* parent carries on */
@@ -150,8 +161,9 @@
 		/* Do some sanity checking on the shared memory we
 		 * attached
 		 */
-		if(!(data->daemon_running==0 || data->daemon_running==1 ||
-		     data->daemon_running==2) ||
+		if(!(data->daemon_running==DAEMON_STARTING || 
+		     data->daemon_running==DAEMON_RUNNING ||
+		     data->daemon_running==DAEMON_DIED_AT_STARTUP) ||
 		   (strncmp (data->daemon+1, "mono-handle-daemon-", 19)!=0)) {
 			g_warning ("Shared memory sanity check failed.");
 			*success=FALSE;
@@ -159,7 +171,7 @@
 		}
 	}
 		
-	for(tries=0; data->daemon_running==0 && tries < 100; tries++) {
+	for(tries=0; data->daemon_running==DAEMON_STARTING && tries < 100; tries++) {
 		/* wait for the daemon to sort itself out.  To be
 		 * completely safe, we should have a timeout before
 		 * giving up.
@@ -171,7 +183,7 @@
 			
 		nanosleep (&sleepytime, NULL);
 	}
-	if(tries==100 && data->daemon_running==0) {
+	if(tries==100 && data->daemon_running==DAEMON_STARTING) {
 		/* Daemon didnt get going */
 		if(fork_daemon==TRUE) {
 			_wapi_shm_destroy ();
@@ -181,7 +193,7 @@
 		return(NULL);
 	}
 	
-	if(data->daemon_running==2) {
+	if(data->daemon_running==DAEMON_DIED_AT_STARTUP) {
 		/* Oh dear, the daemon had an error starting up */
 		if(fork_daemon==TRUE) {
 			_wapi_shm_destroy ();
Index: wapi-private.h
===================================================================
RCS file: /mono/mono/mono/io-layer/wapi-private.h,v
retrieving revision 1.12
diff -u -b -B -r1.12 wapi-private.h
--- wapi-private.h	9 May 2002 13:10:19 -0000	1.12
+++ wapi-private.h	6 Jun 2002 20:42:42 -0000
@@ -95,6 +95,12 @@
 #define _WAPI_MAX_HANDLES 4096
 #define _WAPI_HANDLE_INVALID (gpointer)-1
 
+typedef enum {
+	DAEMON_STARTING = 0,
+	DAEMON_RUNNING  = 1,
+	DAEMON_DIED_AT_STARTUP = 2,
+} _wapi_deamon_status;
+
 /*
  * This is the layout of the shared memory segment
  */
@@ -104,7 +110,7 @@
 	 * header file
 	 */
 	guchar daemon[108];
-	guint32 daemon_running;
+	_wapi_deamon_status daemon_running;
 	
 #ifdef _POSIX_THREAD_PROCESS_SHARED
 	mono_mutex_t signal_mutex;

--=-=-=--