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.
7 This file is part of XEmacs.
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
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
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. */
24 /* Written by Kirill M. Katsnelson <kkm@kis.ru>, April 1998 */
45 /* Arbitrary size limit for code fragments passed to run_in_other_process */
46 #define FRAGMENT_CODE_SIZE 32
48 /* Bound by winnt.el */
49 Lisp_Object Qnt_quote_process_args;
51 /* Implementation-specific data. Pointed to by Lisp_Process->process_data */
52 struct nt_process_data
55 int need_enable_child_signals;
58 #define NT_DATA(p) ((struct nt_process_data*)((p)->process_data))
60 /*-----------------------------------------------------------------------*/
62 /*-----------------------------------------------------------------------*/
64 /* This one breaks process abstraction. Prototype is in console-msw.h,
65 used by select_process method in event-msw.c */
67 get_nt_process_handle (Lisp_Process *p)
69 return (NT_DATA (p)->h_process);
72 /*-----------------------------------------------------------------------*/
73 /* Running remote threads. See Microsoft Systems Journal 1994 Number 5 */
74 /* Jeffrey Richter, Load Your 32-bit DLL into Another Process's Address..*/
75 /*-----------------------------------------------------------------------*/
85 * Allocate SIZE bytes in H_PROCESS address space. Fill in PMC used
86 * further by other routines. Return nonzero if successful.
88 * The memory in other process is allocated by creating a suspended
89 * thread. Initial stack of that thread is used as the memory
90 * block. The thread entry point is the routine ExitThread in
91 * kernel32.dll, so the allocated memory is freed just by resuming the
92 * thread, which immediately terminates after that.
96 alloc_process_memory (HANDLE h_process, size_t size,
99 LPTHREAD_START_ROUTINE adr_ExitThread =
100 (LPTHREAD_START_ROUTINE)
101 GetProcAddress (GetModuleHandle ("kernel32"), "ExitThread");
104 MEMORY_BASIC_INFORMATION mbi;
106 pmc->h_process = h_process;
107 pmc->h_thread = CreateRemoteThread (h_process, NULL, size,
108 adr_ExitThread, NULL,
109 CREATE_SUSPENDED, &dw_unused);
110 if (pmc->h_thread == NULL)
113 /* Get context, for thread's stack pointer */
114 context.ContextFlags = CONTEXT_CONTROL;
115 if (!GetThreadContext (pmc->h_thread, &context))
118 /* Determine base address of the committed range */
119 if (sizeof(mbi) != VirtualQueryEx (h_process,
121 (LPDWORD)context.Esp - 1,
122 #elif defined (_ALPHA_)
123 (LPDWORD)context.IntSp - 1,
125 #error Unknown processor architecture
130 /* Change the page protection of the allocated memory to executable,
132 if (!VirtualProtectEx (h_process, mbi.BaseAddress, size,
133 PAGE_EXECUTE_READWRITE, &dw_unused))
136 pmc->address = mbi.BaseAddress;
140 ResumeThread (pmc->h_thread);
146 free_process_memory (process_memory* pmc)
148 ResumeThread (pmc->h_thread);
152 * Run ROUTINE in the context of process determined by H_PROCESS. The
153 * routine is passed the address of DATA as parameter. The ROUTINE must
154 * not be longer than ROUTINE_CODE_SIZE bytes. DATA_SIZE is the size of
157 * Note that the code must be positionally independent, and compiled
158 * without stack checks (they cause implicit calls into CRT so will
159 * fail). DATA should not refer any data in calling process, as both
160 * routine and its data are copied into remote process. Size of data
161 * and code together should not exceed one page (4K on x86 systems).
163 * Return the value returned by ROUTINE, or (DWORD)-1 if call failed.
166 run_in_other_process (HANDLE h_process,
167 LPTHREAD_START_ROUTINE routine,
168 LPVOID data, size_t data_size)
171 const size_t code_size = FRAGMENT_CODE_SIZE;
172 /* Need at most 3 extra bytes of memory, for data alignment */
173 size_t total_size = code_size + data_size + 3;
178 /* Allocate memory */
179 if (!alloc_process_memory (h_process, total_size, &pm))
183 if (!WriteProcessMemory (h_process, pm.address, (LPVOID)routine,
190 remote_data = (LPBYTE)pm.address + ((code_size + 4) & ~3);
191 if (!WriteProcessMemory (h_process, remote_data, data, data_size, NULL))
197 /* Execute the remote copy of code, passing it remote data */
198 h_thread = CreateRemoteThread (h_process, NULL, 0,
199 (LPTHREAD_START_ROUTINE) pm.address,
200 remote_data, 0, &dw_unused);
201 if (h_thread == NULL)
204 /* Wait till thread finishes */
205 WaitForSingleObject (h_thread, INFINITE);
207 /* Free remote memory */
208 free_process_memory (&pm);
210 /* Return thread's exit code */
213 GetExitCodeThread (h_thread, &exit_code);
214 CloseHandle (h_thread);
219 free_process_memory (&pm);
223 /*-----------------------------------------------------------------------*/
224 /* Sending signals */
225 /*-----------------------------------------------------------------------*/
228 * We handle the following signals:
230 * SIGKILL, SIGTERM, SIGQUIT, SIGHUP - These four translate to ExitProcess
231 * executed by the remote process
232 * SIGINT - The remote process is sent CTRL_BREAK_EVENT
234 * The MSVC5.0 compiler feels free to re-order functions within a
235 * compilation unit, so we have no way of finding out the size of the
236 * following functions. Therefore these functions must not be larger than
237 * FRAGMENT_CODE_SIZE.
245 void (WINAPI *adr_ExitProcess) (UINT);
249 sigkill_proc (sigkill_data* data)
251 (*data->adr_ExitProcess)(255);
256 * Sending break or control c
260 BOOL (WINAPI *adr_GenerateConsoleCtrlEvent) (DWORD, DWORD);
265 sigint_proc (sigint_data* data)
267 return (*data->adr_GenerateConsoleCtrlEvent) (data->event, 0);
275 BOOL (WINAPI *adr_SetConsoleCtrlHandler) (LPVOID, BOOL);
279 sig_enable_proc (sig_enable_data* data)
281 (*data->adr_SetConsoleCtrlHandler) (NULL, FALSE);
286 * Send signal SIGNO to process H_PROCESS.
287 * Return nonzero if successful.
290 /* This code assigns a return value of GetProcAddress to function pointers
291 of many different types. Instead of heavy obscure casts, we just disable
292 warnings about assignments to different function pointer types. */
293 #pragma warning (disable : 4113)
296 send_signal (HANDLE h_process, int signo)
298 HMODULE h_kernel = GetModuleHandle ("kernel32");
301 assert (h_kernel != NULL);
311 d.adr_ExitProcess = GetProcAddress (h_kernel, "ExitProcess");
312 assert (d.adr_ExitProcess);
313 retval = run_in_other_process (h_process,
314 (LPTHREAD_START_ROUTINE)sigkill_proc,
321 d.adr_GenerateConsoleCtrlEvent =
322 GetProcAddress (h_kernel, "GenerateConsoleCtrlEvent");
323 assert (d.adr_GenerateConsoleCtrlEvent);
324 d.event = CTRL_C_EVENT;
325 retval = run_in_other_process (h_process,
326 (LPTHREAD_START_ROUTINE)sigint_proc,
334 return (int)retval > 0 ? 1 : 0;
338 * Enable CTRL_C_EVENT handling in a new child process
341 enable_child_signals (HANDLE h_process)
343 HMODULE h_kernel = GetModuleHandle ("kernel32");
346 assert (h_kernel != NULL);
347 d.adr_SetConsoleCtrlHandler =
348 GetProcAddress (h_kernel, "SetConsoleCtrlHandler");
349 assert (d.adr_SetConsoleCtrlHandler);
350 run_in_other_process (h_process, (LPTHREAD_START_ROUTINE)sig_enable_proc,
354 #pragma warning (default : 4113)
357 * Signal error if SIGNO is not supported
360 validate_signal_number (int signo)
362 if (signo != SIGKILL && signo != SIGTERM
363 && signo != SIGQUIT && signo != SIGINT
365 signal_simple_error ("Signal number not supported", make_int (signo));
368 /*-----------------------------------------------------------------------*/
369 /* Process methods */
370 /*-----------------------------------------------------------------------*/
373 * Allocate and initialize Lisp_Process->process_data
377 nt_alloc_process_data (Lisp_Process *p)
379 p->process_data = xnew_and_zero (struct nt_process_data);
383 nt_finalize_process_data (Lisp_Process *p, int for_disksave)
385 assert (!for_disksave);
386 if (NT_DATA(p)->h_process)
387 CloseHandle (NT_DATA(p)->h_process);
391 * Initialize XEmacs process implementation once
394 nt_init_process (void)
396 /* Initialize winsock */
398 /* Request Winsock v1.1 Note the order: (minor=1, major=1) */
399 WSAStartup (MAKEWORD (1,1), &wsa_data);
403 * Fork off a subprocess. P is a pointer to newly created subprocess
404 * object. If this function signals, the caller is responsible for
405 * deleting (and finalizing) the process object.
407 * The method must return PID of the new process, a (positive??? ####) number
408 * which fits into Lisp_Int. No return value indicates an error, the method
409 * must signal an error instead.
413 signal_cannot_launch (Lisp_Object image_file, DWORD err)
415 mswindows_set_errno (err);
416 signal_simple_error_2 ("Error starting", image_file, lisp_strerror (errno));
420 nt_create_process (Lisp_Process *p,
421 Lisp_Object *argv, int nargv,
422 Lisp_Object program, Lisp_Object cur_dir)
424 HANDLE hmyshove, hmyslurp, hprocin, hprocout, hprocerr;
426 BOOL do_io, windowed;
429 /* Find out whether the application is windowed or not */
431 /* SHGetFileInfo tends to return ERROR_FILE_NOT_FOUND on most
432 errors. This leads to bogus error message. */
434 char *p = strrchr ((char *)XSTRING_DATA (program), '.');
436 (stricmp (p, ".exe") == 0 ||
437 stricmp (p, ".com") == 0 ||
438 stricmp (p, ".bat") == 0 ||
439 stricmp (p, ".cmd") == 0))
441 image_type = SHGetFileInfo ((char *)XSTRING_DATA (program), 0,NULL,
446 char progname[MAX_PATH];
447 sprintf (progname, "%s.exe", (char *)XSTRING_DATA (program));
448 image_type = SHGetFileInfo (progname, 0, NULL, 0, SHGFI_EXETYPE);
451 signal_cannot_launch (program, (GetLastError () == ERROR_FILE_NOT_FOUND
452 ? ERROR_BAD_FORMAT : GetLastError ()));
453 windowed = HIWORD (image_type) != 0;
456 /* Decide whether to do I/O on process handles, or just mark the
457 process exited immediately upon successful launching. We do I/O if the
458 process is a console one, or if it is windowed but windowed_process_io
460 do_io = !windowed || windowed_process_io ;
464 /* Create two unidirectional named pipes */
466 SECURITY_ATTRIBUTES sa;
468 sa.nLength = sizeof(sa);
469 sa.bInheritHandle = TRUE;
470 sa.lpSecurityDescriptor = NULL;
472 CreatePipe (&hprocin, &hmyshove, &sa, 0);
473 CreatePipe (&hmyslurp, &hprocout, &sa, 0);
475 /* Duplicate the stdout handle for use as stderr */
476 DuplicateHandle(GetCurrentProcess(), hprocout, GetCurrentProcess(), &hprocerr,
477 0, TRUE, DUPLICATE_SAME_ACCESS);
479 /* Stupid Win32 allows to create a pipe with *both* ends either
480 inheritable or not. We need process ends inheritable, and local
481 ends not inheritable. */
482 DuplicateHandle (GetCurrentProcess(), hmyshove, GetCurrentProcess(), &htmp,
483 0, FALSE, DUPLICATE_CLOSE_SOURCE | DUPLICATE_SAME_ACCESS);
485 DuplicateHandle (GetCurrentProcess(), hmyslurp, GetCurrentProcess(), &htmp,
486 0, FALSE, DUPLICATE_CLOSE_SOURCE | DUPLICATE_SAME_ACCESS);
490 /* Convert an argv vector into Win32 style command line by a call to
491 lisp function `nt-quote-process-args' which see (in winnt.el)*/
494 Lisp_Object args_or_ret = Qnil;
497 GCPRO1 (args_or_ret);
499 for (i = 0; i < nargv; ++i)
500 args_or_ret = Fcons (*argv++, args_or_ret);
501 args_or_ret = Fnreverse (args_or_ret);
502 args_or_ret = Fcons (program, args_or_ret);
504 args_or_ret = call1 (Qnt_quote_process_args, args_or_ret);
506 if (!STRINGP (args_or_ret))
507 /* Luser wrote his/her own clever version */
508 error ("Bogus return value from `nt-quote-process-args'");
510 command_line = alloca_array (char, (XSTRING_LENGTH (program)
511 + XSTRING_LENGTH (args_or_ret) + 2));
512 strcpy (command_line, XSTRING_DATA (program));
513 strcat (command_line, " ");
514 strcat (command_line, XSTRING_DATA (args_or_ret));
516 UNGCPRO; /* args_or_ret */
519 /* Set `proc_env' to a nul-separated array of the strings in
520 Vprocess_environment terminated by 2 nuls. */
523 extern int compare_env (const char **strp1, const char **strp2);
525 REGISTER Lisp_Object tem;
526 REGISTER char **new_env;
527 REGISTER int new_length = 0, i, new_space;
530 for (tem = Vprocess_environment;
532 && STRINGP (XCAR (tem)));
536 /* new_length + 1 to include terminating 0. */
537 env = new_env = alloca_array (char *, new_length + 1);
539 /* Copy the Vprocess_environment strings into new_env. */
540 for (tem = Vprocess_environment;
542 && STRINGP (XCAR (tem)));
546 char *string = (char *) XSTRING_DATA (XCAR (tem));
547 /* See if this string duplicates any string already in the env.
548 If so, don't put it in.
549 When an env var has multiple definitions,
550 we keep the definition that comes first in process-environment. */
551 for (; ep != new_env; ep++)
553 char *p = *ep, *q = string;
557 /* The string is malformed; might as well drop it. */
571 /* Sort the environment variables */
572 new_length = new_env - env;
573 qsort (env, new_length, sizeof (char *), compare_env);
575 /* Work out how much space to allocate */
577 for (i = 0; i < new_length; i++)
579 new_space += strlen(env[i]) + 1;
583 /* Allocate space and copy variables into it */
584 penv = proc_env = (char*) alloca(new_space);
585 for (i = 0; i < new_length; i++)
587 strcpy(penv, env[i]);
588 penv += strlen(env[i]) + 1;
596 PROCESS_INFORMATION pi;
600 si.dwFlags = STARTF_USESHOWWINDOW;
601 si.wShowWindow = windowed ? SW_SHOWNORMAL : SW_HIDE;
604 si.hStdInput = hprocin;
605 si.hStdOutput = hprocout;
606 si.hStdError = hprocerr;
607 si.dwFlags |= STARTF_USESTDHANDLES;
610 err = (CreateProcess (NULL, command_line, NULL, NULL, TRUE,
611 CREATE_NEW_CONSOLE | CREATE_NEW_PROCESS_GROUP
613 proc_env, (char *) XSTRING_DATA (cur_dir), &si, &pi)
614 ? 0 : GetLastError ());
618 /* These just have been inherited; we do not need a copy */
619 CloseHandle (hprocin);
620 CloseHandle (hprocout);
621 CloseHandle (hprocerr);
624 /* Handle process creation failure */
629 CloseHandle (hmyshove);
630 CloseHandle (hmyslurp);
632 signal_cannot_launch (program, GetLastError ());
635 /* The process started successfully */
638 NT_DATA(p)->h_process = pi.hProcess;
639 init_process_io_handles (p, (void*)hmyslurp, (void*)hmyshove, 0);
643 /* Indicate as if the process has exited immediately. */
644 p->status_symbol = Qexit;
645 CloseHandle (pi.hProcess);
648 ResumeThread (pi.hThread);
649 CloseHandle (pi.hThread);
651 /* Remember to enable child signals later if this is not a windowed
652 app. Can't do it right now because that screws up the MKS Toolkit
656 NT_DATA(p)->need_enable_child_signals = 10;
657 kick_status_notify ();
660 return ((int)pi.dwProcessId);
665 * This method is called to update status fields of the process
666 * structure. If the process has not existed, this method is expected
669 * The method is called only for real child processes.
673 nt_update_status_if_terminated (Lisp_Process* p)
677 if (NT_DATA(p)->need_enable_child_signals > 1)
679 NT_DATA(p)->need_enable_child_signals -= 1;
680 kick_status_notify ();
682 else if (NT_DATA(p)->need_enable_child_signals == 1)
684 enable_child_signals(NT_DATA(p)->h_process);
685 NT_DATA(p)->need_enable_child_signals = 0;
688 if (GetExitCodeProcess (NT_DATA(p)->h_process, &exit_code)
689 && exit_code != STILL_ACTIVE)
693 /* The exit code can be a code returned by process, or an
694 NTSTATUS value. We cannot accurately handle the latter since
695 it is a full 32 bit integer */
696 if (exit_code & 0xC0000000)
698 p->status_symbol = Qsignal;
699 p->exit_code = exit_code & 0x1FFFFFFF;
703 p->status_symbol = Qexit;
704 p->exit_code = exit_code;
710 * Stuff the entire contents of LSTREAM to the process output pipe
713 /* #### If only this function could be somehow merged with
714 unix_send_process... */
717 nt_send_process (Lisp_Object proc, struct lstream* lstream)
719 volatile Lisp_Object vol_proc = proc;
720 Lisp_Process *volatile p = XPROCESS (proc);
722 /* use a reasonable-sized buffer (somewhere around the size of the
723 stream buffer) so as to avoid inundating the stream with blocked
725 Bufbyte chunkbuf[128];
732 chunklen = Lstream_read (lstream, chunkbuf, 128);
734 break; /* perhaps should abort() if < 0?
735 This should never happen. */
737 /* Lstream_write() will never successfully write less than the
738 amount sent in. In the worst case, it just buffers the
740 writeret = Lstream_write (XLSTREAM (DATA_OUTSTREAM(p)), chunkbuf,
742 Lstream_flush (XLSTREAM (DATA_OUTSTREAM(p)));
745 p->status_symbol = Qexit;
746 p->exit_code = ERROR_BROKEN_PIPE;
750 deactivate_process (*((Lisp_Object *) (&vol_proc)));
751 error ("Broken pipe error sending to process %s; closed it",
752 XSTRING_DATA (p->name));
757 while (Lstream_was_blocked_p (XLSTREAM (p->pipe_outstream)))
759 /* Buffer is full. Wait, accepting input; that may allow
760 the program to finish doing output and read more. */
761 Faccept_process_output (Qnil, Qzero, make_int (wait_ms));
762 Lstream_flush (XLSTREAM (p->pipe_outstream));
763 wait_ms = min (1000, 2 * wait_ms);
770 * Send a signal number SIGNO to PROCESS.
771 * CURRENT_GROUP means send to the process group that currently owns
772 * the terminal being used to communicate with PROCESS.
773 * This is used for various commands in shell mode.
774 * If NOMSG is zero, insert signal-announcements into process's buffers
777 * If we can, we try to signal PROCESS by sending control characters
778 * down the pty. This allows us to signal inferiors who have changed
779 * their uid, for which killpg would return an EPERM error.
781 * The method signals an error if the given SIGNO is not valid
785 nt_kill_child_process (Lisp_Object proc, int signo,
786 int current_group, int nomsg)
788 Lisp_Process *p = XPROCESS (proc);
790 /* Enable child signals if necessary. This may lose the first
791 but it's better than nothing. */
792 if (NT_DATA(p)->need_enable_child_signals > 0)
794 enable_child_signals(NT_DATA(p)->h_process);
795 NT_DATA(p)->need_enable_child_signals = 0;
798 /* Signal error if SIGNO cannot be sent */
799 validate_signal_number (signo);
802 if (!send_signal (NT_DATA(p)->h_process, signo))
803 error ("Cannot send signal to process");
807 * Kill any process in the system given its PID.
809 * Returns zero if a signal successfully sent, or
810 * negative number upon failure
813 nt_kill_process_by_pid (int pid, int signo)
818 /* Signal error if SIGNO cannot be sent */
819 validate_signal_number (signo);
821 /* Try to open the process with required privileges */
822 h_process = OpenProcess (PROCESS_CREATE_THREAD
823 | PROCESS_QUERY_INFORMATION
824 | PROCESS_VM_OPERATION
827 if (h_process == NULL)
830 send_result = send_signal (h_process, signo);
832 CloseHandle (h_process);
834 return send_result ? 0 : -1;
837 /*-----------------------------------------------------------------------*/
838 /* Sockets connections */
839 /*-----------------------------------------------------------------------*/
842 /* #### Hey MS, how long Winsock 2 for '95 will be in beta? */
844 #define SOCK_TIMER_ID 666
845 #define XM_SOCKREPLY (WM_USER + 666)
848 get_internet_address (Lisp_Object host, struct sockaddr_in *address,
851 char buf [MAXGETHOSTSTRUCT];
856 address->sin_family = AF_INET;
858 /* First check if HOST is already a numeric address */
860 unsigned long inaddr = inet_addr (XSTRING_DATA (host));
861 if (inaddr != INADDR_NONE)
863 address->sin_addr.s_addr = inaddr;
868 /* Create a window which will receive completion messages */
869 hwnd = CreateWindow ("STATIC", NULL, WS_OVERLAPPED, 0, 0, 1, 1,
870 NULL, NULL, NULL, NULL);
873 /* Post name resolution request */
874 hasync = WSAAsyncGetHostByName (hwnd, XM_SOCKREPLY, XSTRING_DATA (host),
879 /* Set a timer to poll for quit every 250 ms */
880 SetTimer (hwnd, SOCK_TIMER_ID, 250, NULL);
885 GetMessage (&msg, hwnd, 0, 0);
886 if (msg.message == XM_SOCKREPLY)
888 /* Ok, got an answer */
889 if (WSAGETASYNCERROR(msg.lParam) == NO_ERROR)
893 warn_when_safe(Qstream, Qwarning,
894 "cannot get IP address for host \"%s\"",
895 XSTRING_DATA (host));
899 else if (msg.message == WM_TIMER && msg.wParam == SOCK_TIMER_ID)
903 WSACancelAsyncRequest (hasync);
904 KillTimer (hwnd, SOCK_TIMER_ID);
905 DestroyWindow (hwnd);
909 DispatchMessage (&msg);
913 KillTimer (hwnd, SOCK_TIMER_ID);
914 DestroyWindow (hwnd);
917 /* BUF starts with struct hostent */
918 struct hostent* he = (struct hostent*) buf;
919 address->sin_addr.s_addr = *(unsigned long*)he->h_addr_list[0];
925 nt_canonicalize_host_name (Lisp_Object host)
927 struct sockaddr_in address;
929 if (!get_internet_address (host, &address, ERROR_ME_NOT))
932 if (address.sin_family == AF_INET)
933 return build_string (inet_ntoa (address.sin_addr));
938 /* open a TCP network connection to a given HOST/SERVICE. Treated
939 exactly like a normal process when reading and writing. Only
940 differences are in status display and process deletion. A network
941 connection has no PID; you cannot signal it. All you can do is
942 deactivate and close it via delete-process */
945 nt_open_network_stream (Lisp_Object name, Lisp_Object host, Lisp_Object service,
946 Lisp_Object protocol, void** vinfd, void** voutfd)
948 struct sockaddr_in address;
955 if (!EQ (protocol, Qtcp))
956 error ("Unsupported protocol \"%s\"",
957 string_data (symbol_name (XSYMBOL (protocol))));
960 port = htons ((unsigned short) XINT (service));
963 struct servent *svc_info;
964 CHECK_STRING (service);
965 svc_info = getservbyname ((char *) XSTRING_DATA (service), "tcp");
967 error ("Unknown service \"%s\"", XSTRING_DATA (service));
968 port = svc_info->s_port;
971 get_internet_address (host, &address, ERROR_ME);
972 address.sin_port = port;
974 s = socket (address.sin_family, SOCK_STREAM, 0);
976 report_file_error ("error creating socket", list1 (name));
978 /* We don't want to be blocked on connect */
980 unsigned long nonblock = 1;
981 ioctlsocket (s, FIONBIO, &nonblock);
984 retval = connect (s, (struct sockaddr *) &address, sizeof (address));
985 if (retval != NO_ERROR && WSAGetLastError() != WSAEWOULDBLOCK)
987 /* Wait while connection is established */
1000 /* Poll for quit every 250 ms */
1002 tv.tv_usec = 250 * 1000;
1006 nsel = select (0, NULL, &fdset, &fdset, &tv);
1010 /* Check: was connection successful or not? */
1012 nsel = select (0, NULL, NULL, &fdset, &tv);
1014 goto connect_failed;
1020 /* We are connected at this point */
1022 DuplicateHandle (GetCurrentProcess(), (HANDLE)s,
1023 GetCurrentProcess(), (LPHANDLE)voutfd,
1024 0, FALSE, DUPLICATE_SAME_ACCESS);
1029 if (INTP (service)) {
1030 warn_when_safe(Qstream, Qwarning,
1031 "failure to open network stream to host \"%s\" for service \"%d\"",
1032 XSTRING_DATA (host),
1033 (unsigned short) XINT (service));
1036 warn_when_safe(Qstream, Qwarning,
1037 "failure to open network stream to host \"%s\" for service \"%s\"",
1038 XSTRING_DATA (host),
1039 XSTRING_DATA (service));
1041 report_file_error ("connection failed", list2 (host, name));
1046 /*-----------------------------------------------------------------------*/
1047 /* Initialization */
1048 /*-----------------------------------------------------------------------*/
1051 process_type_create_nt (void)
1053 PROCESS_HAS_METHOD (nt, alloc_process_data);
1054 PROCESS_HAS_METHOD (nt, finalize_process_data);
1055 PROCESS_HAS_METHOD (nt, init_process);
1056 PROCESS_HAS_METHOD (nt, create_process);
1057 PROCESS_HAS_METHOD (nt, update_status_if_terminated);
1058 PROCESS_HAS_METHOD (nt, send_process);
1059 PROCESS_HAS_METHOD (nt, kill_child_process);
1060 PROCESS_HAS_METHOD (nt, kill_process_by_pid);
1062 PROCESS_HAS_METHOD (nt, canonicalize_host_name);
1063 PROCESS_HAS_METHOD (nt, open_network_stream);
1064 #ifdef HAVE_MULTICAST
1065 #error I won't do this until '95 has winsock2
1066 PROCESS_HAS_METHOD (nt, open_multicast_group);
1072 syms_of_process_nt (void)
1074 defsymbol (&Qnt_quote_process_args, "nt-quote-process-args");
1078 vars_of_process_nt (void)