diff --git a/winsup/cygwin/ChangeLog b/winsup/cygwin/ChangeLog index 98a5b7039..fbb75b33e 100644 --- a/winsup/cygwin/ChangeLog +++ b/winsup/cygwin/ChangeLog @@ -1,3 +1,44 @@ +Thu Oct 26 11:51:59 2000 Corinna Vinschen + + * dtable.cc (dtable::release): Check for socket. Change + cnt_need_fixup_before accordingly. + (dtable::dup2): Ditto. + (dtable::fixup_before_fork): New method. + (dtable::fixup_before_exec): Ditto. + * dtable.h (class dtable): Add member `cnt_need_fixup_before'. Add + definition for methods `dec_need_fixup_before', `inc_need_fixup_before', + `need_fixup_before', `fixup_before_exec' and `fixup_before_fork'. + * fhandler.h (class fhandler_base): Slight rearrangements. Add + definitions for methods `fixup_before_fork_exec'. + (class fhandler_socket): Eliminate superfluous constructor. + Add member `prot_info_ptr'. Add destructor. Add definitions for + methods `dup', `fixup_before_fork_exec', `fixup_after_fork' and + `fixup_after_exec'. + * fork.cc (fork_parent): Care for file types which need a fixup + before fork. Start child in suspended state then. + * net.cc: New global variable `ws2_32_handle' and `wsadata'. + (fdsock): Check for Winsock version. Call `set_socket_inheritance' + only if Winsock version < 2.0. Care for `need_fixup' count in fdtab. + (cygwin_socket): Eliminate call to `set_socket_inheritance'. + (cygwin_accept): Ditto. + (cygwin_rcmd): Ditto. + (cygwin_rresvport): Ditto. + (cygwin_rexec): Ditto. + (socketpair): Ditto. + (fhandler_socket::fhandler_socket): Set `need_fork_fixup'. Allocate + space for the WSAPROTOCOL_INFOA struct used in fixup. + (fhandler_socket::~fhandler_socket): New destructor. + (fhandler_socket::fixup_before_fork_exec): New method. + (fhandler_socket::fixup_after_fork): Ditto. + (fhandler_socket::dup): Ditto. + (wsock_init): New static function. + (LoadDLLinitfunc (wsock32)): Rearranged. + (LoadDLLinitfunc (ws2_32)): New function. + (dummy_autoload): Add autoload statemants for `WSADuplicateSocketA' + and `WSASocketA'. + * spawn.cc (spawn_guts): Care for file types which need a fixup + before exec. Start child in suspended state then. + Wed Oct 25 20:49:59 2000 Christopher Faylor * signal.cc (kill_pgrp): Don't limit sending of signals to stopped diff --git a/winsup/cygwin/dtable.cc b/winsup/cygwin/dtable.cc index b08d547b8..4df56993c 100644 --- a/winsup/cygwin/dtable.cc +++ b/winsup/cygwin/dtable.cc @@ -153,6 +153,8 @@ dtable::release (int fd) { if (!not_open (fd)) { + if ((fds[fd]->get_device () & FH_DEVMASK) == FH_SOCKET) + dec_need_fixup_before (); delete fds[fd]; fds[fd] = NULL; } @@ -377,6 +379,11 @@ dtable::dup2 (int oldfd, int newfd) if (!not_open (newfd)) _close (newfd); fds[newfd] = newfh; + + /* Count sockets. */ + if ((fds[newfd]->get_device () & FH_DEVMASK) == FH_SOCKET) + inc_need_fixup_before (); + ReleaseResourceLock(LOCK_FD_LIST,WRITE_LOCK|READ_LOCK,"dup"); MALLOC_CHECK; @@ -443,6 +450,34 @@ dtable::select_except (int fd, select_record *s) /* Function to walk the fd table after an exec and perform per-fhandler type fixups. */ +void +dtable::fixup_before_fork (DWORD target_proc_id) +{ + SetResourceLock(LOCK_FD_LIST,WRITE_LOCK|READ_LOCK,"dup"); + fhandler_base *fh; + for (size_t i = 0; i < size; i++) + if ((fh = fds[i]) != NULL) + { + debug_printf ("fd %d(%s)", i, fh->get_name ()); + fh->fixup_before_fork_exec (target_proc_id); + } + ReleaseResourceLock(LOCK_FD_LIST,WRITE_LOCK|READ_LOCK,"dup"); +} + +void +dtable::fixup_before_exec (DWORD target_proc_id) +{ + SetResourceLock(LOCK_FD_LIST,WRITE_LOCK|READ_LOCK,"dup"); + fhandler_base *fh; + for (size_t i = 0; i < size; i++) + if ((fh = fds[i]) != NULL && (!fh->get_close_on_exec ())) + { + debug_printf ("fd %d(%s)", i, fh->get_name ()); + fh->fixup_before_fork_exec (target_proc_id); + } + ReleaseResourceLock(LOCK_FD_LIST,WRITE_LOCK|READ_LOCK,"dup"); +} + void dtable::fixup_after_exec (HANDLE parent, size_t sz, fhandler_base **f) { diff --git a/winsup/cygwin/dtable.h b/winsup/cygwin/dtable.h index 1952e944b..3851dbfae 100644 --- a/winsup/cygwin/dtable.h +++ b/winsup/cygwin/dtable.h @@ -16,13 +16,26 @@ class dtable fhandler_base **fds; fhandler_base **fds_on_hold; int first_fd_for_open; + int cnt_need_fixup_before; public: size_t size; - dtable () {first_fd_for_open = 3;} + + dtable () + : first_fd_for_open(3), cnt_need_fixup_before(0) {} + + void dec_need_fixup_before () + { if (cnt_need_fixup_before > 0) --cnt_need_fixup_before; } + void inc_need_fixup_before () + { ++cnt_need_fixup_before; } + BOOL need_fixup_before () + { return cnt_need_fixup_before > 0; } + int vfork_child_dup (); void vfork_parent_restore (); fhandler_base *dup_worker (fhandler_base *oldfh); int extend (int howmuch); + void fixup_before_exec (DWORD win_proc_id); + void fixup_before_fork (DWORD win_proc_id); void fixup_after_fork (HANDLE); fhandler_base *build_fhandler (int fd, DWORD dev, const char *name, int unit = -1); diff --git a/winsup/cygwin/fhandler.h b/winsup/cygwin/fhandler.h index 43b33ed14..f8c3bd7e8 100644 --- a/winsup/cygwin/fhandler.h +++ b/winsup/cygwin/fhandler.h @@ -197,7 +197,10 @@ public: void set_need_fork_fixup () { FHSETF (FFIXUP); } virtual void set_close_on_exec (int val); - virtual void fixup_after_fork (HANDLE parent); + + virtual void fixup_before_fork_exec (DWORD) {} + virtual void fixup_after_fork (HANDLE); + virtual void fixup_after_exec (HANDLE) {} int get_symlink_p () { return FHISSETF (SYMLINK); } void set_symlink_p (int val) { FHCONDSETF (val, SYMLINK); } @@ -291,8 +294,6 @@ public: virtual int raw_read (void *ptr, size_t ulen); virtual int raw_write (const void *ptr, size_t ulen); - virtual void fixup_after_exec (HANDLE) {} - /* Virtual accessor functions to hide the fact that some fd's have two handles. */ virtual HANDLE get_handle () const { return io_handle; } @@ -320,9 +321,11 @@ class fhandler_socket: public fhandler_base { private: int addr_family; + struct _WSAPROTOCOL_INFOA *prot_info_ptr; + public: fhandler_socket (const char *name = 0); - fhandler_socket (unsigned int, const char *name = 0); + ~fhandler_socket (); int get_socket () const { return (int) get_handle(); } fhandler_socket * is_socket () { return this; } int write (const void *ptr, size_t len); @@ -332,6 +335,11 @@ public: off_t lseek (off_t, int) { return 0; } int close (); void hclose (HANDLE) {close ();} + int dup (fhandler_base *child); + + virtual void fixup_before_fork_exec (DWORD); + void fixup_after_fork (HANDLE); + void fixup_after_exec (HANDLE parent) { fixup_after_fork (parent); } select_record *select_read (select_record *s); select_record *select_write (select_record *s); diff --git a/winsup/cygwin/fork.cc b/winsup/cygwin/fork.cc index c304d34b0..87315a4c2 100644 --- a/winsup/cygwin/fork.cc +++ b/winsup/cygwin/fork.cc @@ -341,6 +341,13 @@ fork_parent (void *stack_here, HANDLE& hParent, dll *&first_dll, bool& load_dlls else c_flags |= DETACHED_PROCESS; + /* Some file types (currently only sockets) need extra effort in the + parent after CreateProcess and before copying the datastructures + to the child. So we have to start the child in suspend state, + unfortunately, to avoid a race condition. */ + if (fdtab.need_fixup_before ()) + c_flags |= CREATE_SUSPENDED; + hParent = NULL; if (!DuplicateHandle (hMainProc, hMainProc, hMainProc, &hParent, 0, 1, DUPLICATE_SAME_ACCESS)) @@ -429,6 +436,14 @@ fork_parent (void *stack_here, HANDLE& hParent, dll *&first_dll, bool& load_dlls return -1; } + /* Fixup the parent datastructure if needed and resume the child's + main thread. */ + if (fdtab.need_fixup_before ()) + { + fdtab.fixup_before_fork (pi.dwProcessId); + ResumeThread (pi.hThread); + } + pinfo forked (cygwin_pid (pi.dwProcessId), 1); /* Initialize things that are done later in dll_crt0_1 that aren't done diff --git a/winsup/cygwin/net.cc b/winsup/cygwin/net.cc index d5e358c10..7f587a1de 100644 --- a/winsup/cygwin/net.cc +++ b/winsup/cygwin/net.cc @@ -22,7 +22,8 @@ details. */ #include #include #include "autoload.h" -#include +#include +#include "cygheap.h" #include "cygerrno.h" #include "fhandler.h" #include "path.h" @@ -43,6 +44,9 @@ int __stdcall rresvport (int *); int sscanf (const char *, const char *, ...); } /* End of "C" section */ +extern HANDLE ws2_32_handle; +WSADATA wsadata; + /* Cygwin internal */ static SOCKET __stdcall set_socket_inheritance (SOCKET sock) @@ -308,9 +312,12 @@ cygwin_getprotobynumber (int number) fhandler_socket * fdsock (int fd, const char *name, SOCKET soc) { + if (wsadata.wVersion < 512) /* < Winsock 2.0 */ + soc = set_socket_inheritance (soc); fhandler_socket *fh = (fhandler_socket *) fdtab.build_fhandler (fd, FH_SOCKET, name); fh->set_io_handle ((HANDLE) soc); fh->set_flags (O_RDWR); + fdtab.inc_need_fixup_before (); return fh; } @@ -339,8 +346,6 @@ cygwin_socket (int af, int type, int protocol) goto done; } - soc = set_socket_inheritance (soc); - const char *name; if (af == AF_INET) name = (type == SOCK_STREAM ? "/dev/tcp" : "/dev/udp"); @@ -720,8 +725,6 @@ cygwin_accept (int fd, struct sockaddr *peer, int *len) set_winsock_errno (); else { - res = set_socket_inheritance (res); - fdsock (res_fd, sock->get_name (), res); res = res_fd; } @@ -1593,15 +1596,11 @@ cygwin_rcmd (char **ahost, unsigned short inport, char *locuser, goto done; else { - res = set_socket_inheritance (res); - fdsock (res_fd, "/dev/tcp", res); res = res_fd; } if (fd2p) { - fd2s = set_socket_inheritance (fd2s); - fdsock (*fd2p, "/dev/tcp", fd2s); } done: @@ -1625,8 +1624,6 @@ cygwin_rresvport (int *port) goto done; else { - res = set_socket_inheritance (res); - fdsock (res_fd, "/dev/tcp", res); res = res_fd; } @@ -1658,8 +1655,6 @@ cygwin_rexec (char **ahost, unsigned short inport, char *locuser, goto done; else { - res = set_socket_inheritance (res); - fdsock (res_fd, "/dev/tcp", res); res = res_fd; } @@ -1766,11 +1761,8 @@ socketpair (int, int type, int, int *sb) closesocket (newsock); res = 0; - insock = set_socket_inheritance (insock); - fdsock (sb[0], "/dev/tcp", insock); - outsock = set_socket_inheritance (outsock); fdsock (sb[1], "/dev/tcp", outsock); done: @@ -1779,15 +1771,6 @@ done: return res; } -/**********************************************************************/ -/* fhandler_socket */ - -fhandler_socket::fhandler_socket (const char *name) : - fhandler_base (FH_SOCKET, name) -{ - set_cb (sizeof *this); -} - /* sethostent: standards? */ extern "C" void sethostent (int) @@ -1800,6 +1783,89 @@ endhostent (void) { } +/**********************************************************************/ +/* fhandler_socket */ + +fhandler_socket::fhandler_socket (const char *name) : + fhandler_base (FH_SOCKET, name) +{ + set_cb (sizeof *this); + set_need_fork_fixup (); + prot_info_ptr = (LPWSAPROTOCOL_INFOA) cmalloc (HEAP_BUF, + sizeof (WSAPROTOCOL_INFOA)); +} + +fhandler_socket::~fhandler_socket () +{ + if (prot_info_ptr) + cfree (prot_info_ptr); +} + +void +fhandler_socket::fixup_before_fork_exec (DWORD win_proc_id) +{ + int ret = 1; + + if (prot_info_ptr && + (ret = WSADuplicateSocketA (get_socket (), win_proc_id, prot_info_ptr))) + { + debug_printf ("WSADuplicateSocket error"); + set_winsock_errno (); + } + if (!ret && ws2_32_handle) + { + debug_printf ("WSADuplicateSocket went fine, dwServiceFlags1=%d", + prot_info_ptr->dwServiceFlags1); + } + else + { + fhandler_base::fixup_before_fork_exec (win_proc_id); + debug_printf ("Without Winsock 2.0"); + } +} + +void +fhandler_socket::fixup_after_fork (HANDLE parent) +{ + SOCKET new_sock = INVALID_SOCKET; + + debug_printf ("WSASocket begin, dwServiceFlags1=%d", + prot_info_ptr->dwServiceFlags1); + if (prot_info_ptr && + (new_sock = WSASocketA (FROM_PROTOCOL_INFO, + FROM_PROTOCOL_INFO, + FROM_PROTOCOL_INFO, + prot_info_ptr, 0, 0)) == INVALID_SOCKET) + { + debug_printf ("WSASocket error"); + set_winsock_errno (); + } + if (new_sock != INVALID_SOCKET && ws2_32_handle) + { + debug_printf ("WSASocket went fine"); + set_io_handle ((HANDLE) new_sock); + } + else + { + fhandler_base::fixup_after_fork (parent); + debug_printf ("Without Winsock 2.0"); + } +} + +int +fhandler_socket::dup (fhandler_base *child) +{ + fhandler_socket *fhs = (fhandler_socket *) child; + fhs->set_io_handle (get_io_handle ()); + fhs->fixup_before_fork_exec (GetCurrentProcessId ()); + if (ws2_32_handle) + { + fhs->fixup_after_fork (hMainProc); + return 0; + } + return fhandler_base::dup (child); +} + int fhandler_socket::read (void *ptr, size_t len) { @@ -2011,12 +2077,28 @@ fhandler_socket::fcntl (int cmd, void *arg) return res; } +static void +wsock_init () +{ + int res = WSAStartup ((2<<8) | 2, &wsadata); + + debug_printf ("res %d", res); + debug_printf ("wVersion %d", wsadata.wVersion); + debug_printf ("wHighVersion %d", wsadata.wHighVersion); + debug_printf ("szDescription %s", wsadata.szDescription); + debug_printf ("szSystemStatus %s", wsadata.szSystemStatus); + debug_printf ("iMaxSockets %d", wsadata.iMaxSockets); + debug_printf ("iMaxUdpDg %d", wsadata.iMaxUdpDg); + debug_printf ("lpVendorInfo %d", wsadata.lpVendorInfo); + + if (FIONBIO != REAL_FIONBIO) + debug_printf ("**************** FIONBIO != REAL_FIONBIO"); +} + extern "C" { /* Initialize WinSock */ LoadDLLinitfunc (wsock32) { - WSADATA p; - int res; HANDLE h; if ((h = LoadLibrary ("wsock32.dll")) != NULL) @@ -2026,29 +2108,32 @@ LoadDLLinitfunc (wsock32) else return 0; /* Already done by another thread? */ - res = WSAStartup ((2<<8) | 2, &p); - - debug_printf ("res %d", res); - debug_printf ("wVersion %d", p.wVersion); - debug_printf ("wHighVersion %d", p.wHighVersion); - debug_printf ("szDescription %s", p.szDescription); - debug_printf ("szSystemStatus %s", p.szSystemStatus); - debug_printf ("iMaxSockets %d", p.iMaxSockets); - debug_printf ("iMaxUdpDg %d", p.iMaxUdpDg); - debug_printf ("lpVendorInfo %d", p.lpVendorInfo); - - if (FIONBIO != REAL_FIONBIO) - debug_printf ("**************** FIONBIO != REAL_FIONBIO"); + if (!ws2_32_handle) + wsock_init (); return 0; } -LoadDLLinit (wsock32) +/* Initialize WinSock2.0 */ +LoadDLLinitfunc (ws2_32) +{ + HANDLE h; + + if ((h = LoadLibrary ("ws2_32.dll")) == NULL) + return 0; /* Already done or not available. */ + ws2_32_handle = h; + + if (!wsock32_handle) + wsock_init (); + + return 0; +} static void dummy_autoload (void) __attribute__ ((unused)); static void dummy_autoload (void) { +LoadDLLinit (wsock32) LoadDLLfunc (WSAAsyncSelect, 16, wsock32) LoadDLLfunc (WSACleanup, 0, wsock32) LoadDLLfunc (WSAGetLastError, 0, wsock32) @@ -2084,5 +2169,9 @@ LoadDLLfunc (sendto, 24, wsock32) LoadDLLfunc (setsockopt, 20, wsock32) LoadDLLfunc (shutdown, 8, wsock32) LoadDLLfunc (socket, 12, wsock32) + +LoadDLLinit (ws2_32) +LoadDLLfuncEx (WSADuplicateSocketA, 12, ws2_32, 1) +LoadDLLfuncEx (WSASocketA, 24, ws2_32, 1) } } diff --git a/winsup/cygwin/spawn.cc b/winsup/cygwin/spawn.cc index 2e0490db7..35aac9363 100644 --- a/winsup/cygwin/spawn.cc +++ b/winsup/cygwin/spawn.cc @@ -540,6 +540,14 @@ skip_arg_parsing: if (mode != _P_OVERLAY) flags |= CREATE_SUSPENDED; + /* Some file types (currently only sockets) need extra effort in the + parent after CreateProcess and before copying the datastructures + to the child. So we have to start the child in suspend state, + unfortunately, to avoid a race condition. */ + if (fdtab.need_fixup_before ()) + flags |= CREATE_SUSPENDED; + + /* Build windows style environment list */ char *envblock; if (real_path.iscygexec ()) @@ -656,6 +664,15 @@ skip_arg_parsing: return -1; } + /* Fixup the parent datastructure if needed and resume the child's + main thread. */ + if (fdtab.need_fixup_before ()) + { + fdtab.fixup_before_exec (pi.dwProcessId); + if (mode == _P_OVERLAY) + ResumeThread (pi.hThread); + } + if (mode == _P_OVERLAY) cygpid = myself->pid; else