0e3eb7db6327e97919d165d7a78a0b570b5ec0ae
[chise/xemacs-chise.git.1] / src / process-nt.c
1 /* Asynchronous subprocess implementation for Win32
2    Copyright (C) 1985, 1986, 1987, 1988, 1992, 1993, 1994, 1995
3    Free Software Foundation, Inc.
4    Copyright (C) 1995 Sun Microsystems, Inc.
5    Copyright (C) 1995, 1996 Ben Wing.
6
7 This file is part of XEmacs.
8
9 XEmacs is free software; you can redistribute it and/or modify it
10 under the terms of the GNU General Public License as published by the
11 Free Software Foundation; either version 2, or (at your option) any
12 later version.
13
14 XEmacs is distributed in the hope that it will be useful, but WITHOUT
15 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
16 FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
17 for more details.
18
19 You should have received a copy of the GNU General Public License
20 along with XEmacs; see the file COPYING.  If not, write to
21 the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
22 Boston, MA 02111-1307, USA.  */
23
24 /* Written by Kirill M. Katsnelson <kkm@kis.ru>, April 1998 */
25
26 #include <config.h>
27 #include "lisp.h"
28
29 #include "hash.h"
30 #include "lstream.h"
31 #include "process.h"
32 #include "procimpl.h"
33 #include "sysdep.h"
34
35 #include <windows.h>
36 #ifndef __MINGW32__
37 #include <shellapi.h>
38 #else
39 #include <errno.h>
40 #endif
41 #include <signal.h>
42 #ifdef HAVE_SOCKETS
43 #include <winsock.h>
44 #endif
45
46 /* Arbitrary size limit for code fragments passed to run_in_other_process */
47 #define FRAGMENT_CODE_SIZE 32
48
49 /* Bound by winnt.el */
50 Lisp_Object Qnt_quote_process_args;
51
52 /* Implementation-specific data. Pointed to by Lisp_Process->process_data */
53 struct nt_process_data
54 {
55   HANDLE h_process;
56   int need_enable_child_signals;
57 };
58
59 #define NT_DATA(p) ((struct nt_process_data*)((p)->process_data))
60 \f
61 /*-----------------------------------------------------------------------*/
62 /* Process helpers                                                       */
63 /*-----------------------------------------------------------------------*/
64
65 /* This one breaks process abstraction. Prototype is in console-msw.h,
66    used by select_process method in event-msw.c */
67 HANDLE
68 get_nt_process_handle (struct Lisp_Process *p)
69 {
70   return (NT_DATA (p)->h_process);
71 }
72 \f
73 /*-----------------------------------------------------------------------*/
74 /* Running remote threads. See Microsoft Systems Journal 1994 Number 5   */
75 /* Jeffrey Richter, Load Your 32-bit DLL into Another Process's Address..*/
76 /*-----------------------------------------------------------------------*/
77
78 typedef struct
79 {
80   HANDLE h_process;
81   HANDLE h_thread;
82   LPVOID address;
83 } process_memory;
84
85 /*
86  * Allocate SIZE bytes in H_PROCESS address space. Fill in PMC used
87  * further by other routines. Return nonzero if successful.
88  *
89  * The memory in other process is allocated by creating a suspended
90  * thread. Initial stack of that thread is used as the memory
91  * block. The thread entry point is the routine ExitThread in
92  * kernel32.dll, so the allocated memory is freed just by resuming the 
93  * thread, which immediately terminates after that.
94  */
95
96 static int 
97 alloc_process_memory (HANDLE h_process, size_t size,
98                       process_memory* pmc)
99 {
100   LPTHREAD_START_ROUTINE adr_ExitThread =
101     (LPTHREAD_START_ROUTINE)
102     GetProcAddress (GetModuleHandle ("kernel32"), "ExitThread");
103   DWORD dw_unused;
104   CONTEXT context;
105   MEMORY_BASIC_INFORMATION mbi;
106
107   pmc->h_process = h_process;
108   pmc->h_thread = CreateRemoteThread (h_process, NULL, size,
109                                      adr_ExitThread, NULL,
110                                      CREATE_SUSPENDED, &dw_unused);
111   if (pmc->h_thread == NULL)
112     return 0;
113
114   /* Get context, for thread's stack pointer */
115   context.ContextFlags = CONTEXT_CONTROL;
116   if (!GetThreadContext (pmc->h_thread, &context))
117     goto failure;
118
119   /* Determine base address of the committed range */
120   if (sizeof(mbi) != VirtualQueryEx (h_process,
121 #if defined (_X86_)
122                                      (LPDWORD)context.Esp - 1,
123 #elif defined (_ALPHA_)
124                                      (LPDWORD)context.IntSp - 1,
125 #else
126 #error Unknown processor architecture
127 #endif
128                                      &mbi, sizeof(mbi)))
129     goto failure;
130
131   /* Change the page protection of the allocated memory to executable,
132      read, and write. */
133   if (!VirtualProtectEx (h_process, mbi.BaseAddress, size,
134                          PAGE_EXECUTE_READWRITE, &dw_unused))
135     goto failure;
136
137   pmc->address = mbi.BaseAddress;
138   return 1;
139
140  failure:
141   ResumeThread (pmc->h_thread);
142   pmc->address = 0;
143   return 0;
144 }
145
146 static void
147 free_process_memory (process_memory* pmc)
148 {
149   ResumeThread (pmc->h_thread);
150 }
151
152 /*
153  * Run ROUTINE in the context of process determined by H_PROCESS. The
154  * routine is passed the address of DATA as parameter. The ROUTINE must
155  * not be longer than ROUTINE_CODE_SIZE bytes. DATA_SIZE is the size of
156  * DATA structure.
157  *
158  * Note that the code must be positionally independent, and compiled
159  * without stack checks (they cause implicit calls into CRT so will
160  * fail). DATA should not refer any data in calling process, as both
161  * routine and its data are copied into remote process. Size of data
162  * and code together should not exceed one page (4K on x86 systems).
163  *
164  * Return the value returned by ROUTINE, or (DWORD)-1 if call failed.
165  */
166 static DWORD
167 run_in_other_process (HANDLE h_process,
168                       LPTHREAD_START_ROUTINE routine,
169                       LPVOID data, size_t data_size)
170 {
171   process_memory pm;
172   CONST size_t code_size = FRAGMENT_CODE_SIZE;
173   /* Need at most 3 extra bytes of memory, for data alignment */
174   size_t total_size = code_size + data_size + 3;
175   LPVOID remote_data;
176   HANDLE h_thread;
177   DWORD dw_unused;
178
179   /* Allocate memory */
180   if (!alloc_process_memory (h_process, total_size, &pm))
181     return (DWORD)-1;
182
183   /* Copy code */
184   if (!WriteProcessMemory (h_process, pm.address, (LPVOID)routine,
185                            code_size, NULL))
186     goto failure;
187
188   /* Copy data */
189   if (data_size)
190     {
191       remote_data = (LPBYTE)pm.address + ((code_size + 4) & ~3);
192       if (!WriteProcessMemory (h_process, remote_data, data, data_size, NULL))
193         goto failure;
194     }
195   else
196     remote_data = NULL;
197
198   /* Execute the remote copy of code, passing it remote data */
199   h_thread = CreateRemoteThread (h_process, NULL, 0,
200                                  (LPTHREAD_START_ROUTINE) pm.address,
201                                  remote_data, 0, &dw_unused);
202   if (h_thread == NULL)
203     goto failure;
204
205   /* Wait till thread finishes */
206   WaitForSingleObject (h_thread, INFINITE);
207
208   /* Free remote memory */
209   free_process_memory (&pm);
210
211   /* Return thread's exit code */
212   {
213     DWORD exit_code;
214     GetExitCodeThread (h_thread, &exit_code);
215     CloseHandle (h_thread);
216     return exit_code;
217   }
218
219  failure:
220   free_process_memory (&pm);
221   return (DWORD)-1;
222 }
223 \f
224 /*-----------------------------------------------------------------------*/
225 /* Sending signals                                                       */
226 /*-----------------------------------------------------------------------*/
227
228 /*
229  * We handle the following signals:
230  *
231  * SIGKILL, SIGTERM, SIGQUIT, SIGHUP - These four translate to ExitProcess
232  *    executed by the remote process
233  * SIGINT - The remote process is sent CTRL_BREAK_EVENT
234  *
235  * The MSVC5.0 compiler feels free to re-order functions within a
236  * compilation unit, so we have no way of finding out the size of the
237  * following functions. Therefore these functions must not be larger than
238  * FRAGMENT_CODE_SIZE.
239  */
240
241 /*
242  * Sending SIGKILL
243  */
244 typedef struct
245 {
246   void (WINAPI *adr_ExitProcess) (UINT);
247 } sigkill_data;
248
249 static DWORD WINAPI
250 sigkill_proc (sigkill_data* data)
251 {
252   (*data->adr_ExitProcess)(255);
253   return 1;
254 }
255
256 /*
257  * Sending break or control c
258  */
259 typedef struct
260 {
261   BOOL (WINAPI *adr_GenerateConsoleCtrlEvent) (DWORD, DWORD);
262   DWORD event;
263 } sigint_data;
264
265 static DWORD WINAPI
266 sigint_proc (sigint_data* data)
267 {
268   return (*data->adr_GenerateConsoleCtrlEvent) (data->event, 0);
269 }
270
271 /*
272  * Enabling signals
273  */
274 typedef struct
275 {
276   BOOL (WINAPI *adr_SetConsoleCtrlHandler) (LPVOID, BOOL);
277 } sig_enable_data;
278
279 static DWORD WINAPI
280 sig_enable_proc (sig_enable_data* data)
281 {
282   (*data->adr_SetConsoleCtrlHandler) (NULL, FALSE);
283   return 1;
284 }
285
286 /*
287  * Send signal SIGNO to process H_PROCESS.
288  * Return nonzero if successful.
289  */
290
291 /* This code assigns a return value of GetProcAddress to function pointers
292    of many different types. Instead of heavy obscure casts, we just disable
293    warnings about assignments to different function pointer types. */
294 #pragma warning (disable : 4113)
295
296 static int
297 send_signal (HANDLE h_process, int signo)
298 {
299   HMODULE h_kernel = GetModuleHandle ("kernel32");
300   DWORD retval;
301   
302   assert (h_kernel != NULL);
303   
304   switch (signo)
305     {
306     case SIGKILL:
307     case SIGTERM:
308     case SIGQUIT:
309     case SIGHUP:
310       {
311         sigkill_data d;
312         d.adr_ExitProcess = GetProcAddress (h_kernel, "ExitProcess");
313         assert (d.adr_ExitProcess);
314         retval = run_in_other_process (h_process, 
315                                        (LPTHREAD_START_ROUTINE)sigkill_proc,
316                                        &d, sizeof (d));
317         break;
318       }
319     case SIGINT:
320       {
321         sigint_data d;
322         d.adr_GenerateConsoleCtrlEvent =
323           GetProcAddress (h_kernel, "GenerateConsoleCtrlEvent");
324         assert (d.adr_GenerateConsoleCtrlEvent);
325         d.event = CTRL_C_EVENT;
326         retval = run_in_other_process (h_process, 
327                                        (LPTHREAD_START_ROUTINE)sigint_proc,
328                                        &d, sizeof (d));
329         break;
330       }
331     default:
332       assert (0);
333     }
334
335   return (int)retval > 0 ? 1 : 0;
336 }
337
338 /*
339  * Enable CTRL_C_EVENT handling in a new child process
340  */
341 static void
342 enable_child_signals (HANDLE h_process)
343 {
344   HMODULE h_kernel = GetModuleHandle ("kernel32");
345   sig_enable_data d;
346   
347   assert (h_kernel != NULL);
348   d.adr_SetConsoleCtrlHandler =
349     GetProcAddress (h_kernel, "SetConsoleCtrlHandler");
350   assert (d.adr_SetConsoleCtrlHandler);
351   run_in_other_process (h_process, (LPTHREAD_START_ROUTINE)sig_enable_proc,
352                         &d, sizeof (d));
353 }
354   
355 #pragma warning (default : 4113)
356
357 /*
358  * Signal error if SIGNO is not supported
359  */
360 static void
361 validate_signal_number (int signo)
362 {
363   if (signo != SIGKILL && signo != SIGTERM
364       && signo != SIGQUIT && signo != SIGINT
365       && signo != SIGHUP)
366     signal_simple_error ("Signal number not supported", make_int (signo));
367 }
368 \f  
369 /*-----------------------------------------------------------------------*/
370 /* Process methods                                                       */
371 /*-----------------------------------------------------------------------*/
372
373 /*
374  * Allocate and initialize Lisp_Process->process_data
375  */
376
377 static void
378 nt_alloc_process_data (struct Lisp_Process *p)
379 {
380   p->process_data = xnew_and_zero (struct nt_process_data);
381 }
382
383 static void
384 nt_finalize_process_data (struct Lisp_Process *p, int for_disksave)
385 {
386   assert (!for_disksave);
387   if (NT_DATA(p)->h_process)
388     CloseHandle (NT_DATA(p)->h_process);
389 }
390
391 /*
392  * Initialize XEmacs process implementation once
393  */
394 static void
395 nt_init_process (void)
396 {
397   /* Initialize winsock */
398   WSADATA wsa_data;
399   /* Request Winsock v1.1 Note the order: (minor=1, major=1) */
400   WSAStartup (MAKEWORD (1,1), &wsa_data);
401 }
402
403 /*
404  * Fork off a subprocess. P is a pointer to newly created subprocess
405  * object. If this function signals, the caller is responsible for
406  * deleting (and finalizing) the process object.
407  *
408  * The method must return PID of the new process, a (positive??? ####) number
409  * which fits into Lisp_Int. No return value indicates an error, the method
410  * must signal an error instead.
411  */
412
413 static void
414 signal_cannot_launch (Lisp_Object image_file, DWORD err)
415 {
416   mswindows_set_errno (err);
417   signal_simple_error_2 ("Error starting", image_file, lisp_strerror (errno));
418 }
419
420 static int
421 nt_create_process (struct Lisp_Process *p,
422                    Lisp_Object *argv, int nargv,
423                    Lisp_Object program, Lisp_Object cur_dir)
424 {
425   HANDLE hmyshove, hmyslurp, hprocin, hprocout, hprocerr;
426   LPTSTR command_line;
427   BOOL do_io, windowed;
428   char *proc_env;
429
430   /* Find out whether the application is windowed or not */
431   {
432     /* SHGetFileInfo tends to return ERROR_FILE_NOT_FOUND on most
433        errors. This leads to bogus error message. */
434     DWORD image_type;
435     char *p = strrchr ((char *)XSTRING_DATA (program), '.');
436     if (p != NULL &&
437         (stricmp (p, ".exe") == 0 ||
438          stricmp (p, ".com") == 0 ||
439          stricmp (p, ".bat") == 0 ||
440          stricmp (p, ".cmd") == 0))
441       {
442         image_type = SHGetFileInfo ((char *)XSTRING_DATA (program), 0,NULL,
443                                     0, SHGFI_EXETYPE);
444       }
445     else
446       {
447         char progname[MAX_PATH];
448         sprintf (progname, "%s.exe", (char *)XSTRING_DATA (program));
449         image_type = SHGetFileInfo (progname, 0, NULL, 0, SHGFI_EXETYPE);
450       }
451     if (image_type == 0)
452       signal_cannot_launch (program, (GetLastError () == ERROR_FILE_NOT_FOUND
453                                       ? ERROR_BAD_FORMAT : GetLastError ()));
454     windowed = HIWORD (image_type) != 0;
455   }
456
457   /* Decide whether to do I/O on process handles, or just mark the
458      process exited immediately upon successful launching. We do I/O if the
459      process is a console one, or if it is windowed but windowed_process_io
460      is non-zero */
461   do_io = !windowed || windowed_process_io ;
462   
463   if (do_io)
464     {
465       /* Create two unidirectional named pipes */
466       HANDLE htmp;
467       SECURITY_ATTRIBUTES sa;
468
469       sa.nLength = sizeof(sa);
470       sa.bInheritHandle = TRUE;
471       sa.lpSecurityDescriptor = NULL;
472
473       CreatePipe (&hprocin, &hmyshove, &sa, 0);
474       CreatePipe (&hmyslurp, &hprocout, &sa, 0);
475
476       /* Duplicate the stdout handle for use as stderr */
477       DuplicateHandle(GetCurrentProcess(), hprocout, GetCurrentProcess(), &hprocerr,
478         0, TRUE, DUPLICATE_SAME_ACCESS);
479
480       /* Stupid Win32 allows to create a pipe with *both* ends either
481          inheritable or not. We need process ends inheritable, and local
482          ends not inheritable. */
483       DuplicateHandle (GetCurrentProcess(), hmyshove, GetCurrentProcess(), &htmp,
484                        0, FALSE, DUPLICATE_CLOSE_SOURCE | DUPLICATE_SAME_ACCESS);
485       hmyshove = htmp;
486       DuplicateHandle (GetCurrentProcess(), hmyslurp, GetCurrentProcess(), &htmp,
487                        0, FALSE, DUPLICATE_CLOSE_SOURCE | DUPLICATE_SAME_ACCESS);
488       hmyslurp = htmp;
489     }
490
491   /* Convert an argv vector into Win32 style command line by a call to
492      lisp function `nt-quote-process-args' which see (in winnt.el)*/
493   {
494     int i;
495     Lisp_Object args_or_ret = Qnil;
496     struct gcpro gcpro1;
497
498     GCPRO1 (args_or_ret);
499
500     for (i = 0; i < nargv; ++i)
501       args_or_ret = Fcons (*argv++, args_or_ret);
502     args_or_ret = Fnreverse (args_or_ret);
503     args_or_ret = Fcons (program, args_or_ret);
504
505     args_or_ret = call1 (Qnt_quote_process_args, args_or_ret);
506
507     if (!STRINGP (args_or_ret))
508       /* Luser wrote his/her own clever version */
509       error ("Bogus return value from `nt-quote-process-args'");
510
511     command_line = alloca_array (char, (XSTRING_LENGTH (program)
512                                         + XSTRING_LENGTH (args_or_ret) + 2));
513     strcpy (command_line, XSTRING_DATA (program));
514     strcat (command_line, " ");
515     strcat (command_line, XSTRING_DATA (args_or_ret));
516
517     UNGCPRO; /* args_or_ret */
518   }
519
520   /* Set `proc_env' to a nul-separated array of the strings in
521      Vprocess_environment terminated by 2 nuls.  */
522  
523   {
524     extern int compare_env (const char **strp1, const char **strp2);
525     char **env;
526     REGISTER Lisp_Object tem;
527     REGISTER char **new_env;
528     REGISTER int new_length = 0, i, new_space;
529     char *penv;
530     
531     for (tem = Vprocess_environment;
532          (CONSP (tem)
533           && STRINGP (XCAR (tem)));
534          tem = XCDR (tem))
535       new_length++;
536     
537     /* new_length + 1 to include terminating 0.  */
538     env = new_env = alloca_array (char *, new_length + 1);
539  
540     /* Copy the Vprocess_environment strings into new_env.  */
541     for (tem = Vprocess_environment;
542          (CONSP (tem)
543           && STRINGP (XCAR (tem)));
544          tem = XCDR (tem))
545       {
546         char **ep = env;
547         char *string = (char *) XSTRING_DATA (XCAR (tem));
548         /* See if this string duplicates any string already in the env.
549            If so, don't put it in.
550            When an env var has multiple definitions,
551            we keep the definition that comes first in process-environment.  */
552         for (; ep != new_env; ep++)
553           {
554             char *p = *ep, *q = string;
555             while (1)
556               {
557                 if (*q == 0)
558                   /* The string is malformed; might as well drop it.  */
559                   goto duplicate;
560                 if (*q != *p)
561                   break;
562                 if (*q == '=')
563                   goto duplicate;
564                 p++, q++;
565               }
566           }
567         *new_env++ = string;
568       duplicate: ;
569       }
570     *new_env = 0;
571     
572     /* Sort the environment variables */
573     new_length = new_env - env;
574     qsort (env, new_length, sizeof (char *), compare_env);
575     
576     /* Work out how much space to allocate */
577     new_space = 0;
578     for (i = 0; i < new_length; i++)
579       {
580         new_space += strlen(env[i]) + 1;
581       }
582     new_space++;
583     
584     /* Allocate space and copy variables into it */
585     penv = proc_env = alloca(new_space);
586     for (i = 0; i < new_length; i++)
587       {
588         strcpy(penv, env[i]);
589         penv += strlen(env[i]) + 1;
590       }
591     *penv = 0;
592   }
593   
594   /* Create process */
595   {
596     STARTUPINFO si;
597     PROCESS_INFORMATION pi;
598     DWORD err;
599
600     xzero (si);
601     si.dwFlags = STARTF_USESHOWWINDOW;
602     si.wShowWindow = windowed ? SW_SHOWNORMAL : SW_HIDE;
603     if (do_io)
604       {
605         si.hStdInput = hprocin;
606         si.hStdOutput = hprocout;
607         si.hStdError = hprocerr;
608         si.dwFlags |= STARTF_USESTDHANDLES;
609       }
610
611     err = (CreateProcess (NULL, command_line, NULL, NULL, TRUE,
612                           CREATE_NEW_CONSOLE | CREATE_NEW_PROCESS_GROUP
613                           | CREATE_SUSPENDED,
614                           proc_env, (char *) XSTRING_DATA (cur_dir), &si, &pi)
615            ? 0 : GetLastError ());
616
617     if (do_io)
618       {
619         /* These just have been inherited; we do not need a copy */
620         CloseHandle (hprocin);
621         CloseHandle (hprocout);
622         CloseHandle (hprocerr);
623       }
624     
625     /* Handle process creation failure */
626     if (err)
627       {
628         if (do_io)
629           {
630             CloseHandle (hmyshove);
631             CloseHandle (hmyslurp);
632           }
633         signal_cannot_launch (program, GetLastError ());
634       }
635
636     /* The process started successfully */
637     if (do_io)
638       {
639         NT_DATA(p)->h_process = pi.hProcess;
640         init_process_io_handles (p, (void*)hmyslurp, (void*)hmyshove, 0);
641       }
642     else
643       {
644         /* Indicate as if the process has exited immediately. */
645         p->status_symbol = Qexit;
646         CloseHandle (pi.hProcess);
647       }
648
649     ResumeThread (pi.hThread);
650     CloseHandle (pi.hThread);
651
652     /* Remember to enable child signals later if this is not a windowed
653        app.  Can't do it right now because that screws up the MKS Toolkit
654        shell. */
655     if (!windowed)
656       {
657         NT_DATA(p)->need_enable_child_signals = 10;
658         kick_status_notify ();
659       }
660
661     /* Hack to support Windows 95 negative pids */
662     return ((int)pi.dwProcessId < 0
663             ? -(int)pi.dwProcessId : (int)pi.dwProcessId);
664   }
665 }
666
667 /* 
668  * This method is called to update status fields of the process
669  * structure. If the process has not existed, this method is expected
670  * to do nothing.
671  *
672  * The method is called only for real child processes.  
673  */
674
675 static void
676 nt_update_status_if_terminated (struct Lisp_Process* p)
677 {
678   DWORD exit_code;
679
680   if (NT_DATA(p)->need_enable_child_signals > 1)
681     {
682       NT_DATA(p)->need_enable_child_signals -= 1;
683       kick_status_notify ();
684     }
685   else if (NT_DATA(p)->need_enable_child_signals == 1)
686     {
687       enable_child_signals(NT_DATA(p)->h_process);
688       NT_DATA(p)->need_enable_child_signals = 0;
689     }
690
691   if (GetExitCodeProcess (NT_DATA(p)->h_process, &exit_code)
692       && exit_code != STILL_ACTIVE)
693     {
694       p->tick++;
695       p->core_dumped = 0;
696       /* The exit code can be a code returned by process, or an
697          NTSTATUS value. We cannot accurately handle the latter since
698          it is a full 32 bit integer */
699       if (exit_code & 0xC0000000)
700         {
701           p->status_symbol = Qsignal;
702           p->exit_code = exit_code & 0x1FFFFFFF;
703         }
704       else
705         {
706           p->status_symbol = Qexit;
707           p->exit_code = exit_code;
708         }
709     }
710 }
711
712 /*
713  * Stuff the entire contents of LSTREAM to the process output pipe
714  */
715
716 /* #### If only this function could be somehow merged with
717    unix_send_process... */
718
719 static void
720 nt_send_process (Lisp_Object proc, struct lstream* lstream)
721 {
722   struct Lisp_Process *p = XPROCESS (proc);
723
724   /* use a reasonable-sized buffer (somewhere around the size of the
725      stream buffer) so as to avoid inundating the stream with blocked
726      data. */
727   Bufbyte chunkbuf[128];
728   Bytecount chunklen;
729
730   while (1)
731     {
732       ssize_t writeret;
733
734       chunklen = Lstream_read (lstream, chunkbuf, 128);
735       if (chunklen <= 0)
736         break; /* perhaps should abort() if < 0?
737                   This should never happen. */
738
739       /* Lstream_write() will never successfully write less than the
740          amount sent in.  In the worst case, it just buffers the
741          unwritten data. */
742       writeret = Lstream_write (XLSTREAM (DATA_OUTSTREAM(p)), chunkbuf,
743                                 chunklen);
744       Lstream_flush (XLSTREAM (DATA_OUTSTREAM(p)));
745       if (writeret < 0)
746         {
747           p->status_symbol = Qexit;
748           p->exit_code = ERROR_BROKEN_PIPE;
749           p->core_dumped = 0;
750           p->tick++;
751           process_tick++;
752           deactivate_process (proc);
753           error ("Broken pipe error sending to process %s; closed it",
754                  XSTRING_DATA (p->name));
755         }
756
757       {
758         int wait_ms = 25;
759         while (Lstream_was_blocked_p (XLSTREAM (p->pipe_outstream)))
760           {
761             /* Buffer is full.  Wait, accepting input; that may allow
762                the program to finish doing output and read more.  */
763             Faccept_process_output (Qnil, Qzero, make_int (wait_ms));
764             Lstream_flush (XLSTREAM (p->pipe_outstream));
765             wait_ms = min (1000, 2 * wait_ms);
766           }
767       }
768     }
769 }
770
771 /*
772  * Send a signal number SIGNO to PROCESS.
773  * CURRENT_GROUP means send to the process group that currently owns
774  * the terminal being used to communicate with PROCESS.
775  * This is used for various commands in shell mode.
776  * If NOMSG is zero, insert signal-announcements into process's buffers
777  * right away.
778  *
779  * If we can, we try to signal PROCESS by sending control characters
780  * down the pty.  This allows us to signal inferiors who have changed
781  * their uid, for which killpg would return an EPERM error.
782  *
783  * The method signals an error if the given SIGNO is not valid
784  */
785
786 static void
787 nt_kill_child_process (Lisp_Object proc, int signo,
788                        int current_group, int nomsg)
789 {
790   struct Lisp_Process *p = XPROCESS (proc);
791
792   /* Enable child signals if necessary.  This may lose the first
793      but it's better than nothing. */
794   if (NT_DATA(p)->need_enable_child_signals > 0)
795     {
796       enable_child_signals(NT_DATA(p)->h_process);
797       NT_DATA(p)->need_enable_child_signals = 0;
798     }
799
800   /* Signal error if SIGNO cannot be sent */
801   validate_signal_number (signo);
802
803   /* Send signal */
804   if (!send_signal (NT_DATA(p)->h_process, signo))
805     error ("Cannot send signal to process");
806 }
807
808 /*
809  * Kill any process in the system given its PID.
810  *
811  * Returns zero if a signal successfully sent, or
812  * negative number upon failure
813  */
814 static int
815 nt_kill_process_by_pid (int pid, int signo)
816 {
817   HANDLE h_process;
818   int send_result;
819   
820   /* Signal error if SIGNO cannot be sent */
821   validate_signal_number (signo);
822
823   /* Try to open the process with required privileges */
824   h_process = OpenProcess (PROCESS_CREATE_THREAD
825                            | PROCESS_QUERY_INFORMATION 
826                            | PROCESS_VM_OPERATION
827                            | PROCESS_VM_WRITE,
828                            FALSE, pid);
829   if (h_process == NULL)
830     return -1;
831   
832   send_result = send_signal (h_process, signo);
833   
834   CloseHandle (h_process);
835
836   return send_result ? 0 : -1;
837 }
838 \f
839 /*-----------------------------------------------------------------------*/
840 /* Sockets connections                                                   */
841 /*-----------------------------------------------------------------------*/
842 #ifdef HAVE_SOCKETS
843
844 /* #### Hey MS, how long Winsock 2 for '95 will be in beta? */
845
846 #define SOCK_TIMER_ID 666
847 #define XM_SOCKREPLY (WM_USER + 666)
848
849 static int
850 get_internet_address (Lisp_Object host, struct sockaddr_in *address,
851                       Error_behavior errb)
852 {
853   char buf [MAXGETHOSTSTRUCT];
854   HWND hwnd;
855   HANDLE hasync;
856   int success = 0;
857
858   address->sin_family = AF_INET;
859
860   /* First check if HOST is already a numeric address */
861   {
862     unsigned long inaddr = inet_addr (XSTRING_DATA (host));
863     if (inaddr != INADDR_NONE)
864       {
865         address->sin_addr.s_addr = inaddr;
866         return 1;
867       }
868   }
869
870   /* Create a window which will receive completion messages */
871   hwnd = CreateWindow ("STATIC", NULL, WS_OVERLAPPED, 0, 0, 1, 1,
872                        NULL, NULL, NULL, NULL);
873   assert (hwnd);
874
875   /* Post name resolution request */
876   hasync = WSAAsyncGetHostByName (hwnd, XM_SOCKREPLY, XSTRING_DATA (host),
877                                   buf, sizeof (buf));
878   if (hasync == NULL)
879     goto done;
880
881   /* Set a timer to poll for quit every 250 ms */
882   SetTimer (hwnd, SOCK_TIMER_ID, 250, NULL);
883
884   while (1)
885     {
886       MSG msg;
887       GetMessage (&msg, hwnd, 0, 0);
888       if (msg.message == XM_SOCKREPLY)
889         {
890           /* Ok, got an answer */
891           if (WSAGETASYNCERROR(msg.lParam) == NO_ERROR)
892             success = 1;
893           goto done;
894         }
895       else if (msg.message == WM_TIMER && msg.wParam == SOCK_TIMER_ID)
896         {
897           if (QUITP)
898             {
899               WSACancelAsyncRequest (hasync);
900               KillTimer (hwnd, SOCK_TIMER_ID);
901               DestroyWindow (hwnd);
902               REALLY_QUIT;
903             }
904         }
905       DispatchMessage (&msg);
906     }
907
908  done:
909   KillTimer (hwnd, SOCK_TIMER_ID);
910   DestroyWindow (hwnd);
911   if (success)
912     {
913       /* BUF starts with struct hostent */
914       struct hostent* he = (struct hostent*) buf;
915       address->sin_addr.s_addr = *(unsigned long*)he->h_addr_list[0];
916     }
917   return success;
918 }
919
920 static Lisp_Object
921 nt_canonicalize_host_name (Lisp_Object host)
922 {
923   struct sockaddr_in address;
924
925   if (!get_internet_address (host, &address, ERROR_ME_NOT))
926     return host;
927
928   if (address.sin_family == AF_INET)
929     return build_string (inet_ntoa (address.sin_addr));
930   else
931     return host;
932 }
933
934 /* open a TCP network connection to a given HOST/SERVICE.  Treated
935    exactly like a normal process when reading and writing.  Only
936    differences are in status display and process deletion.  A network
937    connection has no PID; you cannot signal it.  All you can do is
938    deactivate and close it via delete-process */
939
940 static void
941 nt_open_network_stream (Lisp_Object name, Lisp_Object host, Lisp_Object service,
942                         Lisp_Object protocol, void** vinfd, void** voutfd)
943 {
944   struct sockaddr_in address;
945   SOCKET s;
946   int port;
947   int retval;
948
949   CHECK_STRING (host);
950
951   if (!EQ (protocol, Qtcp))
952     error ("Unsupported protocol \"%s\"",
953            string_data (symbol_name (XSYMBOL (protocol))));
954
955   if (INTP (service))
956     port = htons ((unsigned short) XINT (service));
957   else
958     {
959       struct servent *svc_info;
960       CHECK_STRING (service);
961       svc_info = getservbyname ((char *) XSTRING_DATA (service), "tcp");
962       if (svc_info == 0)
963         error ("Unknown service \"%s\"", XSTRING_DATA (service));
964       port = svc_info->s_port;
965     }
966
967   get_internet_address (host, &address, ERROR_ME);
968   address.sin_port = port;
969
970   s = socket (address.sin_family, SOCK_STREAM, 0);
971   if (s < 0)
972     report_file_error ("error creating socket", list1 (name));
973
974   /* We don't want to be blocked on connect */
975   {
976     unsigned long nonblock = 1;
977     ioctlsocket (s, FIONBIO, &nonblock);
978   }
979   
980   retval = connect (s, (struct sockaddr *) &address, sizeof (address));
981   if (retval != NO_ERROR && WSAGetLastError() != WSAEWOULDBLOCK)
982     goto connect_failed;
983
984   /* Wait while connection is established */
985   while (1)
986     {
987       fd_set fdset;
988       struct timeval tv;
989       int nsel;
990
991       if (QUITP)
992         {
993           closesocket (s);
994           REALLY_QUIT;
995         }
996
997       /* Poll for quit every 250 ms */
998       tv.tv_sec = 0;
999       tv.tv_usec = 250 * 1000;
1000
1001       FD_ZERO (&fdset);
1002       FD_SET (s, &fdset);
1003       nsel = select (0, NULL, &fdset, &fdset, &tv);
1004
1005       if (nsel > 0)
1006         {
1007           /* Check: was connection successful or not? */
1008           tv.tv_usec = 0;
1009           nsel = select (0, NULL, NULL, &fdset, &tv);
1010           if (nsel > 0)
1011             goto connect_failed;
1012           else
1013             break;
1014         }
1015     }
1016
1017   /* We are connected at this point */
1018   *vinfd = (void*)s;
1019   DuplicateHandle (GetCurrentProcess(), (HANDLE)s,
1020                    GetCurrentProcess(), (LPHANDLE)voutfd,
1021                    0, FALSE, DUPLICATE_SAME_ACCESS);
1022   return;
1023
1024  connect_failed:  
1025   closesocket (s);
1026   report_file_error ("connection failed", list2 (host, name));
1027 }
1028
1029 #endif
1030 \f
1031 /*-----------------------------------------------------------------------*/
1032 /* Initialization                                                        */
1033 /*-----------------------------------------------------------------------*/
1034
1035 void
1036 process_type_create_nt (void)
1037 {
1038   PROCESS_HAS_METHOD (nt, alloc_process_data);
1039   PROCESS_HAS_METHOD (nt, finalize_process_data);
1040   PROCESS_HAS_METHOD (nt, init_process);
1041   PROCESS_HAS_METHOD (nt, create_process);
1042   PROCESS_HAS_METHOD (nt, update_status_if_terminated);
1043   PROCESS_HAS_METHOD (nt, send_process);
1044   PROCESS_HAS_METHOD (nt, kill_child_process);
1045   PROCESS_HAS_METHOD (nt, kill_process_by_pid);
1046 #ifdef HAVE_SOCKETS
1047   PROCESS_HAS_METHOD (nt, canonicalize_host_name);
1048   PROCESS_HAS_METHOD (nt, open_network_stream);
1049 #ifdef HAVE_MULTICAST
1050 #error I won't do this until '95 has winsock2
1051   PROCESS_HAS_METHOD (nt, open_multicast_group);
1052 #endif
1053 #endif
1054 }
1055
1056 void
1057 syms_of_process_nt (void)
1058 {
1059   defsymbol (&Qnt_quote_process_args, "nt-quote-process-args");
1060 }
1061
1062 void
1063 vars_of_process_nt (void)
1064 {
1065 }