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