File: channels\core\corechannel.cs
Project: ndp\clr\src\managedlibraries\remoting\System.Runtime.Remoting.csproj (System.Runtime.Remoting)
// ==++==
// 
//   Copyright (c) Microsoft Corporation.  All rights reserved.
// 
// ==--==
using System;
using System.Text;
using System.Threading;
#if !FEATURE_PAL
using System.DirectoryServices;
#endif
using System.Reflection;
using System.Runtime.Serialization;
using System.Runtime.Serialization.Formatters;
using System.Runtime.Serialization.Formatters.Soap;
using System.Runtime.Serialization.Formatters.Binary;
using System.Runtime.Remoting;
using System.Runtime.Remoting.Channels;
using System.Runtime.Remoting.Messaging;       
using System.Runtime.Remoting.Metadata;
using System.Security.Principal;
using System.ComponentModel;
using System.IO;
using System.Net;
using System.Net.NetworkInformation;
using System.Collections;
using System.Net.Sockets;
using System.Resources;
using System.Diagnostics;
using System.Globalization;
#if !FEATURE_PAL
using System.Web;
#endif
using System.Runtime.InteropServices;
 
#if FEATURE_COMINTEROP
 
// These two attributes are for supporting side-by-side of COM-visible
// objects with NDP 1.0 RTM. This needs to be set on all assemblies that 
// expose COM-visible types to be made Side by Side with NDP 1.0 RTM.
// This declaration covers System.Runtime.Remoting.dll
[assembly:ComCompatibleVersion(1,0,3300,0)]
[assembly:TypeLibVersion(4,0)]
 
#endif // FEATURE_COMINTEROP
 
namespace System.Runtime.Remoting.Channels
{
 
    // Use this internal indicator (as opposed to the nested enum found
    //   on some of the server channel sinks)
    internal enum SinkChannelProtocol
    {
        Http, // special processing needed for http
        Other
    } // ChannelProtocol
 
    
 
    internal static class CoreChannel    
    {
        private static IByteBufferPool _bufferPool = new ByteBufferPool(10, 4096);
        private static RequestQueue _requestQueue = new RequestQueue(8,4,250);        
 
        internal static IByteBufferPool BufferPool { get { return _bufferPool; } }
        internal static RequestQueue RequestQueue { get { return _requestQueue; } }
        
    
        internal const int MaxStringLen = 512;
 
        internal const String SOAPMimeType = "text/xml";
        internal const String BinaryMimeType = "application/octet-stream";
 
        internal const String SOAPContentType = "text/xml; charset=\"utf-8\"";
 
        private static String s_hostName = null; 
        private static String s_MachineName = null;
        private static String s_MachineIp = null;
 
        private static volatile IPHostEntry s_CachedIPHostEntry = null; 
 
        // Copy of consts defined in RemotingServices.cs
        internal const int CLIENT_MSG_GEN          = 1;
        internal const int CLIENT_MSG_SINK_CHAIN   = 2;
        internal const int CLIENT_MSG_SER          = 3;
        internal const int CLIENT_MSG_SEND         = 4;
        internal const int SERVER_MSG_RECEIVE      = 5;
        internal const int SERVER_MSG_DESER        = 6;
        internal const int SERVER_MSG_SINK_CHAIN   = 7;
        internal const int SERVER_MSG_STACK_BUILD  = 8;
        internal const int SERVER_DISPATCH         = 9;
        internal const int SERVER_RET_STACK_BUILD  = 10;
        internal const int SERVER_RET_SINK_CHAIN   = 11;
        internal const int SERVER_RET_SER          = 12;
        internal const int SERVER_RET_SEND         = 13;
        internal const int SERVER_RET_END          = 14;
        internal const int CLIENT_RET_RECEIVE      = 15;
        internal const int CLIENT_RET_DESER        = 16;
        internal const int CLIENT_RET_SINK_CHAIN   = 17;
        internal const int CLIENT_RET_PROPAGATION  = 18;
        internal const int CLIENT_END_CALL         = 19;
        internal const int TIMING_DATA_EOF         = 99;
 
        private static bool s_isClientSKUInstallationInitialized = false;
        private static bool s_isClientSKUInstallation = false;
 
        static CoreChannel()
        {
            try
            {
                NetworkChange.NetworkAddressChanged += new NetworkAddressChangedEventHandler(OnNetworkAddressChanged);
            }
            catch
            {
                // in case exception gets thrown from static constructor, we won't get network address changed notifications 
                // but at least we won't be left with a half constructed class ......
            }
        } // cctor
 
        // Returns true if the Fx Client SKU is installed, false if Full SKU
        internal static bool IsClientSKUInstallation
        {
            get
            {
                if (!s_isClientSKUInstallationInitialized)
                {
                    Type type = Type.GetType("System.Web.HttpContext, " + AssemblyRef.SystemWeb, false);
                    s_isClientSKUInstallation = (type == null);
                    s_isClientSKUInstallationInitialized = true;
                }
 
                return s_isClientSKUInstallation;
            }
        } // IsClientSKUInstallation
 
