]> sourceware.org Git - newlib-cygwin.git/blame - winsup/cygserver/client.cc
* Makefile.in: Add -lntdll to link line.
[newlib-cygwin.git] / winsup / cygserver / client.cc
CommitLineData
282113ba 1/* client.cc
f449bfef 2
1dcd520b 3 Copyright 2001, 2002, 2003, 2004 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"
1c001dd2 30
56797078 31#include "cygserver.h"
282113ba 32#include "transport.h"
1c001dd2
CS
33
34int cygserver_running = CYGSERVER_UNKNOWN; // Nb: inherited by children.
f449bfef 35
29c1c508 36bool allow_server = false; // Nb: inherited by children.
f449bfef 37
1c001dd2
CS
38client_request_get_version::client_request_get_version ()
39 : client_request (CYGSERVER_REQUEST_GET_VERSION, &version, sizeof (version))
f449bfef 40{
1c001dd2
CS
41 msglen (0); // No parameters for request.
42
43 // verbose: syscall_printf ("created");
f449bfef
RC
44}
45
1c001dd2
CS
46/*
47 * client_request_get_version::check_version ()
48 *
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).
52 */
53
282113ba
CV
54#ifdef __INSIDE_CYGWIN__
55
1c001dd2
CS
56bool
57client_request_get_version::check_version () const
f449bfef 58{
1c001dd2
CS
59 const bool ok = (version.major == CYGWIN_SERVER_VERSION_MAJOR
60 && version.api == CYGWIN_SERVER_VERSION_API
61 && version.minor <= CYGWIN_SERVER_VERSION_MINOR);
62
63 if (!ok)
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,
71 version.major,
72 version.api,
73 version.minor,
74 version.patch);
75
76 return ok;
f449bfef
RC
77}
78
1c001dd2
CS
79client_request_attach_tty::client_request_attach_tty (DWORD nmaster_pid,
80 HANDLE nfrom_master,
81 HANDLE nto_master)
82 : client_request (CYGSERVER_REQUEST_ATTACH_TTY, &req, sizeof (req))
f449bfef 83{
1c001dd2 84 req.pid = GetCurrentProcessId ();
f449bfef
RC
85 req.master_pid = nmaster_pid;
86 req.from_master = nfrom_master;
87 req.to_master = nto_master;
f449bfef 88
1c001dd2
CS
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);
f449bfef 92}
1c001dd2
CS
93#endif /* __INSIDE_CYGWIN__ */
94
95/*
96 * client_request_attach_tty::send ()
97 *
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.
103 */
104
105void
106client_request_attach_tty::send (transport_layer_base * const conn)
f449bfef 107{
1c001dd2
CS
108 client_request::send (conn);
109
110 if (msglen () && error_code ())
111 {
112 if (from_master ())
113 CloseHandle (from_master ());
114 if (to_master ())
115 CloseHandle (to_master ());
116 msglen (0);
117 }
f449bfef
RC
118}
119
1c001dd2
CS
120client_request::header_t::header_t (const request_code_t request_code,
121 const size_t msglen)
122 : msglen (msglen),
123 request_code (request_code)
f449bfef 124{
1c001dd2 125 assert (request_code >= 0 && request_code < CYGSERVER_REQUEST_LAST);
f449bfef
RC
126}
127
1c001dd2
CS
128// FIXME: also check write and read result for -1.
129
f449bfef 130void
1c001dd2 131client_request::send (transport_layer_base * const conn)
f449bfef 132{
1c001dd2
CS
133 assert (conn);
134 assert (!(msglen () && !_buf)); // i.e., msglen () implies _buf
135 assert (msglen () <= _buflen);
136
137 {
138 const ssize_t count = conn->write (&_header, sizeof (_header));
139
140 if (count != sizeof (_header))
141 {
142 assert (errno);
143 error_code (errno);
144 syscall_printf (("request header write failure: "
145 "only %ld bytes sent of %ld, "
146 "error = %d(%lu)"),
147 count, sizeof (_header),
148 errno, GetLastError ());
149 return;
150 }
151 }
152
153 if (msglen ())
f449bfef 154 {
1c001dd2
CS
155 const ssize_t count = conn->write (_buf, msglen ());
156
157 if (count == -1 || (size_t) count != msglen ())
158 {
159 assert (errno);
160 error_code (errno);
161 syscall_printf (("request body write failure: "
162 "only %ld bytes sent of %ld, "
163 "error = %d(%lu)"),
164 count, msglen (),
165 errno, GetLastError ());
166 return;
167 }
168 }
169
170 // verbose: syscall_printf ("request sent (%ld + %ld bytes)",
171 // sizeof (_header), msglen ());
172
173 {
174 const ssize_t count = conn->read (&_header, sizeof (_header));
175
176 if (count != sizeof (_header))
177 {
178 assert (errno);
179 error_code (errno);
180 syscall_printf (("reply header read failure: "
181 "only %ld bytes received of %ld, "
182 "error = %d(%lu)"),
183 count, sizeof (_header),
184 errno, GetLastError ());
185 return;
186 }
187 }
188
189 if (msglen () && !_buf)
190 {
191 system_printf ("no client buffer for reply body: %ld bytes needed",
192 msglen ());
193 error_code (EINVAL);
194 return;
195 }
196
197 if (msglen () > _buflen)
198 {
199 system_printf (("client buffer too small for reply body: "
200 "have %ld bytes and need %ld"),
201 _buflen, msglen ());
202 error_code (EINVAL);
f449bfef
RC
203 return;
204 }
205
1c001dd2
CS
206 if (msglen ())
207 {
208 const ssize_t count = conn->read (_buf, msglen ());
209
210 if (count == -1 || (size_t) count != msglen ())
211 {
212 assert (errno);
213 error_code (errno);
214 syscall_printf (("reply body read failure: "
215 "only %ld bytes received of %ld, "
216 "error = %d(%lu)"),
217 count, msglen (),
218 errno, GetLastError ());
219 return;
220 }
221 }
222
223 // verbose: syscall_printf ("reply received (%ld + %ld bytes)",
224 // sizeof (_header), msglen ());
225}
226
282113ba
CV
227#ifdef __OUTSIDE_CYGWIN__
228
229client_request_attach_tty::client_request_attach_tty ()
230 : client_request (CYGSERVER_REQUEST_ATTACH_TTY, &req, sizeof (req))
231{
232}
1c001dd2
CS
233
234/*
235 * client_request::handle_request ()
236 *
237 * A server-side method.
238 *
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.
242 *
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.
246 *
247 * FIXME: also check write and read result for -1.
248 */
249
250/* static */ void
251client_request::handle_request (transport_layer_base *const conn,
252 process_cache *const cache)
253{
254 // verbose: debug_printf ("about to read");
255
256 header_t header;
257
258 {
259 const ssize_t count = conn->read (&header, sizeof (header));
260
261 if (count != sizeof (header))
262 {
263 syscall_printf (("request header read failure: "
264 "only %ld bytes received of %ld, "
265 "error = %d(%lu)"),
266 count, sizeof (header),
267 errno, GetLastError ());
268 return;
269 }
270
271 // verbose: debug_printf ("got header (%ld)", count);
272 }
f449bfef 273
1c001dd2
CS
274 client_request *req = NULL;
275
276 switch (header.request_code)
f449bfef 277 {
1c001dd2 278 case CYGSERVER_REQUEST_GET_VERSION:
282113ba 279 req = new client_request_get_version;
1c001dd2
CS
280 break;
281 case CYGSERVER_REQUEST_SHUTDOWN:
282113ba 282 req = new client_request_shutdown;
1c001dd2
CS
283 break;
284 case CYGSERVER_REQUEST_ATTACH_TTY:
282113ba
CV
285 req = new client_request_attach_tty;
286 break;
287 case CYGSERVER_REQUEST_MSG:
288 req = new client_request_msg;
289 break;
290 case CYGSERVER_REQUEST_SEM:
291 req = new client_request_sem;
1c001dd2
CS
292 break;
293 case CYGSERVER_REQUEST_SHM:
282113ba 294 req = new client_request_shm;
1c001dd2
CS
295 break;
296 default:
297 syscall_printf ("unknown request code %d received: request ignored",
298 header.request_code);
f449bfef
RC
299 return;
300 }
1c001dd2
CS
301
302 assert (req);
303
304 req->msglen (header.msglen);
305 req->handle (conn, cache);
306
282113ba 307 delete req;
f449bfef
RC
308}
309
1c001dd2
CS
310/*
311 * client_request::handle ()
312 *
313 * A server-side method.
314 *
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.
319 *
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.
323 *
324 * FIXME: also check write and read result for -1.
325 */
326
327void
328client_request::handle (transport_layer_base *const conn,
329 process_cache *const cache)
330{
331 if (msglen () && !_buf)
332 {
333 system_printf ("no buffer for request body: %ld bytes needed",
334 msglen ());
335 error_code (EINVAL);
336 return;
337 }
338
339 if (msglen () > _buflen)
340 {
341 system_printf (("buffer too small for request body: "
342 "have %ld bytes and need %ld"),
343 _buflen, msglen ());
344 error_code (EINVAL);
345 return;
346 }
347
348 if (msglen ())
349 {
350 const ssize_t count = conn->read (_buf, msglen ());
351
352 if (count == -1 || (size_t) count != msglen ())
353 {
354 assert (errno);
355 error_code (errno);
356 syscall_printf (("request body read failure: "
357 "only %ld bytes received of %ld, "
358 "error = %d(%lu)"),
359 count, msglen (),
360 errno, GetLastError ());
361 return;
362 }
363 }
364
365 // verbose: syscall_printf ("request received (%ld + %ld bytes)",
366 // sizeof (_header), msglen ());
367
368 error_code (0); // Overwrites the _header.request_code field.
369
370 /*
371 * This is not allowed to fail. We must return ENOSYS at a minimum
372 * to the client.
373 */
374 serve (conn, cache);
375
376 {
377 const ssize_t count = conn->write (&_header, sizeof (_header));
378
379 if (count != sizeof (_header))
380 {
381 assert (errno);
382 error_code (errno);
383 syscall_printf (("reply header write failure: "
384 "only %ld bytes sent of %ld, "
385 "error = %d(%lu)"),
386 count, sizeof (_header),
387 errno, GetLastError ());
388 return;
389 }
390 }
391
392 if (msglen ())
393 {
394 const ssize_t count = conn->write (_buf, msglen ());
395
396 if (count == -1 || (size_t) count != msglen ())
397 {
398 assert (errno);
399 error_code (errno);
400 syscall_printf (("reply body write failure: "
401 "only %ld bytes sent of %ld, "
402 "error = %d(%lu)"),
403 count, msglen (),
404 errno, GetLastError ());
405 return;
406 }
407 }
408
409 // verbose: syscall_printf ("reply sent (%ld + %ld bytes)",
410 // sizeof (_header), msglen ());
411}
412
282113ba
CV
413/* The server side implementation of make_request. Very simple. */
414int
415client_request::make_request ()
416{
417 transport_layer_base *const transport = create_server_transport ();
418 assert (transport);
419 if (transport->connect () == -1)
420 {
421 if (errno)
422 error_code (errno);
423 else
424 error_code (ENOSYS);
425 delete transport;
426 return -1;
427 }
428 send (transport);
429 delete transport;
430 return 0;
431}
432#endif /* __OUTSIDE_CYGWIN__ */
433
434client_request::client_request (request_code_t const id,
435 void * const buf,
436 size_t const buflen)
437 : _header (id, buflen),
438 _buf (buf),
439 _buflen (buflen)
440{
441 assert ((!_buf && !_buflen) || (_buf && _buflen));
442}
443
444client_request::~client_request ()
445{}
446
447#ifdef __INSIDE_CYGWIN__
448int
449client_request::make_request ()
450{
451 assert (cygserver_running == CYGSERVER_UNKNOWN \
452 || cygserver_running == CYGSERVER_OK \
453 || cygserver_running == CYGSERVER_UNAVAIL);
454
455 if (cygserver_running == CYGSERVER_UNKNOWN)
456 cygserver_init ();
457
458 assert (cygserver_running == CYGSERVER_OK \
459 || cygserver_running == CYGSERVER_UNAVAIL);
460
461 /* Don't retry every request if the server's not there */
462 if (cygserver_running == CYGSERVER_UNAVAIL)
463 {
464 syscall_printf ("cygserver un-available");
465 error_code (ENOSYS);
466 return -1;
467 }
468
469 transport_layer_base *const transport = create_server_transport ();
470
471 assert (transport);
472
473 if (transport->connect () == -1)
474 {
475 if (errno)
476 error_code (errno);
477 else
478 error_code (ENOSYS);
479 delete transport;
480 return -1;
481 }
482
483 // verbose: debug_printf ("connected to server %p", transport);
484
485 send (transport);
486
487 delete transport;
488
489 return 0;
490}
1c001dd2
CS
491
492bool
f449bfef
RC
493check_cygserver_available ()
494{
1c001dd2
CS
495 assert (cygserver_running == CYGSERVER_UNKNOWN \
496 || cygserver_running == CYGSERVER_UNAVAIL);
497
498 cygserver_running = CYGSERVER_OK; // For make_request ().
499
500 client_request_get_version req;
501
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.
504 */
505 if (req.make_request () == -1)
506 return false;
507
508 /* We connected to the server but something went wrong after that
509 * (in sending the message, in cygserver itself, or in receiving the
510 * reply).
511 */
512 if (req.error_code ())
513 {
514 syscall_printf ("failure in cygserver version request: %d",
515 req.error_code ());
516 syscall_printf ("process will continue without cygserver support");
517 return false;
518 }
519
520 return req.check_version ();
f449bfef 521}
f449bfef
RC
522
523void
524cygserver_init ()
525{
29c1c508 526 if (!allow_server)
f449bfef 527 {
1c001dd2
CS
528 syscall_printf ("cygserver use disabled in client");
529 cygserver_running = CYGSERVER_UNAVAIL;
f449bfef
RC
530 return;
531 }
532
1c001dd2
CS
533 assert (cygserver_running == CYGSERVER_UNKNOWN \
534 || cygserver_running == CYGSERVER_OK \
535 || cygserver_running == CYGSERVER_UNAVAIL);
536
537 if (cygserver_running == CYGSERVER_OK)
f449bfef
RC
538 return;
539
1c001dd2
CS
540 if (!check_cygserver_available ())
541 cygserver_running = CYGSERVER_UNAVAIL;
f449bfef 542}
282113ba 543#endif /* __INSIDE_CYGWIN__ */
This page took 0.162021 seconds and 5 git commands to generate.