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"
30 #include "cygserver.h"
31 #include "transport.h"
33 int cygserver_running
= CYGSERVER_UNKNOWN
; // 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).
51 #ifdef __INSIDE_CYGWIN__
54 client_request_get_version::check_version () const
56 const bool ok
= (version
.major
== CYGWIN_SERVER_VERSION_MAJOR
57 && version
.api
== CYGWIN_SERVER_VERSION_API
58 && version
.minor
<= CYGWIN_SERVER_VERSION_MINOR
);
61 syscall_printf (("incompatible version of cygwin server: "
62 "client version %d.%d.%d.%d, "
63 "server version %d.%d.%d.%d"),
64 CYGWIN_SERVER_VERSION_MAJOR
,
65 CYGWIN_SERVER_VERSION_API
,
66 CYGWIN_SERVER_VERSION_MINOR
,
67 CYGWIN_SERVER_VERSION_PATCH
,
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 = %u, master_pid = %u, "
87 "from_master = %p, to_master = %p"),
88 req
.pid
, req
.master_pid
, req
.from_master
, req
.to_master
);
90 #endif /* __INSIDE_CYGWIN__ */
93 * client_request_attach_tty::send ()
95 * Wraps the base method to provide error handling support. If the
96 * reply contains a body but is flagged as an error, close any handles
97 * that have been returned by cygserver and then discard the message
98 * body, i.e. the client either sees a successful result with handles
99 * or an unsuccessful result with no handles.
103 client_request_attach_tty::send (transport_layer_base
* const conn
)
105 client_request::send (conn
);
107 if (msglen () && error_code ())
110 CloseHandle (from_master ());
112 CloseHandle (to_master ());
117 client_request::header_t::header_t (const request_code_t request_code
,
119 : request_code (request_code
)
121 assert (request_code
>= 0 && request_code
< CYGSERVER_REQUEST_LAST
);
125 // FIXME: also check write and read result for -1.
128 client_request::send (transport_layer_base
* const conn
)
131 assert (!(msglen () && !_buf
)); // i.e., msglen () implies _buf
132 assert (msglen () <= _buflen
);
135 const ssize_t count
= conn
->write (&_header
, sizeof (_header
));
137 if (count
!= sizeof (_header
))
141 syscall_printf (("request header write failure: "
142 "only %lu bytes sent of %lu, "
144 count
, sizeof (_header
),
145 errno
, GetLastError ());
152 const ssize_t count
= conn
->write (_buf
, msglen ());
154 if (count
== -1 || (size_t) count
!= msglen ())
158 syscall_printf (("request body write failure: "
159 "only %lu bytes sent of %lu, "
162 errno
, GetLastError ());
168 const ssize_t count
= conn
->read (&_header
, sizeof (_header
));
170 if (count
!= sizeof (_header
))
174 syscall_printf (("reply header read failure: "
175 "only %lu bytes received of %lu, "
177 count
, sizeof (_header
),
178 errno
, GetLastError ());
183 if (msglen () && !_buf
)
185 system_printf ("no client buffer for reply body: %lu bytes needed",
191 if (msglen () > _buflen
)
193 system_printf (("client buffer too small for reply body: "
194 "have %lu bytes and need %lu"),
202 const ssize_t count
= conn
->read (_buf
, msglen ());
204 if (count
== -1 || (size_t) count
!= msglen ())
208 syscall_printf (("reply body read failure: "
209 "only %lu bytes received of %lu, "
212 errno
, GetLastError ());
218 #ifdef __OUTSIDE_CYGWIN__
220 client_request_attach_tty::client_request_attach_tty ()
221 : client_request (CYGSERVER_REQUEST_ATTACH_TTY
, &req
, sizeof (req
))
226 * client_request::handle_request ()
228 * A server-side method.
230 * This is a factory method for the client_request subclasses. It
231 * reads the incoming request header and, based on its request code,
232 * creates an instance of the appropriate class.
234 * FIXME: If the incoming packet is malformed, the server drops it on
235 * the floor. Should it try and generate some sort of reply for the
236 * client? As it is, the client will simply get a broken connection.
238 * FIXME: also check write and read result for -1.
242 client_request::handle_request (transport_layer_base
*const conn
,
243 process_cache
*const cache
)
245 // verbose: debug_printf ("about to read");
250 const ssize_t count
= conn
->read (&header
, sizeof (header
));
252 if (count
!= sizeof (header
))
254 syscall_printf (("request header read failure: "
255 "only %lu bytes received of %lu, "
257 count
, sizeof (header
),
258 errno
, GetLastError ());
263 client_request
*req
= NULL
;
265 switch (header
.request_code
)
267 case CYGSERVER_REQUEST_GET_VERSION
:
268 req
= new client_request_get_version
;
270 case CYGSERVER_REQUEST_SHUTDOWN
:
271 req
= new client_request_shutdown
;
273 case CYGSERVER_REQUEST_ATTACH_TTY
:
274 req
= new client_request_attach_tty
;
276 case CYGSERVER_REQUEST_MSG
:
277 req
= new client_request_msg
;
279 case CYGSERVER_REQUEST_SEM
:
280 req
= new client_request_sem
;
282 case CYGSERVER_REQUEST_SHM
:
283 req
= new client_request_shm
;
285 case CYGSERVER_REQUEST_SETPWD
:
286 req
= new client_request_setpwd
;
289 syscall_printf ("unknown request code %d received: request ignored",
290 header
.request_code
);
296 req
->msglen (header
.msglen
);
297 req
->handle (conn
, cache
);
303 * client_request::handle ()
305 * A server-side method.
307 * At this point, the header of an incoming request has been read and
308 * an appropriate client_request object constructed. This method has
309 * to read the request body into its buffer, if there is such a body,
310 * then perform the request and send back the results to the client.
312 * FIXME: If the incoming packet is malformed, the server drops it on
313 * the floor. Should it try and generate some sort of reply for the
314 * client? As it is, the client will simply get a broken connection.
316 * FIXME: also check write and read result for -1.
320 client_request::handle (transport_layer_base
*const conn
,
321 process_cache
*const cache
)
323 if (msglen () && !_buf
)
325 system_printf ("no buffer for request body: %lu bytes needed",
331 if (msglen () > _buflen
)
333 system_printf (("buffer too small for request body: "
334 "have %lu bytes and need %lu"),
342 const ssize_t count
= conn
->read (_buf
, msglen ());
344 if (count
== -1 || (size_t) count
!= msglen ())
348 syscall_printf (("request body read failure: "
349 "only %lu bytes received of %lu, "
352 errno
, GetLastError ());
357 error_code (0); // Overwrites the _header.request_code field.
360 * This is not allowed to fail. We must return ENOSYS at a minimum
366 const ssize_t count
= conn
->write (&_header
, sizeof (_header
));
368 if (count
!= sizeof (_header
))
372 syscall_printf (("reply header write failure: "
373 "only %lu bytes sent of %lu, "
375 count
, sizeof (_header
),
376 errno
, GetLastError ());
383 const ssize_t count
= conn
->write (_buf
, msglen ());
385 if (count
== -1 || (size_t) count
!= msglen ())
389 syscall_printf (("reply body write failure: "
390 "only %lu bytes sent of %lu, "
393 errno
, GetLastError ());
399 /* The server side implementation of make_request. Very simple. */
401 client_request::make_request ()
403 transport_layer_base
*const transport
= create_server_transport ();
405 if (transport
->connect () == -1)
418 #endif /* __OUTSIDE_CYGWIN__ */
420 client_request::client_request (request_code_t
const id
,
423 : _header (id
, buflen
),
427 assert ((!_buf
&& !_buflen
) || (_buf
&& _buflen
));
430 client_request::~client_request ()
433 #ifdef __INSIDE_CYGWIN__
435 client_request::make_request ()
437 assert (cygserver_running
== CYGSERVER_UNKNOWN \
438 || cygserver_running
== CYGSERVER_OK \
439 || cygserver_running
== CYGSERVER_UNAVAIL
);
441 if (cygserver_running
== CYGSERVER_UNKNOWN
)
444 assert (cygserver_running
== CYGSERVER_OK \
445 || cygserver_running
== CYGSERVER_UNAVAIL
);
447 /* Don't retry every request if the server's not there */
448 if (cygserver_running
== CYGSERVER_UNAVAIL
)
450 syscall_printf ("cygserver un-available");
455 transport_layer_base
*const transport
= create_server_transport ();
459 if (transport
->connect () == -1)
469 // verbose: debug_printf ("connected to server %p", transport);
479 check_cygserver_available ()
481 assert (cygserver_running
== CYGSERVER_UNKNOWN \
482 || cygserver_running
== CYGSERVER_UNAVAIL
);
484 cygserver_running
= CYGSERVER_OK
; // For make_request ().
486 client_request_get_version req
;
488 /* This indicates that we failed to connect to cygserver at all but
489 * that's fine as cygwin doesn't need it to be running.
491 if (req
.make_request () == -1)
494 /* We connected to the server but something went wrong after that
495 * (in sending the message, in cygserver itself, or in receiving the
498 if (req
.error_code ())
500 syscall_printf ("failure in cygserver version request: %d",
502 syscall_printf ("process will continue without cygserver support");
506 return req
.check_version ();
512 assert (cygserver_running
== CYGSERVER_UNKNOWN \
513 || cygserver_running
== CYGSERVER_OK \
514 || cygserver_running
== CYGSERVER_UNAVAIL
);
516 if (cygserver_running
== CYGSERVER_OK
)
519 if (!check_cygserver_available ())
520 cygserver_running
= CYGSERVER_UNAVAIL
;
522 #endif /* __INSIDE_CYGWIN__ */