IpcPort.cs source code in C# .NET

Source code for the .NET framework in C#

                        

Code:

/ 4.0 / 4.0 / untmp / DEVDIV_TFS / Dev10 / Releases / RTMRel / ndp / clr / src / ManagedLibraries / Remoting / Channels / IPC / IpcPort.cs / 1305376 / IpcPort.cs

                            // ==++== 
//
//   Copyright (c) Microsoft Corporation.  All rights reserved.
//
// ==--== 
//============================================================================
//  File:       IpcPort.cs 
//  Author:   [....]@Microsoft.Com 
//  Summary:    Implements an abstraction over Named pipes
// 
//=========================================================================


using System; 
using System.Collections;
using System.IO; 
using System.Text; 
using System.Threading;
using System.Security.AccessControl; 
using System.Security.Principal;
using System.Runtime.InteropServices;
using System.Globalization;
 
namespace System.Runtime.Remoting.Channels.Ipc
{ 
    internal class IpcPort : IDisposable 
    {
        private PipeHandle _handle; 
        private string _portName;
        private bool _cacheable;
        private const string prefix = @"\\.\pipe\";  // To make sure we are on the same machine
        private const string networkSidSddlForm = @"S-1-5-2";  // This is the wellknown sid for network sid 
        private const string authenticatedUserSidSddlForm = @"S-1-5-11";  // This is the wellknown sid for authenticated user sid
        private static CommonSecurityDescriptor s_securityDescriptor = CreateSecurityDescriptor(null); 
 
        private IpcPort(string portName, PipeHandle handle)
        { 
            _portName = portName;
            _handle = handle;
            _cacheable = true;
#pragma warning disable 618 
            // Bind the current handle to the threadpool for IOCompletion
            ThreadPool.BindHandle(_handle.Handle); 
#pragma warning restore 618 
        }
 
        internal string Name { get { return _portName; } }

        internal bool Cacheable{ get { return _cacheable;} set { _cacheable = value;} }
 
        internal static CommonSecurityDescriptor CreateSecurityDescriptor(SecurityIdentifier userSid)
        { 
            SecurityIdentifier sid = new SecurityIdentifier(networkSidSddlForm); 
            DiscretionaryAcl dacl = new DiscretionaryAcl(false, false, 1);
            // Deny all access to NetworkSid 
            dacl.AddAccess(AccessControlType.Deny, sid, -1, InheritanceFlags.None, PropagationFlags.None);
            if (userSid != null)
                dacl.AddAccess(AccessControlType.Allow, userSid, -1, InheritanceFlags.None, PropagationFlags.None);
            // Add access to the current user creating the pipe 
            dacl.AddAccess(AccessControlType.Allow, WindowsIdentity.GetCurrent().User, -1, InheritanceFlags.None, PropagationFlags.None);
            // Initialize and return the CommonSecurityDescriptor 
            return new CommonSecurityDescriptor(false, false, ControlFlags.OwnerDefaulted | ControlFlags.GroupDefaulted | ControlFlags.DiscretionaryAclPresent, null, null, null, dacl);; 
        }
 