        private static void OnNetworkAddressChanged(object sender, EventArgs e)
        {
            try
            {
                UpdateCachedIPAddresses();
            }
            catch 
            {
                // this call is coming from an event; leak no exceptions
            }
        } // OnNetworkAddressChanged
 
        private static void UpdateCachedIPAddresses()
        {
            try
            {
                s_CachedIPHostEntry = Dns.GetHostEntry(GetMachineName());
            }
            catch (Exception exception)
            {
                s_CachedIPHostEntry = null;
 
                InternalRemotingServices.RemotingTrace(string.Format(
                       "CoreChannel.UpdateCachedIPAddresses caught exception '{0}'; \r\nMessage: {1}", exception.GetType().ToString(), exception.Message));
 
                throw; 
            }
        } // UpdateCachedIPAddresses
 
        internal static String GetHostName()
        {
            if (s_hostName == null)
            {
                s_hostName = Dns.GetHostName();
 
                if (s_hostName == null)
                {
                    throw new ArgumentNullException("hostName");
                }
            }
 
            return s_hostName;
        } // GetHostName
 
        internal static String GetMachineName()
        {
            if (s_MachineName == null)
            {     
                String machineName = GetHostName();
                if (machineName != null)
                {
                    IPHostEntry host = Dns.GetHostEntry(machineName);
                    if (host != null)
                        s_MachineName = host.HostName;
                } 
 
                if (s_MachineName == null)
                {
                    throw new ArgumentNullException("machine");
                }
            }
            
            return s_MachineName;      
        } // GetMachineName
 
 
        // This helper function Checks whether the remote IP Adress is actually a local address
        internal static bool IsLocalIpAddress(IPAddress remoteAddress)
        {
            if (s_CachedIPHostEntry == null)
            {
                UpdateCachedIPAddresses(); 
            }
 
            return IsLocalIpAddress(s_CachedIPHostEntry, remoteAddress.AddressFamily, remoteAddress);
        }
        
        //This helper function compares and IpAddress with all addresses in IpHostEntry
        internal static bool IsLocalIpAddress(IPHostEntry host, AddressFamily addressFamily, IPAddress remoteAddress)
        {
            if (host != null)
            {
                IPAddress[] addressList = host.AddressList;
                for (int i = 0; i < addressList.Length; i++)
                {
                    if (addressList[i].AddressFamily == addressFamily)
                    {
                        if(addressList[i].Equals(remoteAddress))
                            return true;
                    }
                }
            }
            return false;
        }
 
        // process specified host name to see if it is a meta-hostname that
        //   should be replaced with something else.
        internal static String DecodeMachineName(String machineName)
        {
            if (machineName.Equals("$hostName"))
                return GetHostName();
 
            return machineName;
        } // DecodeMachineName
        
 
        internal static String GetMachineIp()
        {
            if (s_MachineIp == null)
            {            
                String hostName = GetMachineName();
 
                // NOTE: We intentionally allow exceptions from these api's
                //  propagate out to the caller.
                IPHostEntry ipEntries = Dns.GetHostEntry(hostName);
 
                //Assumption is Socket.OSSupportsIPv4 will be false only on OS >= Vista with IPv4 turned off.
                AddressFamily addressFamily = (Socket.OSSupportsIPv4) ? AddressFamily.InterNetwork : AddressFamily.InterNetworkV6;
                IPAddress addr = GetMachineAddress(ipEntries, addressFamily);
                if (addr != null)
                {
                    s_MachineIp = addr.ToString();
                }
                
                if (s_MachineIp == null)
                {
                    throw new ArgumentNullException("ip");
                }
            }
            
            return s_MachineIp;      
        } // GetMachineIp
 
