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