        internal static IpcPort Create(String portName, CommonSecurityDescriptor securityDescriptor, bool exclusive)
        {
            if (Environment.OSVersion.Platform != PlatformID.Win32NT) {
                throw new NotSupportedException(CoreChannel.GetResourceString("Remoting_Ipc_Win9x")); 
            }
            PipeHandle handle = null; 
            // Add the prefix to the portName 
            string pipeName = prefix + portName;
            SECURITY_ATTRIBUTES attr = new SECURITY_ATTRIBUTES(); 
            attr.nLength = (int)Marshal.SizeOf(attr);
            byte[] sd = null;
            // If no securityDescriptor was set by the user use the default
            if (securityDescriptor == null) 
            {
                securityDescriptor = s_securityDescriptor; 
            } 

            sd = new byte[securityDescriptor.BinaryLength]; 
            // Get the binary form of the descriptor
            securityDescriptor.GetBinaryForm(sd, 0);

            GCHandle pinningHandle = GCHandle.Alloc(sd, GCHandleType.Pinned); 
            // get the address of the security descriptor
            attr.lpSecurityDescriptor = Marshal.UnsafeAddrOfPinnedArrayElement(sd, 0); 
 
            // Create the named pipe with the appropriate name
            handle = NativePipe.CreateNamedPipe(pipeName, 
                                      NativePipe.PIPE_ACCESS_DUPLEX  | NativePipe.FILE_FLAG_OVERLAPPED
                                            | (exclusive ? NativePipe.FILE_FLAG_FIRST_PIPE_INSTANCE : 0x0), // Or exclusive flag
                                      NativePipe.PIPE_TYPE_BYTE | NativePipe.PIPE_READMODE_BYTE | NativePipe.PIPE_WAIT,
                                      NativePipe.PIPE_UNLIMITED_INSTANCES, 
                                      8192,
                                      8192, 
                                      NativePipe.NMPWAIT_WAIT_FOREVER, 
                                      attr);
 
            pinningHandle.Free();
            if (handle.Handle.ToInt32() == NativePipe.INVALID_HANDLE_VALUE){
                int error = Marshal.GetLastWin32Error();
                throw new RemotingException(String.Format(CultureInfo.CurrentCulture, CoreChannel.GetResourceString("Remoting_Ipc_CreateIpcFailed"), GetMessage(error))); 
            }
 
             return new IpcPort(portName, handle); 
        }
 
        public bool WaitForConnect()
        {
            // Wait for clients to connect
            bool status = NativePipe.ConnectNamedPipe(_handle, null); 

            return status ? true : (Marshal.GetLastWin32Error() == NativePipe.ERROR_PIPE_CONNECTED); 
        } 

        internal static IpcPort Connect(String portName, bool secure, TokenImpersonationLevel impersonationLevel, int timeout) 
        {
            string pipeName = prefix + portName;
            uint impersonation = NativePipe.SECURITY_SQOS_PRESENT;
 
            // convert the impersonation Level to the correct flag
            if (secure) { 
                switch (impersonationLevel) 
                {
                    case TokenImpersonationLevel.None: 
                            impersonation = NativePipe.SECURITY_SQOS_PRESENT;
                            break;
                    case TokenImpersonationLevel.Identification:
                            impersonation = NativePipe.SECURITY_SQOS_PRESENT | NativePipe.SECURITY_IDENTIFICATION; 
                            break;
                    case TokenImpersonationLevel.Impersonation: 
                            impersonation = NativePipe.SECURITY_SQOS_PRESENT | NativePipe.SECURITY_IMPERSONATION; 
                            break;
                    case TokenImpersonationLevel.Delegation: 
                            impersonation = NativePipe.SECURITY_SQOS_PRESENT | NativePipe.SECURITY_DELEGATION;
                            break;
                }
            } 

            while (true) 
            { 
                // Invoke CreateFile with the pipeName to open a client side connection
                PipeHandle handle = NativePipe.CreateFile(pipeName, 
                                     NativePipe.GENERIC_READ | NativePipe.GENERIC_WRITE ,
                                     NativePipe.FILE_SHARE_READ |
                                     NativePipe.FILE_SHARE_WRITE,
                                     IntPtr.Zero, 
                                     NativePipe.OPEN_EXISTING,
                                     NativePipe.FILE_ATTRIBUTE_NORMAL | 
                                     NativePipe.FILE_FLAG_OVERLAPPED | 
                                     impersonation,
                                     IntPtr.Zero); 

                if(handle.Handle.ToInt32() != NativePipe.INVALID_HANDLE_VALUE)
                    return new IpcPort(portName, handle);
 
                int error = Marshal.GetLastWin32Error();
                if(error != NativePipe.ERROR_PIPE_BUSY) 
                { 
                    throw new RemotingException(String.Format(CultureInfo.CurrentCulture, CoreChannel.GetResourceString("Remoting_Ipc_ConnectIpcFailed"), GetMessage(error)));
                } 

                if(!NativePipe.WaitNamedPipe(pipeName, timeout))
                {
                    throw new RemotingException(String.Format(CultureInfo.CurrentCulture, CoreChannel.GetResourceString("Remoting_Ipc_Busy"), GetMessage(error))); 
                }
            } 
 
        }
 