        // This helper function returns the first IPAddress with family 'addressFamily' from
        // host.AddressList, or null if there is no such address or if host is null.
        internal static IPAddress GetMachineAddress(IPHostEntry host, AddressFamily addressFamily)
        {
            // NOTE: We intentionally allow exceptions from these api's
            //  propagate out to the caller.
            IPAddress result = null;
            if (host != null)
            {
                // find the first address for this address family
                IPAddress[] addressList = host.AddressList;
                for (int i = 0; i < addressList.Length; i++)
                {
                    if (addressList[i].AddressFamily == addressFamily)
                    {
                        result = addressList[i];
                        break;
                    }
                }
            }
            
            //Console.WriteLine("GetMachineAddress(" + hostName + ", " + addressFamily + ") -> " + (result == null ? "<null>" : result.ToString()));
            return result;
        } // GetMachineAddress
        
 
        //
        // Core Serialization and Deserialization support
        //        
        internal static Header[] GetMessagePropertiesAsSoapHeader(IMessage reqMsg)
        {
            IDictionary d = reqMsg.Properties;
            if (d == null)
                return null;
                
            int count = d.Count;
            if (count == 0)
                return null;
 
            IDictionaryEnumerator e = (IDictionaryEnumerator) d.GetEnumerator();
 
            // cycle through the headers to get a length
            bool[] map = new bool[count];
            int len = 0, i=0;
            IMethodMessage msg = (IMethodMessage)reqMsg;
            while (e.MoveNext())
            {                   
                String key = (String)e.Key;
                if ((key.Length >= 2) &&
                    (String.CompareOrdinal(key, 0, "__", 0, 2)  == 0) 
                     &&
                     (
                        key.Equals("__Args") 
                                ||
                        key.Equals("__OutArgs") 
                                ||
                        key.Equals("__Return") 
                                ||
                        key.Equals("__Uri") 
                                ||
                        key.Equals("__MethodName") 
                                ||
                        (key.Equals("__MethodSignature") 
                                && (!RemotingServices.IsMethodOverloaded(msg))
                                && (!msg.HasVarArgs))
                                ||
                        key.Equals("__TypeName") 
                                ||
                        key.Equals("__Fault") 
                                ||
                        (key.Equals("__CallContext") 
                                && ((e.Value != null) ? (((LogicalCallContext)e.Value).HasInfo==false) : true))
                      )                       
                  )
                {
                        i++;
                    continue;
                }
                map[i] = true;
                i++;                
                len++;
            }
            if (len == 0)
                return null;
 
            
            Header[] ret = new Header[len];
            e.Reset();
            int k=0; 
            i = 0;
            while (e.MoveNext())
            {
                Object key = e.Key;
                if (!map[k])
                {
                    k++;
                    continue;
                }
                
                Header h = e.Value as Header;
 
                // If the property is not a header, then make a header out of it.
                if (h == null)
                {
                    h = 
                        new Header(
                            (String)key, e.Value, false,
                            "http://schemas.microsoft.com/clr/soap/messageProperties");
                }
 
                // <
                if (i == ret.Length)
                {
                    InternalRemotingServices.RemotingTrace("HTTPChannel::GetHeaders creating a new array of length " + (i+1) + "\n");
                    Header[] newret= new Header[i+1];
                    Array.Copy(ret, newret, i);
                    ret = newret;
                }
                ret[i] = h;
                i++;
                k++;
            }
            
            return ret;
        } // GetMessagePropertiesAsSoapHeader
        
 
        internal static Header[] GetSoapHeaders(IMessage reqMsg)
        {    
            // If there are message properties, we'll need to resize the header array.
            Header[] msgProperties = GetMessagePropertiesAsSoapHeader(reqMsg);
 
            return msgProperties;
        } // GetSoapHeaders
 
 
 
        internal static SoapFormatter CreateSoapFormatter(bool serialize, bool includeVersions)
        {            
            SoapFormatter remotingFormatter = new SoapFormatter();
 
            if (serialize)
            {
                RemotingSurrogateSelector rss = new RemotingSurrogateSelector();
                remotingFormatter.SurrogateSelector = rss;
                rss.UseSoapFormat();
            }
            else
                remotingFormatter.SurrogateSelector = null;
 
            remotingFormatter.Context = new StreamingContext(StreamingContextStates.Other);
 
            remotingFormatter.AssemblyFormat = 
                includeVersions ? 
                    FormatterAssemblyStyle.Full :
                    FormatterAssemblyStyle.Simple;
 
            return remotingFormatter;
        } // CreateSoapFormatter
 
 
        internal static BinaryFormatter CreateBinaryFormatter(bool serialize, 
                                                              bool includeVersionsOrStrictBinding)
        {
            BinaryFormatter remotingFormatter = new BinaryFormatter();
 
            if (serialize)
            {
                RemotingSurrogateSelector rss = new RemotingSurrogateSelector();
                remotingFormatter.SurrogateSelector = rss;
            }
            else
            {
                remotingFormatter.SurrogateSelector = null;
            }
 
            remotingFormatter.Context = new StreamingContext(StreamingContextStates.Other);
 
            remotingFormatter.AssemblyFormat = 
                includeVersionsOrStrictBinding ? 
                    FormatterAssemblyStyle.Full :
                    FormatterAssemblyStyle.Simple;  
            
            return remotingFormatter;
        } // CreateBinaryFormatter
 
 
 
 
        internal static void SerializeSoapMessage(IMessage msg, Stream outputStream, bool includeVersions)
        {
            // create soap formatter
            SoapFormatter fmt = CreateSoapFormatter(true, includeVersions);
 
            //check for special options if this is the SoapFormatter
            IMethodMessage methodMsg = msg as IMethodMessage;
            if (methodMsg != null)
            {
                MethodBase mb = methodMsg.MethodBase;
                if (mb != null)
                {
                    Type type = methodMsg.MethodBase.DeclaringType;
                    SoapTypeAttribute cache = 
                        (SoapTypeAttribute)InternalRemotingServices.GetCachedSoapAttribute(type);
                    if ((cache.SoapOptions & SoapOption.AlwaysIncludeTypes) == SoapOption.AlwaysIncludeTypes)
                        fmt.TypeFormat |= FormatterTypeStyle.TypesAlways;
                    if ((cache.SoapOptions & SoapOption.XsdString) == SoapOption.XsdString)
                        fmt.TypeFormat |= FormatterTypeStyle.XsdString;                
                }
            }
            // end of set special options for SoapFormatter
            
            Header[] h = GetSoapHeaders(msg);
 
            // this is to make messages within a  message serialize correctly 
            // and not use the fake type
            ((RemotingSurrogateSelector)fmt.SurrogateSelector).SetRootObject(msg);
            fmt.Serialize(outputStream, msg, h);
        } // SerializeSoapMessage
 
