updated browser capabilities file
[mono.git] / mono / io-layer / daemon.c
1 /*
2  * daemon.c:  The handle daemon
3  *
4  * Author:
5  *      Dick Porter (dick@ximian.com)
6  *
7  * (C) 2002 Ximian, Inc.
8  */
9
10 #include <config.h>
11 #include <glib.h>
12
13 #include <stdio.h>
14 #include <sys/types.h>
15 #include <sys/socket.h>
16 #include <sys/un.h>
17 #include <stdlib.h>
18 #include <unistd.h>
19 #include <errno.h>
20 #include <signal.h>
21 #include <sys/wait.h>
22 #include <string.h>
23 #include <sys/time.h>
24
25 #ifdef HAVE_POLL
26 #include <sys/poll.h>
27 #endif
28
29 #include <mono/io-layer/io-layer.h>
30 #include <mono/io-layer/handles-private.h>
31 #include <mono/io-layer/wapi-private.h>
32 #include <mono/io-layer/daemon-messages.h>
33 #include <mono/io-layer/timefuncs-private.h>
34 #include <mono/io-layer/daemon-private.h>
35
36 #undef DEBUG
37
38 /* The shared thread codepath doesn't seem to work yet... */
39 #undef _POSIX_THREAD_PROCESS_SHARED
40
41 /* Keep track of the number of clients */
42 static int nfds=0;
43
44 /* Arrays to keep track of channel data for the 
45  * daemon and clients indexed by file descriptor
46  * value.
47  */
48
49 typedef struct _channel_data {
50         int io_source; /* the ID given back by g_io_add_watch */
51         guint32 *open_handles; /* array of open handles for this client */
52 } ChannelData;
53
54 static ChannelData *daemon_channel_data=NULL;
55 static ChannelData *channels=NULL;
56 static int channels_length=0;
57
58 /* The socket which we listen to new connections on */
59 static int main_sock;
60
61 /* Set to TRUE by the SIGCHLD signal handler */
62 static volatile gboolean check_processes=FALSE;
63
64 static gboolean fd_activity (GIOChannel *channel, GIOCondition condition,
65                              gpointer data);
66
67
68 /* Deletes the shared memory segment.  If we're exiting on error,
69  * clients will get EPIPEs.
70  */
71 static void cleanup (void)
72 {
73         int i;
74         
75 #ifdef NEED_LINK_UNLINK
76         unlink(_wapi_shared_data[0]->daemon);
77 #endif 
78         for(i=1; i<_wapi_shared_data[0]->num_segments; i++) {
79                 unlink (_wapi_shm_file (WAPI_SHM_DATA, i));
80         }
81         unlink (_wapi_shm_file (WAPI_SHM_DATA, 0));
82         
83         /* There's only one scratch file */
84         unlink (_wapi_shm_file (WAPI_SHM_SCRATCH, 0));
85 }
86
87 /* If there is only one socket, and no child processes, we can exit.
88  * We test for child processes by counting handle references held by
89  * the daemon.
90  */
91 static void maybe_exit (void)
92 {
93         guint32 i;
94
95 #ifdef DEBUG
96         g_message (G_GNUC_PRETTY_FUNCTION ": Seeing if we should exit");
97 #endif
98
99         if(nfds>1) {
100 #ifdef DEBUG
101                 g_message (G_GNUC_PRETTY_FUNCTION ": Still got clients");
102 #endif
103                 return;
104         }
105
106         /* Prevent new clients from connecting... */
107         _wapi_shared_data[0]->daemon_running=DAEMON_CLOSING;
108
109         for(i=0;
110             i<_wapi_shared_data[0]->num_segments * _WAPI_HANDLES_PER_SEGMENT;
111             i++) {
112                 if(daemon_channel_data->open_handles[i]>0) {
113 #ifdef DEBUG
114                         g_message (G_GNUC_PRETTY_FUNCTION
115                                    ": Still got handle references");
116 #endif
117
118                         _wapi_shared_data[0]->daemon_running=DAEMON_RUNNING;
119                         return;
120                 }
121         }
122         
123 #ifdef HAVE_POLL
124         /* Last check, make sure no client came along while we were
125          * checking the handle lists.
126          *
127          * Use poll() directly here, as glib doesn't seem to have any
128          * exposed way of seeing if a file descriptor is ready
129          * (g_io_channel_get_buffer_condition() isn't it.)
130          *
131          * Crappy systems that don't have poll() will just have to
132          * lump it (for them there is still the very slight chance
133          * that someone tried to connect just as the DAEMON_CLOSING
134          * flag was being set.)
135          */
136         {
137                 struct pollfd fds[1];
138                 
139                 fds[0].fd=main_sock;
140                 fds[0].events=POLLIN;
141                 fds[0].revents=0;
142                 
143 #ifdef DEBUG
144                 g_message (G_GNUC_PRETTY_FUNCTION ": Last connect check");
145 #endif
146
147                 if(poll (fds, 1, 0)>0) {
148                         /* Someone did connect, so carry on running */
149 #ifdef DEBUG
150                         g_message (G_GNUC_PRETTY_FUNCTION
151                                    ": Someone connected");
152 #endif
153
154                         _wapi_shared_data[0]->daemon_running=DAEMON_RUNNING;
155                         return;
156                 }
157         }
158 #endif
159         
160 #ifdef DEBUG
161         g_message (G_GNUC_PRETTY_FUNCTION ": Byebye");
162 #endif
163         
164         cleanup ();
165         exit (0);
166 }
167
168 /*
169  * signal_handler:
170  * @unused: unused
171  *
172  * Called if daemon receives a SIGTERM or SIGINT
173  */
174 static void signal_handler (int signo)
175 {
176 #ifdef DEBUG
177         g_message (G_GNUC_PRETTY_FUNCTION ": daemon received signal %d", signo);
178 #endif
179         cleanup ();
180         exit (-1);
181 }
182
183 /*
184  * sigchld_handler:
185  * @unused: unused
186  *
187  * Called if daemon receives a SIGCHLD, and notes that a process needs
188  * to be wait()ed for.
189  */
190 static void sigchld_handler (int unused)
191 {
192         /* Notice that a child process died */
193         check_processes=TRUE;
194 }
195
196 /*
197  * startup:
198  *
199  * Bind signals and attach to shared memory
200  */
201 static void startup (void)
202 {
203         struct sigaction sa;
204         
205         sa.sa_handler=signal_handler;
206         sigemptyset (&sa.sa_mask);
207         sa.sa_flags=0;
208         sigaction (SIGINT, &sa, NULL);
209         sigaction (SIGTERM, &sa, NULL);
210         
211 #ifndef HAVE_MSG_NOSIGNAL
212         sa.sa_handler=SIG_IGN;
213         sigaction (SIGPIPE, &sa, NULL);
214 #endif
215
216         sa.sa_handler=sigchld_handler;
217         sa.sa_flags=SA_NOCLDSTOP;
218         sigaction (SIGCHLD, &sa, NULL);
219         
220 #ifdef NEED_LINK_UNLINK
221         /* Here's a more portable method... */
222         snprintf (_wapi_shared_data[0]->daemon, MONO_SIZEOF_SUNPATH-1,
223                   "/tmp/mono-handle-daemon-%d-%ld-%ld", getuid (), random (),
224                   time (NULL));
225 #else
226         /* Leave the first byte NULL so we create the socket in the
227          * abstrace namespace, not on the filesystem.  (Lets see how
228          * portable _that_ is :)
229          *
230          * The name is intended to be unique, not cryptographically
231          * secure...
232          */
233         snprintf (_wapi_shared_data[0]->daemon+1, MONO_SIZEOF_SUNPATH-2,
234                   "mono-handle-daemon-%d-%d-%ld", getuid (), getpid (),
235                   time (NULL));
236 #endif
237 }
238
239
240 /*
241  * ref_handle:
242  * @channel_data: Channel data for calling client
243  * @handle: handle to inc refcnt
244  *
245  * Increase ref count of handle for the calling client.  Handle 0 is
246  * ignored.
247  */
248 static void ref_handle (ChannelData *channel_data, guint32 handle)
249 {
250         guint32 segment, idx;
251         
252         if(handle==0) {
253                 return;
254         }
255         
256         _wapi_handle_segment (GUINT_TO_POINTER (handle), &segment, &idx);
257         
258         _wapi_shared_data[segment]->handles[idx].ref++;
259         channel_data->open_handles[handle]++;
260         
261 #ifdef DEBUG
262         g_message (G_GNUC_PRETTY_FUNCTION
263                    ": handle 0x%x ref now %d (%d this process)", handle,
264                    _wapi_shared_data[segment]->handles[idx].ref,
265                    channel_data->open_handles[handle]);
266 #endif
267 }
268
269 /*
270  * unref_handle:
271  * @channel_data: Channel data for calling client
272  * @handle: handle to inc refcnt
273  *
274  * Decrease ref count of handle for the calling client. If global ref
275  * count reaches 0 it is free'ed. Return TRUE if the local ref count
276  * is 0. Handle 0 is ignored.
277  */
278 static gboolean unref_handle (ChannelData *channel_data, guint32 handle)
279 {
280         gboolean destroy=FALSE;
281         guint32 segment, idx;
282         
283         if(handle==0) {
284                 return(FALSE);
285         }
286         
287         if (channel_data->open_handles[handle] == 0) {
288                 g_warning(G_GNUC_PRETTY_FUNCTION
289                           ": unref on %d called when ref was already 0", 
290                           handle);
291                 return TRUE;
292         }
293
294         _wapi_handle_segment (GUINT_TO_POINTER (handle), &segment, &idx);
295         
296         _wapi_shared_data[segment]->handles[idx].ref--;
297         channel_data->open_handles[handle]--;
298         
299 #ifdef DEBUG
300         g_message (G_GNUC_PRETTY_FUNCTION
301                    ": handle 0x%x ref now %d (%d this process)", handle,
302                    _wapi_shared_data[segment]->handles[idx].ref,
303                    channel_data->open_handles[handle]);
304 #endif
305
306         if(channel_data->open_handles[handle]==0) {
307                 /* This client has released the handle */
308                 destroy=TRUE;
309         }
310         
311         if(_wapi_shared_data[segment]->handles[idx].ref==0) {
312                 if (channel_data->open_handles[handle]!=0) {
313                         g_warning (G_GNUC_PRETTY_FUNCTION ": per-process open_handles mismatch, set to %d, should be 0", 
314                                         channel_data->open_handles[handle]);
315                 }
316                 
317 #ifdef DEBUG
318                 g_message (G_GNUC_PRETTY_FUNCTION ": Destroying handle 0x%x",
319                            handle);
320 #endif
321                 
322                 _wapi_handle_ops_close_shared (GUINT_TO_POINTER (handle));
323                 
324 #if defined(_POSIX_THREAD_PROCESS_SHARED) && _POSIX_THREAD_PROCESS_SHARED != -1
325                 mono_mutex_destroy (&_wapi_shared_data[segment]->handles[idx].signal_mutex);
326                 pthread_cond_destroy (&_wapi_shared_data[segment]->handles[idx].signal_cond);
327 #endif
328
329                 memset (&_wapi_shared_data[segment]->handles[idx].u, '\0', sizeof(_wapi_shared_data[segment]->handles[idx].u));
330                 _wapi_shared_data[segment]->handles[idx].type=WAPI_HANDLE_UNUSED;
331         }
332
333         if(channel_data == daemon_channel_data) {
334                 /* The daemon released a reference, so see if it's
335                  * ready to exit
336                  */
337                 maybe_exit ();
338         }
339         
340         return(destroy);
341 }
342
343 /*
344  * add_fd:
345  * @fd: Filehandle to add
346  *
347  * Create a new GIOChannel, and add it to the main loop event sources.
348  */
349 static void add_fd(int fd)
350 {
351         GIOChannel *io_channel;
352         guint32 *refs;
353         
354         io_channel=g_io_channel_unix_new (fd);
355         
356         /* Turn off all encoding and buffering crap */
357         g_io_channel_set_encoding (io_channel, NULL, NULL);
358         g_io_channel_set_buffered (io_channel, FALSE);
359         
360         refs=g_new0 (guint32,_wapi_shared_data[0]->num_segments * _WAPI_HANDLES_PER_SEGMENT);
361
362         if(fd>=channels_length) {
363                 /* Add a bit of padding, so we dont resize for _every_
364                  * new connection
365                  */
366                 int old_len=channels_length * sizeof(ChannelData);
367                 
368                 channels_length=fd+10;
369                 if(channels==NULL) {
370                         channels=g_new0 (ChannelData, channels_length);
371                         /* We rely on the daemon channel being created first.
372                          * That's safe, because every other channel is the
373                          * result of an accept() on the daemon channel.
374                          */
375                         daemon_channel_data = &channels[fd];
376                 } else {
377                         int daemon_index=daemon_channel_data - channels;
378
379                         /* Can't use g_renew here, because the unused
380                          * elements must be NULL and g_renew doesn't
381                          * initialise the memory it returns
382                          */
383                         channels=_wapi_g_renew0 (channels, old_len, channels_length * sizeof(ChannelData));
384                         daemon_channel_data = channels + daemon_index;
385                 }
386
387         }
388
389         channels[fd].open_handles=refs;
390         channels[fd].io_source=g_io_add_watch (io_channel, G_IO_IN|G_IO_ERR|G_IO_HUP|G_IO_NVAL,
391                                         fd_activity, NULL);
392
393         nfds++;
394 }
395
396 /*
397  * rem_fd:
398  * @channel: GIOChannel to close
399  *
400  * Closes the IO channel. Closes all handles that it may have open. If
401  * only main_sock is left, the daemon is shut down.
402  */
403 static void rem_fd(GIOChannel *channel, ChannelData *channel_data)
404 {
405         guint32 handle_count;
406         int i, j, fd;
407         
408         fd=g_io_channel_unix_get_fd (channel);
409         
410         if(fd == main_sock) {
411                 /* We shouldn't be deleting the daemon's fd */
412                 g_warning (G_GNUC_PRETTY_FUNCTION ": Deleting daemon fd!");
413                 cleanup ();
414                 exit (-1);
415         }
416         
417 #ifdef DEBUG
418         g_message (G_GNUC_PRETTY_FUNCTION ": Removing client fd %d", fd);
419 #endif
420
421         g_io_channel_shutdown (channel, TRUE, NULL);
422         g_source_remove (channel_data->io_source);
423         g_io_channel_unref (channel);
424
425         for(i=0;
426             i<_wapi_shared_data[0]->num_segments * _WAPI_HANDLES_PER_SEGMENT;
427             i++) {
428                 handle_count=channel_data->open_handles[i];
429                 
430                 for(j=0; j<handle_count; j++) {
431 #ifdef DEBUG
432                         g_message (G_GNUC_PRETTY_FUNCTION ": closing handle 0x%x for client at index %d", i, g_io_channel_unix_get_fd (channel));
433 #endif
434                         /* Ignore the hint to the client to destroy
435                          * the handle private data
436                          */
437                         unref_handle (channel_data, i);
438                 }
439         }
440         
441         g_free (channel_data->open_handles);
442         channel_data->open_handles=NULL;
443         channel_data->io_source=0;
444         
445         nfds--;
446         if(nfds==1) {
447                 /* Just the master socket left, so see if we can
448                  * cleanup and exit
449                  */
450                 maybe_exit ();
451         }
452 }
453
454 static gboolean process_compare (gpointer handle, gpointer user_data)
455 {
456         struct _WapiHandle_process *process_handle;
457         gboolean ok;
458         pid_t pid;
459         guint32 segment, idx;
460         
461         ok=_wapi_lookup_handle (handle, WAPI_HANDLE_PROCESS,
462                                 (gpointer *)&process_handle, NULL);
463         if(ok==FALSE) {
464                 g_warning (G_GNUC_PRETTY_FUNCTION
465                            ": error looking up process handle %p", handle);
466                 return(FALSE);
467         }
468
469         _wapi_handle_segment (handle, &segment, &idx);
470         if (_wapi_shared_data[segment]->handles[idx].signalled) {
471                 return(FALSE);
472         }
473
474         pid=GPOINTER_TO_UINT (user_data);
475         if(process_handle->id==pid) {
476                 return(TRUE);
477         } else {
478                 return(FALSE);
479         }
480 }
481
482 static gboolean process_thread_compare (gpointer handle, gpointer user_data)
483 {
484         struct _WapiHandle_thread *thread_handle;
485         gboolean ok;
486         guint32 segment, idx;
487         
488         ok=_wapi_lookup_handle (handle, WAPI_HANDLE_THREAD,
489                                 (gpointer *)&thread_handle, NULL);
490         if(ok==FALSE) {
491                 g_warning (G_GNUC_PRETTY_FUNCTION
492                            ": error looking up thread handle %p", handle);
493                 return(FALSE);
494         }
495
496         if(thread_handle->process_handle==user_data) {
497                 /* Signal the handle.  Don't use
498                  * _wapi_handle_set_signal_state() unless we have
499                  * process-shared pthread support.
500                  */
501 #ifdef DEBUG
502                 g_message (G_GNUC_PRETTY_FUNCTION ": Set thread handle %p signalled, because its process died", handle);
503 #endif
504
505                 thread_handle->exitstatus=0;
506
507 #if defined(_POSIX_THREAD_PROCESS_SHARED) && _POSIX_THREAD_PROCESS_SHARED != -1
508                 _wapi_handle_lock_handle (handle);
509                 _wapi_handle_set_signal_state (handle, TRUE, TRUE);
510                 _wapi_handle_unlock_handle (handle);
511 #else
512                 /* Just tweak the signal state directly.  This is not
513                  * recommended behaviour, but it works for threads
514                  * because they can never become unsignalled.  There
515                  * are some nasty kludges in the handle waiting code
516                  * to cope with missing condition signals for when
517                  * process-shared pthread support is missing.
518                  */
519                 _wapi_handle_segment (handle, &segment, &idx);
520                 _wapi_shared_data[segment]->handles[idx].signalled=TRUE;
521 #endif /* _POSIX_THREAD_PROCESS_SHARED */
522         }
523         
524         /* Return false to keep searching */
525         return(FALSE);
526 }
527
528 /* Find the handle associated with pid, mark it dead and record exit
529  * status.  Finds all thread handles associated with this process
530  * handle, and marks those signalled too, with exitstatus '0'.  It
531  * also drops the daemon's reference to the handle, and the thread
532  * pointed at by main_thread.
533  */
534 static void process_post_mortem (pid_t pid, int status)
535 {
536         gpointer process_handle;
537         struct _WapiHandle_process *process_handle_data;
538         guint32 segment, idx;
539         
540         process_handle=_wapi_search_handle (WAPI_HANDLE_PROCESS,
541                                             process_compare,
542                                             GUINT_TO_POINTER (pid),
543                                             (gpointer *)&process_handle_data,
544                                             NULL);
545         if(process_handle==0) {
546                 g_warning (G_GNUC_PRETTY_FUNCTION
547                            ": Couldn't find handle for process %d!", pid);
548         } else {
549                 /* Signal the handle.  Don't use
550                  * _wapi_handle_set_signal_state() unless we have
551                  * process-shared pthread support.
552                  */
553                 struct timeval tv;
554                 
555 #ifdef DEBUG
556                 g_message (G_GNUC_PRETTY_FUNCTION
557                            ": Set process %d exitstatus to %d", pid,
558                            WEXITSTATUS (status));
559 #endif
560                 
561                 /* Technically WEXITSTATUS is only valid if the
562                  * process exited normally, but I don't care if the
563                  * process caught a signal or not.
564                  */
565                 process_handle_data->exitstatus=WEXITSTATUS (status);
566
567                 /* Ignore errors */
568                 gettimeofday (&tv, NULL);
569                 _wapi_timeval_to_filetime (&tv,
570                                            &process_handle_data->exit_time);
571
572 #if defined(_POSIX_THREAD_PROCESS_SHARED) && _POSIX_THREAD_PROCESS_SHARED != -1
573                 _wapi_handle_lock_handle (process_handle);
574                 _wapi_handle_set_signal_state (process_handle, TRUE, TRUE);
575                 _wapi_handle_unlock_handle (process_handle);
576 #else
577                 /* Just tweak the signal state directly.  This is not
578                  * recommended behaviour, but it works for processes
579                  * because they can never become unsignalled.  There
580                  * are some nasty kludges in the handle waiting code
581                  * to cope with missing condition signals for when
582                  * process-shared pthread support is missing.
583                  */
584                 _wapi_handle_segment (process_handle, &segment, &idx);
585                 _wapi_shared_data[segment]->handles[idx].signalled=TRUE;
586 #endif /* _POSIX_THREAD_PROCESS_SHARED */
587         }
588
589         /* Find all threads that have their process
590          * handle==process_handle.  Ignore the return value, all the
591          * work will be done in the compare func
592          */
593         (void)_wapi_search_handle (WAPI_HANDLE_THREAD, process_thread_compare,
594                                    process_handle, NULL, NULL);
595
596         unref_handle (daemon_channel_data,
597                       GPOINTER_TO_UINT (process_handle_data->main_thread));
598         unref_handle (daemon_channel_data, GPOINTER_TO_UINT (process_handle));
599 }
600
601 static void process_died (void)
602 {
603         int status;
604         pid_t pid;
605         
606         check_processes=FALSE;
607
608 #ifdef DEBUG
609         g_message (G_GNUC_PRETTY_FUNCTION ": Reaping processes");
610 #endif
611
612         while(TRUE) {
613                 pid=waitpid (-1, &status, WNOHANG);
614                 if(pid==0 || pid==-1) {
615                         /* Finished waiting.  I was checking pid==-1
616                          * separately but was getting ECHILD when
617                          * there were no more child processes (which
618                          * doesnt seem to conform to the man page)
619                          */
620                         return;
621                 } else {
622                         /* pid contains the ID of a dead process */
623 #ifdef DEBUG
624                         g_message (G_GNUC_PRETTY_FUNCTION ": process %d reaped", pid);
625 #endif
626                         process_post_mortem (pid, status);
627                 }
628         }
629 }
630
631
632 /*
633  * send_reply:
634  * @channel: channel to send reply to
635  * @resp: Package to send
636  *
637  * Send a package to a client
638  */
639 static void send_reply (GIOChannel *channel, WapiHandleResponse *resp)
640 {
641         /* send message */
642         _wapi_daemon_response (g_io_channel_unix_get_fd (channel), resp);
643 }
644
645 /*
646  * process_new:
647  * @channel: The client making the request
648  * @channel_data: Our data for this channel
649  * @type: type to init handle to
650  *
651  * Find a free handle and initialize it to 'type', increase refcnt and
652  * send back a reply to the client.
653  */
654 static void process_new (GIOChannel *channel, ChannelData *channel_data,
655                          WapiHandleType type)
656 {
657         guint32 handle;
658         WapiHandleResponse resp={0};
659         
660         handle=_wapi_handle_new_internal (type);
661         if(handle==0) {
662                 /* Try and allocate a new shared segment, and have
663                  * another go
664                  */
665                 guint32 segment=_wapi_shared_data[0]->num_segments;
666                 int i;
667                 
668                 _wapi_handle_ensure_mapped (segment);
669                 if(_wapi_shared_data[segment]!=NULL) {
670                         /* Got a new segment */
671                         gulong old_len, new_len;
672                         
673                         old_len=_wapi_shared_data[0]->num_segments * _WAPI_HANDLES_PER_SEGMENT * sizeof(guint32);
674                         _wapi_shared_data[0]->num_segments++;
675                         new_len=_wapi_shared_data[0]->num_segments * _WAPI_HANDLES_PER_SEGMENT * sizeof(guint32);
676
677                         /* Need to expand all the handle reference
678                          * count arrays
679                          */
680
681                         for(i=0; i<channels_length; i++) {
682                                 if(channels[i].open_handles!=NULL) {
683                                         channels[i].open_handles=_wapi_g_renew0 (channels[i].open_handles, old_len, new_len);
684                                 }
685                         }
686
687                         handle=_wapi_handle_new_internal (type);
688                 } else {
689                         /* Map failed.  Just return 0 meaning "out of
690                          * handles"
691                          */
692                 }
693         }
694         
695         /* handle might still be set to 0.  This is handled at the
696          * client end
697          */
698
699         ref_handle (channel_data, handle);
700
701 #ifdef DEBUG
702         g_message (G_GNUC_PRETTY_FUNCTION ": returning new handle 0x%x",
703                    handle);
704 #endif
705
706         resp.type=WapiHandleResponseType_New;
707         resp.u.new.type=type;
708         resp.u.new.handle=handle;
709                         
710         send_reply (channel, &resp);
711 }
712
713 /*
714  * process_open:
715  * @channel: The client making the request
716  * @channel_data: Our data for this channel
717  * @handle: handle no.
718  *
719  * Increase refcnt on a previously created handle and send back a
720  * response to the client.
721  */
722 static void process_open (GIOChannel *channel, ChannelData *channel_data,
723                           guint32 handle)
724 {
725         WapiHandleResponse resp={0};
726         guint32 segment, idx;
727         struct _WapiHandleShared *shared;
728
729         _wapi_handle_segment (GUINT_TO_POINTER (handle), &segment, &idx);
730         shared=&_wapi_shared_data[segment]->handles[idx];
731                 
732         if(shared->type!=WAPI_HANDLE_UNUSED && handle!=0) {
733                 ref_handle (channel_data, handle);
734
735 #ifdef DEBUG
736                 g_message (G_GNUC_PRETTY_FUNCTION
737                            ": returning new handle 0x%x", handle);
738 #endif
739
740                 resp.type=WapiHandleResponseType_Open;
741                 resp.u.new.type=shared->type;
742                 resp.u.new.handle=handle;
743                         
744                 send_reply (channel, &resp);
745
746                 return;
747         }
748
749         resp.type=WapiHandleResponseType_Open;
750         resp.u.new.handle=0;
751                         
752         send_reply (channel, &resp);
753 }
754
755 /*
756  * process_close:
757  * @channel: The client making the request
758  * @channel_data: Our data for this channel
759  * @handle: handle no.
760  *
761  * Decrease refcnt on a previously created handle and send back a
762  * response to the client with notice of it being destroyed.
763  */
764 static void process_close (GIOChannel *channel, ChannelData *channel_data,
765                            guint32 handle)
766 {
767         WapiHandleResponse resp={0};
768         
769         resp.type=WapiHandleResponseType_Close;
770         resp.u.close.destroy=unref_handle (channel_data, handle);
771
772 #ifdef DEBUG
773         g_message (G_GNUC_PRETTY_FUNCTION ": unreffing handle 0x%x", handle);
774 #endif
775                         
776         send_reply (channel, &resp);
777 }
778
779 /*
780  * process_scratch:
781  * @channel: The client making the request
782  * @length: allocate this much scratch space
783  *
784  * Allocate some scratch space and send a reply to the client.
785  */
786 static void process_scratch (GIOChannel *channel, guint32 length)
787 {
788         WapiHandleResponse resp={0};
789         
790         resp.type=WapiHandleResponseType_Scratch;
791         resp.u.scratch.idx=_wapi_handle_scratch_store_internal (length, &resp.u.scratch.remap);
792 #ifdef DEBUG
793         g_message (G_GNUC_PRETTY_FUNCTION ": allocating scratch index 0x%x",
794                    resp.u.scratch.idx);
795 #endif
796                         
797         send_reply (channel, &resp);
798 }
799
800 /*
801  * process_scratch_free:
802  * @channel: The client making the request
803  * @scratch_idx: deallocate this scratch space
804  *
805  * Deallocate scratch space and send a reply to the client.
806  */
807 static void process_scratch_free (GIOChannel *channel, guint32 scratch_idx)
808 {
809         WapiHandleResponse resp={0};
810         
811         resp.type=WapiHandleResponseType_ScratchFree;
812         _wapi_handle_scratch_delete_internal (scratch_idx);
813
814 #ifdef DEBUG
815         g_message (G_GNUC_PRETTY_FUNCTION ": deleting scratch index 0x%x",
816                    scratch_idx);
817 #endif
818                         
819         send_reply (channel, &resp);
820 }
821
822 /*
823  * process_process_fork:
824  * @channel: The client making the request
825  * @open_handles: An array of handles referenced by this client
826  * @process_fork: Describes the process to fork
827  * @fds: stdin, stdout, and stderr for the new process
828  *
829  * Forks a new process, and returns the process and thread data to the
830  * client.
831  */
832 static void process_process_fork (GIOChannel *channel, ChannelData *channel_data,
833                                   WapiHandleRequest_ProcessFork process_fork,
834                                   int *fds)
835 {
836         WapiHandleResponse resp={0};
837         guint32 process_handle, thread_handle;
838         struct _WapiHandle_process *process_handle_data;
839         struct _WapiHandle_thread *thread_handle_data;
840         pid_t pid;
841         
842         resp.type=WapiHandleResponseType_ProcessFork;
843         
844         /* Create handles first, so the child process can store exec
845          * errors.  Either handle might be set to 0, if this happens
846          * just reply to the client without bothering to fork.  The
847          * client must check if either handle is 0 and take
848          * appropriate error handling action.
849          */
850         process_handle=_wapi_handle_new_internal (WAPI_HANDLE_PROCESS);
851         ref_handle (daemon_channel_data, process_handle);
852         ref_handle (channel_data, process_handle);
853         
854         thread_handle=_wapi_handle_new_internal (WAPI_HANDLE_THREAD);
855         ref_handle (daemon_channel_data, thread_handle);
856         ref_handle (channel_data, thread_handle);
857         
858         if(process_handle==0 || thread_handle==0) {
859                 /* unref_handle() copes with the handle being 0 */
860                 unref_handle (daemon_channel_data, process_handle);
861                 unref_handle (channel_data, process_handle);
862                 unref_handle (daemon_channel_data, thread_handle);
863                 unref_handle (channel_data, thread_handle);
864                 process_handle=0;
865                 thread_handle=0;
866         } else {
867                 char *cmd=NULL, *dir=NULL, **argv, **env;
868                 GError *gerr=NULL;
869                 gboolean ret;
870                 struct timeval tv;
871                 
872                 /* Get usable copies of the cmd, dir and env now
873                  * rather than in the child process.  This is to
874                  * prevent the race condition where the parent can
875                  * return the reply to the client, which then promptly
876                  * deletes the scratch data before the new process
877                  * gets to see it.  Also explode argv here so we can
878                  * use it to set the process name.
879                  */
880                 cmd=_wapi_handle_scratch_lookup (process_fork.cmd);
881                 dir=_wapi_handle_scratch_lookup (process_fork.dir);
882                 env=_wapi_handle_scratch_lookup_string_array (process_fork.env);
883                 
884                 ret=g_shell_parse_argv (cmd, NULL, &argv, &gerr);
885                 if(ret==FALSE) {
886                         /* FIXME: Could do something with the
887                          * GError here
888                          */
889                         process_handle_data->exec_errno=gerr->code;
890                 } else {
891 #ifdef DEBUG
892                         g_message (G_GNUC_PRETTY_FUNCTION ": forking");
893 #endif
894
895                         _wapi_lookup_handle (GUINT_TO_POINTER (process_handle),
896                                              WAPI_HANDLE_PROCESS,
897                                              (gpointer *)&process_handle_data,
898                                              NULL);
899
900                         _wapi_lookup_handle (GUINT_TO_POINTER (thread_handle),
901                                              WAPI_HANDLE_THREAD,
902                                              (gpointer *)&thread_handle_data,
903                                              NULL);
904
905                         /* Fork, exec cmd with args and optional env,
906                          * and return the handles with pid and blank
907                          * thread id
908                          */
909                         pid=fork ();
910                         if(pid==-1) {
911                                 process_handle_data->exec_errno=errno;
912                         } else if (pid==0) {
913                                 /* child */
914                                 int i;
915                                 
916                                 /* should we detach from the process
917                                  * group? We're already running
918                                  * without a controlling tty...
919                                  */
920
921                                 /* Connect stdin, stdout and stderr */
922                                 dup2 (fds[0], 0);
923                                 dup2 (fds[1], 1);
924                                 dup2 (fds[2], 2);
925
926                                 if(process_fork.inherit!=TRUE) {
927                                         /* FIXME: do something here */
928                                 }
929                                 
930                                 /* Close all file descriptors */
931                                 for(i=3; i<getdtablesize (); i++) {
932                                         close (i);
933                                 }
934                         
935                                 /* pass process and thread handle info
936                                  * to the child, so it doesn't have to
937                                  * do an expensive search over the
938                                  * whole list
939                                  */
940                                 {
941                                         guint env_count=0;
942                                         
943                                         while(env[env_count]!=NULL) {
944                                                 env_count++;
945                                         }
946
947                                         env=(char **)g_renew (char **, env, env_count+3);
948                                         
949                                         env[env_count]=g_strdup_printf ("_WAPI_PROCESS_HANDLE=%d", process_handle);
950                                         env[env_count+1]=g_strdup_printf ("_WAPI_THREAD_HANDLE=%d", thread_handle);
951                                         env[env_count+2]=NULL;
952                                 }
953
954 #ifdef DEBUG
955                                 g_message (G_GNUC_PRETTY_FUNCTION
956                                            ": exec()ing [%s] in dir [%s]",
957                                            cmd, dir);
958                                 {
959                                         i=0;
960                                         while(argv[i]!=NULL) {
961                                                 g_message ("arg %d: [%s]",
962                                                            i, argv[i]);
963                                                 i++;
964                                         }
965
966                                         i=0;
967                                         while(env[i]!=NULL) {
968                                                 g_message ("env %d: [%s]",
969                                                            i, env[i]);
970                                                 i++;
971                                         }
972                                 }
973 #endif
974                         
975                                 /* set cwd */
976                                 if(chdir (dir)==-1) {
977                                         process_handle_data->exec_errno=errno;
978                                         exit (-1);
979                                 }
980                                 
981                                 /* exec */
982                                 execve (argv[0], argv, env);
983                 
984                                 /* bummer! */
985                                 process_handle_data->exec_errno=errno;
986                                 exit (-1);
987                         }
988                 }
989                 /* parent */
990
991                 /* store process name, based on the last section of the cmd */
992                 {
993                         char *slash=strrchr (argv[0], '/');
994                         
995                         if(slash!=NULL) {
996                                 process_handle_data->proc_name=_wapi_handle_scratch_store (slash+1, strlen (slash+1));
997                         } else {
998                                 process_handle_data->proc_name=_wapi_handle_scratch_store (argv[0], strlen (argv[0]));
999                         }
1000                 }
1001                 
1002                 /* These seem to be the defaults on w2k */
1003                 process_handle_data->min_working_set=204800;
1004                 process_handle_data->max_working_set=1413120;
1005                 
1006                 if(cmd!=NULL) {
1007                         g_free (cmd);
1008                 }
1009                 if(dir!=NULL) {
1010                         g_free (dir);
1011                 }
1012                 g_strfreev (argv);
1013                 g_strfreev (env);
1014                 
1015                 /* store pid */
1016                 process_handle_data->id=pid;
1017                 process_handle_data->main_thread=GUINT_TO_POINTER (thread_handle);
1018                 /* Ignore errors */
1019                 gettimeofday (&tv, NULL);
1020                 _wapi_timeval_to_filetime (&tv,
1021                                            &process_handle_data->create_time);
1022                 
1023                 /* FIXME: if env==0, inherit the env from the current
1024                  * process
1025                  */
1026                 process_handle_data->env=process_fork.env;
1027
1028                 thread_handle_data->process_handle=GUINT_TO_POINTER (process_handle);
1029
1030                 resp.u.process_fork.pid=pid;
1031         }
1032                         
1033         resp.u.process_fork.process_handle=process_handle;
1034         resp.u.process_fork.thread_handle=thread_handle;
1035
1036         send_reply (channel, &resp);
1037 }
1038
1039 /*
1040  * read_message:
1041  * @channel: The client to read the request from
1042  * @open_handles: An array of handles referenced by this client
1043  *
1044  * Read a message (A WapiHandleRequest) from a client and dispatch
1045  * whatever it wants to the process_* calls.
1046  */
1047 static void read_message (GIOChannel *channel, ChannelData *channel_data)
1048 {
1049         WapiHandleRequest req;
1050         int fds[3]={0, 1, 2};
1051         int ret;
1052         gboolean has_fds=FALSE;
1053         
1054         /* Reading data */
1055         ret=_wapi_daemon_request (g_io_channel_unix_get_fd (channel), &req,
1056                                   fds, &has_fds);
1057         if(ret==0) {
1058                 /* Other end went away */
1059 #ifdef DEBUG
1060                 g_message ("Read 0 bytes on fd %d, closing it",
1061                            g_io_channel_unix_get_fd (channel));
1062 #endif
1063                 rem_fd (channel, channel_data);
1064                 return;
1065         }
1066         
1067 #ifdef DEBUG
1068         g_message ("Process request %d", req.type);
1069 #endif
1070         switch(req.type) {
1071         case WapiHandleRequestType_New:
1072                 process_new (channel, channel_data, req.u.new.type);
1073                 break;
1074         case WapiHandleRequestType_Open:
1075 #ifdef DEBUG
1076                 g_assert(req.u.open.handle < _wapi_shared_data[0]->num_segments * _WAPI_HANDLES_PER_SEGMENT);
1077 #endif
1078                 process_open (channel, channel_data, req.u.open.handle);
1079                 break;
1080         case WapiHandleRequestType_Close:
1081 #ifdef DEBUG
1082                 g_assert(req.u.close.handle < _wapi_shared_data[0]->num_segments * _WAPI_HANDLES_PER_SEGMENT);
1083 #endif
1084                 process_close (channel, channel_data, req.u.close.handle);
1085                 break;
1086         case WapiHandleRequestType_Scratch:
1087                 process_scratch (channel, req.u.scratch.length);
1088                 break;
1089         case WapiHandleRequestType_ScratchFree:
1090                 process_scratch_free (channel, req.u.scratch_free.idx);
1091                 break;
1092         case WapiHandleRequestType_ProcessFork:
1093                 process_process_fork (channel, channel_data,
1094                                       req.u.process_fork, fds);
1095                 break;
1096         case WapiHandleRequestType_Error:
1097                 /* fall through */
1098         default:
1099                 /* Catch bogus requests */
1100                 /* FIXME: call rem_fd? */
1101                 break;
1102         }
1103
1104         if(has_fds==TRUE) {
1105 #ifdef DEBUG
1106                 g_message (G_GNUC_PRETTY_FUNCTION ": closing %d", fds[0]);
1107                 g_message (G_GNUC_PRETTY_FUNCTION ": closing %d", fds[1]);
1108                 g_message (G_GNUC_PRETTY_FUNCTION ": closing %d", fds[2]);
1109 #endif
1110                 
1111                 close (fds[0]);
1112                 close (fds[1]);
1113                 close (fds[2]);
1114         }
1115 }
1116
1117 /*
1118  * fd_activity:
1119  * @channel: The IO channel that is active
1120  * @condition: The condition that has been satisfied
1121  * @data: A pointer to an array of handles referenced by this client
1122  *
1123  * The callback called by the main loop when there is activity on an
1124  * IO channel.
1125  */
1126 static gboolean fd_activity (GIOChannel *channel, GIOCondition condition,
1127                              gpointer data)
1128 {
1129         int fd=g_io_channel_unix_get_fd (channel);
1130         ChannelData *channel_data=&channels[fd];
1131         
1132         if(condition & (G_IO_HUP | G_IO_ERR | G_IO_NVAL)) {
1133 #ifdef DEBUG
1134                 g_message ("fd %d error", fd);
1135 #endif
1136
1137                 rem_fd (channel, channel_data);
1138                 return(FALSE);
1139         }
1140
1141         if(condition & (G_IO_IN | G_IO_PRI)) {
1142                 if(fd==main_sock) {
1143                         int newsock;
1144                         struct sockaddr addr;
1145                         socklen_t addrlen=sizeof(struct sockaddr);
1146                         
1147                         newsock=accept (main_sock, &addr, &addrlen);
1148                         if(newsock==-1) {
1149                                 g_critical ("accept error: %s",
1150                                             g_strerror (errno));
1151                                 cleanup ();
1152                                 exit (-1);
1153                         }
1154
1155 #ifdef DEBUG
1156                         g_message ("accept returning %d", newsock);
1157 #endif
1158
1159                         add_fd (newsock);
1160                 } else {
1161 #ifdef DEBUG
1162                         g_message ("reading data on fd %d", fd);
1163 #endif
1164
1165                         read_message (channel, channel_data);
1166                 }
1167                 return(TRUE);
1168         }
1169         
1170         return(FALSE);  /* remove source */
1171 }
1172
1173 /*
1174  * _wapi_daemon_main:
1175  *
1176  * Open socket, create shared mem segment and begin listening for
1177  * clients.
1178  */
1179 void _wapi_daemon_main(gpointer data, gpointer scratch)
1180 {
1181         struct sockaddr_un main_socket_address;
1182         int ret;
1183
1184 #ifdef DEBUG
1185         g_message ("Starting up...");
1186 #endif
1187
1188         _wapi_shared_data[0]=data;
1189         _wapi_shared_scratch=scratch;
1190         _wapi_shared_scratch->is_shared=TRUE;
1191         
1192         /* Note that we've got the starting segment already */
1193         _wapi_shared_data[0]->num_segments=1;
1194         _wapi_shm_mapped_segments=1;
1195         
1196         startup ();
1197         
1198         main_sock=socket(PF_UNIX, SOCK_STREAM, 0);
1199
1200         main_socket_address.sun_family=AF_UNIX;
1201         memcpy(main_socket_address.sun_path, _wapi_shared_data[0]->daemon,
1202                MONO_SIZEOF_SUNPATH);
1203
1204         ret=bind(main_sock, (struct sockaddr *)&main_socket_address,
1205                  sizeof(struct sockaddr_un));
1206         if(ret==-1) {
1207                 g_critical ("bind failed: %s", g_strerror (errno));
1208                 _wapi_shared_data[0]->daemon_running=DAEMON_DIED_AT_STARTUP;
1209                 exit(-1);
1210         }
1211
1212 #ifdef DEBUG
1213         g_message("bound");
1214 #endif
1215
1216         ret=listen(main_sock, 5);
1217         if(ret==-1) {
1218                 g_critical ("listen failed: %s", g_strerror (errno));
1219                 _wapi_shared_data[0]->daemon_running=DAEMON_DIED_AT_STARTUP;
1220                 exit(-1);
1221         }
1222
1223 #ifdef DEBUG
1224         g_message("listening");
1225 #endif
1226
1227         add_fd(main_sock);
1228
1229         /* We're finished setting up, let everyone else know we're
1230          * ready.  From now on, it's up to us to delete the shared
1231          * memory segment when appropriate.
1232          */
1233         _wapi_shared_data[0]->daemon_running=DAEMON_RUNNING;
1234
1235         while(TRUE) {
1236                 if(check_processes==TRUE) {
1237                         process_died ();
1238                 }
1239                 
1240 #ifdef DEBUG
1241                 g_message ("polling");
1242 #endif
1243
1244                 /* Block until something happens. We don't use
1245                  * g_main_loop_run() because we rely on the SIGCHLD
1246                  * signal interrupting poll() so we can reap child
1247                  * processes as soon as they die, without burning cpu
1248                  * time by polling the flag.
1249                  */
1250                 g_main_context_iteration (g_main_context_default (), TRUE);
1251         }
1252 }