        // Gets an error message for a Win32 error code.
        internal static String GetMessage(int errorCode) {
            StringBuilder sb = new StringBuilder(512);
            int result = NativePipe.FormatMessage(NativePipe.FORMAT_MESSAGE_IGNORE_INSERTS | 
                NativePipe.FORMAT_MESSAGE_FROM_SYSTEM | NativePipe.FORMAT_MESSAGE_ARGUMENT_ARRAY,
                NativePipe.NULL, errorCode, 0, sb, sb.Capacity, NativePipe.NULL); 
            if (result != 0) { 
                // result is the # of characters copied to the StringBuilder on NT,
                // but on Win9x, it appears to be the number of MBCS bytes. 
                // Just give up and return the String as-is...
                String s = sb.ToString();
                return s;
            } 
            else {
                return String.Format(CultureInfo.CurrentCulture, CoreChannel.GetResourceString("Remoting_UnknownError_Num"), errorCode.ToString(CultureInfo.InvariantCulture)); 
            } 
        }
 
        internal void ImpersonateClient()
        {
            bool status = NativePipe.ImpersonateNamedPipeClient(_handle);
 
            if (!status)
            { 
                int error = Marshal.GetLastWin32Error(); 
                throw new RemotingException(String.Format(CultureInfo.CurrentCulture, CoreChannel.GetResourceString("Remoting_Ipc_ImpersonationFailed"), GetMessage(error)));
            } 
        }

        internal unsafe int Read(byte[] data, int offset, int length)
        { 
            bool status = false;
            int numBytesRead = 0; 
 
            fixed(byte* p = data) {
                    status = NativePipe.ReadFile(_handle, p + offset, length, ref numBytesRead, IntPtr.Zero); 
            }
            if (!status) {
                int error = Marshal.GetLastWin32Error();
                throw new RemotingException(String.Format(CultureInfo.CurrentCulture, CoreChannel.GetResourceString("Remoting_Ipc_ReadFailure"), GetMessage(error))); 
            }
            else 
                return numBytesRead; 
        }
 
        internal unsafe IAsyncResult BeginRead(byte[] data, int offset, int size, AsyncCallback callback, object state)
        {
            PipeAsyncResult asyncResult = new PipeAsyncResult(callback);
            // Create a managed overlapped class 
            // We will set the file offsets later
            Overlapped overlapped = new Overlapped(0, 0, IntPtr.Zero, asyncResult); 
 
            // Pack the Overlapped class, and store it in the async result
            NativeOverlapped* intOverlapped; 
            intOverlapped = overlapped.UnsafePack(IOCallback, data);
            asyncResult._overlapped = intOverlapped;
            bool status;
 
            // pin the buffer and read data with overlapped
            fixed(byte* p = data) { 
                    status = NativePipe.ReadFile(_handle, p + offset, size, IntPtr.Zero, intOverlapped); 
            }
            if (!status) 
            {
                int error = Marshal.GetLastWin32Error();
                // For pipes, when they hit EOF, they will come here.
                if (error == NativePipe.ERROR_BROKEN_PIPE) { 
                    // Not an error, but EOF.  AsyncFSCallback will NOT be
                    // called.  Call the user callback here. 
                    asyncResult.CallUserCallback(); 
                    // EndRead will free the Overlapped struct correctly.
                } 
                else if (error != NativePipe.ERROR_IO_PENDING)
                    throw new RemotingException(String.Format(CultureInfo.CurrentCulture, CoreChannel.GetResourceString("Remoting_Ipc_ReadFailure"), GetMessage(error)));
            }
            return asyncResult; 
        }
 
