1 //------------------------------------------------------------------------------
2 // <copyright file="Internal.cs" company="Microsoft">
3 // Copyright (c) Microsoft Corporation. All rights reserved.
5 //------------------------------------------------------------------------------
9 using System.Reflection;
10 using System.Collections;
11 using System.Collections.Specialized;
12 using System.Globalization;
13 using System.Net.Sockets;
14 using System.Net.WebSockets;
15 using System.Runtime.InteropServices;
16 using System.Runtime.Versioning;
17 using System.Security.Authentication.ExtendedProtection;
18 using System.Security.Cryptography.X509Certificates;
19 using System.Security.Permissions;
20 using System.Diagnostics;
21 using System.Threading;
22 using System.Security;
23 using System.Net.Security;
24 using System.Net.NetworkInformation;
25 using System.Runtime.Serialization;
26 using Microsoft.Win32;
27 using System.Collections.Generic;
29 internal static class IntPtrHelper {
32 internal static IntPtr Add(IntPtr a, IntPtr b) {
33 return (IntPtr) ((long)a + (long)b);
36 internal static IntPtr Add(IntPtr a, int b) {
37 return (IntPtr) ((long)a + (long)b);
40 internal static long Subtract(IntPtr a, IntPtr b) {
41 return ((long)a - (long)b);
45 internal class InternalException : SystemException
47 internal InternalException()
49 GlobalLog.Assert("InternalException thrown.");
52 internal InternalException(SerializationInfo serializationInfo, StreamingContext streamingContext) :
53 base(serializationInfo, streamingContext)
57 internal static class NclUtilities
61 /// Indicates true if the threadpool is low on threads,
62 /// in this case we need to refuse to start new requests,
63 /// and avoid blocking.
66 internal static bool IsThreadPoolLow()
69 if (ComNetOS.IsAspNetServer)
75 int workerThreads, completionPortThreads;
76 ThreadPool.GetAvailableThreads(out workerThreads, out completionPortThreads);
79 return workerThreads < 2 || (completionPortThreads < 2);
81 GlobalLog.Assert(completionPortThreads == 0, "completionPortThreads should be zero on the PAL");
82 return workerThreads < 2;
87 internal static bool HasShutdownStarted
91 return Environment.HasShutdownStarted || AppDomain.CurrentDomain.IsFinalizingForUnload();
95 // This only works for context-destroying errors.
96 internal static bool IsCredentialFailure(SecurityStatus error)
98 return error == SecurityStatus.LogonDenied ||
99 error == SecurityStatus.UnknownCredentials ||
100 error == SecurityStatus.NoImpersonation ||
101 error == SecurityStatus.NoAuthenticatingAuthority ||
102 error == SecurityStatus.UntrustedRoot ||
103 error == SecurityStatus.CertExpired ||
104 error == SecurityStatus.SmartcardLogonRequired ||
105 error == SecurityStatus.BadBinding;
108 // This only works for context-destroying errors.
109 internal static bool IsClientFault(SecurityStatus error)
111 return error == SecurityStatus.InvalidToken ||
112 error == SecurityStatus.CannotPack ||
113 error == SecurityStatus.QopNotSupported ||
114 error == SecurityStatus.NoCredentials ||
115 error == SecurityStatus.MessageAltered ||
116 error == SecurityStatus.OutOfSequence ||
117 error == SecurityStatus.IncompleteMessage ||
118 error == SecurityStatus.IncompleteCredentials ||
119 error == SecurityStatus.WrongPrincipal ||
120 error == SecurityStatus.TimeSkew ||
121 error == SecurityStatus.IllegalMessage ||
122 error == SecurityStatus.CertUnknown ||
123 error == SecurityStatus.AlgorithmMismatch ||
124 error == SecurityStatus.SecurityQosFailed ||
125 error == SecurityStatus.UnsupportedPreauth;
129 // ContextRelativeDemand
130 // Allows easily demanding a permission against a given ExecutionContext.
131 // Have requested the CLR to provide this method on ExecutionContext.
132 private static volatile ContextCallback s_ContextRelativeDemandCallback;
134 internal static ContextCallback ContextRelativeDemandCallback
138 if (s_ContextRelativeDemandCallback == null)
139 s_ContextRelativeDemandCallback = new ContextCallback(DemandCallback);
140 return s_ContextRelativeDemandCallback;
144 private static void DemandCallback(object state)
146 ((CodeAccessPermission) state).Demand();
149 // This is for checking if a hostname probably refers to this machine without going to DNS.
150 internal static bool GuessWhetherHostIsLoopback(string host)
152 string hostLower = host.ToLowerInvariant();
153 if (hostLower == "localhost" || hostLower == "loopback")
159 IPGlobalProperties ip = IPGlobalProperties.InternalGetIPGlobalProperties();
160 string hostnameLower = ip.HostName.ToLowerInvariant();
161 return hostLower == hostnameLower || hostLower == hostnameLower + "." + ip.DomainName.ToLowerInvariant();
167 internal static bool IsFatal(Exception exception)
169 return exception != null && (exception is OutOfMemoryException || exception is StackOverflowException || exception is ThreadAbortException);
172 // Need a fast cached list of local addresses for internal use.
173 private static volatile IPAddress[] _LocalAddresses;
174 private static object _LocalAddressesLock;
178 private static volatile NetworkAddressChangePolled s_AddressChange;
180 internal static IPAddress[] LocalAddresses
184 if (s_AddressChange != null && s_AddressChange.CheckAndReset())
186 return (_LocalAddresses = GetLocalAddresses());
189 if (_LocalAddresses != null)
191 return _LocalAddresses;
194 lock (LocalAddressesLock)
196 if (_LocalAddresses != null)
198 return _LocalAddresses;
201 s_AddressChange = new NetworkAddressChangePolled();
203 return (_LocalAddresses = GetLocalAddresses());
208 private static IPAddress[] GetLocalAddresses()
212 ArrayList collections = new ArrayList(16);
215 SafeLocalFree buffer = null;
216 GetAdaptersAddressesFlags gaaFlags = GetAdaptersAddressesFlags.SkipAnycast | GetAdaptersAddressesFlags.SkipMulticast |
217 GetAdaptersAddressesFlags.SkipFriendlyName | GetAdaptersAddressesFlags.SkipDnsServer;
219 uint result = UnsafeNetInfoNativeMethods.GetAdaptersAddresses(AddressFamily.Unspecified, (uint)gaaFlags, IntPtr.Zero, SafeLocalFree.Zero, ref size);
220 while (result == IpHelperErrors.ErrorBufferOverflow)
224 buffer = SafeLocalFree.LocalAlloc((int)size);
225 result = UnsafeNetInfoNativeMethods.GetAdaptersAddresses(AddressFamily.Unspecified, (uint)gaaFlags, IntPtr.Zero, buffer, ref size);
227 if (result == IpHelperErrors.Success)
229 IntPtr nextAdapter = buffer.DangerousGetHandle();
231 while (nextAdapter != IntPtr.Zero)
233 IpAdapterAddresses adapterAddresses = (IpAdapterAddresses)Marshal.PtrToStructure(
234 nextAdapter, typeof(IpAdapterAddresses));
236 if (adapterAddresses.firstUnicastAddress != IntPtr.Zero)
238 UnicastIPAddressInformationCollection coll =
239 SystemUnicastIPAddressInformation.MarshalUnicastIpAddressInformationCollection(
240 adapterAddresses.firstUnicastAddress);
242 collections.Add(coll);
245 nextAdapter = adapterAddresses.next;
257 if (result != IpHelperErrors.Success && result != IpHelperErrors.ErrorNoData)
259 throw new NetworkInformationException((int)result);
262 local = new IPAddress[total];
264 foreach (UnicastIPAddressInformationCollection coll in collections)
266 foreach (IPAddressInformation info in coll)
268 local[i++] = info.Address;
275 internal static bool IsAddressLocal(IPAddress ipAddress) {
276 IPAddress[] localAddresses = NclUtilities.LocalAddresses;
277 for (int i = 0; i < localAddresses.Length; i++)
279 if (ipAddress.Equals(localAddresses[i], false))
287 #else // !FEATURE_PAL
289 internal static bool IsAddressLocal(IPAddress ipAddress) {
290 IPAddress[] localAddresses = NclUtilities.LocalAddresses;
291 for (int i = 0; i < localAddresses.Length; i++)
293 if (ipAddress.Equals(localAddresses[i], false))
301 private const int HostNameBufferLength = 256;
302 internal static string _LocalDomainName;
304 // Copied from the old version of DNS.cs
305 // Returns a list of our local addresses by calling gethostbyname with null.
307 private static IPHostEntry GetLocalHost()
310 return Dns.GetHostByName (Dns.GetHostName ());
313 // IPv6 Changes: If IPv6 is enabled, we can't simply use the
314 // old IPv4 gethostbyname(null). Instead we need
315 // to do a more complete lookup.
317 if (Socket.SupportsIPv6)
320 // IPv6 enabled: use getaddrinfo() of the local host name
321 // to obtain this information. Need to get the machines
322 // name as well - do that here so that we don't need to
323 // Assert DNS permissions.
325 StringBuilder hostname = new StringBuilder(HostNameBufferLength);
326 SocketError errorCode =
327 UnsafeNclNativeMethods.OSSOCK.gethostname(
329 HostNameBufferLength);
331 if (errorCode != SocketError.Success)
333 throw new SocketException();
336 return Dns.GetHostByName(hostname.ToString());
341 // IPv6 disabled: use gethostbyname() to obtain information.
343 IntPtr nativePointer =
344 UnsafeNclNativeMethods.OSSOCK.gethostbyname(
347 if (nativePointer == IntPtr.Zero)
349 throw new SocketException();
352 return Dns.NativeToHostEntry(nativePointer);
358 internal static IPAddress[] LocalAddresses
362 IPAddress[] local = _LocalAddresses;
368 lock (LocalAddressesLock)
370 local = _LocalAddresses;
376 List<IPAddress> localList = new List<IPAddress>();
380 IPHostEntry hostEntry = GetLocalHost();
381 if (hostEntry != null)
383 if (hostEntry.HostName != null)
385 int dot = hostEntry.HostName.IndexOf('.');
388 _LocalDomainName = hostEntry.HostName.Substring(dot);
392 IPAddress[] ipAddresses = hostEntry.AddressList;
393 if (ipAddresses != null)
395 foreach (IPAddress ipAddress in ipAddresses)
397 localList.Add(ipAddress);
406 local = new IPAddress[localList.Count];
408 foreach (IPAddress ipAddress in localList)
410 local[index] = ipAddress;
413 _LocalAddresses = local;
419 #endif // !FEATURE_PAL
421 private static object LocalAddressesLock
425 if (_LocalAddressesLock == null)
427 Interlocked.CompareExchange(ref _LocalAddressesLock, new object(), null);
429 return _LocalAddressesLock;
434 internal static class NclConstants
436 internal static readonly object Sentinel = new object();
437 internal static readonly object[] EmptyObjectArray = new object[0];
438 internal static readonly Uri[] EmptyUriArray = new Uri[0];
440 internal static readonly byte[] CRLF = new byte[] {(byte) '\r', (byte) '\n'};
441 internal static readonly byte[] ChunkTerminator = new byte[] {(byte) '0', (byte) '\r', (byte) '\n', (byte) '\r', (byte) '\n'};
445 // A simple [....] point, useful for deferring work. Just an int value with helper methods.
446 // This is used by HttpWebRequest to syncronize Reads/Writes while waiting for a 100-Continue response.
448 internal struct InterlockedGate
452 // Not currently waiting for a response
453 internal const int Open = 0; // Initial state of gate.
454 // Starting the timer to wait for a response (async)
455 internal const int Triggering = 1; // Gate is being actively held by a thread - indeterminate state.
456 // Waiting for response
457 internal const int Triggered = 2; // The triggering event has occurred.
458 // Stopping the timer (got a response or timed out)
459 internal const int Signaling = 3;
460 // Got a response or timed out, may process the response.
461 internal const int Signaled = 4;
462 // Re/submitting data.
463 internal const int Completed = 5; // The gated event is done.
477 // Only call when all threads are guaranteed to be done with the gate.
478 internal void Reset()
483 // Returns false if the gate is not taken. If exclusive is true, throws if the gate is already triggered.
484 internal bool Trigger(bool exclusive)
486 int gate = Interlocked.CompareExchange(ref m_State, Triggered, Open);
487 if (exclusive && (gate == Triggering || gate == Triggered))
489 GlobalLog.Assert("InterlockedGate::Trigger", "Gate already triggered.");
490 throw new InternalException();
495 // Use StartTrigger() and FinishTrigger() to trigger the gate as a two step operation. This is useful to set up an invariant
496 // that must be ready by the time another thread closes the gate. Do not block between StartTrigger() and FinishTrigger(), just
497 // set up your state to be consistent. If this method returns true, FinishTrigger() *must* be called to avoid deadlock - do
500 // Returns false if the gate is not taken. If exclusive is true, throws if the gate is already triggering/ed.
501 internal bool StartTriggering(bool exclusive)
503 int gate = Interlocked.CompareExchange(ref m_State, Triggering, Open);
504 if (exclusive && (gate == Triggering || gate == Triggered))
506 GlobalLog.Assert("InterlockedGate::StartTriggering", "Gate already triggered.");
507 throw new InternalException();
512 // Gate must be held by StartTriggering().
513 internal void FinishTriggering()
515 int gate = Interlocked.CompareExchange(ref m_State, Triggered, Triggering);
516 if (gate != Triggering)
518 GlobalLog.Assert("InterlockedGate::FinishTriggering", "Gate not Triggering.");
519 throw new InternalException();
523 // Use StartSignaling() and FinishSignaling() to signal the gate as a two step operation. This is useful to
524 // set up an invariant that must be ready by the time another thread closes the gate. Do not block between
525 // StartSignaling() and FinishSignaling(), just set up your state to be consistent. If this method returns
526 // true, FinishSignaling() *must* be called to avoid deadlock - do it in a finally.
528 // Returns false if the gate is not taken. If exclusive is true, throws if the gate is already Signaling/ed.
529 internal bool StartSignaling(bool exclusive)
531 int gate = Interlocked.CompareExchange(ref m_State, Signaling, Triggered);
532 if (exclusive && (gate == Signaling || gate == Signaled)) //
534 GlobalLog.Assert("InterlockedGate::StartTrigger", "Gate already Signaled.");
535 throw new InternalException();
537 Debug.Assert(gate != Triggering, "Still Triggering");
538 return gate == Triggered;
541 // Gate must be held by StartSignaling().
542 internal void FinishSignaling()
544 int gate = Interlocked.CompareExchange(ref m_State, Signaled, Signaling);
545 if (gate != Signaling)
547 GlobalLog.Assert("InterlockedGate::FinishSignaling", "Gate not Signaling; " + gate);
548 throw new InternalException();
552 // Makes sure only one thread completes the opperation.
553 internal bool Complete()
555 int gate = Interlocked.CompareExchange(ref m_State, Completed, Signaled);
556 Debug.Assert(gate != Signaling, "Still Signaling");
557 return (gate == Signaled);
563 // A polling implementation of NetworkAddressChange.
565 internal class NetworkAddressChangePolled : IDisposable
567 private bool disposed;
568 private SafeCloseSocketAndEvent ipv4Socket = null;
569 private SafeCloseSocketAndEvent ipv6Socket = null;
572 internal unsafe NetworkAddressChangePolled()
574 Socket.InitializeSockets();
576 if (Socket.OSSupportsIPv4)
579 ipv4Socket = SafeCloseSocketAndEvent.CreateWSASocketWithEvent(AddressFamily.InterNetwork, SocketType.Dgram, (ProtocolType)0, true, false);
580 UnsafeNclNativeMethods.OSSOCK.ioctlsocket(ipv4Socket, IoctlSocketConstants.FIONBIO, ref blocking);
583 if(Socket.OSSupportsIPv6){
585 ipv6Socket = SafeCloseSocketAndEvent.CreateWSASocketWithEvent(AddressFamily.InterNetworkV6, SocketType.Dgram, (ProtocolType)0, true, false);
586 UnsafeNclNativeMethods.OSSOCK.ioctlsocket(ipv6Socket,IoctlSocketConstants.FIONBIO,ref blocking);
588 Setup(StartIPOptions.Both);
591 private unsafe void Setup(StartIPOptions startIPOptions)
594 SocketError errorCode;
597 if (Socket.OSSupportsIPv4 && (startIPOptions & StartIPOptions.StartIPv4) != 0){
598 errorCode = (SocketError)UnsafeNclNativeMethods.OSSOCK.WSAIoctl_Blocking(
599 ipv4Socket.DangerousGetHandle(),
600 (int) IOControlCode.AddressListChange,
603 SafeNativeOverlapped.Zero, IntPtr.Zero);
605 if (errorCode != SocketError.Success) {
606 NetworkInformationException exception = new NetworkInformationException();
607 if (exception.ErrorCode != (uint)SocketError.WouldBlock) {
613 errorCode = (SocketError)UnsafeNclNativeMethods.OSSOCK.WSAEventSelect(ipv4Socket, ipv4Socket.GetEventHandle().SafeWaitHandle, AsyncEventBits.FdAddressListChange);
614 if (errorCode != SocketError.Success) {
620 if(Socket.OSSupportsIPv6 && (startIPOptions & StartIPOptions.StartIPv6) !=0){
621 errorCode = (SocketError) UnsafeNclNativeMethods.OSSOCK.WSAIoctl_Blocking(
622 ipv6Socket.DangerousGetHandle(),
623 (int) IOControlCode.AddressListChange,
626 SafeNativeOverlapped.Zero, IntPtr.Zero);
628 if (errorCode != SocketError.Success) {
629 NetworkInformationException exception = new NetworkInformationException();
630 if (exception.ErrorCode != (uint)SocketError.WouldBlock) {
636 errorCode = (SocketError)UnsafeNclNativeMethods.OSSOCK.WSAEventSelect(ipv6Socket, ipv6Socket.GetEventHandle().SafeWaitHandle, AsyncEventBits.FdAddressListChange);
637 if (errorCode != SocketError.Success) {
644 internal bool CheckAndReset()
649 StartIPOptions options = StartIPOptions.None;
651 if (ipv4Socket != null && ipv4Socket.GetEventHandle().WaitOne(0, false)){
652 options|= StartIPOptions.StartIPv4;
654 if (ipv6Socket != null && ipv6Socket.GetEventHandle().WaitOne(0, false))
656 options|= StartIPOptions.StartIPv6;
659 if(options != StartIPOptions.None){
669 public void Dispose()
674 if(ipv6Socket != null){
678 if(ipv4Socket != null){
688 #endif // FEATURE_PAL
693 internal static class ComNetOS
695 private const string OSInstallTypeRegKey = @"Software\Microsoft\Windows NT\CurrentVersion";
696 private const string OSInstallTypeRegKeyPath = @"HKEY_LOCAL_MACHINE\" + OSInstallTypeRegKey;
697 private const string OSInstallTypeRegName = "InstallationType";
698 private const string InstallTypeStringClient = "Client";
699 private const string InstallTypeStringServer = "Server";
700 private const string InstallTypeStringServerCore = "Server Core";
701 private const string InstallTypeStringEmbedded = "Embedded";
703 // Minimum support for Windows 2008 is assumed.
704 internal static readonly bool IsAspNetServer; // ie: running under ASP+
705 internal static readonly bool IsWin7orLater; // Is Windows 7 or later
706 internal static readonly bool IsWin7Sp1orLater; // Is Windows 7 Sp1 or later (2008 R2 Sp1+)
707 internal static readonly bool IsWin8orLater; // Is Windows 8 or later
708 internal static readonly WindowsInstallationType InstallationType; // e.g. Client, Server, Server Core
710 // We use it safe so assert
711 [EnvironmentPermission(SecurityAction.Assert, Unrestricted = true)]
712 [ResourceExposure(ResourceScope.None)]
713 [ResourceConsumption(ResourceScope.AppDomain, ResourceScope.AppDomain)]
716 OperatingSystem operatingSystem = Environment.OSVersion;
718 GlobalLog.Print("ComNetOS::.ctor(): " + operatingSystem.ToString());
720 Debug.Assert(operatingSystem.Platform != PlatformID.Win32Windows, "Windows 9x is not supported");
723 // Detect ASP+ as a platform running under NT
728 IsAspNetServer = (Thread.GetDomain().GetData(".appDomain") != null);
732 IsWin7orLater = (operatingSystem.Version >= new Version(6, 1));
734 IsWin7Sp1orLater = (operatingSystem.Version >= new Version(6, 1, 7601));
736 IsWin8orLater = (operatingSystem.Version >= new Version(6, 2));
738 InstallationType = GetWindowsInstallType();
739 if (Logging.On) Logging.PrintInfo(Logging.Web, SR.GetString(SR.net_osinstalltype, InstallationType));
742 [RegistryPermission(SecurityAction.Assert, Read = OSInstallTypeRegKeyPath)]
743 private static WindowsInstallationType GetWindowsInstallType()
747 using (RegistryKey installTypeKey = Registry.LocalMachine.OpenSubKey(OSInstallTypeRegKey))
749 string installType = installTypeKey.GetValue(OSInstallTypeRegName) as string;
751 if (string.IsNullOrEmpty(installType))
753 if (Logging.On) Logging.PrintWarning(Logging.Web, SR.GetString(SR.net_empty_osinstalltype, OSInstallTypeRegKey + "\\" + OSInstallTypeRegName));
754 return WindowsInstallationType.Unknown;
758 if (String.Compare(installType, InstallTypeStringClient, StringComparison.OrdinalIgnoreCase) == 0)
760 return WindowsInstallationType.Client;
762 if (String.Compare(installType, InstallTypeStringServer, StringComparison.OrdinalIgnoreCase) == 0)
764 return WindowsInstallationType.Server;
766 if (String.Compare(installType, InstallTypeStringServerCore, StringComparison.OrdinalIgnoreCase) == 0)
768 return WindowsInstallationType.ServerCore;
770 if (String.Compare(installType, InstallTypeStringEmbedded, StringComparison.OrdinalIgnoreCase) == 0)
772 return WindowsInstallationType.Embedded;
775 if (Logging.On) Logging.PrintError(Logging.Web, SR.GetString(SR.net_unknown_osinstalltype, installType));
777 // Our default return is unknown when we don't recognize the SKU or if the registry value
778 // doesn't exist. As a result, the SKU-specific checks in System.Net will not limit the set
779 // of functionality available. This allows SKUs we are not aware of to use all of our
780 // functionality. Burden is on them to ensure that all our dependencies are present.
781 // The alternative would be for us to throw an exception here. If we did this, these other
782 // SKUs wouldn't be able to load this code and test their behavior. We would need to update
783 // this code to enable them to run.
784 return WindowsInstallationType.Unknown;
788 catch (UnauthorizedAccessException e)
790 if (Logging.On) Logging.PrintWarning(Logging.Web, SR.GetString(SR.net_cant_determine_osinstalltype, OSInstallTypeRegKey, e.Message));
791 return WindowsInstallationType.Unknown;
793 catch (SecurityException e)
795 if (Logging.On) Logging.PrintWarning(Logging.Web, SR.GetString(SR.net_cant_determine_osinstalltype, OSInstallTypeRegKey, e.Message));
796 return WindowsInstallationType.Unknown;
804 // support class for Validation related stuff.
806 internal static class ValidationHelper {
808 public static string [] EmptyArray = new string[0];
810 internal static readonly char[] InvalidMethodChars =
818 // invalid characters that cannot be found in a valid method-verb or http header
819 internal static readonly char[] InvalidParamChars =
844 public static string [] MakeEmptyArrayNull(string [] stringArray) {
845 if ( stringArray == null || stringArray.Length == 0 ) {
852 public static string MakeStringNull(string stringValue) {
853 if ( stringValue == null || stringValue.Length == 0) {
861 // Consider removing.
862 public static string MakeStringEmpty(string stringValue) {
863 if ( stringValue == null || stringValue.Length == 0) {
873 // Consider removing.
874 public static int HashCode(object objectValue) {
875 if (objectValue == null) {
878 return objectValue.GetHashCode();
884 public static string ExceptionMessage(Exception exception) {
885 if (exception==null) {
888 if (exception.InnerException==null) {
889 return exception.Message;
891 return exception.Message + " (" + ExceptionMessage(exception.InnerException) + ")";
894 public static string ToString(object objectValue) {
895 if (objectValue == null) {
897 } else if (objectValue is string && ((string)objectValue).Length==0) {
898 return "(string.empty)";
899 } else if (objectValue is Exception) {
900 return ExceptionMessage(objectValue as Exception);
901 } else if (objectValue is IntPtr) {
902 return "0x" + ((IntPtr)objectValue).ToString("x");
904 return objectValue.ToString();
907 public static string HashString(object objectValue) {
908 if (objectValue == null) {
910 } else if (objectValue is string && ((string)objectValue).Length==0) {
911 return "(string.empty)";
913 return objectValue.GetHashCode().ToString(NumberFormatInfo.InvariantInfo);
917 public static bool IsInvalidHttpString(string stringValue) {
918 return stringValue.IndexOfAny(InvalidParamChars)!=-1;
921 public static bool IsBlankString(string stringValue) {
922 return stringValue==null || stringValue.Length==0;
926 // Consider removing.
927 public static bool ValidateUInt32(long address) {
928 // on false, API should throw new ArgumentOutOfRangeException("address");
929 return address>=0x00000000 && address<=0xFFFFFFFF;
933 public static bool ValidateTcpPort(int port) {
934 // on false, API should throw new ArgumentOutOfRangeException("port");
935 return port>=IPEndPoint.MinPort && port<=IPEndPoint.MaxPort;
938 public static bool ValidateRange(int actual, int fromAllowed, int toAllowed) {
939 // on false, API should throw new ArgumentOutOfRangeException("argument");
940 return actual>=fromAllowed && actual<=toAllowed;
944 // Consider removing.
945 public static bool ValidateRange(long actual, long fromAllowed, long toAllowed) {
946 // on false, API should throw new ArgumentOutOfRangeException("argument");
947 return actual>=fromAllowed && actual<=toAllowed;
951 // There are threading tricks a malicious app can use to create an ArraySegment with mismatched
952 // array/offset/count. Copy locally and make sure they're valid before using them.
953 internal static void ValidateSegment(ArraySegment<byte> segment) {
954 if (segment == null || segment.Array == null) {
955 throw new ArgumentNullException("segment");
957 // Length zero is explicitly allowed
958 if (segment.Offset < 0 || segment.Count < 0
959 || segment.Count > (segment.Array.Length - segment.Offset)) {
960 throw new ArgumentOutOfRangeException("segment");
965 internal static class ExceptionHelper
968 internal static readonly KeyContainerPermission KeyContainerPermissionOpen = new KeyContainerPermission(KeyContainerPermissionFlags.Open);
969 internal static readonly WebPermission WebPermissionUnrestricted = new WebPermission(NetworkAccess.Connect);
970 internal static readonly SecurityPermission UnmanagedPermission = new SecurityPermission(SecurityPermissionFlag.UnmanagedCode);
971 internal static readonly SocketPermission UnrestrictedSocketPermission = new SocketPermission(PermissionState.Unrestricted);
972 internal static readonly SecurityPermission InfrastructurePermission = new SecurityPermission(SecurityPermissionFlag.Infrastructure);
973 internal static readonly SecurityPermission ControlPolicyPermission = new SecurityPermission(SecurityPermissionFlag.ControlPolicy);
974 internal static readonly SecurityPermission ControlPrincipalPermission = new SecurityPermission(SecurityPermissionFlag.ControlPrincipal);
976 internal static NotImplementedException MethodNotImplementedException {
978 return new NotImplementedException(SR.GetString(SR.net_MethodNotImplementedException));
982 internal static NotImplementedException PropertyNotImplementedException {
984 return new NotImplementedException(SR.GetString(SR.net_PropertyNotImplementedException));
988 internal static NotSupportedException MethodNotSupportedException {
990 return new NotSupportedException(SR.GetString(SR.net_MethodNotSupportedException));
994 internal static NotSupportedException PropertyNotSupportedException {
996 return new NotSupportedException(SR.GetString(SR.net_PropertyNotSupportedException));
1000 internal static WebException IsolatedException {
1002 return new WebException(NetRes.GetWebStatusString("net_requestaborted", WebExceptionStatus.KeepAliveFailure),WebExceptionStatus.KeepAliveFailure, WebExceptionInternalStatus.Isolated, null);
1006 internal static WebException RequestAbortedException {
1008 return new WebException(NetRes.GetWebStatusString("net_requestaborted", WebExceptionStatus.RequestCanceled), WebExceptionStatus.RequestCanceled);
1012 internal static WebException CacheEntryNotFoundException {
1014 return new WebException(NetRes.GetWebStatusString("net_requestaborted", WebExceptionStatus.CacheEntryNotFound), WebExceptionStatus.CacheEntryNotFound);
1018 internal static WebException RequestProhibitedByCachePolicyException {
1020 return new WebException(NetRes.GetWebStatusString("net_requestaborted", WebExceptionStatus.RequestProhibitedByCachePolicy), WebExceptionStatus.RequestProhibitedByCachePolicy);
1025 internal enum WindowsInstallationType
1034 internal enum SecurityStatus
1036 // Success / Informational
1038 ContinueNeeded = unchecked((int)0x00090312),
1039 CompleteNeeded = unchecked((int)0x00090313),
1040 CompAndContinue = unchecked((int)0x00090314),
1041 ContextExpired = unchecked((int)0x00090317),
1042 CredentialsNeeded = unchecked((int)0x00090320),
1043 Renegotiate = unchecked((int)0x00090321),
1046 OutOfMemory = unchecked((int)0x80090300),
1047 InvalidHandle = unchecked((int)0x80090301),
1048 Unsupported = unchecked((int)0x80090302),
1049 TargetUnknown = unchecked((int)0x80090303),
1050 InternalError = unchecked((int)0x80090304),
1051 PackageNotFound = unchecked((int)0x80090305),
1052 NotOwner = unchecked((int)0x80090306),
1053 CannotInstall = unchecked((int)0x80090307),
1054 InvalidToken = unchecked((int)0x80090308),
1055 CannotPack = unchecked((int)0x80090309),
1056 QopNotSupported = unchecked((int)0x8009030A),
1057 NoImpersonation = unchecked((int)0x8009030B),
1058 LogonDenied = unchecked((int)0x8009030C),
1059 UnknownCredentials = unchecked((int)0x8009030D),
1060 NoCredentials = unchecked((int)0x8009030E),
1061 MessageAltered = unchecked((int)0x8009030F),
1062 OutOfSequence = unchecked((int)0x80090310),
1063 NoAuthenticatingAuthority = unchecked((int)0x80090311),
1064 IncompleteMessage = unchecked((int)0x80090318),
1065 IncompleteCredentials = unchecked((int)0x80090320),
1066 BufferNotEnough = unchecked((int)0x80090321),
1067 WrongPrincipal = unchecked((int)0x80090322),
1068 TimeSkew = unchecked((int)0x80090324),
1069 UntrustedRoot = unchecked((int)0x80090325),
1070 IllegalMessage = unchecked((int)0x80090326),
1071 CertUnknown = unchecked((int)0x80090327),
1072 CertExpired = unchecked((int)0x80090328),
1073 AlgorithmMismatch = unchecked((int)0x80090331),
1074 SecurityQosFailed = unchecked((int)0x80090332),
1075 SmartcardLogonRequired = unchecked((int)0x8009033E),
1076 UnsupportedPreauth = unchecked((int)0x80090343),
1077 BadBinding = unchecked((int)0x80090346)
1080 internal enum ContentTypeValues {
1081 ChangeCipherSpec = 0x14,
1085 Unrecognized = 0xFF,
1088 internal enum ContextAttribute {
1090 // look into <sspi.h> and <schannel.h>
1097 //KeyInfo = 0x05, must not be used, see ConnectionInfo instead
1099 // SECPKG_ATTR_PROTO_INFO = 7,
1100 // SECPKG_ATTR_PASSWORD_EXPIRY = 8,
1101 // SECPKG_ATTR_SESSION_KEY = 9,
1103 // SECPKG_ATTR_USER_FLAGS = 11,
1104 NegotiationInfo = 0x0C,
1105 // SECPKG_ATTR_NATIVE_NAMES = 13,
1106 // SECPKG_ATTR_FLAGS = 14,
1107 // SECPKG_ATTR_USE_VALIDATED = 15,
1108 // SECPKG_ATTR_CREDENTIAL_NAME = 16,
1109 // SECPKG_ATTR_TARGET_INFORMATION = 17,
1110 // SECPKG_ATTR_ACCESS_TOKEN = 18,
1111 // SECPKG_ATTR_TARGET = 19,
1112 // SECPKG_ATTR_AUTHENTICATION_ID = 20,
1113 UniqueBindings = 0x19,
1114 EndpointBindings = 0x1A,
1115 ClientSpecifiedSpn = 0x1B, // SECPKG_ATTR_CLIENT_SPECIFIED_TARGET = 27
1116 RemoteCertificate = 0x53,
1117 LocalCertificate = 0x54,
1119 IssuerListInfoEx = 0x59,
1120 ConnectionInfo = 0x5A,
1121 // SECPKG_ATTR_EAP_KEY_BLOCK 0x5b // returns SecPkgContext_EapKeyBlock
1122 // SECPKG_ATTR_MAPPED_CRED_ATTR 0x5c // returns SecPkgContext_MappedCredAttr
1123 // SECPKG_ATTR_SESSION_INFO 0x5d // returns SecPkgContext_SessionInfo
1124 // SECPKG_ATTR_APP_DATA 0x5e // sets/returns SecPkgContext_SessionAppData
1125 // SECPKG_ATTR_REMOTE_CERTIFICATES 0x5F // returns SecPkgContext_Certificates
1126 // SECPKG_ATTR_CLIENT_CERT_POLICY 0x60 // sets SecPkgCred_ClientCertCtlPolicy
1127 // SECPKG_ATTR_CC_POLICY_RESULT 0x61 // returns SecPkgContext_ClientCertPolicyResult
1128 // SECPKG_ATTR_USE_NCRYPT 0x62 // Sets the CRED_FLAG_USE_NCRYPT_PROVIDER FLAG on cred group
1129 // SECPKG_ATTR_LOCAL_CERT_INFO 0x63 // returns SecPkgContext_CertInfo
1130 // SECPKG_ATTR_CIPHER_INFO 0x64 // returns new CNG SecPkgContext_CipherInfo
1131 // SECPKG_ATTR_EAP_PRF_INFO 0x65 // sets SecPkgContext_EapPrfInfo
1132 // SECPKG_ATTR_SUPPORTED_SIGNATURES 0x66 // returns SecPkgContext_SupportedSignatures
1133 // SECPKG_ATTR_REMOTE_CERT_CHAIN 0x67 // returns PCCERT_CONTEXT
1134 UiInfo = 0x68, // sets SEcPkgContext_UiInfo
1137 internal enum Endianness {
1142 internal enum CredentialUse {
1148 internal enum BufferType {
1157 Padding = 0x09, // non-data padding
1159 ChannelBindings = 0x0E,
1161 ReadOnlyFlag = unchecked((int)0x80000000),
1162 ReadOnlyWithChecksum= 0x10000000
1165 internal enum ChainPolicyType {
1168 Authenticode_TS = 3,
1170 BasicConstraints = 5,
1174 internal enum IgnoreCertProblem {
1175 not_time_valid = 0x00000001,
1176 ctl_not_time_valid = 0x00000002,
1177 not_time_nested = 0x00000004,
1178 invalid_basic_constraints = 0x00000008,
1180 all_not_time_valid =
1182 ctl_not_time_valid |
1185 allow_unknown_ca = 0x00000010,
1186 wrong_usage = 0x00000020,
1187 invalid_name = 0x00000040,
1188 invalid_policy = 0x00000080,
1189 end_rev_unknown = 0x00000100,
1190 ctl_signer_rev_unknown = 0x00000200,
1191 ca_rev_unknown = 0x00000400,
1192 root_rev_unknown = 0x00000800,
1196 ctl_signer_rev_unknown |
1201 ctl_not_time_valid |
1203 invalid_basic_constraints |
1209 ctl_signer_rev_unknown |
1214 internal enum CertUsage {
1215 MatchTypeAnd = 0x00,
1221 [StructLayout(LayoutKind.Sequential)]
1222 internal unsafe struct ChainPolicyParameter {
1224 public uint dwFlags;
1225 public SSL_EXTRA_CERT_CHAIN_POLICY_PARA* pvExtraPolicyPara;
1227 public static readonly uint StructSize = (uint) Marshal.SizeOf(typeof(ChainPolicyParameter));
1230 [StructLayout(LayoutKind.Sequential)]
1231 internal unsafe struct SSL_EXTRA_CERT_CHAIN_POLICY_PARA {
1233 [StructLayout(LayoutKind.Explicit)]
1235 [FieldOffset(0)] internal uint cbStruct; //DWORD
1236 [FieldOffset(0)] internal uint cbSize; //DWORD
1239 internal int dwAuthType; //DWORD
1240 internal uint fdwChecks; //DWORD
1241 internal char* pwszServerName; //WCHAR* // used to check against CN=xxxx
1243 internal SSL_EXTRA_CERT_CHAIN_POLICY_PARA(bool amIServer)
1245 u.cbStruct = StructSize;
1246 u.cbSize = StructSize;
1247 //# define AUTHTYPE_CLIENT 1
1248 //# define AUTHTYPE_SERVER 2
1249 dwAuthType = amIServer? 1: 2;
1251 pwszServerName = null;
1253 static readonly uint StructSize = (uint) Marshal.SizeOf(typeof(SSL_EXTRA_CERT_CHAIN_POLICY_PARA));
1256 [StructLayout(LayoutKind.Sequential)]
1257 internal unsafe struct ChainPolicyStatus {
1259 public uint dwError;
1260 public uint lChainIndex;
1261 public uint lElementIndex;
1262 public void* pvExtraPolicyStatus;
1264 public static readonly uint StructSize = (uint) Marshal.SizeOf(typeof(ChainPolicyStatus));
1267 [StructLayout(LayoutKind.Sequential)]
1268 internal unsafe struct CertEnhKeyUse {
1270 public uint cUsageIdentifier;
1271 public void* rgpszUsageIdentifier;
1274 public override string ToString() {
1275 return "cUsageIdentifier="+cUsageIdentifier.ToString()+ " rgpszUsageIdentifier=" + new IntPtr(rgpszUsageIdentifier).ToString("x");
1280 [StructLayout(LayoutKind.Sequential)]
1281 internal struct CertUsageMatch {
1282 public CertUsage dwType;
1283 public CertEnhKeyUse Usage;
1285 public override string ToString() {
1286 return "dwType="+dwType.ToString()+" "+Usage.ToString();
1291 [StructLayout(LayoutKind.Sequential)]
1292 internal struct ChainParameters {
1294 public CertUsageMatch RequestedUsage;
1295 public CertUsageMatch RequestedIssuancePolicy;
1296 public uint UrlRetrievalTimeout;
1297 public int BoolCheckRevocationFreshnessTime;
1298 public uint RevocationFreshnessTime;
1301 public static readonly uint StructSize = (uint) Marshal.SizeOf(typeof(ChainParameters));
1303 public override string ToString() {
1304 return "cbSize="+cbSize.ToString()+" "+RequestedUsage.ToString();
1309 [StructLayout(LayoutKind.Sequential)]
1310 struct _CERT_CHAIN_ELEMENT
1313 public IntPtr pCertContext;
1314 // Since this structure is allocated by unmanaged code, we can
1315 // omit the fileds below since we don't need to access them
1316 // CERT_TRUST_STATUS TrustStatus;
1317 // IntPtr pRevocationInfo;
1318 // IntPtr pIssuanceUsage;
1319 // IntPtr pApplicationUsage;
1323 //[StructLayout(LayoutKind.Sequential)]
1324 //unsafe struct CryptoBlob {
1325 // // public uint cbData;
1326 // // public byte* pbData;
1327 // public uint dataSize;
1328 // public byte* dataBlob;
1331 // SecPkgContext_IssuerListInfoEx
1332 [StructLayout(LayoutKind.Sequential)]
1333 unsafe struct IssuerListInfoEx {
1334 public SafeHandle aIssuers;
1335 public uint cIssuers;
1337 public unsafe IssuerListInfoEx(SafeHandle handle, byte[] nativeBuffer) {
1339 fixed(byte* voidPtr = nativeBuffer) {
1340 // if this breaks on 64 bit, do the sizeof(IntPtr) trick
1341 cIssuers = *((uint*)(voidPtr + IntPtr.Size));
1347 [StructLayout(LayoutKind.Sequential)]
1348 internal struct SecureCredential {
1351 typedef struct _SCHANNEL_CRED
1353 DWORD dwVersion; // always SCHANNEL_CRED_VERSION
1355 PCCERT_CONTEXT *paCred;
1356 HCERTSTORE hRootStore;
1359 struct _HMAPPER **aphMappers;
1361 DWORD cSupportedAlgs;
1362 ALG_ID * palgSupportedAlgs;
1364 DWORD grbitEnabledProtocols;
1365 DWORD dwMinimumCipherStrength;
1366 DWORD dwMaximumCipherStrength;
1367 DWORD dwSessionLifespan;
1370 } SCHANNEL_CRED, *PSCHANNEL_CRED;
1373 public const int CurrentVersion = 0x4;
1378 // ptr to an array of pointers
1379 // There is a hack done with this field. AcquireCredentialsHandle requires an array of
1380 // certificate handles; we only ever use one. In order to avoid pinning a one element array,
1381 // we copy this value onto the stack, create a pointer on the stack to the copied value,
1382 // and replace this field with the pointer, during the call to AcquireCredentialsHandle.
1383 // Then we fix it up afterwards. Fine as long as all the SSPI credentials are not
1384 // supposed to be threadsafe.
1385 public IntPtr certContextArray;
1387 private readonly IntPtr rootStore; // == always null, OTHERWISE NOT RELIABLE
1388 public int cMappers;
1389 private readonly IntPtr phMappers; // == always null, OTHERWISE NOT RELIABLE
1390 public int cSupportedAlgs;
1391 private readonly IntPtr palgSupportedAlgs; // == always null, OTHERWISE NOT RELIABLE
1392 public SchProtocols grbitEnabledProtocols;
1393 public int dwMinimumCipherStrength;
1394 public int dwMaximumCipherStrength;
1395 public int dwSessionLifespan;
1396 public SecureCredential.Flags dwFlags;
1397 public int reserved;
1402 NoSystemMapper = 0x02,
1404 ValidateManual = 0x08,
1405 NoDefaultCred = 0x10,
1406 ValidateAuto = 0x20,
1407 UseStrongCrypto = 0x00400000,
1410 public SecureCredential(int version, X509Certificate certificate, SecureCredential.Flags flags, SchProtocols protocols, EncryptionPolicy policy) {
1411 // default values required for a struct
1412 rootStore = phMappers = palgSupportedAlgs = certContextArray = IntPtr.Zero;
1413 cCreds = cMappers = cSupportedAlgs = 0;
1415 if (policy == EncryptionPolicy.RequireEncryption) {
1416 // Prohibit null encryption cipher
1417 dwMinimumCipherStrength = 0;
1418 dwMaximumCipherStrength = 0;
1420 else if (policy == EncryptionPolicy.AllowNoEncryption) {
1421 // Allow null encryption cipher in addition to other ciphers
1422 dwMinimumCipherStrength = -1;
1423 dwMaximumCipherStrength = 0;
1425 else if (policy == EncryptionPolicy.NoEncryption) {
1426 // Suppress all encryption and require null encryption cipher only
1427 dwMinimumCipherStrength = -1;
1428 dwMaximumCipherStrength = -1;
1431 throw new ArgumentException(SR.GetString(SR.net_invalid_enum, "EncryptionPolicy"), "policy");
1434 dwSessionLifespan = reserved = 0;
1435 this.version = version;
1437 grbitEnabledProtocols = protocols;
1438 if (certificate != null) {
1439 certContextArray = certificate.Handle;
1444 [System.Diagnostics.Conditional("TRAVE")]
1445 internal void DebugDump() {
1446 GlobalLog.Print("SecureCredential #"+GetHashCode());
1447 GlobalLog.Print(" version = " + version);
1448 GlobalLog.Print(" cCreds = " + cCreds);
1449 GlobalLog.Print(" certContextArray = " + String.Format("0x{0:x}", certContextArray));
1450 GlobalLog.Print(" rootStore = " + String.Format("0x{0:x}", rootStore));
1451 GlobalLog.Print(" cMappers = " + cMappers);
1452 GlobalLog.Print(" phMappers = " + String.Format("0x{0:x}", phMappers));
1453 GlobalLog.Print(" cSupportedAlgs = " + cSupportedAlgs);
1454 GlobalLog.Print(" palgSupportedAlgs = " + String.Format("0x{0:x}", palgSupportedAlgs));
1455 GlobalLog.Print(" grbitEnabledProtocols = " + String.Format("0x{0:x}", grbitEnabledProtocols));
1456 GlobalLog.Print(" dwMinimumCipherStrength = " + dwMinimumCipherStrength);
1457 GlobalLog.Print(" dwMaximumCipherStrength = " + dwMaximumCipherStrength);
1458 GlobalLog.Print(" dwSessionLifespan = " + String.Format("0x{0:x}", dwSessionLifespan));
1459 GlobalLog.Print(" dwFlags = " + String.Format("0x{0:x}", dwFlags));
1460 GlobalLog.Print(" reserved = " + String.Format("0x{0:x}", reserved));
1463 } // SecureCredential
1465 #endif // !FEATURE_PAL
1467 [StructLayout(LayoutKind.Sequential)]
1468 internal unsafe struct SecurityBufferStruct {
1470 public BufferType type;
1471 public IntPtr token;
1473 public static readonly int Size = sizeof(SecurityBufferStruct);
1476 internal class SecurityBuffer {
1478 public BufferType type;
1479 public byte[] token;
1480 public SafeHandle unmanagedToken;
1483 public SecurityBuffer(byte[] data, int offset, int size, BufferType tokentype) {
1484 GlobalLog.Assert(offset >= 0 && offset <= (data == null ? 0 : data.Length), "SecurityBuffer::.ctor", "'offset' out of range. [" + offset + "]");
1485 GlobalLog.Assert(size >= 0 && size <= (data == null ? 0 : data.Length - offset), "SecurityBuffer::.ctor", "'size' out of range. [" + size + "]");
1487 this.offset = data == null || offset < 0 ? 0 : Math.Min(offset, data.Length);
1488 this.size = data == null || size < 0 ? 0 : Math.Min(size, data.Length - this.offset);
1489 this.type = tokentype;
1490 this.token = size == 0 ? null : data;
1493 public SecurityBuffer(byte[] data, BufferType tokentype) {
1494 this.size = data == null ? 0 : data.Length;
1495 this.type = tokentype;
1496 this.token = size == 0 ? null : data;
1499 public SecurityBuffer(int size, BufferType tokentype) {
1500 GlobalLog.Assert(size >= 0, "SecurityBuffer::.ctor", "'size' out of range. [" + size.ToString(NumberFormatInfo.InvariantInfo) + "]");
1503 this.type = tokentype;
1504 this.token = size == 0 ? null : new byte[size];
1507 public SecurityBuffer(ChannelBinding binding) {
1508 this.size = (binding == null ? 0 : binding.Size);
1509 this.type = BufferType.ChannelBindings;
1510 this.unmanagedToken = binding;
1514 [StructLayout(LayoutKind.Sequential)]
1515 internal unsafe class SecurityBufferDescriptor {
1517 typedef struct _SecBufferDesc {
1520 PSecBuffer pBuffers;
1521 } SecBufferDesc, * PSecBufferDesc;
1523 public readonly int Version;
1524 public readonly int Count;
1525 public void* UnmanagedPointer;
1527 public SecurityBufferDescriptor(int count) {
1530 UnmanagedPointer = null;
1533 [System.Diagnostics.Conditional("TRAVE")]
1534 internal void DebugDump() {
1535 GlobalLog.Print("SecurityBufferDescriptor #" + ValidationHelper.HashString(this));
1536 GlobalLog.Print(" version = " + Version);
1537 GlobalLog.Print(" count = " + Count);
1538 GlobalLog.Print(" securityBufferArray = 0x" + (new IntPtr(UnmanagedPointer)).ToString("x"));
1540 } // SecurityBufferDescriptor
1542 internal enum CertificateEncoding {
1544 X509AsnEncoding = unchecked((int)0x00000001),
1545 X509NdrEncoding = unchecked((int)0x00000002),
1546 Pkcs7AsnEncoding = unchecked((int)0x00010000),
1547 Pkcs7NdrEncoding = unchecked((int)0x00020000),
1548 AnyAsnEncoding = X509AsnEncoding|Pkcs7AsnEncoding
1551 internal enum CertificateProblem {
1553 TrustNOSIGNATURE = unchecked((int)0x800B0100),
1554 CertEXPIRED = unchecked((int)0x800B0101),
1555 CertVALIDITYPERIODNESTING = unchecked((int)0x800B0102),
1556 CertROLE = unchecked((int)0x800B0103),
1557 CertPATHLENCONST = unchecked((int)0x800B0104),
1558 CertCRITICAL = unchecked((int)0x800B0105),
1559 CertPURPOSE = unchecked((int)0x800B0106),
1560 CertISSUERCHAINING = unchecked((int)0x800B0107),
1561 CertMALFORMED = unchecked((int)0x800B0108),
1562 CertUNTRUSTEDROOT = unchecked((int)0x800B0109),
1563 CertCHAINING = unchecked((int)0x800B010A),
1564 CertREVOKED = unchecked((int)0x800B010C),
1565 CertUNTRUSTEDTESTROOT = unchecked((int)0x800B010D),
1566 CertREVOCATION_FAILURE = unchecked((int)0x800B010E),
1567 CertCN_NO_MATCH = unchecked((int)0x800B010F),
1568 CertWRONG_USAGE = unchecked((int)0x800B0110),
1569 TrustEXPLICITDISTRUST = unchecked((int)0x800B0111),
1570 CertUNTRUSTEDCA = unchecked((int)0x800B0112),
1571 CertINVALIDPOLICY = unchecked((int)0x800B0113),
1572 CertINVALIDNAME = unchecked((int)0x800B0114),
1574 CryptNOREVOCATIONCHECK = unchecked((int)0x80092012),
1575 CryptREVOCATIONOFFLINE = unchecked((int)0x80092013),
1577 TrustSYSTEMERROR = unchecked((int)0x80096001),
1578 TrustNOSIGNERCERT = unchecked((int)0x80096002),
1579 TrustCOUNTERSIGNER = unchecked((int)0x80096003),
1580 TrustCERTSIGNATURE = unchecked((int)0x80096004),
1581 TrustTIMESTAMP = unchecked((int)0x80096005),
1582 TrustBADDIGEST = unchecked((int)0x80096010),
1583 TrustBASICCONSTRAINTS = unchecked((int)0x80096019),
1584 TrustFINANCIALCRITERIA = unchecked((int)0x8009601E),
1587 [StructLayout(LayoutKind.Sequential)]
1588 internal class SecChannelBindings
1590 internal int dwInitiatorAddrType;
1591 internal int cbInitiatorLength;
1592 internal int dwInitiatorOffset;
1594 internal int dwAcceptorAddrType;
1595 internal int cbAcceptorLength;
1596 internal int dwAcceptorOffset;
1598 internal int cbApplicationDataLength;
1599 internal int dwApplicationDataOffset;
1603 // WebRequestPrefixElement
1605 // This is an element of the prefix list. It contains the prefix and the
1606 // interface to be called to create a request for that prefix.
1610 /// <para>[To be supplied.]</para>
1612 // internal class WebRequestPrefixElement {
1613 internal class WebRequestPrefixElement {
1616 /// <para>[To be supplied.]</para>
1618 public string Prefix;
1620 /// <para>[To be supplied.]</para>
1622 internal IWebRequestCreate creator;
1624 /// <para>[To be supplied.]</para>
1626 internal Type creatorType;
1628 public IWebRequestCreate Creator {
1630 if (creator == null && creatorType != null) {
1632 if (creator == null) {
1633 creator = (IWebRequestCreate)Activator.CreateInstance(
1635 BindingFlags.CreateInstance
1636 | BindingFlags.Instance
1637 | BindingFlags.NonPublic
1638 | BindingFlags.Public,
1640 new object[0], // no arguments
1641 CultureInfo.InvariantCulture
1655 public WebRequestPrefixElement(string P, Type creatorType) {
1656 // verify that its of the proper type of IWebRequestCreate
1657 if (!typeof(IWebRequestCreate).IsAssignableFrom(creatorType))
1659 throw new InvalidCastException(SR.GetString(SR.net_invalid_cast,
1660 creatorType.AssemblyQualifiedName,
1661 "IWebRequestCreate"));
1665 this.creatorType = creatorType;
1669 /// <para>[To be supplied.]</para>
1671 public WebRequestPrefixElement(string P, IWebRequestCreate C) {
1676 } // class PrefixListElement
1679 #if MONO_FEATURE_WEB_STACK
1682 // HttpRequestCreator.
1684 // This is the class that we use to create HTTP and HTTPS requests.
1687 internal class HttpRequestCreator : IWebRequestCreate {
1691 Create - Create an HttpWebRequest.
1693 This is our method to create an HttpWebRequest. We register
1694 for HTTP and HTTPS Uris, and this method is called when a request
1695 needs to be created for one of those.
1699 Uri - Uri for request being created.
1702 The newly created HttpWebRequest.
1706 public WebRequest Create( Uri Uri ) {
1708 // Note, DNS permissions check will not happen on WebRequest
1710 return new HttpWebRequest(Uri, null);
1713 } // class HttpRequestCreator
1716 // WebSocketHttpRequestCreator.
1718 // This is the class that we use to create WebSocket connection requests.
1721 internal class WebSocketHttpRequestCreator : IWebRequestCreate
1723 private string m_httpScheme;
1725 // This ctor is used to create a WebSocketHttpRequestCreator.
1726 // We will do a URI change to update the scheme with Http or Https scheme. The usingHttps boolean is
1727 // used to indicate whether the created HttpWebRequest should take the https scheme or not.
1728 public WebSocketHttpRequestCreator(bool usingHttps)
1730 m_httpScheme = usingHttps ? Uri.UriSchemeHttps : Uri.UriSchemeHttp;
1735 Create - Create an HttpWebRequest.
1737 This is our method to create an HttpWebRequest for WebSocket connection. We register
1738 We will register it for custom Uri prefixes. And this method is called when a request
1739 needs to be created for one of those. The created HttpWebRequest will still be with Http or Https
1740 scheme, depending on the m_httpScheme field of this object.
1744 Uri - Uri for request being created.
1747 The newly created HttpWebRequest for WebSocket connection.
1751 public WebRequest Create(Uri Uri)
1753 UriBuilder uriBuilder = new UriBuilder(Uri);
1754 uriBuilder.Scheme = m_httpScheme;
1755 HttpWebRequest request = new HttpWebRequest(uriBuilder.Uri, null, true, "WebSocket" + Guid.NewGuid());
1756 WebSocketHelpers.PrepareWebRequest(ref request);
1760 } // class WebSocketHttpRequestCreator
1766 // CoreResponseData - Used to store result of HTTP header parsing and
1767 // response parsing. Also Contains new stream to use, and
1768 // is used as core of new Response
1770 internal class CoreResponseData {
1772 // Status Line Response Values
1773 public HttpStatusCode m_StatusCode;
1774 public string m_StatusDescription;
1775 public bool m_IsVersionHttp11;
1777 // Content Length needed for semantics, -1 if chunked
1778 public long m_ContentLength;
1781 public WebHeaderCollection m_ResponseHeaders;
1783 // ConnectStream - for reading actual data
1784 public Stream m_ConnectStream;
1786 internal CoreResponseData Clone() {
1787 CoreResponseData cloneResponseData = new CoreResponseData();
1788 cloneResponseData.m_StatusCode = m_StatusCode;
1789 cloneResponseData.m_StatusDescription = m_StatusDescription;
1790 cloneResponseData.m_IsVersionHttp11 = m_IsVersionHttp11;
1791 cloneResponseData.m_ContentLength = m_ContentLength;
1792 cloneResponseData.m_ResponseHeaders = m_ResponseHeaders;
1793 cloneResponseData.m_ConnectStream = m_ConnectStream;
1794 return cloneResponseData;
1801 internal delegate bool HttpAbortDelegate(HttpWebRequest request, WebException webException);
1804 // this class contains known header names
1807 internal static class HttpKnownHeaderNames {
1809 public const string CacheControl = "Cache-Control";
1810 public const string Connection = "Connection";
1811 public const string Date = "Date";
1812 public const string KeepAlive = "Keep-Alive";
1813 public const string Pragma = "Pragma";
1814 public const string ProxyConnection = "Proxy-Connection";
1815 public const string Trailer = "Trailer";
1816 public const string TransferEncoding = "Transfer-Encoding";
1817 public const string Upgrade = "Upgrade";
1818 public const string Via = "Via";
1819 public const string Warning = "Warning";
1820 public const string ContentLength = "Content-Length";
1821 public const string ContentType = "Content-Type";
1822 public const string ContentDisposition = "Content-Disposition";
1823 public const string ContentEncoding = "Content-Encoding";
1824 public const string ContentLanguage = "Content-Language";
1825 public const string ContentLocation = "Content-Location";
1826 public const string ContentRange = "Content-Range";
1827 public const string Expires = "Expires";
1828 public const string LastModified = "Last-Modified";
1829 public const string Age = "Age";
1830 public const string Location = "Location";
1831 public const string ProxyAuthenticate = "Proxy-Authenticate";
1832 public const string RetryAfter = "Retry-After";
1833 public const string Server = "Server";
1834 public const string SetCookie = "Set-Cookie";
1835 public const string SetCookie2 = "Set-Cookie2";
1836 public const string Vary = "Vary";
1837 public const string WWWAuthenticate = "WWW-Authenticate";
1838 public const string Accept = "Accept";
1839 public const string AcceptCharset = "Accept-Charset";
1840 public const string AcceptEncoding = "Accept-Encoding";
1841 public const string AcceptLanguage = "Accept-Language";
1842 public const string Authorization = "Authorization";
1843 public const string Cookie = "Cookie";
1844 public const string Cookie2 = "Cookie2";
1845 public const string Expect = "Expect";
1846 public const string From = "From";
1847 public const string Host = "Host";
1848 public const string IfMatch = "If-Match";
1849 public const string IfModifiedSince = "If-Modified-Since";
1850 public const string IfNoneMatch = "If-None-Match";
1851 public const string IfRange = "If-Range";
1852 public const string IfUnmodifiedSince = "If-Unmodified-Since";
1853 public const string MaxForwards = "Max-Forwards";
1854 public const string ProxyAuthorization = "Proxy-Authorization";
1855 public const string Referer = "Referer";
1856 public const string Range = "Range";
1857 public const string UserAgent = "User-Agent";
1858 public const string ContentMD5 = "Content-MD5";
1859 public const string ETag = "ETag";
1860 public const string TE = "TE";
1861 public const string Allow = "Allow";
1862 public const string AcceptRanges = "Accept-Ranges";
1863 public const string P3P = "P3P";
1864 public const string XPoweredBy = "X-Powered-By";
1865 public const string XAspNetVersion = "X-AspNet-Version";
1866 public const string SecWebSocketKey = "Sec-WebSocket-Key";
1867 public const string SecWebSocketExtensions = "Sec-WebSocket-Extensions";
1868 public const string SecWebSocketAccept = "Sec-WebSocket-Accept";
1869 public const string Origin = "Origin";
1870 public const string SecWebSocketProtocol = "Sec-WebSocket-Protocol";
1871 public const string SecWebSocketVersion = "Sec-WebSocket-Version";
1876 /// Represents the method that will notify callers when a continue has been
1877 /// received by the client.
1880 // Delegate type for us to notify callers when we receive a continue
1881 public delegate void HttpContinueDelegate(int StatusCode, WebHeaderCollection httpHeaders);
1884 // HttpWriteMode - used to control the way in which an entity Body is posted.
1886 enum HttpWriteMode {
1894 // Used by Request to notify Connection that we are no longer holding the Connection (for NTLM connection sharing)
1895 delegate void UnlockConnectionDelegate();
1897 enum HttpBehaviour : byte {
1900 HTTP11PartiallyCompliant = 2,
1904 internal enum HttpProcessingResult {
1911 // HttpVerb - used to define various per Verb Properties
1915 // Note - this is a place holder for Verb properties,
1916 // the following two bools can most likely be combined into
1917 // a single Enum type. And the Verb can be incorporated.
1919 class KnownHttpVerb {
1920 internal string Name; // verb name
1922 internal bool RequireContentBody; // require content body to be sent
1923 internal bool ContentBodyNotAllowed; // not allowed to send content body
1924 internal bool ConnectRequest; // special semantics for a connect request
1925 internal bool ExpectNoContentResponse; // response will not have content body
1927 internal KnownHttpVerb(string name, bool requireContentBody, bool contentBodyNotAllowed, bool connectRequest, bool expectNoContentResponse) {
1929 RequireContentBody = requireContentBody;
1930 ContentBodyNotAllowed = contentBodyNotAllowed;
1931 ConnectRequest = connectRequest;
1932 ExpectNoContentResponse = expectNoContentResponse;
1935 // Force an an init, before we use them
1936 private static ListDictionary NamedHeaders;
1939 internal static KnownHttpVerb Get;
1940 internal static KnownHttpVerb Connect;
1941 internal static KnownHttpVerb Head;
1942 internal static KnownHttpVerb Put;
1943 internal static KnownHttpVerb Post;
1944 internal static KnownHttpVerb MkCol;
1947 // InitializeKnownVerbs - Does basic init for this object,
1948 // such as creating defaultings and filling them
1950 static KnownHttpVerb() {
1951 NamedHeaders = new ListDictionary(CaseInsensitiveAscii.StaticInstance);
1952 Get = new KnownHttpVerb("GET", false, true, false, false);
1953 Connect = new KnownHttpVerb("CONNECT", false, true, true, false);
1954 Head = new KnownHttpVerb("HEAD", false, true, false, true);
1955 Put = new KnownHttpVerb("PUT", true, false, false, false);
1956 Post = new KnownHttpVerb("POST", true, false, false, false);
1957 MkCol = new KnownHttpVerb("MKCOL",false,false,false,false);
1958 NamedHeaders[Get.Name] = Get;
1959 NamedHeaders[Connect.Name] = Connect;
1960 NamedHeaders[Head.Name] = Head;
1961 NamedHeaders[Put.Name] = Put;
1962 NamedHeaders[Post.Name] = Post;
1963 NamedHeaders[MkCol.Name] = MkCol;
1966 public bool Equals(KnownHttpVerb verb) {
1967 return this==verb || string.Compare(Name, verb.Name, StringComparison.OrdinalIgnoreCase)==0;
1970 public static KnownHttpVerb Parse(string name) {
1971 KnownHttpVerb knownHttpVerb = NamedHeaders[name] as KnownHttpVerb;
1972 if (knownHttpVerb==null) {
1973 // unknown verb, default behaviour
1974 knownHttpVerb = new KnownHttpVerb(name, false, false, false, false);
1976 return knownHttpVerb;
1981 // HttpProtocolUtils - A collection of utility functions for HTTP usage.
1984 internal class HttpProtocolUtils {
1986 private HttpProtocolUtils() {
1990 // extra buffers for build/parsing, recv/send HTTP data,
1991 // at some point we should consolidate
1995 // parse String to DateTime format.
1996 internal static DateTime string2date(String S) {
1998 if (HttpDateParse.ParseHttpDate(S,out dtOut)) {
2002 throw new ProtocolViolationException(SR.GetString(SR.net_baddate));
2007 // convert Date to String using RFC 1123 pattern
2008 internal static string date2string(DateTime D) {
2009 DateTimeFormatInfo dateFormat = new DateTimeFormatInfo();
2010 return D.ToUniversalTime().ToString("R", dateFormat);
2015 // Proxy class for linking between ICertificatePolicy <--> ICertificateDecider
2016 internal class PolicyWrapper {
2017 private const uint IgnoreUnmatchedCN = 0x00001000;
2018 private ICertificatePolicy fwdPolicy;
2019 private ServicePoint srvPoint;
2020 private WebRequest request;
2022 internal PolicyWrapper(ICertificatePolicy policy, ServicePoint sp, WebRequest wr) {
2023 this.fwdPolicy = policy;
2028 public bool Accept(X509Certificate Certificate, int CertificateProblem) {
2029 return fwdPolicy.CheckValidationResult(srvPoint, Certificate, request, CertificateProblem);
2032 internal static uint VerifyChainPolicy(SafeFreeCertChain chainContext, ref ChainPolicyParameter cpp) {
2033 GlobalLog.Enter("PolicyWrapper::VerifyChainPolicy", "chainContext="+ chainContext + ", options="+String.Format("0x{0:x}", cpp.dwFlags));
2034 ChainPolicyStatus status = new ChainPolicyStatus();
2035 status.cbSize = ChainPolicyStatus.StructSize;
2037 UnsafeNclNativeMethods.NativePKI.CertVerifyCertificateChainPolicy(
2038 (IntPtr) ChainPolicyType.SSL,
2043 GlobalLog.Print("PolicyWrapper::VerifyChainPolicy() CertVerifyCertificateChainPolicy returned: " + errorCode);
2045 GlobalLog.Print("PolicyWrapper::VerifyChainPolicy() error code: " + status.dwError+String.Format(" [0x{0:x8}", status.dwError) + " " + SecureChannel.MapSecurityStatus(status.dwError) + "]");
2047 GlobalLog.Leave("PolicyWrapper::VerifyChainPolicy", status.dwError.ToString());
2048 return status.dwError;
2051 private static IgnoreCertProblem MapErrorCode(uint errorCode) {
2052 switch ((CertificateProblem) errorCode) {
2054 case CertificateProblem.CertINVALIDNAME :
2055 case CertificateProblem.CertCN_NO_MATCH :
2056 return IgnoreCertProblem.invalid_name;
2058 case CertificateProblem.CertINVALIDPOLICY :
2059 case CertificateProblem.CertPURPOSE :
2060 return IgnoreCertProblem.invalid_policy;
2062 case CertificateProblem.CertEXPIRED :
2063 return IgnoreCertProblem.not_time_valid | IgnoreCertProblem.ctl_not_time_valid;
2065 case CertificateProblem.CertVALIDITYPERIODNESTING :
2066 return IgnoreCertProblem.not_time_nested;
2068 case CertificateProblem.CertCHAINING :
2069 case CertificateProblem.CertUNTRUSTEDCA :
2070 case CertificateProblem.CertUNTRUSTEDROOT :
2071 return IgnoreCertProblem.allow_unknown_ca;
2073 case CertificateProblem.CertREVOKED :
2074 case CertificateProblem.CertREVOCATION_FAILURE :
2075 case CertificateProblem.CryptNOREVOCATIONCHECK:
2076 case CertificateProblem.CryptREVOCATIONOFFLINE:
2077 return IgnoreCertProblem.all_rev_unknown;
2079 case CertificateProblem.CertROLE:
2080 case CertificateProblem.TrustBASICCONSTRAINTS:
2081 return IgnoreCertProblem.invalid_basic_constraints;
2083 case CertificateProblem.CertWRONG_USAGE :
2084 return IgnoreCertProblem.wrong_usage;
2092 private uint[] GetChainErrors(string hostName, X509Chain chain, ref bool fatalError)
2095 SafeFreeCertChain chainContext= new SafeFreeCertChain(chain.ChainContext);
2096 ArrayList certificateProblems = new ArrayList();
2099 ChainPolicyParameter cppStruct = new ChainPolicyParameter();
2100 cppStruct.cbSize = ChainPolicyParameter.StructSize;
2101 cppStruct.dwFlags = 0;
2103 SSL_EXTRA_CERT_CHAIN_POLICY_PARA eppStruct = new SSL_EXTRA_CERT_CHAIN_POLICY_PARA(false);
2104 cppStruct.pvExtraPolicyPara = &eppStruct;
2106 fixed (char* namePtr = hostName) {
2107 if (ServicePointManager.CheckCertificateName){
2108 eppStruct.pwszServerName = namePtr;
2112 status = VerifyChainPolicy(chainContext, ref cppStruct);
2113 uint ignoreErrorMask = (uint)MapErrorCode(status);
2115 certificateProblems.Add(status);
2117 if (status == 0) { // No more problems with the certificate?
2118 break; // Then break out of the callback loop
2121 if (ignoreErrorMask == 0) { // Unrecognized error encountered
2126 cppStruct.dwFlags |= ignoreErrorMask;
2127 if ((CertificateProblem)status == CertificateProblem.CertCN_NO_MATCH && ServicePointManager.CheckCertificateName) {
2128 eppStruct.fdwChecks = IgnoreUnmatchedCN;
2135 return (uint[]) certificateProblems.ToArray(typeof(uint));
2138 internal bool CheckErrors(string hostName, X509Certificate certificate, X509Chain chain, SslPolicyErrors sslPolicyErrors)
2140 if (sslPolicyErrors == 0)
2141 return Accept(certificate, 0);
2143 if ((sslPolicyErrors & SslPolicyErrors.RemoteCertificateNotAvailable) != 0)
2144 return Accept(certificate, (int) CertificateProblem.CertCRITICAL); // ToDO, Define an appropriate enum entry
2146 if ((sslPolicyErrors & SslPolicyErrors.RemoteCertificateChainErrors) != 0 ||
2147 (sslPolicyErrors & SslPolicyErrors.RemoteCertificateNameMismatch) != 0)
2149 bool fatalError = false;
2150 uint[] certificateProblems = GetChainErrors(hostName, chain, ref fatalError);
2153 // By today design we cannot allow decider to ignore a fatal error.
2154 // This error is fatal.
2155 Accept(certificate, (int) SecurityStatus.InternalError);
2160 if (certificateProblems.Length == 0)
2161 return Accept(certificate, (int) CertificateProblem.OK);
2163 // Run each error through Accept().
2164 foreach (uint error in certificateProblems)
2165 if (!Accept(certificate, (int) error))
2172 /* CONSIDER: Use this code when we switch to managed X509 API
2173 internal static int MapStatusToWin32Error(X509ChainStatusFlags status)
2177 case X509ChainStatusFlags.NoError: return CertificateProblem.OK;
2178 case X509ChainStatusFlags.NotTimeValid: return CertificateProblem.CertEXPIRED;
2179 case X509ChainStatusFlags.NotTimeNested: return CertificateProblem.CertVALIDITYPERIODNESTING;
2180 case X509ChainStatusFlags.Revoked: return CertificateProblem.CertREVOKED;
2181 case X509ChainStatusFlags.NotSignatureValid:return CertificateProblem.TrustCERTSIGNATURE;
2182 case X509ChainStatusFlags.NotValidForUsage: return CertificateProblem.CertWRONG_USAGE;
2183 case X509ChainStatusFlags.UntrustedRoot: return CertificateProblem.CertUNTRUSTEDROOT;
2184 case X509ChainStatusFlags.RevocationStatusUnknown: return CertificateProblem.CryptNOREVOCATIONCHECK;
2185 case X509ChainStatusFlags.Cyclic: return CertificateProblem.CertCHAINING; //??
2186 case X509ChainStatusFlags.InvalidExtension: return CertificateProblem.CertCRITICAL; //??
2187 case X509ChainStatusFlags.InvalidPolicyConstraints: return CertificateProblem.CertINVALIDPOLICY;
2188 case X509ChainStatusFlags.InvalidBasicConstraints: return CertificateProblem.TrustBASICCONSTRAINTS;
2189 case X509ChainStatusFlagsInvalidNameConstraints: return CertificateProblem.CertINVALIDNAME;
2190 case X509ChainStatusFlags.HasNotSupportedNameConstraint: return CertificateProblem.CertINVALIDNAME; //??
2191 case X509ChainStatusFlags.HasNotDefinedNameConstraint: return CertificateProblem.CertINVALIDNAME; //??
2192 case X509ChainStatusFlags.HasNotPermittedNameConstraint: return CertificateProblem.CertINVALIDNAME; //??
2193 case X509ChainStatusFlags.HasExcludedNameConstraint: return CertificateProblem.CertINVALIDNAME; //??
2194 case X509ChainStatusFlags.PartialChain: return CertificateProblem.CertCHAINING; //??
2195 case X509ChainStatusFlags.CtlNotTimeValid: return CertificateProblem.CertEXPIRED;
2196 case X509ChainStatusFlags.CtlNotSignatureValid: return CertificateProblem.TrustCERTSIGNATURE;
2197 case X509ChainStatusFlags.CtlNotValidForUsage: return CertificateProblem.CertWRONG_USAGE;
2198 case X509ChainStatusFlags.OfflineRevocation: return CertificateProblem.CryptREVOCATIONOFFLINE;
2199 case X509ChainStatusFlags.NoIssuanceChainPolicy:return CertificateProblem.CertINVALIDPOLICY;
2200 default: return (int) CertificateProblem.TrustSYSTEMERROR; // unknown
2205 // Class implementing default certificate policy
2206 internal class DefaultCertPolicy : ICertificatePolicy {
2207 public bool CheckValidationResult(ServicePoint sp, X509Certificate cert, WebRequest request, int problem) {
2208 return problem == (int)CertificateProblem.OK;
2211 #endif // !FEATURE_PAL
2213 internal enum TriState {
2219 internal enum DefaultPorts {
2220 DEFAULT_FTP_PORT = 21,
2221 DEFAULT_GOPHER_PORT = 70,
2222 DEFAULT_HTTP_PORT = 80,
2223 DEFAULT_HTTPS_PORT = 443,
2224 DEFAULT_NNTP_PORT = 119,
2225 DEFAULT_SMTP_PORT = 25,
2226 DEFAULT_TELNET_PORT = 23
2229 [StructLayout(LayoutKind.Sequential, CharSet=CharSet.Unicode)]
2230 internal struct hostent {
2231 public IntPtr h_name;
2232 public IntPtr h_aliases;
2233 public short h_addrtype;
2234 public short h_length;
2235 public IntPtr h_addr_list;
2239 [StructLayout(LayoutKind.Sequential)]
2240 internal struct Blob {
2242 public int pBlobData;
2246 // This is only for internal code path i.e. TLS stream.
2247 // See comments on GetNextBuffer() method below.
2249 internal class SplitWritesState
2251 private const int c_SplitEncryptedBuffersSize = 64*1024;
2252 private BufferOffsetSize[] _UserBuffers;
2254 private int _LastBufferConsumed;
2255 private BufferOffsetSize[] _RealBuffers;
2258 internal SplitWritesState(BufferOffsetSize[] buffers)
2260 _UserBuffers = buffers;
2261 _LastBufferConsumed = 0;
2263 _RealBuffers = null;
2266 // Everything was handled
2268 internal bool IsDone {
2270 if (_LastBufferConsumed != 0)
2273 for (int index = _Index ;index < _UserBuffers.Length; ++index)
2274 if (_UserBuffers[index].Size != 0)
2280 // Encryption takes CPU and if the input is large (like 10 mb) then a delay may
2281 // be 30 sec or so. Hence split the ecnrypt and write operations in smaller chunks
2282 // up to c_SplitEncryptedBuffersSize total.
2283 // Note that upon return from here EncryptBuffers() may additonally split the input
2284 // into chunks each <= chkSecureChannel.MaxDataSize (~16k) yet it will complete them all as a single IO.
2286 // Returns null if done, returns the _buffers reference if everything is handled in one shot (also done)
2288 // Otheriwse returns subsequent BufferOffsetSize[] to encrypt and pass to base IO method
2290 internal BufferOffsetSize[] GetNextBuffers()
2292 int curIndex = _Index;
2293 int currentTotalSize = 0;
2294 int lastChunkSize = 0;
2296 int firstBufferConsumed = _LastBufferConsumed;
2298 for ( ;_Index < _UserBuffers.Length; ++_Index)
2300 lastChunkSize = _UserBuffers[_Index].Size-_LastBufferConsumed;
2302 currentTotalSize += lastChunkSize;
2304 if (currentTotalSize > c_SplitEncryptedBuffersSize)
2306 lastChunkSize -= (currentTotalSize - c_SplitEncryptedBuffersSize);
2307 currentTotalSize = c_SplitEncryptedBuffersSize;
2312 _LastBufferConsumed = 0;
2315 // Are we done done?
2316 if (currentTotalSize == 0)
2319 // Do all buffers fit the limit?
2320 if (firstBufferConsumed == 0 && curIndex == 0 && _Index == _UserBuffers.Length)
2321 return _UserBuffers;
2323 // We do have something to split and send out
2324 int buffersCount = lastChunkSize == 0? _Index-curIndex: _Index-curIndex+1;
2326 if (_RealBuffers == null || _RealBuffers.Length != buffersCount)
2327 _RealBuffers = new BufferOffsetSize[buffersCount];
2330 for (; curIndex < _Index; ++curIndex)
2332 _RealBuffers[j++] = new BufferOffsetSize(_UserBuffers[curIndex].Buffer, _UserBuffers[curIndex].Offset + firstBufferConsumed, _UserBuffers[curIndex].Size-firstBufferConsumed, false);
2333 firstBufferConsumed = 0;
2336 if (lastChunkSize != 0)
2338 _RealBuffers[j] = new BufferOffsetSize(_UserBuffers[curIndex].Buffer, _UserBuffers[curIndex].Offset + _LastBufferConsumed, lastChunkSize, false);
2339 if ((_LastBufferConsumed += lastChunkSize) == _UserBuffers[_Index].Size)
2342 _LastBufferConsumed = 0;
2346 return _RealBuffers;