1 // 2 // PipeWin32.cs 3 // 4 // Author: 5 // Atsushi Enomoto <atsushi@ximian.com> 6 // 7 // Copyright (C) 2009 Novell, Inc. http://www.novell.com 8 // 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: 16 // 17 // The above copyright notice and this permission notice shall be 18 // included in all copies or substantial portions of the Software. 19 // 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. 27 // 28 29 #if !BOOTSTRAP_BASIC 30 31 using System; 32 using System.ComponentModel; 33 using System.IO; 34 using System.Linq; 35 using System.Runtime.InteropServices; 36 using System.Security.AccessControl; 37 using System.Security.Permissions; 38 using System.Security.Principal; 39 using System.Text; 40 using Microsoft.Win32; 41 using Microsoft.Win32.SafeHandles; 42 43 namespace System.IO.Pipes 44 { 45 static class Win32PipeError 46 { GetException()47 public static Exception GetException () 48 { 49 return GetException (Marshal.GetLastWin32Error ()); 50 } 51 GetException(int errorCode)52 public static Exception GetException (int errorCode) 53 { 54 switch (errorCode) { 55 case 5: return new UnauthorizedAccessException (); 56 default: return new Win32Exception (errorCode); 57 } 58 } 59 } 60 61 abstract class Win32AnonymousPipe : IPipe 62 { Win32AnonymousPipe()63 protected Win32AnonymousPipe () 64 { 65 } 66 67 public abstract SafePipeHandle Handle { get; } 68 WaitForPipeDrain()69 public void WaitForPipeDrain () 70 { 71 throw new NotImplementedException (); 72 } 73 } 74 75 class Win32AnonymousPipeClient : Win32AnonymousPipe, IAnonymousPipeClient 76 { 77 // AnonymousPipeClientStream owner; 78 Win32AnonymousPipeClient(AnonymousPipeClientStream owner, SafePipeHandle handle)79 public Win32AnonymousPipeClient (AnonymousPipeClientStream owner, SafePipeHandle handle) 80 { 81 // this.owner = owner; 82 83 this.handle = handle; 84 } 85 86 SafePipeHandle handle; 87 88 public override SafePipeHandle Handle { 89 get { return handle; } 90 } 91 } 92 93 class Win32AnonymousPipeServer : Win32AnonymousPipe, IAnonymousPipeServer 94 { 95 // AnonymousPipeServerStream owner; 96 Win32AnonymousPipeServer(AnonymousPipeServerStream owner, PipeDirection direction, HandleInheritability inheritability, int bufferSize, PipeSecurity pipeSecurity)97 public unsafe Win32AnonymousPipeServer (AnonymousPipeServerStream owner, PipeDirection direction, 98 HandleInheritability inheritability, int bufferSize, 99 PipeSecurity pipeSecurity) 100 { 101 IntPtr r, w; 102 103 byte[] securityDescriptor = null; 104 if (pipeSecurity != null) 105 securityDescriptor = pipeSecurity.GetSecurityDescriptorBinaryForm (); 106 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 (); 111 } 112 113 var rh = new SafePipeHandle (r, true); 114 var wh = new SafePipeHandle (w, true); 115 116 if (direction == PipeDirection.Out) { 117 server_handle = wh; 118 client_handle = rh; 119 } else { 120 server_handle = rh; 121 client_handle = wh; 122 } 123 } 124 Win32AnonymousPipeServer(AnonymousPipeServerStream owner, SafePipeHandle serverHandle, SafePipeHandle clientHandle)125 public Win32AnonymousPipeServer (AnonymousPipeServerStream owner, SafePipeHandle serverHandle, SafePipeHandle clientHandle) 126 { 127 // this.owner = owner; 128 this.server_handle = serverHandle; 129 this.client_handle = clientHandle; 130 } 131 132 SafePipeHandle server_handle, client_handle; 133 134 public override SafePipeHandle Handle { 135 get { return server_handle; } 136 } 137 138 public SafePipeHandle ClientHandle { 139 get { return client_handle; } 140 } 141 DisposeLocalCopyOfClientHandle()142 public void DisposeLocalCopyOfClientHandle () 143 { 144 throw new NotImplementedException (); 145 } 146 } 147 148 abstract class Win32NamedPipe : IPipe 149 { 150 string name_cache; 151 152 public string Name { 153 get { 154 if (name_cache != null) 155 return name_cache; 156 157 int s, c, m, t; 158 byte [] un = new byte [200]; 159 while (true) { 160 if (!Win32Marshal.GetNamedPipeHandleState (Handle, out s, out c, out m, out t, un, un.Length)) 161 throw Win32PipeError.GetException (); 162 163 if (un [un.Length - 1] == 0) 164 break; 165 un = new byte [un.Length * 10]; 166 } 167 name_cache = Encoding.Default.GetString (un); 168 return name_cache; 169 } 170 } 171 172 public abstract SafePipeHandle Handle { get; } 173 WaitForPipeDrain()174 public void WaitForPipeDrain () 175 { 176 throw new NotImplementedException (); 177 } 178 } 179 180 class Win32NamedPipeClient : Win32NamedPipe, INamedPipeClient 181 { 182 NamedPipeClientStream owner; 183 184 // .ctor with existing handle Win32NamedPipeClient(NamedPipeClientStream owner, SafePipeHandle safePipeHandle)185 public Win32NamedPipeClient (NamedPipeClientStream owner, SafePipeHandle safePipeHandle) 186 { 187 this.handle = safePipeHandle; 188 this.owner = owner; 189 190 // FIXME: retrieve is_async from state? 191 } 192 193 // .ctor without handle - create new Win32NamedPipeClient(NamedPipeClientStream owner, string serverName, string pipeName, PipeAccessRights desiredAccessRights, PipeOptions options, HandleInheritability inheritability)194 public Win32NamedPipeClient (NamedPipeClientStream owner, string serverName, string pipeName, 195 PipeAccessRights desiredAccessRights, PipeOptions options, 196 HandleInheritability inheritability) 197 { 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; 201 202 opener = delegate { 203 var ret = Win32Marshal.CreateFile (name, desiredAccessRights, 0, ref att, 3, 0, IntPtr.Zero); 204 if (ret == new IntPtr (-1L)) 205 throw Win32PipeError.GetException (); 206 207 return new SafePipeHandle (ret, true); 208 }; 209 this.owner = owner; 210 } 211 212 Func<SafePipeHandle> opener; 213 bool is_async; 214 string name; 215 SafePipeHandle handle; 216 217 public override SafePipeHandle Handle { 218 get { return handle; } 219 } 220 221 public bool IsAsync { 222 get { return is_async; } 223 } 224 Connect()225 public void Connect () 226 { 227 if (owner.IsConnected) 228 throw new InvalidOperationException ("The named pipe is already connected"); 229 230 handle = opener (); 231 } 232 Connect(int timeout)233 public void Connect (int timeout) 234 { 235 if (owner.IsConnected) 236 throw new InvalidOperationException ("The named pipe is already connected"); 237 238 if (!Win32Marshal.WaitNamedPipe (name, timeout)) 239 throw Win32PipeError.GetException (); 240 Connect (); 241 } 242 243 public int NumberOfServerInstances { 244 get { 245 int s, c, m, t; 246 byte [] un = null; 247 if (!Win32Marshal.GetNamedPipeHandleState (Handle, out s, out c, out m, out t, un, 0)) 248 throw Win32PipeError.GetException (); 249 return c; 250 } 251 } 252 } 253 254 class Win32NamedPipeServer : Win32NamedPipe, INamedPipeServer 255 { 256 //NamedPipeServerStream owner; 257 258 // .ctor with existing handle Win32NamedPipeServer(NamedPipeServerStream owner, SafePipeHandle safePipeHandle)259 public Win32NamedPipeServer (NamedPipeServerStream owner, SafePipeHandle safePipeHandle) 260 { 261 handle = safePipeHandle; 262 //this.owner = owner; 263 } 264 265 // .ctor without handle - create new Win32NamedPipeServer(NamedPipeServerStream owner, string pipeName, int maxNumberOfServerInstances, PipeTransmissionMode transmissionMode, PipeAccessRights rights, PipeOptions options, int inBufferSize, int outBufferSize, PipeSecurity pipeSecurity, HandleInheritability inheritability)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) 270 { 271 string name = String.Format ("\\\\.\\pipe\\{0}", pipeName); 272 273 uint openMode; 274 openMode = (uint)rights | (uint)options; // Enum values match Win32 flags exactly. 275 276 int pipeMode = 0; 277 if ((owner.TransmissionMode & PipeTransmissionMode.Message) != 0) 278 pipeMode |= 4; 279 //if ((readTransmissionMode & PipeTransmissionMode.Message) != 0) 280 // pipeMode |= 2; 281 if ((options & PipeOptions.Asynchronous) != 0) 282 pipeMode |= 1; 283 284 byte[] securityDescriptor = null; 285 if (pipeSecurity != null) 286 securityDescriptor = pipeSecurity.GetSecurityDescriptorBinaryForm (); 287 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); 296 } 297 } 298 299 SafePipeHandle handle; 300 301 public override SafePipeHandle Handle { 302 get { return handle; } 303 } 304 Disconnect()305 public void Disconnect () 306 { 307 Win32Marshal.DisconnectNamedPipe (Handle); 308 } 309 WaitForConnection()310 public void WaitForConnection () 311 { 312 if (!Win32Marshal.ConnectNamedPipe (Handle, IntPtr.Zero)) 313 throw Win32PipeError.GetException (); 314 } 315 } 316 317 [StructLayout (LayoutKind.Sequential)] 318 struct SecurityAttributes 319 { 320 public readonly int Length; 321 public readonly IntPtr SecurityDescriptor; 322 public readonly bool Inheritable; 323 SecurityAttributesSystem.IO.Pipes.SecurityAttributes324 public SecurityAttributes (HandleInheritability inheritability, IntPtr securityDescriptor) 325 { 326 Length = Marshal.SizeOf (typeof (SecurityAttributes)); 327 SecurityDescriptor = securityDescriptor; 328 Inheritable = inheritability == HandleInheritability.Inheritable; 329 } 330 } 331 332 static class Win32Marshal 333 { 334 internal static bool IsWindows { 335 get { 336 switch (Environment.OSVersion.Platform) { 337 case PlatformID.Win32S: 338 case PlatformID.Win32Windows: 339 case PlatformID.Win32NT: 340 case PlatformID.WinCE: 341 return true; 342 default: 343 return false; 344 } 345 } 346 } 347 348 // http://msdn.microsoft.com/en-us/library/aa365152%28VS.85%29.aspx 349 [DllImport ("kernel32", SetLastError=true)] CreatePipe(out IntPtr readHandle, out IntPtr writeHandle, ref SecurityAttributes pipeAtts, int size)350 internal static extern bool CreatePipe (out IntPtr readHandle, out IntPtr writeHandle, 351 ref SecurityAttributes pipeAtts, int size); 352 353 // http://msdn.microsoft.com/en-us/library/aa365150%28VS.85%29.aspx 354 [DllImport ("kernel32", SetLastError=true)] CreateNamedPipe(string name, uint openMode, int pipeMode, int maxInstances, int outBufferSize, int inBufferSize, int defaultTimeout, ref SecurityAttributes securityAttributes, IntPtr atts)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); 358 359 // http://msdn.microsoft.com/en-us/library/aa365146%28VS.85%29.aspx 360 [DllImport ("kernel32", SetLastError=true)] ConnectNamedPipe(SafePipeHandle handle, IntPtr overlapped)361 internal static extern bool ConnectNamedPipe (SafePipeHandle handle, IntPtr overlapped); 362 363 // http://msdn.microsoft.com/en-us/library/aa365166%28VS.85%29.aspx 364 [DllImport ("kernel32", SetLastError=true)] DisconnectNamedPipe(SafePipeHandle handle)365 internal static extern bool DisconnectNamedPipe (SafePipeHandle handle); 366 367 // http://msdn.microsoft.com/en-us/library/aa365443%28VS.85%29.aspx 368 [DllImport ("kernel32", SetLastError=true)] GetNamedPipeHandleState(SafePipeHandle handle, out int state, out int curInstances, out int maxCollectionCount, out int collectDateTimeout, byte [] userName, int maxUserNameSize)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); 373 374 // http://msdn.microsoft.com/en-us/library/aa365800%28VS.85%29.aspx 375 [DllImport ("kernel32", SetLastError=true)] WaitNamedPipe(string name, int timeout)376 internal static extern bool WaitNamedPipe (string name, int timeout); 377 378 // http://msdn.microsoft.com/en-us/library/aa363858%28VS.85%29.aspx 379 [DllImport ("kernel32", SetLastError=true)] CreateFile(string name, PipeAccessRights desiredAccess, FileShare fileShare, ref SecurityAttributes atts, int creationDisposition, int flags, IntPtr templateHandle)380 internal static extern IntPtr CreateFile (string name, PipeAccessRights desiredAccess, FileShare fileShare, 381 ref SecurityAttributes atts, int creationDisposition, int flags, IntPtr templateHandle); 382 383 } 384 } 385 386 #endif 387