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