        internal static Stream SerializeSoapMessage(IMessage msg, bool includeVersions)
        {
            MemoryStream memStream = new MemoryStream();
            SerializeSoapMessage(msg, memStream, includeVersions);
            memStream.Position = 0;
            return memStream;
        } // SerializeSoapMessage
        
 
 
        internal static void SerializeBinaryMessage(IMessage msg, Stream outputStream, bool includeVersions)
        {
            // create binary formatter
            BinaryFormatter fmt = CreateBinaryFormatter(true, includeVersions);
 
            // WE SHOULD NOT CALL GetHeaders() here. The BinaryFormatter does special
            //   serialization for any headers that might be present.
 
            fmt.Serialize(outputStream, msg, null);
        } // SerializeBinaryMessage
        
        internal static Stream SerializeBinaryMessage(IMessage msg, bool includeVersions)
        {
            MemoryStream memStream = new MemoryStream();
            SerializeBinaryMessage(msg, memStream, includeVersions);
            memStream.Position = 0;
            return memStream;
        } // SerializeBinaryMessage
 
 
 
        // class used to pass uri into binary serializer, so that the message
        //   gets the object uri.
        private class UriHeaderHandler
        {
            String _uri = null;
 
            internal UriHeaderHandler(String uri)
            {
                _uri = uri;
            }
        
            public Object HeaderHandler(Header[] Headers)
            {
                return _uri;
            }
            
        } // classUriHeaderHandler
 
 
        internal static IMessage DeserializeSoapRequestMessage(
            Stream inputStream, Header[] h, bool bStrictBinding, TypeFilterLevel securityLevel)
        {
            SoapFormatter fmt = CreateSoapFormatter(false, bStrictBinding);
            fmt.FilterLevel = securityLevel;
 
            MethodCall mc = new MethodCall(h);
            fmt.Deserialize(inputStream, new HeaderHandler(mc.HeaderHandler));
 
            IMessage resMessage = (IMessage)mc;
 
            return resMessage;
        } // DeserializeSoapRequestMessage
 
 
        internal static IMessage DeserializeSoapResponseMessage(
            Stream inputStream, IMessage requestMsg, Header[] h, bool bStrictBinding)
        {
            SoapFormatter fmt = CreateSoapFormatter(false, bStrictBinding);
 
            IMethodCallMessage mcm = (IMethodCallMessage)requestMsg;
            MethodResponse mr = new MethodResponse(h, mcm);
            fmt.Deserialize(inputStream, new HeaderHandler(mr.HeaderHandler));
 
            IMessage resMessage = (IMessage)mr;
 
            return resMessage;
        } // DeserializeSoapResponseMessage
 
 
        internal static IMessage DeserializeBinaryRequestMessage(
            String objectUri, 
            Stream inputStream,
            bool bStrictBinding,
            TypeFilterLevel securityLevel)
        {
            BinaryFormatter fmt = CreateBinaryFormatter(false, bStrictBinding);
            fmt.FilterLevel = securityLevel; 
 
            UriHeaderHandler uriHH = new UriHeaderHandler(objectUri);
 
            IMessage reqMsg = 
                (IMessage)fmt.UnsafeDeserialize(inputStream, new HeaderHandler(uriHH.HeaderHandler));
 
            return reqMsg;
        } // DeserializeBinaryRequestMessage
 
 
        internal static IMessage DeserializeBinaryResponseMessage(
            Stream inputStream,
            IMethodCallMessage reqMsg,
            bool bStrictBinding)
        {
            BinaryFormatter fmt = CreateBinaryFormatter(false, bStrictBinding);
 
            IMessage replyMsg = (IMessage)fmt.UnsafeDeserializeMethodResponse(inputStream, null, reqMsg);
            return replyMsg;
        } // DeserializeBinaryResponseMessage
 
