diff options
author | Conrad Scott <conrad.scott@dsl.pipex.com> | 2002-06-18 01:35:37 +0400 |
---|---|---|
committer | Conrad Scott <conrad.scott@dsl.pipex.com> | 2002-06-18 01:35:37 +0400 |
commit | c84589dfeacc877975ab35b5a3c86815887cd237 (patch) | |
tree | 15d448a388a3e60e91a4da0fd6100960649659b1 /winsup/cygwin | |
parent | 061625829e483cba153df9dbc5670d027b501b1e (diff) |
* include/cygwin/cygserver.h: Change the client_request classes to
give greater encapsulation and to allow variable length requests
and replies.
(enum cygserver_request_code): Now client_request::request_code_t.
(class request_header): Now client_request::header_t. Make a
union of the request_code and the error_code. The `cb' field,
which was the buffer length, is now the `size_t msglen' field.
(struct request_get_version): Now
client_request_get_version::request_get_version.
(struct request_shutdown): Remove unused type.
(struct request_attach_tty): Now
client_request_attach_tty::request_attach_tty.
(client_request::_buf): Make field const.
(client_request::_buflen): New const private field.
(client_request::request_code): New accessor.
(client_request::error_code): Ditto.
(client_request::msglen): Ditto.
(client_request::handle_request): New static method.
(client_request::make_request): New virtual method.
(client_request::handle): New method.
(client_request::send): Make private.
(client_request_get_version::check_version): New method.
(client_request_get_version::serve): Make private.
(client_request_get_version::version): Ditto.
(client_request_shutdown::serve): Ditto.
(client_request_attach_tty::req): Ditto.
(client_request_attach_tty::serve): Ditto.
(client_request_attach_tty::from_master): Make method const.
(client_request_attach_tty::from_master): Ditto.
* cygserver_client.cc
(client_request_get_version::client_request_get_version): Track
changes to the client_request classes.
(client_request_attach_tty::client_request_attach_tty): Ditto.
(client_request_get_version::check_version): New method to
encapsulate code from cygserver_init().
(client_request_shutdown::client_request_shutdown): Move into
"cygserver.cc".
(client_request::send): Track changes to the client_request
classes. Add more error checking.
(client_request::handle_request): New static method containing the
first half of the old server_request::process() code.
(client_request::make_request): New method to replace the old
cygserver_request() function.
(client_request::handle): New method containing the second half of
the old server_request::process() code.
(cygserver_init): Track changes to the client_request classes. In
particular, some code moved into the
client_request_get_version::check_version() method.
* cygserver.cc (client_request_attach_tty::serve): Track changes
to the client_request classes. In particular, only return a reply
body if some handles are successfully duplicated for the client.
And remove goto's.
(client_request_get_version::serve): Track changes to the
client_request classes.
(client_request_shutdown::serve): Ditto.
(class client_request_invalid): Dead, and so young too.
(server_request::request_buffer): Remove unnecessary field.
(client_request_shutdown::client_request_shutdown): Moved here
from "cygserver_client.cc".
(server_request::process): Implementation moved into the new
client_request::handle_request() and client_request::handle()
methods.
* cygserver_shm.h (class client_request_shm): Put client- and
server-specific interfaces inside #ifdef/#ifndef __INSIDE_CYGWIN__
guards.
(client_request_shm::serve): Make private.
* cygserver_shm.cc
(client_request_shm::client_request_shm): Track changes to the
client_request classes.
(client_request_shm::serve): Ditto
* shm.cc (client_request_shm::client_request_shm): Ditto. Use
alloc_sd() rather than set_security_attribute() to get access to
the SECURITY_DESCRIPTOR length, so that we can use it to set the
request body length.
(shmat): Track changes to the client_request classes. In
particular, allocate client_request objects on the stack rather
than on the heap, and use the client_request::make_request()
method rather than the old cygserver_request() function.
(shmdt): Ditto.
(shmctl): Ditto.
(shmget): Ditto.
* fhandler_tty.cc (fhandler_tty_slave::cygserver_attach_tty): Ditto.
Diffstat (limited to 'winsup/cygwin')
-rw-r--r-- | winsup/cygwin/ChangeLog | 85 | ||||
-rwxr-xr-x | winsup/cygwin/cygserver.cc | 296 | ||||
-rwxr-xr-x | winsup/cygwin/cygserver_client.cc | 415 | ||||
-rwxr-xr-x | winsup/cygwin/cygserver_shm.cc | 117 | ||||
-rw-r--r-- | winsup/cygwin/cygserver_shm.h | 37 | ||||
-rw-r--r-- | winsup/cygwin/fhandler_tty.cc | 28 | ||||
-rwxr-xr-x | winsup/cygwin/include/cygwin/cygserver.h | 187 | ||||
-rw-r--r-- | winsup/cygwin/shm.cc | 121 |
8 files changed, 825 insertions, 461 deletions
diff --git a/winsup/cygwin/ChangeLog b/winsup/cygwin/ChangeLog index ffb8e4d0f..4860a810c 100644 --- a/winsup/cygwin/ChangeLog +++ b/winsup/cygwin/ChangeLog @@ -1,5 +1,90 @@ 2002-06-17 Conrad Scott <conrad.scott@dsl.pipex.com> + * include/cygwin/cygserver.h: Change the client_request classes to + give greater encapsulation and to allow variable length requests + and replies. + (enum cygserver_request_code): Now client_request::request_code_t. + (class request_header): Now client_request::header_t. Make a + union of the request_code and the error_code. The `cb' field, + which was the buffer length, is now the `size_t msglen' field. + (struct request_get_version): Now + client_request_get_version::request_get_version. + (struct request_shutdown): Remove unused type. + (struct request_attach_tty): Now + client_request_attach_tty::request_attach_tty. + (client_request::_buf): Make field const. + (client_request::_buflen): New const private field. + (client_request::request_code): New accessor. + (client_request::error_code): Ditto. + (client_request::msglen): Ditto. + (client_request::handle_request): New static method. + (client_request::make_request): New virtual method. + (client_request::handle): New method. + (client_request::send): Make private. + (client_request_get_version::check_version): New method. + (client_request_get_version::serve): Make private. + (client_request_get_version::version): Ditto. + (client_request_shutdown::serve): Ditto. + (client_request_attach_tty::req): Ditto. + (client_request_attach_tty::serve): Ditto. + (client_request_attach_tty::from_master): Make method const. + (client_request_attach_tty::from_master): Ditto. + * cygserver_client.cc + (client_request_get_version::client_request_get_version): Track + changes to the client_request classes. + (client_request_attach_tty::client_request_attach_tty): Ditto. + (client_request_get_version::check_version): New method to + encapsulate code from cygserver_init(). + (client_request_shutdown::client_request_shutdown): Move into + "cygserver.cc". + (client_request::send): Track changes to the client_request + classes. Add more error checking. + (client_request::handle_request): New static method containing the + first half of the old server_request::process() code. + (client_request::make_request): New method to replace the old + cygserver_request() function. + (client_request::handle): New method containing the second half of + the old server_request::process() code. + (cygserver_init): Track changes to the client_request classes. In + particular, some code moved into the + client_request_get_version::check_version() method. + * cygserver.cc (client_request_attach_tty::serve): Track changes + to the client_request classes. In particular, only return a reply + body if some handles are successfully duplicated for the client. + And remove goto's. + (client_request_get_version::serve): Track changes to the + client_request classes. + (client_request_shutdown::serve): Ditto. + (class client_request_invalid): Dead, and so young too. + (server_request::request_buffer): Remove unnecessary field. + (client_request_shutdown::client_request_shutdown): Moved here + from "cygserver_client.cc". + (server_request::process): Implementation moved into the new + client_request::handle_request() and client_request::handle() + methods. + * cygserver_shm.h (class client_request_shm): Put client- and + server-specific interfaces inside #ifdef/#ifndef __INSIDE_CYGWIN__ + guards. + (client_request_shm::serve): Make private. + * cygserver_shm.cc + (client_request_shm::client_request_shm): Track changes to the + client_request classes. + (client_request_shm::serve): Ditto + * shm.cc (client_request_shm::client_request_shm): Ditto. Use + alloc_sd() rather than set_security_attribute() to get access to + the SECURITY_DESCRIPTOR length, so that we can use it to set the + request body length. + (shmat): Track changes to the client_request classes. In + particular, allocate client_request objects on the stack rather + than on the heap, and use the client_request::make_request() + method rather than the old cygserver_request() function. + (shmdt): Ditto. + (shmctl): Ditto. + (shmget): Ditto. + * fhandler_tty.cc (fhandler_tty_slave::cygserver_attach_tty): Ditto. + +2002-06-17 Conrad Scott <conrad.scott@dsl.pipex.com> + * include/cygwin/cygserver_transport.h (cygserver_transport::read): Change buffer type to void *. (cygserver_transport::write): Ditto. diff --git a/winsup/cygwin/cygserver.cc b/winsup/cygwin/cygserver.cc index 836117e3f..d74ee1342 100755 --- a/winsup/cygwin/cygserver.cc +++ b/winsup/cygwin/cygserver.cc @@ -244,146 +244,153 @@ check_and_dup_handle (HANDLE from_process, HANDLE to_process, return (ret_val); } +/* + * client_request_attach_tty::serve () + */ + void -client_request_attach_tty::serve(transport_layer_base *conn, class process_cache *cache) +client_request_attach_tty::serve (transport_layer_base * const conn, + process_cache *) { - HANDLE from_process_handle = NULL; - HANDLE to_process_handle = NULL; - HANDLE token_handle = NULL; - DWORD rc; + assert (conn); + + assert (!error_code ()); if (!wincap.has_security ()) { - system_printf ("this should not be called in a system without security"); - header.error_code = EINVAL; + syscall_printf ("operation only supported on systems with security"); + error_code (EINVAL); + msglen (0); return; } - if (header.cb != sizeof (req)) + if (msglen () != sizeof (req)) { - header.error_code = EINVAL; + syscall_printf ("bad request body length: expecting %lu bytes, got %lu", + sizeof (req), msglen ()); + error_code (EINVAL); + msglen (0); return; } - const HANDLE from_master_orig = req.from_master; - const HANDLE to_master_orig = req.to_master; + 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, + // from_master, to_master, // req.pid); // verbose: debug_printf ("opening process %ld", req.master_pid); - from_process_handle = OpenProcess (PROCESS_DUP_HANDLE, FALSE, 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); - to_process_handle = OpenProcess (PROCESS_DUP_HANDLE, FALSE, req.pid); - if (!from_process_handle || !to_process_handle) + + const HANDLE to_process_handle = + OpenProcess (PROCESS_DUP_HANDLE, FALSE, req.pid); + + if (!to_process_handle) { - system_printf ("error opening process (%lu)", GetLastError ()); - header.error_code = EACCES; - goto out; + 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"); - rc = OpenThreadToken (GetCurrentThread (), - TOKEN_QUERY, - TRUE, - &token_handle); + 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 (%lu)", GetLastError ()); - header.error_code = EACCES; - goto out; - } - - if (check_and_dup_handle (from_process_handle, to_process_handle, - token_handle, - GENERIC_READ, - req.from_master, - &req.from_master, TRUE) != 0) - { - system_printf ("error duplicating from_master handle (%lu)", + system_printf ("error opening thread token, error = %lu", GetLastError ()); - header.error_code = EACCES; - goto out; + CloseHandle (from_process_handle); + CloseHandle (to_process_handle); + error_code (EACCES); + return; } - if (req.to_master) - { - if (check_and_dup_handle (from_process_handle, to_process_handle, - token_handle, - GENERIC_WRITE, - req.to_master, - &req.to_master, TRUE) != 0) - { - system_printf ("error duplicating to_master handle (%lu)", - GetLastError ()); - header.error_code = EACCES; - goto out; - } - } + // 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_orig, to_master_orig, + req.master_pid, from_master, to_master, req.pid, req.from_master, req.to_master); - header.error_code = 0; - -out: - if (from_process_handle) - CloseHandle (from_process_handle); - if (to_process_handle) - CloseHandle (to_process_handle); - if (token_handle) - CloseHandle (token_handle); + return; } void -client_request_get_version::serve(transport_layer_base *conn, class process_cache *cache) +client_request_get_version::serve(transport_layer_base *, process_cache *) { - if (header.cb != sizeof (version)) - { - header.error_code = EINVAL; - return; - } - header.error_code = 0; + 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 client_request_invalid - * - * Used by server_request::process() to handle unrecognised client - * requests. Apart from error reporting (to the log and to the - * client), its main purpose is to provide an implementation of the - * (pure virtual) serve() method that server_request::process() can - * call. - */ - -class client_request_invalid : public client_request -{ -public: - client_request_invalid (const request_header * const hdr) - : client_request (CYGSERVER_REQUEST_INVALID, 0) - { - header.error_code = ENOSYS; - system_printf ("invalid request [type = %d]: returning ENOSYS", - hdr->req_id); - }; - - virtual void serve (transport_layer_base *, class process_cache *) - {}; -}; - class server_request : public queue_request { public: @@ -392,7 +399,6 @@ class server_request : public queue_request virtual ~server_request(); virtual void process (); private: - char request_buffer [MAX_REQUEST_SIZE]; transport_layer_base *conn; class process_cache *cache; }; @@ -411,6 +417,7 @@ class server_request_queue : public threaded_queue void process_requests (transport_layer_base *transport); void add_connection (transport_layer_base *conn); }; + class server_request_queue request_queue; static DWORD WINAPI @@ -442,14 +449,27 @@ server_request_queue::process_requests (transport_layer_base *transport) threaded_queue::process_requests (params, request_loop); } +client_request_shutdown::client_request_shutdown () + : client_request (CYGSERVER_REQUEST_SHUTDOWN) +{ + syscall_printf ("created"); +} + void -client_request_shutdown::serve (transport_layer_base *conn, class process_cache *cache) +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_ */ /* tell the main thread to shutdown */ - request_queue.active=false; + request_queue.active = false; + + msglen (0); } server_request::server_request (transport_layer_base *newconn, @@ -465,71 +485,7 @@ server_request::~server_request () void server_request::process () { - ssize_t bytes_read, bytes_written; - struct request_header* req_ptr = (struct request_header*) &request_buffer; - client_request *req = NULL; - // verbose: debug_printf ("about to read"); - - bytes_read = conn->read (request_buffer, sizeof (struct request_header)); - if (bytes_read != sizeof (struct request_header)) - { - system_printf ("error reading from connection (%lu)", GetLastError ()); - return; - } - // verbose: debug_printf ("got header (%ld)", bytes_read); - - switch (req_ptr->req_id) - { - case CYGSERVER_REQUEST_GET_VERSION: - req = new client_request_get_version (); break; - case CYGSERVER_REQUEST_ATTACH_TTY: - req = new client_request_attach_tty (); break; - case CYGSERVER_REQUEST_SHUTDOWN: - req = new client_request_shutdown (); break; - case CYGSERVER_REQUEST_SHM_GET: - req = new client_request_shm (); break; - default: - req = new client_request_invalid (req_ptr); break; - } - - assert (req); - - if (req->header.cb != req_ptr->cb) - { - system_printf ("Mismatch in request buffer sizes"); - delete req; - return; - } - - if (req->header.cb) - { - bytes_read = conn->read (req->buffer, req->header.cb); - if (bytes_read != req->header.cb) - { - system_printf ("error reading from connection (%lu)", GetLastError ()); - delete req; - return; - } - // verbose: debug_printf ("got body (%ld)",bytes_read); - } - - /* this is not allowed to fail. We must return ENOSYS at a minimum to the client */ - req->serve (conn, cache); - - if ((bytes_written = conn->write ((char *)&req->header, sizeof (req->header))) - != sizeof(req->header) || (req->header.cb && - (bytes_written = conn->write (req->buffer, req->header.cb)) != req->header.cb)) - { - req->header.error_code = -1; - system_printf ("error writing to connection (%lu)", GetLastError ()); - delete req; - return; - } - - // verbose: debug_printf("Sent reply, size (%ld)",bytes_written); - printf ("."); - - delete (req); + client_request::handle_request (conn, cache); } void @@ -680,24 +636,20 @@ main (const int argc, char *argv[]) return 1; } - transport_layer_base * const transport = create_server_transport (); - - assert (transport); - if (shutdown) { - if (!transport->connect()) - { - system_printf ("couldn't establish connection with server"); - return 1; - } + client_request_shutdown req; + + if (req.make_request () == -1 || req.error_code ()) + return 1; - client_request_shutdown request; - request.send (transport); - transport->close(); return 0; } + transport_layer_base * const transport = create_server_transport (); + + assert (transport); + setbuf (stdout, NULL); printf ("daemon starting up"); print_version (pgm); diff --git a/winsup/cygwin/cygserver_client.cc b/winsup/cygwin/cygserver_client.cc index d50e7d9a8..25bb10390 100755 --- a/winsup/cygwin/cygserver_client.cc +++ b/winsup/cygwin/cygserver_client.cc @@ -4,11 +4,11 @@ Written by Egor Duda <deo@logos-m.ru> - This file is part of Cygwin. +This file is part of Cygwin. - This software is a copyrighted work licensed under the terms of the - Cygwin license. Please consult the file "CYGWIN_LICENSE" for - details. */ +This software is a copyrighted work licensed under the terms of the +Cygwin license. Please consult the file "CYGWIN_LICENSE" for +details. */ /* to allow this to link into cygwin and the .dll, a little magic is needed. */ #ifdef __OUTSIDE_CYGWIN__ @@ -18,108 +18,283 @@ #endif #include <sys/socket.h> + +#include <assert.h> #include <errno.h> +#include <stdio.h> #include <unistd.h> -//#include "security.h" + #include "cygwin/cygserver_transport.h" #include "cygwin/cygserver_transport_pipes.h" #include "cygwin/cygserver_transport_sockets.h" #include "cygwin/cygserver.h" +#include "cygserver_shm.h" + +int cygserver_running = CYGSERVER_UNKNOWN; -/* 0 = untested, 1 = running, 2 = dead */ -int cygserver_running=CYGSERVER_UNKNOWN; -/* on by default during development. For release, we probably want off by default */ +/* On by default during development. For release, we probably want off + * by default. + */ int allow_daemon = TRUE; -client_request_get_version::client_request_get_version () : client_request (CYGSERVER_REQUEST_GET_VERSION, sizeof (version)) +client_request_get_version::client_request_get_version () + : client_request (CYGSERVER_REQUEST_GET_VERSION, &version, sizeof (version)) { - buffer = (char *)&version; -} + msglen (0); // No parameters for request. -#ifndef __INSIDE_CYGWIN__ + syscall_printf ("created"); +} -client_request_attach_tty::client_request_attach_tty () : client_request (CYGSERVER_REQUEST_ATTACH_TTY, sizeof (req)) +void +client_request_get_version::check_version () const { - buffer = (char *)&req; - req.pid = 0; - req.master_pid = 0; - req.from_master = NULL; - req.to_master = NULL; + if (version.major != CYGWIN_SERVER_VERSION_MAJOR || + version.api != CYGWIN_SERVER_VERSION_API || + version.minor > CYGWIN_SERVER_VERSION_MINOR) + api_fatal ("incompatible version of cygwin server:\n" + "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); } -#else /* __INSIDE_CYGWIN__ */ +#ifdef __INSIDE_CYGWIN__ -client_request_attach_tty::client_request_attach_tty (DWORD npid, DWORD nmaster_pid, HANDLE nfrom_master, HANDLE nto_master) : client_request (CYGSERVER_REQUEST_ATTACH_TTY, sizeof (req)) +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)) { - buffer = (char *)&req; - req.pid = npid; + 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); } -#endif /* __INSIDE_CYGWIN__ */ +#else /* !__INSIDE_CYGWIN__ */ -client_request_shutdown::client_request_shutdown () : client_request (CYGSERVER_REQUEST_SHUTDOWN, 0) +client_request_attach_tty::client_request_attach_tty () + : client_request (CYGSERVER_REQUEST_ATTACH_TTY, &req, sizeof (req)) { - buffer = NULL; + syscall_printf ("created"); } -client_request::client_request (cygserver_request_code id, ssize_t buffer_size) : header (id, buffer_size) -{ -} +#endif /* __INSIDE_CYGWIN__ */ -client_request::~client_request () +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 *conn) +client_request::send (transport_layer_base * const conn) { - if (!conn) - return; - debug_printf("this=%p, conn=%p",this, conn); - ssize_t bytes_written, bytes_read; - debug_printf("header.cb = %ld",header.cb); - if ((bytes_written = conn->write ((char *)&header, sizeof (header))) - != sizeof(header) || (header.cb && - (bytes_written = conn->write (buffer, header.cb)) != header.cb)) + assert (conn); + assert (!(_header.msglen && !_buf)); // i.e., _header.msglen implies _buf + assert (_header.msglen <= _buflen); + + { + const ssize_t count = conn->write (&_header, sizeof (_header)); + + if (count != sizeof (_header)) + { + 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 (_header.msglen) { - header.error_code = -1; - debug_printf ("bytes written != request size"); + const ssize_t count = conn->write (_buf, _header.msglen); + + if (count == -1 || (size_t) count != _header.msglen) + { + error_code(errno); + syscall_printf (("request body write failure: " + "only %ld bytes sent of %ld, " + "error = %d(%lu)"), + count, _header.msglen, + errno, GetLastError ()); + return; + } + } + + syscall_printf ("request sent (%ld + %ld bytes)", + sizeof (_header), _header.msglen); + + { + const ssize_t count = conn->read (&_header, sizeof (_header)); + + if (count != sizeof (_header)) + { + 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 (_header.msglen && !_buf) + { + system_printf ("no client buffer for reply body: %ld bytes needed", + _header.msglen); + error_code(EINVAL); return; } - debug_printf("Sent request, size (%ld)",bytes_written); + if (_header.msglen > _buflen) + { + system_printf (("client buffer too small for reply body: " + "have %ld bytes and need %ld"), + _buflen, _header.msglen); + error_code(EINVAL); + return; + } - if ((bytes_read = conn->read ((char *)&header, sizeof (header))) - != sizeof (header) || (header.cb && - (bytes_read = conn->read (buffer, header.cb)) != header.cb)) + if (_header.msglen) { - header.error_code = -1; - debug_printf("failed reading response "); + const ssize_t count = conn->read (_buf, _header.msglen); + + if (count == -1 || (size_t) count != _header.msglen) + { + error_code(errno); + syscall_printf (("reply body read failure: " + "only %ld bytes received of %ld, " + "error = %d(%lu)"), + count, _header.msglen, + errno, GetLastError ()); + return; + } + } + + syscall_printf ("reply received (%ld + %ld bytes)", + sizeof (_header), _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 *conn, + class process_cache *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)", bytes_read); + + client_request *req = NULL; + + switch (header.request_code) + { + case CYGSERVER_REQUEST_GET_VERSION: + req = new client_request_get_version (); + break; + case CYGSERVER_REQUEST_SHUTDOWN: + req = new client_request_shutdown (); + break; + case CYGSERVER_REQUEST_ATTACH_TTY: + req = new client_request_attach_tty (); + break; + case CYGSERVER_REQUEST_SHM: + req = new client_request_shm (); + break; + default: + syscall_printf ("unknown request code %d received: request ignored", + header.request_code); return; } - debug_printf ("completed ok"); + + assert (req); + + req->msglen (header.msglen); + req->handle (conn, cache); + + delete (req); + printf ("."); } -#ifdef __INSIDE_CYGWIN__ +#endif /* !__INSIDE_CYGWIN__ */ -/* Oh, BTW: Fix the procedural basis and make this more intuitive. */ +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 -cygserver_request (client_request * req) +client_request::make_request () { - class transport_layer_base *transport; - - if (!req || allow_daemon != TRUE) + if (!allow_daemon) return -1; - /* dont' retry every request if the server's not there */ - if (cygserver_running==CYGSERVER_DEAD && req->header.req_id != CYGSERVER_REQUEST_GET_VERSION) + /* Don't retry every request if the server's not there */ + if (cygserver_running == CYGSERVER_DEAD + && request_code() != CYGSERVER_REQUEST_GET_VERSION) return -1; - transport = create_server_transport (); + class transport_layer_base * const transport = create_server_transport (); + + assert (transport); /* FIXME: have at most one connection per thread. use TLS to store the details */ /* logic is: @@ -134,7 +309,7 @@ cygserver_request (client_request * req) debug_printf ("connected to server %p", transport); - req->send(transport); + send (transport); transport->close (); @@ -143,6 +318,112 @@ cygserver_request (client_request * req) 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, + class process_cache * const cache) +{ + if (_header.msglen && !_buf) + { + system_printf ("no buffer for request body: %ld bytes needed", + _header.msglen); + error_code(EINVAL); + return; + } + + if (_header.msglen > _buflen) + { + system_printf (("buffer too small for request body: " + "have %ld bytes and need %ld"), + _buflen, _header.msglen); + error_code(EINVAL); + return; + } + + if (_header.msglen) + { + const ssize_t count = conn->read (_buf, _header.msglen); + + if (count == -1 || (size_t) count != _header.msglen) + { + error_code(errno); + syscall_printf (("request body read failure: " + "only %ld bytes received of %ld, " + "error = %d(%lu)"), + count, _header.msglen, + errno, GetLastError ()); + return; + } + } + + syscall_printf ("request received (%ld + %ld bytes)", + sizeof (_header), _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)) + { + 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 (_header.msglen) + { + const ssize_t count = conn->write (_buf, _header.msglen); + + if (count == -1 || (size_t) count != _header.msglen) + { + error_code(errno); + syscall_printf (("reply body write failure: " + "only %ld bytes sent of %ld, " + "error = %d(%lu)"), + count, _header.msglen, + errno, GetLastError ()); + return; + } + } + + syscall_printf ("reply sent (%ld + %ld bytes)", + sizeof (_header), _header.msglen); +} + +#endif /* !__INSIDE_CYGWIN__ */ + +#ifdef __INSIDE_CYGWIN__ + #if 0 BOOL check_cygserver_available () @@ -181,7 +462,7 @@ cygserver_init () // 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 (cygserver_request (&req) == -1) + if (req.make_request () == -1) { cygserver_running = CYGSERVER_DEAD; return; @@ -189,28 +470,16 @@ cygserver_init () // We connected to the server but something went wrong after that // (sending the message, cygserver itself, or receiving the reply). - if (req.header.error_code != 0) + if (req.error_code () != 0) { cygserver_running = CYGSERVER_DEAD; debug_printf ("failure in cygserver version request: %d", - req.header.error_code); + req.error_code ()); debug_printf ("process will continue without cygserver support"); return; } - if (req.version.major != CYGWIN_SERVER_VERSION_MAJOR || - req.version.api != CYGWIN_SERVER_VERSION_API || - req.version.minor > CYGWIN_SERVER_VERSION_MINOR) - api_fatal ("incompatible version of cygwin server:\n" - "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, - req.version.major, - req.version.api, - req.version.minor, - req.version.patch); + req.check_version (); // Dies if bad . . . cygserver_running = CYGSERVER_OK; } diff --git a/winsup/cygwin/cygserver_shm.cc b/winsup/cygwin/cygserver_shm.cc index 49e86a3fe..90473032c 100755 --- a/winsup/cygwin/cygserver_shm.cc +++ b/winsup/cygwin/cygserver_shm.cc @@ -12,22 +12,20 @@ #include "woutsup.h" -// #include <sys/stat.h> +#include <sys/types.h> +#include <sys/shm.h> + +#include <assert.h> #include <errno.h> #include <stdio.h> #include <time.h> -#include "cygerrno.h" #include <unistd.h> -#include "security.h" -//#include "fhandler.h" -//#include "dtable.h" -//#include "cygheap.h" -//#include "thread.h" -#include <sys/shm.h> -//#include "perprocess.h" -#include <threaded_queue.h> -#include <cygwin/cygserver_process.h> + +#include "cygerrno.h" #include "cygserver_shm.h" +#include "cygwin/cygserver_process.h" +#include "security.h" +#include "threaded_queue.h" // FIXME IS THIS CORRECT /* Implementation notes: We use two shared memory regions per key: @@ -50,11 +48,10 @@ getsystemallocgranularity () return buffer_offset; } - -client_request_shm::client_request_shm ():client_request (CYGSERVER_REQUEST_SHM_GET, - sizeof (parameters)) +client_request_shm::client_request_shm () + : client_request (CYGSERVER_REQUEST_SHM, ¶meters, sizeof (parameters)) { - buffer = (char *) ¶meters; + syscall_printf ("created"); } /* FIXME: evaluate getuid() and getgid() against the requested mode. Then @@ -127,8 +124,33 @@ delete_shmnode (shmnode **nodeptr) } void -client_request_shm::serve (transport_layer_base * conn, process_cache * cache) +client_request_shm::serve (transport_layer_base * const conn, + process_cache * const cache) { + assert (conn); + assert (cache); + + assert (!error_code ()); + + // The minimum possible request length. SHM_CREATE requests should + // be longer than this. + const size_t min_req_msglen = + (sizeof (parameters.in) - sizeof (parameters.in.sd_buf)); + + if (msglen () < min_req_msglen) + { + syscall_printf (("bad request body length: " + "expecting at least %lu bytes, got %lu"), + min_req_msglen, msglen ()); + error_code (EINVAL); + msglen (0); + return; + } + + // FIXME: check length of sd_buf contents for SHM_CREATE? + + msglen (sizeof (parameters.out)); + HANDLE from_process_handle = NULL; HANDLE token_handle = NULL; DWORD rc; @@ -142,7 +164,7 @@ client_request_shm::serve (transport_layer_base * conn, process_cache * cache) if (!from_process_handle) { system_printf ("error opening process (%lu)", GetLastError ()); - header.error_code = EACCES; + error_code (EACCES); return; } @@ -158,7 +180,7 @@ client_request_shm::serve (transport_layer_base * conn, process_cache * cache) if (!rc) { system_printf ("error opening thread token (%lu)", GetLastError ()); - header.error_code = EACCES; + error_code (EACCES); CloseHandle (from_process_handle); return; } @@ -185,7 +207,7 @@ client_request_shm::serve (transport_layer_base * conn, process_cache * cache) { system_printf ("error duplicating filemap handle (%lu)", GetLastError ()); - header.error_code = EACCES; + error_code (EACCES); } if (check_and_dup_handle (GetCurrentProcess (), from_process_handle, token_handle, @@ -194,14 +216,14 @@ client_request_shm::serve (transport_layer_base * conn, process_cache * cache) { system_printf ("error duplicating attachmap handle (%lu)", GetLastError ()); - header.error_code = EACCES; + error_code (EACCES); } CloseHandle (token_handle); return; } tempnode = tempnode->next; } - header.error_code = EINVAL; + error_code (EINVAL); CloseHandle (token_handle); return; } @@ -220,13 +242,12 @@ client_request_shm::serve (transport_layer_base * conn, process_cache * cache) if (tempnode->shm_id == parameters.in.shm_id) { InterlockedIncrement (&tempnode->shmds->ds.shm_nattch); - header.error_code = 0; CloseHandle (token_handle); return; } tempnode = tempnode->next; } - header.error_code = EINVAL; + error_code (EINVAL); CloseHandle (token_handle); return; } @@ -240,13 +261,12 @@ client_request_shm::serve (transport_layer_base * conn, process_cache * cache) if (tempnode->shm_id == parameters.in.shm_id) { InterlockedDecrement (&tempnode->shmds->ds.shm_nattch); - header.error_code = 0; CloseHandle (token_handle); return; } tempnode = tempnode->next; } - header.error_code = EINVAL; + error_code (EINVAL); CloseHandle (token_handle); return; } @@ -256,7 +276,7 @@ client_request_shm::serve (transport_layer_base * conn, process_cache * cache) { shmnode **tempnode = &shm_head; while (*tempnode) - { + { if ((*tempnode)->shm_id == parameters.in.shm_id) { // unlink from the accessible node list @@ -276,13 +296,12 @@ client_request_shm::serve (transport_layer_base * conn, process_cache * cache) delete_shmnode (&temp2); } - header.error_code = 0; CloseHandle (token_handle); return; } tempnode = &(*tempnode)->next; } - header.error_code = EINVAL; + error_code (EINVAL); CloseHandle (token_handle); return; } @@ -325,8 +344,6 @@ client_request_shm::serve (transport_layer_base * conn, process_cache * cache) * with the same key and size. Different modes is a ?. */ - - /* walk the list of known keys and return the id if found. remember, we are * authoritative... */ @@ -341,7 +358,7 @@ client_request_shm::serve (transport_layer_base * conn, process_cache * cache) if (parameters.in.size && tempnode->shmds->ds.shm_segsz < parameters.in.size) { - header.error_code = EINVAL; + error_code (EINVAL); CloseHandle (token_handle); return; } @@ -351,7 +368,7 @@ client_request_shm::serve (transport_layer_base * conn, process_cache * cache) if ((parameters.in.shmflg & IPC_CREAT) && (parameters.in.shmflg & IPC_EXCL)) { - header.error_code = EEXIST; + error_code (EEXIST); debug_printf ("attempt to exclusively create already created shm_area with key 0x%0qx", parameters.in.key); @@ -376,8 +393,8 @@ client_request_shm::serve (transport_layer_base * conn, process_cache * cache) { system_printf ("error duplicating filemap handle (%lu)", GetLastError ()); - header.error_code = EACCES; -/*mutex*/ + error_code (EACCES); + /*mutex*/ CloseHandle (token_handle); return; } @@ -388,8 +405,8 @@ client_request_shm::serve (transport_layer_base * conn, process_cache * cache) { system_printf ("error duplicating attachmap handle (%lu)", GetLastError ()); - header.error_code = EACCES; -/*mutex*/ + error_code (EACCES); + /*mutex*/ CloseHandle (token_handle); return; } @@ -432,7 +449,7 @@ client_request_shm::serve (transport_layer_base * conn, process_cache * cache) GetLastError ()); // free the mutex // we can assume that it exists, and that it was an access problem. - header.error_code = EACCES; + error_code (EACCES); CloseHandle (token_handle); return; } @@ -450,7 +467,7 @@ client_request_shm::serve (transport_layer_base * conn, process_cache * cache) { /* FIXME free mutex */ CloseHandle (filemap); - header.error_code = EEXIST; + error_code (EEXIST); CloseHandle (token_handle); return; } @@ -462,7 +479,7 @@ client_request_shm::serve (transport_layer_base * conn, process_cache * cache) { CloseHandle (filemap); /* FIXME free mutex */ - header.error_code = ENOENT; + error_code (ENOENT); CloseHandle (token_handle); return; } @@ -476,7 +493,7 @@ client_request_shm::serve (transport_layer_base * conn, process_cache * cache) CloseHandle (filemap); //FIXME: close filemap and free the mutex /* we couldn't access the mapped area with the requested permissions */ - header.error_code = EACCES; + error_code (EACCES); CloseHandle (token_handle); return; } @@ -491,13 +508,13 @@ client_request_shm::serve (transport_layer_base * conn, process_cache * cache) parameters.in.size % getsystemallocgranularity (), shmaname // object name - ); + ); conn->revert_to_self (); if (attachmap == NULL) { system_printf ("failed to get shm attachmap"); - header.error_code = ENOMEM; + error_code (ENOMEM); UnmapViewOfFile (mapptr); CloseHandle (filemap); /* FIXME exit the mutex */ @@ -509,7 +526,7 @@ client_request_shm::serve (transport_layer_base * conn, process_cache * cache) if (!shmtemp) { system_printf ("failed to malloc shm node"); - header.error_code = ENOMEM; + error_code (ENOMEM); UnmapViewOfFile (mapptr); CloseHandle (filemap); CloseHandle (attachmap); @@ -545,7 +562,7 @@ client_request_shm::serve (transport_layer_base * conn, process_cache * cache) /* we now have the area in the daemon list, opened. - FIXME: leave the system wide shm mutex */ + FIXME: leave the system wide shm mutex */ parameters.out.shm_id = tempnode->shm_id; if (check_and_dup_handle (GetCurrentProcess (), from_process_handle, @@ -556,9 +573,9 @@ client_request_shm::serve (transport_layer_base * conn, process_cache * cache) { system_printf ("error duplicating filemap handle (%lu)", GetLastError ()); - header.error_code = EACCES; + error_code (EACCES); CloseHandle (token_handle); -/* mutex et al */ + /* mutex et al */ return; } if (check_and_dup_handle (GetCurrentProcess (), from_process_handle, @@ -569,20 +586,18 @@ client_request_shm::serve (transport_layer_base * conn, process_cache * cache) { system_printf ("error duplicating attachmap handle (%lu)", GetLastError ()); - header.error_code = EACCES; + error_code (EACCES); CloseHandle (from_process_handle); CloseHandle (token_handle); -/* more cleanup... yay! */ + /* more cleanup... yay! */ return; } CloseHandle (token_handle); - return; } - header.error_code = ENOSYS; + error_code (ENOSYS); CloseHandle (token_handle); - return; } diff --git a/winsup/cygwin/cygserver_shm.h b/winsup/cygwin/cygserver_shm.h index bc389c28a..a8b7dd2a6 100644 --- a/winsup/cygwin/cygserver_shm.h +++ b/winsup/cygwin/cygserver_shm.h @@ -51,14 +51,37 @@ struct shmnode class client_request_shm : public client_request { public: -#ifndef __INSIDE_CYGWIN__ - virtual void serve (transport_layer_base *conn, process_cache *cache); -#endif +#ifdef __INSIDE_CYGWIN__ client_request_shm (key_t ntype, size_t nsize, int shmflg); - client_request_shm (); client_request_shm (int ntype, int nshmid); - union { - struct {int type; pid_t cygpid; DWORD winpid; int shm_id; key_t key; size_t size; int shmflg; char sd_buf[4096];} in; - struct {int shm_id; HANDLE filemap; HANDLE attachmap; key_t key;} out; +#else + client_request_shm (); +#endif + + union + { + struct + { + int type; + pid_t cygpid; + DWORD winpid; + int shm_id; + key_t key; + size_t size; + int shmflg; + char sd_buf[4096]; // Must be the last item (variable length). + } in; + struct + { + int shm_id; + HANDLE filemap; + HANDLE attachmap; + key_t key; + } out; } parameters; + +private: +#ifndef __INSIDE_CYGWIN__ + virtual void serve (transport_layer_base *, process_cache *); +#endif }; diff --git a/winsup/cygwin/fhandler_tty.cc b/winsup/cygwin/fhandler_tty.cc index 758d6eaec..fe4ea6911 100644 --- a/winsup/cygwin/fhandler_tty.cc +++ b/winsup/cygwin/fhandler_tty.cc @@ -572,29 +572,15 @@ fhandler_tty_slave::cygserver_attach_tty (LPHANDLE from_master_ptr, if (!from_master_ptr || !to_master_ptr) return 0; - client_request_attach_tty *request = - new client_request_attach_tty ((DWORD) GetCurrentProcessId (), - (DWORD) get_ttyp ()->master_pid, - (HANDLE) get_ttyp ()->from_master, - (HANDLE) get_ttyp ()->to_master); - - if (cygserver_request (request) != 0 || - request->header.error_code != 0) - return 0; + client_request_attach_tty req ((DWORD) get_ttyp ()->master_pid, + (HANDLE) get_ttyp ()->from_master, + (HANDLE) get_ttyp ()->to_master); -/* - struct request_attach_tty req; - INIT_REQUEST (req, CYGSERVER_REQUEST_ATTACH_TTY); - req.pid = GetCurrentProcessId (); - req.master_pid = get_ttyp ()->master_pid; - req.from_master = get_ttyp ()->from_master; - req.to_master = get_ttyp ()->to_master; - if (cygserver_request ((struct request_header*) &req) != 0) + if (req.make_request () != 0 || req.error_code () != 0) return 0; -*/ - *from_master_ptr = request->from_master (); - *to_master_ptr = request->to_master (); - delete request; + + *from_master_ptr = req.from_master (); + *to_master_ptr = req.to_master (); return 1; } diff --git a/winsup/cygwin/include/cygwin/cygserver.h b/winsup/cygwin/include/cygwin/cygserver.h index 8c9c0a93b..5873e2424 100755 --- a/winsup/cygwin/include/cygwin/cygserver.h +++ b/winsup/cygwin/include/cygwin/cygserver.h @@ -13,123 +13,162 @@ details. */ #ifndef _CYGSERVER_H_ #define _CYGSERVER_H_ -#define MAX_REQUEST_SIZE 128 +#ifdef __GNUC__ +#define CYGSERVER_PACKED __attribute__ ((packed)) +#else +#define CYGSERVER_PACKED +#endif #define CYGWIN_SERVER_VERSION_MAJOR 1 #define CYGWIN_SERVER_VERSION_API 1 #define CYGWIN_SERVER_VERSION_MINOR 0 #define CYGWIN_SERVER_VERSION_PATCH 0 - typedef enum { - CYGSERVER_UNKNOWN=0, - CYGSERVER_OK=1, - CYGSERVER_DEAD=2 + CYGSERVER_UNKNOWN = 0, + CYGSERVER_OK, + CYGSERVER_DEAD } cygserver_states; -typedef enum { - CYGSERVER_REQUEST_INVALID = 0, - CYGSERVER_REQUEST_GET_VERSION, - CYGSERVER_REQUEST_ATTACH_TTY, - CYGSERVER_REQUEST_SHUTDOWN, - CYGSERVER_REQUEST_SHM_GET, - CYGSERVER_REQUEST_LAST -} cygserver_request_code; - -class request_header +/*---------------------------------------------------------------------------* + * class client_request + *---------------------------------------------------------------------------*/ + +class client_request { +protected: + typedef enum { + CYGSERVER_REQUEST_INVALID, + CYGSERVER_REQUEST_GET_VERSION, + CYGSERVER_REQUEST_SHUTDOWN, + CYGSERVER_REQUEST_ATTACH_TTY, + CYGSERVER_REQUEST_SHM, + CYGSERVER_REQUEST_LAST + } request_code_t; + + struct header_t + { + size_t msglen; + union + { + request_code_t request_code; + ssize_t error_code; + }; + + header_t () {}; + header_t (request_code_t, size_t); + } CYGSERVER_PACKED; + public: - ssize_t cb; - cygserver_request_code req_id; - ssize_t error_code; - request_header (cygserver_request_code id, ssize_t ncb) : cb (ncb), req_id (id), error_code (0) {} ; -} -#ifdef __GNUC__ - __attribute__ ((packed)) +#ifndef __INSIDE_CYGWIN__ + static void handle_request (transport_layer_base *, class process_cache *); #endif -; -extern void cygserver_init (); + client_request (request_code_t request_code, + void *buf = NULL, + size_t bufsiz = 0); + virtual ~client_request(); -#define INIT_REQUEST(req,id) \ - (req).header.cb = sizeof (req); \ - (req).header.req_id = id; + request_code_t request_code () const { return _header.request_code; } -struct request_get_version -{ - DWORD major, api, minor, patch; -} -#ifdef __GNUC__ - __attribute__ ((packed)) -#endif -; + ssize_t error_code () const { return _header.error_code; }; + void error_code (ssize_t error_code) { _header.error_code = error_code; }; -struct request_shutdown -{ - int foo; -} -#ifdef __GNUC__ - __attribute__ ((packed)) -#endif -; + size_t msglen () const { return _header.msglen; }; + void msglen (size_t len) { _header.msglen = len; }; -struct request_attach_tty -{ - DWORD pid, master_pid; - HANDLE from_master, to_master; -} -#ifdef __GNUC__ - __attribute__ ((packed)) -#endif -; + virtual int make_request (); + +private: + header_t _header; + void * const _buf; + const size_t _buflen; -class client_request -{ -public: - client_request (cygserver_request_code id, ssize_t data_size); - void send (transport_layer_base *conn); #ifndef __INSIDE_CYGWIN__ + void handle (transport_layer_base *, class process_cache *); virtual void serve (transport_layer_base *, class process_cache *) = 0; #endif - cygserver_request_code req_id () {return header.req_id;}; - virtual ~client_request(); - request_header header; - char *buffer; + + void send (transport_layer_base *); }; +/*---------------------------------------------------------------------------* + * class client_request_get_version + *---------------------------------------------------------------------------*/ + class client_request_get_version : public client_request { +private: + struct request_get_version + { + DWORD major, api, minor, patch; + } CYGSERVER_PACKED; + public: + client_request_get_version (); + + void check_version () const; + +private: + struct request_get_version version; + #ifndef __INSIDE_CYGWIN__ - virtual void serve (transport_layer_base *conn, class process_cache *cache); + virtual void serve (transport_layer_base *, class process_cache *); #endif - client_request_get_version::client_request_get_version(); - struct request_get_version version; }; +/*---------------------------------------------------------------------------* + * class client_request_shutdown + * + * Nb. This whole class is only !__INSIDE_CYGWIN__ since it is used + * solely by cygserver itself. + *---------------------------------------------------------------------------*/ + +#ifndef __INSIDE_CYGWIN__ + class client_request_shutdown : public client_request { public: -#ifndef __INSIDE_CYGWIN__ - virtual void serve (transport_layer_base *conn, class process_cache *cache); -#endif client_request_shutdown (); + +private: + virtual void serve (transport_layer_base *, class process_cache *); }; +#endif /* !__INSIDE_CYGWIN__ */ + +/*---------------------------------------------------------------------------* + * class client_request_attach_tty + *---------------------------------------------------------------------------*/ + class client_request_attach_tty : public client_request { +private: + struct request_attach_tty + { + DWORD pid, master_pid; + HANDLE from_master, to_master; + } CYGSERVER_PACKED; + public: -#ifndef __INSIDE_CYGWIN__ - virtual void serve (transport_layer_base *conn, class process_cache *cache); - client_request_attach_tty (); +#ifdef __INSIDE_CYGWIN__ + client_request_attach_tty (DWORD nmaster_pid, + HANDLE nfrom_master, HANDLE nto_master); #else - client_request_attach_tty (DWORD npid, DWORD nmaster_pid, HANDLE nfrom_master, HANDLE nto_master); + client_request_attach_tty (); #endif - HANDLE from_master () {return req.from_master;}; - HANDLE to_master () {return req.to_master;}; + + HANDLE from_master () const { return req.from_master; }; + HANDLE to_master () const { return req.to_master; }; + +private: struct request_attach_tty req; + +#ifndef __INSIDE_CYGWIN__ + virtual void serve (transport_layer_base *, class process_cache *); +#endif }; -extern int cygserver_request (client_request *); +extern void cygserver_init (); #endif /* _CYGSERVER_H_ */ diff --git a/winsup/cygwin/shm.cc b/winsup/cygwin/shm.cc index d22217f72..7d52fa3b8 100644 --- a/winsup/cygwin/shm.cc +++ b/winsup/cygwin/shm.cc @@ -69,15 +69,13 @@ getsystemallocgranularity () * Used for: SHM_ATTACH, SHM_DETACH, SHM_REATTACH, and SHM_DEL. */ client_request_shm::client_request_shm (int ntype, int nshmid) - : client_request (CYGSERVER_REQUEST_SHM_GET, sizeof (parameters)) + : client_request (CYGSERVER_REQUEST_SHM, ¶meters, sizeof (parameters)) { assert (ntype == SHM_REATTACH \ || ntype == SHM_ATTACH \ || ntype == SHM_DETACH \ || ntype == SHM_DEL); - buffer = (char *) ¶meters; - parameters.in.type = ntype; parameters.in.cygpid = getpid (); parameters.in.winpid = GetCurrentProcessId (); @@ -86,20 +84,21 @@ client_request_shm::client_request_shm (int ntype, int nshmid) assert (parameters.in.cygpid > 0); assert (parameters.in.winpid != 0); - debug_printf ("created: ntype = %d, shmid = %d", ntype, nshmid); + msglen (sizeof (parameters.in) - sizeof (parameters.in.sd_buf)); + + syscall_printf ("created: type = %d, shmid = %d", + parameters.in.type, parameters.in.shm_id); } /* * Used for: SHM_CREATE. */ client_request_shm::client_request_shm (key_t nkey, size_t nsize, int nshmflg) - : client_request (CYGSERVER_REQUEST_SHM_GET, sizeof (parameters)) + : client_request (CYGSERVER_REQUEST_SHM, ¶meters, sizeof (parameters)) { assert (nkey != (key_t) -1); assert (nsize >= 0); - buffer = (char *) ¶meters; - parameters.in.type = SHM_CREATE; parameters.in.cygpid = getpid (); parameters.in.winpid = GetCurrentProcessId (); @@ -110,16 +109,29 @@ client_request_shm::client_request_shm (key_t nkey, size_t nsize, int nshmflg) assert (parameters.in.cygpid > 0); assert (parameters.in.winpid != 0); + DWORD sd_buf_size = 0; + if (wincap.has_security ()) { SECURITY_ATTRIBUTES sa = sec_none; - set_security_attribute (nshmflg & 0777, &sa, - parameters.in.sd_buf, - sizeof (parameters.in.sd_buf)); + sd_buf_size = sizeof (parameters.in.sd_buf); + + PSECURITY_DESCRIPTOR psd = (PSECURITY_DESCRIPTOR) parameters.in.sd_buf; + + InitializeSecurityDescriptor (psd, SECURITY_DESCRIPTOR_REVISION); + + alloc_sd (geteuid32 (), getegid32 (), parameters.in.shmflg & 0777, + psd, &sd_buf_size); } - debug_printf ("created: key = 0x%x%08x, size = %ld, shmflg = %o", - hi_ulong(nkey), lo_ulong(nkey), nsize, nshmflg); + msglen (sizeof (parameters.in) - sizeof (parameters.in.sd_buf) + + sd_buf_size); + + syscall_printf (("created: type = %d, " + "key = 0x%x%08x, size = %ld, shmflg = %o"), + parameters.in.type, + hi_ulong(parameters.in.key), lo_ulong(parameters.in.key), + parameters.in.size, parameters.in.shmflg); } static shmnode *shm_head = NULL; @@ -268,20 +280,17 @@ shmat (int shmid, const void *shmaddr, int shmflg) /* couldn't find a currently open shm control area for the key - probably because * shmget hasn't been called. * Allocate a new control block - this has to be handled by the daemon */ - client_request_shm *req = new client_request_shm (SHM_REATTACH, shmid); + client_request_shm req (SHM_REATTACH, shmid); - int rc; - if ((rc = cygserver_request (req))) + if (req.make_request () == -1) { - delete req; set_errno (ENOSYS); /* daemon communication failed */ return (void *) -1; } - if (req->header.error_code) /* shm_get failed in the daemon */ + if (req.error_code ()) /* shm_get failed in the daemon */ { - set_errno (req->header.error_code); - delete req; + set_errno (req.error_code ()); return (void *) -1; } @@ -290,11 +299,10 @@ shmat (int shmid, const void *shmaddr, int shmflg) * FIXME: make this a method of shmnode ? */ tempnode = - build_inprocess_shmds (req->parameters.out.filemap, - req->parameters.out.attachmap, - req->parameters.out.key, - req->parameters.out.shm_id); - delete req; + build_inprocess_shmds (req.parameters.out.filemap, + req.parameters.out.attachmap, + req.parameters.out.key, + req.parameters.out.shm_id); if (!tempnode) return (void *) -1; @@ -320,13 +328,12 @@ shmat (int shmid, const void *shmaddr, int shmflg) return (void *) -1; } /* tell the daemon we have attached */ - client_request_shm *req = new client_request_shm (SHM_ATTACH, shmid); - int rc; - if ((rc = cygserver_request (req))) + client_request_shm req (SHM_ATTACH, shmid); + + if (req.make_request () == -1) { debug_printf ("failed to tell daemon that we have attached"); } - delete req; _shmattach *attachnode = new _shmattach; attachnode->data = rv; @@ -368,14 +375,12 @@ shmdt (const void *shmaddr) UnmapViewOfFile (attachnode->data); /* tell the daemon we have attached */ - client_request_shm *req = - new client_request_shm (SHM_DETACH, tempnode->shm_id); - int rc; - if ((rc = cygserver_request (req))) + client_request_shm req (SHM_DETACH, tempnode->shm_id); + + if (req.make_request () == -1) { debug_printf ("failed to tell daemon that we have detached"); } - delete req; return 0; } @@ -392,20 +397,17 @@ shmctl (int shmid, int cmd, struct shmid_ds *buf) /* couldn't find a currently open shm control area for the key - probably because * shmget hasn't been called. * Allocate a new control block - this has to be handled by the daemon */ - client_request_shm *req = new client_request_shm (SHM_REATTACH, shmid); + client_request_shm req (SHM_REATTACH, shmid); - int rc; - if ((rc = cygserver_request (req))) + if (req.make_request () == -1) { - delete req; set_errno (ENOSYS); /* daemon communication failed */ return -1; } - if (req->header.error_code) /* shm_get failed in the daemon */ + if (req.error_code ()) /* shm_get failed in the daemon */ { - set_errno (req->header.error_code); - delete req; + set_errno (req.error_code ()); return -1; } @@ -414,11 +416,10 @@ shmctl (int shmid, int cmd, struct shmid_ds *buf) * FIXME: make this a method of shmnode ? */ tempnode = - build_inprocess_shmds (req->parameters.out.filemap, - req->parameters.out.attachmap, - req->parameters.out.key, - req->parameters.out.shm_id); - delete req; + build_inprocess_shmds (req.parameters.out.filemap, + req.parameters.out.attachmap, + req.parameters.out.key, + req.parameters.out.shm_id); if (!tempnode) return -1; } @@ -444,19 +445,17 @@ shmctl (int shmid, int cmd, struct shmid_ds *buf) * daemon has an attach. The daemon gets asked to detach immediately. */ //waiting for the daemon to handle terminating process's - client_request_shm *req = new client_request_shm (SHM_DEL, shmid); - int rc; - if ((rc = cygserver_request (req))) + client_request_shm req (SHM_DEL, shmid); + + if (req.make_request () == -1) { - delete req; set_errno (ENOSYS); /* daemon communication failed */ return -1; } - if (req->header.error_code) /* shm_del failed in the daemon */ + if (req.error_code ()) /* shm_del failed in the daemon */ { - set_errno (req->header.error_code); - delete req; + set_errno (req.error_code ()); return -1; } @@ -528,20 +527,17 @@ shmget (key_t key, size_t size, int shmflg) } /* couldn't find a currently open shm control area for the key. * Allocate a new control block - this has to be handled by the daemon */ - client_request_shm *req = new client_request_shm (key, size, shmflg); + client_request_shm req (key, size, shmflg); - int rc; - if ((rc = cygserver_request (req))) + if (req.make_request () == -1) { - delete req; set_errno (ENOSYS); /* daemon communication failed */ return -1; } - if (req->header.error_code) /* shm_get failed in the daemon */ + if (req.error_code ()) /* shm_get failed in the daemon */ { - set_errno (req->header.error_code); - delete req; + set_errno (req.error_code ()); return -1; } @@ -549,11 +545,10 @@ shmget (key_t key, size_t size, int shmflg) * This tests security automagically * FIXME: make this a method of shmnode ? */ - shmnode *shmtemp = build_inprocess_shmds (req->parameters.out.filemap, - req->parameters.out.attachmap, + shmnode *shmtemp = build_inprocess_shmds (req.parameters.out.filemap, + req.parameters.out.attachmap, key, - req->parameters.out.shm_id); - delete req; + req.parameters.out.shm_id); if (shmtemp) return shmtemp->shm_id; return -1; |