        private unsafe static readonly IOCompletionCallback IOCallback = new IOCompletionCallback(IpcPort.AsyncFSCallback); 
        unsafe private static void AsyncFSCallback(uint errorCode, uint numBytes, NativeOverlapped* pOverlapped)
        { 
            // Unpack overlapped
            Overlapped overlapped = Overlapped.Unpack(pOverlapped);
            // Free the overlapped struct in EndRead/EndWrite.
 
            // Extract async result from overlapped
            PipeAsyncResult asyncResult = 
                (PipeAsyncResult)overlapped.AsyncResult; 
            asyncResult._numBytes = (int)numBytes;
 
            // Handle reading from & writing to closed pipes.  While I'm not sure
            // this is entirely necessary anymore, maybe it's possible for
            // an async read on a pipe to be issued and then the pipe is closed,
            // returning this error.  This may very well be necessary. 
            if (errorCode == NativePipe.ERROR_BROKEN_PIPE)
                errorCode = 0; 
 
            asyncResult._errorCode = (int)errorCode;
            // Call the user-provided callback.  It can and often should 
            // call EndRead or EndWrite.  There's no reason to use an async
            // delegate here - we're already on a threadpool thread.
            // IAsyncResult's completedSynchronously property must return
            // false here, saying the user callback was called on another thread. 
            AsyncCallback userCallback = asyncResult._userCallback;
            userCallback(asyncResult); 
        } 

        internal unsafe int EndRead(IAsyncResult iar) 
        {
            PipeAsyncResult ar = iar as PipeAsyncResult;
            // Free memory & GC handles.
            NativeOverlapped* overlappedPtr = ar._overlapped; 
            if (overlappedPtr != null)
                Overlapped.Free(overlappedPtr); 
 
            // Now check for any error during the read.
            if (ar._errorCode != 0) 
                throw new RemotingException(String.Format(CultureInfo.CurrentCulture, CoreChannel.GetResourceString("Remoting_Ipc_ReadFailure"), GetMessage(ar._errorCode)));

            return ar._numBytes;
        } 

        internal unsafe void Write(byte[] data, int offset, int size) 
        { 
            int numBytesWritten = 0;
            bool status = false; 

            // pin the buffer and write data
            fixed(byte* p = data) {
                status = NativePipe.WriteFile(_handle, p + offset, size, ref numBytesWritten, IntPtr.Zero); 
            }
 
            if (!status) { 
                int error = Marshal.GetLastWin32Error();
                throw new RemotingException(String.Format(CultureInfo.CurrentCulture, CoreChannel.GetResourceString("Remoting_Ipc_WriteFailure"), GetMessage(error))); 
            }
        }

        private bool isDisposed = false; 

        ~IpcPort(){ 
            Dispose(); 
        }
 
        public void Dispose()
        {
            InternalRemotingServices.RemotingAssert(_handle.Handle != IntPtr.Zero, "Handle should be valid");
            if (!isDisposed){ 
                _handle.Close();
                isDisposed = true; 
                GC.SuppressFinalize(this); 
            }
        } 

        public bool IsDisposed {
            get { return isDisposed; }
        } 
    }
 
    internal unsafe class PipeAsyncResult: IAsyncResult 
    {
        internal NativeOverlapped* _overlapped; 
        internal AsyncCallback _userCallback;
        internal int _numBytes;
        internal int _errorCode;
 
        internal PipeAsyncResult(AsyncCallback callback)
        { 
            _userCallback = callback; 
        }
 
        public bool IsCompleted { get { throw new NotSupportedException();} }
        public WaitHandle AsyncWaitHandle { get { throw new NotSupportedException();} }
        public Object     AsyncState      { get { throw new NotSupportedException();} }
        public bool       CompletedSynchronously { get { return false;} } 

 
        internal void CallUserCallback() 
        {
            // Call user's callback on a threadpool thread. 
            // Set completedSynchronously to false, since it's on another
            // thread, not the main thread.
            ThreadPool.QueueUserWorkItem(new WaitCallback(CallUserCallbackWorker));
        } 

        private void CallUserCallbackWorker(Object callbackState) 
        { 
            // This needs to call the user callback, then set _isComplete to
            // true and set the event if it exists.  This is similar to the 
            // logic in AsyncFSCallback.
            _userCallback(this);
        }
    } 

} 

// File provided for Reference Use Only by Microsoft Corporation (c) 2007.
                        

Link Menu

Network programming in C#, Network Programming in VB.NET, Network Programming in .NET
This book is available now!
Buy at Amazon US or
Buy at Amazon UK