        internal static Stream SerializeMessage(String mimeType, IMessage msg, bool includeVersions)
        {
            Stream returnStream = new MemoryStream();
            SerializeMessage(mimeType, msg, returnStream, includeVersions);
            returnStream.Position = 0;
            return returnStream;
        } // SerializeMessage
 
 
        internal static void SerializeMessage(String mimeType, IMessage msg, Stream outputStream,
                                              bool includeVersions)
        {
            InternalRemotingServices.RemotingTrace("SerializeMessage");
            InternalRemotingServices.RemotingTrace("MimeType: " + mimeType);
            CoreChannel.DebugMessage(msg);
            
            if (string.Compare(mimeType, SOAPMimeType, StringComparison.Ordinal) == 0)
            {
                SerializeSoapMessage(msg, outputStream, includeVersions);
            }
            else
            if (string.Compare(mimeType, BinaryMimeType, StringComparison.Ordinal) == 0)
            {
                SerializeBinaryMessage(msg, outputStream, includeVersions);
            }                   
 
            InternalRemotingServices.RemotingTrace("SerializeMessage: OUT");
        } // SerializeMessage
 
 
 
        
        internal static IMessage DeserializeMessage(String mimeType, Stream xstm, bool methodRequest, IMessage msg)
        {
            return DeserializeMessage(mimeType, xstm, methodRequest, msg, null);
        }
 
        internal static IMessage DeserializeMessage(String mimeType, Stream xstm, bool methodRequest, IMessage msg, Header[] h)
        {
            InternalRemotingServices.RemotingTrace("DeserializeMessage");
            InternalRemotingServices.RemotingTrace("MimeType: " + mimeType);
 
            CoreChannel.DebugOutXMLStream(xstm, "Deserializing");
 
            Stream fmtStm = null;
 
            bool bin64encode = false;
            bool doHeaderBodyAsOne = true;
 
            if (string.Compare(mimeType, BinaryMimeType, StringComparison.Ordinal) == 0)
            {
                doHeaderBodyAsOne = true;
            }
 
            if (string.Compare(mimeType, SOAPMimeType, StringComparison.Ordinal) == 0)
            {
                doHeaderBodyAsOne = false;
            }
 
            if (bin64encode == false)
            {
                fmtStm  = xstm;
            }
            else
            {
                InternalRemotingServices.RemotingTrace("***************** Before base64 decode *****");
 
                long Position = xstm.Position;
                MemoryStream inStm = (MemoryStream)xstm;
                byte[] byteArray = inStm.ToArray();
                xstm.Position = Position;
 
                String base64String = Encoding.ASCII.GetString(byteArray,0, byteArray.Length);
 
                byte[] byteArrayContent = Convert.FromBase64String(base64String);
 
                MemoryStream memStm = new MemoryStream(byteArrayContent);
 
                fmtStm = memStm;
                InternalRemotingServices.RemotingTrace("***************** after base64 decode *****");
            }
 
            Object ret;
            IRemotingFormatter fmt = MimeTypeToFormatter(mimeType, false);
 
            if (doHeaderBodyAsOne == true)
            {
                ret = ((BinaryFormatter)fmt).UnsafeDeserializeMethodResponse(fmtStm, null, (IMethodCallMessage)msg);
            }
            else
            {
                InternalRemotingServices.RemotingTrace("Content");
                InternalRemotingServices.RemotingTrace("***************** Before Deserialize Headers *****");
 
                InternalRemotingServices.RemotingTrace("***************** After Deserialize Headers *****");
 
                InternalRemotingServices.RemotingTrace("***************** Before Deserialize Message *****");
 
                if (methodRequest == true)
                {
                    MethodCall mc = new MethodCall(h);
                    InternalRemotingServices.RemotingTrace("***************** Before Deserialize Message - as MethodCall *****");
                    fmt.Deserialize(fmtStm, new HeaderHandler(mc.HeaderHandler));
                    ret = mc;
                }
                else
                {
                    IMethodCallMessage mcm = (IMethodCallMessage)msg;
                    MethodResponse mr = new MethodResponse(h, mcm);
                    InternalRemotingServices.RemotingTrace("***************** Before Deserialize Message - as MethodResponse *****");
                    fmt.Deserialize(fmtStm, new HeaderHandler(mr.HeaderHandler));
                    ret = mr;
                }
 
                InternalRemotingServices.RemotingTrace("***************** After Deserialize Message *****");
            }
 
            // Workaround to make this method verifiable
            IMessage resMessage = (IMessage) ret;
 
            InternalRemotingServices.RemotingTrace("CoreChannel::DeserializeMessage OUT");
            CoreChannel.DebugMessage(resMessage);
 
            return resMessage;
        }
       
    
 
        internal static IRemotingFormatter MimeTypeToFormatter(String mimeType, bool serialize)
        {
            InternalRemotingServices.RemotingTrace("MimeTypeToFormatter: mimeType: " + mimeType);
 
            if (string.Compare(mimeType, SOAPMimeType, StringComparison.Ordinal) == 0)
            {
                return CreateSoapFormatter(serialize, true);
            }
            else
            if (string.Compare(mimeType, BinaryMimeType, StringComparison.Ordinal) == 0)
            {
                return CreateBinaryFormatter(serialize, true);
            }     
 
            return null;
        } // MimeTypeToFormatter
 
 
        //
        // Other helper methods
        //
 
