// // PipeWin32.cs // // Author: // Atsushi Enomoto // // Copyright (C) 2009 Novell, Inc. http://www.novell.com // // Permission is hereby granted, free of charge, to any person obtaining // a copy of this software and associated documentation files (the // "Software"), to deal in the Software without restriction, including // without limitation the rights to use, copy, modify, merge, publish, // distribute, sublicense, and/or sell copies of the Software, and to // permit persons to whom the Software is furnished to do so, subject to // the following conditions: // // The above copyright notice and this permission notice shall be // included in all copies or substantial portions of the Software. // // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. // #if !BOOTSTRAP_BASIC using System; using System.ComponentModel; using System.IO; using System.Linq; using System.Runtime.InteropServices; using System.Security.AccessControl; using System.Security.Permissions; using System.Security.Principal; using System.Text; using Microsoft.Win32; using Microsoft.Win32.SafeHandles; namespace System.IO.Pipes { abstract class Win32AnonymousPipe : IPipe { protected Win32AnonymousPipe () { } public abstract SafePipeHandle Handle { get; } public void WaitForPipeDrain () { throw new NotImplementedException (); } } class Win32AnonymousPipeClient : Win32AnonymousPipe, IAnonymousPipeClient { // AnonymousPipeClientStream owner; public Win32AnonymousPipeClient (AnonymousPipeClientStream owner, SafePipeHandle handle) { // this.owner = owner; this.handle = handle; } SafePipeHandle handle; public override SafePipeHandle Handle { get { return handle; } } } class Win32AnonymousPipeServer : Win32AnonymousPipe, IAnonymousPipeServer { // AnonymousPipeServerStream owner; public Win32AnonymousPipeServer (AnonymousPipeServerStream owner, PipeDirection direction, HandleInheritability inheritability, int bufferSize) { IntPtr r, w; SecurityAttributesHack att = new SecurityAttributesHack (inheritability == HandleInheritability.Inheritable); if (!Win32Marshal.CreatePipe (out r, out w, ref att, bufferSize)) throw new Win32Exception (Marshal.GetLastWin32Error ()); var rh = new SafePipeHandle (r, true); var wh = new SafePipeHandle (w, true); if (direction == PipeDirection.Out) { server_handle = wh; client_handle = rh; } else { server_handle = rh; client_handle = wh; } } public Win32AnonymousPipeServer (AnonymousPipeServerStream owner, SafePipeHandle serverHandle, SafePipeHandle clientHandle) { // this.owner = owner; this.server_handle = serverHandle; this.client_handle = clientHandle; } SafePipeHandle server_handle, client_handle; public override SafePipeHandle Handle { get { return server_handle; } } public SafePipeHandle ClientHandle { get { return client_handle; } } public void DisposeLocalCopyOfClientHandle () { throw new NotImplementedException (); } } abstract class Win32NamedPipe : IPipe { string name_cache; public string Name { get { if (name_cache != null) return name_cache; int s, c, m, t; byte [] un = new byte [200]; while (true) { if (!Win32Marshal.GetNamedPipeHandleState (Handle, out s, out c, out m, out t, un, un.Length)) { var xxx = Marshal.GetLastWin32Error (); throw new Win32Exception (xxx); } if (un [un.Length - 1] == 0) break; un = new byte [un.Length * 10]; } name_cache = Encoding.Default.GetString (un); return name_cache; } } public abstract SafePipeHandle Handle { get; } public void WaitForPipeDrain () { throw new NotImplementedException (); } } class Win32NamedPipeClient : Win32NamedPipe, INamedPipeClient { NamedPipeClientStream owner; // .ctor with existing handle public Win32NamedPipeClient (NamedPipeClientStream owner, SafePipeHandle safePipeHandle) { this.handle = safePipeHandle; this.owner = owner; // FIXME: retrieve is_async from state? } // .ctor without handle - create new public Win32NamedPipeClient (NamedPipeClientStream owner, string serverName, string pipeName, PipeAccessRights desiredAccessRights, PipeOptions options, HandleInheritability inheritability) { name = String.Format ("\\\\{0}\\pipe\\{1}", serverName, pipeName); var att = new SecurityAttributesHack (inheritability == HandleInheritability.Inheritable); is_async = (options & PipeOptions.Asynchronous) != PipeOptions.None; opener = delegate { var ret = Win32Marshal.CreateFile (name, desiredAccessRights, 0, ref att, 3, 0, IntPtr.Zero); if (ret == new IntPtr (-1L)) throw new Win32Exception (Marshal.GetLastWin32Error ()); return new SafePipeHandle (ret, true); }; this.owner = owner; } Func opener; bool is_async; string name; SafePipeHandle handle; public override SafePipeHandle Handle { get { return handle; } } public bool IsAsync { get { return is_async; } } public void Connect () { if (owner.IsConnected) throw new InvalidOperationException ("The named pipe is already connected"); handle = opener (); } public void Connect (int timeout) { if (owner.IsConnected) throw new InvalidOperationException ("The named pipe is already connected"); if (!Win32Marshal.WaitNamedPipe (name, timeout)) throw new Win32Exception (Marshal.GetLastWin32Error ()); Connect (); } public int NumberOfServerInstances { get { int s, c, m, t; byte [] un = null; if (!Win32Marshal.GetNamedPipeHandleState (Handle, out s, out c, out m, out t, un, 0)) throw new Win32Exception (Marshal.GetLastWin32Error ()); return c; } } } class Win32NamedPipeServer : Win32NamedPipe, INamedPipeServer { //NamedPipeServerStream owner; // .ctor with existing handle public Win32NamedPipeServer (NamedPipeServerStream owner, SafePipeHandle safePipeHandle) { handle = safePipeHandle; //this.owner = owner; } // .ctor without handle - create new public Win32NamedPipeServer (NamedPipeServerStream owner, string pipeName, int maxNumberOfServerInstances, PipeTransmissionMode transmissionMode, PipeAccessRights rights, PipeOptions options, int inBufferSize, int outBufferSize, HandleInheritability inheritability) { string name = String.Format ("\\\\.\\pipe\\{0}", pipeName); uint openMode = 0; if ((rights & PipeAccessRights.ReadData) != 0) openMode |= 1; if ((rights & PipeAccessRights.WriteData) != 0) openMode |= 2; if ((options & PipeOptions.WriteThrough) != 0) openMode |= 0x80000000; int pipeMode = 0; if ((owner.TransmissionMode & PipeTransmissionMode.Message) != 0) pipeMode |= 4; //if ((readTransmissionMode & PipeTransmissionMode.Message) != 0) // pipeMode |= 2; if ((options & PipeOptions.Asynchronous) != 0) pipeMode |= 1; // FIXME: is nDefaultTimeout = 0 ok? var att = new SecurityAttributesHack (inheritability == HandleInheritability.Inheritable); var ret = Win32Marshal.CreateNamedPipe (name, openMode, pipeMode, maxNumberOfServerInstances, outBufferSize, inBufferSize, 0, ref att, IntPtr.Zero); if (ret == new IntPtr (-1L)) throw new Win32Exception (Marshal.GetLastWin32Error ()); handle = new SafePipeHandle (ret, true); } SafePipeHandle handle; public override SafePipeHandle Handle { get { return handle; } } public void Disconnect () { Win32Marshal.DisconnectNamedPipe (Handle); } public void WaitForConnection () { if (!Win32Marshal.ConnectNamedPipe (Handle, IntPtr.Zero)) throw new Win32Exception (Marshal.GetLastWin32Error ()); } } [StructLayout (LayoutKind.Sequential)] struct SecurityAttributesHack { public readonly int Length; public readonly IntPtr SecurityDescriptor; public readonly bool Inheritable; public SecurityAttributesHack (bool inheritable) { Length = 0; SecurityDescriptor = IntPtr.Zero; Inheritable = inheritable; } } static class Win32Marshal { internal static bool IsWindows { get { switch (Environment.OSVersion.Platform) { case PlatformID.Win32S: case PlatformID.Win32Windows: case PlatformID.Win32NT: case PlatformID.WinCE: return true; default: return false; } } } // http://msdn.microsoft.com/en-us/library/aa365152%28VS.85%29.aspx [DllImport ("kernel32")] internal static extern bool CreatePipe (out IntPtr readHandle, out IntPtr writeHandle, ref SecurityAttributesHack pipeAtts, int size); // http://msdn.microsoft.com/en-us/library/aa365150%28VS.85%29.aspx [DllImport ("kernel32")] internal static extern IntPtr CreateNamedPipe (string name, uint openMode, int pipeMode, int maxInstances, int outBufferSize, int inBufferSize, int defaultTimeout, ref SecurityAttributesHack securityAttributes, IntPtr atts); // http://msdn.microsoft.com/en-us/library/aa365146%28VS.85%29.aspx [DllImport ("kernel32")] internal static extern bool ConnectNamedPipe (SafePipeHandle handle, IntPtr overlapped); // http://msdn.microsoft.com/en-us/library/aa365166%28VS.85%29.aspx [DllImport ("kernel32")] internal static extern bool DisconnectNamedPipe (SafePipeHandle handle); // http://msdn.microsoft.com/en-us/library/aa365443%28VS.85%29.aspx [DllImport ("kernel32")] internal static extern bool GetNamedPipeHandleState (SafePipeHandle handle, out int state, out int curInstances, out int maxCollectionCount, out int collectDateTimeout, byte [] userName, int maxUserNameSize); // http://msdn.microsoft.com/en-us/library/aa365800%28VS.85%29.aspx [DllImport ("kernel32")] internal static extern bool WaitNamedPipe (string name, int timeout); // http://msdn.microsoft.com/en-us/library/aa363858%28VS.85%29.aspx [DllImport ("kernel32")] internal static extern IntPtr CreateFile (string name, PipeAccessRights desiredAccess, FileShare fileShare, ref SecurityAttributesHack atts, int creationDisposition, int flags, IntPtr templateHandle); } } #endif