]> sourceware.org Git - newlib-cygwin.git/blob - winsup/cygserver/transport_pipes.cc
Remove dependency from Cygwin internal code.
[newlib-cygwin.git] / winsup / cygserver / transport_pipes.cc
1 /* transport_pipes.cc
2
3 Copyright 2001, 2002, 2003, 2004 Red Hat Inc.
4
5 Written by Robert Collins <rbtcollins@hotmail.com>
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 <sys/types.h>
21
22 #include <assert.h>
23 #include <netdb.h>
24 #include <pthread.h>
25 #include <unistd.h>
26
27 #include "cygerrno.h"
28 #include "transport.h"
29 #include "transport_pipes.h"
30
31 #ifndef __INSIDE_CYGWIN__
32 #include "cygserver.h"
33 #include "cygserver_ipc.h"
34 #else
35 #include "security.h"
36 #endif
37
38 #ifdef __INSIDE_CYGWIN__
39 #define SET_ERRNO(err) set_errno (err)
40 #else
41 #define SET_ERRNO(err) errno = (err)
42 #endif
43
44 enum
45 {
46 MAX_WAIT_NAMED_PIPE_RETRY = 64,
47 WAIT_NAMED_PIPE_TIMEOUT = 10 // milliseconds
48 };
49
50 #ifndef __INSIDE_CYGWIN__
51
52 static pthread_once_t pipe_instance_lock_once = PTHREAD_ONCE_INIT;
53 static CRITICAL_SECTION pipe_instance_lock;
54 static long pipe_instance = 0;
55
56 static void
57 initialise_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__
66
67 transport_layer_pipes::transport_layer_pipes (const HANDLE hPipe)
68 : _pipe_name (""),
69 _hPipe (hPipe),
70 _is_accepted_endpoint (true),
71 _is_listening_endpoint (false)
72 {
73 assert (_hPipe);
74 assert (_hPipe != INVALID_HANDLE_VALUE);
75
76 }
77
78 #endif /* !__INSIDE_CYGWIN__ */
79
80 transport_layer_pipes::transport_layer_pipes ()
81 : _pipe_name ("\\\\.\\pipe\\cygwin_lpc"),
82 _hPipe (NULL),
83 _is_accepted_endpoint (false),
84 _is_listening_endpoint (false)
85 {
86 }
87
88 transport_layer_pipes::~transport_layer_pipes ()
89 {
90 close ();
91 }
92
93 #ifndef __INSIDE_CYGWIN__
94
95 int
96 transport_layer_pipes::listen ()
97 {
98 assert (!_hPipe);
99 assert (!_is_accepted_endpoint);
100 assert (!_is_listening_endpoint);
101
102 _is_listening_endpoint = true;
103
104 /* no-op */
105 return 0;
106 }
107
108 class transport_layer_pipes *
109 transport_layer_pipes::accept (bool *const recoverable)
110 {
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,
133 &sec_all_nih);
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)
145 {
146 *recoverable = false;
147 system_printf ("failed to create named pipe: "
148 "is the daemon already running?");
149 return NULL;
150 }
151
152 if (accept_pipe == INVALID_HANDLE_VALUE)
153 {
154 debug_printf ("error creating pipe (%lu).", GetLastError ());
155 *recoverable = true; // FIXME: case analysis?
156 return NULL;
157 }
158
159 assert (accept_pipe);
160
161 if (!ConnectNamedPipe (accept_pipe, NULL)
162 && GetLastError () != ERROR_PIPE_CONNECTED)
163 {
164 debug_printf ("error connecting to pipe (%lu)", GetLastError ());
165 (void) CloseHandle (accept_pipe);
166 *recoverable = true; // FIXME: case analysis?
167 return NULL;
168 }
169
170 return new transport_layer_pipes (accept_pipe);
171 }
172
173 #endif /* !__INSIDE_CYGWIN__ */
174
175 void
176 transport_layer_pipes::close ()
177 {
178 // verbose: debug_printf ("closing pipe %p", _hPipe);
179
180 if (_hPipe)
181 {
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;
207 }
208 }
209
210 ssize_t
211 transport_layer_pipes::read (void *const buf, const size_t len)
212 {
213 // verbose: debug_printf ("reading from pipe %p", _hPipe);
214
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))
221 {
222 debug_printf ("error reading from pipe (%lu)", GetLastError ());
223 SET_ERRNO (EINVAL); // FIXME?
224 return -1;
225 }
226
227 return count;
228 }
229
230 ssize_t
231 transport_layer_pipes::write (void *const buf, const size_t len)
232 {
233 // verbose: debug_printf ("writing to pipe %p", _hPipe);
234
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))
241 {
242 debug_printf ("error writing to pipe, error = %lu", GetLastError ());
243 SET_ERRNO (EINVAL); // FIXME?
244 return -1;
245 }
246
247 return count;
248 }
249
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
259 int
260 transport_layer_pipes::connect ()
261 {
262 assert (!_hPipe);
263 assert (!_is_accepted_endpoint);
264 assert (!_is_listening_endpoint);
265
266 static bool assume_cygserver = false;
267
268 BOOL rc = TRUE;
269 int retries = 0;
270
271 while (rc)
272 {
273 _hPipe = CreateFile (_pipe_name,
274 GENERIC_READ | GENERIC_WRITE,
275 FILE_SHARE_READ | FILE_SHARE_WRITE,
276 &sec_all_nih,
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)
294 {
295 debug_printf ("Error opening the pipe (%lu)", GetLastError ());
296 return -1;
297 }
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.
303 */
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 }
312 }
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;
322 }
323
324 #ifndef __INSIDE_CYGWIN__
325
326 bool
327 transport_layer_pipes::impersonate_client ()
328 {
329 assert (_hPipe);
330 assert (_hPipe != INVALID_HANDLE_VALUE);
331 assert (_is_accepted_endpoint);
332
333 if (_hPipe && !ImpersonateNamedPipeClient (_hPipe))
334 {
335 debug_printf ("Failed to Impersonate client, (%lu)", GetLastError ());
336 return false;
337 }
338
339 return true;
340 }
341
342 bool
343 transport_layer_pipes::revert_to_self ()
344 {
345 assert (_is_accepted_endpoint);
346
347 if (!RevertToSelf ())
348 {
349 debug_printf ("Failed to RevertToSelf, (%lu)", GetLastError ());
350 return false;
351 }
352 return true;
353 }
354
355 #endif /* !__INSIDE_CYGWIN__ */
This page took 0.048538 seconds and 5 git commands to generate.