        // Removes application name from front of uri if present.
        internal static String RemoveApplicationNameFromUri(String uri)
        {
            if (uri == null)
                return null;
        
            String appName = RemotingConfiguration.ApplicationName;
            if ((appName == null) || (appName.Length == 0))
                return uri;
 
            // uri must be longer than the appname plus a slash (hence the "+2")
            if (uri.Length < (appName.Length + 2))
                return uri;
            
            // case-insensitively determine if uri starts with app name
            if (String.Compare(appName, 0, uri, 0, appName.Length, StringComparison.OrdinalIgnoreCase) == 0)
            {
                // make sure a slash follows the app name (we already made sure
                //   uri was long enough above)
                if (uri[appName.Length] == '/')
                {
                    uri = uri.Substring(appName.Length + 1);
                }
            }            
 
            return uri;            
        } // RemoveApplicationNameFromUri
 
 
        internal static void AppendProviderToClientProviderChain(
            IClientChannelSinkProvider providerChain,
            IClientChannelSinkProvider provider)
        {
            if (providerChain == null)
                throw new ArgumentNullException("providerChain");
 
            // walk to last provider in chain
            while (providerChain.Next != null)
            {
                providerChain = providerChain.Next;
            }
 
            providerChain.Next = provider;
        } // AppendProviderToClientProviderChain
 
        internal static void CollectChannelDataFromServerSinkProviders(
            ChannelDataStore channelData,
            IServerChannelSinkProvider provider)
        {
            // walk chain and ask each provider for channel data
            while (provider != null)
            {
                provider.GetChannelData(channelData);
            
                provider = provider.Next;
            }
        } // CollectChannelDataFromServerSinkProviders
 
 
        // called by providers that aren't expecting custom provider data
        internal static void VerifyNoProviderData(String providerTypeName, ICollection providerData)
        {
            if ((providerData != null) && (providerData.Count > 0))
            {
                throw new RemotingException(
                    String.Format(
                        CultureInfo.CurrentCulture, CoreChannel.GetResourceString(
                            "Remoting_Providers_Config_NotExpectingProviderData"),
                        providerTypeName));
            }                    
        } // VerifyNoProviderData
 
        internal static void ReportUnknownProviderConfigProperty(String providerTypeName,
                                                                 String propertyName)
        {
            throw new RemotingException(
                String.Format(
                    CultureInfo.CurrentCulture, CoreChannel.GetResourceString(
                        "Remoting_Providers_Config_UnknownProperty"),
                    providerTypeName, propertyName));
        } // ReportUnknownProviderConfigProperty
 
 
 
        internal static SinkChannelProtocol DetermineChannelProtocol(IChannel channel)
        {
            String objectUri;
            String channelUri = channel.Parse("http://foo.com/foo", out objectUri);
            if (channelUri != null)
                return SinkChannelProtocol.Http;
 
            return SinkChannelProtocol.Other;
        } // DetermineChannelProtocol
 
        // SetupUrlBashingForIisSslIfNecessaryWorker wrapper.
        // Prevents System.Web type load for client sku installations.
        internal static bool SetupUrlBashingForIisSslIfNecessary()
        {
            bool bBashUrl;
 
            if (IsClientSKUInstallation)
            {
                bBashUrl = false;
            }
            else
            {
                bBashUrl = SetupUrlBashingForIisSslIfNecessaryWorker();
            }
 
            return bBashUrl;
        } // SetupUrlBashingForIisSslIfNecessary
 
        [System.Runtime.CompilerServices.MethodImpl(System.Runtime.CompilerServices.MethodImplOptions.NoInlining)]
        internal static bool SetupUrlBashingForIisSslIfNecessaryWorker()
        {
#if FEATURE_PAL
            // Rotor doesn't support SSL.
            return false;
#else
 
            // If the incoming request was IIS ssl we  need to add an 
            // entry to the call context so that the ObjRef knows
            // to Microsoft the channel data.           
            // During serialization when using ssl the ObjRef url
            // must have the host name.
            
            HttpContext httpContext = HttpContext.Current;
            bool bBashUrl = false;
            
            if ((httpContext != null) && httpContext.Request.IsSecureConnection)
            {
                // create new url
                Uri requestUrl = httpContext.Request.Url;                
 
                StringBuilder sb = new StringBuilder(100);
                sb.Append("https://");
                sb.Append(requestUrl.Host);
                sb.Append(":");
                sb.Append(requestUrl.Port);
                sb.Append("/");
                sb.Append(RemotingConfiguration.ApplicationName);
            
                String[] bashInfo = new String[2];
                bashInfo[0] = IisHelper.ApplicationUrl;
                bashInfo[1] = sb.ToString();
                CallContext.SetData("__bashChannelUrl", bashInfo);
                bBashUrl = true;
            }
 
            return bBashUrl;
#endif
        } // SetupUrlBashingForIisSslIfNecessaryWorker
 
