3 Copyright 2001, 2002 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__
25 #include "cygserver_shm.h"
26 #include "safe_memory.h"
28 #include "cygserver.h"
29 #include "cygserver_transport.h"
31 int cygserver_running = CYGSERVER_UNKNOWN; // Nb: inherited by children.
33 bool allow_server = false; // Nb: inherited by children.
35 client_request_get_version::client_request_get_version ()
36 : client_request (CYGSERVER_REQUEST_GET_VERSION, &version, sizeof (version))
38 msglen (0); // No parameters for request.
40 // verbose: syscall_printf ("created");
44 * client_request_get_version::check_version ()
46 * The major version and API version numbers must match exactly. An
47 * older than expected minor version number is accepted (as long as
48 * the first numbers match, that is).
52 client_request_get_version::check_version () const
54 const bool ok = (version.major == CYGWIN_SERVER_VERSION_MAJOR
55 && version.api == CYGWIN_SERVER_VERSION_API
56 && version.minor <= CYGWIN_SERVER_VERSION_MINOR);
59 syscall_printf (("incompatible version of cygwin server: "
60 "client version %d.%d.%d.%d, "
61 "server version %ld.%ld.%ld.%ld"),
62 CYGWIN_SERVER_VERSION_MAJOR,
63 CYGWIN_SERVER_VERSION_API,
64 CYGWIN_SERVER_VERSION_MINOR,
65 CYGWIN_SERVER_VERSION_PATCH,
74 #ifdef __INSIDE_CYGWIN__
76 client_request_attach_tty::client_request_attach_tty (DWORD nmaster_pid,
79 : client_request (CYGSERVER_REQUEST_ATTACH_TTY, &req, sizeof (req))
81 req.pid = GetCurrentProcessId ();
82 req.master_pid = nmaster_pid;
83 req.from_master = nfrom_master;
84 req.to_master = nto_master;
86 syscall_printf (("created: pid = %lu, master_pid = %lu, "
87 "from_master = %lu, to_master = %lu"),
88 req.pid, req.master_pid, req.from_master, req.to_master);
91 #else /* !__INSIDE_CYGWIN__ */
93 client_request_attach_tty::client_request_attach_tty ()
94 : client_request (CYGSERVER_REQUEST_ATTACH_TTY, &req, sizeof (req))
96 // verbose: syscall_printf ("created");
99 #endif /* __INSIDE_CYGWIN__ */
102 * client_request_attach_tty::send ()
104 * Wraps the base method to provide error handling support. If the
105 * reply contains a body but is flagged as an error, close any handles
106 * that have been returned by cygserver and then discard the message
107 * body, i.e. the client either sees a successful result with handles
108 * or an unsuccessful result with no handles.
112 client_request_attach_tty::send (transport_layer_base * const conn)
114 client_request::send (conn);
116 if (msglen () && error_code ())
119 CloseHandle (from_master ());
121 CloseHandle (to_master ());
126 client_request::header_t::header_t (const request_code_t request_code,
129 request_code (request_code)
131 assert (request_code >= 0 && request_code < CYGSERVER_REQUEST_LAST);
134 // FIXME: also check write and read result for -1.
137 client_request::send (transport_layer_base * const conn)
140 assert (!(msglen () && !_buf)); // i.e., msglen () implies _buf
141 assert (msglen () <= _buflen);
144 const ssize_t count = conn->write (&_header, sizeof (_header));
146 if (count != sizeof (_header))
150 syscall_printf (("request header write failure: "
151 "only %ld bytes sent of %ld, "
153 count, sizeof (_header),
154 errno, GetLastError ());
161 const ssize_t count = conn->write (_buf, msglen ());
163 if (count == -1 || (size_t) count != msglen ())
167 syscall_printf (("request body write failure: "
168 "only %ld bytes sent of %ld, "
171 errno, GetLastError ());
176 // verbose: syscall_printf ("request sent (%ld + %ld bytes)",
177 // sizeof (_header), msglen ());
180 const ssize_t count = conn->read (&_header, sizeof (_header));
182 if (count != sizeof (_header))
186 syscall_printf (("reply header read failure: "
187 "only %ld bytes received of %ld, "
189 count, sizeof (_header),
190 errno, GetLastError ());
195 if (msglen () && !_buf)
197 system_printf ("no client buffer for reply body: %ld bytes needed",
203 if (msglen () > _buflen)
205 system_printf (("client buffer too small for reply body: "
206 "have %ld bytes and need %ld"),
214 const ssize_t count = conn->read (_buf, msglen ());
216 if (count == -1 || (size_t) count != msglen ())
220 syscall_printf (("reply body read failure: "
221 "only %ld bytes received of %ld, "
224 errno, GetLastError ());
229 // verbose: syscall_printf ("reply received (%ld + %ld bytes)",
230 // sizeof (_header), msglen ());
233 #ifndef __INSIDE_CYGWIN__
236 * client_request::handle_request ()
238 * A server-side method.
240 * This is a factory method for the client_request subclasses. It
241 * reads the incoming request header and, based on its request code,
242 * creates an instance of the appropriate class.
244 * FIXME: If the incoming packet is malformed, the server drops it on
245 * the floor. Should it try and generate some sort of reply for the
246 * client? As it is, the client will simply get a broken connection.
248 * FIXME: also check write and read result for -1.
252 client_request::handle_request (transport_layer_base *const conn,
253 process_cache *const cache)
255 // verbose: debug_printf ("about to read");
260 const ssize_t count = conn->read (&header, sizeof (header));
262 if (count != sizeof (header))
264 syscall_printf (("request header read failure: "
265 "only %ld bytes received of %ld, "
267 count, sizeof (header),
268 errno, GetLastError ());
272 // verbose: debug_printf ("got header (%ld)", count);
275 client_request *req = NULL;
277 switch (header.request_code)
279 case CYGSERVER_REQUEST_GET_VERSION:
280 req = safe_new0 (client_request_get_version);
282 case CYGSERVER_REQUEST_SHUTDOWN:
283 req = safe_new0 (client_request_shutdown);
285 case CYGSERVER_REQUEST_ATTACH_TTY:
286 req = safe_new0 (client_request_attach_tty);
288 case CYGSERVER_REQUEST_SHM:
289 req = safe_new0 (client_request_shm);
292 syscall_printf ("unknown request code %d received: request ignored",
293 header.request_code);
299 req->msglen (header.msglen);
300 req->handle (conn, cache);
305 printf ("."); // A little noise when we're being quiet.
309 #endif /* !__INSIDE_CYGWIN__ */
311 client_request::client_request (request_code_t const id,
314 : _header (id, buflen),
318 assert ((!_buf && !_buflen) || (_buf && _buflen));
321 client_request::~client_request ()
325 client_request::make_request ()
327 assert (cygserver_running == CYGSERVER_UNKNOWN \
328 || cygserver_running == CYGSERVER_OK \
329 || cygserver_running == CYGSERVER_UNAVAIL);
331 if (cygserver_running == CYGSERVER_UNKNOWN)
334 assert (cygserver_running == CYGSERVER_OK \
335 || cygserver_running == CYGSERVER_UNAVAIL);
337 /* Don't retry every request if the server's not there */
338 if (cygserver_running == CYGSERVER_UNAVAIL)
340 syscall_printf ("cygserver un-available");
345 transport_layer_base *const transport = create_server_transport ();
349 if (transport->connect () == -1)
355 safe_delete (transport);
359 // verbose: debug_printf ("connected to server %p", transport);
363 safe_delete (transport);
368 #ifndef __INSIDE_CYGWIN__
371 * client_request::handle ()
373 * A server-side method.
375 * At this point, the header of an incoming request has been read and
376 * an appropriate client_request object constructed. This method has
377 * to read the request body into its buffer, if there is such a body,
378 * then perform the request and send back the results to the client.
380 * FIXME: If the incoming packet is malformed, the server drops it on
381 * the floor. Should it try and generate some sort of reply for the
382 * client? As it is, the client will simply get a broken connection.
384 * FIXME: also check write and read result for -1.
388 client_request::handle (transport_layer_base *const conn,
389 process_cache *const cache)
391 if (msglen () && !_buf)
393 system_printf ("no buffer for request body: %ld bytes needed",
399 if (msglen () > _buflen)
401 system_printf (("buffer too small for request body: "
402 "have %ld bytes and need %ld"),
410 const ssize_t count = conn->read (_buf, msglen ());
412 if (count == -1 || (size_t) count != msglen ())
416 syscall_printf (("request body read failure: "
417 "only %ld bytes received of %ld, "
420 errno, GetLastError ());
425 // verbose: syscall_printf ("request received (%ld + %ld bytes)",
426 // sizeof (_header), msglen ());
428 error_code (0); // Overwrites the _header.request_code field.
431 * This is not allowed to fail. We must return ENOSYS at a minimum
437 const ssize_t count = conn->write (&_header, sizeof (_header));
439 if (count != sizeof (_header))
443 syscall_printf (("reply header write failure: "
444 "only %ld bytes sent of %ld, "
446 count, sizeof (_header),
447 errno, GetLastError ());
454 const ssize_t count = conn->write (_buf, msglen ());
456 if (count == -1 || (size_t) count != msglen ())
460 syscall_printf (("reply body write failure: "
461 "only %ld bytes sent of %ld, "
464 errno, GetLastError ());
469 // verbose: syscall_printf ("reply sent (%ld + %ld bytes)",
470 // sizeof (_header), msglen ());
473 #endif /* !__INSIDE_CYGWIN__ */
476 check_cygserver_available ()
478 assert (cygserver_running == CYGSERVER_UNKNOWN \
479 || cygserver_running == CYGSERVER_UNAVAIL);
481 cygserver_running = CYGSERVER_OK; // For make_request ().
483 client_request_get_version req;
485 /* This indicates that we failed to connect to cygserver at all but
486 * that's fine as cygwin doesn't need it to be running.
488 if (req.make_request () == -1)
491 /* We connected to the server but something went wrong after that
492 * (in sending the message, in cygserver itself, or in receiving the
495 if (req.error_code ())
497 syscall_printf ("failure in cygserver version request: %d",
499 syscall_printf ("process will continue without cygserver support");
503 return req.check_version ();
511 syscall_printf ("cygserver use disabled in client");
512 cygserver_running = CYGSERVER_UNAVAIL;
516 assert (cygserver_running == CYGSERVER_UNKNOWN \
517 || cygserver_running == CYGSERVER_OK \
518 || cygserver_running == CYGSERVER_UNAVAIL);
520 if (cygserver_running == CYGSERVER_OK)
523 if (!check_cygserver_available ())
524 cygserver_running = CYGSERVER_UNAVAIL;