3 Copyright 2001, 2002, 2003, 2004 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"
31 #include "cygserver.h"
32 #include "transport.h"
34 int cygserver_running
= CYGSERVER_UNKNOWN
; // Nb: inherited by children.
36 bool allow_server
= false; // Nb: inherited by children.
38 client_request_get_version::client_request_get_version ()
39 : client_request (CYGSERVER_REQUEST_GET_VERSION
, &version
, sizeof (version
))
41 msglen (0); // No parameters for request.
43 // verbose: syscall_printf ("created");
47 * client_request_get_version::check_version ()
49 * The major version and API version numbers must match exactly. An
50 * older than expected minor version number is accepted (as long as
51 * the first numbers match, that is).
54 #ifdef __INSIDE_CYGWIN__
57 client_request_get_version::check_version () const
59 const bool ok
= (version
.major
== CYGWIN_SERVER_VERSION_MAJOR
60 && version
.api
== CYGWIN_SERVER_VERSION_API
61 && version
.minor
<= CYGWIN_SERVER_VERSION_MINOR
);
64 syscall_printf (("incompatible version of cygwin server: "
65 "client version %d.%d.%d.%d, "
66 "server version %ld.%ld.%ld.%ld"),
67 CYGWIN_SERVER_VERSION_MAJOR
,
68 CYGWIN_SERVER_VERSION_API
,
69 CYGWIN_SERVER_VERSION_MINOR
,
70 CYGWIN_SERVER_VERSION_PATCH
,
79 client_request_attach_tty::client_request_attach_tty (DWORD nmaster_pid
,
82 : client_request (CYGSERVER_REQUEST_ATTACH_TTY
, &req
, sizeof (req
))
84 req
.pid
= GetCurrentProcessId ();
85 req
.master_pid
= nmaster_pid
;
86 req
.from_master
= nfrom_master
;
87 req
.to_master
= nto_master
;
89 syscall_printf (("created: pid = %lu, master_pid = %lu, "
90 "from_master = %lu, to_master = %lu"),
91 req
.pid
, req
.master_pid
, req
.from_master
, req
.to_master
);
93 #endif /* __INSIDE_CYGWIN__ */
96 * client_request_attach_tty::send ()
98 * Wraps the base method to provide error handling support. If the
99 * reply contains a body but is flagged as an error, close any handles
100 * that have been returned by cygserver and then discard the message
101 * body, i.e. the client either sees a successful result with handles
102 * or an unsuccessful result with no handles.
106 client_request_attach_tty::send (transport_layer_base
* const conn
)
108 client_request::send (conn
);
110 if (msglen () && error_code ())
113 CloseHandle (from_master ());
115 CloseHandle (to_master ());
120 client_request::header_t::header_t (const request_code_t request_code
,
123 request_code (request_code
)
125 assert (request_code
>= 0 && request_code
< CYGSERVER_REQUEST_LAST
);
128 // FIXME: also check write and read result for -1.
131 client_request::send (transport_layer_base
* const conn
)
134 assert (!(msglen () && !_buf
)); // i.e., msglen () implies _buf
135 assert (msglen () <= _buflen
);
138 const ssize_t count
= conn
->write (&_header
, sizeof (_header
));
140 if (count
!= sizeof (_header
))
144 syscall_printf (("request header write failure: "
145 "only %ld bytes sent of %ld, "
147 count
, sizeof (_header
),
148 errno
, GetLastError ());
155 const ssize_t count
= conn
->write (_buf
, msglen ());
157 if (count
== -1 || (size_t) count
!= msglen ())
161 syscall_printf (("request body write failure: "
162 "only %ld bytes sent of %ld, "
165 errno
, GetLastError ());
170 // verbose: syscall_printf ("request sent (%ld + %ld bytes)",
171 // sizeof (_header), msglen ());
174 const ssize_t count
= conn
->read (&_header
, sizeof (_header
));
176 if (count
!= sizeof (_header
))
180 syscall_printf (("reply header read failure: "
181 "only %ld bytes received of %ld, "
183 count
, sizeof (_header
),
184 errno
, GetLastError ());
189 if (msglen () && !_buf
)
191 system_printf ("no client buffer for reply body: %ld bytes needed",
197 if (msglen () > _buflen
)
199 system_printf (("client buffer too small for reply body: "
200 "have %ld bytes and need %ld"),
208 const ssize_t count
= conn
->read (_buf
, msglen ());
210 if (count
== -1 || (size_t) count
!= msglen ())
214 syscall_printf (("reply body read failure: "
215 "only %ld bytes received of %ld, "
218 errno
, GetLastError ());
223 // verbose: syscall_printf ("reply received (%ld + %ld bytes)",
224 // sizeof (_header), msglen ());
227 #ifdef __OUTSIDE_CYGWIN__
229 client_request_attach_tty::client_request_attach_tty ()
230 : client_request (CYGSERVER_REQUEST_ATTACH_TTY
, &req
, sizeof (req
))
235 * client_request::handle_request ()
237 * A server-side method.
239 * This is a factory method for the client_request subclasses. It
240 * reads the incoming request header and, based on its request code,
241 * creates an instance of the appropriate class.
243 * FIXME: If the incoming packet is malformed, the server drops it on
244 * the floor. Should it try and generate some sort of reply for the
245 * client? As it is, the client will simply get a broken connection.
247 * FIXME: also check write and read result for -1.
251 client_request::handle_request (transport_layer_base
*const conn
,
252 process_cache
*const cache
)
254 // verbose: debug_printf ("about to read");
259 const ssize_t count
= conn
->read (&header
, sizeof (header
));
261 if (count
!= sizeof (header
))
263 syscall_printf (("request header read failure: "
264 "only %ld bytes received of %ld, "
266 count
, sizeof (header
),
267 errno
, GetLastError ());
271 // verbose: debug_printf ("got header (%ld)", count);
274 client_request
*req
= NULL
;
276 switch (header
.request_code
)
278 case CYGSERVER_REQUEST_GET_VERSION
:
279 req
= new client_request_get_version
;
281 case CYGSERVER_REQUEST_SHUTDOWN
:
282 req
= new client_request_shutdown
;
284 case CYGSERVER_REQUEST_ATTACH_TTY
:
285 req
= new client_request_attach_tty
;
287 case CYGSERVER_REQUEST_MSG
:
288 req
= new client_request_msg
;
290 case CYGSERVER_REQUEST_SEM
:
291 req
= new client_request_sem
;
293 case CYGSERVER_REQUEST_SHM
:
294 req
= new client_request_shm
;
297 syscall_printf ("unknown request code %d received: request ignored",
298 header
.request_code
);
304 req
->msglen (header
.msglen
);
305 req
->handle (conn
, cache
);
311 * client_request::handle ()
313 * A server-side method.
315 * At this point, the header of an incoming request has been read and
316 * an appropriate client_request object constructed. This method has
317 * to read the request body into its buffer, if there is such a body,
318 * then perform the request and send back the results to the client.
320 * FIXME: If the incoming packet is malformed, the server drops it on
321 * the floor. Should it try and generate some sort of reply for the
322 * client? As it is, the client will simply get a broken connection.
324 * FIXME: also check write and read result for -1.
328 client_request::handle (transport_layer_base
*const conn
,
329 process_cache
*const cache
)
331 if (msglen () && !_buf
)
333 system_printf ("no buffer for request body: %ld bytes needed",
339 if (msglen () > _buflen
)
341 system_printf (("buffer too small for request body: "
342 "have %ld bytes and need %ld"),
350 const ssize_t count
= conn
->read (_buf
, msglen ());
352 if (count
== -1 || (size_t) count
!= msglen ())
356 syscall_printf (("request body read failure: "
357 "only %ld bytes received of %ld, "
360 errno
, GetLastError ());
365 // verbose: syscall_printf ("request received (%ld + %ld bytes)",
366 // sizeof (_header), msglen ());
368 error_code (0); // Overwrites the _header.request_code field.
371 * This is not allowed to fail. We must return ENOSYS at a minimum
377 const ssize_t count
= conn
->write (&_header
, sizeof (_header
));
379 if (count
!= sizeof (_header
))
383 syscall_printf (("reply header write failure: "
384 "only %ld bytes sent of %ld, "
386 count
, sizeof (_header
),
387 errno
, GetLastError ());
394 const ssize_t count
= conn
->write (_buf
, msglen ());
396 if (count
== -1 || (size_t) count
!= msglen ())
400 syscall_printf (("reply body write failure: "
401 "only %ld bytes sent of %ld, "
404 errno
, GetLastError ());
409 // verbose: syscall_printf ("reply sent (%ld + %ld bytes)",
410 // sizeof (_header), msglen ());
413 /* The server side implementation of make_request. Very simple. */
415 client_request::make_request ()
417 transport_layer_base
*const transport
= create_server_transport ();
419 if (transport
->connect () == -1)
432 #endif /* __OUTSIDE_CYGWIN__ */
434 client_request::client_request (request_code_t
const id
,
437 : _header (id
, buflen
),
441 assert ((!_buf
&& !_buflen
) || (_buf
&& _buflen
));
444 client_request::~client_request ()
447 #ifdef __INSIDE_CYGWIN__
449 client_request::make_request ()
451 assert (cygserver_running
== CYGSERVER_UNKNOWN \
452 || cygserver_running
== CYGSERVER_OK \
453 || cygserver_running
== CYGSERVER_UNAVAIL
);
455 if (cygserver_running
== CYGSERVER_UNKNOWN
)
458 assert (cygserver_running
== CYGSERVER_OK \
459 || cygserver_running
== CYGSERVER_UNAVAIL
);
461 /* Don't retry every request if the server's not there */
462 if (cygserver_running
== CYGSERVER_UNAVAIL
)
464 syscall_printf ("cygserver un-available");
469 transport_layer_base
*const transport
= create_server_transport ();
473 if (transport
->connect () == -1)
483 // verbose: debug_printf ("connected to server %p", transport);
493 check_cygserver_available ()
495 assert (cygserver_running
== CYGSERVER_UNKNOWN \
496 || cygserver_running
== CYGSERVER_UNAVAIL
);
498 cygserver_running
= CYGSERVER_OK
; // For make_request ().
500 client_request_get_version req
;
502 /* This indicates that we failed to connect to cygserver at all but
503 * that's fine as cygwin doesn't need it to be running.
505 if (req
.make_request () == -1)
508 /* We connected to the server but something went wrong after that
509 * (in sending the message, in cygserver itself, or in receiving the
512 if (req
.error_code ())
514 syscall_printf ("failure in cygserver version request: %d",
516 syscall_printf ("process will continue without cygserver support");
520 return req
.check_version ();
528 syscall_printf ("cygserver use disabled in client");
529 cygserver_running
= CYGSERVER_UNAVAIL
;
533 assert (cygserver_running
== CYGSERVER_UNKNOWN \
534 || cygserver_running
== CYGSERVER_OK \
535 || cygserver_running
== CYGSERVER_UNAVAIL
);
537 if (cygserver_running
== CYGSERVER_OK
)
540 if (!check_cygserver_available ())
541 cygserver_running
= CYGSERVER_UNAVAIL
;
543 #endif /* __INSIDE_CYGWIN__ */