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