From b9fbe9492e000511d0b2b7db6b81c0fc98ab6f80 Mon Sep 17 00:00:00 2001 From: cvs2svn <> Date: Sun, 22 Sep 2002 12:04:16 +0000 Subject: This commit was manufactured by cvs2svn to create tag 'Z -cygwin_daemon_merge-new_HEAD'. Sprout from cygwin_daemon 2002-01-02 00:06:36 UTC cvs2svn 'This commit was manufactured by cvs2svn to create branch 'cygwin_daemon'.' Cherrypick from cygwin_daemon 2002-02-25 17:47:52 UTC cvs2svn 'This commit was manufactured by cvs2svn to create branch 'cygwin_daemon'.': winsup/cygwin/how-spawn-works.txt winsup/cygwin/wsock_event.h Cherrypick from cygwin_daemon 2002-06-06 15:35:10 UTC cvs2svn 'This commit was manufactured by cvs2svn to create branch 'cygwin_daemon'.': winsup/cygwin/include/netinet/udp.h winsup/cygwin/stackdump.sgml Cherrypick from cygwin_daemon 2002-01-17 10:39:38 UTC cvs2svn 'This commit was manufactured by cvs2svn to create branch 'cygwin_daemon'.': winsup/cygwin/libc/fnmatch.c Cherrypick from cygwin_daemon 2002-07-03 20:31:40 UTC cvs2svn 'This commit was manufactured by cvs2svn to create branch 'cygwin_daemon'.': winsup/cygwin/include/sys/statfs.h Cherrypick from cygwin_daemon 2002-09-04 15:17:25 UTC cvs2svn 'This commit was manufactured by cvs2svn to create branch 'cygwin_daemon'.': winsup/cygwin/how-autoload-works.txt Cherrypick from master 2002-09-22 12:04:15 UTC Conrad Scott '2002-09-22 Conrad Scott ': winsup/cygserver/threaded_queue.cc winsup/cygserver/woutsup.h winsup/cygwin/CYGWIN_LICENSE winsup/cygwin/ChangeLog winsup/cygwin/ChangeLog-1998 winsup/cygwin/ChangeLog-1999 winsup/cygwin/ChangeLog-2000 winsup/cygwin/Makefile.in winsup/cygwin/assert.cc winsup/cygwin/autoload.cc winsup/cygwin/child_info.h winsup/cygwin/configure winsup/cygwin/configure.in winsup/cygwin/cygerrno.h winsup/cygwin/cygheap.cc winsup/cygwin/cygheap.h winsup/cygwin/cygmagic winsup/cygwin/cygmalloc.h winsup/cygwin/cygrun.c winsup/cygwin/cygserver.cc winsup/cygwin/cygserver_client.cc winsup/cygwin/cygserver_ipc.h winsup/cygwin/cygserver_process.cc winsup/cygwin/cygserver_shm.cc winsup/cygwin/cygserver_shm.h winsup/cygwin/cygserver_transport.cc winsup/cygwin/cygserver_transport_pipes.cc winsup/cygwin/cygserver_transport_sockets.cc winsup/cygwin/cygthread.cc winsup/cygwin/cygthread.h winsup/cygwin/cygwin.din winsup/cygwin/cygwin.sc winsup/cygwin/dcrt0.cc winsup/cygwin/debug.cc winsup/cygwin/debug.h winsup/cygwin/dir.cc winsup/cygwin/dlfcn.cc winsup/cygwin/dll_init.cc winsup/cygwin/dll_init.h winsup/cygwin/dlmalloc.c winsup/cygwin/dtable.cc winsup/cygwin/dtable.h winsup/cygwin/environ.cc winsup/cygwin/environ.h winsup/cygwin/errno.cc winsup/cygwin/exceptions.cc winsup/cygwin/exec.cc winsup/cygwin/external.cc winsup/cygwin/fcntl.cc winsup/cygwin/fhandler.cc winsup/cygwin/fhandler.h winsup/cygwin/fhandler_clipboard.cc winsup/cygwin/fhandler_console.cc winsup/cygwin/fhandler_disk_file.cc winsup/cygwin/fhandler_dsp.cc winsup/cygwin/fhandler_floppy.cc winsup/cygwin/fhandler_mem.cc winsup/cygwin/fhandler_proc.cc winsup/cygwin/fhandler_process.cc winsup/cygwin/fhandler_random.cc winsup/cygwin/fhandler_raw.cc winsup/cygwin/fhandler_registry.cc winsup/cygwin/fhandler_serial.cc winsup/cygwin/fhandler_socket.cc winsup/cygwin/fhandler_tape.cc winsup/cygwin/fhandler_termios.cc winsup/cygwin/fhandler_tty.cc winsup/cygwin/fhandler_virtual.cc winsup/cygwin/fhandler_windows.cc winsup/cygwin/fhandler_zero.cc winsup/cygwin/fork.cc winsup/cygwin/glob.c winsup/cygwin/gmon.c winsup/cygwin/grp.cc winsup/cygwin/heap.cc winsup/cygwin/heap.h winsup/cygwin/hires.h winsup/cygwin/how-cygheap-works.txt winsup/cygwin/how-fhandlers-work.txt winsup/cygwin/how-signals-work.txt winsup/cygwin/how-to-debug-cygwin.txt winsup/cygwin/include/cygwin/acl.h winsup/cygwin/include/cygwin/cygserver.h winsup/cygwin/include/cygwin/cygserver_process.h winsup/cygwin/include/cygwin/cygserver_transport.h winsup/cygwin/include/cygwin/cygserver_transport_pipes.h winsup/cygwin/include/cygwin/cygserver_transport_sockets.h winsup/cygwin/include/cygwin/grp.h winsup/cygwin/include/cygwin/if.h winsup/cygwin/include/cygwin/ipc.h winsup/cygwin/include/cygwin/msg.h winsup/cygwin/include/cygwin/mtio.h winsup/cygwin/include/cygwin/sem.h winsup/cygwin/include/cygwin/shm.h winsup/cygwin/include/cygwin/socket.h winsup/cygwin/include/cygwin/stat.h winsup/cygwin/include/cygwin/types.h winsup/cygwin/include/cygwin/version.h winsup/cygwin/include/fnmatch.h winsup/cygwin/include/getopt.h winsup/cygwin/include/glob.h winsup/cygwin/include/limits.h winsup/cygwin/include/netdb.h winsup/cygwin/include/netinet/ip.h winsup/cygwin/include/netinet/tcp.h winsup/cygwin/include/pthread.h winsup/cygwin/include/sys/cygwin.h winsup/cygwin/include/sys/ioctl.h winsup/cygwin/include/sys/mount.h winsup/cygwin/include/sys/resource.h winsup/cygwin/include/sys/socket.h winsup/cygwin/include/sys/soundcard.h winsup/cygwin/include/sys/strace.h winsup/cygwin/include/sys/sysmacros.h winsup/cygwin/include/sys/termios.h winsup/cygwin/include/sys/uio.h winsup/cygwin/include/sys/un.h winsup/cygwin/include/sys/vfs.h winsup/cygwin/init.cc winsup/cygwin/ioctl.cc winsup/cygwin/ipc.cc winsup/cygwin/lib/cygwin_crt0.c winsup/cygwin/lib/dll_main.cc winsup/cygwin/lib/getopt.c winsup/cygwin/localtime.cc winsup/cygwin/malloc.cc winsup/cygwin/malloc_wrapper.cc winsup/cygwin/miscfuncs.cc winsup/cygwin/mkvers.sh winsup/cygwin/mmap.cc winsup/cygwin/msg.cc winsup/cygwin/net.cc winsup/cygwin/ntdll.h winsup/cygwin/ntea.cc winsup/cygwin/passwd.cc winsup/cygwin/path.cc winsup/cygwin/path.h winsup/cygwin/perthread.h winsup/cygwin/pinfo.cc winsup/cygwin/pinfo.h winsup/cygwin/pipe.cc winsup/cygwin/poll.cc winsup/cygwin/pthread.cc winsup/cygwin/pwdgrp.h winsup/cygwin/regex/regcomp.c winsup/cygwin/registry.cc winsup/cygwin/resource.cc winsup/cygwin/safe_memory.h winsup/cygwin/sched.cc winsup/cygwin/sec_acl.cc winsup/cygwin/sec_helper.cc winsup/cygwin/security.cc winsup/cygwin/security.h winsup/cygwin/select.cc winsup/cygwin/sem.cc winsup/cygwin/shared.cc winsup/cygwin/shared_info.h winsup/cygwin/shm.cc winsup/cygwin/signal.cc winsup/cygwin/sigproc.cc winsup/cygwin/sigproc.h winsup/cygwin/smallprint.c winsup/cygwin/spawn.cc winsup/cygwin/speclib winsup/cygwin/strace.cc winsup/cygwin/sync.cc winsup/cygwin/sync.h winsup/cygwin/syscalls.cc winsup/cygwin/sysconf.cc winsup/cygwin/syslog.cc winsup/cygwin/termios.cc winsup/cygwin/thread.cc winsup/cygwin/thread.h winsup/cygwin/threaded_queue.cc winsup/cygwin/threaded_queue.h winsup/cygwin/times.cc winsup/cygwin/tty.cc winsup/cygwin/tty.h winsup/cygwin/uinfo.cc winsup/cygwin/uname.cc winsup/cygwin/wait.cc winsup/cygwin/winbase.h winsup/cygwin/wincap.cc winsup/cygwin/wincap.h winsup/cygwin/window.cc winsup/cygwin/winsup.h winsup/cygwin/winver.rc winsup/cygwin/woutsup.h Delete: winsup/cygwin/include/cygwin/ip.h winsup/cygwin/include/sys/ipc.h winsup/cygwin/include/sys/shm.h winsup/cygwin/include/wchar.h winsup/cygwin/lib/_cygwin_S_IEXEC.cc winsup/cygwin/regexp/regerror.c winsup/cygwin/regexp/regexp.3 winsup/cygwin/regexp/regexp.c winsup/cygwin/regexp/regsub.c winsup/cygwin/shortcut.c winsup/cygwin/shortcut.h winsup/cygwin/test.c --- winsup/cygwin/cygserver_transport_pipes.cc | 390 ++++++++++++++++++++--------- 1 file changed, 278 insertions(+), 112 deletions(-) (limited to 'winsup/cygwin/cygserver_transport_pipes.cc') diff --git a/winsup/cygwin/cygserver_transport_pipes.cc b/winsup/cygwin/cygserver_transport_pipes.cc index d9accce1e..f318a7592 100755 --- a/winsup/cygwin/cygserver_transport_pipes.cc +++ b/winsup/cygwin/cygserver_transport_pipes.cc @@ -1,197 +1,363 @@ /* cygserver_transport_pipes.cc - Copyright 2001 Red Hat Inc. + Copyright 2001, 2002 Red Hat Inc. Written by Robert Collins - This file is part of Cygwin. +This file is part of Cygwin. - This software is a copyrighted work licensed under the terms of the - Cygwin license. Please consult the file "CYGWIN_LICENSE" for - details. */ +This software is a copyrighted work licensed under the terms of the +Cygwin license. Please consult the file "CYGWIN_LICENSE" for +details. */ + +/* to allow this to link into cygwin and the .dll, a little magic is needed. */ +#ifdef __OUTSIDE_CYGWIN__ +#include "woutsup.h" +#else +#include "winsup.h" +#endif -#include -#include -#include -#include #include -#include + +#include +#include #include -#include "wincap.h" +#include +#include + +#include "cygerrno.h" #include "cygwin/cygserver_transport.h" #include "cygwin/cygserver_transport_pipes.h" -/* to allow this to link into cygwin and the .dll, a little magic is needed. */ -#ifndef __OUTSIDE_CYGWIN__ -#include "winsup.h" -#else -#define DEBUG 0 -#define debug_printf if (DEBUG) printf +#ifndef __INSIDE_CYGWIN__ +#include "cygwin/cygserver.h" #endif -transport_layer_pipes::transport_layer_pipes (HANDLE new_pipe) +enum + { + MAX_WAIT_NAMED_PIPE_RETRY = 64, + WAIT_NAMED_PIPE_TIMEOUT = 10 // milliseconds + }; + +#ifndef __INSIDE_CYGWIN__ + +static pthread_once_t pipe_instance_lock_once = PTHREAD_ONCE_INIT; +static CRITICAL_SECTION pipe_instance_lock; +static long pipe_instance = 0; + +static void +initialise_pipe_instance_lock () { - pipe = new_pipe; - if (inited != true) - init_security(); -}; + assert (pipe_instance == 0); + InitializeCriticalSection (&pipe_instance_lock); +} + +#endif /* !__INSIDE_CYGWIN__ */ + +#ifndef __INSIDE_CYGWIN__ -transport_layer_pipes::transport_layer_pipes () +transport_layer_pipes::transport_layer_pipes (const HANDLE hPipe) + : _pipe_name (""), + _hPipe (hPipe), + _is_accepted_endpoint (true), + _is_listening_endpoint (false) { - pipe = NULL; - strcpy(pipe_name, "\\\\.\\pipe\\cygwin_lpc"); - if (inited != true) - init_security(); + assert (_hPipe); + assert (_hPipe != INVALID_HANDLE_VALUE); + + init_security (); } +#endif /* !__INSIDE_CYGWIN__ */ + +transport_layer_pipes::transport_layer_pipes () + : _pipe_name ("\\\\.\\pipe\\cygwin_lpc"), + _hPipe (NULL), + _is_accepted_endpoint (false), + _is_listening_endpoint (false) +{ + init_security (); +} void -transport_layer_pipes::init_security() +transport_layer_pipes::init_security () { + assert (wincap.has_security ()); + /* FIXME: pthread_once or equivalent needed */ - InitializeSecurityDescriptor (&sd, SECURITY_DESCRIPTOR_REVISION); - SetSecurityDescriptorDacl (&sd, TRUE, 0, FALSE); - - sec_none_nih.nLength = sec_all_nih.nLength = sizeof (SECURITY_ATTRIBUTES); - sec_none_nih.bInheritHandle = sec_all_nih.bInheritHandle = FALSE; - sec_none_nih.lpSecurityDescriptor = NULL; - sec_all_nih.lpSecurityDescriptor = &sd; - inited = true; + + InitializeSecurityDescriptor (&_sd, SECURITY_DESCRIPTOR_REVISION); + SetSecurityDescriptorDacl (&_sd, TRUE, NULL, FALSE); + + _sec_all_nih.nLength = sizeof (SECURITY_ATTRIBUTES); + _sec_all_nih.lpSecurityDescriptor = &_sd; + _sec_all_nih.bInheritHandle = FALSE; } -void +transport_layer_pipes::~transport_layer_pipes () +{ + close (); +} + +#ifndef __INSIDE_CYGWIN__ + +int transport_layer_pipes::listen () { + assert (!_hPipe); + assert (!_is_accepted_endpoint); + assert (!_is_listening_endpoint); + + _is_listening_endpoint = true; + /* no-op */ + return 0; } class transport_layer_pipes * -transport_layer_pipes::accept () +transport_layer_pipes::accept (bool *const recoverable) { - if (pipe) + assert (!_hPipe); + assert (!_is_accepted_endpoint); + assert (_is_listening_endpoint); + + pthread_once (&pipe_instance_lock_once, &initialise_pipe_instance_lock); + + EnterCriticalSection (&pipe_instance_lock); + + // Read: http://www.securityinternals.com/research/papers/namedpipe.php + // See also the Microsoft security bulletins MS00-053 and MS01-031. + + // FIXME: Remove FILE_CREATE_PIPE_INSTANCE. + + const bool first_instance = (pipe_instance == 0); + + const HANDLE accept_pipe = + CreateNamedPipe (_pipe_name, + (PIPE_ACCESS_DUPLEX + | (first_instance ? FILE_FLAG_FIRST_PIPE_INSTANCE : 0)), + (PIPE_TYPE_BYTE | PIPE_WAIT), + PIPE_UNLIMITED_INSTANCES, + 0, 0, 1000, + &_sec_all_nih); + + const bool duplicate = (accept_pipe == INVALID_HANDLE_VALUE + && pipe_instance == 0 + && GetLastError () == ERROR_ACCESS_DENIED); + + if (accept_pipe != INVALID_HANDLE_VALUE) + InterlockedIncrement (&pipe_instance); + + LeaveCriticalSection (&pipe_instance_lock); + + if (duplicate) { - debug_printf ("Already have a pipe in this %p\n",this); + *recoverable = false; + system_printf ("failed to create named pipe: " + "is the daemon already running?"); return NULL; } - pipe = CreateNamedPipe (pipe_name, - PIPE_ACCESS_DUPLEX, - PIPE_TYPE_BYTE | PIPE_WAIT, - PIPE_UNLIMITED_INSTANCES, - 0, 0, 1000, - &sec_all_nih ); - if (pipe == INVALID_HANDLE_VALUE) + if (accept_pipe == INVALID_HANDLE_VALUE) { - debug_printf ("error creating pipe (%lu)\n.", GetLastError ()); + debug_printf ("error creating pipe (%lu).", GetLastError ()); + *recoverable = true; // FIXME: case analysis? return NULL; } - if ( !ConnectNamedPipe ( pipe, NULL ) && - GetLastError () != ERROR_PIPE_CONNECTED) + assert (accept_pipe); + + if (!ConnectNamedPipe (accept_pipe, NULL) + && GetLastError () != ERROR_PIPE_CONNECTED) { - printf ("error connecting to pipe (%lu)\n.", GetLastError ()); - CloseHandle (pipe); - pipe = NULL; + debug_printf ("error connecting to pipe (%lu)\n.", GetLastError ()); + (void) CloseHandle (accept_pipe); + *recoverable = true; // FIXME: case analysis? return NULL; } - - transport_layer_pipes *new_conn = new transport_layer_pipes (pipe); - pipe = NULL; - return new_conn; + return safe_new (transport_layer_pipes, accept_pipe); } +#endif /* !__INSIDE_CYGWIN__ */ + void -transport_layer_pipes::close() +transport_layer_pipes::close () { - if (pipe && pipe != INVALID_HANDLE_VALUE) + // verbose: debug_printf ("closing pipe %p", _hPipe); + + if (_hPipe) { - FlushFileBuffers (pipe); - DisconnectNamedPipe (pipe); - CloseHandle (pipe); + assert (_hPipe != INVALID_HANDLE_VALUE); + +#ifndef __INSIDE_CYGWIN__ + + if (_is_accepted_endpoint) + { + (void) FlushFileBuffers (_hPipe); // Blocks until client reads. + (void) DisconnectNamedPipe (_hPipe); + EnterCriticalSection (&pipe_instance_lock); + (void) CloseHandle (_hPipe); + assert (pipe_instance > 0); + InterlockedDecrement (&pipe_instance); + LeaveCriticalSection (&pipe_instance_lock); + } + else + (void) CloseHandle (_hPipe); + +#else /* __INSIDE_CYGWIN__ */ + + assert (!_is_accepted_endpoint); + (void) ForceCloseHandle (_hPipe); + +#endif /* __INSIDE_CYGWIN__ */ + + _hPipe = NULL; } } ssize_t -transport_layer_pipes::read (char *buf, size_t len) +transport_layer_pipes::read (void *const buf, const size_t len) { - DWORD bytes_read, rc; - if (!pipe || pipe == INVALID_HANDLE_VALUE) - return -1; + // verbose: debug_printf ("reading from pipe %p", _hPipe); + + assert (_hPipe); + assert (_hPipe != INVALID_HANDLE_VALUE); + assert (!_is_listening_endpoint); - rc = ReadFile (pipe, buf, len, &bytes_read, NULL); - if (!rc) + DWORD count; + if (!ReadFile (_hPipe, buf, len, &count, NULL)) { - debug_printf ("error reading from pipe (%lu)\n", GetLastError ()); + debug_printf ("error reading from pipe (%lu)", GetLastError ()); + set_errno (EINVAL); // FIXME? return -1; } - return bytes_read; + + return count; } ssize_t -transport_layer_pipes::write (char *buf, size_t len) +transport_layer_pipes::write (void *const buf, const size_t len) { - DWORD bytes_written, rc; - if (!pipe || pipe == INVALID_HANDLE_VALUE) - return -1; + // verbose: debug_printf ("writing to pipe %p", _hPipe); + + assert (_hPipe); + assert (_hPipe != INVALID_HANDLE_VALUE); + assert (!_is_listening_endpoint); - rc = WriteFile (pipe, buf, len, &bytes_written, NULL); - if (!rc) + DWORD count; + if (!WriteFile (_hPipe, buf, len, &count, NULL)) { - debug_printf ("error writing to pipe (%lu)\n", GetLastError ()); + debug_printf ("error writing to pipe, error = %lu", GetLastError ()); + set_errno (EINVAL); // FIXME? return -1; } - return bytes_written; + + return count; } -bool +/* + * This routine holds a static variable, assume_cygserver, that is set + * if the transport has good reason to think that cygserver is + * running, i.e. if if successfully connected to it with the previous + * attempt. If this is set, the code tries a lot harder to get a + * connection, making the assumption that any failures are just + * congestion and overloading problems. + */ + +int transport_layer_pipes::connect () { - if (pipe && pipe != INVALID_HANDLE_VALUE) - { - debug_printf ("Already have a pipe in this %p\n",this); - return false; - } + assert (!_hPipe); + assert (!_is_accepted_endpoint); + assert (!_is_listening_endpoint); + + static bool assume_cygserver = false; + + BOOL rc = TRUE; + int retries = 0; - while (1) + while (rc) { - pipe = CreateFile (pipe_name, - GENERIC_READ | GENERIC_WRITE, - FILE_SHARE_READ | FILE_SHARE_WRITE, - &sec_all_nih, - OPEN_EXISTING, - 0, NULL); - - if (pipe != INVALID_HANDLE_VALUE) - /* got the pipe */ - return true; - - if (GetLastError () != ERROR_PIPE_BUSY) - { - debug_printf ("Error opening the pipe (%lu)\n", GetLastError ()); - pipe = NULL; - return false; - } - if (!WaitNamedPipe (pipe_name, 20000)) - debug_printf ( "error connecting to server pipe after 20 seconds (%lu)\n", GetLastError () ); - /* We loop here, because the pipe exists but is busy. If it doesn't exist - * the != ERROR_PIPE_BUSY will catch it. - */ + _hPipe = CreateFile (_pipe_name, + GENERIC_READ | GENERIC_WRITE, + FILE_SHARE_READ | FILE_SHARE_WRITE, + &_sec_all_nih, + OPEN_EXISTING, + SECURITY_IMPERSONATION, + NULL); + + if (_hPipe != INVALID_HANDLE_VALUE) + { + assert (_hPipe); +#ifdef __INSIDE_CYGWIN__ + ProtectHandle (_hPipe); +#endif + assume_cygserver = true; + return 0; + } + + _hPipe = NULL; + + if (!assume_cygserver && GetLastError () != ERROR_PIPE_BUSY) + { + debug_printf ("Error opening the pipe (%lu)", GetLastError ()); + return -1; + } + + /* Note: `If no instances of the specified named pipe exist, the + * WaitNamedPipe function returns immediately, regardless of the + * time-out value.' Thus the explicit Sleep if the call fails + * with ERROR_FILE_NOT_FOUND. + */ + while (retries != MAX_WAIT_NAMED_PIPE_RETRY + && !(rc = WaitNamedPipe (_pipe_name, WAIT_NAMED_PIPE_TIMEOUT))) + { + if (GetLastError () == ERROR_FILE_NOT_FOUND) + Sleep (0); // Give the server a chance. + + retries += 1; + } } + + assert (retries == MAX_WAIT_NAMED_PIPE_RETRY); + + system_printf ("lost connection to cygserver, error = %lu", + GetLastError ()); + + assume_cygserver = false; + + return -1; } +#ifndef __INSIDE_CYGWIN__ + void transport_layer_pipes::impersonate_client () { - if (pipe && pipe != INVALID_HANDLE_VALUE) - ImpersonateNamedPipeClient (pipe); - debug_printf("I am who you are\n"); + assert (_hPipe); + assert (_hPipe != INVALID_HANDLE_VALUE); + assert (_is_accepted_endpoint); + + // verbose: debug_printf ("impersonating pipe %p", _hPipe); + if (_hPipe) + { + assert (_hPipe != INVALID_HANDLE_VALUE); + + if (!ImpersonateNamedPipeClient (_hPipe)) + debug_printf ("Failed to Impersonate the client, (%lu)", + GetLastError ()); + } + // verbose: debug_printf ("I am who you are"); } void transport_layer_pipes::revert_to_self () { - RevertToSelf (); - debug_printf("I am who I yam\n"); + assert (_is_accepted_endpoint); + + RevertToSelf (); + // verbose: debug_printf ("I am who I yam"); } +#endif /* !__INSIDE_CYGWIN__ */ -- cgit v1.2.3