OSDN Git Service

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