        internal static void CleanupUrlBashingForIisSslIfNecessary(bool bBashedUrl)
        {
#if FEATURE_PAL
            return;
#else
            if (bBashedUrl)
                CallContext.FreeNamedDataSlot("__bashChannelUrl");
#endif
        } // CleanupUrlBashingForIisSslIfNecessary
 
#if !FEATURE_PAL
        internal static string GetCurrentSidString() 
        {
            return WindowsIdentity.GetCurrent().User.ToString();
        }
        
        internal static string SidToString(IntPtr sidPointer) 
        {
            if (!NativeMethods.IsValidSid(sidPointer))
                throw new RemotingException(CoreChannel.GetResourceString("Remoting_InvalidSid"));
                
            StringBuilder sidString = new StringBuilder();
            IntPtr sidIdentifierAuthorityPointer = NativeMethods.GetSidIdentifierAuthority(sidPointer);            
            int lastError = Marshal.GetLastWin32Error();                                                                                 
            if (lastError != 0)        
                throw new Win32Exception(lastError);                                                           
            byte[] sidIdentifierAuthority = new byte[6];
            Marshal.Copy(sidIdentifierAuthorityPointer, sidIdentifierAuthority, 0, 6); 
            
            IntPtr subAuthorityCountPointer = NativeMethods.GetSidSubAuthorityCount(sidPointer);                    
            lastError = Marshal.GetLastWin32Error();                                                                                 
            if (lastError != 0)        
                throw new Win32Exception(lastError);                                               
            uint subAuthorityCount = (uint)Marshal.ReadByte(subAuthorityCountPointer);
                    
            if (sidIdentifierAuthority[0] != 0 && sidIdentifierAuthority[1] != 0) 
                sidString.Append(String.Format(CultureInfo.CurrentCulture, "{0:x2}{1:x2}{2:x2}{3:x2}{4:x2}{5:x2}",
                                                            sidIdentifierAuthority[0], 
                                                            sidIdentifierAuthority[1], 
                                                            sidIdentifierAuthority[2], 
                                                            sidIdentifierAuthority[3], 
                                                            sidIdentifierAuthority[4], 
                                                            sidIdentifierAuthority[5]));        
                                                                                                                        
            else 
            {
                uint number = (uint)sidIdentifierAuthority[5] +
                                    (uint)(sidIdentifierAuthority[4] << 8) +
                                    (uint)(sidIdentifierAuthority[3] << 16) +
                                    (uint)(sidIdentifierAuthority[2] << 24) ;
                
                sidString.Append(String.Format(CultureInfo.CurrentCulture, "{0:x12}", number)); 
            }            
                
            for (int index = 0; index < subAuthorityCount; ++index) 
            {
                IntPtr subAuthorityPointer = NativeMethods.GetSidSubAuthority(sidPointer, index);
                lastError = Marshal.GetLastWin32Error();                                                                                 
                if (lastError != 0)        
                    throw new Win32Exception(lastError);                                               
                    
                uint number = (uint)Marshal.ReadInt32(subAuthorityPointer);                            
                sidString.Append(String.Format(CultureInfo.CurrentCulture, "-{0:x12}", number));
            }                       
            
            return sidString.ToString();
        }    
#endif // !FEATURE_PAL
        
 
        //** Resource helpers ***************************************************
        internal static ResourceManager SystemResMgr;
 
        private static ResourceManager InitResourceManager()
        {
			if (SystemResMgr == null)
                SystemResMgr = new ResourceManager("System.Runtime.Remoting", typeof(CoreChannel).Module.Assembly);
			return SystemResMgr;
        }
 
        // Looks up the resource string value for key.
        // 
        internal static String GetResourceString(String key)
        {
            if (SystemResMgr == null)
                InitResourceManager();
            String s = SystemResMgr.GetString(key, null);
            Debug.Assert(s!=null, "Resource string lookup failed.  Resource name was: \""+key+"\"");
            return s;
        }
    
        //** Debug items ***************************************************
        [Conditional("_DEBUG")]
        internal static void DebugOut(String s)
        {
                InternalRemotingServices.DebugOutChnl(s);
        }
 
        [Conditional("_DEBUG")]
        internal static void DebugOutXMLStream(Stream stm, String tag)
        {
            /*
            This can't be done when using networked streams.
            long oldpos = stm.Position;
            stm.Position=0;
            StreamReader sr = new StreamReader(stm, Encoding.UTF8);
            String line;
            InternalRemotingServices.DebugOutChnl("\n   -----------" + tag + " OPEN-------------\n") ;
            while ((line = sr.ReadLine()) != null)
            {
                InternalRemotingServices.DebugOutChnl(line);
            }
            InternalRemotingServices.DebugOutChnl("\n   -----------" + tag + " CLOSE------------\n") ;
 
            stm.Position = oldpos;
            */
        }
 
