]> sourceware.org Git - newlib-cygwin.git/blame - winsup/cygserver/client.cc
* cygserver.cc (print_usage): Align output to utilities in utils
[newlib-cygwin.git] / winsup / cygserver / client.cc
CommitLineData
282113ba 1/* client.cc
f449bfef 2
7ffaa17c 3 Copyright 2001, 2002, 2003, 2004, 2008, 2009 Red Hat Inc.
f449bfef
RC
4
5 Written by Egor Duda <deo@logos-m.ru>
6
1c001dd2 7This file is part of Cygwin.
f449bfef 8
1c001dd2
CS
9This software is a copyrighted work licensed under the terms of the
10Cygwin license. Please consult the file "CYGWIN_LICENSE" for
11details. */
f449bfef 12
1c001dd2 13/* to allow this to link into cygwin and the .dll, a little magic is needed. */
f449bfef 14#ifdef __OUTSIDE_CYGWIN__
1c001dd2 15#include "woutsup.h"
f449bfef
RC
16#else
17#include "winsup.h"
18#endif
19
1c001dd2 20#include <assert.h>
1dcd520b 21#include <errno.h>
1c001dd2 22#include <stdio.h>
f449bfef 23#include <unistd.h>
1c001dd2 24
373a036f
CV
25#include "sigproc.h"
26
282113ba
CV
27#include "cygserver_msg.h"
28#include "cygserver_sem.h"
1c001dd2 29#include "cygserver_shm.h"
d4db08d7 30#include "cygserver_setpwd.h"
1c001dd2 31
56797078 32#include "cygserver.h"
282113ba 33#include "transport.h"
1c001dd2
CS
34
35int cygserver_running = CYGSERVER_UNKNOWN; // Nb: inherited by children.
f449bfef 36
1c001dd2
CS
37client_request_get_version::client_request_get_version ()
38 : client_request (CYGSERVER_REQUEST_GET_VERSION, &version, sizeof (version))
f449bfef 39{
1c001dd2
CS
40 msglen (0); // No parameters for request.
41
42 // verbose: syscall_printf ("created");
f449bfef
RC
43}
44
1c001dd2
CS
45/*
46 * client_request_get_version::check_version ()
47 *
48 * The major version and API version numbers must match exactly. An
49 * older than expected minor version number is accepted (as long as
50 * the first numbers match, that is).
51 */
52
282113ba
CV
53#ifdef __INSIDE_CYGWIN__
54
1c001dd2
CS
55bool
56client_request_get_version::check_version () const
f449bfef 57{
1c001dd2
CS
58 const bool ok = (version.major == CYGWIN_SERVER_VERSION_MAJOR
59 && version.api == CYGWIN_SERVER_VERSION_API
60 && version.minor <= CYGWIN_SERVER_VERSION_MINOR);
61
62 if (!ok)
63 syscall_printf (("incompatible version of cygwin server: "
64 "client version %d.%d.%d.%d, "
65 "server version %ld.%ld.%ld.%ld"),
66 CYGWIN_SERVER_VERSION_MAJOR,
67 CYGWIN_SERVER_VERSION_API,
68 CYGWIN_SERVER_VERSION_MINOR,
69 CYGWIN_SERVER_VERSION_PATCH,
70 version.major,
71 version.api,
72 version.minor,
73 version.patch);
74
75 return ok;
f449bfef
RC
76}
77
1c001dd2
CS
78client_request_attach_tty::client_request_attach_tty (DWORD nmaster_pid,
79 HANDLE nfrom_master,
80 HANDLE nto_master)
81 : client_request (CYGSERVER_REQUEST_ATTACH_TTY, &req, sizeof (req))
f449bfef 82{
1c001dd2 83 req.pid = GetCurrentProcessId ();
f449bfef
RC
84 req.master_pid = nmaster_pid;
85 req.from_master = nfrom_master;
86 req.to_master = nto_master;
f449bfef 87
1c001dd2
CS
88 syscall_printf (("created: pid = %lu, master_pid = %lu, "
89 "from_master = %lu, to_master = %lu"),
90 req.pid, req.master_pid, req.from_master, req.to_master);
f449bfef 91}
1c001dd2
CS
92#endif /* __INSIDE_CYGWIN__ */
93
94/*
95 * client_request_attach_tty::send ()
96 *
97 * Wraps the base method to provide error handling support. If the
98 * reply contains a body but is flagged as an error, close any handles
99 * that have been returned by cygserver and then discard the message
100 * body, i.e. the client either sees a successful result with handles
101 * or an unsuccessful result with no handles.
102 */
103
104void
105client_request_attach_tty::send (transport_layer_base * const conn)
f449bfef 106{
1c001dd2
CS
107 client_request::send (conn);
108
109 if (msglen () && error_code ())
110 {
111 if (from_master ())
112 CloseHandle (from_master ());
113 if (to_master ())
114 CloseHandle (to_master ());
115 msglen (0);
116 }
f449bfef
RC
117}
118
1c001dd2
CS
119client_request::header_t::header_t (const request_code_t request_code,
120 const size_t msglen)
121 : msglen (msglen),
122 request_code (request_code)
f449bfef 123{
1c001dd2 124 assert (request_code >= 0 && request_code < CYGSERVER_REQUEST_LAST);
f449bfef
RC
125}
126
1c001dd2
CS
127// FIXME: also check write and read result for -1.
128
f449bfef 129void
1c001dd2 130client_request::send (transport_layer_base * const conn)
f449bfef 131{
1c001dd2
CS
132 assert (conn);
133 assert (!(msglen () && !_buf)); // i.e., msglen () implies _buf
134 assert (msglen () <= _buflen);
135
136 {
137 const ssize_t count = conn->write (&_header, sizeof (_header));
138
139 if (count != sizeof (_header))
140 {
141 assert (errno);
142 error_code (errno);
143 syscall_printf (("request header write failure: "
144 "only %ld bytes sent of %ld, "
145 "error = %d(%lu)"),
146 count, sizeof (_header),
147 errno, GetLastError ());
148 return;
149 }
150 }
151
152 if (msglen ())
f449bfef 153 {
1c001dd2
CS
154 const ssize_t count = conn->write (_buf, msglen ());
155
156 if (count == -1 || (size_t) count != msglen ())
157 {
158 assert (errno);
159 error_code (errno);
160 syscall_printf (("request body write failure: "
161 "only %ld bytes sent of %ld, "
162 "error = %d(%lu)"),
163 count, msglen (),
164 errno, GetLastError ());
165 return;
166 }
167 }
168
169 // verbose: syscall_printf ("request sent (%ld + %ld bytes)",
170 // sizeof (_header), msglen ());
171
172 {
173 const ssize_t count = conn->read (&_header, sizeof (_header));
174
175 if (count != sizeof (_header))
176 {
177 assert (errno);
178 error_code (errno);
179 syscall_printf (("reply header read failure: "
180 "only %ld bytes received of %ld, "
181 "error = %d(%lu)"),
182 count, sizeof (_header),
183 errno, GetLastError ());
184 return;
185 }
186 }
187
188 if (msglen () && !_buf)
189 {
190 system_printf ("no client buffer for reply body: %ld bytes needed",
191 msglen ());
192 error_code (EINVAL);
193 return;
194 }
195
196 if (msglen () > _buflen)
197 {
198 system_printf (("client buffer too small for reply body: "
199 "have %ld bytes and need %ld"),
200 _buflen, msglen ());
201 error_code (EINVAL);
f449bfef
RC
202 return;
203 }
204
1c001dd2
CS
205 if (msglen ())
206 {
207 const ssize_t count = conn->read (_buf, msglen ());
208
209 if (count == -1 || (size_t) count != msglen ())
210 {
211 assert (errno);
212 error_code (errno);
213 syscall_printf (("reply body read failure: "
214 "only %ld bytes received of %ld, "
215 "error = %d(%lu)"),
216 count, msglen (),
217 errno, GetLastError ());
218 return;
219 }
220 }
221
222 // verbose: syscall_printf ("reply received (%ld + %ld bytes)",
223 // sizeof (_header), msglen ());
224}
225
282113ba
CV
226#ifdef __OUTSIDE_CYGWIN__
227
228client_request_attach_tty::client_request_attach_tty ()
229 : client_request (CYGSERVER_REQUEST_ATTACH_TTY, &req, sizeof (req))
230{
231}
1c001dd2
CS
232
233/*
234 * client_request::handle_request ()
235 *
236 * A server-side method.
237 *
238 * This is a factory method for the client_request subclasses. It
239 * reads the incoming request header and, based on its request code,
240 * creates an instance of the appropriate class.
241 *
242 * FIXME: If the incoming packet is malformed, the server drops it on
243 * the floor. Should it try and generate some sort of reply for the
244 * client? As it is, the client will simply get a broken connection.
245 *
246 * FIXME: also check write and read result for -1.
247 */
248
249/* static */ void
250client_request::handle_request (transport_layer_base *const conn,
251 process_cache *const cache)
252{
253 // verbose: debug_printf ("about to read");
254
255 header_t header;
256
257 {
258 const ssize_t count = conn->read (&header, sizeof (header));
259
260 if (count != sizeof (header))
261 {
262 syscall_printf (("request header read failure: "
263 "only %ld bytes received of %ld, "
264 "error = %d(%lu)"),
265 count, sizeof (header),
266 errno, GetLastError ());
267 return;
268 }
269
270 // verbose: debug_printf ("got header (%ld)", count);
271 }
f449bfef 272
1c001dd2
CS
273 client_request *req = NULL;
274
275 switch (header.request_code)
f449bfef 276 {
1c001dd2 277 case CYGSERVER_REQUEST_GET_VERSION:
282113ba 278 req = new client_request_get_version;
1c001dd2
CS
279 break;
280 case CYGSERVER_REQUEST_SHUTDOWN:
282113ba 281 req = new client_request_shutdown;
1c001dd2
CS
282 break;
283 case CYGSERVER_REQUEST_ATTACH_TTY:
282113ba
CV
284 req = new client_request_attach_tty;
285 break;
286 case CYGSERVER_REQUEST_MSG:
287 req = new client_request_msg;
288 break;
289 case CYGSERVER_REQUEST_SEM:
290 req = new client_request_sem;
1c001dd2
CS
291 break;
292 case CYGSERVER_REQUEST_SHM:
282113ba 293 req = new client_request_shm;
1c001dd2 294 break;
d4db08d7
CV
295 case CYGSERVER_REQUEST_SETPWD:
296 req = new client_request_setpwd;
297 break;
1c001dd2
CS
298 default:
299 syscall_printf ("unknown request code %d received: request ignored",
300 header.request_code);
f449bfef
RC
301 return;
302 }
1c001dd2
CS
303
304 assert (req);
305
306 req->msglen (header.msglen);
307 req->handle (conn, cache);
308
282113ba 309 delete req;
f449bfef
RC
310}
311
1c001dd2
CS
312/*
313 * client_request::handle ()
314 *
315 * A server-side method.
316 *
317 * At this point, the header of an incoming request has been read and
318 * an appropriate client_request object constructed. This method has
319 * to read the request body into its buffer, if there is such a body,
320 * then perform the request and send back the results to the client.
321 *
322 * FIXME: If the incoming packet is malformed, the server drops it on
323 * the floor. Should it try and generate some sort of reply for the
324 * client? As it is, the client will simply get a broken connection.
325 *
326 * FIXME: also check write and read result for -1.
327 */
328
329void
330client_request::handle (transport_layer_base *const conn,
331 process_cache *const cache)
332{
333 if (msglen () && !_buf)
334 {
335 system_printf ("no buffer for request body: %ld bytes needed",
336 msglen ());
337 error_code (EINVAL);
338 return;
339 }
340
341 if (msglen () > _buflen)
342 {
343 system_printf (("buffer too small for request body: "
344 "have %ld bytes and need %ld"),
345 _buflen, msglen ());
346 error_code (EINVAL);
347 return;
348 }
349
350 if (msglen ())
351 {
352 const ssize_t count = conn->read (_buf, msglen ());
353
354 if (count == -1 || (size_t) count != msglen ())
355 {
356 assert (errno);
357 error_code (errno);
358 syscall_printf (("request body read failure: "
359 "only %ld bytes received of %ld, "
360 "error = %d(%lu)"),
361 count, msglen (),
362 errno, GetLastError ());
363 return;
364 }
365 }
366
367 // verbose: syscall_printf ("request received (%ld + %ld bytes)",
368 // sizeof (_header), msglen ());
369
370 error_code (0); // Overwrites the _header.request_code field.
371
372 /*
373 * This is not allowed to fail. We must return ENOSYS at a minimum
374 * to the client.
375 */
376 serve (conn, cache);
377
378 {
379 const ssize_t count = conn->write (&_header, sizeof (_header));
380
381 if (count != sizeof (_header))
382 {
383 assert (errno);
384 error_code (errno);
385 syscall_printf (("reply header write failure: "
386 "only %ld bytes sent of %ld, "
387 "error = %d(%lu)"),
388 count, sizeof (_header),
389 errno, GetLastError ());
390 return;
391 }
392 }
393
394 if (msglen ())
395 {
396 const ssize_t count = conn->write (_buf, msglen ());
397
398 if (count == -1 || (size_t) count != msglen ())
399 {
400 assert (errno);
401 error_code (errno);
402 syscall_printf (("reply body write failure: "
403 "only %ld bytes sent of %ld, "
404 "error = %d(%lu)"),
405 count, msglen (),
406 errno, GetLastError ());
407 return;
408 }
409 }
410
411 // verbose: syscall_printf ("reply sent (%ld + %ld bytes)",
412 // sizeof (_header), msglen ());
413}
414
282113ba
CV
415/* The server side implementation of make_request. Very simple. */
416int
417client_request::make_request ()
418{
419 transport_layer_base *const transport = create_server_transport ();
420 assert (transport);
421 if (transport->connect () == -1)
422 {
423 if (errno)
424 error_code (errno);
425 else
426 error_code (ENOSYS);
427 delete transport;
428 return -1;
429 }
430 send (transport);
431 delete transport;
432 return 0;
433}
434#endif /* __OUTSIDE_CYGWIN__ */
435
436client_request::client_request (request_code_t const id,
437 void * const buf,
438 size_t const buflen)
439 : _header (id, buflen),
440 _buf (buf),
441 _buflen (buflen)
442{
443 assert ((!_buf && !_buflen) || (_buf && _buflen));
444}
445
446client_request::~client_request ()
447{}
448
449#ifdef __INSIDE_CYGWIN__
450int
451client_request::make_request ()
452{
453 assert (cygserver_running == CYGSERVER_UNKNOWN \
454 || cygserver_running == CYGSERVER_OK \
455 || cygserver_running == CYGSERVER_UNAVAIL);
456
457 if (cygserver_running == CYGSERVER_UNKNOWN)
458 cygserver_init ();
459
460 assert (cygserver_running == CYGSERVER_OK \
461 || cygserver_running == CYGSERVER_UNAVAIL);
462
463 /* Don't retry every request if the server's not there */
464 if (cygserver_running == CYGSERVER_UNAVAIL)
465 {
466 syscall_printf ("cygserver un-available");
467 error_code (ENOSYS);
468 return -1;
469 }
470
471 transport_layer_base *const transport = create_server_transport ();
472
473 assert (transport);
474
475 if (transport->connect () == -1)
476 {
477 if (errno)
478 error_code (errno);
479 else
480 error_code (ENOSYS);
481 delete transport;
482 return -1;
483 }
484
485 // verbose: debug_printf ("connected to server %p", transport);
486
487 send (transport);
488
489 delete transport;
490
491 return 0;
492}
1c001dd2
CS
493
494bool
f449bfef
RC
495check_cygserver_available ()
496{
1c001dd2
CS
497 assert (cygserver_running == CYGSERVER_UNKNOWN \
498 || cygserver_running == CYGSERVER_UNAVAIL);
499
500 cygserver_running = CYGSERVER_OK; // For make_request ().
501
502 client_request_get_version req;
503
504 /* This indicates that we failed to connect to cygserver at all but
505 * that's fine as cygwin doesn't need it to be running.
506 */
507 if (req.make_request () == -1)
508 return false;
509
510 /* We connected to the server but something went wrong after that
511 * (in sending the message, in cygserver itself, or in receiving the
512 * reply).
513 */
514 if (req.error_code ())
515 {
516 syscall_printf ("failure in cygserver version request: %d",
517 req.error_code ());
518 syscall_printf ("process will continue without cygserver support");
519 return false;
520 }
521
522 return req.check_version ();
f449bfef 523}
f449bfef
RC
524
525void
526cygserver_init ()
527{
1c001dd2
CS
528 assert (cygserver_running == CYGSERVER_UNKNOWN \
529 || cygserver_running == CYGSERVER_OK \
530 || cygserver_running == CYGSERVER_UNAVAIL);
531
532 if (cygserver_running == CYGSERVER_OK)
f449bfef
RC
533 return;
534
1c001dd2
CS
535 if (!check_cygserver_available ())
536 cygserver_running = CYGSERVER_UNAVAIL;
f449bfef 537}
282113ba 538#endif /* __INSIDE_CYGWIN__ */
This page took 0.207744 seconds and 5 git commands to generate.