diff --git a/winsup/cygwin/ChangeLog b/winsup/cygwin/ChangeLog index 8810d54cd..5be0a6f46 100644 --- a/winsup/cygwin/ChangeLog +++ b/winsup/cygwin/ChangeLog @@ -1,3 +1,7 @@ +2003-08-30 Christopher Faylor + + Remove some cygserver files. + 2003-08-28 Christopher Faylor * sigproc.h: Make some functions regparm. diff --git a/winsup/cygwin/cygserver.cc b/winsup/cygwin/cygserver.cc deleted file mode 100755 index 137730f9e..000000000 --- a/winsup/cygwin/cygserver.cc +++ /dev/null @@ -1,773 +0,0 @@ -/* cygserver.cc - - Copyright 2001, 2002 Red Hat Inc. - - Written by Egor Duda - -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. */ - -#include "woutsup.h" - -#include - -#include -#include -#include -#include -#include -#include -#include -#include - -#include "cygerrno.h" -#include "cygwin_version.h" - -#include "cygwin/cygserver.h" -#include "cygwin/cygserver_process.h" -#include "cygwin/cygserver_transport.h" - -// Version string. -static const char version[] = "$Revision$"; - -/* - * Support function for the XXX_printf () macros in "woutsup.h". - * Copied verbatim from "strace.cc". - */ -static int -getfunc (char *in_dst, const char *func) -{ - const char *p; - const char *pe; - char *dst = in_dst; - for (p = func; (pe = strchr (p, '(')); p = pe + 1) - if (isalnum ((int)pe[-1]) || pe[-1] == '_') - break; - else if (isspace ((int)pe[-1])) - { - pe--; - break; - } - if (!pe) - pe = strchr (func, '\0'); - for (p = pe; p > func; p--) - if (p != pe && *p == ' ') - { - p++; - break; - } - if (*p == '*') - p++; - while (p < pe) - *dst++ = *p++; - - *dst++ = ':'; - *dst++ = ' '; - *dst = '\0'; - - return dst - in_dst; -} - -/* - * Support function for the XXX_printf () macros in "woutsup.h". - */ -extern "C" void -__cygserver__printf (const char *const function, const char *const fmt, ...) -{ - const DWORD lasterror = GetLastError (); - const int lasterrno = errno; - - va_list ap; - - char *const buf = (char *) alloca (BUFSIZ); - - assert (buf); - - int len = 0; - - if (function) - len += getfunc (buf, function); - - va_start (ap, fmt); - len += vsnprintf (buf + len, BUFSIZ - len, fmt, ap); - va_end (ap); - - len += snprintf (buf + len, BUFSIZ - len, "\n"); - - const int actual = (len > BUFSIZ ? BUFSIZ : len); - - write (2, buf, actual); - - errno = lasterrno; - SetLastError (lasterror); - - return; -} - -#ifdef DEBUGGING - -int __stdcall -__set_errno (const char *func, int ln, int val) -{ - debug_printf ("%s:%d val %d", func, ln, val); - return _impure_ptr->_errno = val; -} - -#endif /* DEBUGGING */ - -GENERIC_MAPPING access_mapping; - -static BOOL -setup_privileges () -{ - BOOL rc, ret_val; - HANDLE hToken = NULL; - TOKEN_PRIVILEGES sPrivileges; - - rc = OpenProcessToken (GetCurrentProcess () , TOKEN_ALL_ACCESS , &hToken) ; - if (!rc) - { - system_printf ("error opening process token (%lu)", GetLastError ()); - ret_val = FALSE; - goto out; - } - rc = LookupPrivilegeValue (NULL, SE_DEBUG_NAME, &sPrivileges.Privileges[0].Luid); - if (!rc) - { - system_printf ("error getting privilege luid (%lu)", GetLastError ()); - ret_val = FALSE; - goto out; - } - sPrivileges.PrivilegeCount = 1 ; - sPrivileges.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED ; - rc = AdjustTokenPrivileges (hToken, FALSE, &sPrivileges, 0, NULL, NULL) ; - if (!rc) - { - system_printf ("error adjusting privilege level. (%lu)", - GetLastError ()); - ret_val = FALSE; - goto out; - } - - access_mapping.GenericRead = FILE_READ_DATA; - access_mapping.GenericWrite = FILE_WRITE_DATA; - access_mapping.GenericExecute = 0; - access_mapping.GenericAll = FILE_READ_DATA | FILE_WRITE_DATA; - - ret_val = TRUE; - -out: - CloseHandle (hToken); - return ret_val; -} - -int -check_and_dup_handle (HANDLE from_process, HANDLE to_process, - HANDLE from_process_token, - DWORD access, - HANDLE from_handle, - HANDLE *to_handle_ptr, BOOL bInheritHandle = FALSE) -{ - HANDLE local_handle = NULL; - int ret_val = EACCES; - - if (from_process != GetCurrentProcess ()) - { - if (!DuplicateHandle (from_process, from_handle, - GetCurrentProcess (), &local_handle, - 0, bInheritHandle, - DUPLICATE_SAME_ACCESS)) - { - system_printf ("error getting handle(%u) to server (%lu)", - (unsigned int)from_handle, GetLastError ()); - goto out; - } - } else - local_handle = from_handle; - - if (!wincap.has_security ()) - assert (!from_process_token); - else - { - char sd_buf [1024]; - PSECURITY_DESCRIPTOR sd = (PSECURITY_DESCRIPTOR) &sd_buf; - DWORD bytes_needed; - PRIVILEGE_SET ps; - DWORD ps_len = sizeof (ps); - BOOL status; - - if (!GetKernelObjectSecurity (local_handle, - (OWNER_SECURITY_INFORMATION - | GROUP_SECURITY_INFORMATION - | DACL_SECURITY_INFORMATION), - sd, sizeof (sd_buf), &bytes_needed)) - { - system_printf ("error getting handle SD (%lu)", GetLastError ()); - goto out; - } - - MapGenericMask (&access, &access_mapping); - - if (!AccessCheck (sd, from_process_token, access, &access_mapping, - &ps, &ps_len, &access, &status)) - { - system_printf ("error checking access rights (%lu)", - GetLastError ()); - goto out; - } - - if (!status) - { - system_printf ("access to object denied"); - goto out; - } - } - - if (!DuplicateHandle (from_process, from_handle, - to_process, to_handle_ptr, - access, bInheritHandle, 0)) - { - system_printf ("error getting handle to client (%lu)", GetLastError ()); - goto out; - } - - // verbose: debug_printf ("Duplicated %p to %p", from_handle, *to_handle_ptr); - - ret_val = 0; - - out: - if (local_handle && from_process != GetCurrentProcess ()) - CloseHandle (local_handle); - - return (ret_val); -} - -/* - * client_request_attach_tty::serve () - */ - -void -client_request_attach_tty::serve (transport_layer_base *const conn, - process_cache *) -{ - assert (conn); - - assert (!error_code ()); - - if (!wincap.has_security ()) - { - syscall_printf ("operation only supported on systems with security"); - error_code (EINVAL); - msglen (0); - return; - } - - if (msglen () != sizeof (req)) - { - syscall_printf ("bad request body length: expecting %lu bytes, got %lu", - sizeof (req), msglen ()); - error_code (EINVAL); - msglen (0); - return; - } - - msglen (0); // Until we fill in some fields. - - // verbose: debug_printf ("pid %ld:(%p,%p) -> pid %ld", - // req.master_pid, req.from_master, req.to_master, - // req.pid); - - // verbose: debug_printf ("opening process %ld", req.master_pid); - - const HANDLE from_process_handle = - OpenProcess (PROCESS_DUP_HANDLE, FALSE, req.master_pid); - - if (!from_process_handle) - { - system_printf ("error opening `from' process, error = %lu", - GetLastError ()); - error_code (EACCES); - return; - } - - // verbose: debug_printf ("opening process %ld", req.pid); - - const HANDLE to_process_handle = - OpenProcess (PROCESS_DUP_HANDLE, FALSE, req.pid); - - if (!to_process_handle) - { - system_printf ("error opening `to' process, error = %lu", - GetLastError ()); - CloseHandle (from_process_handle); - error_code (EACCES); - return; - } - - // verbose: debug_printf ("Impersonating client"); - conn->impersonate_client (); - - HANDLE token_handle = NULL; - - // verbose: debug_printf ("about to open thread token"); - const DWORD rc = OpenThreadToken (GetCurrentThread (), - TOKEN_QUERY, - TRUE, - &token_handle); - - // verbose: debug_printf ("opened thread token, rc=%lu", rc); - conn->revert_to_self (); - - if (!rc) - { - system_printf ("error opening thread token, error = %lu", - GetLastError ()); - CloseHandle (from_process_handle); - CloseHandle (to_process_handle); - error_code (EACCES); - return; - } - - // From this point on, a reply body is returned to the client. - - const HANDLE from_master = req.from_master; - const HANDLE to_master = req.to_master; - - req.from_master = NULL; - req.to_master = NULL; - - msglen (sizeof (req)); - - if (from_master) - if (check_and_dup_handle (from_process_handle, to_process_handle, - token_handle, - GENERIC_READ, - from_master, - &req.from_master, TRUE) != 0) - { - system_printf ("error duplicating from_master handle, error = %lu", - GetLastError ()); - error_code (EACCES); - } - - if (to_master) - if (check_and_dup_handle (from_process_handle, to_process_handle, - token_handle, - GENERIC_WRITE, - to_master, - &req.to_master, TRUE) != 0) - { - system_printf ("error duplicating to_master handle, error = %lu", - GetLastError ()); - error_code (EACCES); - } - - CloseHandle (from_process_handle); - CloseHandle (to_process_handle); - CloseHandle (token_handle); - - debug_printf ("%lu(%lu, %lu) -> %lu(%lu,%lu)", - req.master_pid, from_master, to_master, - req.pid, req.from_master, req.to_master); - - return; -} - -void -client_request_get_version::serve (transport_layer_base *, process_cache *) -{ - assert (!error_code ()); - - if (msglen ()) - syscall_printf ("unexpected request body ignored: %lu bytes", msglen ()); - - msglen (sizeof (version)); - - version.major = CYGWIN_SERVER_VERSION_MAJOR; - version.api = CYGWIN_SERVER_VERSION_API; - version.minor = CYGWIN_SERVER_VERSION_MINOR; - version.patch = CYGWIN_SERVER_VERSION_PATCH; -} - -class server_request : public queue_request -{ -public: - server_request (transport_layer_base *const conn, process_cache *const cache) - : _conn (conn), _cache (cache) - {} - - virtual ~server_request () - { - safe_delete (_conn); - } - - virtual void process () - { - client_request::handle_request (_conn, _cache); - } - -private: - transport_layer_base *const _conn; - process_cache *const _cache; -}; - -class server_submission_loop : public queue_submission_loop -{ -public: - server_submission_loop (threaded_queue *const queue, - transport_layer_base *const transport, - process_cache *const cache) - : queue_submission_loop (queue, false), - _transport (transport), - _cache (cache) - { - assert (_transport); - assert (_cache); - } - -private: - transport_layer_base *const _transport; - process_cache *const _cache; - - virtual void request_loop (); -}; - -/* FIXME: this is a little ugly. What we really want is to wait on - * two objects: one for the pipe/socket, and one for being told to - * shutdown. Otherwise this will stay a problem (we won't actually - * shutdown until the request _AFTER_ the shutdown request. And - * sending ourselves a request is ugly - */ -void -server_submission_loop::request_loop () -{ - /* I'd like the accepting thread's priority to be above any "normal" - * thread in the system to avoid overflowing the listen queue (for - * sockets; similar issues exist for named pipes); but, for example, - * a normal priority thread in a foregrounded process is boosted to - * THREAD_PRIORITY_HIGHEST (AFAICT). Thus try to set the current - * thread's priority to a level one above that. This fails on - * win9x/ME so assume any failure in that call is due to that and - * simply call again at one priority level lower. - */ - if (!SetThreadPriority (GetCurrentThread (), THREAD_PRIORITY_HIGHEST + 1)) - if (!SetThreadPriority (GetCurrentThread (), THREAD_PRIORITY_HIGHEST)) - debug_printf ("failed to raise accept thread priority, error = %lu", - GetLastError ()); - - while (_running) - { - bool recoverable = false; - transport_layer_base *const conn = _transport->accept (&recoverable); - if (!conn && !recoverable) - { - system_printf ("fatal error on IPC transport: closing down"); - return; - } - // EINTR probably implies a shutdown request; so back off for a - // moment to let the main thread take control, otherwise the - // server spins here receiving EINTR repeatedly since the signal - // handler in the main thread doesn't get a chance to be called. - if (!conn && errno == EINTR) - { - if (!SetThreadPriority (GetCurrentThread (), THREAD_PRIORITY_NORMAL)) - debug_printf ("failed to reset thread priority, error = %lu", - GetLastError ()); - - Sleep (0); - if (!SetThreadPriority (GetCurrentThread (), - THREAD_PRIORITY_HIGHEST + 1)) - if (!SetThreadPriority (GetCurrentThread (), - THREAD_PRIORITY_HIGHEST)) - debug_printf ("failed to raise thread priority, error = %lu", - GetLastError ()); - } - if (conn) - _queue->add (safe_new (server_request, conn, _cache)); - } -} - -client_request_shutdown::client_request_shutdown () - : client_request (CYGSERVER_REQUEST_SHUTDOWN) -{ - // verbose: syscall_printf ("created"); -} - -void -client_request_shutdown::serve (transport_layer_base *, process_cache *) -{ - assert (!error_code ()); - - if (msglen ()) - syscall_printf ("unexpected request body ignored: %lu bytes", msglen ()); - - /* FIXME: link upwards, and then this becomes a trivial method call to - * only shutdown _this queue_ - */ - - kill (getpid (), SIGINT); - - msglen (0); -} - -static sig_atomic_t shutdown_server = false; - -static void -handle_signal (const int signum) -{ - /* any signal makes us die :} */ - - shutdown_server = true; -} - -/* - * print_usage () - */ - -static void -print_usage (const char *const pgm) -{ - printf ("Usage: %s [OPTIONS]\n", pgm); - printf (" -c, --cleanup-threads number of cleanup threads to use\n"); - printf (" -h, --help output usage information and exit\n"); - printf (" -r, --request-threads number of request threads to use\n"); - printf (" -s, --shutdown shutdown the daemon\n"); - printf (" -v, --version output version information and exit\n"); -} - -/* - * print_version () - */ - -static void -print_version (const char *const pgm) -{ - char *vn = NULL; - - const char *const colon = strchr (version, ':'); - - if (!colon) - { - vn = strdup ("?"); - } - else - { - vn = strdup (colon + 2); // Skip ": " - - char *const spc = strchr (vn, ' '); - - if (spc) - *spc = '\0'; - } - - char buf[200]; - snprintf (buf, sizeof (buf), "%d.%d.%d(%d.%d/%d/%d)-(%d.%d.%d.%d) %s", - cygwin_version.dll_major / 1000, - cygwin_version.dll_major % 1000, - cygwin_version.dll_minor, - cygwin_version.api_major, - cygwin_version.api_minor, - cygwin_version.shared_data, - CYGWIN_SERVER_VERSION_MAJOR, - CYGWIN_SERVER_VERSION_API, - CYGWIN_SERVER_VERSION_MINOR, - CYGWIN_SERVER_VERSION_PATCH, - cygwin_version.mount_registry, - cygwin_version.dll_build_date); - - printf ("%s (cygwin) %s\n", pgm, vn); - printf ("API version %s\n", buf); - printf ("Copyright 2001, 2002 Red Hat, Inc.\n"); - printf ("Compiled on %s\n", __DATE__); - - free (vn); -} - -/* - * main () - */ - -int -main (const int argc, char *argv[]) -{ - const struct option longopts[] = { - {"cleanup-threads", required_argument, NULL, 'c'}, - {"help", no_argument, NULL, 'h'}, - {"request-threads", required_argument, NULL, 'r'}, - {"shutdown", no_argument, NULL, 's'}, - {"version", no_argument, NULL, 'v'}, - {0, no_argument, NULL, 0} - }; - - const char opts[] = "c:hr:sv"; - - int cleanup_threads = 2; - int request_threads = 10; - bool shutdown = false; - - const char *pgm = NULL; - - if (!(pgm = strrchr (*argv, '\\')) && !(pgm = strrchr (*argv, '/'))) - pgm = *argv; - else - pgm++; - - wincap.init (); - if (wincap.has_security ()) - setup_privileges (); - - int opt; - - while ((opt = getopt_long (argc, argv, opts, longopts, NULL)) != EOF) - switch (opt) - { - case 'c': - cleanup_threads = atoi (optarg); - if (cleanup_threads <= 0) - { - fprintf (stderr, - "%s: number of cleanup threads must be positive\n", - pgm); - exit (1); - } - break; - - case 'h': - print_usage (pgm); - return 0; - - case 'r': - request_threads = atoi (optarg); - if (request_threads <= 0) - { - fprintf (stderr, - "%s: number of request threads must be positive\n", - pgm); - exit (1); - } - break; - - case 's': - shutdown = true; - break; - - case 'v': - print_version (pgm); - return 0; - - case '?': - fprintf (stderr, "Try `%s --help' for more information.\n", pgm); - exit (1); - } - - if (optind != argc) - { - fprintf (stderr, "%s: too many arguments\n", pgm); - exit (1); - } - - if (shutdown) - { - /* Setting `cygserver_running' stops the request code making a - * version request, which is not much to the point. - */ - cygserver_running = CYGSERVER_OK; - - client_request_shutdown req; - - if (req.make_request () == -1 || req.error_code ()) - { - fprintf (stderr, "%s: shutdown request failed: %s\n", - pgm, strerror (req.error_code ())); - exit (1); - } - - // FIXME: It would be nice to wait here for the daemon to exit. - - return 0; - } - -#define SIGHANDLE(SIG) \ - do \ - { \ - struct sigaction act; \ - \ - act.sa_handler = &handle_signal; \ - act.sa_mask = 0; \ - act.sa_flags = 0; \ - \ - if (sigaction (SIG, &act, NULL) == -1) \ - { \ - system_printf ("failed to install handler for " #SIG ": %s", \ - strerror (errno)); \ - exit (1); \ - } \ - } while (false) - - SIGHANDLE (SIGHUP); - SIGHANDLE (SIGINT); - SIGHANDLE (SIGTERM); - - print_version (pgm); - setbuf (stdout, NULL); - printf ("daemon starting up"); - - threaded_queue request_queue (request_threads); - printf ("."); - - transport_layer_base *const transport = create_server_transport (); - assert (transport); - printf ("."); - - process_cache cache (cleanup_threads); - printf ("."); - - server_submission_loop submission_loop (&request_queue, transport, &cache); - printf ("."); - - request_queue.add_submission_loop (&submission_loop); - printf ("."); - - if (transport->listen () == -1) - { - exit (1); - } - printf ("."); - - cache.start (); - printf ("."); - - request_queue.start (); - printf ("."); - - printf ("complete\n"); - - /* TODO: wait on multiple objects - the thread handle for each - * request loop + all the process handles. This should be done by - * querying the request_queue and the process cache for all their - * handles, and then waiting for (say) 30 seconds. after that we - * recreate the list of handles to wait on, and wait again. the - * point of all this abstraction is that we can trivially server - * both sockets and pipes simply by making a new transport, and then - * calling request_queue.process_requests (transport2); - */ - /* WaitForMultipleObjects abort && request_queue && process_queue && signal - -- if signal event then retrigger it - */ - while (!shutdown_server && request_queue.running () && cache.running ()) - pause (); - - printf ("\nShutdown request received - new requests will be denied\n"); - request_queue.stop (); - printf ("All pending requests processed\n"); - safe_delete (transport); - printf ("No longer accepting requests - cygwin will operate in daemonless mode\n"); - cache.stop (); - printf ("All outstanding process-cache activities completed\n"); - printf ("daemon shutdown\n"); - - return 0; -} diff --git a/winsup/cygwin/cygserver_client.cc b/winsup/cygwin/cygserver_client.cc deleted file mode 100755 index f6683182d..000000000 --- a/winsup/cygwin/cygserver_client.cc +++ /dev/null @@ -1,528 +0,0 @@ -/* cygserver_client.cc - - Copyright 2001, 2002 Red Hat Inc. - - Written by Egor Duda - -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. */ - -/* 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 "cygerrno.h" -#include "cygserver_shm.h" -#include "safe_memory.h" - -#include "cygwin/cygserver.h" -#include "cygwin/cygserver_transport.h" - -int cygserver_running = CYGSERVER_UNKNOWN; // Nb: inherited by children. - -/* On by default during development. For release, we probably want off - * by default. - */ -bool allow_daemon = true; // Nb: inherited by children. - -client_request_get_version::client_request_get_version () - : client_request (CYGSERVER_REQUEST_GET_VERSION, &version, sizeof (version)) -{ - msglen (0); // No parameters for request. - - // verbose: syscall_printf ("created"); -} - -/* - * client_request_get_version::check_version () - * - * The major version and API version numbers must match exactly. An - * older than expected minor version number is accepted (as long as - * the first numbers match, that is). - */ - -bool -client_request_get_version::check_version () const -{ - const bool ok = (version.major == CYGWIN_SERVER_VERSION_MAJOR - && version.api == CYGWIN_SERVER_VERSION_API - && version.minor <= CYGWIN_SERVER_VERSION_MINOR); - - if (!ok) - syscall_printf (("incompatible version of cygwin server: " - "client version %d.%d.%d.%d, " - "server version %ld.%ld.%ld.%ld"), - CYGWIN_SERVER_VERSION_MAJOR, - CYGWIN_SERVER_VERSION_API, - CYGWIN_SERVER_VERSION_MINOR, - CYGWIN_SERVER_VERSION_PATCH, - version.major, - version.api, - version.minor, - version.patch); - - return ok; -} - -#ifdef __INSIDE_CYGWIN__ - -client_request_attach_tty::client_request_attach_tty (DWORD nmaster_pid, - HANDLE nfrom_master, - HANDLE nto_master) - : client_request (CYGSERVER_REQUEST_ATTACH_TTY, &req, sizeof (req)) -{ - req.pid = GetCurrentProcessId (); - req.master_pid = nmaster_pid; - req.from_master = nfrom_master; - req.to_master = nto_master; - - syscall_printf (("created: pid = %lu, master_pid = %lu, " - "from_master = %lu, to_master = %lu"), - req.pid, req.master_pid, req.from_master, req.to_master); -} - -#else /* !__INSIDE_CYGWIN__ */ - -client_request_attach_tty::client_request_attach_tty () - : client_request (CYGSERVER_REQUEST_ATTACH_TTY, &req, sizeof (req)) -{ - // verbose: syscall_printf ("created"); -} - -#endif /* __INSIDE_CYGWIN__ */ - -/* - * client_request_attach_tty::send () - * - * Wraps the base method to provide error handling support. If the - * reply contains a body but is flagged as an error, close any handles - * that have been returned by cygserver and then discard the message - * body, i.e. the client either sees a successful result with handles - * or an unsuccessful result with no handles. - */ - -void -client_request_attach_tty::send (transport_layer_base * const conn) -{ - client_request::send (conn); - - if (msglen () && error_code ()) - { - if (from_master ()) - CloseHandle (from_master ()); - if (to_master ()) - CloseHandle (to_master ()); - msglen (0); - } -} - -client_request::header_t::header_t (const request_code_t request_code, - const size_t msglen) - : msglen (msglen), - request_code (request_code) -{ - assert (request_code >= 0 && request_code < CYGSERVER_REQUEST_LAST); -} - -// FIXME: also check write and read result for -1. - -void -client_request::send (transport_layer_base * const conn) -{ - assert (conn); - assert (!(msglen () && !_buf)); // i.e., msglen () implies _buf - assert (msglen () <= _buflen); - - { - const ssize_t count = conn->write (&_header, sizeof (_header)); - - if (count != sizeof (_header)) - { - assert (errno); - error_code (errno); - syscall_printf (("request header write failure: " - "only %ld bytes sent of %ld, " - "error = %d(%lu)"), - count, sizeof (_header), - errno, GetLastError ()); - return; - } - } - - if (msglen ()) - { - const ssize_t count = conn->write (_buf, msglen ()); - - if (count == -1 || (size_t) count != msglen ()) - { - assert (errno); - error_code (errno); - syscall_printf (("request body write failure: " - "only %ld bytes sent of %ld, " - "error = %d(%lu)"), - count, msglen (), - errno, GetLastError ()); - return; - } - } - - // verbose: syscall_printf ("request sent (%ld + %ld bytes)", - // sizeof (_header), msglen ()); - - { - const ssize_t count = conn->read (&_header, sizeof (_header)); - - if (count != sizeof (_header)) - { - assert (errno); - error_code (errno); - syscall_printf (("reply header read failure: " - "only %ld bytes received of %ld, " - "error = %d(%lu)"), - count, sizeof (_header), - errno, GetLastError ()); - return; - } - } - - if (msglen () && !_buf) - { - system_printf ("no client buffer for reply body: %ld bytes needed", - msglen ()); - error_code (EINVAL); - return; - } - - if (msglen () > _buflen) - { - system_printf (("client buffer too small for reply body: " - "have %ld bytes and need %ld"), - _buflen, msglen ()); - error_code (EINVAL); - return; - } - - if (msglen ()) - { - const ssize_t count = conn->read (_buf, msglen ()); - - if (count == -1 || (size_t) count != msglen ()) - { - assert (errno); - error_code (errno); - syscall_printf (("reply body read failure: " - "only %ld bytes received of %ld, " - "error = %d(%lu)"), - count, msglen (), - errno, GetLastError ()); - return; - } - } - - // verbose: syscall_printf ("reply received (%ld + %ld bytes)", - // sizeof (_header), msglen ()); -} - -#ifndef __INSIDE_CYGWIN__ - -/* - * client_request::handle_request () - * - * A server-side method. - * - * This is a factory method for the client_request subclasses. It - * reads the incoming request header and, based on its request code, - * creates an instance of the appropriate class. - * - * FIXME: If the incoming packet is malformed, the server drops it on - * the floor. Should it try and generate some sort of reply for the - * client? As it is, the client will simply get a broken connection. - * - * FIXME: also check write and read result for -1. - */ - -/* static */ void -client_request::handle_request (transport_layer_base *const conn, - process_cache *const cache) -{ - // verbose: debug_printf ("about to read"); - - header_t header; - - { - const ssize_t count = conn->read (&header, sizeof (header)); - - if (count != sizeof (header)) - { - syscall_printf (("request header read failure: " - "only %ld bytes received of %ld, " - "error = %d(%lu)"), - count, sizeof (header), - errno, GetLastError ()); - return; - } - - // verbose: debug_printf ("got header (%ld)", count); - } - - client_request *req = NULL; - - switch (header.request_code) - { - case CYGSERVER_REQUEST_GET_VERSION: - req = safe_new0 (client_request_get_version); - break; - case CYGSERVER_REQUEST_SHUTDOWN: - req = safe_new0 (client_request_shutdown); - break; - case CYGSERVER_REQUEST_ATTACH_TTY: - req = safe_new0 (client_request_attach_tty); - break; - case CYGSERVER_REQUEST_SHM: - req = safe_new0 (client_request_shm); - break; - default: - syscall_printf ("unknown request code %d received: request ignored", - header.request_code); - return; - } - - assert (req); - - req->msglen (header.msglen); - req->handle (conn, cache); - - safe_delete (req); - -#ifndef DEBUGGING - printf ("."); // A little noise when we're being quiet. -#endif -} - -#endif /* !__INSIDE_CYGWIN__ */ - -client_request::client_request (request_code_t const id, - void * const buf, - size_t const buflen) - : _header (id, buflen), - _buf (buf), - _buflen (buflen) -{ - assert ((!_buf && !_buflen) || (_buf && _buflen)); -} - -client_request::~client_request () -{} - -int -client_request::make_request () -{ - assert (cygserver_running == CYGSERVER_UNKNOWN \ - || cygserver_running == CYGSERVER_OK \ - || cygserver_running == CYGSERVER_UNAVAIL); - - if (cygserver_running == CYGSERVER_UNKNOWN) - cygserver_init (); - - assert (cygserver_running == CYGSERVER_OK \ - || cygserver_running == CYGSERVER_UNAVAIL); - - /* Don't retry every request if the server's not there */ - if (cygserver_running == CYGSERVER_UNAVAIL) - { - syscall_printf ("cygserver un-available"); - error_code (ENOSYS); - return -1; - } - - transport_layer_base *const transport = create_server_transport (); - - assert (transport); - - if (transport->connect () == -1) - { - if (errno) - error_code (errno); - else - error_code (ENOSYS); - safe_delete (transport); - return -1; - } - - // verbose: debug_printf ("connected to server %p", transport); - - send (transport); - - safe_delete (transport); - - return 0; -} - -#ifndef __INSIDE_CYGWIN__ - -/* - * client_request::handle () - * - * A server-side method. - * - * At this point, the header of an incoming request has been read and - * an appropriate client_request object constructed. This method has - * to read the request body into its buffer, if there is such a body, - * then perform the request and send back the results to the client. - * - * FIXME: If the incoming packet is malformed, the server drops it on - * the floor. Should it try and generate some sort of reply for the - * client? As it is, the client will simply get a broken connection. - * - * FIXME: also check write and read result for -1. - */ - -void -client_request::handle (transport_layer_base *const conn, - process_cache *const cache) -{ - if (msglen () && !_buf) - { - system_printf ("no buffer for request body: %ld bytes needed", - msglen ()); - error_code (EINVAL); - return; - } - - if (msglen () > _buflen) - { - system_printf (("buffer too small for request body: " - "have %ld bytes and need %ld"), - _buflen, msglen ()); - error_code (EINVAL); - return; - } - - if (msglen ()) - { - const ssize_t count = conn->read (_buf, msglen ()); - - if (count == -1 || (size_t) count != msglen ()) - { - assert (errno); - error_code (errno); - syscall_printf (("request body read failure: " - "only %ld bytes received of %ld, " - "error = %d(%lu)"), - count, msglen (), - errno, GetLastError ()); - return; - } - } - - // verbose: syscall_printf ("request received (%ld + %ld bytes)", - // sizeof (_header), msglen ()); - - error_code (0); // Overwrites the _header.request_code field. - - /* - * This is not allowed to fail. We must return ENOSYS at a minimum - * to the client. - */ - serve (conn, cache); - - { - const ssize_t count = conn->write (&_header, sizeof (_header)); - - if (count != sizeof (_header)) - { - assert (errno); - error_code (errno); - syscall_printf (("reply header write failure: " - "only %ld bytes sent of %ld, " - "error = %d(%lu)"), - count, sizeof (_header), - errno, GetLastError ()); - return; - } - } - - if (msglen ()) - { - const ssize_t count = conn->write (_buf, msglen ()); - - if (count == -1 || (size_t) count != msglen ()) - { - assert (errno); - error_code (errno); - syscall_printf (("reply body write failure: " - "only %ld bytes sent of %ld, " - "error = %d(%lu)"), - count, msglen (), - errno, GetLastError ()); - return; - } - } - - // verbose: syscall_printf ("reply sent (%ld + %ld bytes)", - // sizeof (_header), msglen ()); -} - -#endif /* !__INSIDE_CYGWIN__ */ - -bool -check_cygserver_available () -{ - assert (cygserver_running == CYGSERVER_UNKNOWN \ - || cygserver_running == CYGSERVER_UNAVAIL); - - cygserver_running = CYGSERVER_OK; // For make_request (). - - client_request_get_version req; - - /* This indicates that we failed to connect to cygserver at all but - * that's fine as cygwin doesn't need it to be running. - */ - if (req.make_request () == -1) - return false; - - /* We connected to the server but something went wrong after that - * (in sending the message, in cygserver itself, or in receiving the - * reply). - */ - if (req.error_code ()) - { - syscall_printf ("failure in cygserver version request: %d", - req.error_code ()); - syscall_printf ("process will continue without cygserver support"); - return false; - } - - return req.check_version (); -} - -void -cygserver_init () -{ - if (!allow_daemon) - { - syscall_printf ("cygserver use disabled in client"); - cygserver_running = CYGSERVER_UNAVAIL; - return; - } - - assert (cygserver_running == CYGSERVER_UNKNOWN \ - || cygserver_running == CYGSERVER_OK \ - || cygserver_running == CYGSERVER_UNAVAIL); - - if (cygserver_running == CYGSERVER_OK) - return; - - if (!check_cygserver_available ()) - cygserver_running = CYGSERVER_UNAVAIL; -} diff --git a/winsup/cygwin/cygserver_ipc.h b/winsup/cygwin/cygserver_ipc.h deleted file mode 100644 index 0d0ebbc76..000000000 --- a/winsup/cygwin/cygserver_ipc.h +++ /dev/null @@ -1,84 +0,0 @@ -/* cygserver_ipc.h - - Copyright 2002 Red Hat, Inc. - - Originally written by Conrad Scott - -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. */ - -#ifndef __CYGSERVER_IPC_H__ -#define __CYGSERVER_IPC_H__ - -#include -#include /* For OPEN_MAX. */ - -/* - * The sysv ipc id's (msgid, semid, shmid) are integers arranged such - * that they no subsystem will generate the same id as some other - * subsystem; nor do these ids overlap file descriptors (the other - * common integer ids). Since Cygwin can allocate more than OPEN_MAX - * file descriptors, it can't be guaranteed not to overlap, but it - * should help catch some errors. - * - * msgid's: OPEN_MAX, OPEN_MAX + 3, OPEN_MAX + 6, . . . - * semid's: OPEN_MAX + 1, OPEN_MAX + 4, OPEN_MAX + 7, . . . - * shmid's: OPEN_MAX + 2, OPEN_MAX + 5, OPEN_MAX + 8, . . . - * - * To further ensure that ids are unique, if ipc objects are created - * and destroyed and then re-created, they are given new ids by - * munging the basic id (as above) with a sequence number. - * - * Internal ipc id's, which are 0, 1, ... within each subsystem (and - * not munged with a sequence number), are used solely by the ipcs(8) - * interface. - */ - -enum ipc_subsys_t - { - IPC_MSGOP = 0, - IPC_SEMOP = 1, - IPC_SHMOP = 2, - IPC_SUBSYS_COUNT - }; - -/* - * IPCMNI - The absolute maximum number of simultaneous ipc ids for - * any one subsystem. - */ - -enum - { - IPCMNI = 0x10000 // Must be a power of two. - }; - -inline int -ipc_int2ext (const int intid, const ipc_subsys_t subsys, long & sequence) -{ - assert (0 <= intid && intid < IPCMNI); - - const long tmp = InterlockedIncrement (&sequence); - - return (((tmp & 0x7fff) << 16) - | (OPEN_MAX + (intid * IPC_SUBSYS_COUNT) + subsys)); -} - -inline int -ipc_ext2int_subsys (const int extid) -{ - return ((extid & (IPCMNI - 1)) - OPEN_MAX) % IPC_SUBSYS_COUNT; -} - -inline int -ipc_ext2int (const int extid, const ipc_subsys_t subsys) -{ - if (ipc_ext2int_subsys (extid) != subsys) - return -1; - else - return ((extid & (IPCMNI - 1)) - OPEN_MAX) / IPC_SUBSYS_COUNT; -} - -#endif /* __CYGSERVER_IPC_H__ */ diff --git a/winsup/cygwin/cygserver_process.cc b/winsup/cygwin/cygserver_process.cc deleted file mode 100755 index 2cc7be19c..000000000 --- a/winsup/cygwin/cygserver_process.cc +++ /dev/null @@ -1,431 +0,0 @@ -/* cygserver_process.cc - - Copyright 2001, 2002 Red Hat Inc. - - Written by Robert Collins - -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. */ - -#include "woutsup.h" - -#include - -#include -#include - -#include "cygerrno.h" - -#include "cygwin/cygserver_process.h" - -/*****************************************************************************/ - -#define elements(ARRAY) (sizeof (ARRAY) / sizeof (*ARRAY)) - -/*****************************************************************************/ - -process_cleanup::~process_cleanup () -{ - safe_delete (_process); -} - -void -process_cleanup::process () -{ - _process->cleanup (); -} - -/*****************************************************************************/ - -/* cleanup_routine */ -cleanup_routine::~cleanup_routine () -{ -} - -/*****************************************************************************/ - -process::process (const pid_t cygpid, const DWORD winpid) - : _cygpid (cygpid), - _winpid (winpid), - _hProcess (NULL), - _cleaning_up (false), - _exit_status (STILL_ACTIVE), - _routines_head (NULL), - _next (NULL) -{ - _hProcess = OpenProcess (PROCESS_ALL_ACCESS, FALSE, winpid); - if (!_hProcess) - { - system_printf ("unable to obtain handle for new cache process %d(%lu)", - _cygpid, _winpid); - _hProcess = INVALID_HANDLE_VALUE; - _exit_status = 0; - } - else - debug_printf ("got handle %p for new cache process %d(%lu)", - _hProcess, _cygpid, _winpid); - InitializeCriticalSection (&_access); -} - -process::~process () -{ - DeleteCriticalSection (&_access); - (void) CloseHandle (_hProcess); -} - -/* No need to be thread-safe as this is only ever called by - * process_cache::remove_process (). If it has to be made thread-safe - * later on, it should not use the `access' critical section as that - * is held by the client request handlers for an arbitrary length of - * time, i.e. while they do whatever processing is required for a - * client request. - */ -DWORD -process::check_exit_code () -{ - if (_hProcess && _hProcess != INVALID_HANDLE_VALUE - && _exit_status == STILL_ACTIVE - && !GetExitCodeProcess (_hProcess, &_exit_status)) - { - system_printf ("failed to retrieve exit code for %d(%lu), error = %lu", - _cygpid, _winpid, GetLastError ()); - _hProcess = INVALID_HANDLE_VALUE; - } - return _exit_status; -} - -bool -process::add (cleanup_routine *const entry) -{ - assert (entry); - - bool res = false; - EnterCriticalSection (&_access); - - if (!_cleaning_up) - { - entry->_next = _routines_head; - _routines_head = entry; - res = true; - } - - LeaveCriticalSection (&_access); - return res; -} - -bool -process::remove (const cleanup_routine *const entry) -{ - assert (entry); - - bool res = false; - EnterCriticalSection (&_access); - - if (!_cleaning_up) - { - cleanup_routine *previous = NULL; - - for (cleanup_routine *ptr = _routines_head; - ptr; - previous = ptr, ptr = ptr->_next) - { - if (*ptr == *entry) - { - if (previous) - previous->_next = ptr->_next; - else - _routines_head = ptr->_next; - - safe_delete (ptr); - res = true; - break; - } - } - } - - LeaveCriticalSection (&_access); - return res; -} - -/* This is single threaded. It's called after the process is removed - * from the cache, but inserts may be attemped by worker threads that - * have a pointer to it. - */ -void -process::cleanup () -{ - EnterCriticalSection (&_access); - assert (!is_active ()); - assert (!_cleaning_up); - InterlockedExchange (&_cleaning_up, true); - cleanup_routine *entry = _routines_head; - _routines_head = NULL; - LeaveCriticalSection (&_access); - - while (entry) - { - cleanup_routine *const ptr = entry; - entry = entry->_next; - ptr->cleanup (this); - safe_delete (ptr); - } -} - -/*****************************************************************************/ - -void -process_cache::submission_loop::request_loop () -{ - assert (this); - assert (_cache); - assert (_interrupt_event); - - while (_running) - _cache->wait_for_processes (_interrupt_event); -} - -/*****************************************************************************/ - -process_cache::process_cache (const unsigned int initial_workers) - : _queue (initial_workers), - _submitter (this, &_queue), // true == interruptible - _processes_count (0), - _processes_head (NULL), - _cache_add_trigger (NULL) -{ - /* there can only be one */ - InitializeCriticalSection (&_cache_write_access); - - _cache_add_trigger = CreateEvent (NULL, // SECURITY_ATTRIBUTES - FALSE, // Auto-reset - FALSE, // Initially non-signalled - NULL); // Anonymous - - if (!_cache_add_trigger) - { - system_printf ("failed to create cache add trigger, error = %lu", - GetLastError ()); - abort (); - } - - _queue.add_submission_loop (&_submitter); -} - -process_cache::~process_cache () -{ - (void) CloseHandle (_cache_add_trigger); - DeleteCriticalSection (&_cache_write_access); -} - -/* This returns the process object to the caller already locked, that - * is, with the object's `access' critical region entered. Thus the - * caller must unlock the object when it's finished with it (via - * process::release ()). It must then not try to access the object - * afterwards, except by going through this routine again, as it may - * have been deleted once it has been unlocked. - */ -class process * -process_cache::process (const pid_t cygpid, const DWORD winpid) -{ - /* TODO: make this more granular, so a search doesn't involve the - * write lock. - */ - EnterCriticalSection (&_cache_write_access); - class process *previous = NULL; - class process *entry = find (winpid, &previous); - - if (!entry) - { - if (_processes_count + SPECIALS_COUNT >= MAXIMUM_WAIT_OBJECTS) - { - LeaveCriticalSection (&_cache_write_access); - system_printf (("process limit (%d processes) reached; " - "new connection refused for %d(%lu)"), - MAXIMUM_WAIT_OBJECTS - SPECIALS_COUNT, - cygpid, winpid); - set_errno (EAGAIN); - return NULL; - } - - entry = safe_new (class process, cygpid, winpid); - if (!entry->is_active ()) - { - LeaveCriticalSection (&_cache_write_access); - safe_delete (entry); - set_errno (ESRCH); - return NULL; - } - - if (previous) - { - entry->_next = previous->_next; - previous->_next = entry; - } - else - { - entry->_next = _processes_head; - _processes_head = entry; - } - - _processes_count += 1; - SetEvent (_cache_add_trigger); - } - - EnterCriticalSection (&entry->_access); // To be released by the caller. - LeaveCriticalSection (&_cache_write_access); - assert (entry); - assert (entry->_winpid == winpid); - return entry; -} - -void -process_cache::wait_for_processes (const HANDLE interrupt_event) -{ - // Update `_wait_array' with handles of all current processes. - const size_t count = sync_wait_array (interrupt_event); - - debug_printf ("waiting on %u objects in total (%u processes)", - count, _processes_count); - - const DWORD rc = WaitForMultipleObjects (count, _wait_array, - FALSE, INFINITE); - - if (rc == WAIT_FAILED) - { - system_printf ("could not wait on the process handles, error = %lu", - GetLastError ()); - abort (); - } - - const size_t start = rc - WAIT_OBJECT_0; - - if (rc < WAIT_OBJECT_0 || start > count) - { - system_printf (("unexpected return code %rc " - "from WaitForMultipleObjects: " - "expected [%u .. %u)"), - rc, WAIT_OBJECT_0, WAIT_OBJECT_0 + count); - abort (); - } - - // Tell all the processes, from the signalled point up, the bad news. - for (size_t index = start; index != count; index++) - if (_process_array[index]) - check_and_remove_process (index); -} - -/* - * process_cache::sync_wait_array () - * - * Fill-in the wait array with the handles that the cache needs to wait on. - * These handles are: - * - the process_process_param's interrupt event - * - the process_cache's cache_add_trigger event - * - the handle for each live process in the cache. - * - * Return value: the number of live handles in the array. - */ - -size_t -process_cache::sync_wait_array (const HANDLE interrupt_event) -{ - assert (this); - assert (_cache_add_trigger && _cache_add_trigger != INVALID_HANDLE_VALUE); - assert (interrupt_event && interrupt_event != INVALID_HANDLE_VALUE); - - EnterCriticalSection (&_cache_write_access); - - assert (_processes_count + SPECIALS_COUNT <= elements (_wait_array)); - - size_t index = 0; - - for (class process *ptr = _processes_head; ptr; ptr = ptr->_next) - { - assert (ptr->_hProcess && ptr->_hProcess != INVALID_HANDLE_VALUE); - assert (ptr->is_active ()); - - _wait_array[index] = ptr->handle (); - _process_array[index++] = ptr; - - assert (index <= elements (_wait_array)); - } - - /* Sorry for shouting, but THESE MUST BE ADDED AT THE END! */ - /* Well, not strictly `must', but it's more efficient if they are :-) */ - - _wait_array[index] = interrupt_event; - _process_array[index++] = NULL; - - _wait_array[index] = _cache_add_trigger; - _process_array[index++] = NULL; - - /* Phew, back to normal volume now. */ - - assert (index <= elements (_wait_array)); - - LeaveCriticalSection (&_cache_write_access); - - return index; -} - -void -process_cache::check_and_remove_process (const size_t index) -{ - assert (this); - assert (index < elements (_wait_array) - SPECIALS_COUNT); - - class process *const process = _process_array[index]; - - assert (process); - assert (process->handle () == _wait_array[index]); - - if (process->check_exit_code () == STILL_ACTIVE) - return; - - debug_printf ("process %d(%lu) has left the building ($? = %lu)", - process->_cygpid, process->_winpid, process->_exit_status); - - /* Unlink the process object from the process list. */ - - EnterCriticalSection (&_cache_write_access); - - class process *previous = NULL; - - const class process *const tmp = find (process->_winpid, &previous); - - assert (tmp == process); - assert (previous ? previous->_next == process : _processes_head == process); - - if (previous) - previous->_next = process->_next; - else - _processes_head = process->_next; - - _processes_count -= 1; - LeaveCriticalSection (&_cache_write_access); - - /* Schedule any cleanup tasks for this process. */ - _queue.add (safe_new (process_cleanup, process)); -} - -class process * -process_cache::find (const DWORD winpid, class process **previous) -{ - if (previous) - *previous = NULL; - - for (class process *ptr = _processes_head; ptr; ptr = ptr->_next) - if (ptr->_winpid == winpid) - return ptr; - else if (ptr->_winpid > winpid) // The list is sorted by winpid. - return NULL; - else if (previous) - *previous = ptr; - - return NULL; -} - -/*****************************************************************************/ diff --git a/winsup/cygwin/cygserver_shm.cc b/winsup/cygwin/cygserver_shm.cc deleted file mode 100755 index 90053eec2..000000000 --- a/winsup/cygwin/cygserver_shm.cc +++ /dev/null @@ -1,896 +0,0 @@ -/* cygserver_shm.cc: Single unix specification IPC interface for Cygwin. - - Copyright 2002 Red Hat, Inc. - - Written by Conrad Scott . - Based on code by Robert Collins . - -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. */ - -#include "woutsup.h" - -#include -#include -#include -#include -#include - -#include "cygserver_ipc.h" -#include "cygserver_shm.h" -#include "security.h" - -#include "cygwin/cygserver.h" -#include "cygwin/cygserver_process.h" -#include "cygwin/cygserver_transport.h" - -/*---------------------------------------------------------------------------* - * class server_shmmgr - * - * A singleton class. - *---------------------------------------------------------------------------*/ - -#define shmmgr (server_shmmgr::instance ()) - -class server_shmmgr -{ -private: - class attach_t - { - public: - class process *const _client; - unsigned int _refcnt; - - attach_t *_next; - - attach_t (class process *const client) - : _client (client), - _refcnt (0), - _next (NULL) - {} - }; - - class segment_t - { - private: - // Bits for the _flg field. - enum { IS_DELETED = 0x01 }; - - public: - const int _intid; - const int _shmid; - struct shmid_ds _ds; - - segment_t *_next; - - segment_t (const key_t key, const int intid, const HANDLE hFileMap); - ~segment_t (); - - bool is_deleted () const - { - return _flg & IS_DELETED; - } - - bool is_pending_delete () const - { - return !_ds.shm_nattch && is_deleted (); - } - - void mark_deleted () - { - assert (!is_deleted ()); - - _flg |= IS_DELETED; - } - - int attach (class process *, HANDLE & hFileMap); - int detach (class process *); - - private: - static long _sequence; - - int _flg; - const HANDLE _hFileMap; - attach_t *_attach_head; // A list sorted by winpid; - - attach_t *find (const class process *, attach_t **previous = NULL); - }; - - class cleanup_t : public cleanup_routine - { - public: - cleanup_t (const segment_t *const segptr) - : cleanup_routine (reinterpret_cast (segptr->_shmid)) - { - assert (key ()); - } - - int shmid () const { return reinterpret_cast (key ()); } - - virtual void cleanup (class process *const client) - { - const int res = shmmgr.shmdt (shmid (), client); - - if (res != 0) - debug_printf ("process cleanup failed [shmid = %d]: %s", - shmid (), strerror (-res)); - } - }; - -public: - static server_shmmgr & instance (); - - int shmat (HANDLE & hFileMap, - int shmid, int shmflg, class process *); - int shmctl (int & out_shmid, struct shmid_ds & out_ds, - struct shminfo & out_shminfo, struct shm_info & out_shm_info, - const int shmid, int cmd, const struct shmid_ds &, - class process *); - int shmdt (int shmid, class process *); - int shmget (int & out_shmid, key_t, size_t, int shmflg, uid_t, gid_t, - class process *); - -private: - static server_shmmgr *_instance; - static pthread_once_t _instance_once; - - static void initialise_instance (); - - CRITICAL_SECTION _segments_lock; - segment_t *_segments_head; // A list sorted by int_id. - - int _shm_ids; // Number of shm segments (for ipcs(8)). - int _shm_tot; // Total bytes of shm segments (for ipcs(8)). - int _shm_atts; // Number of attached segments (for ipcs(8)). - int _intid_max; // Highest intid yet allocated (for ipcs(8)). - - server_shmmgr (); - ~server_shmmgr (); - - // Undefined (as this class is a singleton): - server_shmmgr (const server_shmmgr &); - server_shmmgr & operator= (const server_shmmgr &); - - segment_t *find_by_key (key_t); - segment_t *find (int intid, segment_t **previous = NULL); - - int new_segment (key_t, size_t, int shmflg, pid_t, uid_t, gid_t); - - segment_t *new_segment (key_t, size_t, HANDLE); - void delete_segment (segment_t *); -}; - -/* static */ long server_shmmgr::segment_t::_sequence = 0; - -/* static */ server_shmmgr *server_shmmgr::_instance = NULL; -/* static */ pthread_once_t server_shmmgr::_instance_once = PTHREAD_ONCE_INIT; - -/*---------------------------------------------------------------------------* - * server_shmmgr::segment_t::segment_t () - *---------------------------------------------------------------------------*/ - -server_shmmgr::segment_t::segment_t (const key_t key, - const int intid, - const HANDLE hFileMap) - : _intid (intid), - _shmid (ipc_int2ext (intid, IPC_SHMOP, _sequence)), - _next (NULL), - _flg (0), - _hFileMap (hFileMap), - _attach_head (NULL) -{ - assert (0 <= _intid && _intid < SHMMNI); - - memset (&_ds, '\0', sizeof (_ds)); - _ds.shm_perm.key = key; -} - -/*---------------------------------------------------------------------------* - * server_shmmgr::segment_t::~segment_t () - *---------------------------------------------------------------------------*/ - -server_shmmgr::segment_t::~segment_t () -{ - assert (!_attach_head); - - if (!CloseHandle (_hFileMap)) - syscall_printf ("failed to close file map [handle = 0x%x]: %E", _hFileMap); -} - -/*---------------------------------------------------------------------------* - * server_shmmgr::segment_t::attach () - *---------------------------------------------------------------------------*/ - -int -server_shmmgr::segment_t::attach (class process *const client, - HANDLE & hFileMap) -{ - assert (client); - - if (!DuplicateHandle (GetCurrentProcess (), - _hFileMap, - client->handle (), - &hFileMap, - 0, - FALSE, // bInheritHandle - DUPLICATE_SAME_ACCESS)) - { - syscall_printf (("failed to duplicate handle for client " - "[key = 0x%016llx, shmid = %d, handle = 0x%x]: %E"), - _ds.shm_perm.key, _shmid, _hFileMap); - - return -EACCES; // FIXME: Case analysis? - } - - _ds.shm_lpid = client->cygpid (); - _ds.shm_nattch += 1; - _ds.shm_atime = time (NULL); // FIXME: sub-second times. - - attach_t *previous = NULL; - attach_t *attptr = find (client, &previous); - - if (!attptr) - { - attptr = safe_new (attach_t, client); - - if (previous) - { - attptr->_next = previous->_next; - previous->_next = attptr; - } - else - { - attptr->_next = _attach_head; - _attach_head = attptr; - } - } - - attptr->_refcnt += 1; - - cleanup_t *const cleanup = safe_new (cleanup_t, this); - - // FIXME: ::add should only fail if the process object is already - // cleaning up; but it can't be doing that since this thread has it - // locked. - - const bool result = client->add (cleanup); - - assert (result); - - return 0; -} - -/*---------------------------------------------------------------------------* - * server_shmmgr::segment_t::detach () - *---------------------------------------------------------------------------*/ - -int -server_shmmgr::segment_t::detach (class process *const client) -{ - attach_t *previous = NULL; - attach_t *const attptr = find (client, &previous); - - if (!attptr) - return -EINVAL; - - if (client->is_active ()) - { - const cleanup_t key (this); - - if (!client->remove (&key)) - syscall_printf (("failed to remove cleanup routine for %d(%lu) " - "[shmid = %d]"), - client->cygpid (), client->winpid (), - _shmid); - } - - attptr->_refcnt -= 1; - - if (!attptr->_refcnt) - { - assert (previous ? previous->_next == attptr : _attach_head == attptr); - - if (previous) - previous->_next = attptr->_next; - else - _attach_head = attptr->_next; - - safe_delete (attptr); - } - - assert (_ds.shm_nattch > 0); - - _ds.shm_lpid = client->cygpid (); - _ds.shm_nattch -= 1; - _ds.shm_dtime = time (NULL); // FIXME: sub-second times. - - return 0; -} - -/*---------------------------------------------------------------------------* - * server_shmmgr::segment_t::find () - *---------------------------------------------------------------------------*/ - -server_shmmgr::attach_t * -server_shmmgr::segment_t::find (const class process *const client, - attach_t **previous) -{ - if (previous) - *previous = NULL; - - // Nb. The _attach_head list is sorted by winpid. - - for (attach_t *attptr = _attach_head; attptr; attptr = attptr->_next) - if (attptr->_client == client) - return attptr; - else if (attptr->_client->winpid () > client->winpid ()) - return NULL; - else if (previous) - *previous = attptr; - - return NULL; -} - -/*---------------------------------------------------------------------------* - * server_shmmgr::instance () - *---------------------------------------------------------------------------*/ - -/* static */ server_shmmgr & -server_shmmgr::instance () -{ - pthread_once (&_instance_once, &initialise_instance); - - assert (_instance); - - return *_instance; -} - -/*---------------------------------------------------------------------------* - * server_shmmgr::shmat () - *---------------------------------------------------------------------------*/ - -int -server_shmmgr::shmat (HANDLE & hFileMap, - const int shmid, const int shmflg, - class process *const client) -{ - syscall_printf ("shmat (shmid = %d, shmflg = 0%o) for %d(%lu)", - shmid, shmflg, client->cygpid (), client->winpid ()); - - int result = 0; - EnterCriticalSection (&_segments_lock); - - segment_t *const segptr = find (ipc_ext2int (shmid, IPC_SHMOP)); - - if (!segptr) - result = -EINVAL; - else - result = segptr->attach (client, hFileMap); - - if (!result) - _shm_atts += 1; - - LeaveCriticalSection (&_segments_lock); - - if (result < 0) - syscall_printf (("-1 [%d] = shmat (shmid = %d, shmflg = 0%o) " - "for %d(%lu)"), - -result, shmid, shmflg, - client->cygpid (), client->winpid ()); - else - syscall_printf (("0x%x = shmat (shmid = %d, shmflg = 0%o) " - "for %d(%lu)"), - hFileMap, shmid, shmflg, - client->cygpid (), client->winpid ()); - - return result; -} - -/*---------------------------------------------------------------------------* - * server_shmmgr::shmctl () - *---------------------------------------------------------------------------*/ - -int -server_shmmgr::shmctl (int & out_shmid, - struct shmid_ds & out_ds, - struct shminfo & out_shminfo, - struct shm_info & out_shm_info, - const int shmid, const int cmd, - const struct shmid_ds & ds, - class process *const client) -{ - syscall_printf ("shmctl (shmid = %d, cmd = 0x%x) for %d(%lu)", - shmid, cmd, client->cygpid (), client->winpid ()); - - int result = 0; - EnterCriticalSection (&_segments_lock); - - switch (cmd) - { - case IPC_STAT: - case SHM_STAT: // Uses intids rather than shmids. - case IPC_SET: - case IPC_RMID: - { - int intid; - - if (cmd == SHM_STAT) - intid = shmid; - else - intid = ipc_ext2int (shmid, IPC_SHMOP); - - segment_t *const segptr = find (intid); - - if (!segptr) - result = -EINVAL; - else - switch (cmd) - { - case IPC_STAT: - out_ds = segptr->_ds; - break; - - case IPC_SET: - segptr->_ds.shm_perm.uid = ds.shm_perm.uid; - segptr->_ds.shm_perm.gid = ds.shm_perm.gid; - segptr->_ds.shm_perm.mode = ds.shm_perm.mode & 0777; - segptr->_ds.shm_lpid = client->cygpid (); - segptr->_ds.shm_ctime = time (NULL); // FIXME: sub-second times. - break; - - case IPC_RMID: - if (segptr->is_deleted ()) - result = -EIDRM; - else - { - segptr->mark_deleted (); - if (segptr->is_pending_delete ()) - delete_segment (segptr); - } - break; - - case SHM_STAT: // ipcs(8) i'face. - out_ds = segptr->_ds; - out_shmid = segptr->_shmid; - break; - } - } - break; - - case IPC_INFO: - out_shminfo.shmmax = SHMMAX; - out_shminfo.shmmin = SHMMIN; - out_shminfo.shmmni = SHMMNI; - out_shminfo.shmseg = SHMSEG; - out_shminfo.shmall = SHMALL; - break; - - case SHM_INFO: // ipcs(8) i'face. - out_shmid = _intid_max; - out_shm_info.shm_ids = _shm_ids; - out_shm_info.shm_tot = _shm_tot; - out_shm_info.shm_atts = _shm_atts; - break; - - default: - result = -EINVAL; - break; - } - - LeaveCriticalSection (&_segments_lock); - - if (result < 0) - syscall_printf (("-1 [%d] = " - "shmctl (shmid = %d, cmd = 0x%x) for %d(%lu)"), - -result, - shmid, cmd, client->cygpid (), client->winpid ()); - else - syscall_printf (("%d = " - "shmctl (shmid = %d, cmd = 0x%x) for %d(%lu)"), - ((cmd == SHM_STAT || cmd == SHM_INFO) - ? out_shmid - : result), - shmid, cmd, client->cygpid (), client->winpid ()); - - return result; -} - -/*---------------------------------------------------------------------------* - * server_shmmgr::shmdt () - *---------------------------------------------------------------------------*/ - -int -server_shmmgr::shmdt (const int shmid, class process *const client) -{ - syscall_printf ("shmdt (shmid = %d) for %d(%lu)", - shmid, client->cygpid (), client->winpid ()); - - int result = 0; - EnterCriticalSection (&_segments_lock); - - segment_t *const segptr = find (ipc_ext2int (shmid, IPC_SHMOP)); - - if (!segptr) - result = -EINVAL; - else - result = segptr->detach (client); - - if (!result) - _shm_atts -= 1; - - if (!result && segptr->is_pending_delete ()) - delete_segment (segptr); - - LeaveCriticalSection (&_segments_lock); - - if (result < 0) - syscall_printf ("-1 [%d] = shmdt (shmid = %d) for %d(%lu)", - -result, shmid, client->cygpid (), client->winpid ()); - else - syscall_printf ("%d = shmdt (shmid = %d) for %d(%lu)", - result, shmid, client->cygpid (), client->winpid ()); - - return result; -} - -/*---------------------------------------------------------------------------* - * server_shmmgr::shmget () - *---------------------------------------------------------------------------*/ - -int -server_shmmgr::shmget (int & out_shmid, - const key_t key, const size_t size, const int shmflg, - const uid_t uid, const gid_t gid, - class process *const client) -{ - syscall_printf (("shmget (key = 0x%016llx, size = %u, shmflg = 0%o) " - "for %d(%lu)"), - key, size, shmflg, - client->cygpid (), client->winpid ()); - - int result = 0; - EnterCriticalSection (&_segments_lock); - - if (key == IPC_PRIVATE) - result = new_segment (key, size, shmflg, - client->cygpid (), uid, gid); - else - { - segment_t *const segptr = find_by_key (key); - - if (!segptr) - if (shmflg & IPC_CREAT) - result = new_segment (key, size, shmflg, - client->cygpid (), uid, gid); - else - result = -ENOENT; - else if (segptr->is_deleted ()) - result = -EIDRM; - else if ((shmflg & IPC_CREAT) && (shmflg & IPC_EXCL)) - result = -EEXIST; - else if ((shmflg & ~(segptr->_ds.shm_perm.mode)) & 0777) - result = -EACCES; - else if (size && segptr->_ds.shm_segsz < size) - result = -EINVAL; - else - result = segptr->_shmid; - } - - LeaveCriticalSection (&_segments_lock); - - if (result >= 0) - { - out_shmid = result; - result = 0; - } - - if (result < 0) - syscall_printf (("-1 [%d] = " - "shmget (key = 0x%016llx, size = %u, shmflg = 0%o) " - "for %d(%lu)"), - -result, - key, size, shmflg, - client->cygpid (), client->winpid ()); - else - syscall_printf (("%d = " - "shmget (key = 0x%016llx, size = %u, shmflg = 0%o) " - "for %d(%lu)"), - out_shmid, - key, size, shmflg, - client->cygpid (), client->winpid ()); - - return result; -} - -/*---------------------------------------------------------------------------* - * server_shmmgr::initialise_instance () - *---------------------------------------------------------------------------*/ - -/* static */ void -server_shmmgr::initialise_instance () -{ - assert (!_instance); - - _instance = safe_new0 (server_shmmgr); - - assert (_instance); -} - -/*---------------------------------------------------------------------------* - * server_shmmgr::server_shmmgr () - *---------------------------------------------------------------------------*/ - -server_shmmgr::server_shmmgr () - : _segments_head (NULL), - _shm_ids (0), - _shm_tot (0), - _shm_atts (0), - _intid_max (0) -{ - InitializeCriticalSection (&_segments_lock); -} - -/*---------------------------------------------------------------------------* - * server_shmmgr::~server_shmmgr () - *---------------------------------------------------------------------------*/ - -server_shmmgr::~server_shmmgr () -{ - DeleteCriticalSection (&_segments_lock); -} - -/*---------------------------------------------------------------------------* - * server_shmmgr::find_by_key () - *---------------------------------------------------------------------------*/ - -server_shmmgr::segment_t * -server_shmmgr::find_by_key (const key_t key) -{ - for (segment_t *segptr = _segments_head; segptr; segptr = segptr->_next) - if (segptr->_ds.shm_perm.key == key) - return segptr; - - return NULL; -} - -/*---------------------------------------------------------------------------* - * server_shmmgr::find () - *---------------------------------------------------------------------------*/ - -server_shmmgr::segment_t * -server_shmmgr::find (const int intid, segment_t **previous) -{ - if (previous) - *previous = NULL; - - for (segment_t *segptr = _segments_head; segptr; segptr = segptr->_next) - if (segptr->_intid == intid) - return segptr; - else if (segptr->_intid > intid) // The list is sorted by intid. - return NULL; - else if (previous) - *previous = segptr; - - return NULL; -} - -/*---------------------------------------------------------------------------* - * server_shmmgr::new_segment () - *---------------------------------------------------------------------------*/ - -int -server_shmmgr::new_segment (const key_t key, - const size_t size, - const int shmflg, - const pid_t cygpid, - const uid_t uid, - const gid_t gid) -{ - if (size < SHMMIN || size > SHMMAX) - return -EINVAL; - - const HANDLE hFileMap = CreateFileMapping (INVALID_HANDLE_VALUE, - NULL, PAGE_READWRITE, - 0, size, - NULL); - - if (!hFileMap) - { - syscall_printf ("failed to create file mapping [size = %lu]: %E", size); - return -ENOMEM; // FIXME - } - - segment_t *const segptr = new_segment (key, size, hFileMap); - - if (!segptr) - { - (void) CloseHandle (hFileMap); - return -ENOSPC; - } - - segptr->_ds.shm_perm.cuid = segptr->_ds.shm_perm.uid = uid; - segptr->_ds.shm_perm.cgid = segptr->_ds.shm_perm.gid = gid; - segptr->_ds.shm_perm.mode = shmflg & 0777; - segptr->_ds.shm_segsz = size; - segptr->_ds.shm_cpid = cygpid; - segptr->_ds.shm_ctime = time (NULL); // FIXME: sub-second times. - - return segptr->_shmid; -} - -/*---------------------------------------------------------------------------* - * server_shmmgr::new_segment () - * - * Allocate a new segment for the given key and file map with the - * lowest available intid and insert into the segment map. - *---------------------------------------------------------------------------*/ - -server_shmmgr::segment_t * -server_shmmgr::new_segment (const key_t key, const size_t size, - const HANDLE hFileMap) -{ - // FIXME: Overflow risk. - if (_shm_tot + size > SHMALL) - return NULL; - - int intid = 0; // Next expected intid value. - segment_t *previous = NULL; // Insert pointer. - - // Find first unallocated intid. - for (segment_t *segptr = _segments_head; - segptr && segptr->_intid == intid; - segptr = segptr->_next, intid++) - { - previous = segptr; - } - - /* By the time this condition is reached (given the default value of - * SHMMNI), the linear searches should all replaced by something - * just a *little* cleverer . . . - */ - if (intid >= SHMMNI) - return NULL; - - segment_t *const segptr = safe_new (segment_t, key, intid, hFileMap); - - assert (segptr); - - if (previous) - { - segptr->_next = previous->_next; - previous->_next = segptr; - } - else - { - segptr->_next = _segments_head; - _segments_head = segptr; - } - - _shm_ids += 1; - _shm_tot += size; - if (intid > _intid_max) - _intid_max = intid; - - return segptr; -} - -/*---------------------------------------------------------------------------* - * server_shmmgr::delete_segment () - *---------------------------------------------------------------------------*/ - -void -server_shmmgr::delete_segment (segment_t *const segptr) -{ - assert (segptr); - assert (segptr->is_pending_delete ()); - - segment_t *previous = NULL; - - const segment_t *const tmp = find (segptr->_intid, &previous); - - assert (tmp == segptr); - assert (previous ? previous->_next == segptr : _segments_head == segptr); - - if (previous) - previous->_next = segptr->_next; - else - _segments_head = segptr->_next; - - assert (_shm_ids > 0); - _shm_ids -= 1; - _shm_tot -= segptr->_ds.shm_segsz; - - safe_delete (segptr); -} - -/*---------------------------------------------------------------------------* - * client_request_shm::client_request_shm () - *---------------------------------------------------------------------------*/ - -client_request_shm::client_request_shm () - : client_request (CYGSERVER_REQUEST_SHM, - &_parameters, sizeof (_parameters)) -{ - // verbose: syscall_printf ("created"); -} - -/*---------------------------------------------------------------------------* - * client_request_shm::serve () - *---------------------------------------------------------------------------*/ - -void -client_request_shm::serve (transport_layer_base *const conn, - process_cache *const cache) -{ - assert (conn); - - assert (!error_code ()); - - if (msglen () != sizeof (_parameters.in)) - { - syscall_printf ("bad request body length: expecting %lu bytes, got %lu", - sizeof (_parameters), msglen ()); - error_code (EINVAL); - msglen (0); - return; - } - - // FIXME: Get a return code out of this and don't continue on error. - conn->impersonate_client (); - - class process *const client = cache->process (_parameters.in.cygpid, - _parameters.in.winpid); - - if (!client) - { - error_code (EAGAIN); - msglen (0); - return; - } - - int result = -EINVAL; - - switch (_parameters.in.shmop) - { - case SHMOP_shmget: - result = shmmgr.shmget (_parameters.out.shmid, - _parameters.in.key, _parameters.in.size, - _parameters.in.shmflg, - _parameters.in.uid, _parameters.in.gid, - client); - break; - - case SHMOP_shmat: - result = shmmgr.shmat (_parameters.out.hFileMap, - _parameters.in.shmid, _parameters.in.shmflg, - client); - break; - - case SHMOP_shmdt: - result = shmmgr.shmdt (_parameters.in.shmid, client); - break; - - case SHMOP_shmctl: - result = shmmgr.shmctl (_parameters.out.shmid, - _parameters.out.ds, _parameters.out.shminfo, - _parameters.out.shm_info, - _parameters.in.shmid, _parameters.in.cmd, - _parameters.in.ds, - client); - break; - } - - client->release (); - conn->revert_to_self (); - - if (result < 0) - { - error_code (-result); - msglen (0); - } - else - msglen (sizeof (_parameters.out)); -} diff --git a/winsup/cygwin/cygserver_shm.h b/winsup/cygwin/cygserver_shm.h deleted file mode 100644 index 5a5ee3820..000000000 --- a/winsup/cygwin/cygserver_shm.h +++ /dev/null @@ -1,147 +0,0 @@ -/* cygserver_shm.h: Single unix specification IPC interface for Cygwin. - - Copyright 2002 Red Hat, Inc. - - Written by Conrad Scott . - Based on code by Robert Collins . - -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. */ - -#ifndef __CYGSERVER_SHM_H__ -#define __CYGSERVER_SHM_H__ - -#include -#include - -#include -#include - -#include "cygserver_ipc.h" - -#include "cygwin/cygserver.h" - -/*---------------------------------------------------------------------------* - * Values for the shminfo entries. - * - * Nb. The values are segregated between two enums so that the `small' - * values aren't promoted to `unsigned long' equivalents. - *---------------------------------------------------------------------------*/ - -enum - { - SHMMAX = ULONG_MAX, - SHMSEG = ULONG_MAX, - SHMALL = ULONG_MAX - }; - -enum - { - SHMMIN = 1, - SHMMNI = IPCMNI // Must be <= IPCMNI. - }; - -/*---------------------------------------------------------------------------* - * class client_request_shm - *---------------------------------------------------------------------------*/ - -#ifndef __INSIDE_CYGWIN__ -class transport_layer_base; -class process_cache; -#endif - -class client_request_shm : public client_request -{ - friend class client_request; - -public: - enum shmop_t - { - SHMOP_shmat, - SHMOP_shmctl, - SHMOP_shmdt, - SHMOP_shmget - }; - -#ifdef __INSIDE_CYGWIN__ - client_request_shm (int shmid, int shmflg); // shmat - client_request_shm (int shmid, int cmd, const struct shmid_ds *); // shmctl - client_request_shm (int shmid); // shmdt - client_request_shm (key_t, size_t, int shmflg); // shmget -#endif - - // Accessors for out parameters. - - int shmid () const - { - assert (!error_code ()); - return _parameters.out.shmid; - } - - HANDLE hFileMap () const - { - assert (!error_code ()); - return _parameters.out.hFileMap; - } - - const struct shmid_ds & ds () const - { - assert (!error_code ()); - return _parameters.out.ds; - } - - const struct shminfo & shminfo () const - { - assert (!error_code ()); - return _parameters.out.shminfo; - } - - const struct shm_info & shm_info () const - { - assert (!error_code ()); - return _parameters.out.shm_info; - } - -private: - union - { - struct - { - shmop_t shmop; - key_t key; - size_t size; - int shmflg; - int shmid; - int cmd; - pid_t cygpid; - DWORD winpid; - __uid32_t uid; - __gid32_t gid; - struct shmid_ds ds; - } in; - - struct { - int shmid; - union - { - HANDLE hFileMap; - struct shmid_ds ds; - struct shminfo shminfo; - struct shm_info shm_info; - }; - } out; - } _parameters; - -#ifndef __INSIDE_CYGWIN__ - client_request_shm (); -#endif - -#ifndef __INSIDE_CYGWIN__ - virtual void serve (transport_layer_base *, process_cache *); -#endif -}; - -#endif /* __CYGSERVER_SHM_H__ */ diff --git a/winsup/cygwin/cygserver_transport.cc b/winsup/cygwin/cygserver_transport.cc deleted file mode 100755 index 8684a6148..000000000 --- a/winsup/cygwin/cygserver_transport.cc +++ /dev/null @@ -1,51 +0,0 @@ -/* cygserver_transport.cc - - Copyright 2001, 2002 Red Hat Inc. - - Written by Robert Collins - -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. */ - -/* 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 "safe_memory.h" - -#include "cygwin/cygserver_transport.h" -#include "cygwin/cygserver_transport_pipes.h" -#include "cygwin/cygserver_transport_sockets.h" - -/* The factory */ -transport_layer_base * -create_server_transport () -{ - if (wincap.is_winnt ()) - return safe_new0 (transport_layer_pipes); - else - return safe_new0 (transport_layer_sockets); -} - -#ifndef __INSIDE_CYGWIN__ - -void -transport_layer_base::impersonate_client () -{} - -void -transport_layer_base::revert_to_self () -{} - -#endif /* !__INSIDE_CYGWIN__ */ - -transport_layer_base::~transport_layer_base () -{} diff --git a/winsup/cygwin/cygserver_transport_pipes.cc b/winsup/cygwin/cygserver_transport_pipes.cc deleted file mode 100755 index 6d80defd4..000000000 --- a/winsup/cygwin/cygserver_transport_pipes.cc +++ /dev/null @@ -1,362 +0,0 @@ -/* cygserver_transport_pipes.cc - - Copyright 2001, 2002 Red Hat Inc. - - Written by Robert Collins - -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. */ - -/* 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 "cygerrno.h" -#include "cygwin/cygserver_transport.h" -#include "cygwin/cygserver_transport_pipes.h" - -#ifndef __INSIDE_CYGWIN__ -#include "cygwin/cygserver.h" -#endif - -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 () -{ - assert (pipe_instance == 0); - InitializeCriticalSection (&pipe_instance_lock); -} - -#endif /* !__INSIDE_CYGWIN__ */ - -#ifndef __INSIDE_CYGWIN__ - -transport_layer_pipes::transport_layer_pipes (const HANDLE hPipe) - : _pipe_name (""), - _hPipe (hPipe), - _is_accepted_endpoint (true), - _is_listening_endpoint (false) -{ - 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 () -{ - assert (wincap.has_security ()); - - /* FIXME: pthread_once or equivalent needed */ - - 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; -} - -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 (bool *const recoverable) -{ - 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) - { - *recoverable = false; - system_printf ("failed to create named pipe: " - "is the daemon already running?"); - return NULL; - } - - if (accept_pipe == INVALID_HANDLE_VALUE) - { - debug_printf ("error creating pipe (%lu).", GetLastError ()); - *recoverable = true; // FIXME: case analysis? - return NULL; - } - - assert (accept_pipe); - - if (!ConnectNamedPipe (accept_pipe, NULL) - && GetLastError () != ERROR_PIPE_CONNECTED) - { - debug_printf ("error connecting to pipe (%lu)", GetLastError ()); - (void) CloseHandle (accept_pipe); - *recoverable = true; // FIXME: case analysis? - return NULL; - } - - return safe_new (transport_layer_pipes, accept_pipe); -} - -#endif /* !__INSIDE_CYGWIN__ */ - -void -transport_layer_pipes::close () -{ - // verbose: debug_printf ("closing pipe %p", _hPipe); - - if (_hPipe) - { - 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 (void *const buf, const size_t len) -{ - // verbose: debug_printf ("reading from pipe %p", _hPipe); - - assert (_hPipe); - assert (_hPipe != INVALID_HANDLE_VALUE); - assert (!_is_listening_endpoint); - - DWORD count; - if (!ReadFile (_hPipe, buf, len, &count, NULL)) - { - debug_printf ("error reading from pipe (%lu)", GetLastError ()); - set_errno (EINVAL); // FIXME? - return -1; - } - - return count; -} - -ssize_t -transport_layer_pipes::write (void *const buf, const size_t len) -{ - // verbose: debug_printf ("writing to pipe %p", _hPipe); - - assert (_hPipe); - assert (_hPipe != INVALID_HANDLE_VALUE); - assert (!_is_listening_endpoint); - - DWORD count; - if (!WriteFile (_hPipe, buf, len, &count, NULL)) - { - debug_printf ("error writing to pipe, error = %lu", GetLastError ()); - set_errno (EINVAL); // FIXME? - return -1; - } - - return count; -} - -/* - * 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 () -{ - assert (!_hPipe); - assert (!_is_accepted_endpoint); - assert (!_is_listening_endpoint); - - static bool assume_cygserver = false; - - BOOL rc = TRUE; - int retries = 0; - - while (rc) - { - _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 () -{ - 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 () -{ - assert (_is_accepted_endpoint); - - RevertToSelf (); - // verbose: debug_printf ("I am who I yam"); -} - -#endif /* !__INSIDE_CYGWIN__ */ diff --git a/winsup/cygwin/cygserver_transport_sockets.cc b/winsup/cygwin/cygserver_transport_sockets.cc deleted file mode 100755 index 6ade14bff..000000000 --- a/winsup/cygwin/cygserver_transport_sockets.cc +++ /dev/null @@ -1,387 +0,0 @@ -/* cygserver_transport_sockets.cc - - Copyright 2001, 2002 Red Hat Inc. - - Written by Robert Collins - -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. */ - -/* 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 "cygwin/cygserver_transport.h" -#include "cygwin/cygserver_transport_sockets.h" - -/* to allow this to link into cygwin and the .dll, a little magic is needed. */ -#ifndef __OUTSIDE_CYGWIN__ - -extern "C" int cygwin_accept (int fd, struct sockaddr *, int *len); -extern "C" int cygwin_bind (int fd, const struct sockaddr *, int len); -extern "C" int cygwin_connect (int fd, const struct sockaddr *, int len); -extern "C" int cygwin_listen (int fd, int backlog); -extern "C" int cygwin_shutdown (int fd, int how); -extern "C" int cygwin_socket (int af, int type, int protocol); - -#else /* __OUTSIDE_CYGWIN__ */ - -#define cygwin_accept(A,B,C) ::accept (A,B,C) -#define cygwin_bind(A,B,C) ::bind (A,B,C) -#define cygwin_connect(A,B,C) ::connect (A,B,C) -#define cygwin_listen(A,B) ::listen (A,B) -#define cygwin_shutdown(A,B) ::shutdown (A,B) -#define cygwin_socket(A,B,C) ::socket (A,B,C) - -#endif /* __OUTSIDE_CYGWIN__ */ - -enum - { - MAX_CONNECT_RETRY = 64 - }; - -transport_layer_sockets::transport_layer_sockets (const int fd) - : _fd (fd), - _addr_len (0), - _is_accepted_endpoint (true), - _is_listening_endpoint (false) -{ - assert (_fd != -1); - - memset (&_addr, '\0', sizeof (_addr)); -} - -transport_layer_sockets::transport_layer_sockets () - : _fd (-1), - _addr_len (0), - _is_accepted_endpoint (false), - _is_listening_endpoint (false) -{ - memset (&_addr, '\0', sizeof (_addr)); - - _addr.sun_family = AF_UNIX; - strcpy (_addr.sun_path, "/tmp/cygdaemo"); // FIXME: $TMP? - _addr_len = SUN_LEN (&_addr); -} - -transport_layer_sockets::~transport_layer_sockets () -{ - close (); -} - -#ifndef __INSIDE_CYGWIN__ - -int -transport_layer_sockets::listen () -{ - assert (_fd == -1); - assert (!_is_accepted_endpoint); - assert (!_is_listening_endpoint); - - debug_printf ("listen () [this = %p]", this); - - struct stat sbuf; - - if (stat (_addr.sun_path, &sbuf) == -1) - { - if (errno != ENOENT) - { - system_printf ("cannot access socket file `%s': %s", - _addr.sun_path, strerror (errno)); - return -1; - } - } - else if (S_ISSOCK (sbuf.st_mode)) - { - // The socket already exists: is a duplicate cygserver running? - - const int newfd = cygwin_socket (AF_UNIX, SOCK_STREAM, 0); - - if (newfd == -1) - { - system_printf ("failed to create UNIX domain socket: %s", - strerror (errno)); - return -1; - } - - if (cygwin_connect (newfd, (struct sockaddr *) &_addr, _addr_len) == 0) - { - system_printf ("the daemon is already running"); - (void) cygwin_shutdown (newfd, SHUT_WR); - char buf[BUFSIZ]; - while (::read (newfd, buf, sizeof (buf)) > 0) - {} - (void) ::close (newfd); - return -1; - } - - if (unlink (_addr.sun_path) == -1) - { - system_printf ("failed to remove `%s': %s", - _addr.sun_path, strerror (errno)); - (void) ::close (newfd); - return -1; - } - } - else - { - system_printf ("cannot create socket `%s': File already exists", - _addr.sun_path); - return -1; - } - - _fd = cygwin_socket (AF_UNIX, SOCK_STREAM, 0); - - if (_fd == -1) - { - system_printf ("failed to create UNIX domain socket: %s", - strerror (errno)); - return -1; - } - - if (cygwin_bind (_fd, (struct sockaddr *) &_addr, _addr_len) == -1) - { - const int saved_errno = errno; - close (); - errno = saved_errno; - system_printf ("failed to bind UNIX domain socket `%s': %s", - _addr.sun_path, strerror (errno)); - return -1; - } - - _is_listening_endpoint = true; // i.e. this really means "have bound". - - if (cygwin_listen (_fd, SOMAXCONN) == -1) - { - const int saved_errno = errno; - close (); - errno = saved_errno; - system_printf ("failed to listen on UNIX domain socket `%s': %s", - _addr.sun_path, strerror (errno)); - return -1; - } - - debug_printf ("0 = listen () [this = %p, fd = %d]", this, _fd); - - return 0; -} - -class transport_layer_sockets * -transport_layer_sockets::accept (bool *const recoverable) -{ - assert (_fd != -1); - assert (!_is_accepted_endpoint); - assert (_is_listening_endpoint); - - debug_printf ("accept () [this = %p, fd = %d]", this, _fd); - - struct sockaddr_un client_addr; - socklen_t client_addr_len = sizeof (client_addr); - - const int accept_fd = - cygwin_accept (_fd, (struct sockaddr *) &client_addr, &client_addr_len); - - if (accept_fd == -1) - { - system_printf ("failed to accept connection: %s", strerror (errno)); - switch (errno) - { - case ECONNABORTED: - case EINTR: - case EMFILE: - case ENFILE: - case ENOBUFS: - case ENOMEM: - *recoverable = true; - break; - - default: - *recoverable = false; - break; - } - return NULL; - } - - debug_printf ("%d = accept () [this = %p, fd = %d]", accept_fd, this, _fd); - - return safe_new (transport_layer_sockets, accept_fd); -} - -#endif /* !__INSIDE_CYGWIN__ */ - -void -transport_layer_sockets::close () -{ - debug_printf ("close () [this = %p, fd = %d]", this, _fd); - - if (_is_listening_endpoint) - (void) unlink (_addr.sun_path); - - if (_fd != -1) - { - (void) cygwin_shutdown (_fd, SHUT_WR); - if (!_is_listening_endpoint) - { - char buf[BUFSIZ]; - while (::read (_fd, buf, sizeof (buf)) > 0) - {} - } - (void) ::close (_fd); - _fd = -1; - } - - _is_listening_endpoint = false; -} - -ssize_t -transport_layer_sockets::read (void *const buf, const size_t buf_len) -{ - assert (_fd != -1); - assert (!_is_listening_endpoint); - - assert (buf); - assert (buf_len > 0); - - // verbose: debug_printf ("read (buf = %p, len = %u) [this = %p, fd = %d]", - // buf, buf_len, this, _fd); - - char *read_buf = static_cast (buf); - size_t read_buf_len = buf_len; - ssize_t res = 0; - - while (read_buf_len != 0 - && (res = ::read (_fd, read_buf, read_buf_len)) > 0) - { - read_buf += res; - read_buf_len -= res; - - assert (read_buf_len >= 0); - } - - if (res != -1) - { - if (res == 0) - errno = EIO; // FIXME? - - res = buf_len - read_buf_len; - } - - if (res != static_cast (buf_len)) - debug_printf ("%d = read (buf = %p, len = %u) [this = %p, fd = %d]: %s", - res, buf, buf_len, this, _fd, - (res == -1 ? strerror (errno) : "EOF")); - else - { - // verbose: debug_printf ("%d = read (buf = %p, len = %u) [this = %p, fd = %d]", - // res, buf, buf_len, this, _fd); - } - - return res; -} - -ssize_t -transport_layer_sockets::write (void *const buf, const size_t buf_len) -{ - assert (_fd != -1); - assert (!_is_listening_endpoint); - - assert (buf); - assert (buf_len > 0); - - // verbose: debug_printf ("write (buf = %p, len = %u) [this = %p, fd = %d]", - // buf, buf_len, this, _fd); - - char *write_buf = static_cast (buf); - size_t write_buf_len = buf_len; - ssize_t res = 0; - - while (write_buf_len != 0 - && (res = ::write (_fd, write_buf, write_buf_len)) > 0) - { - write_buf += res; - write_buf_len -= res; - - assert (write_buf_len >= 0); - } - - if (res != -1) - { - if (res == 0) - errno = EIO; // FIXME? - - res = buf_len - write_buf_len; - } - - if (res != static_cast (buf_len)) - debug_printf ("%d = write (buf = %p, len = %u) [this = %p, fd = %d]: %s", - res, buf, buf_len, this, _fd, - (res == -1 ? strerror (errno) : "EOF")); - else - { - // verbose: debug_printf ("%d = write (buf = %p, len = %u) [this = %p, fd = %d]", - // res, buf, buf_len, this, _fd); - } - - return res; -} - -int -transport_layer_sockets::connect () -{ - assert (_fd == -1); - assert (!_is_accepted_endpoint); - assert (!_is_listening_endpoint); - - static bool assume_cygserver = false; - - debug_printf ("connect () [this = %p]", this); - - for (int retries = 0; retries != MAX_CONNECT_RETRY; retries++) - { - _fd = cygwin_socket (AF_UNIX, SOCK_STREAM, 0); - - if (_fd == -1) - { - system_printf ("failed to create UNIX domain socket: %s", - strerror (errno)); - return -1; - } - - if (cygwin_connect (_fd, (struct sockaddr *) &_addr, _addr_len) == 0) - { - assume_cygserver = true; - debug_printf ("0 = connect () [this = %p, fd = %d]", this, _fd); - return 0; - } - - if (!assume_cygserver || errno != ECONNREFUSED) - { - debug_printf ("failed to connect to server: %s", strerror (errno)); - (void) ::close (_fd); - _fd = -1; - return -1; - } - - (void) ::close (_fd); - _fd = -1; - Sleep (0); // Give the server a chance. - } - - debug_printf ("failed to connect to server: %s", strerror (errno)); - return -1; -} diff --git a/winsup/cygwin/threaded_queue.h b/winsup/cygwin/threaded_queue.h deleted file mode 100755 index 5b6fddc42..000000000 --- a/winsup/cygwin/threaded_queue.h +++ /dev/null @@ -1,127 +0,0 @@ -/* threaded_queue.h - - Copyright 2001, 2002 Red Hat Inc. - - Written by Robert Collins - -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. */ - -#ifndef _THREADED_QUEUE_ -#define _THREADED_QUEUE_ - -/*****************************************************************************/ - -/* a specific request */ - -class queue_request -{ -public: - queue_request *_next; - - queue_request () : _next (NULL) {} - virtual ~queue_request (); - - virtual void process () = 0; -}; - -/*****************************************************************************/ - -/* a queue to allocate requests from n submission loops to x worker threads */ - -class queue_submission_loop; - -class threaded_queue -{ -public: - threaded_queue (size_t initial_workers = 1); - ~threaded_queue (); - - void add_submission_loop (queue_submission_loop *); - - bool running () const { return _running; } - - bool start (); - bool stop (); - - void add (queue_request *); - -private: - long _workers_count; - bool _running; - - queue_submission_loop *_submitters_head; - - long _requests_count; // Informational only. - queue_request *_requests_head; - - CRITICAL_SECTION _queue_lock; - HANDLE _requests_sem; // == _requests_count - - static DWORD WINAPI start_routine (LPVOID /* this */); - - void create_workers (size_t initial_workers); - void worker_loop (); -}; - -/*****************************************************************************/ - -/* parameters for a request finding and submitting loop */ - -class queue_submission_loop -{ - friend class threaded_queue; - -public: - queue_submission_loop (threaded_queue *, bool ninterruptible); - virtual ~queue_submission_loop (); - - bool start (); - bool stop (); - - threaded_queue *queue () { return _queue; }; - -protected: - bool _running; - HANDLE _interrupt_event; - threaded_queue *const _queue; - -private: - bool _interruptible; - HANDLE _hThread; - DWORD _tid; - queue_submission_loop *_next; - - static DWORD WINAPI start_routine (LPVOID /* this */); - virtual void request_loop () = 0; -}; - -#ifdef __cplusplus - -/*---------------------------------------------------------------------------* - * Some type-safe versions of the various interlocked functions. - *---------------------------------------------------------------------------*/ - -template T * -TInterlockedExchangePointer (T **lvalue, T *rvalue) -{ - return reinterpret_cast - (InterlockedExchangePointer (reinterpret_cast (lvalue), - reinterpret_cast (rvalue))); -} - -template T * -TInterlockedCompareExchangePointer (T **lvalue, T *rvalue1, T *rvalue2) -{ - return reinterpret_cast - (InterlockedCompareExchangePointer (reinterpret_cast (lvalue), - reinterpret_cast (rvalue1), - reinterpret_cast (rvalue2))); -} - -#endif /* __cplusplus */ - -#endif /* _THREADED_QUEUE_ */