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;
28 internal static class IntPtrHelper {
31 internal static IntPtr Add(IntPtr a, IntPtr b) {
32 return (IntPtr) ((long)a + (long)b);
35 internal static IntPtr Add(IntPtr a, int b) {
36 return (IntPtr) ((long)a + (long)b);
39 internal static long Subtract(IntPtr a, IntPtr b) {
40 return ((long)a - (long)b);
44 internal class InternalException : SystemException
46 internal InternalException()
48 GlobalLog.Assert("InternalException thrown.");
51 internal InternalException(SerializationInfo serializationInfo, StreamingContext streamingContext) :
52 base(serializationInfo, streamingContext)
56 internal static class NclUtilities
60 /// Indicates true if the threadpool is low on threads,
61 /// in this case we need to refuse to start new requests,
62 /// and avoid blocking.
65 internal static bool IsThreadPoolLow()
68 if (ComNetOS.IsAspNetServer)
74 int workerThreads, completionPortThreads;
75 ThreadPool.GetAvailableThreads(out workerThreads, out completionPortThreads);
78 return workerThreads < 2 || (completionPortThreads < 2);
80 GlobalLog.Assert(completionPortThreads == 0, "completionPortThreads should be zero on the PAL");
81 return workerThreads < 2;
86 internal static bool HasShutdownStarted
90 return Environment.HasShutdownStarted || AppDomain.CurrentDomain.IsFinalizingForUnload();
94 // This only works for context-destroying errors.
95 internal static bool IsCredentialFailure(SecurityStatus error)
97 return error == SecurityStatus.LogonDenied ||
98 error == SecurityStatus.UnknownCredentials ||
99 error == SecurityStatus.NoImpersonation ||
100 error == SecurityStatus.NoAuthenticatingAuthority ||
101 error == SecurityStatus.UntrustedRoot ||
102 error == SecurityStatus.CertExpired ||
103 error == SecurityStatus.SmartcardLogonRequired ||
104 error == SecurityStatus.BadBinding;
107 // This only works for context-destroying errors.
108 internal static bool IsClientFault(SecurityStatus error)
110 return error == SecurityStatus.InvalidToken ||
111 error == SecurityStatus.CannotPack ||
112 error == SecurityStatus.QopNotSupported ||
113 error == SecurityStatus.NoCredentials ||
114 error == SecurityStatus.MessageAltered ||
115 error == SecurityStatus.OutOfSequence ||
116 error == SecurityStatus.IncompleteMessage ||
117 error == SecurityStatus.IncompleteCredentials ||
118 error == SecurityStatus.WrongPrincipal ||
119 error == SecurityStatus.TimeSkew ||
120 error == SecurityStatus.IllegalMessage ||
121 error == SecurityStatus.CertUnknown ||
122 error == SecurityStatus.AlgorithmMismatch ||
123 error == SecurityStatus.SecurityQosFailed ||
124 error == SecurityStatus.UnsupportedPreauth;
128 // ContextRelativeDemand
129 // Allows easily demanding a permission against a given ExecutionContext.
130 // Have requested the CLR to provide this method on ExecutionContext.
131 private static volatile ContextCallback s_ContextRelativeDemandCallback;
133 internal static ContextCallback ContextRelativeDemandCallback
137 if (s_ContextRelativeDemandCallback == null)
138 s_ContextRelativeDemandCallback = new ContextCallback(DemandCallback);
139 return s_ContextRelativeDemandCallback;
143 private static void DemandCallback(object state)
145 ((CodeAccessPermission) state).Demand();
148 // This is for checking if a hostname probably refers to this machine without going to DNS.
149 internal static bool GuessWhetherHostIsLoopback(string host)
151 string hostLower = host.ToLowerInvariant();
152 if (hostLower == "localhost" || hostLower == "loopback")
158 IPGlobalProperties ip = IPGlobalProperties.InternalGetIPGlobalProperties();
159 string hostnameLower = ip.HostName.ToLowerInvariant();
160 return hostLower == hostnameLower || hostLower == hostnameLower + "." + ip.DomainName.ToLowerInvariant();
166 internal static bool IsFatal(Exception exception)
168 return exception != null && (exception is OutOfMemoryException || exception is StackOverflowException || exception is ThreadAbortException);
171 // Need a fast cached list of local addresses for internal use.
172 private static volatile IPAddress[] _LocalAddresses;
173 private static object _LocalAddressesLock;
175 #if MONO_NOT_IMPLEMENTED
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
288 private const int HostNameBufferLength = 256;
289 internal static string _LocalDomainName;
291 // Copied from the old version of DNS.cs
292 // Returns a list of our local addresses by calling gethostbyname with null.
294 private static IPHostEntry GetLocalHost()
297 // IPv6 Changes: If IPv6 is enabled, we can't simply use the
298 // old IPv4 gethostbyname(null). Instead we need
299 // to do a more complete lookup.
301 if (Socket.SupportsIPv6)
304 // IPv6 enabled: use getaddrinfo() of the local host name
305 // to obtain this information. Need to get the machines
306 // name as well - do that here so that we don't need to
307 // Assert DNS permissions.
309 StringBuilder hostname = new StringBuilder(HostNameBufferLength);
310 SocketError errorCode =
311 UnsafeNclNativeMethods.OSSOCK.gethostname(
313 HostNameBufferLength);
315 if (errorCode != SocketError.Success)
317 throw new SocketException();
320 return Dns.GetHostByName(hostname.ToString());
325 // IPv6 disabled: use gethostbyname() to obtain information.
327 IntPtr nativePointer =
328 UnsafeNclNativeMethods.OSSOCK.gethostbyname(
331 if (nativePointer == IntPtr.Zero)
333 throw new SocketException();
336 return Dns.NativeToHostEntry(nativePointer);
341 internal static IPAddress[] LocalAddresses
345 IPAddress[] local = _LocalAddresses;
351 lock (LocalAddressesLock)
353 local = _LocalAddresses;
359 List<IPAddress> localList = new List<IPAddress>();
363 IPHostEntry hostEntry = GetLocalHost();
364 if (hostEntry != null)
366 if (hostEntry.HostName != null)
368 int dot = hostEntry.HostName.IndexOf('.');
371 _LocalDomainName = hostEntry.HostName.Substring(dot);
375 IPAddress[] ipAddresses = hostEntry.AddressList;
376 if (ipAddresses != null)
378 foreach (IPAddress ipAddress in ipAddresses)
380 localList.Add(ipAddress);
389 local = new IPAddress[localList.Count];
391 foreach (IPAddress ipAddress in localList)
393 local[index] = ipAddress;
396 _LocalAddresses = local;
402 #endif // !FEATURE_PAL
405 private static object LocalAddressesLock
409 if (_LocalAddressesLock == null)
411 Interlocked.CompareExchange(ref _LocalAddressesLock, new object(), null);
413 return _LocalAddressesLock;
418 internal static class NclConstants
420 internal static readonly object Sentinel = new object();
421 internal static readonly object[] EmptyObjectArray = new object[0];
422 internal static readonly Uri[] EmptyUriArray = new Uri[0];
424 internal static readonly byte[] CRLF = new byte[] {(byte) '\r', (byte) '\n'};
425 internal static readonly byte[] ChunkTerminator = new byte[] {(byte) '0', (byte) '\r', (byte) '\n', (byte) '\r', (byte) '\n'};
429 // A simple [....] point, useful for deferring work. Just an int value with helper methods.
430 // This is used by HttpWebRequest to syncronize Reads/Writes while waiting for a 100-Continue response.
432 internal struct InterlockedGate
436 // Not currently waiting for a response
437 internal const int Open = 0; // Initial state of gate.
438 // Starting the timer to wait for a response (async)
439 internal const int Triggering = 1; // Gate is being actively held by a thread - indeterminate state.
440 // Waiting for response
441 internal const int Triggered = 2; // The triggering event has occurred.
442 // Stopping the timer (got a response or timed out)
443 internal const int Signaling = 3;
444 // Got a response or timed out, may process the response.
445 internal const int Signaled = 4;
446 // Re/submitting data.
447 internal const int Completed = 5; // The gated event is done.
461 // Only call when all threads are guaranteed to be done with the gate.
462 internal void Reset()
467 // Returns false if the gate is not taken. If exclusive is true, throws if the gate is already triggered.
468 internal bool Trigger(bool exclusive)
470 int gate = Interlocked.CompareExchange(ref m_State, Triggered, Open);
471 if (exclusive && (gate == Triggering || gate == Triggered))
473 GlobalLog.Assert("InterlockedGate::Trigger", "Gate already triggered.");
474 throw new InternalException();
479 // Use StartTrigger() and FinishTrigger() to trigger the gate as a two step operation. This is useful to set up an invariant
480 // that must be ready by the time another thread closes the gate. Do not block between StartTrigger() and FinishTrigger(), just
481 // set up your state to be consistent. If this method returns true, FinishTrigger() *must* be called to avoid deadlock - do
484 // Returns false if the gate is not taken. If exclusive is true, throws if the gate is already triggering/ed.
485 internal bool StartTriggering(bool exclusive)
487 int gate = Interlocked.CompareExchange(ref m_State, Triggering, Open);
488 if (exclusive && (gate == Triggering || gate == Triggered))
490 GlobalLog.Assert("InterlockedGate::StartTriggering", "Gate already triggered.");
491 throw new InternalException();
496 // Gate must be held by StartTriggering().
497 internal void FinishTriggering()
499 int gate = Interlocked.CompareExchange(ref m_State, Triggered, Triggering);
500 if (gate != Triggering)
502 GlobalLog.Assert("InterlockedGate::FinishTriggering", "Gate not Triggering.");
503 throw new InternalException();
507 // Use StartSignaling() and FinishSignaling() to signal the gate as a two step operation. This is useful to
508 // set up an invariant that must be ready by the time another thread closes the gate. Do not block between
509 // StartSignaling() and FinishSignaling(), just set up your state to be consistent. If this method returns
510 // true, FinishSignaling() *must* be called to avoid deadlock - do it in a finally.
512 // Returns false if the gate is not taken. If exclusive is true, throws if the gate is already Signaling/ed.
513 internal bool StartSignaling(bool exclusive)
515 int gate = Interlocked.CompareExchange(ref m_State, Signaling, Triggered);
516 if (exclusive && (gate == Signaling || gate == Signaled)) //
518 GlobalLog.Assert("InterlockedGate::StartTrigger", "Gate already Signaled.");
519 throw new InternalException();
521 Debug.Assert(gate != Triggering, "Still Triggering");
522 return gate == Triggered;
525 // Gate must be held by StartSignaling().
526 internal void FinishSignaling()
528 int gate = Interlocked.CompareExchange(ref m_State, Signaled, Signaling);
529 if (gate != Signaling)
531 GlobalLog.Assert("InterlockedGate::FinishSignaling", "Gate not Signaling; " + gate);
532 throw new InternalException();
536 // Makes sure only one thread completes the opperation.
537 internal bool Complete()
539 int gate = Interlocked.CompareExchange(ref m_State, Completed, Signaled);
540 Debug.Assert(gate != Signaling, "Still Signaling");
541 return (gate == Signaled);
547 // A polling implementation of NetworkAddressChange.
549 internal class NetworkAddressChangePolled : IDisposable
551 private bool disposed;
552 private SafeCloseSocketAndEvent ipv4Socket = null;
553 private SafeCloseSocketAndEvent ipv6Socket = null;
556 internal unsafe NetworkAddressChangePolled()
558 Socket.InitializeSockets();
560 if (Socket.OSSupportsIPv4)
563 ipv4Socket = SafeCloseSocketAndEvent.CreateWSASocketWithEvent(AddressFamily.InterNetwork, SocketType.Dgram, (ProtocolType)0, true, false);
564 UnsafeNclNativeMethods.OSSOCK.ioctlsocket(ipv4Socket, IoctlSocketConstants.FIONBIO, ref blocking);
567 if(Socket.OSSupportsIPv6){
569 ipv6Socket = SafeCloseSocketAndEvent.CreateWSASocketWithEvent(AddressFamily.InterNetworkV6, SocketType.Dgram, (ProtocolType)0, true, false);
570 UnsafeNclNativeMethods.OSSOCK.ioctlsocket(ipv6Socket,IoctlSocketConstants.FIONBIO,ref blocking);
572 Setup(StartIPOptions.Both);
575 private unsafe void Setup(StartIPOptions startIPOptions)
578 SocketError errorCode;
581 if (Socket.OSSupportsIPv4 && (startIPOptions & StartIPOptions.StartIPv4) != 0){
582 errorCode = (SocketError)UnsafeNclNativeMethods.OSSOCK.WSAIoctl_Blocking(
583 ipv4Socket.DangerousGetHandle(),
584 (int) IOControlCode.AddressListChange,
587 SafeNativeOverlapped.Zero, IntPtr.Zero);
589 if (errorCode != SocketError.Success) {
590 NetworkInformationException exception = new NetworkInformationException();
591 if (exception.ErrorCode != (uint)SocketError.WouldBlock) {
597 errorCode = (SocketError)UnsafeNclNativeMethods.OSSOCK.WSAEventSelect(ipv4Socket, ipv4Socket.GetEventHandle().SafeWaitHandle, AsyncEventBits.FdAddressListChange);
598 if (errorCode != SocketError.Success) {
604 if(Socket.OSSupportsIPv6 && (startIPOptions & StartIPOptions.StartIPv6) !=0){
605 errorCode = (SocketError) UnsafeNclNativeMethods.OSSOCK.WSAIoctl_Blocking(
606 ipv6Socket.DangerousGetHandle(),
607 (int) IOControlCode.AddressListChange,
610 SafeNativeOverlapped.Zero, IntPtr.Zero);
612 if (errorCode != SocketError.Success) {
613 NetworkInformationException exception = new NetworkInformationException();
614 if (exception.ErrorCode != (uint)SocketError.WouldBlock) {
620 errorCode = (SocketError)UnsafeNclNativeMethods.OSSOCK.WSAEventSelect(ipv6Socket, ipv6Socket.GetEventHandle().SafeWaitHandle, AsyncEventBits.FdAddressListChange);
621 if (errorCode != SocketError.Success) {
628 internal bool CheckAndReset()
633 StartIPOptions options = StartIPOptions.None;
635 if (ipv4Socket != null && ipv4Socket.GetEventHandle().WaitOne(0, false)){
636 options|= StartIPOptions.StartIPv4;
638 if (ipv6Socket != null && ipv6Socket.GetEventHandle().WaitOne(0, false))
640 options|= StartIPOptions.StartIPv6;
643 if(options != StartIPOptions.None){
653 public void Dispose()
658 if(ipv6Socket != null){
662 if(ipv4Socket != null){
672 #endif // FEATURE_PAL
677 internal static class ComNetOS
679 private const string OSInstallTypeRegKey = @"Software\Microsoft\Windows NT\CurrentVersion";
680 private const string OSInstallTypeRegKeyPath = @"HKEY_LOCAL_MACHINE\" + OSInstallTypeRegKey;
681 private const string OSInstallTypeRegName = "InstallationType";
682 private const string InstallTypeStringClient = "Client";
683 private const string InstallTypeStringServer = "Server";
684 private const string InstallTypeStringServerCore = "Server Core";
685 private const string InstallTypeStringEmbedded = "Embedded";
687 // Minimum support for Windows 2008 is assumed.
688 internal static readonly bool IsAspNetServer; // ie: running under ASP+
689 internal static readonly bool IsWin7orLater; // Is Windows 7 or later
690 internal static readonly bool IsWin7Sp1orLater; // Is Windows 7 Sp1 or later (2008 R2 Sp1+)
691 internal static readonly bool IsWin8orLater; // Is Windows 8 or later
692 internal static readonly WindowsInstallationType InstallationType; // e.g. Client, Server, Server Core
694 // We use it safe so assert
695 [EnvironmentPermission(SecurityAction.Assert, Unrestricted = true)]
696 [ResourceExposure(ResourceScope.None)]
697 [ResourceConsumption(ResourceScope.AppDomain, ResourceScope.AppDomain)]
700 OperatingSystem operatingSystem = Environment.OSVersion;
702 GlobalLog.Print("ComNetOS::.ctor(): " + operatingSystem.ToString());
704 Debug.Assert(operatingSystem.Platform != PlatformID.Win32Windows, "Windows 9x is not supported");
707 // Detect ASP+ as a platform running under NT
712 IsAspNetServer = (Thread.GetDomain().GetData(".appDomain") != null);
716 IsWin7orLater = (operatingSystem.Version >= new Version(6, 1));
718 IsWin7Sp1orLater = (operatingSystem.Version >= new Version(6, 1, 7601));
720 IsWin8orLater = (operatingSystem.Version >= new Version(6, 2));
722 InstallationType = GetWindowsInstallType();
723 if (Logging.On) Logging.PrintInfo(Logging.Web, SR.GetString(SR.net_osinstalltype, InstallationType));
726 [RegistryPermission(SecurityAction.Assert, Read = OSInstallTypeRegKeyPath)]
727 private static WindowsInstallationType GetWindowsInstallType()
731 using (RegistryKey installTypeKey = Registry.LocalMachine.OpenSubKey(OSInstallTypeRegKey))
733 string installType = installTypeKey.GetValue(OSInstallTypeRegName) as string;
735 if (string.IsNullOrEmpty(installType))
737 if (Logging.On) Logging.PrintWarning(Logging.Web, SR.GetString(SR.net_empty_osinstalltype, OSInstallTypeRegKey + "\\" + OSInstallTypeRegName));
738 return WindowsInstallationType.Unknown;
742 if (String.Compare(installType, InstallTypeStringClient, StringComparison.OrdinalIgnoreCase) == 0)
744 return WindowsInstallationType.Client;
746 if (String.Compare(installType, InstallTypeStringServer, StringComparison.OrdinalIgnoreCase) == 0)
748 return WindowsInstallationType.Server;
750 if (String.Compare(installType, InstallTypeStringServerCore, StringComparison.OrdinalIgnoreCase) == 0)
752 return WindowsInstallationType.ServerCore;
754 if (String.Compare(installType, InstallTypeStringEmbedded, StringComparison.OrdinalIgnoreCase) == 0)
756 return WindowsInstallationType.Embedded;
759 if (Logging.On) Logging.PrintError(Logging.Web, SR.GetString(SR.net_unknown_osinstalltype, installType));
761 // Our default return is unknown when we don't recognize the SKU or if the registry value
762 // doesn't exist. As a result, the SKU-specific checks in System.Net will not limit the set
763 // of functionality available. This allows SKUs we are not aware of to use all of our
764 // functionality. Burden is on them to ensure that all our dependencies are present.
765 // The alternative would be for us to throw an exception here. If we did this, these other
766 // SKUs wouldn't be able to load this code and test their behavior. We would need to update
767 // this code to enable them to run.
768 return WindowsInstallationType.Unknown;
772 catch (UnauthorizedAccessException e)
774 if (Logging.On) Logging.PrintWarning(Logging.Web, SR.GetString(SR.net_cant_determine_osinstalltype, OSInstallTypeRegKey, e.Message));
775 return WindowsInstallationType.Unknown;
777 catch (SecurityException e)
779 if (Logging.On) Logging.PrintWarning(Logging.Web, SR.GetString(SR.net_cant_determine_osinstalltype, OSInstallTypeRegKey, e.Message));
780 return WindowsInstallationType.Unknown;
788 // support class for Validation related stuff.
790 internal static class ValidationHelper {
792 public static string [] EmptyArray = new string[0];
794 internal static readonly char[] InvalidMethodChars =
802 // invalid characters that cannot be found in a valid method-verb or http header
803 internal static readonly char[] InvalidParamChars =
828 public static string [] MakeEmptyArrayNull(string [] stringArray) {
829 if ( stringArray == null || stringArray.Length == 0 ) {
836 public static string MakeStringNull(string stringValue) {
837 if ( stringValue == null || stringValue.Length == 0) {
845 // Consider removing.
846 public static string MakeStringEmpty(string stringValue) {
847 if ( stringValue == null || stringValue.Length == 0) {
857 // Consider removing.
858 public static int HashCode(object objectValue) {
859 if (objectValue == null) {
862 return objectValue.GetHashCode();
868 public static string ExceptionMessage(Exception exception) {
869 if (exception==null) {
872 if (exception.InnerException==null) {
873 return exception.Message;
875 return exception.Message + " (" + ExceptionMessage(exception.InnerException) + ")";
878 public static string ToString(object objectValue) {
879 if (objectValue == null) {
881 } else if (objectValue is string && ((string)objectValue).Length==0) {
882 return "(string.empty)";
883 } else if (objectValue is Exception) {
884 return ExceptionMessage(objectValue as Exception);
885 } else if (objectValue is IntPtr) {
886 return "0x" + ((IntPtr)objectValue).ToString("x");
888 return objectValue.ToString();
891 public static string HashString(object objectValue) {
892 if (objectValue == null) {
894 } else if (objectValue is string && ((string)objectValue).Length==0) {
895 return "(string.empty)";
897 return objectValue.GetHashCode().ToString(NumberFormatInfo.InvariantInfo);
901 public static bool IsInvalidHttpString(string stringValue) {
902 return stringValue.IndexOfAny(InvalidParamChars)!=-1;
905 public static bool IsBlankString(string stringValue) {
906 return stringValue==null || stringValue.Length==0;
910 // Consider removing.
911 public static bool ValidateUInt32(long address) {
912 // on false, API should throw new ArgumentOutOfRangeException("address");
913 return address>=0x00000000 && address<=0xFFFFFFFF;
917 public static bool ValidateTcpPort(int port) {
918 // on false, API should throw new ArgumentOutOfRangeException("port");
919 return port>=IPEndPoint.MinPort && port<=IPEndPoint.MaxPort;
922 public static bool ValidateRange(int actual, int fromAllowed, int toAllowed) {
923 // on false, API should throw new ArgumentOutOfRangeException("argument");
924 return actual>=fromAllowed && actual<=toAllowed;
928 // Consider removing.
929 public static bool ValidateRange(long actual, long fromAllowed, long toAllowed) {
930 // on false, API should throw new ArgumentOutOfRangeException("argument");
931 return actual>=fromAllowed && actual<=toAllowed;
935 // There are threading tricks a malicious app can use to create an ArraySegment with mismatched
936 // array/offset/count. Copy locally and make sure they're valid before using them.
937 internal static void ValidateSegment(ArraySegment<byte> segment) {
938 if (segment == null || segment.Array == null) {
939 throw new ArgumentNullException("segment");
941 // Length zero is explicitly allowed
942 if (segment.Offset < 0 || segment.Count < 0
943 || segment.Count > (segment.Array.Length - segment.Offset)) {
944 throw new ArgumentOutOfRangeException("segment");
949 internal static class ExceptionHelper
952 internal static readonly KeyContainerPermission KeyContainerPermissionOpen = new KeyContainerPermission(KeyContainerPermissionFlags.Open);
953 internal static readonly WebPermission WebPermissionUnrestricted = new WebPermission(NetworkAccess.Connect);
954 internal static readonly SecurityPermission UnmanagedPermission = new SecurityPermission(SecurityPermissionFlag.UnmanagedCode);
955 internal static readonly SocketPermission UnrestrictedSocketPermission = new SocketPermission(PermissionState.Unrestricted);
956 internal static readonly SecurityPermission InfrastructurePermission = new SecurityPermission(SecurityPermissionFlag.Infrastructure);
957 internal static readonly SecurityPermission ControlPolicyPermission = new SecurityPermission(SecurityPermissionFlag.ControlPolicy);
958 internal static readonly SecurityPermission ControlPrincipalPermission = new SecurityPermission(SecurityPermissionFlag.ControlPrincipal);
960 internal static NotImplementedException MethodNotImplementedException {
962 return new NotImplementedException(SR.GetString(SR.net_MethodNotImplementedException));
966 internal static NotImplementedException PropertyNotImplementedException {
968 return new NotImplementedException(SR.GetString(SR.net_PropertyNotImplementedException));
972 internal static NotSupportedException MethodNotSupportedException {
974 return new NotSupportedException(SR.GetString(SR.net_MethodNotSupportedException));
978 internal static NotSupportedException PropertyNotSupportedException {
980 return new NotSupportedException(SR.GetString(SR.net_PropertyNotSupportedException));
984 #if MONO_FEATURE_WEB_STACK
985 internal static WebException IsolatedException {
987 return new WebException(NetRes.GetWebStatusString("net_requestaborted", WebExceptionStatus.KeepAliveFailure),WebExceptionStatus.KeepAliveFailure, WebExceptionInternalStatus.Isolated, null);
991 internal static WebException RequestAbortedException {
993 return new WebException(NetRes.GetWebStatusString("net_requestaborted", WebExceptionStatus.RequestCanceled), WebExceptionStatus.RequestCanceled);
997 internal static WebException CacheEntryNotFoundException {
999 return new WebException(NetRes.GetWebStatusString("net_requestaborted", WebExceptionStatus.CacheEntryNotFound), WebExceptionStatus.CacheEntryNotFound);
1003 internal static WebException RequestProhibitedByCachePolicyException {
1005 return new WebException(NetRes.GetWebStatusString("net_requestaborted", WebExceptionStatus.RequestProhibitedByCachePolicy), WebExceptionStatus.RequestProhibitedByCachePolicy);
1011 internal enum WindowsInstallationType
1020 internal enum SecurityStatus
1022 // Success / Informational
1024 ContinueNeeded = unchecked((int)0x00090312),
1025 CompleteNeeded = unchecked((int)0x00090313),
1026 CompAndContinue = unchecked((int)0x00090314),
1027 ContextExpired = unchecked((int)0x00090317),
1028 CredentialsNeeded = unchecked((int)0x00090320),
1029 Renegotiate = unchecked((int)0x00090321),
1032 OutOfMemory = unchecked((int)0x80090300),
1033 InvalidHandle = unchecked((int)0x80090301),
1034 Unsupported = unchecked((int)0x80090302),
1035 TargetUnknown = unchecked((int)0x80090303),
1036 InternalError = unchecked((int)0x80090304),
1037 PackageNotFound = unchecked((int)0x80090305),
1038 NotOwner = unchecked((int)0x80090306),
1039 CannotInstall = unchecked((int)0x80090307),
1040 InvalidToken = unchecked((int)0x80090308),
1041 CannotPack = unchecked((int)0x80090309),
1042 QopNotSupported = unchecked((int)0x8009030A),
1043 NoImpersonation = unchecked((int)0x8009030B),
1044 LogonDenied = unchecked((int)0x8009030C),
1045 UnknownCredentials = unchecked((int)0x8009030D),
1046 NoCredentials = unchecked((int)0x8009030E),
1047 MessageAltered = unchecked((int)0x8009030F),
1048 OutOfSequence = unchecked((int)0x80090310),
1049 NoAuthenticatingAuthority = unchecked((int)0x80090311),
1050 IncompleteMessage = unchecked((int)0x80090318),
1051 IncompleteCredentials = unchecked((int)0x80090320),
1052 BufferNotEnough = unchecked((int)0x80090321),
1053 WrongPrincipal = unchecked((int)0x80090322),
1054 TimeSkew = unchecked((int)0x80090324),
1055 UntrustedRoot = unchecked((int)0x80090325),
1056 IllegalMessage = unchecked((int)0x80090326),
1057 CertUnknown = unchecked((int)0x80090327),
1058 CertExpired = unchecked((int)0x80090328),
1059 AlgorithmMismatch = unchecked((int)0x80090331),
1060 SecurityQosFailed = unchecked((int)0x80090332),
1061 SmartcardLogonRequired = unchecked((int)0x8009033E),
1062 UnsupportedPreauth = unchecked((int)0x80090343),
1063 BadBinding = unchecked((int)0x80090346)
1066 internal enum ContentTypeValues {
1067 ChangeCipherSpec = 0x14,
1071 Unrecognized = 0xFF,
1074 internal enum ContextAttribute {
1076 // look into <sspi.h> and <schannel.h>
1083 //KeyInfo = 0x05, must not be used, see ConnectionInfo instead
1085 // SECPKG_ATTR_PROTO_INFO = 7,
1086 // SECPKG_ATTR_PASSWORD_EXPIRY = 8,
1087 // SECPKG_ATTR_SESSION_KEY = 9,
1089 // SECPKG_ATTR_USER_FLAGS = 11,
1090 NegotiationInfo = 0x0C,
1091 // SECPKG_ATTR_NATIVE_NAMES = 13,
1092 // SECPKG_ATTR_FLAGS = 14,
1093 // SECPKG_ATTR_USE_VALIDATED = 15,
1094 // SECPKG_ATTR_CREDENTIAL_NAME = 16,
1095 // SECPKG_ATTR_TARGET_INFORMATION = 17,
1096 // SECPKG_ATTR_ACCESS_TOKEN = 18,
1097 // SECPKG_ATTR_TARGET = 19,
1098 // SECPKG_ATTR_AUTHENTICATION_ID = 20,
1099 UniqueBindings = 0x19,
1100 EndpointBindings = 0x1A,
1101 ClientSpecifiedSpn = 0x1B, // SECPKG_ATTR_CLIENT_SPECIFIED_TARGET = 27
1102 RemoteCertificate = 0x53,
1103 LocalCertificate = 0x54,
1105 IssuerListInfoEx = 0x59,
1106 ConnectionInfo = 0x5A,
1107 // SECPKG_ATTR_EAP_KEY_BLOCK 0x5b // returns SecPkgContext_EapKeyBlock
1108 // SECPKG_ATTR_MAPPED_CRED_ATTR 0x5c // returns SecPkgContext_MappedCredAttr
1109 // SECPKG_ATTR_SESSION_INFO 0x5d // returns SecPkgContext_SessionInfo
1110 // SECPKG_ATTR_APP_DATA 0x5e // sets/returns SecPkgContext_SessionAppData
1111 // SECPKG_ATTR_REMOTE_CERTIFICATES 0x5F // returns SecPkgContext_Certificates
1112 // SECPKG_ATTR_CLIENT_CERT_POLICY 0x60 // sets SecPkgCred_ClientCertCtlPolicy
1113 // SECPKG_ATTR_CC_POLICY_RESULT 0x61 // returns SecPkgContext_ClientCertPolicyResult
1114 // SECPKG_ATTR_USE_NCRYPT 0x62 // Sets the CRED_FLAG_USE_NCRYPT_PROVIDER FLAG on cred group
1115 // SECPKG_ATTR_LOCAL_CERT_INFO 0x63 // returns SecPkgContext_CertInfo
1116 // SECPKG_ATTR_CIPHER_INFO 0x64 // returns new CNG SecPkgContext_CipherInfo
1117 // SECPKG_ATTR_EAP_PRF_INFO 0x65 // sets SecPkgContext_EapPrfInfo
1118 // SECPKG_ATTR_SUPPORTED_SIGNATURES 0x66 // returns SecPkgContext_SupportedSignatures
1119 // SECPKG_ATTR_REMOTE_CERT_CHAIN 0x67 // returns PCCERT_CONTEXT
1120 UiInfo = 0x68, // sets SEcPkgContext_UiInfo
1123 internal enum Endianness {
1128 internal enum CredentialUse {
1134 internal enum BufferType {
1143 Padding = 0x09, // non-data padding
1145 ChannelBindings = 0x0E,
1147 ReadOnlyFlag = unchecked((int)0x80000000),
1148 ReadOnlyWithChecksum= 0x10000000
1151 internal enum ChainPolicyType {
1154 Authenticode_TS = 3,
1156 BasicConstraints = 5,
1160 internal enum IgnoreCertProblem {
1161 not_time_valid = 0x00000001,
1162 ctl_not_time_valid = 0x00000002,
1163 not_time_nested = 0x00000004,
1164 invalid_basic_constraints = 0x00000008,
1166 all_not_time_valid =
1168 ctl_not_time_valid |
1171 allow_unknown_ca = 0x00000010,
1172 wrong_usage = 0x00000020,
1173 invalid_name = 0x00000040,
1174 invalid_policy = 0x00000080,
1175 end_rev_unknown = 0x00000100,
1176 ctl_signer_rev_unknown = 0x00000200,
1177 ca_rev_unknown = 0x00000400,
1178 root_rev_unknown = 0x00000800,
1182 ctl_signer_rev_unknown |
1187 ctl_not_time_valid |
1189 invalid_basic_constraints |
1195 ctl_signer_rev_unknown |
1200 internal enum CertUsage {
1201 MatchTypeAnd = 0x00,
1207 [StructLayout(LayoutKind.Sequential)]
1208 internal unsafe struct ChainPolicyParameter {
1210 public uint dwFlags;
1211 public SSL_EXTRA_CERT_CHAIN_POLICY_PARA* pvExtraPolicyPara;
1213 public static readonly uint StructSize = (uint) Marshal.SizeOf(typeof(ChainPolicyParameter));
1216 [StructLayout(LayoutKind.Sequential)]
1217 internal unsafe struct SSL_EXTRA_CERT_CHAIN_POLICY_PARA {
1219 [StructLayout(LayoutKind.Explicit)]
1221 [FieldOffset(0)] internal uint cbStruct; //DWORD
1222 [FieldOffset(0)] internal uint cbSize; //DWORD
1225 internal int dwAuthType; //DWORD
1226 internal uint fdwChecks; //DWORD
1227 internal char* pwszServerName; //WCHAR* // used to check against CN=xxxx
1229 internal SSL_EXTRA_CERT_CHAIN_POLICY_PARA(bool amIServer)
1231 u.cbStruct = StructSize;
1232 u.cbSize = StructSize;
1233 //# define AUTHTYPE_CLIENT 1
1234 //# define AUTHTYPE_SERVER 2
1235 dwAuthType = amIServer? 1: 2;
1237 pwszServerName = null;
1239 static readonly uint StructSize = (uint) Marshal.SizeOf(typeof(SSL_EXTRA_CERT_CHAIN_POLICY_PARA));
1242 [StructLayout(LayoutKind.Sequential)]
1243 internal unsafe struct ChainPolicyStatus {
1245 public uint dwError;
1246 public uint lChainIndex;
1247 public uint lElementIndex;
1248 public void* pvExtraPolicyStatus;
1250 public static readonly uint StructSize = (uint) Marshal.SizeOf(typeof(ChainPolicyStatus));
1253 [StructLayout(LayoutKind.Sequential)]
1254 internal unsafe struct CertEnhKeyUse {
1256 public uint cUsageIdentifier;
1257 public void* rgpszUsageIdentifier;
1260 public override string ToString() {
1261 return "cUsageIdentifier="+cUsageIdentifier.ToString()+ " rgpszUsageIdentifier=" + new IntPtr(rgpszUsageIdentifier).ToString("x");
1266 [StructLayout(LayoutKind.Sequential)]
1267 internal struct CertUsageMatch {
1268 public CertUsage dwType;
1269 public CertEnhKeyUse Usage;
1271 public override string ToString() {
1272 return "dwType="+dwType.ToString()+" "+Usage.ToString();
1277 [StructLayout(LayoutKind.Sequential)]
1278 internal struct ChainParameters {
1280 public CertUsageMatch RequestedUsage;
1281 public CertUsageMatch RequestedIssuancePolicy;
1282 public uint UrlRetrievalTimeout;
1283 public int BoolCheckRevocationFreshnessTime;
1284 public uint RevocationFreshnessTime;
1287 public static readonly uint StructSize = (uint) Marshal.SizeOf(typeof(ChainParameters));
1289 public override string ToString() {
1290 return "cbSize="+cbSize.ToString()+" "+RequestedUsage.ToString();
1295 [StructLayout(LayoutKind.Sequential)]
1296 struct _CERT_CHAIN_ELEMENT
1299 public IntPtr pCertContext;
1300 // Since this structure is allocated by unmanaged code, we can
1301 // omit the fileds below since we don't need to access them
1302 // CERT_TRUST_STATUS TrustStatus;
1303 // IntPtr pRevocationInfo;
1304 // IntPtr pIssuanceUsage;
1305 // IntPtr pApplicationUsage;
1309 //[StructLayout(LayoutKind.Sequential)]
1310 //unsafe struct CryptoBlob {
1311 // // public uint cbData;
1312 // // public byte* pbData;
1313 // public uint dataSize;
1314 // public byte* dataBlob;
1317 // SecPkgContext_IssuerListInfoEx
1318 [StructLayout(LayoutKind.Sequential)]
1319 unsafe struct IssuerListInfoEx {
1320 public SafeHandle aIssuers;
1321 public uint cIssuers;
1323 public unsafe IssuerListInfoEx(SafeHandle handle, byte[] nativeBuffer) {
1325 fixed(byte* voidPtr = nativeBuffer) {
1326 // if this breaks on 64 bit, do the sizeof(IntPtr) trick
1327 cIssuers = *((uint*)(voidPtr + IntPtr.Size));
1333 [StructLayout(LayoutKind.Sequential)]
1334 internal struct SecureCredential {
1337 typedef struct _SCHANNEL_CRED
1339 DWORD dwVersion; // always SCHANNEL_CRED_VERSION
1341 PCCERT_CONTEXT *paCred;
1342 HCERTSTORE hRootStore;
1345 struct _HMAPPER **aphMappers;
1347 DWORD cSupportedAlgs;
1348 ALG_ID * palgSupportedAlgs;
1350 DWORD grbitEnabledProtocols;
1351 DWORD dwMinimumCipherStrength;
1352 DWORD dwMaximumCipherStrength;
1353 DWORD dwSessionLifespan;
1356 } SCHANNEL_CRED, *PSCHANNEL_CRED;
1359 public const int CurrentVersion = 0x4;
1364 // ptr to an array of pointers
1365 // There is a hack done with this field. AcquireCredentialsHandle requires an array of
1366 // certificate handles; we only ever use one. In order to avoid pinning a one element array,
1367 // we copy this value onto the stack, create a pointer on the stack to the copied value,
1368 // and replace this field with the pointer, during the call to AcquireCredentialsHandle.
1369 // Then we fix it up afterwards. Fine as long as all the SSPI credentials are not
1370 // supposed to be threadsafe.
1371 public IntPtr certContextArray;
1373 private readonly IntPtr rootStore; // == always null, OTHERWISE NOT RELIABLE
1374 public int cMappers;
1375 private readonly IntPtr phMappers; // == always null, OTHERWISE NOT RELIABLE
1376 public int cSupportedAlgs;
1377 private readonly IntPtr palgSupportedAlgs; // == always null, OTHERWISE NOT RELIABLE
1378 public SchProtocols grbitEnabledProtocols;
1379 public int dwMinimumCipherStrength;
1380 public int dwMaximumCipherStrength;
1381 public int dwSessionLifespan;
1382 public SecureCredential.Flags dwFlags;
1383 public int reserved;
1388 NoSystemMapper = 0x02,
1390 ValidateManual = 0x08,
1391 NoDefaultCred = 0x10,
1392 ValidateAuto = 0x20,
1393 UseStrongCrypto = 0x00400000,
1396 public SecureCredential(int version, X509Certificate certificate, SecureCredential.Flags flags, SchProtocols protocols, EncryptionPolicy policy) {
1397 // default values required for a struct
1398 rootStore = phMappers = palgSupportedAlgs = certContextArray = IntPtr.Zero;
1399 cCreds = cMappers = cSupportedAlgs = 0;
1401 if (policy == EncryptionPolicy.RequireEncryption) {
1402 // Prohibit null encryption cipher
1403 dwMinimumCipherStrength = 0;
1404 dwMaximumCipherStrength = 0;
1406 else if (policy == EncryptionPolicy.AllowNoEncryption) {
1407 // Allow null encryption cipher in addition to other ciphers
1408 dwMinimumCipherStrength = -1;
1409 dwMaximumCipherStrength = 0;
1411 else if (policy == EncryptionPolicy.NoEncryption) {
1412 // Suppress all encryption and require null encryption cipher only
1413 dwMinimumCipherStrength = -1;
1414 dwMaximumCipherStrength = -1;
1417 throw new ArgumentException(SR.GetString(SR.net_invalid_enum, "EncryptionPolicy"), "policy");
1420 dwSessionLifespan = reserved = 0;
1421 this.version = version;
1423 grbitEnabledProtocols = protocols;
1424 if (certificate != null) {
1425 certContextArray = certificate.Handle;
1430 [System.Diagnostics.Conditional("TRAVE")]
1431 internal void DebugDump() {
1432 GlobalLog.Print("SecureCredential #"+GetHashCode());
1433 GlobalLog.Print(" version = " + version);
1434 GlobalLog.Print(" cCreds = " + cCreds);
1435 GlobalLog.Print(" certContextArray = " + String.Format("0x{0:x}", certContextArray));
1436 GlobalLog.Print(" rootStore = " + String.Format("0x{0:x}", rootStore));
1437 GlobalLog.Print(" cMappers = " + cMappers);
1438 GlobalLog.Print(" phMappers = " + String.Format("0x{0:x}", phMappers));
1439 GlobalLog.Print(" cSupportedAlgs = " + cSupportedAlgs);
1440 GlobalLog.Print(" palgSupportedAlgs = " + String.Format("0x{0:x}", palgSupportedAlgs));
1441 GlobalLog.Print(" grbitEnabledProtocols = " + String.Format("0x{0:x}", grbitEnabledProtocols));
1442 GlobalLog.Print(" dwMinimumCipherStrength = " + dwMinimumCipherStrength);
1443 GlobalLog.Print(" dwMaximumCipherStrength = " + dwMaximumCipherStrength);
1444 GlobalLog.Print(" dwSessionLifespan = " + String.Format("0x{0:x}", dwSessionLifespan));
1445 GlobalLog.Print(" dwFlags = " + String.Format("0x{0:x}", dwFlags));
1446 GlobalLog.Print(" reserved = " + String.Format("0x{0:x}", reserved));
1449 } // SecureCredential
1451 #endif // !FEATURE_PAL
1453 [StructLayout(LayoutKind.Sequential)]
1454 internal unsafe struct SecurityBufferStruct {
1456 public BufferType type;
1457 public IntPtr token;
1459 public static readonly int Size = sizeof(SecurityBufferStruct);
1462 internal class SecurityBuffer {
1464 public BufferType type;
1465 public byte[] token;
1466 public SafeHandle unmanagedToken;
1469 public SecurityBuffer(byte[] data, int offset, int size, BufferType tokentype) {
1470 GlobalLog.Assert(offset >= 0 && offset <= (data == null ? 0 : data.Length), "SecurityBuffer::.ctor", "'offset' out of range. [" + offset + "]");
1471 GlobalLog.Assert(size >= 0 && size <= (data == null ? 0 : data.Length - offset), "SecurityBuffer::.ctor", "'size' out of range. [" + size + "]");
1473 this.offset = data == null || offset < 0 ? 0 : Math.Min(offset, data.Length);
1474 this.size = data == null || size < 0 ? 0 : Math.Min(size, data.Length - this.offset);
1475 this.type = tokentype;
1476 this.token = size == 0 ? null : data;
1479 public SecurityBuffer(byte[] data, BufferType tokentype) {
1480 this.size = data == null ? 0 : data.Length;
1481 this.type = tokentype;
1482 this.token = size == 0 ? null : data;
1485 public SecurityBuffer(int size, BufferType tokentype) {
1486 GlobalLog.Assert(size >= 0, "SecurityBuffer::.ctor", "'size' out of range. [" + size.ToString(NumberFormatInfo.InvariantInfo) + "]");
1489 this.type = tokentype;
1490 this.token = size == 0 ? null : new byte[size];
1493 public SecurityBuffer(ChannelBinding binding) {
1494 this.size = (binding == null ? 0 : binding.Size);
1495 this.type = BufferType.ChannelBindings;
1496 this.unmanagedToken = binding;
1500 [StructLayout(LayoutKind.Sequential)]
1501 internal unsafe class SecurityBufferDescriptor {
1503 typedef struct _SecBufferDesc {
1506 PSecBuffer pBuffers;
1507 } SecBufferDesc, * PSecBufferDesc;
1509 public readonly int Version;
1510 public readonly int Count;
1511 public void* UnmanagedPointer;
1513 public SecurityBufferDescriptor(int count) {
1516 UnmanagedPointer = null;
1519 [System.Diagnostics.Conditional("TRAVE")]
1520 internal void DebugDump() {
1521 GlobalLog.Print("SecurityBufferDescriptor #" + ValidationHelper.HashString(this));
1522 GlobalLog.Print(" version = " + Version);
1523 GlobalLog.Print(" count = " + Count);
1524 GlobalLog.Print(" securityBufferArray = 0x" + (new IntPtr(UnmanagedPointer)).ToString("x"));
1526 } // SecurityBufferDescriptor
1528 internal enum CertificateEncoding {
1530 X509AsnEncoding = unchecked((int)0x00000001),
1531 X509NdrEncoding = unchecked((int)0x00000002),
1532 Pkcs7AsnEncoding = unchecked((int)0x00010000),
1533 Pkcs7NdrEncoding = unchecked((int)0x00020000),
1534 AnyAsnEncoding = X509AsnEncoding|Pkcs7AsnEncoding
1537 internal enum CertificateProblem {
1539 TrustNOSIGNATURE = unchecked((int)0x800B0100),
1540 CertEXPIRED = unchecked((int)0x800B0101),
1541 CertVALIDITYPERIODNESTING = unchecked((int)0x800B0102),
1542 CertROLE = unchecked((int)0x800B0103),
1543 CertPATHLENCONST = unchecked((int)0x800B0104),
1544 CertCRITICAL = unchecked((int)0x800B0105),
1545 CertPURPOSE = unchecked((int)0x800B0106),
1546 CertISSUERCHAINING = unchecked((int)0x800B0107),
1547 CertMALFORMED = unchecked((int)0x800B0108),
1548 CertUNTRUSTEDROOT = unchecked((int)0x800B0109),
1549 CertCHAINING = unchecked((int)0x800B010A),
1550 CertREVOKED = unchecked((int)0x800B010C),
1551 CertUNTRUSTEDTESTROOT = unchecked((int)0x800B010D),
1552 CertREVOCATION_FAILURE = unchecked((int)0x800B010E),
1553 CertCN_NO_MATCH = unchecked((int)0x800B010F),
1554 CertWRONG_USAGE = unchecked((int)0x800B0110),
1555 TrustEXPLICITDISTRUST = unchecked((int)0x800B0111),
1556 CertUNTRUSTEDCA = unchecked((int)0x800B0112),
1557 CertINVALIDPOLICY = unchecked((int)0x800B0113),
1558 CertINVALIDNAME = unchecked((int)0x800B0114),
1560 CryptNOREVOCATIONCHECK = unchecked((int)0x80092012),
1561 CryptREVOCATIONOFFLINE = unchecked((int)0x80092013),
1563 TrustSYSTEMERROR = unchecked((int)0x80096001),
1564 TrustNOSIGNERCERT = unchecked((int)0x80096002),
1565 TrustCOUNTERSIGNER = unchecked((int)0x80096003),
1566 TrustCERTSIGNATURE = unchecked((int)0x80096004),
1567 TrustTIMESTAMP = unchecked((int)0x80096005),
1568 TrustBADDIGEST = unchecked((int)0x80096010),
1569 TrustBASICCONSTRAINTS = unchecked((int)0x80096019),
1570 TrustFINANCIALCRITERIA = unchecked((int)0x8009601E),
1573 [StructLayout(LayoutKind.Sequential)]
1574 internal class SecChannelBindings
1576 internal int dwInitiatorAddrType;
1577 internal int cbInitiatorLength;
1578 internal int dwInitiatorOffset;
1580 internal int dwAcceptorAddrType;
1581 internal int cbAcceptorLength;
1582 internal int dwAcceptorOffset;
1584 internal int cbApplicationDataLength;
1585 internal int dwApplicationDataOffset;
1589 // WebRequestPrefixElement
1591 // This is an element of the prefix list. It contains the prefix and the
1592 // interface to be called to create a request for that prefix.
1596 /// <para>[To be supplied.]</para>
1598 // internal class WebRequestPrefixElement {
1599 internal class WebRequestPrefixElement {
1602 /// <para>[To be supplied.]</para>
1604 public string Prefix;
1606 /// <para>[To be supplied.]</para>
1608 internal IWebRequestCreate creator;
1610 /// <para>[To be supplied.]</para>
1612 internal Type creatorType;
1614 public IWebRequestCreate Creator {
1616 if (creator == null && creatorType != null) {
1618 if (creator == null) {
1619 creator = (IWebRequestCreate)Activator.CreateInstance(
1621 BindingFlags.CreateInstance
1622 | BindingFlags.Instance
1623 | BindingFlags.NonPublic
1624 | BindingFlags.Public,
1626 new object[0], // no arguments
1627 CultureInfo.InvariantCulture
1641 public WebRequestPrefixElement(string P, Type creatorType) {
1642 // verify that its of the proper type of IWebRequestCreate
1643 if (!typeof(IWebRequestCreate).IsAssignableFrom(creatorType))
1645 throw new InvalidCastException(SR.GetString(SR.net_invalid_cast,
1646 creatorType.AssemblyQualifiedName,
1647 "IWebRequestCreate"));
1651 this.creatorType = creatorType;
1655 /// <para>[To be supplied.]</para>
1657 public WebRequestPrefixElement(string P, IWebRequestCreate C) {
1662 } // class PrefixListElement
1665 #if MONO_FEATURE_WEB_STACK
1668 // HttpRequestCreator.
1670 // This is the class that we use to create HTTP and HTTPS requests.
1673 internal class HttpRequestCreator : IWebRequestCreate {
1677 Create - Create an HttpWebRequest.
1679 This is our method to create an HttpWebRequest. We register
1680 for HTTP and HTTPS Uris, and this method is called when a request
1681 needs to be created for one of those.
1685 Uri - Uri for request being created.
1688 The newly created HttpWebRequest.
1692 public WebRequest Create( Uri Uri ) {
1694 // Note, DNS permissions check will not happen on WebRequest
1696 return new HttpWebRequest(Uri, null);
1699 } // class HttpRequestCreator
1702 // WebSocketHttpRequestCreator.
1704 // This is the class that we use to create WebSocket connection requests.
1707 internal class WebSocketHttpRequestCreator : IWebRequestCreate
1709 private string m_httpScheme;
1711 // This ctor is used to create a WebSocketHttpRequestCreator.
1712 // We will do a URI change to update the scheme with Http or Https scheme. The usingHttps boolean is
1713 // used to indicate whether the created HttpWebRequest should take the https scheme or not.
1714 public WebSocketHttpRequestCreator(bool usingHttps)
1716 m_httpScheme = usingHttps ? Uri.UriSchemeHttps : Uri.UriSchemeHttp;
1721 Create - Create an HttpWebRequest.
1723 This is our method to create an HttpWebRequest for WebSocket connection. We register
1724 We will register it for custom Uri prefixes. And this method is called when a request
1725 needs to be created for one of those. The created HttpWebRequest will still be with Http or Https
1726 scheme, depending on the m_httpScheme field of this object.
1730 Uri - Uri for request being created.
1733 The newly created HttpWebRequest for WebSocket connection.
1737 public WebRequest Create(Uri Uri)
1739 UriBuilder uriBuilder = new UriBuilder(Uri);
1740 uriBuilder.Scheme = m_httpScheme;
1741 HttpWebRequest request = new HttpWebRequest(uriBuilder.Uri, null, true, "WebSocket" + Guid.NewGuid());
1742 WebSocketHelpers.PrepareWebRequest(ref request);
1746 } // class WebSocketHttpRequestCreator
1752 // CoreResponseData - Used to store result of HTTP header parsing and
1753 // response parsing. Also Contains new stream to use, and
1754 // is used as core of new Response
1756 internal class CoreResponseData {
1758 // Status Line Response Values
1759 public HttpStatusCode m_StatusCode;
1760 public string m_StatusDescription;
1761 public bool m_IsVersionHttp11;
1763 // Content Length needed for semantics, -1 if chunked
1764 public long m_ContentLength;
1767 public WebHeaderCollection m_ResponseHeaders;
1769 // ConnectStream - for reading actual data
1770 public Stream m_ConnectStream;
1772 internal CoreResponseData Clone() {
1773 CoreResponseData cloneResponseData = new CoreResponseData();
1774 cloneResponseData.m_StatusCode = m_StatusCode;
1775 cloneResponseData.m_StatusDescription = m_StatusDescription;
1776 cloneResponseData.m_IsVersionHttp11 = m_IsVersionHttp11;
1777 cloneResponseData.m_ContentLength = m_ContentLength;
1778 cloneResponseData.m_ResponseHeaders = m_ResponseHeaders;
1779 cloneResponseData.m_ConnectStream = m_ConnectStream;
1780 return cloneResponseData;
1787 internal delegate bool HttpAbortDelegate(HttpWebRequest request, WebException webException);
1790 // this class contains known header names
1793 internal static class HttpKnownHeaderNames {
1795 public const string CacheControl = "Cache-Control";
1796 public const string Connection = "Connection";
1797 public const string Date = "Date";
1798 public const string KeepAlive = "Keep-Alive";
1799 public const string Pragma = "Pragma";
1800 public const string ProxyConnection = "Proxy-Connection";
1801 public const string Trailer = "Trailer";
1802 public const string TransferEncoding = "Transfer-Encoding";
1803 public const string Upgrade = "Upgrade";
1804 public const string Via = "Via";
1805 public const string Warning = "Warning";
1806 public const string ContentLength = "Content-Length";
1807 public const string ContentType = "Content-Type";
1808 public const string ContentDisposition = "Content-Disposition";
1809 public const string ContentEncoding = "Content-Encoding";
1810 public const string ContentLanguage = "Content-Language";
1811 public const string ContentLocation = "Content-Location";
1812 public const string ContentRange = "Content-Range";
1813 public const string Expires = "Expires";
1814 public const string LastModified = "Last-Modified";
1815 public const string Age = "Age";
1816 public const string Location = "Location";
1817 public const string ProxyAuthenticate = "Proxy-Authenticate";
1818 public const string RetryAfter = "Retry-After";
1819 public const string Server = "Server";
1820 public const string SetCookie = "Set-Cookie";
1821 public const string SetCookie2 = "Set-Cookie2";
1822 public const string Vary = "Vary";
1823 public const string WWWAuthenticate = "WWW-Authenticate";
1824 public const string Accept = "Accept";
1825 public const string AcceptCharset = "Accept-Charset";
1826 public const string AcceptEncoding = "Accept-Encoding";
1827 public const string AcceptLanguage = "Accept-Language";
1828 public const string Authorization = "Authorization";
1829 public const string Cookie = "Cookie";
1830 public const string Cookie2 = "Cookie2";
1831 public const string Expect = "Expect";
1832 public const string From = "From";
1833 public const string Host = "Host";
1834 public const string IfMatch = "If-Match";
1835 public const string IfModifiedSince = "If-Modified-Since";
1836 public const string IfNoneMatch = "If-None-Match";
1837 public const string IfRange = "If-Range";
1838 public const string IfUnmodifiedSince = "If-Unmodified-Since";
1839 public const string MaxForwards = "Max-Forwards";
1840 public const string ProxyAuthorization = "Proxy-Authorization";
1841 public const string Referer = "Referer";
1842 public const string Range = "Range";
1843 public const string UserAgent = "User-Agent";
1844 public const string ContentMD5 = "Content-MD5";
1845 public const string ETag = "ETag";
1846 public const string TE = "TE";
1847 public const string Allow = "Allow";
1848 public const string AcceptRanges = "Accept-Ranges";
1849 public const string P3P = "P3P";
1850 public const string XPoweredBy = "X-Powered-By";
1851 public const string XAspNetVersion = "X-AspNet-Version";
1852 public const string SecWebSocketKey = "Sec-WebSocket-Key";
1853 public const string SecWebSocketExtensions = "Sec-WebSocket-Extensions";
1854 public const string SecWebSocketAccept = "Sec-WebSocket-Accept";
1855 public const string Origin = "Origin";
1856 public const string SecWebSocketProtocol = "Sec-WebSocket-Protocol";
1857 public const string SecWebSocketVersion = "Sec-WebSocket-Version";
1862 /// Represents the method that will notify callers when a continue has been
1863 /// received by the client.
1866 // Delegate type for us to notify callers when we receive a continue
1867 public delegate void HttpContinueDelegate(int StatusCode, WebHeaderCollection httpHeaders);
1870 // HttpWriteMode - used to control the way in which an entity Body is posted.
1872 enum HttpWriteMode {
1880 // Used by Request to notify Connection that we are no longer holding the Connection (for NTLM connection sharing)
1881 delegate void UnlockConnectionDelegate();
1883 enum HttpBehaviour : byte {
1886 HTTP11PartiallyCompliant = 2,
1890 internal enum HttpProcessingResult {
1896 #if MONO_FEATURE_WEB_STACK
1898 // HttpVerb - used to define various per Verb Properties
1902 // Note - this is a place holder for Verb properties,
1903 // the following two bools can most likely be combined into
1904 // a single Enum type. And the Verb can be incorporated.
1906 class KnownHttpVerb {
1907 internal string Name; // verb name
1909 internal bool RequireContentBody; // require content body to be sent
1910 internal bool ContentBodyNotAllowed; // not allowed to send content body
1911 internal bool ConnectRequest; // special semantics for a connect request
1912 internal bool ExpectNoContentResponse; // response will not have content body
1914 internal KnownHttpVerb(string name, bool requireContentBody, bool contentBodyNotAllowed, bool connectRequest, bool expectNoContentResponse) {
1916 RequireContentBody = requireContentBody;
1917 ContentBodyNotAllowed = contentBodyNotAllowed;
1918 ConnectRequest = connectRequest;
1919 ExpectNoContentResponse = expectNoContentResponse;
1922 // Force an an init, before we use them
1923 private static ListDictionary NamedHeaders;
1926 internal static KnownHttpVerb Get;
1927 internal static KnownHttpVerb Connect;
1928 internal static KnownHttpVerb Head;
1929 internal static KnownHttpVerb Put;
1930 internal static KnownHttpVerb Post;
1931 internal static KnownHttpVerb MkCol;
1934 // InitializeKnownVerbs - Does basic init for this object,
1935 // such as creating defaultings and filling them
1937 static KnownHttpVerb() {
1938 NamedHeaders = new ListDictionary(CaseInsensitiveAscii.StaticInstance);
1939 Get = new KnownHttpVerb("GET", false, true, false, false);
1940 Connect = new KnownHttpVerb("CONNECT", false, true, true, false);
1941 Head = new KnownHttpVerb("HEAD", false, true, false, true);
1942 Put = new KnownHttpVerb("PUT", true, false, false, false);
1943 Post = new KnownHttpVerb("POST", true, false, false, false);
1944 MkCol = new KnownHttpVerb("MKCOL",false,false,false,false);
1945 NamedHeaders[Get.Name] = Get;
1946 NamedHeaders[Connect.Name] = Connect;
1947 NamedHeaders[Head.Name] = Head;
1948 NamedHeaders[Put.Name] = Put;
1949 NamedHeaders[Post.Name] = Post;
1950 NamedHeaders[MkCol.Name] = MkCol;
1953 public bool Equals(KnownHttpVerb verb) {
1954 return this==verb || string.Compare(Name, verb.Name, StringComparison.OrdinalIgnoreCase)==0;
1957 public static KnownHttpVerb Parse(string name) {
1958 KnownHttpVerb knownHttpVerb = NamedHeaders[name] as KnownHttpVerb;
1959 if (knownHttpVerb==null) {
1960 // unknown verb, default behaviour
1961 knownHttpVerb = new KnownHttpVerb(name, false, false, false, false);
1963 return knownHttpVerb;
1969 // HttpProtocolUtils - A collection of utility functions for HTTP usage.
1972 internal class HttpProtocolUtils {
1974 private HttpProtocolUtils() {
1978 // extra buffers for build/parsing, recv/send HTTP data,
1979 // at some point we should consolidate
1983 // parse String to DateTime format.
1984 internal static DateTime string2date(String S) {
1986 if (HttpDateParse.ParseHttpDate(S,out dtOut)) {
1990 throw new ProtocolViolationException(SR.GetString(SR.net_baddate));
1995 // convert Date to String using RFC 1123 pattern
1996 internal static string date2string(DateTime D) {
1997 DateTimeFormatInfo dateFormat = new DateTimeFormatInfo();
1998 return D.ToUniversalTime().ToString("R", dateFormat);
2004 // Proxy class for linking between ICertificatePolicy <--> ICertificateDecider
2005 internal class PolicyWrapper {
2006 private const uint IgnoreUnmatchedCN = 0x00001000;
2007 private ICertificatePolicy fwdPolicy;
2008 private ServicePoint srvPoint;
2009 private WebRequest request;
2011 internal PolicyWrapper(ICertificatePolicy policy, ServicePoint sp, WebRequest wr) {
2012 this.fwdPolicy = policy;
2017 public bool Accept(X509Certificate Certificate, int CertificateProblem) {
2018 return fwdPolicy.CheckValidationResult(srvPoint, Certificate, request, CertificateProblem);
2021 internal static uint VerifyChainPolicy(SafeFreeCertChain chainContext, ref ChainPolicyParameter cpp) {
2022 GlobalLog.Enter("PolicyWrapper::VerifyChainPolicy", "chainContext="+ chainContext + ", options="+String.Format("0x{0:x}", cpp.dwFlags));
2023 ChainPolicyStatus status = new ChainPolicyStatus();
2024 status.cbSize = ChainPolicyStatus.StructSize;
2026 UnsafeNclNativeMethods.NativePKI.CertVerifyCertificateChainPolicy(
2027 (IntPtr) ChainPolicyType.SSL,
2032 GlobalLog.Print("PolicyWrapper::VerifyChainPolicy() CertVerifyCertificateChainPolicy returned: " + errorCode);
2034 GlobalLog.Print("PolicyWrapper::VerifyChainPolicy() error code: " + status.dwError+String.Format(" [0x{0:x8}", status.dwError) + " " + SecureChannel.MapSecurityStatus(status.dwError) + "]");
2036 GlobalLog.Leave("PolicyWrapper::VerifyChainPolicy", status.dwError.ToString());
2037 return status.dwError;
2040 private static IgnoreCertProblem MapErrorCode(uint errorCode) {
2041 switch ((CertificateProblem) errorCode) {
2043 case CertificateProblem.CertINVALIDNAME :
2044 case CertificateProblem.CertCN_NO_MATCH :
2045 return IgnoreCertProblem.invalid_name;
2047 case CertificateProblem.CertINVALIDPOLICY :
2048 case CertificateProblem.CertPURPOSE :
2049 return IgnoreCertProblem.invalid_policy;
2051 case CertificateProblem.CertEXPIRED :
2052 return IgnoreCertProblem.not_time_valid | IgnoreCertProblem.ctl_not_time_valid;
2054 case CertificateProblem.CertVALIDITYPERIODNESTING :
2055 return IgnoreCertProblem.not_time_nested;
2057 case CertificateProblem.CertCHAINING :
2058 case CertificateProblem.CertUNTRUSTEDCA :
2059 case CertificateProblem.CertUNTRUSTEDROOT :
2060 return IgnoreCertProblem.allow_unknown_ca;
2062 case CertificateProblem.CertREVOKED :
2063 case CertificateProblem.CertREVOCATION_FAILURE :
2064 case CertificateProblem.CryptNOREVOCATIONCHECK:
2065 case CertificateProblem.CryptREVOCATIONOFFLINE:
2066 return IgnoreCertProblem.all_rev_unknown;
2068 case CertificateProblem.CertROLE:
2069 case CertificateProblem.TrustBASICCONSTRAINTS:
2070 return IgnoreCertProblem.invalid_basic_constraints;
2072 case CertificateProblem.CertWRONG_USAGE :
2073 return IgnoreCertProblem.wrong_usage;
2081 private uint[] GetChainErrors(string hostName, X509Chain chain, ref bool fatalError)
2084 SafeFreeCertChain chainContext= new SafeFreeCertChain(chain.ChainContext);
2085 ArrayList certificateProblems = new ArrayList();
2088 ChainPolicyParameter cppStruct = new ChainPolicyParameter();
2089 cppStruct.cbSize = ChainPolicyParameter.StructSize;
2090 cppStruct.dwFlags = 0;
2092 SSL_EXTRA_CERT_CHAIN_POLICY_PARA eppStruct = new SSL_EXTRA_CERT_CHAIN_POLICY_PARA(false);
2093 cppStruct.pvExtraPolicyPara = &eppStruct;
2095 fixed (char* namePtr = hostName) {
2096 if (ServicePointManager.CheckCertificateName){
2097 eppStruct.pwszServerName = namePtr;
2101 status = VerifyChainPolicy(chainContext, ref cppStruct);
2102 uint ignoreErrorMask = (uint)MapErrorCode(status);
2104 certificateProblems.Add(status);
2106 if (status == 0) { // No more problems with the certificate?
2107 break; // Then break out of the callback loop
2110 if (ignoreErrorMask == 0) { // Unrecognized error encountered
2115 cppStruct.dwFlags |= ignoreErrorMask;
2116 if ((CertificateProblem)status == CertificateProblem.CertCN_NO_MATCH && ServicePointManager.CheckCertificateName) {
2117 eppStruct.fdwChecks = IgnoreUnmatchedCN;
2124 return (uint[]) certificateProblems.ToArray(typeof(uint));
2127 internal bool CheckErrors(string hostName, X509Certificate certificate, X509Chain chain, SslPolicyErrors sslPolicyErrors)
2129 if (sslPolicyErrors == 0)
2130 return Accept(certificate, 0);
2132 if ((sslPolicyErrors & SslPolicyErrors.RemoteCertificateNotAvailable) != 0)
2133 return Accept(certificate, (int) CertificateProblem.CertCRITICAL); // ToDO, Define an appropriate enum entry
2135 if ((sslPolicyErrors & SslPolicyErrors.RemoteCertificateChainErrors) != 0 ||
2136 (sslPolicyErrors & SslPolicyErrors.RemoteCertificateNameMismatch) != 0)
2138 bool fatalError = false;
2139 uint[] certificateProblems = GetChainErrors(hostName, chain, ref fatalError);
2142 // By today design we cannot allow decider to ignore a fatal error.
2143 // This error is fatal.
2144 Accept(certificate, (int) SecurityStatus.InternalError);
2149 if (certificateProblems.Length == 0)
2150 return Accept(certificate, (int) CertificateProblem.OK);
2152 // Run each error through Accept().
2153 foreach (uint error in certificateProblems)
2154 if (!Accept(certificate, (int) error))
2161 /* CONSIDER: Use this code when we switch to managed X509 API
2162 internal static int MapStatusToWin32Error(X509ChainStatusFlags status)
2166 case X509ChainStatusFlags.NoError: return CertificateProblem.OK;
2167 case X509ChainStatusFlags.NotTimeValid: return CertificateProblem.CertEXPIRED;
2168 case X509ChainStatusFlags.NotTimeNested: return CertificateProblem.CertVALIDITYPERIODNESTING;
2169 case X509ChainStatusFlags.Revoked: return CertificateProblem.CertREVOKED;
2170 case X509ChainStatusFlags.NotSignatureValid:return CertificateProblem.TrustCERTSIGNATURE;
2171 case X509ChainStatusFlags.NotValidForUsage: return CertificateProblem.CertWRONG_USAGE;
2172 case X509ChainStatusFlags.UntrustedRoot: return CertificateProblem.CertUNTRUSTEDROOT;
2173 case X509ChainStatusFlags.RevocationStatusUnknown: return CertificateProblem.CryptNOREVOCATIONCHECK;
2174 case X509ChainStatusFlags.Cyclic: return CertificateProblem.CertCHAINING; //??
2175 case X509ChainStatusFlags.InvalidExtension: return CertificateProblem.CertCRITICAL; //??
2176 case X509ChainStatusFlags.InvalidPolicyConstraints: return CertificateProblem.CertINVALIDPOLICY;
2177 case X509ChainStatusFlags.InvalidBasicConstraints: return CertificateProblem.TrustBASICCONSTRAINTS;
2178 case X509ChainStatusFlagsInvalidNameConstraints: return CertificateProblem.CertINVALIDNAME;
2179 case X509ChainStatusFlags.HasNotSupportedNameConstraint: return CertificateProblem.CertINVALIDNAME; //??
2180 case X509ChainStatusFlags.HasNotDefinedNameConstraint: return CertificateProblem.CertINVALIDNAME; //??
2181 case X509ChainStatusFlags.HasNotPermittedNameConstraint: return CertificateProblem.CertINVALIDNAME; //??
2182 case X509ChainStatusFlags.HasExcludedNameConstraint: return CertificateProblem.CertINVALIDNAME; //??
2183 case X509ChainStatusFlags.PartialChain: return CertificateProblem.CertCHAINING; //??
2184 case X509ChainStatusFlags.CtlNotTimeValid: return CertificateProblem.CertEXPIRED;
2185 case X509ChainStatusFlags.CtlNotSignatureValid: return CertificateProblem.TrustCERTSIGNATURE;
2186 case X509ChainStatusFlags.CtlNotValidForUsage: return CertificateProblem.CertWRONG_USAGE;
2187 case X509ChainStatusFlags.OfflineRevocation: return CertificateProblem.CryptREVOCATIONOFFLINE;
2188 case X509ChainStatusFlags.NoIssuanceChainPolicy:return CertificateProblem.CertINVALIDPOLICY;
2189 default: return (int) CertificateProblem.TrustSYSTEMERROR; // unknown
2194 // Class implementing default certificate policy
2195 internal class DefaultCertPolicy : ICertificatePolicy {
2196 public bool CheckValidationResult(ServicePoint sp, X509Certificate cert, WebRequest request, int problem) {
2197 return problem == (int)CertificateProblem.OK;
2200 #endif // !FEATURE_PAL
2202 internal enum TriState {
2208 internal enum DefaultPorts {
2209 DEFAULT_FTP_PORT = 21,
2210 DEFAULT_GOPHER_PORT = 70,
2211 DEFAULT_HTTP_PORT = 80,
2212 DEFAULT_HTTPS_PORT = 443,
2213 DEFAULT_NNTP_PORT = 119,
2214 DEFAULT_SMTP_PORT = 25,
2215 DEFAULT_TELNET_PORT = 23
2218 [StructLayout(LayoutKind.Sequential, CharSet=CharSet.Unicode)]
2219 internal struct hostent {
2220 public IntPtr h_name;
2221 public IntPtr h_aliases;
2222 public short h_addrtype;
2223 public short h_length;
2224 public IntPtr h_addr_list;
2228 [StructLayout(LayoutKind.Sequential)]
2229 internal struct Blob {
2231 public int pBlobData;
2235 // This is only for internal code path i.e. TLS stream.
2236 // See comments on GetNextBuffer() method below.
2238 internal class SplitWritesState
2240 private const int c_SplitEncryptedBuffersSize = 64*1024;
2241 private BufferOffsetSize[] _UserBuffers;
2243 private int _LastBufferConsumed;
2244 private BufferOffsetSize[] _RealBuffers;
2247 internal SplitWritesState(BufferOffsetSize[] buffers)
2249 _UserBuffers = buffers;
2250 _LastBufferConsumed = 0;
2252 _RealBuffers = null;
2255 // Everything was handled
2257 internal bool IsDone {
2259 if (_LastBufferConsumed != 0)
2262 for (int index = _Index ;index < _UserBuffers.Length; ++index)
2263 if (_UserBuffers[index].Size != 0)
2269 // Encryption takes CPU and if the input is large (like 10 mb) then a delay may
2270 // be 30 sec or so. Hence split the ecnrypt and write operations in smaller chunks
2271 // up to c_SplitEncryptedBuffersSize total.
2272 // Note that upon return from here EncryptBuffers() may additonally split the input
2273 // into chunks each <= chkSecureChannel.MaxDataSize (~16k) yet it will complete them all as a single IO.
2275 // Returns null if done, returns the _buffers reference if everything is handled in one shot (also done)
2277 // Otheriwse returns subsequent BufferOffsetSize[] to encrypt and pass to base IO method
2279 internal BufferOffsetSize[] GetNextBuffers()
2281 int curIndex = _Index;
2282 int currentTotalSize = 0;
2283 int lastChunkSize = 0;
2285 int firstBufferConsumed = _LastBufferConsumed;
2287 for ( ;_Index < _UserBuffers.Length; ++_Index)
2289 lastChunkSize = _UserBuffers[_Index].Size-_LastBufferConsumed;
2291 currentTotalSize += lastChunkSize;
2293 if (currentTotalSize > c_SplitEncryptedBuffersSize)
2295 lastChunkSize -= (currentTotalSize - c_SplitEncryptedBuffersSize);
2296 currentTotalSize = c_SplitEncryptedBuffersSize;
2301 _LastBufferConsumed = 0;
2304 // Are we done done?
2305 if (currentTotalSize == 0)
2308 // Do all buffers fit the limit?
2309 if (firstBufferConsumed == 0 && curIndex == 0 && _Index == _UserBuffers.Length)
2310 return _UserBuffers;
2312 // We do have something to split and send out
2313 int buffersCount = lastChunkSize == 0? _Index-curIndex: _Index-curIndex+1;
2315 if (_RealBuffers == null || _RealBuffers.Length != buffersCount)
2316 _RealBuffers = new BufferOffsetSize[buffersCount];
2319 for (; curIndex < _Index; ++curIndex)
2321 _RealBuffers[j++] = new BufferOffsetSize(_UserBuffers[curIndex].Buffer, _UserBuffers[curIndex].Offset + firstBufferConsumed, _UserBuffers[curIndex].Size-firstBufferConsumed, false);
2322 firstBufferConsumed = 0;
2325 if (lastChunkSize != 0)
2327 _RealBuffers[j] = new BufferOffsetSize(_UserBuffers[curIndex].Buffer, _UserBuffers[curIndex].Offset + _LastBufferConsumed, lastChunkSize, false);
2328 if ((_LastBufferConsumed += lastChunkSize) == _UserBuffers[_Index].Size)
2331 _LastBufferConsumed = 0;
2335 return _RealBuffers;