3 Copyright 2001, 2002, 2003, 2004, 2008, 2009 Red Hat Inc.
5 Written by Egor Duda <deo@logos-m.ru>
7 This file is part of Cygwin.
9 This software is a copyrighted work licensed under the terms of the
10 Cygwin license. Please consult the file "CYGWIN_LICENSE" for
13 /* to allow this to link into cygwin and the .dll, a little magic is needed. */
14 #ifdef __OUTSIDE_CYGWIN__
27 #include "cygserver_msg.h"
28 #include "cygserver_sem.h"
29 #include "cygserver_shm.h"
30 #include "cygserver_setpwd.h"
32 #include "cygserver.h"
33 #include "transport.h"
35 int cygserver_running = CYGSERVER_UNKNOWN; // Nb: inherited by children.
37 client_request_get_version::client_request_get_version ()
38 : client_request (CYGSERVER_REQUEST_GET_VERSION, &version, sizeof (version))
40 msglen (0); // No parameters for request.
42 // verbose: syscall_printf ("created");
46 * client_request_get_version::check_version ()
48 * The major version and API version numbers must match exactly. An
49 * older than expected minor version number is accepted (as long as
50 * the first numbers match, that is).
53 #ifdef __INSIDE_CYGWIN__
56 client_request_get_version::check_version () const
58 const bool ok = (version.major == CYGWIN_SERVER_VERSION_MAJOR
59 && version.api == CYGWIN_SERVER_VERSION_API
60 && version.minor <= CYGWIN_SERVER_VERSION_MINOR);
63 syscall_printf (("incompatible version of cygwin server: "
64 "client version %d.%d.%d.%d, "
65 "server version %ld.%ld.%ld.%ld"),
66 CYGWIN_SERVER_VERSION_MAJOR,
67 CYGWIN_SERVER_VERSION_API,
68 CYGWIN_SERVER_VERSION_MINOR,
69 CYGWIN_SERVER_VERSION_PATCH,
78 client_request_attach_tty::client_request_attach_tty (DWORD nmaster_pid,
81 : client_request (CYGSERVER_REQUEST_ATTACH_TTY, &req, sizeof (req))
83 req.pid = GetCurrentProcessId ();
84 req.master_pid = nmaster_pid;
85 req.from_master = nfrom_master;
86 req.to_master = nto_master;
88 syscall_printf (("created: pid = %lu, master_pid = %lu, "
89 "from_master = %lu, to_master = %lu"),
90 req.pid, req.master_pid, req.from_master, req.to_master);
92 #endif /* __INSIDE_CYGWIN__ */
95 * client_request_attach_tty::send ()
97 * Wraps the base method to provide error handling support. If the
98 * reply contains a body but is flagged as an error, close any handles
99 * that have been returned by cygserver and then discard the message
100 * body, i.e. the client either sees a successful result with handles
101 * or an unsuccessful result with no handles.
105 client_request_attach_tty::send (transport_layer_base * const conn)
107 client_request::send (conn);
109 if (msglen () && error_code ())
112 CloseHandle (from_master ());
114 CloseHandle (to_master ());
119 client_request::header_t::header_t (const request_code_t request_code,
122 request_code (request_code)
124 assert (request_code >= 0 && request_code < CYGSERVER_REQUEST_LAST);
127 // FIXME: also check write and read result for -1.
130 client_request::send (transport_layer_base * const conn)
133 assert (!(msglen () && !_buf)); // i.e., msglen () implies _buf
134 assert (msglen () <= _buflen);
137 const ssize_t count = conn->write (&_header, sizeof (_header));
139 if (count != sizeof (_header))
143 syscall_printf (("request header write failure: "
144 "only %ld bytes sent of %ld, "
146 count, sizeof (_header),
147 errno, GetLastError ());
154 const ssize_t count = conn->write (_buf, msglen ());
156 if (count == -1 || (size_t) count != msglen ())
160 syscall_printf (("request body write failure: "
161 "only %ld bytes sent of %ld, "
164 errno, GetLastError ());
169 // verbose: syscall_printf ("request sent (%ld + %ld bytes)",
170 // sizeof (_header), msglen ());
173 const ssize_t count = conn->read (&_header, sizeof (_header));
175 if (count != sizeof (_header))
179 syscall_printf (("reply header read failure: "
180 "only %ld bytes received of %ld, "
182 count, sizeof (_header),
183 errno, GetLastError ());
188 if (msglen () && !_buf)
190 system_printf ("no client buffer for reply body: %ld bytes needed",
196 if (msglen () > _buflen)
198 system_printf (("client buffer too small for reply body: "
199 "have %ld bytes and need %ld"),
207 const ssize_t count = conn->read (_buf, msglen ());
209 if (count == -1 || (size_t) count != msglen ())
213 syscall_printf (("reply body read failure: "
214 "only %ld bytes received of %ld, "
217 errno, GetLastError ());
222 // verbose: syscall_printf ("reply received (%ld + %ld bytes)",
223 // sizeof (_header), msglen ());
226 #ifdef __OUTSIDE_CYGWIN__
228 client_request_attach_tty::client_request_attach_tty ()
229 : client_request (CYGSERVER_REQUEST_ATTACH_TTY, &req, sizeof (req))
234 * client_request::handle_request ()
236 * A server-side method.
238 * This is a factory method for the client_request subclasses. It
239 * reads the incoming request header and, based on its request code,
240 * creates an instance of the appropriate class.
242 * FIXME: If the incoming packet is malformed, the server drops it on
243 * the floor. Should it try and generate some sort of reply for the
244 * client? As it is, the client will simply get a broken connection.
246 * FIXME: also check write and read result for -1.
250 client_request::handle_request (transport_layer_base *const conn,
251 process_cache *const cache)
253 // verbose: debug_printf ("about to read");
258 const ssize_t count = conn->read (&header, sizeof (header));
260 if (count != sizeof (header))
262 syscall_printf (("request header read failure: "
263 "only %ld bytes received of %ld, "
265 count, sizeof (header),
266 errno, GetLastError ());
270 // verbose: debug_printf ("got header (%ld)", count);
273 client_request *req = NULL;
275 switch (header.request_code)
277 case CYGSERVER_REQUEST_GET_VERSION:
278 req = new client_request_get_version;
280 case CYGSERVER_REQUEST_SHUTDOWN:
281 req = new client_request_shutdown;
283 case CYGSERVER_REQUEST_ATTACH_TTY:
284 req = new client_request_attach_tty;
286 case CYGSERVER_REQUEST_MSG:
287 req = new client_request_msg;
289 case CYGSERVER_REQUEST_SEM:
290 req = new client_request_sem;
292 case CYGSERVER_REQUEST_SHM:
293 req = new client_request_shm;
295 case CYGSERVER_REQUEST_SETPWD:
296 req = new client_request_setpwd;
299 syscall_printf ("unknown request code %d received: request ignored",
300 header.request_code);
306 req->msglen (header.msglen);
307 req->handle (conn, cache);
313 * client_request::handle ()
315 * A server-side method.
317 * At this point, the header of an incoming request has been read and
318 * an appropriate client_request object constructed. This method has
319 * to read the request body into its buffer, if there is such a body,
320 * then perform the request and send back the results to the client.
322 * FIXME: If the incoming packet is malformed, the server drops it on
323 * the floor. Should it try and generate some sort of reply for the
324 * client? As it is, the client will simply get a broken connection.
326 * FIXME: also check write and read result for -1.
330 client_request::handle (transport_layer_base *const conn,
331 process_cache *const cache)
333 if (msglen () && !_buf)
335 system_printf ("no buffer for request body: %ld bytes needed",
341 if (msglen () > _buflen)
343 system_printf (("buffer too small for request body: "
344 "have %ld bytes and need %ld"),
352 const ssize_t count = conn->read (_buf, msglen ());
354 if (count == -1 || (size_t) count != msglen ())
358 syscall_printf (("request body read failure: "
359 "only %ld bytes received of %ld, "
362 errno, GetLastError ());
367 // verbose: syscall_printf ("request received (%ld + %ld bytes)",
368 // sizeof (_header), msglen ());
370 error_code (0); // Overwrites the _header.request_code field.
373 * This is not allowed to fail. We must return ENOSYS at a minimum
379 const ssize_t count = conn->write (&_header, sizeof (_header));
381 if (count != sizeof (_header))
385 syscall_printf (("reply header write failure: "
386 "only %ld bytes sent of %ld, "
388 count, sizeof (_header),
389 errno, GetLastError ());
396 const ssize_t count = conn->write (_buf, msglen ());
398 if (count == -1 || (size_t) count != msglen ())
402 syscall_printf (("reply body write failure: "
403 "only %ld bytes sent of %ld, "
406 errno, GetLastError ());
411 // verbose: syscall_printf ("reply sent (%ld + %ld bytes)",
412 // sizeof (_header), msglen ());
415 /* The server side implementation of make_request. Very simple. */
417 client_request::make_request ()
419 transport_layer_base *const transport = create_server_transport ();
421 if (transport->connect () == -1)
434 #endif /* __OUTSIDE_CYGWIN__ */
436 client_request::client_request (request_code_t const id,
439 : _header (id, buflen),
443 assert ((!_buf && !_buflen) || (_buf && _buflen));
446 client_request::~client_request ()
449 #ifdef __INSIDE_CYGWIN__
451 client_request::make_request ()
453 assert (cygserver_running == CYGSERVER_UNKNOWN \
454 || cygserver_running == CYGSERVER_OK \
455 || cygserver_running == CYGSERVER_UNAVAIL);
457 if (cygserver_running == CYGSERVER_UNKNOWN)
460 assert (cygserver_running == CYGSERVER_OK \
461 || cygserver_running == CYGSERVER_UNAVAIL);
463 /* Don't retry every request if the server's not there */
464 if (cygserver_running == CYGSERVER_UNAVAIL)
466 syscall_printf ("cygserver un-available");
471 transport_layer_base *const transport = create_server_transport ();
475 if (transport->connect () == -1)
485 // verbose: debug_printf ("connected to server %p", transport);
495 check_cygserver_available ()
497 assert (cygserver_running == CYGSERVER_UNKNOWN \
498 || cygserver_running == CYGSERVER_UNAVAIL);
500 cygserver_running = CYGSERVER_OK; // For make_request ().
502 client_request_get_version req;
504 /* This indicates that we failed to connect to cygserver at all but
505 * that's fine as cygwin doesn't need it to be running.
507 if (req.make_request () == -1)
510 /* We connected to the server but something went wrong after that
511 * (in sending the message, in cygserver itself, or in receiving the
514 if (req.error_code ())
516 syscall_printf ("failure in cygserver version request: %d",
518 syscall_printf ("process will continue without cygserver support");
522 return req.check_version ();
528 assert (cygserver_running == CYGSERVER_UNKNOWN \
529 || cygserver_running == CYGSERVER_OK \
530 || cygserver_running == CYGSERVER_UNAVAIL);
532 if (cygserver_running == CYGSERVER_OK)
535 if (!check_cygserver_available ())
536 cygserver_running = CYGSERVER_UNAVAIL;
538 #endif /* __INSIDE_CYGWIN__ */