3 Written by Egor Duda <deo@logos-m.ru>
5 This file is part of Cygwin.
7 This software is a copyrighted work licensed under the terms of the
8 Cygwin license. Please consult the file "CYGWIN_LICENSE" for
11 /* to allow this to link into cygwin and the .dll, a little magic is needed. */
12 #ifdef __OUTSIDE_CYGWIN__
23 #include "cygserver_msg.h"
24 #include "cygserver_sem.h"
25 #include "cygserver_shm.h"
26 #include "cygserver_setpwd.h"
27 #include "cygserver_pwdgrp.h"
29 #include "cygserver.h"
30 #include "transport.h"
32 int cygserver_running
= CYGSERVER_UNKNOWN
; // Nb: inherited by children.
34 client_request_get_version::client_request_get_version ()
35 : client_request (CYGSERVER_REQUEST_GET_VERSION
, &version
, sizeof (version
))
37 msglen (0); // No parameters for request.
39 // verbose: syscall_printf ("created");
43 * client_request_get_version::check_version ()
45 * The major version and API version numbers must match exactly. An
46 * older than expected minor version number is accepted (as long as
47 * the first numbers match, that is).
50 #ifdef __INSIDE_CYGWIN__
53 client_request_get_version::check_version () const
55 const bool ok
= (version
.major
== CYGWIN_SERVER_VERSION_MAJOR
56 && version
.api
== CYGWIN_SERVER_VERSION_API
57 && version
.minor
<= CYGWIN_SERVER_VERSION_MINOR
);
60 syscall_printf (("incompatible version of cygwin server: "
61 "client version %d.%d.%d.%d, "
62 "server version %d.%d.%d.%d"),
63 CYGWIN_SERVER_VERSION_MAJOR
,
64 CYGWIN_SERVER_VERSION_API
,
65 CYGWIN_SERVER_VERSION_MINOR
,
66 CYGWIN_SERVER_VERSION_PATCH
,
75 client_request_attach_tty::client_request_attach_tty (DWORD nmaster_pid
,
78 : client_request (CYGSERVER_REQUEST_ATTACH_TTY
, &req
, sizeof (req
))
80 req
.pid
= GetCurrentProcessId ();
81 req
.master_pid
= nmaster_pid
;
82 req
.from_master
= nfrom_master
;
83 req
.to_master
= nto_master
;
85 syscall_printf (("created: pid = %u, master_pid = %u, "
86 "from_master = %p, to_master = %p"),
87 req
.pid
, req
.master_pid
, req
.from_master
, req
.to_master
);
89 #endif /* __INSIDE_CYGWIN__ */
92 * client_request_attach_tty::send ()
94 * Wraps the base method to provide error handling support. If the
95 * reply contains a body but is flagged as an error, close any handles
96 * that have been returned by cygserver and then discard the message
97 * body, i.e. the client either sees a successful result with handles
98 * or an unsuccessful result with no handles.
102 client_request_attach_tty::send (transport_layer_base
* const conn
)
104 client_request::send (conn
);
106 if (msglen () && error_code ())
109 CloseHandle (from_master ());
111 CloseHandle (to_master ());
116 client_request::header_t::header_t (const request_code_t request_code
,
118 : request_code (request_code
)
120 assert (request_code
>= 0 && request_code
< CYGSERVER_REQUEST_LAST
);
124 // FIXME: also check write and read result for -1.
127 client_request::send (transport_layer_base
* const conn
)
130 assert (!(msglen () && !_buf
)); // i.e., msglen () implies _buf
131 assert (msglen () <= _buflen
);
134 const ssize_t count
= conn
->write (&_header
, sizeof (_header
));
136 if (count
!= sizeof (_header
))
140 syscall_printf (("request header write failure: "
141 "only %ld bytes sent of %lu, "
143 count
, sizeof (_header
),
144 errno
, GetLastError ());
151 const ssize_t count
= conn
->write (_buf
, msglen ());
153 if (count
== -1 || (size_t) count
!= msglen ())
157 syscall_printf (("request body write failure: "
158 "only %ld bytes sent of %lu, "
161 errno
, GetLastError ());
167 const ssize_t count
= conn
->read (&_header
, sizeof (_header
));
169 if (count
!= sizeof (_header
))
173 syscall_printf (("reply header read failure: "
174 "only %ld bytes received of %lu, "
176 count
, sizeof (_header
),
177 errno
, GetLastError ());
182 if (msglen () && !_buf
)
184 system_printf ("no client buffer for reply body: %lu bytes needed",
190 if (msglen () > _buflen
)
192 system_printf (("client buffer too small for reply body: "
193 "have %lu bytes and need %lu"),
201 const ssize_t count
= conn
->read (_buf
, msglen ());
203 if (count
== -1 || (size_t) count
!= msglen ())
207 syscall_printf (("reply body read failure: "
208 "only %ld bytes received of %lu, "
211 errno
, GetLastError ());
217 #ifdef __OUTSIDE_CYGWIN__
219 client_request_attach_tty::client_request_attach_tty ()
220 : client_request (CYGSERVER_REQUEST_ATTACH_TTY
, &req
, sizeof (req
))
225 * client_request::handle_request ()
227 * A server-side method.
229 * This is a factory method for the client_request subclasses. It
230 * reads the incoming request header and, based on its request code,
231 * creates an instance of the appropriate class.
233 * FIXME: If the incoming packet is malformed, the server drops it on
234 * the floor. Should it try and generate some sort of reply for the
235 * client? As it is, the client will simply get a broken connection.
237 * FIXME: also check write and read result for -1.
241 client_request::handle_request (transport_layer_base
*const conn
,
242 process_cache
*const cache
)
244 // verbose: debug_printf ("about to read");
249 const ssize_t count
= conn
->read (&header
, sizeof (header
));
251 if (count
!= sizeof (header
))
253 syscall_printf (("request header read failure: "
254 "only %ld bytes received of %lu, "
256 count
, sizeof (header
),
257 errno
, GetLastError ());
262 client_request
*req
= NULL
;
264 switch (header
.request_code
)
266 case CYGSERVER_REQUEST_GET_VERSION
:
267 req
= new client_request_get_version
;
269 case CYGSERVER_REQUEST_SHUTDOWN
:
270 req
= new client_request_shutdown
;
272 case CYGSERVER_REQUEST_ATTACH_TTY
:
273 req
= new client_request_attach_tty
;
275 case CYGSERVER_REQUEST_MSG
:
276 req
= new client_request_msg
;
278 case CYGSERVER_REQUEST_SEM
:
279 req
= new client_request_sem
;
281 case CYGSERVER_REQUEST_SHM
:
282 req
= new client_request_shm
;
284 case CYGSERVER_REQUEST_SETPWD
:
285 req
= new client_request_setpwd
;
287 case CYGSERVER_REQUEST_PWDGRP
:
288 req
= new client_request_pwdgrp
;
291 syscall_printf ("unknown request code %d received: request ignored",
292 header
.request_code
);
298 req
->msglen (header
.msglen
);
299 req
->handle (conn
, cache
);
305 * client_request::handle ()
307 * A server-side method.
309 * At this point, the header of an incoming request has been read and
310 * an appropriate client_request object constructed. This method has
311 * to read the request body into its buffer, if there is such a body,
312 * then perform the request and send back the results to the client.
314 * FIXME: If the incoming packet is malformed, the server drops it on
315 * the floor. Should it try and generate some sort of reply for the
316 * client? As it is, the client will simply get a broken connection.
318 * FIXME: also check write and read result for -1.
322 client_request::handle (transport_layer_base
*const conn
,
323 process_cache
*const cache
)
325 if (msglen () && !_buf
)
327 system_printf ("no buffer for request body: %lu bytes needed",
333 if (msglen () > _buflen
)
335 system_printf (("buffer too small for request body: "
336 "have %lu bytes and need %lu"),
344 const ssize_t count
= conn
->read (_buf
, msglen ());
346 if (count
== -1 || (size_t) count
!= msglen ())
350 syscall_printf (("request body read failure: "
351 "only %ld bytes received of %lu, "
354 errno
, GetLastError ());
359 error_code (0); // Overwrites the _header.request_code field.
362 * This is not allowed to fail. We must return ENOSYS at a minimum
368 const ssize_t count
= conn
->write (&_header
, sizeof (_header
));
370 if (count
!= sizeof (_header
))
374 syscall_printf (("reply header write failure: "
375 "only %ld bytes sent of %lu, "
377 count
, sizeof (_header
),
378 errno
, GetLastError ());
385 const ssize_t count
= conn
->write (_buf
, msglen ());
387 if (count
== -1 || (size_t) count
!= msglen ())
391 syscall_printf (("reply body write failure: "
392 "only %ld bytes sent of %lu, "
395 errno
, GetLastError ());
401 /* The server side implementation of make_request. Very simple. */
403 client_request::make_request ()
405 transport_layer_base
*const transport
= create_server_transport ();
407 if (transport
->connect () == -1)
420 #endif /* __OUTSIDE_CYGWIN__ */
422 client_request::client_request (request_code_t
const id
,
425 : _header (id
, buflen
),
429 assert ((!_buf
&& !_buflen
) || (_buf
&& _buflen
));
432 client_request::~client_request ()
435 #ifdef __INSIDE_CYGWIN__
437 client_request::make_request ()
439 assert (cygserver_running
== CYGSERVER_UNKNOWN \
440 || cygserver_running
== CYGSERVER_OK \
441 || cygserver_running
== CYGSERVER_UNAVAIL
);
443 if (cygserver_running
== CYGSERVER_UNKNOWN
)
446 assert (cygserver_running
== CYGSERVER_OK \
447 || cygserver_running
== CYGSERVER_UNAVAIL
);
449 /* Don't retry every request if the server's not there */
450 if (cygserver_running
== CYGSERVER_UNAVAIL
)
452 syscall_printf ("cygserver un-available");
457 transport_layer_base
*const transport
= create_server_transport ();
461 if (transport
->connect () == -1)
471 // verbose: debug_printf ("connected to server %p", transport);
481 check_cygserver_available ()
483 assert (cygserver_running
== CYGSERVER_UNKNOWN \
484 || cygserver_running
== CYGSERVER_UNAVAIL
);
486 cygserver_running
= CYGSERVER_OK
; // For make_request ().
488 client_request_get_version req
;
490 /* This indicates that we failed to connect to cygserver at all but
491 * that's fine as cygwin doesn't need it to be running.
493 if (req
.make_request () == -1)
496 /* We connected to the server but something went wrong after that
497 * (in sending the message, in cygserver itself, or in receiving the
500 if (req
.error_code ())
502 syscall_printf ("failure in cygserver version request: %d",
504 syscall_printf ("process will continue without cygserver support");
508 return req
.check_version ();
514 assert (cygserver_running
== CYGSERVER_UNKNOWN \
515 || cygserver_running
== CYGSERVER_OK \
516 || cygserver_running
== CYGSERVER_UNAVAIL
);
518 if (cygserver_running
== CYGSERVER_OK
)
521 if (!check_cygserver_available ())
522 cygserver_running
= CYGSERVER_UNAVAIL
;
524 #endif /* __INSIDE_CYGWIN__ */