3 Copyright 2001, 2002, 2003, 2004, 2008, 2009, 2012, 2013, 2014 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_msg.h"
26 #include "cygserver_sem.h"
27 #include "cygserver_shm.h"
28 #include "cygserver_setpwd.h"
29 #include "cygserver_pwdgrp.h"
31 #include "cygserver.h"
32 #include "transport.h"
34 int cygserver_running
= CYGSERVER_UNKNOWN
; // Nb: inherited by children.
36 client_request_get_version::client_request_get_version ()
37 : client_request (CYGSERVER_REQUEST_GET_VERSION
, &version
, sizeof (version
))
39 msglen (0); // No parameters for request.
41 // verbose: syscall_printf ("created");
45 * client_request_get_version::check_version ()
47 * The major version and API version numbers must match exactly. An
48 * older than expected minor version number is accepted (as long as
49 * the first numbers match, that is).
52 #ifdef __INSIDE_CYGWIN__
55 client_request_get_version::check_version () const
57 const bool ok
= (version
.major
== CYGWIN_SERVER_VERSION_MAJOR
58 && version
.api
== CYGWIN_SERVER_VERSION_API
59 && version
.minor
<= CYGWIN_SERVER_VERSION_MINOR
);
62 syscall_printf (("incompatible version of cygwin server: "
63 "client version %d.%d.%d.%d, "
64 "server version %d.%d.%d.%d"),
65 CYGWIN_SERVER_VERSION_MAJOR
,
66 CYGWIN_SERVER_VERSION_API
,
67 CYGWIN_SERVER_VERSION_MINOR
,
68 CYGWIN_SERVER_VERSION_PATCH
,
77 client_request_attach_tty::client_request_attach_tty (DWORD nmaster_pid
,
80 : client_request (CYGSERVER_REQUEST_ATTACH_TTY
, &req
, sizeof (req
))
82 req
.pid
= GetCurrentProcessId ();
83 req
.master_pid
= nmaster_pid
;
84 req
.from_master
= nfrom_master
;
85 req
.to_master
= nto_master
;
87 syscall_printf (("created: pid = %u, master_pid = %u, "
88 "from_master = %p, to_master = %p"),
89 req
.pid
, req
.master_pid
, req
.from_master
, req
.to_master
);
91 #endif /* __INSIDE_CYGWIN__ */
94 * client_request_attach_tty::send ()
96 * Wraps the base method to provide error handling support. If the
97 * reply contains a body but is flagged as an error, close any handles
98 * that have been returned by cygserver and then discard the message
99 * body, i.e. the client either sees a successful result with handles
100 * or an unsuccessful result with no handles.
104 client_request_attach_tty::send (transport_layer_base
* const conn
)
106 client_request::send (conn
);
108 if (msglen () && error_code ())
111 CloseHandle (from_master ());
113 CloseHandle (to_master ());
118 client_request::header_t::header_t (const request_code_t request_code
,
120 : request_code (request_code
)
122 assert (request_code
>= 0 && request_code
< CYGSERVER_REQUEST_LAST
);
126 // FIXME: also check write and read result for -1.
129 client_request::send (transport_layer_base
* const conn
)
132 assert (!(msglen () && !_buf
)); // i.e., msglen () implies _buf
133 assert (msglen () <= _buflen
);
136 const ssize_t count
= conn
->write (&_header
, sizeof (_header
));
138 if (count
!= sizeof (_header
))
142 syscall_printf (("request header write failure: "
143 "only %ld bytes sent of %lu, "
145 count
, sizeof (_header
),
146 errno
, GetLastError ());
153 const ssize_t count
= conn
->write (_buf
, msglen ());
155 if (count
== -1 || (size_t) count
!= msglen ())
159 syscall_printf (("request body write failure: "
160 "only %ld bytes sent of %lu, "
163 errno
, GetLastError ());
169 const ssize_t count
= conn
->read (&_header
, sizeof (_header
));
171 if (count
!= sizeof (_header
))
175 syscall_printf (("reply header read failure: "
176 "only %ld bytes received of %lu, "
178 count
, sizeof (_header
),
179 errno
, GetLastError ());
184 if (msglen () && !_buf
)
186 system_printf ("no client buffer for reply body: %lu bytes needed",
192 if (msglen () > _buflen
)
194 system_printf (("client buffer too small for reply body: "
195 "have %lu bytes and need %lu"),
203 const ssize_t count
= conn
->read (_buf
, msglen ());
205 if (count
== -1 || (size_t) count
!= msglen ())
209 syscall_printf (("reply body read failure: "
210 "only %ld bytes received of %lu, "
213 errno
, GetLastError ());
219 #ifdef __OUTSIDE_CYGWIN__
221 client_request_attach_tty::client_request_attach_tty ()
222 : client_request (CYGSERVER_REQUEST_ATTACH_TTY
, &req
, sizeof (req
))
227 * client_request::handle_request ()
229 * A server-side method.
231 * This is a factory method for the client_request subclasses. It
232 * reads the incoming request header and, based on its request code,
233 * creates an instance of the appropriate class.
235 * FIXME: If the incoming packet is malformed, the server drops it on
236 * the floor. Should it try and generate some sort of reply for the
237 * client? As it is, the client will simply get a broken connection.
239 * FIXME: also check write and read result for -1.
243 client_request::handle_request (transport_layer_base
*const conn
,
244 process_cache
*const cache
)
246 // verbose: debug_printf ("about to read");
251 const ssize_t count
= conn
->read (&header
, sizeof (header
));
253 if (count
!= sizeof (header
))
255 syscall_printf (("request header read failure: "
256 "only %ld bytes received of %lu, "
258 count
, sizeof (header
),
259 errno
, GetLastError ());
264 client_request
*req
= NULL
;
266 switch (header
.request_code
)
268 case CYGSERVER_REQUEST_GET_VERSION
:
269 req
= new client_request_get_version
;
271 case CYGSERVER_REQUEST_SHUTDOWN
:
272 req
= new client_request_shutdown
;
274 case CYGSERVER_REQUEST_ATTACH_TTY
:
275 req
= new client_request_attach_tty
;
277 case CYGSERVER_REQUEST_MSG
:
278 req
= new client_request_msg
;
280 case CYGSERVER_REQUEST_SEM
:
281 req
= new client_request_sem
;
283 case CYGSERVER_REQUEST_SHM
:
284 req
= new client_request_shm
;
286 case CYGSERVER_REQUEST_SETPWD
:
287 req
= new client_request_setpwd
;
289 case CYGSERVER_REQUEST_PWDGRP
:
290 req
= new client_request_pwdgrp
;
293 syscall_printf ("unknown request code %d received: request ignored",
294 header
.request_code
);
300 req
->msglen (header
.msglen
);
301 req
->handle (conn
, cache
);
307 * client_request::handle ()
309 * A server-side method.
311 * At this point, the header of an incoming request has been read and
312 * an appropriate client_request object constructed. This method has
313 * to read the request body into its buffer, if there is such a body,
314 * then perform the request and send back the results to the client.
316 * FIXME: If the incoming packet is malformed, the server drops it on
317 * the floor. Should it try and generate some sort of reply for the
318 * client? As it is, the client will simply get a broken connection.
320 * FIXME: also check write and read result for -1.
324 client_request::handle (transport_layer_base
*const conn
,
325 process_cache
*const cache
)
327 if (msglen () && !_buf
)
329 system_printf ("no buffer for request body: %lu bytes needed",
335 if (msglen () > _buflen
)
337 system_printf (("buffer too small for request body: "
338 "have %lu bytes and need %lu"),
346 const ssize_t count
= conn
->read (_buf
, msglen ());
348 if (count
== -1 || (size_t) count
!= msglen ())
352 syscall_printf (("request body read failure: "
353 "only %ld bytes received of %lu, "
356 errno
, GetLastError ());
361 error_code (0); // Overwrites the _header.request_code field.
364 * This is not allowed to fail. We must return ENOSYS at a minimum
370 const ssize_t count
= conn
->write (&_header
, sizeof (_header
));
372 if (count
!= sizeof (_header
))
376 syscall_printf (("reply header write failure: "
377 "only %ld bytes sent of %lu, "
379 count
, sizeof (_header
),
380 errno
, GetLastError ());
387 const ssize_t count
= conn
->write (_buf
, msglen ());
389 if (count
== -1 || (size_t) count
!= msglen ())
393 syscall_printf (("reply body write failure: "
394 "only %ld bytes sent of %lu, "
397 errno
, GetLastError ());
403 /* The server side implementation of make_request. Very simple. */
405 client_request::make_request ()
407 transport_layer_base
*const transport
= create_server_transport ();
409 if (transport
->connect () == -1)
422 #endif /* __OUTSIDE_CYGWIN__ */
424 client_request::client_request (request_code_t
const id
,
427 : _header (id
, buflen
),
431 assert ((!_buf
&& !_buflen
) || (_buf
&& _buflen
));
434 client_request::~client_request ()
437 #ifdef __INSIDE_CYGWIN__
439 client_request::make_request ()
441 assert (cygserver_running
== CYGSERVER_UNKNOWN \
442 || cygserver_running
== CYGSERVER_OK \
443 || cygserver_running
== CYGSERVER_UNAVAIL
);
445 if (cygserver_running
== CYGSERVER_UNKNOWN
)
448 assert (cygserver_running
== CYGSERVER_OK \
449 || cygserver_running
== CYGSERVER_UNAVAIL
);
451 /* Don't retry every request if the server's not there */
452 if (cygserver_running
== CYGSERVER_UNAVAIL
)
454 syscall_printf ("cygserver un-available");
459 transport_layer_base
*const transport
= create_server_transport ();
463 if (transport
->connect () == -1)
473 // verbose: debug_printf ("connected to server %p", transport);
483 check_cygserver_available ()
485 assert (cygserver_running
== CYGSERVER_UNKNOWN \
486 || cygserver_running
== CYGSERVER_UNAVAIL
);
488 cygserver_running
= CYGSERVER_OK
; // For make_request ().
490 client_request_get_version req
;
492 /* This indicates that we failed to connect to cygserver at all but
493 * that's fine as cygwin doesn't need it to be running.
495 if (req
.make_request () == -1)
498 /* We connected to the server but something went wrong after that
499 * (in sending the message, in cygserver itself, or in receiving the
502 if (req
.error_code ())
504 syscall_printf ("failure in cygserver version request: %d",
506 syscall_printf ("process will continue without cygserver support");
510 return req
.check_version ();
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
;
526 #endif /* __INSIDE_CYGWIN__ */