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