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