3 Copyright 2001, 2002, 2003, 2004 Red Hat Inc.
5 Written by Robert Collins <rbtcollins@hotmail.com>
7 This file is part of Cygwin.
9 This software is a copyrighted work licensed under the terms of the
10 Cygwin license. Please consult the file "CYGWIN_LICENSE" for
13 /* to allow this to link into cygwin and the .dll, a little magic is needed. */
14 #ifdef __OUTSIDE_CYGWIN__
20 #include <sys/types.h>
28 #include "transport.h"
29 #include "transport_pipes.h"
31 #ifndef __INSIDE_CYGWIN__
32 #include "cygserver.h"
33 #include "cygserver_ipc.h"
38 #ifdef __INSIDE_CYGWIN__
39 #define SET_ERRNO(err) set_errno (err)
41 #define SET_ERRNO(err) errno = (err)
46 MAX_WAIT_NAMED_PIPE_RETRY
= 64,
47 WAIT_NAMED_PIPE_TIMEOUT
= 10 // milliseconds
50 #ifndef __INSIDE_CYGWIN__
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;
57 initialise_pipe_instance_lock ()
59 assert (pipe_instance
== 0);
60 InitializeCriticalSection (&pipe_instance_lock
);
63 #endif /* !__INSIDE_CYGWIN__ */
65 #ifndef __INSIDE_CYGWIN__
67 transport_layer_pipes::transport_layer_pipes (const HANDLE hPipe
)
70 _is_accepted_endpoint (true),
71 _is_listening_endpoint (false)
74 assert (_hPipe
!= INVALID_HANDLE_VALUE
);
78 #endif /* !__INSIDE_CYGWIN__ */
80 transport_layer_pipes::transport_layer_pipes ()
81 : _pipe_name ("\\\\.\\pipe\\cygwin_lpc"),
83 _is_accepted_endpoint (false),
84 _is_listening_endpoint (false)
88 transport_layer_pipes::~transport_layer_pipes ()
93 #ifndef __INSIDE_CYGWIN__
96 transport_layer_pipes::listen ()
99 assert (!_is_accepted_endpoint
);
100 assert (!_is_listening_endpoint
);
102 _is_listening_endpoint
= true;
108 class transport_layer_pipes
*
109 transport_layer_pipes::accept (bool *const recoverable
)
112 assert (!_is_accepted_endpoint
);
113 assert (_is_listening_endpoint
);
115 pthread_once (&pipe_instance_lock_once
, &initialise_pipe_instance_lock
);
117 EnterCriticalSection (&pipe_instance_lock
);
119 // Read: http://www.securityinternals.com/research/papers/namedpipe.php
120 // See also the Microsoft security bulletins MS00-053 and MS01-031.
122 // FIXME: Remove FILE_CREATE_PIPE_INSTANCE.
124 const bool first_instance
= (pipe_instance
== 0);
126 const HANDLE accept_pipe
=
127 CreateNamedPipe (_pipe_name
,
129 | (first_instance
? FILE_FLAG_FIRST_PIPE_INSTANCE
: 0)),
130 (PIPE_TYPE_BYTE
| PIPE_WAIT
),
131 PIPE_UNLIMITED_INSTANCES
,
135 const bool duplicate
= (accept_pipe
== INVALID_HANDLE_VALUE
136 && pipe_instance
== 0
137 && GetLastError () == ERROR_ACCESS_DENIED
);
139 if (accept_pipe
!= INVALID_HANDLE_VALUE
)
140 InterlockedIncrement (&pipe_instance
);
142 LeaveCriticalSection (&pipe_instance_lock
);
146 *recoverable
= false;
147 system_printf ("failed to create named pipe: "
148 "is the daemon already running?");
152 if (accept_pipe
== INVALID_HANDLE_VALUE
)
154 debug_printf ("error creating pipe (%lu).", GetLastError ());
155 *recoverable
= true; // FIXME: case analysis?
159 assert (accept_pipe
);
161 if (!ConnectNamedPipe (accept_pipe
, NULL
)
162 && GetLastError () != ERROR_PIPE_CONNECTED
)
164 debug_printf ("error connecting to pipe (%lu)", GetLastError ());
165 (void) CloseHandle (accept_pipe
);
166 *recoverable
= true; // FIXME: case analysis?
170 return new transport_layer_pipes (accept_pipe
);
173 #endif /* !__INSIDE_CYGWIN__ */
176 transport_layer_pipes::close ()
178 // verbose: debug_printf ("closing pipe %p", _hPipe);
182 assert (_hPipe
!= INVALID_HANDLE_VALUE
);
184 #ifndef __INSIDE_CYGWIN__
186 if (_is_accepted_endpoint
)
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
);
197 (void) CloseHandle (_hPipe
);
199 #else /* __INSIDE_CYGWIN__ */
201 assert (!_is_accepted_endpoint
);
202 (void) ForceCloseHandle (_hPipe
);
204 #endif /* __INSIDE_CYGWIN__ */
211 transport_layer_pipes::read (void *const buf
, const size_t len
)
213 // verbose: debug_printf ("reading from pipe %p", _hPipe);
216 assert (_hPipe
!= INVALID_HANDLE_VALUE
);
217 assert (!_is_listening_endpoint
);
220 if (!ReadFile (_hPipe
, buf
, len
, &count
, NULL
))
222 debug_printf ("error reading from pipe (%lu)", GetLastError ());
223 SET_ERRNO (EINVAL
); // FIXME?
231 transport_layer_pipes::write (void *const buf
, const size_t len
)
233 // verbose: debug_printf ("writing to pipe %p", _hPipe);
236 assert (_hPipe
!= INVALID_HANDLE_VALUE
);
237 assert (!_is_listening_endpoint
);
240 if (!WriteFile (_hPipe
, buf
, len
, &count
, NULL
))
242 debug_printf ("error writing to pipe, error = %lu", GetLastError ());
243 SET_ERRNO (EINVAL
); // FIXME?
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.
260 transport_layer_pipes::connect ()
263 assert (!_is_accepted_endpoint
);
264 assert (!_is_listening_endpoint
);
266 static bool assume_cygserver
= false;
273 _hPipe
= CreateFile (_pipe_name
,
274 GENERIC_READ
| GENERIC_WRITE
,
275 FILE_SHARE_READ
| FILE_SHARE_WRITE
,
278 SECURITY_IMPERSONATION
,
281 if (_hPipe
!= INVALID_HANDLE_VALUE
)
284 #ifdef __INSIDE_CYGWIN__
285 ProtectHandle (_hPipe
);
287 assume_cygserver
= true;
293 if (!assume_cygserver
&& GetLastError () != ERROR_PIPE_BUSY
)
295 debug_printf ("Error opening the pipe (%lu)", GetLastError ());
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.
304 while (retries
!= MAX_WAIT_NAMED_PIPE_RETRY
305 && !(rc
= WaitNamedPipe (_pipe_name
, WAIT_NAMED_PIPE_TIMEOUT
)))
307 if (GetLastError () == ERROR_FILE_NOT_FOUND
)
308 Sleep (0); // Give the server a chance.
314 assert (retries
== MAX_WAIT_NAMED_PIPE_RETRY
);
316 system_printf ("lost connection to cygserver, error = %lu",
319 assume_cygserver
= false;
324 #ifndef __INSIDE_CYGWIN__
327 transport_layer_pipes::impersonate_client ()
330 assert (_hPipe
!= INVALID_HANDLE_VALUE
);
331 assert (_is_accepted_endpoint
);
333 if (_hPipe
&& !ImpersonateNamedPipeClient (_hPipe
))
335 debug_printf ("Failed to Impersonate client, (%lu)", GetLastError ());
343 transport_layer_pipes::revert_to_self ()
345 assert (_is_accepted_endpoint
);
347 if (!RevertToSelf ())
349 debug_printf ("Failed to RevertToSelf, (%lu)", GetLastError ());
355 #endif /* !__INSIDE_CYGWIN__ */