]> sourceware.org Git - newlib-cygwin.git/blame - winsup/cygserver/transport_pipes.cc
* transport_pipes.cc: Include ntdef.h to accommodate cygerrno.h.
[newlib-cygwin.git] / winsup / cygserver / transport_pipes.cc
CommitLineData
282113ba 1/* transport_pipes.cc
f449bfef 2
b079a89e 3 Copyright 2001, 2002, 2003, 2004, 2009 Red Hat Inc.
f449bfef
RC
4
5 Written by Robert Collins <rbtcollins@hotmail.com>
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. */
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"
c0f1ded4 16#include <ntdef.h>
1c001dd2
CS
17#else
18#include "winsup.h"
19#endif
f449bfef 20
f449bfef 21#include <sys/types.h>
1c001dd2
CS
22
23#include <assert.h>
f449bfef 24#include <netdb.h>
1c001dd2
CS
25#include <pthread.h>
26#include <unistd.h>
b079a89e
CV
27#include <wchar.h>
28#include <sys/cygwin.h>
1c001dd2
CS
29
30#include "cygerrno.h"
282113ba
CV
31#include "transport.h"
32#include "transport_pipes.h"
f449bfef 33
1c001dd2 34#ifndef __INSIDE_CYGWIN__
56797078 35#include "cygserver.h"
282113ba
CV
36#include "cygserver_ipc.h"
37#else
38#include "security.h"
f449bfef
RC
39#endif
40
1dcd520b
CV
41#ifdef __INSIDE_CYGWIN__
42#define SET_ERRNO(err) set_errno (err)
43#else
44#define SET_ERRNO(err) errno = (err)
45#endif
46
1c001dd2
CS
47enum
48 {
49 MAX_WAIT_NAMED_PIPE_RETRY = 64,
50 WAIT_NAMED_PIPE_TIMEOUT = 10 // milliseconds
51 };
52
53#ifndef __INSIDE_CYGWIN__
54
55static pthread_once_t pipe_instance_lock_once = PTHREAD_ONCE_INIT;
56static CRITICAL_SECTION pipe_instance_lock;
57static long pipe_instance = 0;
58
59static void
60initialise_pipe_instance_lock ()
61{
62 assert (pipe_instance == 0);
63 InitializeCriticalSection (&pipe_instance_lock);
64}
65
66#endif /* !__INSIDE_CYGWIN__ */
67
68#ifndef __INSIDE_CYGWIN__
241a7c5a 69
1c001dd2 70transport_layer_pipes::transport_layer_pipes (const HANDLE hPipe)
b079a89e 71 : _hPipe (hPipe),
1c001dd2
CS
72 _is_accepted_endpoint (true),
73 _is_listening_endpoint (false)
f449bfef 74{
1c001dd2
CS
75 assert (_hPipe);
76 assert (_hPipe != INVALID_HANDLE_VALUE);
b079a89e 77 _pipe_name[0] = L'\0';
1c001dd2
CS
78}
79
80#endif /* !__INSIDE_CYGWIN__ */
f449bfef 81
73ea29f4 82transport_layer_pipes::transport_layer_pipes ()
b079a89e 83 : _hPipe (NULL),
1c001dd2
CS
84 _is_accepted_endpoint (false),
85 _is_listening_endpoint (false)
f449bfef 86{
b079a89e
CV
87#ifdef __INSIDE_CYGWIN__
88 extern WCHAR installation_key_buf[18];
89 wcpcpy (wcpcpy (wcpcpy (_pipe_name, PIPE_NAME_PREFIX), installation_key_buf),
90 PIPE_NAME_SUFFIX);
91#else
92 wchar_t cyg_instkey[18];
93
94 wchar_t *p = wcpcpy (_pipe_name, PIPE_NAME_PREFIX);
1636ce3b 95 if (!cygwin_internal (CW_GET_INSTKEY, cyg_instkey))
b079a89e
CV
96 wcpcpy (wcpcpy (p, cyg_instkey), PIPE_NAME_SUFFIX);
97#endif
f449bfef
RC
98}
99
1c001dd2
CS
100transport_layer_pipes::~transport_layer_pipes ()
101{
102 close ();
103}
104
105#ifndef __INSIDE_CYGWIN__
106
107int
f449bfef
RC
108transport_layer_pipes::listen ()
109{
1c001dd2
CS
110 assert (!_hPipe);
111 assert (!_is_accepted_endpoint);
112 assert (!_is_listening_endpoint);
113
114 _is_listening_endpoint = true;
115
f449bfef 116 /* no-op */
1c001dd2 117 return 0;
f449bfef
RC
118}
119
120class transport_layer_pipes *
1c001dd2 121transport_layer_pipes::accept (bool *const recoverable)
f449bfef 122{
1c001dd2
CS
123 assert (!_hPipe);
124 assert (!_is_accepted_endpoint);
125 assert (_is_listening_endpoint);
126
127 pthread_once (&pipe_instance_lock_once, &initialise_pipe_instance_lock);
128
129 EnterCriticalSection (&pipe_instance_lock);
130
131 // Read: http://www.securityinternals.com/research/papers/namedpipe.php
132 // See also the Microsoft security bulletins MS00-053 and MS01-031.
133
134 // FIXME: Remove FILE_CREATE_PIPE_INSTANCE.
135
136 const bool first_instance = (pipe_instance == 0);
137
1636ce3b
CV
138 debug ("Try to create named pipe: %ls", _pipe_name);
139
1c001dd2 140 const HANDLE accept_pipe =
b079a89e 141 CreateNamedPipeW (_pipe_name,
1c001dd2
CS
142 (PIPE_ACCESS_DUPLEX
143 | (first_instance ? FILE_FLAG_FIRST_PIPE_INSTANCE : 0)),
144 (PIPE_TYPE_BYTE | PIPE_WAIT),
145 PIPE_UNLIMITED_INSTANCES,
146 0, 0, 1000,
282113ba 147 &sec_all_nih);
1c001dd2
CS
148
149 const bool duplicate = (accept_pipe == INVALID_HANDLE_VALUE
150 && pipe_instance == 0
151 && GetLastError () == ERROR_ACCESS_DENIED);
152
153 if (accept_pipe != INVALID_HANDLE_VALUE)
154 InterlockedIncrement (&pipe_instance);
155
156 LeaveCriticalSection (&pipe_instance_lock);
157
158 if (duplicate)
f449bfef 159 {
1c001dd2
CS
160 *recoverable = false;
161 system_printf ("failed to create named pipe: "
162 "is the daemon already running?");
f449bfef
RC
163 return NULL;
164 }
165
1c001dd2 166 if (accept_pipe == INVALID_HANDLE_VALUE)
f449bfef 167 {
1c001dd2
CS
168 debug_printf ("error creating pipe (%lu).", GetLastError ());
169 *recoverable = true; // FIXME: case analysis?
f449bfef
RC
170 return NULL;
171 }
172
1c001dd2
CS
173 assert (accept_pipe);
174
175 if (!ConnectNamedPipe (accept_pipe, NULL)
176 && GetLastError () != ERROR_PIPE_CONNECTED)
f449bfef 177 {
18be975d 178 debug_printf ("error connecting to pipe (%lu)", GetLastError ());
1c001dd2
CS
179 (void) CloseHandle (accept_pipe);
180 *recoverable = true; // FIXME: case analysis?
f449bfef
RC
181 return NULL;
182 }
73ea29f4 183
282113ba 184 return new transport_layer_pipes (accept_pipe);
f449bfef
RC
185}
186
1c001dd2
CS
187#endif /* !__INSIDE_CYGWIN__ */
188
f449bfef 189void
1c001dd2 190transport_layer_pipes::close ()
f449bfef 191{
1c001dd2
CS
192 // verbose: debug_printf ("closing pipe %p", _hPipe);
193
194 if (_hPipe)
f449bfef 195 {
1c001dd2
CS
196 assert (_hPipe != INVALID_HANDLE_VALUE);
197
198#ifndef __INSIDE_CYGWIN__
199
200 if (_is_accepted_endpoint)
201 {
202 (void) FlushFileBuffers (_hPipe); // Blocks until client reads.
203 (void) DisconnectNamedPipe (_hPipe);
204 EnterCriticalSection (&pipe_instance_lock);
205 (void) CloseHandle (_hPipe);
206 assert (pipe_instance > 0);
207 InterlockedDecrement (&pipe_instance);
208 LeaveCriticalSection (&pipe_instance_lock);
209 }
210 else
211 (void) CloseHandle (_hPipe);
212
213#else /* __INSIDE_CYGWIN__ */
214
215 assert (!_is_accepted_endpoint);
216 (void) ForceCloseHandle (_hPipe);
217
218#endif /* __INSIDE_CYGWIN__ */
219
220 _hPipe = NULL;
f449bfef
RC
221 }
222}
223
224ssize_t
1c001dd2 225transport_layer_pipes::read (void *const buf, const size_t len)
f449bfef 226{
1c001dd2 227 // verbose: debug_printf ("reading from pipe %p", _hPipe);
f449bfef 228
1c001dd2
CS
229 assert (_hPipe);
230 assert (_hPipe != INVALID_HANDLE_VALUE);
231 assert (!_is_listening_endpoint);
232
233 DWORD count;
234 if (!ReadFile (_hPipe, buf, len, &count, NULL))
f449bfef 235 {
1c001dd2 236 debug_printf ("error reading from pipe (%lu)", GetLastError ());
1dcd520b 237 SET_ERRNO (EINVAL); // FIXME?
f449bfef
RC
238 return -1;
239 }
1c001dd2
CS
240
241 return count;
f449bfef
RC
242}
243
244ssize_t
1c001dd2 245transport_layer_pipes::write (void *const buf, const size_t len)
f449bfef 246{
1c001dd2 247 // verbose: debug_printf ("writing to pipe %p", _hPipe);
f449bfef 248
1c001dd2
CS
249 assert (_hPipe);
250 assert (_hPipe != INVALID_HANDLE_VALUE);
251 assert (!_is_listening_endpoint);
252
253 DWORD count;
254 if (!WriteFile (_hPipe, buf, len, &count, NULL))
f449bfef 255 {
1c001dd2 256 debug_printf ("error writing to pipe, error = %lu", GetLastError ());
1dcd520b 257 SET_ERRNO (EINVAL); // FIXME?
f449bfef
RC
258 return -1;
259 }
1c001dd2
CS
260
261 return count;
f449bfef
RC
262}
263
1c001dd2
CS
264/*
265 * This routine holds a static variable, assume_cygserver, that is set
266 * if the transport has good reason to think that cygserver is
267 * running, i.e. if if successfully connected to it with the previous
268 * attempt. If this is set, the code tries a lot harder to get a
269 * connection, making the assumption that any failures are just
270 * congestion and overloading problems.
271 */
272
273int
f449bfef
RC
274transport_layer_pipes::connect ()
275{
1c001dd2
CS
276 assert (!_hPipe);
277 assert (!_is_accepted_endpoint);
278 assert (!_is_listening_endpoint);
f449bfef 279
1c001dd2
CS
280 static bool assume_cygserver = false;
281
282 BOOL rc = TRUE;
283 int retries = 0;
284
1636ce3b 285 debug_printf ("Try to connect to named pipe: %W", _pipe_name);
1c001dd2 286 while (rc)
f449bfef 287 {
b079a89e
CV
288 _hPipe = CreateFileW (_pipe_name,
289 GENERIC_READ | GENERIC_WRITE,
290 FILE_SHARE_READ | FILE_SHARE_WRITE,
291 &sec_all_nih,
292 OPEN_EXISTING,
293 SECURITY_IMPERSONATION,
294 NULL);
1c001dd2
CS
295
296 if (_hPipe != INVALID_HANDLE_VALUE)
297 {
298 assert (_hPipe);
299#ifdef __INSIDE_CYGWIN__
300 ProtectHandle (_hPipe);
301#endif
302 assume_cygserver = true;
303 return 0;
304 }
305
306 _hPipe = NULL;
307
308 if (!assume_cygserver && GetLastError () != ERROR_PIPE_BUSY)
73ea29f4 309 {
1c001dd2
CS
310 debug_printf ("Error opening the pipe (%lu)", GetLastError ());
311 return -1;
73ea29f4 312 }
1c001dd2
CS
313
314 /* Note: `If no instances of the specified named pipe exist, the
315 * WaitNamedPipe function returns immediately, regardless of the
316 * time-out value.' Thus the explicit Sleep if the call fails
317 * with ERROR_FILE_NOT_FOUND.
73ea29f4 318 */
1c001dd2 319 while (retries != MAX_WAIT_NAMED_PIPE_RETRY
b079a89e 320 && !(rc = WaitNamedPipeW (_pipe_name, WAIT_NAMED_PIPE_TIMEOUT)))
1c001dd2
CS
321 {
322 if (GetLastError () == ERROR_FILE_NOT_FOUND)
323 Sleep (0); // Give the server a chance.
324
325 retries += 1;
326 }
f449bfef 327 }
1c001dd2
CS
328
329 assert (retries == MAX_WAIT_NAMED_PIPE_RETRY);
330
331 system_printf ("lost connection to cygserver, error = %lu",
332 GetLastError ());
333
334 assume_cygserver = false;
335
336 return -1;
f449bfef
RC
337}
338
1c001dd2
CS
339#ifndef __INSIDE_CYGWIN__
340
282113ba 341bool
f449bfef
RC
342transport_layer_pipes::impersonate_client ()
343{
1c001dd2
CS
344 assert (_hPipe);
345 assert (_hPipe != INVALID_HANDLE_VALUE);
346 assert (_is_accepted_endpoint);
347
282113ba 348 if (_hPipe && !ImpersonateNamedPipeClient (_hPipe))
f449bfef 349 {
282113ba
CV
350 debug_printf ("Failed to Impersonate client, (%lu)", GetLastError ());
351 return false;
f449bfef 352 }
282113ba
CV
353
354 return true;
f449bfef
RC
355}
356
282113ba 357bool
f449bfef
RC
358transport_layer_pipes::revert_to_self ()
359{
1c001dd2
CS
360 assert (_is_accepted_endpoint);
361
282113ba
CV
362 if (!RevertToSelf ())
363 {
364 debug_printf ("Failed to RevertToSelf, (%lu)", GetLastError ());
365 return false;
366 }
367 return true;
f449bfef
RC
368}
369
1c001dd2 370#endif /* !__INSIDE_CYGWIN__ */
This page took 0.188372 seconds and 5 git commands to generate.