]> sourceware.org Git - newlib-cygwin.git/blame - winsup/cygserver/client.cc
* client.cc: Revert sigproc.h inclusion since it was fixed elsewhere.
[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
282113ba
CV
25#include "cygserver_msg.h"
26#include "cygserver_sem.h"
1c001dd2 27#include "cygserver_shm.h"
d4db08d7 28#include "cygserver_setpwd.h"
1c001dd2 29
56797078 30#include "cygserver.h"
282113ba 31#include "transport.h"
1c001dd2
CS
32
33int cygserver_running = CYGSERVER_UNKNOWN; // Nb: inherited by children.
f449bfef 34
1c001dd2
CS
35client_request_get_version::client_request_get_version ()
36 : client_request (CYGSERVER_REQUEST_GET_VERSION, &version, sizeof (version))
f449bfef 37{
1c001dd2
CS
38 msglen (0); // No parameters for request.
39
40 // verbose: syscall_printf ("created");
f449bfef
RC
41}
42
1c001dd2
CS
43/*
44 * client_request_get_version::check_version ()
45 *
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).
49 */
50
282113ba
CV
51#ifdef __INSIDE_CYGWIN__
52
1c001dd2
CS
53bool
54client_request_get_version::check_version () const
f449bfef 55{
1c001dd2
CS
56 const bool ok = (version.major == CYGWIN_SERVER_VERSION_MAJOR
57 && version.api == CYGWIN_SERVER_VERSION_API
58 && version.minor <= CYGWIN_SERVER_VERSION_MINOR);
59
60 if (!ok)
61 syscall_printf (("incompatible version of cygwin server: "
62 "client version %d.%d.%d.%d, "
63 "server version %ld.%ld.%ld.%ld"),
64 CYGWIN_SERVER_VERSION_MAJOR,
65 CYGWIN_SERVER_VERSION_API,
66 CYGWIN_SERVER_VERSION_MINOR,
67 CYGWIN_SERVER_VERSION_PATCH,
68 version.major,
69 version.api,
70 version.minor,
71 version.patch);
72
73 return ok;
f449bfef
RC
74}
75
1c001dd2
CS
76client_request_attach_tty::client_request_attach_tty (DWORD nmaster_pid,
77 HANDLE nfrom_master,
78 HANDLE nto_master)
79 : client_request (CYGSERVER_REQUEST_ATTACH_TTY, &req, sizeof (req))
f449bfef 80{
1c001dd2 81 req.pid = GetCurrentProcessId ();
f449bfef
RC
82 req.master_pid = nmaster_pid;
83 req.from_master = nfrom_master;
84 req.to_master = nto_master;
f449bfef 85
1c001dd2
CS
86 syscall_printf (("created: pid = %lu, master_pid = %lu, "
87 "from_master = %lu, to_master = %lu"),
88 req.pid, req.master_pid, req.from_master, req.to_master);
f449bfef 89}
1c001dd2
CS
90#endif /* __INSIDE_CYGWIN__ */
91
92/*
93 * client_request_attach_tty::send ()
94 *
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.
100 */
101
102void
103client_request_attach_tty::send (transport_layer_base * const conn)
f449bfef 104{
1c001dd2
CS
105 client_request::send (conn);
106
107 if (msglen () && error_code ())
108 {
109 if (from_master ())
110 CloseHandle (from_master ());
111 if (to_master ())
112 CloseHandle (to_master ());
113 msglen (0);
114 }
f449bfef
RC
115}
116
1c001dd2
CS
117client_request::header_t::header_t (const request_code_t request_code,
118 const size_t msglen)
119 : msglen (msglen),
120 request_code (request_code)
f449bfef 121{
1c001dd2 122 assert (request_code >= 0 && request_code < CYGSERVER_REQUEST_LAST);
f449bfef
RC
123}
124
1c001dd2
CS
125// FIXME: also check write and read result for -1.
126
f449bfef 127void
1c001dd2 128client_request::send (transport_layer_base * const conn)
f449bfef 129{
1c001dd2
CS
130 assert (conn);
131 assert (!(msglen () && !_buf)); // i.e., msglen () implies _buf
132 assert (msglen () <= _buflen);
133
134 {
135 const ssize_t count = conn->write (&_header, sizeof (_header));
136
137 if (count != sizeof (_header))
138 {
139 assert (errno);
140 error_code (errno);
141 syscall_printf (("request header write failure: "
142 "only %ld bytes sent of %ld, "
143 "error = %d(%lu)"),
144 count, sizeof (_header),
145 errno, GetLastError ());
146 return;
147 }
148 }
149
150 if (msglen ())
f449bfef 151 {
1c001dd2
CS
152 const ssize_t count = conn->write (_buf, msglen ());
153
154 if (count == -1 || (size_t) count != msglen ())
155 {
156 assert (errno);
157 error_code (errno);
158 syscall_printf (("request body write failure: "
159 "only %ld bytes sent of %ld, "
160 "error = %d(%lu)"),
161 count, msglen (),
162 errno, GetLastError ());
163 return;
164 }
165 }
166
167 // verbose: syscall_printf ("request sent (%ld + %ld bytes)",
168 // sizeof (_header), msglen ());
169
170 {
171 const ssize_t count = conn->read (&_header, sizeof (_header));
172
173 if (count != sizeof (_header))
174 {
175 assert (errno);
176 error_code (errno);
177 syscall_printf (("reply header read failure: "
178 "only %ld bytes received of %ld, "
179 "error = %d(%lu)"),
180 count, sizeof (_header),
181 errno, GetLastError ());
182 return;
183 }
184 }
185
186 if (msglen () && !_buf)
187 {
188 system_printf ("no client buffer for reply body: %ld bytes needed",
189 msglen ());
190 error_code (EINVAL);
191 return;
192 }
193
194 if (msglen () > _buflen)
195 {
196 system_printf (("client buffer too small for reply body: "
197 "have %ld bytes and need %ld"),
198 _buflen, msglen ());
199 error_code (EINVAL);
f449bfef
RC
200 return;
201 }
202
1c001dd2
CS
203 if (msglen ())
204 {
205 const ssize_t count = conn->read (_buf, msglen ());
206
207 if (count == -1 || (size_t) count != msglen ())
208 {
209 assert (errno);
210 error_code (errno);
211 syscall_printf (("reply body read failure: "
212 "only %ld bytes received of %ld, "
213 "error = %d(%lu)"),
214 count, msglen (),
215 errno, GetLastError ());
216 return;
217 }
218 }
219
220 // verbose: syscall_printf ("reply received (%ld + %ld bytes)",
221 // sizeof (_header), msglen ());
222}
223
282113ba
CV
224#ifdef __OUTSIDE_CYGWIN__
225
226client_request_attach_tty::client_request_attach_tty ()
227 : client_request (CYGSERVER_REQUEST_ATTACH_TTY, &req, sizeof (req))
228{
229}
1c001dd2
CS
230
231/*
232 * client_request::handle_request ()
233 *
234 * A server-side method.
235 *
236 * This is a factory method for the client_request subclasses. It
237 * reads the incoming request header and, based on its request code,
238 * creates an instance of the appropriate class.
239 *
240 * FIXME: If the incoming packet is malformed, the server drops it on
241 * the floor. Should it try and generate some sort of reply for the
242 * client? As it is, the client will simply get a broken connection.
243 *
244 * FIXME: also check write and read result for -1.
245 */
246
247/* static */ void
248client_request::handle_request (transport_layer_base *const conn,
249 process_cache *const cache)
250{
251 // verbose: debug_printf ("about to read");
252
253 header_t header;
254
255 {
256 const ssize_t count = conn->read (&header, sizeof (header));
257
258 if (count != sizeof (header))
259 {
260 syscall_printf (("request header read failure: "
261 "only %ld bytes received of %ld, "
262 "error = %d(%lu)"),
263 count, sizeof (header),
264 errno, GetLastError ());
265 return;
266 }
267
268 // verbose: debug_printf ("got header (%ld)", count);
269 }
f449bfef 270
1c001dd2
CS
271 client_request *req = NULL;
272
273 switch (header.request_code)
f449bfef 274 {
1c001dd2 275 case CYGSERVER_REQUEST_GET_VERSION:
282113ba 276 req = new client_request_get_version;
1c001dd2
CS
277 break;
278 case CYGSERVER_REQUEST_SHUTDOWN:
282113ba 279 req = new client_request_shutdown;
1c001dd2
CS
280 break;
281 case CYGSERVER_REQUEST_ATTACH_TTY:
282113ba
CV
282 req = new client_request_attach_tty;
283 break;
284 case CYGSERVER_REQUEST_MSG:
285 req = new client_request_msg;
286 break;
287 case CYGSERVER_REQUEST_SEM:
288 req = new client_request_sem;
1c001dd2
CS
289 break;
290 case CYGSERVER_REQUEST_SHM:
282113ba 291 req = new client_request_shm;
1c001dd2 292 break;
d4db08d7
CV
293 case CYGSERVER_REQUEST_SETPWD:
294 req = new client_request_setpwd;
295 break;
1c001dd2
CS
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{
1c001dd2
CS
526 assert (cygserver_running == CYGSERVER_UNKNOWN \
527 || cygserver_running == CYGSERVER_OK \
528 || cygserver_running == CYGSERVER_UNAVAIL);
529
530 if (cygserver_running == CYGSERVER_OK)
f449bfef
RC
531 return;
532
1c001dd2
CS
533 if (!check_cygserver_available ())
534 cygserver_running = CYGSERVER_UNAVAIL;
f449bfef 535}
282113ba 536#endif /* __INSIDE_CYGWIN__ */
This page took 0.243805 seconds and 5 git commands to generate.