        [Conditional("_DEBUG")]
        internal static void DebugMessage(IMessage msg)
        {
            /*
              if (msg is IMethodCallMessage)
                InternalRemotingServices.RemotingTrace("IMethodCallMessage");
                
              if (msg is IMethodReturnMessage)
                InternalRemotingServices.RemotingTrace("IMethodReturnMessage");
        
              if (msg == null)
                InternalRemotingServices.RemotingTrace("***** IMessage is null");
        
              InternalRemotingServices.RemotingTrace("DebugMessage Here");
              IDictionary d = msg.Properties;
              if (d == null)
                InternalRemotingServices.RemotingTrace("***** Properties is null");
        
              InternalRemotingServices.RemotingTrace("DebugMessage Here0");      
              if (d.Count == 0)
              {
                  InternalRemotingServices.RemotingTrace("Zero Properties");
                  return;
              }
        
              InternalRemotingServices.RemotingTrace("DebugMessage Here1");
              IDictionaryEnumerator e = (IDictionaryEnumerator) d.GetEnumerator();
              InternalRemotingServices.RemotingTrace("DebugMessage Here1");
        
              while (e.MoveNext())
              {
                InternalRemotingServices.RemotingTrace("DebugMessage Here2");
        
                Object key = e.Key;
                
                InternalRemotingServices.RemotingTrace("DebugMessage Here3");
        
                String keyName = key.ToString();
        
                InternalRemotingServices.RemotingTrace("DebugMessage Here4");
        
                Object value = e.Value;
        
                InternalRemotingServices.RemotingTrace("DebugMessage Here5");
        
                InternalRemotingServices.RemotingTrace(keyName + ":" + e.Value);
        
                InternalRemotingServices.RemotingTrace("DebugMessage Here6");
        
                if (String.Compare(keyName, "__CallContext", StringComparison.OrdinalIgnoreCase) == 0)
                {
                }
                
                InternalRemotingServices.RemotingTrace("DebugMessage Here7");
              }
              */
        }
 
        [Conditional("_DEBUG")]
        internal static void DebugException(String name, Exception e)
        {
            InternalRemotingServices.RemotingTrace("****************************************************\r\n");
            InternalRemotingServices.RemotingTrace("EXCEPTION THROWN!!!!!! - " + name);
            InternalRemotingServices.RemotingTrace("\r\n");
 
            InternalRemotingServices.RemotingTrace(e.Message);
            InternalRemotingServices.RemotingTrace("\r\n");
 
            InternalRemotingServices.RemotingTrace(e.GetType().FullName);
            InternalRemotingServices.RemotingTrace("\r\n");
 
            InternalRemotingServices.RemotingTrace(e.StackTrace);
            InternalRemotingServices.RemotingTrace("\r\n");
            InternalRemotingServices.RemotingTrace("****************************************************\r\n");
        }
 
        [Conditional("_DEBUG")]
        internal static void DebugStream(Stream stm)
        {
            /*
              try
              {
                long Position = stm.Position;
        
                MemoryStream memStm = (MemoryStream)stm;
                byte[] byteArray = memStm.ToArray();
                int byteArrayLength = byteArray.Length;
                String streamString = Encoding.ASCII.GetString(byteArray,0, byteArrayLength);
                InternalRemotingServices.RemotingTrace(streamString);
                stm.Position = Position;
              }
              catch(Exception e)
              {
                DebugException("DebugStream", e);
              }
              */
        }
 
    } // class CoreChannel
 
 
#if !FEATURE_PAL
    internal static class IisHelper
    {
        private static bool _bIsSslRequired = false;
        private static String _iisAppUrl = null;
        
        internal static void Initialize()
        {
            // NOTE!!!: This is only called from the synchronized initialization
            //   stage in HTTP remoting handler.
            try
            {
                HttpRequest request = HttpContext.Current.Request;
                String mdPath = request.ServerVariables["APPL_MD_PATH"];
    
                bool bSslRequired = false;
                if (mdPath.StartsWith("/LM/", StringComparison.Ordinal))
                {
                    mdPath = "IIS://localhost/" + mdPath.Substring(4);  
                    DirectoryEntry dir = new DirectoryEntry(mdPath);
                    bSslRequired = (bool)dir.Properties["AccessSSL"][0];    
                }
 
                _bIsSslRequired = bSslRequired;
            }
            catch
            {
                // If initialization failed, we just assume that ssl isn't required.
                // This just means that we'll have to manually Microsoft the channel data
                // everytime.         
            }
        } // Initialize
    
        internal static bool IsSslRequired
        {
            get { return _bIsSslRequired; }
        } // IsSslRequired
 
        internal static String ApplicationUrl
        {
            get { return _iisAppUrl; }
 
            set { _iisAppUrl = value; }
        } // ApplicationUrl        
        
    } // class IisHelper
#endif // !FEATURE_PAL   
    
}