5 // Atsushi Enomoto <atsushi@ximian.com>
7 // Copyright (C) 2009 Novell, Inc. http://www.novell.com
9 // Permission is hereby granted, free of charge, to any person obtaining
10 // a copy of this software and associated documentation files (the
11 // "Software"), to deal in the Software without restriction, including
12 // without limitation the rights to use, copy, modify, merge, publish,
13 // distribute, sublicense, and/or sell copies of the Software, and to
14 // permit persons to whom the Software is furnished to do so, subject to
15 // the following conditions:
17 // The above copyright notice and this permission notice shall be
18 // included in all copies or substantial portions of the Software.
20 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
21 // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
22 // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
23 // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
24 // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
25 // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
26 // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
32 using System.ComponentModel;
35 using System.Runtime.InteropServices;
36 using System.Security.AccessControl;
37 using System.Security.Permissions;
38 using System.Security.Principal;
40 using Microsoft.Win32;
41 using Microsoft.Win32.SafeHandles;
43 namespace System.IO.Pipes
45 static class Win32PipeError
47 public static Exception GetException ()
49 return GetException (Marshal.GetLastWin32Error ());
52 public static Exception GetException (int errorCode)
55 case 5: return new UnauthorizedAccessException ();
56 default: return new Win32Exception (errorCode);
61 abstract class Win32AnonymousPipe : IPipe
63 protected Win32AnonymousPipe ()
67 public abstract SafePipeHandle Handle { get; }
69 public void WaitForPipeDrain ()
71 throw new NotImplementedException ();
75 class Win32AnonymousPipeClient : Win32AnonymousPipe, IAnonymousPipeClient
77 // AnonymousPipeClientStream owner;
79 public Win32AnonymousPipeClient (AnonymousPipeClientStream owner, SafePipeHandle handle)
81 // this.owner = owner;
86 SafePipeHandle handle;
88 public override SafePipeHandle Handle {
89 get { return handle; }
93 class Win32AnonymousPipeServer : Win32AnonymousPipe, IAnonymousPipeServer
95 // AnonymousPipeServerStream owner;
97 public unsafe Win32AnonymousPipeServer (AnonymousPipeServerStream owner, PipeDirection direction,
98 HandleInheritability inheritability, int bufferSize,
99 PipeSecurity pipeSecurity)
103 byte[] securityDescriptor = null;
104 if (pipeSecurity != null)
105 securityDescriptor = pipeSecurity.GetSecurityDescriptorBinaryForm ();
107 fixed (byte* securityDescriptorPtr = securityDescriptor) {
108 SecurityAttributes att = new SecurityAttributes (inheritability, (IntPtr)securityDescriptorPtr);
109 if (!Win32Marshal.CreatePipe (out r, out w, ref att, bufferSize))
110 throw Win32PipeError.GetException ();
113 var rh = new SafePipeHandle (r, true);
114 var wh = new SafePipeHandle (w, true);
116 if (direction == PipeDirection.Out) {
125 public Win32AnonymousPipeServer (AnonymousPipeServerStream owner, SafePipeHandle serverHandle, SafePipeHandle clientHandle)
127 // this.owner = owner;
128 this.server_handle = serverHandle;
129 this.client_handle = clientHandle;
132 SafePipeHandle server_handle, client_handle;
134 public override SafePipeHandle Handle {
135 get { return server_handle; }
138 public SafePipeHandle ClientHandle {
139 get { return client_handle; }
142 public void DisposeLocalCopyOfClientHandle ()
144 throw new NotImplementedException ();
148 abstract class Win32NamedPipe : IPipe
154 if (name_cache != null)
158 byte [] un = new byte [200];
160 if (!Win32Marshal.GetNamedPipeHandleState (Handle, out s, out c, out m, out t, un, un.Length))
161 throw Win32PipeError.GetException ();
163 if (un [un.Length - 1] == 0)
165 un = new byte [un.Length * 10];
167 name_cache = Encoding.Default.GetString (un);
172 public abstract SafePipeHandle Handle { get; }
174 public void WaitForPipeDrain ()
176 throw new NotImplementedException ();
180 class Win32NamedPipeClient : Win32NamedPipe, INamedPipeClient
182 NamedPipeClientStream owner;
184 // .ctor with existing handle
185 public Win32NamedPipeClient (NamedPipeClientStream owner, SafePipeHandle safePipeHandle)
187 this.handle = safePipeHandle;
190 // FIXME: retrieve is_async from state?
193 // .ctor without handle - create new
194 public Win32NamedPipeClient (NamedPipeClientStream owner, string serverName, string pipeName,
195 PipeAccessRights desiredAccessRights, PipeOptions options,
196 HandleInheritability inheritability)
198 name = String.Format ("\\\\{0}\\pipe\\{1}", serverName, pipeName);
199 var att = new SecurityAttributes (inheritability, IntPtr.Zero);
200 is_async = (options & PipeOptions.Asynchronous) != PipeOptions.None;
203 var ret = Win32Marshal.CreateFile (name, desiredAccessRights, 0, ref att, 3, 0, IntPtr.Zero);
204 if (ret == new IntPtr (-1L))
205 throw Win32PipeError.GetException ();
207 return new SafePipeHandle (ret, true);
212 Func<SafePipeHandle> opener;
215 SafePipeHandle handle;
217 public override SafePipeHandle Handle {
218 get { return handle; }
221 public bool IsAsync {
222 get { return is_async; }
225 public void Connect ()
227 if (owner.IsConnected)
228 throw new InvalidOperationException ("The named pipe is already connected");
233 public void Connect (int timeout)
235 if (owner.IsConnected)
236 throw new InvalidOperationException ("The named pipe is already connected");
238 if (!Win32Marshal.WaitNamedPipe (name, timeout))
239 throw Win32PipeError.GetException ();
243 public int NumberOfServerInstances {
247 if (!Win32Marshal.GetNamedPipeHandleState (Handle, out s, out c, out m, out t, un, 0))
248 throw Win32PipeError.GetException ();
254 class Win32NamedPipeServer : Win32NamedPipe, INamedPipeServer
256 //NamedPipeServerStream owner;
258 // .ctor with existing handle
259 public Win32NamedPipeServer (NamedPipeServerStream owner, SafePipeHandle safePipeHandle)
261 handle = safePipeHandle;
262 //this.owner = owner;
265 // .ctor without handle - create new
266 public unsafe Win32NamedPipeServer (NamedPipeServerStream owner, string pipeName, int maxNumberOfServerInstances,
267 PipeTransmissionMode transmissionMode, PipeAccessRights rights,
268 PipeOptions options, int inBufferSize, int outBufferSize,
269 PipeSecurity pipeSecurity, HandleInheritability inheritability)
271 string name = String.Format ("\\\\.\\pipe\\{0}", pipeName);
274 openMode = (uint)rights | (uint)options; // Enum values match Win32 flags exactly.
277 if ((owner.TransmissionMode & PipeTransmissionMode.Message) != 0)
279 //if ((readTransmissionMode & PipeTransmissionMode.Message) != 0)
281 if ((options & PipeOptions.Asynchronous) != 0)
284 byte[] securityDescriptor = null;
285 if (pipeSecurity != null)
286 securityDescriptor = pipeSecurity.GetSecurityDescriptorBinaryForm ();
288 fixed (byte* securityDescriptorPtr = securityDescriptor) {
289 // FIXME: is nDefaultTimeout = 0 ok?
290 var att = new SecurityAttributes (inheritability, (IntPtr)securityDescriptorPtr);
291 var ret = Win32Marshal.CreateNamedPipe (name, openMode, pipeMode, maxNumberOfServerInstances,
292 outBufferSize, inBufferSize, 0, ref att, IntPtr.Zero);
293 if (ret == new IntPtr (-1L))
294 throw Win32PipeError.GetException ();
295 handle = new SafePipeHandle (ret, true);
299 SafePipeHandle handle;
301 public override SafePipeHandle Handle {
302 get { return handle; }
305 public void Disconnect ()
307 Win32Marshal.DisconnectNamedPipe (Handle);
310 public void WaitForConnection ()
312 if (!Win32Marshal.ConnectNamedPipe (Handle, IntPtr.Zero))
313 throw Win32PipeError.GetException ();
317 [StructLayout (LayoutKind.Sequential)]
318 struct SecurityAttributes
320 public readonly int Length;
321 public readonly IntPtr SecurityDescriptor;
322 public readonly bool Inheritable;
324 public SecurityAttributes (HandleInheritability inheritability, IntPtr securityDescriptor)
326 Length = Marshal.SizeOf (typeof (SecurityAttributes));
327 SecurityDescriptor = securityDescriptor;
328 Inheritable = inheritability == HandleInheritability.Inheritable;
332 static class Win32Marshal
334 internal static bool IsWindows {
336 switch (Environment.OSVersion.Platform) {
337 case PlatformID.Win32S:
338 case PlatformID.Win32Windows:
339 case PlatformID.Win32NT:
340 case PlatformID.WinCE:
348 // http://msdn.microsoft.com/en-us/library/aa365152%28VS.85%29.aspx
349 [DllImport ("kernel32", SetLastError=true)]
350 internal static extern bool CreatePipe (out IntPtr readHandle, out IntPtr writeHandle,
351 ref SecurityAttributes pipeAtts, int size);
353 // http://msdn.microsoft.com/en-us/library/aa365150%28VS.85%29.aspx
354 [DllImport ("kernel32", SetLastError=true)]
355 internal static extern IntPtr CreateNamedPipe (string name, uint openMode, int pipeMode, int maxInstances,
356 int outBufferSize, int inBufferSize, int defaultTimeout,
357 ref SecurityAttributes securityAttributes, IntPtr atts);
359 // http://msdn.microsoft.com/en-us/library/aa365146%28VS.85%29.aspx
360 [DllImport ("kernel32", SetLastError=true)]
361 internal static extern bool ConnectNamedPipe (SafePipeHandle handle, IntPtr overlapped);
363 // http://msdn.microsoft.com/en-us/library/aa365166%28VS.85%29.aspx
364 [DllImport ("kernel32", SetLastError=true)]
365 internal static extern bool DisconnectNamedPipe (SafePipeHandle handle);
367 // http://msdn.microsoft.com/en-us/library/aa365443%28VS.85%29.aspx
368 [DllImport ("kernel32", SetLastError=true)]
369 internal static extern bool GetNamedPipeHandleState (SafePipeHandle handle,
370 out int state, out int curInstances,
371 out int maxCollectionCount, out int collectDateTimeout,
372 byte [] userName, int maxUserNameSize);
374 // http://msdn.microsoft.com/en-us/library/aa365800%28VS.85%29.aspx
375 [DllImport ("kernel32", SetLastError=true)]
376 internal static extern bool WaitNamedPipe (string name, int timeout);
378 // http://msdn.microsoft.com/en-us/library/aa363858%28VS.85%29.aspx
379 [DllImport ("kernel32", SetLastError=true)]
380 internal static extern IntPtr CreateFile (string name, PipeAccessRights desiredAccess, FileShare fileShare,
381 ref SecurityAttributes atts, int creationDisposition, int flags, IntPtr templateHandle);