3 Written by Robert Collins <rbtcollins@hotmail.com>
5 This file is part of Cygwin.
7 This software is a copyrighted work licensed under the terms of the
8 Cygwin license. Please consult the file "CYGWIN_LICENSE" for
11 /* to allow this to link into cygwin and the .dll, a little magic is needed. */
12 #ifdef __OUTSIDE_CYGWIN__
19 #include <sys/types.h>
26 #include <sys/cygwin.h>
29 #include "transport.h"
30 #include "transport_pipes.h"
32 #ifndef __INSIDE_CYGWIN__
33 #include "cygserver.h"
34 #include "cygserver_ipc.h"
39 #ifdef __INSIDE_CYGWIN__
40 #define SET_ERRNO(err) set_errno (err)
42 #define SET_ERRNO(err) errno = (err)
47 MAX_WAIT_NAMED_PIPE_RETRY
= 64,
48 WAIT_NAMED_PIPE_TIMEOUT
= 10 // milliseconds
51 #ifndef __INSIDE_CYGWIN__
53 transport_layer_pipes::transport_layer_pipes (const HANDLE hPipe
)
55 _is_accepted_endpoint (true),
56 _is_listening_endpoint (false)
59 assert (_hPipe
!= INVALID_HANDLE_VALUE
);
60 _pipe_name
[0] = L
'\0';
63 #endif /* !__INSIDE_CYGWIN__ */
65 transport_layer_pipes::transport_layer_pipes ()
67 _is_accepted_endpoint (false),
68 _is_listening_endpoint (false)
70 wchar_t cyg_instkey
[18];
72 wchar_t *p
= wcpcpy (_pipe_name
, PIPE_NAME_PREFIX
);
73 if (!cygwin_internal (CW_GET_INSTKEY
, cyg_instkey
))
74 wcpcpy (wcpcpy (p
, cyg_instkey
), PIPE_NAME_SUFFIX
);
77 transport_layer_pipes::~transport_layer_pipes ()
82 #ifndef __INSIDE_CYGWIN__
84 static HANDLE listen_pipe
;
85 static HANDLE connect_pipe
;
88 transport_layer_pipes::listen ()
91 assert (!_is_accepted_endpoint
);
92 assert (!_is_listening_endpoint
);
94 _is_listening_endpoint
= true;
96 debug ("Try to create named pipe: %ls", _pipe_name
);
98 /* We have to create the first instance of the listening pipe here, and
99 we also have to create at least one instance of the client side to avoid
101 See https://cygwin.com/ml/cygwin/2012-11/threads.html#00144 */
103 CreateNamedPipeW (_pipe_name
,
104 PIPE_ACCESS_DUPLEX
| FILE_FLAG_FIRST_PIPE_INSTANCE
,
105 PIPE_TYPE_BYTE
| PIPE_WAIT
, PIPE_UNLIMITED_INSTANCES
,
106 0, 0, 1000, &sec_all_nih
);
107 if (listen_pipe
!= INVALID_HANDLE_VALUE
)
109 connect_pipe
= CreateFileW (_pipe_name
, GENERIC_READ
| GENERIC_WRITE
, 0,
110 &sec_all_nih
, OPEN_EXISTING
, 0, NULL
);
111 if (connect_pipe
== INVALID_HANDLE_VALUE
)
113 CloseHandle (listen_pipe
);
114 listen_pipe
= INVALID_HANDLE_VALUE
;
118 if (listen_pipe
== INVALID_HANDLE_VALUE
)
120 system_printf ("failed to create named pipe: "
121 "is the daemon already running?");
128 class transport_layer_pipes
*
129 transport_layer_pipes::accept (bool *const recoverable
)
132 assert (!_is_accepted_endpoint
);
133 assert (_is_listening_endpoint
);
135 debug ("Try to create named pipe instance: %ls", _pipe_name
);
137 const HANDLE accept_pipe
=
138 CreateNamedPipeW (_pipe_name
, PIPE_ACCESS_DUPLEX
,
139 PIPE_TYPE_BYTE
| PIPE_WAIT
, PIPE_UNLIMITED_INSTANCES
,
140 0, 0, 1000, &sec_all_nih
);
142 if (accept_pipe
== INVALID_HANDLE_VALUE
)
144 debug_printf ("error creating pipe (%u).", GetLastError ());
145 *recoverable
= true; // FIXME: case analysis?
149 if (!ConnectNamedPipe (accept_pipe
, NULL
)
150 && GetLastError () != ERROR_PIPE_CONNECTED
)
152 debug_printf ("error connecting to pipe (%u)", GetLastError ());
153 (void) CloseHandle (accept_pipe
);
154 *recoverable
= true; // FIXME: case analysis?
158 return new transport_layer_pipes (accept_pipe
);
161 #endif /* !__INSIDE_CYGWIN__ */
164 transport_layer_pipes::close ()
166 // verbose: debug_printf ("closing pipe %p", _hPipe);
170 assert (_hPipe
!= INVALID_HANDLE_VALUE
);
172 #ifndef __INSIDE_CYGWIN__
174 if (_is_accepted_endpoint
)
176 (void) FlushFileBuffers (_hPipe
); // Blocks until client reads.
177 (void) DisconnectNamedPipe (_hPipe
);
178 (void) CloseHandle (_hPipe
);
181 (void) CloseHandle (_hPipe
);
183 #else /* __INSIDE_CYGWIN__ */
185 assert (!_is_accepted_endpoint
);
186 (void) ForceCloseHandle (_hPipe
);
188 #endif /* __INSIDE_CYGWIN__ */
195 transport_layer_pipes::read (void *const buf
, const size_t len
)
197 // verbose: debug_printf ("reading from pipe %p", _hPipe);
200 assert (_hPipe
!= INVALID_HANDLE_VALUE
);
201 assert (!_is_listening_endpoint
);
204 if (!ReadFile (_hPipe
, buf
, len
, &count
, NULL
))
206 debug_printf ("error reading from pipe (%u)", GetLastError ());
207 SET_ERRNO (EINVAL
); // FIXME?
215 transport_layer_pipes::write (void *const buf
, const size_t len
)
217 // verbose: debug_printf ("writing to pipe %p", _hPipe);
220 assert (_hPipe
!= INVALID_HANDLE_VALUE
);
221 assert (!_is_listening_endpoint
);
224 if (!WriteFile (_hPipe
, buf
, len
, &count
, NULL
))
226 debug_printf ("error writing to pipe, error = %u", GetLastError ());
227 SET_ERRNO (EINVAL
); // FIXME?
235 * This routine holds a static variable, assume_cygserver, that is set
236 * if the transport has good reason to think that cygserver is
237 * running, i.e. if if successfully connected to it with the previous
238 * attempt. If this is set, the code tries a lot harder to get a
239 * connection, making the assumption that any failures are just
240 * congestion and overloading problems.
244 transport_layer_pipes::connect ()
247 assert (!_is_accepted_endpoint
);
248 assert (!_is_listening_endpoint
);
250 static bool assume_cygserver
= false;
255 debug_printf ("Try to connect to named pipe: %W", _pipe_name
);
258 _hPipe
= CreateFileW (_pipe_name
,
259 GENERIC_READ
| GENERIC_WRITE
,
260 FILE_SHARE_READ
| FILE_SHARE_WRITE
,
263 SECURITY_IMPERSONATION
,
266 if (_hPipe
!= INVALID_HANDLE_VALUE
)
269 #ifdef __INSIDE_CYGWIN__
270 ProtectHandle (_hPipe
);
272 assume_cygserver
= true;
278 if (!assume_cygserver
&& GetLastError () != ERROR_PIPE_BUSY
)
280 debug_printf ("Error opening the pipe (%u)", GetLastError ());
284 /* Note: `If no instances of the specified named pipe exist, the
285 * WaitNamedPipe function returns immediately, regardless of the
286 * time-out value.' Thus the explicit Sleep if the call fails
287 * with ERROR_FILE_NOT_FOUND.
289 while (retries
!= MAX_WAIT_NAMED_PIPE_RETRY
290 && !(rc
= WaitNamedPipeW (_pipe_name
, WAIT_NAMED_PIPE_TIMEOUT
)))
292 if (GetLastError () == ERROR_FILE_NOT_FOUND
)
293 Sleep (0); // Give the server a chance.
299 assert (retries
== MAX_WAIT_NAMED_PIPE_RETRY
);
301 system_printf ("lost connection to cygserver, error = %u",
304 assume_cygserver
= false;
309 #ifndef __INSIDE_CYGWIN__
312 transport_layer_pipes::impersonate_client ()
315 assert (_hPipe
!= INVALID_HANDLE_VALUE
);
316 assert (_is_accepted_endpoint
);
318 if (_hPipe
&& !ImpersonateNamedPipeClient (_hPipe
))
320 debug_printf ("Failed to Impersonate client, (%u)", GetLastError ());
328 transport_layer_pipes::revert_to_self ()
330 assert (_is_accepted_endpoint
);
332 if (!RevertToSelf ())
334 debug_printf ("Failed to RevertToSelf, (%u)", GetLastError ());
340 #endif /* !__INSIDE_CYGWIN__ */