Decompiled source of H3MPDeps v1.0.0
plugins/System.Threading.dll
Decompiled 2 years ago
The result has been truncated due to the large size, download it to view full contents!
using System; using System.Collections; using System.Collections.Concurrent; using System.Collections.Generic; using System.Collections.ObjectModel; using System.Diagnostics; using System.Globalization; using System.Linq.Parallel; using System.Reflection; using System.Runtime.CompilerServices; using System.Runtime.ConstrainedExecution; using System.Runtime.InteropServices; using System.Runtime.Serialization; using System.Security; using System.Security.Permissions; using System.Threading; using System.Threading.Tasks; [assembly: InternalsVisibleTo("PlinqTest, PublicKey=0024000004800000940000000602000000240000525341310004000001000100CB7351F3887F5CB603C8CFBCA50868570B5BBECB60106DCBBDC4E18A20D5F84A64294699284628A768130175AF63C391C5E0D7FF19F05AF5FD4BC9641391293E094F92CCFF19234F3284DB149AFAE9F604A9A34FA7203549D2D4AD5CD80088682E0C137BCE1C38400955CB7CEDF5E9F532852F9C06AB50FCAA036216A95DE0CE")] [assembly: CompilationRelaxations(8)] [assembly: AssemblyFileVersion("1.0.2856.0")] [assembly: CLSCompliant(true)] [assembly: Debuggable(DebuggableAttribute.DebuggingModes.Default | DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)] [assembly: InternalsVisibleTo("plinq_devtests, PublicKey=0024000004800000940000000602000000240000525341310004000001000100CB7351F3887F5CB603C8CFBCA50868570B5BBECB60106DCBBDC4E18A20D5F84A64294699284628A768130175AF63C391C5E0D7FF19F05AF5FD4BC9641391293E094F92CCFF19234F3284DB149AFAE9F604A9A34FA7203549D2D4AD5CD80088682E0C137BCE1C38400955CB7CEDF5E9F532852F9C06AB50FCAA036216A95DE0CE")] [assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)] [assembly: AssemblyCompany("Microsoft Corporation")] [assembly: AssemblyCopyright("Copyright © Microsoft Corporation 2011")] [assembly: AssemblyTitle("System.Threading")] [assembly: AssemblyProduct("Reactive Extensions Core Library")] [assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)] [assembly: AssemblyVersion("1.0.2856.102")] [module: UnverifiableCode] namespace System.Diagnostics.Contracts { internal static class Contract { [Conditional("DEBUG")] internal static void Assert(bool condition) { } [Conditional("DEBUG")] internal static void Assert(bool condition, string message) { } [Conditional("DEBUG")] internal static void Ensures(bool condition) { } [Conditional("DEBUG")] internal static void EndContractBlock() { } } } namespace System { internal static class Environment2 { internal static string GetResourceString(string key) { if (key == "AggregateException_ToString") { return "{0}{1}---> (Inner Exception #{2}) {3}{4}{5}"; } return key; } } } namespace System.Threading.Tasks { internal interface IThreadPoolWorkItem { void ExecuteWorkItem(); void MarkAborted(ThreadAbortException tae); } } namespace System.Threading { internal class Monitor2 { internal static void Enter(object obj, ref bool taken) { Monitor.Enter(obj); taken = true; } internal static bool TryEnter(object obj) { return Monitor.TryEnter(obj); } internal static void TryEnter(object obj, ref bool taken) { taken = Monitor.TryEnter(obj); } internal static bool TryEnter(object obj, int millisecondsTimeout) { return Monitor.TryEnter(obj, millisecondsTimeout); } internal static bool TryEnter(object obj, TimeSpan timeout) { return Monitor.TryEnter(obj, timeout); } internal static void TryEnter(object obj, int millisecondsTimeout, ref bool taken) { taken = Monitor.TryEnter(obj, millisecondsTimeout); } } } namespace System.Collections.Generic { internal sealed class Mscorlib_DictionaryDebugView<K, V> { private IDictionary<K, V> dict; [DebuggerBrowsable(DebuggerBrowsableState.RootHidden)] internal KeyValuePair<K, V>[] Items { get { KeyValuePair<K, V>[] array = new KeyValuePair<K, V>[dict.Count]; dict.CopyTo(array, 0); return array; } } internal Mscorlib_DictionaryDebugView(IDictionary<K, V> dictionary) { if (dictionary == null) { throw new ArgumentNullException("dictionary"); } dict = dictionary; } } } namespace System { [Serializable] [ComVisible(true)] internal class OperationCanceledException2 : OperationCanceledException { [NonSerialized] private CancellationToken _cancellationToken; public new CancellationToken CancellationToken { get { return _cancellationToken; } private set { _cancellationToken = value; } } public OperationCanceledException2() : base(Environment2.GetResourceString("OperationCanceled")) { } public OperationCanceledException2(string message) : base(message) { } public OperationCanceledException2(string message, Exception innerException) : base(message, innerException) { } public OperationCanceledException2(CancellationToken token) : this() { CancellationToken = token; } public OperationCanceledException2(string message, CancellationToken token) : this(message) { CancellationToken = token; } public OperationCanceledException2(string message, Exception innerException, CancellationToken token) : this(message, innerException) { CancellationToken = token; } protected OperationCanceledException2(SerializationInfo info, StreamingContext context) : base(info, context) { } } } namespace System.Threading { internal static class Platform { internal static int ProcessorCount => Environment.ProcessorCount; internal static bool IsSingleProcessor => ProcessorCount == 1; [DllImport("kernel32.dll")] private static extern int SwitchToThread(); internal static void Yield() { SwitchToThread(); } } } namespace System { internal class SecuritySafeCriticalAttribute : Attribute { } } namespace System.Threading { [StructLayout(LayoutKind.Sequential, Size = 1)] internal struct StackCrawlMark2 { internal static StackCrawlMark2 LookForMyCaller => default(StackCrawlMark2); } } namespace System.Collections.Concurrent { [Serializable] [DebuggerTypeProxy(typeof(Mscorlib_DictionaryDebugView<, >))] [DebuggerDisplay("Count = {Count}")] [ComVisible(false)] [HostProtection(SecurityAction.LinkDemand, Synchronization = true, ExternalThreading = true)] public class ConcurrentDictionary<TKey, TValue> : IDictionary<TKey, TValue>, ICollection<KeyValuePair<TKey, TValue>>, IEnumerable<KeyValuePair<TKey, TValue>>, IDictionary, ICollection, IEnumerable { private class Node { internal TKey m_key; internal TValue m_value; internal volatile Node m_next; internal int m_hashcode; internal Node(TKey key, TValue value, int hashcode) : this(key, value, hashcode, (Node)null) { } internal Node(TKey key, TValue value, int hashcode, Node next) { m_key = key; m_value = value; m_next = next; m_hashcode = hashcode; } } private class DictionaryEnumerator : IDictionaryEnumerator, IEnumerator { private IEnumerator<KeyValuePair<TKey, TValue>> m_enumerator; public DictionaryEntry Entry => new DictionaryEntry(m_enumerator.Current.Key, m_enumerator.Current.Value); public object Key => m_enumerator.Current.Key; public object Value => m_enumerator.Current.Value; public object Current => Entry; internal DictionaryEnumerator(ConcurrentDictionary<TKey, TValue> dictionary) { m_enumerator = dictionary.GetEnumerator(); } public bool MoveNext() { return m_enumerator.MoveNext(); } public void Reset() { m_enumerator.Reset(); } } private const int DEFAULT_CONCURRENCY_MULTIPLIER = 4; private const int DEFAULT_CAPACITY = 31; [NonSerialized] private volatile Node[] m_buckets; [NonSerialized] private object[] m_locks; [NonSerialized] private volatile int[] m_countPerLock; private IEqualityComparer<TKey> m_comparer; private KeyValuePair<TKey, TValue>[] m_serializationArray; private int m_serializationConcurrencyLevel; private int m_serializationCapacity; public TValue this[TKey key] { get { if (!TryGetValue(key, out var value)) { throw new KeyNotFoundException(); } return value; } set { if (key == null) { throw new ArgumentNullException("key"); } TryAddInternal(key, value, updateIfExists: true, acquireLock: true, out var _); } } public int Count { get { int num = 0; int locksAcquired = 0; try { AcquireAllLocks(ref locksAcquired); for (int i = 0; i < m_countPerLock.Length; i++) { num += m_countPerLock[i]; } return num; } finally { ReleaseLocks(0, locksAcquired); } } } public bool IsEmpty { get { int locksAcquired = 0; try { AcquireAllLocks(ref locksAcquired); for (int i = 0; i < m_countPerLock.Length; i++) { if (m_countPerLock[i] != 0) { return false; } } } finally { ReleaseLocks(0, locksAcquired); } return true; } } public ICollection<TKey> Keys => GetKeys(); public ICollection<TValue> Values => GetValues(); bool ICollection<KeyValuePair<TKey, TValue>>.IsReadOnly => false; bool IDictionary.IsFixedSize => false; bool IDictionary.IsReadOnly => false; ICollection IDictionary.Keys => GetKeys(); ICollection IDictionary.Values => GetValues(); object IDictionary.this[object key] { get { if (key == null) { throw new ArgumentNullException("key"); } if (key is TKey && TryGetValue((TKey)key, out var value)) { return value; } return null; } set { if (key == null) { throw new ArgumentNullException("key"); } if (!(key is TKey)) { throw new ArgumentException(GetResource("ConcurrentDictionary_TypeOfKeyIncorrect")); } if (!(value is TValue)) { throw new ArgumentException(GetResource("ConcurrentDictionary_TypeOfValueIncorrect")); } this[(TKey)key] = (TValue)value; } } bool ICollection.IsSynchronized => false; object ICollection.SyncRoot { get { throw new NotSupportedException(Environment2.GetResourceString("ConcurrentCollection_SyncRoot_NotSupported")); } } private static int DefaultConcurrencyLevel => 4 * Environment.ProcessorCount; public ConcurrentDictionary() : this(DefaultConcurrencyLevel, 31) { } public ConcurrentDictionary(int concurrencyLevel, int capacity) : this(concurrencyLevel, capacity, (IEqualityComparer<TKey>)EqualityComparer<TKey>.Default) { } public ConcurrentDictionary(IEnumerable<KeyValuePair<TKey, TValue>> collection) : this(collection, (IEqualityComparer<TKey>)EqualityComparer<TKey>.Default) { } public ConcurrentDictionary(IEqualityComparer<TKey> comparer) : this(DefaultConcurrencyLevel, 31, comparer) { } public ConcurrentDictionary(IEnumerable<KeyValuePair<TKey, TValue>> collection, IEqualityComparer<TKey> comparer) : this(DefaultConcurrencyLevel, collection, comparer) { } public ConcurrentDictionary(int concurrencyLevel, IEnumerable<KeyValuePair<TKey, TValue>> collection, IEqualityComparer<TKey> comparer) : this(concurrencyLevel, 31, comparer) { if (collection == null) { throw new ArgumentNullException("collection"); } if (comparer == null) { throw new ArgumentNullException("comparer"); } InitializeFromCollection(collection); } private void InitializeFromCollection(IEnumerable<KeyValuePair<TKey, TValue>> collection) { foreach (KeyValuePair<TKey, TValue> item in collection) { if (item.Key == null) { throw new ArgumentNullException("key"); } if (!TryAddInternal(item.Key, item.Value, updateIfExists: false, acquireLock: false, out var _)) { throw new ArgumentException(GetResource("ConcurrentDictionary_SourceContainsDuplicateKeys")); } } } public ConcurrentDictionary(int concurrencyLevel, int capacity, IEqualityComparer<TKey> comparer) { if (concurrencyLevel < 1) { throw new ArgumentOutOfRangeException("concurrencyLevel", GetResource("ConcurrentDictionary_ConcurrencyLevelMustBePositive")); } if (capacity < 0) { throw new ArgumentOutOfRangeException("capacity", GetResource("ConcurrentDictionary_CapacityMustNotBeNegative")); } if (comparer == null) { throw new ArgumentNullException("comparer"); } if (capacity < concurrencyLevel) { capacity = concurrencyLevel; } m_locks = new object[concurrencyLevel]; for (int i = 0; i < m_locks.Length; i++) { m_locks[i] = new object(); } m_countPerLock = new int[m_locks.Length]; m_buckets = new Node[capacity]; m_comparer = comparer; } public bool TryAdd(TKey key, TValue value) { if (key == null) { throw new ArgumentNullException("key"); } TValue resultingValue; return TryAddInternal(key, value, updateIfExists: false, acquireLock: true, out resultingValue); } public bool ContainsKey(TKey key) { if (key == null) { throw new ArgumentNullException("key"); } TValue value; return TryGetValue(key, out value); } public bool TryRemove(TKey key, out TValue value) { if (key == null) { throw new ArgumentNullException("key"); } return TryRemoveInternal(key, out value, matchValue: false, default(TValue)); } private bool TryRemoveInternal(TKey key, out TValue value, bool matchValue, TValue oldValue) { while (true) { Node[] buckets = m_buckets; GetBucketAndLockNo(m_comparer.GetHashCode(key), out var bucketNo, out var lockNo, buckets.Length); lock (m_locks[lockNo]) { if (buckets != m_buckets) { continue; } Node node = null; for (Node node2 = m_buckets[bucketNo]; node2 != null; node2 = node2.m_next) { if (m_comparer.Equals(node2.m_key, key)) { if (matchValue && !EqualityComparer<TValue>.Default.Equals(oldValue, node2.m_value)) { value = default(TValue); return false; } if (node == null) { m_buckets[bucketNo] = node2.m_next; } else { node.m_next = node2.m_next; } value = node2.m_value; m_countPerLock[lockNo]--; return true; } node = node2; } break; } } value = default(TValue); return false; } public bool TryGetValue(TKey key, out TValue value) { if (key == null) { throw new ArgumentNullException("key"); } Node[] buckets = m_buckets; GetBucketAndLockNo(m_comparer.GetHashCode(key), out var bucketNo, out var _, buckets.Length); Node node = buckets[bucketNo]; Thread.MemoryBarrier(); while (node != null) { if (m_comparer.Equals(node.m_key, key)) { value = node.m_value; return true; } node = node.m_next; } value = default(TValue); return false; } public bool TryUpdate(TKey key, TValue newValue, TValue comparisonValue) { if (key == null) { throw new ArgumentNullException("key"); } int hashCode = m_comparer.GetHashCode(key); IEqualityComparer<TValue> @default = EqualityComparer<TValue>.Default; while (true) { Node[] buckets = m_buckets; GetBucketAndLockNo(hashCode, out var bucketNo, out var lockNo, buckets.Length); lock (m_locks[lockNo]) { if (buckets != m_buckets) { continue; } Node node = null; for (Node node2 = buckets[bucketNo]; node2 != null; node2 = node2.m_next) { if (m_comparer.Equals(node2.m_key, key)) { if (@default.Equals(node2.m_value, comparisonValue)) { Node node3 = new Node(node2.m_key, newValue, hashCode, node2.m_next); if (node == null) { buckets[bucketNo] = node3; } else { node.m_next = node3; } return true; } return false; } node = node2; } return false; } } } public void Clear() { int locksAcquired = 0; try { AcquireAllLocks(ref locksAcquired); m_buckets = new Node[31]; Array.Clear(m_countPerLock, 0, m_countPerLock.Length); } finally { ReleaseLocks(0, locksAcquired); } } void ICollection<KeyValuePair<TKey, TValue>>.CopyTo(KeyValuePair<TKey, TValue>[] array, int index) { if (array == null) { throw new ArgumentNullException("array"); } if (index < 0) { throw new ArgumentOutOfRangeException("index", GetResource("ConcurrentDictionary_IndexIsNegative")); } int locksAcquired = 0; try { AcquireAllLocks(ref locksAcquired); int num = 0; for (int i = 0; i < m_locks.Length; i++) { num += m_countPerLock[i]; } if (array.Length - num < index || num < 0) { throw new ArgumentException(GetResource("ConcurrentDictionary_ArrayNotLargeEnough")); } CopyToPairs(array, index); } finally { ReleaseLocks(0, locksAcquired); } } public KeyValuePair<TKey, TValue>[] ToArray() { int locksAcquired = 0; checked { try { AcquireAllLocks(ref locksAcquired); int num = 0; for (int i = 0; i < m_locks.Length; i++) { num += m_countPerLock[i]; } KeyValuePair<TKey, TValue>[] array = new KeyValuePair<TKey, TValue>[num]; CopyToPairs(array, 0); return array; } finally { ReleaseLocks(0, locksAcquired); } } } private void CopyToPairs(KeyValuePair<TKey, TValue>[] array, int index) { Node[] buckets = m_buckets; for (int i = 0; i < buckets.Length; i++) { for (Node node = buckets[i]; node != null; node = node.m_next) { ref KeyValuePair<TKey, TValue> reference = ref array[index]; reference = new KeyValuePair<TKey, TValue>(node.m_key, node.m_value); index++; } } } private void CopyToEntries(DictionaryEntry[] array, int index) { Node[] buckets = m_buckets; for (int i = 0; i < buckets.Length; i++) { for (Node node = buckets[i]; node != null; node = node.m_next) { ref DictionaryEntry reference = ref array[index]; reference = new DictionaryEntry(node.m_key, node.m_value); index++; } } } private void CopyToObjects(object[] array, int index) { Node[] buckets = m_buckets; for (int i = 0; i < buckets.Length; i++) { for (Node node = buckets[i]; node != null; node = node.m_next) { array[index] = new KeyValuePair<TKey, TValue>(node.m_key, node.m_value); index++; } } } public IEnumerator<KeyValuePair<TKey, TValue>> GetEnumerator() { Node[] buckets = m_buckets; for (int i = 0; i < buckets.Length; i++) { Node current = buckets[i]; Thread.MemoryBarrier(); while (current != null) { yield return new KeyValuePair<TKey, TValue>(current.m_key, current.m_value); current = current.m_next; } } } private bool TryAddInternal(TKey key, TValue value, bool updateIfExists, bool acquireLock, out TValue resultingValue) { int hashCode = m_comparer.GetHashCode(key); Node[] buckets; bool flag; while (true) { buckets = m_buckets; GetBucketAndLockNo(hashCode, out var bucketNo, out var lockNo, buckets.Length); flag = false; bool taken = false; try { if (acquireLock) { Monitor2.Enter(m_locks[lockNo], ref taken); } if (buckets != m_buckets) { continue; } Node node = null; for (Node node2 = buckets[bucketNo]; node2 != null; node2 = node2.m_next) { if (m_comparer.Equals(node2.m_key, key)) { if (updateIfExists) { Node node3 = new Node(node2.m_key, value, hashCode, node2.m_next); if (node == null) { buckets[bucketNo] = node3; } else { node.m_next = node3; } resultingValue = value; } else { resultingValue = node2.m_value; } return false; } node = node2; } buckets[bucketNo] = new Node(key, value, hashCode, buckets[bucketNo]); checked { m_countPerLock[lockNo]++; } if (m_countPerLock[lockNo] > buckets.Length / m_locks.Length) { flag = true; } break; } finally { if (taken) { Monitor.Exit(m_locks[lockNo]); } } } if (flag) { GrowTable(buckets); } resultingValue = value; return true; } public TValue GetOrAdd(TKey key, Func<TKey, TValue> valueFactory) { if (key == null) { throw new ArgumentNullException("key"); } if (valueFactory == null) { throw new ArgumentNullException("valueFactory"); } if (TryGetValue(key, out var value)) { return value; } TryAddInternal(key, valueFactory(key), updateIfExists: false, acquireLock: true, out value); return value; } public TValue GetOrAdd(TKey key, TValue value) { if (key == null) { throw new ArgumentNullException("key"); } TryAddInternal(key, value, updateIfExists: false, acquireLock: true, out var resultingValue); return resultingValue; } public TValue AddOrUpdate(TKey key, Func<TKey, TValue> addValueFactory, Func<TKey, TValue, TValue> updateValueFactory) { if (key == null) { throw new ArgumentNullException("key"); } if (addValueFactory == null) { throw new ArgumentNullException("addValueFactory"); } if (updateValueFactory == null) { throw new ArgumentNullException("updateValueFactory"); } TValue resultingValue; while (true) { if (TryGetValue(key, out var value)) { TValue val = updateValueFactory(key, value); if (TryUpdate(key, val, value)) { return val; } } else { TValue val = addValueFactory(key); if (TryAddInternal(key, val, updateIfExists: false, acquireLock: true, out resultingValue)) { break; } } } return resultingValue; } public TValue AddOrUpdate(TKey key, TValue addValue, Func<TKey, TValue, TValue> updateValueFactory) { if (key == null) { throw new ArgumentNullException("key"); } if (updateValueFactory == null) { throw new ArgumentNullException("updateValueFactory"); } TValue resultingValue; while (true) { if (TryGetValue(key, out var value)) { TValue val = updateValueFactory(key, value); if (TryUpdate(key, val, value)) { return val; } } else if (TryAddInternal(key, addValue, updateIfExists: false, acquireLock: true, out resultingValue)) { break; } } return resultingValue; } void IDictionary<TKey, TValue>.Add(TKey key, TValue value) { if (!TryAdd(key, value)) { throw new ArgumentException(GetResource("ConcurrentDictionary_KeyAlreadyExisted")); } } bool IDictionary<TKey, TValue>.Remove(TKey key) { TValue value; return TryRemove(key, out value); } void ICollection<KeyValuePair<TKey, TValue>>.Add(KeyValuePair<TKey, TValue> keyValuePair) { ((IDictionary<TKey, TValue>)this).Add(keyValuePair.Key, keyValuePair.Value); } bool ICollection<KeyValuePair<TKey, TValue>>.Contains(KeyValuePair<TKey, TValue> keyValuePair) { if (!TryGetValue(keyValuePair.Key, out var value)) { return false; } return EqualityComparer<TValue>.Default.Equals(value, keyValuePair.Value); } bool ICollection<KeyValuePair<TKey, TValue>>.Remove(KeyValuePair<TKey, TValue> keyValuePair) { if (keyValuePair.Key == null) { throw new ArgumentNullException(GetResource("ConcurrentDictionary_ItemKeyIsNull")); } TValue value; return TryRemoveInternal(keyValuePair.Key, out value, matchValue: true, keyValuePair.Value); } IEnumerator IEnumerable.GetEnumerator() { return GetEnumerator(); } void IDictionary.Add(object key, object value) { if (key == null) { throw new ArgumentNullException("key"); } if (!(key is TKey)) { throw new ArgumentException(GetResource("ConcurrentDictionary_TypeOfKeyIncorrect")); } TValue value2; try { value2 = (TValue)value; } catch (InvalidCastException) { throw new ArgumentException(GetResource("ConcurrentDictionary_TypeOfValueIncorrect")); } ((IDictionary<TKey, TValue>)this).Add((TKey)key, value2); } bool IDictionary.Contains(object key) { if (key == null) { throw new ArgumentNullException("key"); } if (key is TKey) { return ContainsKey((TKey)key); } return false; } IDictionaryEnumerator IDictionary.GetEnumerator() { return new DictionaryEnumerator(this); } void IDictionary.Remove(object key) { if (key == null) { throw new ArgumentNullException("key"); } if (key is TKey) { TryRemove((TKey)key, out var _); } } void ICollection.CopyTo(Array array, int index) { if (array == null) { throw new ArgumentNullException("array"); } if (index < 0) { throw new ArgumentOutOfRangeException("index", GetResource("ConcurrentDictionary_IndexIsNegative")); } int locksAcquired = 0; try { AcquireAllLocks(ref locksAcquired); int num = 0; for (int i = 0; i < m_locks.Length; i++) { num += m_countPerLock[i]; } if (array.Length - num < index || num < 0) { throw new ArgumentException(GetResource("ConcurrentDictionary_ArrayNotLargeEnough")); } if (array is KeyValuePair<TKey, TValue>[] array2) { CopyToPairs(array2, index); return; } if (array is DictionaryEntry[] array3) { CopyToEntries(array3, index); return; } if (array is object[] array4) { CopyToObjects(array4, index); return; } throw new ArgumentException(GetResource("ConcurrentDictionary_ArrayIncorrectType"), "array"); } finally { ReleaseLocks(0, locksAcquired); } } private void GrowTable(Node[] buckets) { int locksAcquired = 0; checked { try { AcquireLocks(0, 1, ref locksAcquired); if (buckets != m_buckets) { return; } int i; try { for (i = buckets.Length * 2 + 1; unchecked(i % 3 == 0 || i % 5 == 0 || i % 7 == 0); i += 2) { } } catch (OverflowException) { return; } Node[] array = new Node[i]; int[] array2 = new int[m_locks.Length]; AcquireLocks(1, m_locks.Length, ref locksAcquired); for (int j = 0; j < buckets.Length; j = unchecked(j + 1)) { Node node = buckets[j]; while (node != null) { Node next = node.m_next; GetBucketAndLockNo(node.m_hashcode, out var bucketNo, out var lockNo, array.Length); array[bucketNo] = new Node(node.m_key, node.m_value, node.m_hashcode, array[bucketNo]); array2[lockNo]++; node = next; } } m_buckets = array; m_countPerLock = array2; } finally { ReleaseLocks(0, locksAcquired); } } } private void GetBucketAndLockNo(int hashcode, out int bucketNo, out int lockNo, int bucketCount) { bucketNo = (hashcode & 0x7FFFFFFF) % bucketCount; lockNo = bucketNo % m_locks.Length; } private void AcquireAllLocks(ref int locksAcquired) { AcquireLocks(0, m_locks.Length, ref locksAcquired); } private void AcquireLocks(int fromInclusive, int toExclusive, ref int locksAcquired) { for (int i = fromInclusive; i < toExclusive; i++) { bool taken = false; try { Monitor2.Enter(m_locks[i], ref taken); } finally { if (taken) { locksAcquired++; } } } } private void ReleaseLocks(int fromInclusive, int toExclusive) { for (int i = fromInclusive; i < toExclusive; i++) { Monitor.Exit(m_locks[i]); } } private ReadOnlyCollection<TKey> GetKeys() { int locksAcquired = 0; try { AcquireAllLocks(ref locksAcquired); List<TKey> list = new List<TKey>(); for (int i = 0; i < m_buckets.Length; i++) { for (Node node = m_buckets[i]; node != null; node = node.m_next) { list.Add(node.m_key); } } return new ReadOnlyCollection<TKey>(list); } finally { ReleaseLocks(0, locksAcquired); } } private ReadOnlyCollection<TValue> GetValues() { int locksAcquired = 0; try { AcquireAllLocks(ref locksAcquired); List<TValue> list = new List<TValue>(); for (int i = 0; i < m_buckets.Length; i++) { for (Node node = m_buckets[i]; node != null; node = node.m_next) { list.Add(node.m_value); } } return new ReadOnlyCollection<TValue>(list); } finally { ReleaseLocks(0, locksAcquired); } } [Conditional("DEBUG")] private void Assert(bool condition) { } private string GetResource(string key) { return Environment2.GetResourceString(key); } [OnSerializing] private void OnSerializing(StreamingContext context) { m_serializationArray = ToArray(); m_serializationConcurrencyLevel = m_locks.Length; m_serializationCapacity = m_buckets.Length; } [OnDeserialized] private void OnDeserialized(StreamingContext context) { KeyValuePair<TKey, TValue>[] serializationArray = m_serializationArray; m_buckets = new Node[m_serializationCapacity]; m_countPerLock = new int[m_serializationConcurrencyLevel]; m_locks = new object[m_serializationConcurrencyLevel]; for (int i = 0; i < m_locks.Length; i++) { m_locks[i] = new object(); } InitializeFromCollection(serializationArray); m_serializationArray = null; } } public interface IProducerConsumerCollection<T> : IEnumerable<T>, ICollection, IEnumerable { void CopyTo(T[] array, int index); bool TryAdd(T item); bool TryTake(out T item); T[] ToArray(); } [Serializable] [DebuggerDisplay("Count = {Count}")] [ComVisible(false)] [DebuggerTypeProxy(typeof(SystemCollectionsConcurrent_ProducerConsumerCollectionDebugView<>))] [HostProtection(SecurityAction.LinkDemand, Synchronization = true, ExternalThreading = true)] public class ConcurrentQueue<T> : IProducerConsumerCollection<T>, IEnumerable<T>, ICollection, IEnumerable { private class Segment { internal volatile T[] m_array; private volatile int[] m_state; private volatile Segment m_next; internal readonly long m_index; private volatile int m_low; private volatile int m_high; internal Segment Next => m_next; internal bool IsEmpty => Low > High; internal int Low => Math.Min(m_low, 32); internal int High => Math.Min(m_high, 31); internal Segment(long index) { m_array = new T[32]; m_state = new int[32]; m_high = -1; m_index = index; } internal void UnsafeAdd(T value) { m_high++; m_array[m_high] = value; m_state[m_high] = 1; } internal Segment UnsafeGrow() { return m_next = new Segment(m_index + 1); } internal void Grow(ref Segment tail) { Segment next = new Segment(m_index + 1); m_next = next; tail = m_next; } internal bool TryAppend(T value, ref Segment tail) { if (m_high >= 31) { return false; } int num = 32; try { } finally { num = Interlocked.Increment(ref m_high); if (num <= 31) { m_array[num] = value; m_state[num] = 1; } if (num == 31) { Grow(ref tail); } } return num <= 31; } internal bool TryRemove(out T result, ref Segment head) { SpinWait spinWait = default(SpinWait); int low = Low; int high = High; while (low <= high) { if (Interlocked.CompareExchange(ref m_low, low + 1, low) == low) { SpinWait spinWait2 = default(SpinWait); while (m_state[low] == 0) { spinWait2.SpinOnce(); } result = m_array[low]; if (low + 1 >= 32) { spinWait2 = default(SpinWait); while (m_next == null) { spinWait2.SpinOnce(); } head = m_next; } return true; } spinWait.SpinOnce(); low = Low; high = High; } result = default(T); return false; } internal bool TryPeek(out T result) { result = default(T); int low = Low; if (low > High) { return false; } SpinWait spinWait = default(SpinWait); while (m_state[low] == 0) { spinWait.SpinOnce(); } result = m_array[low]; return true; } internal List<T> ToList(int start, int end) { List<T> list = new List<T>(); for (int i = start; i <= end; i++) { SpinWait spinWait = default(SpinWait); while (m_state[i] == 0) { spinWait.SpinOnce(); } list.Add(m_array[i]); } return list; } } private const int SEGMENT_SIZE = 32; [NonSerialized] private volatile Segment m_head; [NonSerialized] private volatile Segment m_tail; private T[] m_serializationArray; bool ICollection.IsSynchronized => false; object ICollection.SyncRoot { get { throw new NotSupportedException(Environment2.GetResourceString("ConcurrentCollection_SyncRoot_NotSupported")); } } public bool IsEmpty { get { Segment head = m_head; if (!head.IsEmpty) { return false; } if (head.Next == null) { return true; } SpinWait spinWait = default(SpinWait); while (head.IsEmpty) { if (head.Next == null) { return true; } spinWait.SpinOnce(); head = m_head; } return false; } } public int Count { get { GetHeadTailPositions(out var head, out var tail, out var headLow, out var tailHigh); if (head == tail) { return tailHigh - headLow + 1; } int num = 32 - headLow; num += 32 * (int)(tail.m_index - head.m_index - 1); return num + (tailHigh + 1); } } public ConcurrentQueue() { m_head = (m_tail = new Segment(0L)); } private void InitializeFromCollection(IEnumerable<T> collection) { m_head = (m_tail = new Segment(0L)); int num = 0; foreach (T item in collection) { m_tail.UnsafeAdd(item); num++; if (num >= 32) { m_tail = m_tail.UnsafeGrow(); num = 0; } } } public ConcurrentQueue(IEnumerable<T> collection) { if (collection == null) { throw new ArgumentNullException("collection"); } InitializeFromCollection(collection); } [OnSerializing] private void OnSerializing(StreamingContext context) { m_serializationArray = ToArray(); } [OnDeserialized] private void OnDeserialized(StreamingContext context) { InitializeFromCollection(m_serializationArray); m_serializationArray = null; } void ICollection.CopyTo(Array array, int index) { if (array == null) { throw new ArgumentNullException("array"); } ((ICollection)ToList()).CopyTo(array, index); } IEnumerator IEnumerable.GetEnumerator() { return ((IEnumerable<T>)this).GetEnumerator(); } bool IProducerConsumerCollection<T>.TryAdd(T item) { Enqueue(item); return true; } bool IProducerConsumerCollection<T>.TryTake(out T item) { return TryDequeue(out item); } public T[] ToArray() { return ToList().ToArray(); } private List<T> ToList() { GetHeadTailPositions(out var head, out var tail, out var headLow, out var tailHigh); if (head == tail) { return head.ToList(headLow, tailHigh); } List<T> list = new List<T>(head.ToList(headLow, 31)); for (Segment next = head.Next; next != tail; next = next.Next) { list.AddRange(next.ToList(0, 31)); } list.AddRange(tail.ToList(0, tailHigh)); return list; } private void GetHeadTailPositions(out Segment head, out Segment tail, out int headLow, out int tailHigh) { head = m_head; tail = m_tail; headLow = head.Low; tailHigh = tail.High; SpinWait spinWait = default(SpinWait); while (head != m_head || tail != m_tail || headLow != head.Low || tailHigh != tail.High || head.m_index > tail.m_index) { spinWait.SpinOnce(); head = m_head; tail = m_tail; headLow = head.Low; tailHigh = tail.High; } } public void CopyTo(T[] array, int index) { if (array == null) { throw new ArgumentNullException("array"); } ToList().CopyTo(array, index); } public IEnumerator<T> GetEnumerator() { return ToList().GetEnumerator(); } public void Enqueue(T item) { SpinWait spinWait = default(SpinWait); while (true) { Segment tail = m_tail; if (tail.TryAppend(item, ref m_tail)) { break; } spinWait.SpinOnce(); } } public bool TryDequeue(out T result) { while (!IsEmpty) { Segment head = m_head; if (head.TryRemove(out result, ref m_head)) { return true; } } result = default(T); return false; } public bool TryPeek(out T result) { while (!IsEmpty) { Segment head = m_head; if (head.TryPeek(out result)) { return true; } } result = default(T); return false; } } [Serializable] [DebuggerDisplay("Count = {Count}")] [DebuggerTypeProxy(typeof(SystemCollectionsConcurrent_ProducerConsumerCollectionDebugView<>))] [HostProtection(SecurityAction.LinkDemand, Synchronization = true, ExternalThreading = true)] public class ConcurrentStack<T> : IProducerConsumerCollection<T>, IEnumerable<T>, ICollection, IEnumerable { private class Node { internal T m_value; internal Node m_next; internal Node(T value) { m_value = value; m_next = null; } } private const int BACKOFF_MAX_YIELDS = 8; [NonSerialized] private volatile Node m_head; private T[] m_serializationArray; public bool IsEmpty => m_head == null; public int Count { get { int num = 0; for (Node node = m_head; node != null; node = node.m_next) { num++; } return num; } } bool ICollection.IsSynchronized => false; object ICollection.SyncRoot { get { throw new NotSupportedException(Environment2.GetResourceString("ConcurrentCollection_SyncRoot_NotSupported")); } } public ConcurrentStack() { } public ConcurrentStack(IEnumerable<T> collection) { if (collection == null) { throw new ArgumentNullException("collection"); } InitializeFromCollection(collection); } private void InitializeFromCollection(IEnumerable<T> collection) { Node node = null; foreach (T item in collection) { Node node2 = new Node(item); node2.m_next = node; node = node2; } m_head = node; } [OnSerializing] private void OnSerializing(StreamingContext context) { m_serializationArray = ToArray(); } [OnDeserialized] private void OnDeserialized(StreamingContext context) { Node node = null; Node head = null; for (int i = 0; i < m_serializationArray.Length; i++) { Node node2 = new Node(m_serializationArray[i]); if (node == null) { head = node2; } else { node.m_next = node2; } node = node2; } m_head = head; m_serializationArray = null; } public void Clear() { m_head = null; } void ICollection.CopyTo(Array array, int index) { if (array == null) { throw new ArgumentNullException("array"); } ((ICollection)ToList()).CopyTo(array, index); } public void CopyTo(T[] array, int index) { if (array == null) { throw new ArgumentNullException("array"); } ToList().CopyTo(array, index); } public void Push(T item) { Node node = new Node(item); node.m_next = m_head; if (Interlocked.CompareExchange(ref m_head, node, node.m_next) != node.m_next) { PushCore(node, node); } } public void PushRange(T[] items) { if (items == null) { throw new ArgumentNullException("items"); } PushRange(items, 0, items.Length); } public void PushRange(T[] items, int startIndex, int count) { ValidatePushPopRangeInput(items, startIndex, count); if (count != 0) { Node node; Node node2 = (node = new Node(items[startIndex])); for (int i = startIndex + 1; i < startIndex + count; i++) { Node node3 = new Node(items[i]); node3.m_next = node2; node2 = node3; } node.m_next = m_head; if (Interlocked.CompareExchange(ref m_head, node2, node.m_next) != node.m_next) { PushCore(node2, node); } } } private void PushCore(Node head, Node tail) { SpinWait spinWait = default(SpinWait); do { spinWait.SpinOnce(); tail.m_next = m_head; } while (Interlocked.CompareExchange(ref m_head, head, tail.m_next) != tail.m_next); } private void ValidatePushPopRangeInput(T[] items, int startIndex, int count) { if (items == null) { throw new ArgumentNullException("items"); } if (count < 0) { throw new ArgumentOutOfRangeException("count", Environment2.GetResourceString("ConcurrentStack_PushPopRange_CountOutOfRange")); } int num = items.Length; if (startIndex >= num || startIndex < 0) { throw new ArgumentOutOfRangeException("startIndex", Environment2.GetResourceString("ConcurrentStack_PushPopRange_StartOutOfRange")); } if (num - count < startIndex) { throw new ArgumentException(Environment2.GetResourceString("ConcurrentStack_PushPopRange_InvalidCount")); } } bool IProducerConsumerCollection<T>.TryAdd(T item) { Push(item); return true; } public bool TryPeek(out T result) { Node head = m_head; if (head == null) { result = default(T); return false; } result = head.m_value; return true; } public bool TryPop(out T result) { Node head = m_head; if (head == null) { result = default(T); return false; } if (Interlocked.CompareExchange(ref m_head, head.m_next, head) == head) { result = head.m_value; return true; } return TryPopCore(out result); } public int TryPopRange(T[] items) { if (items == null) { throw new ArgumentNullException("items"); } return TryPopRange(items, 0, items.Length); } public int TryPopRange(T[] items, int startIndex, int count) { ValidatePushPopRangeInput(items, startIndex, count); if (count == 0) { return 0; } Node poppedHead; int num = TryPopCore(count, out poppedHead); if (num > 0) { CopyRemovedItems(poppedHead, items, startIndex, num); } return num; } private bool TryPopCore(out T result) { if (TryPopCore(1, out var poppedHead) == 1) { result = poppedHead.m_value; return true; } result = default(T); return false; } private int TryPopCore(int count, out Node poppedHead) { SpinWait spinWait = default(SpinWait); int num = 1; Random random = new Random(Environment.TickCount & 0x7FFFFFFF); Node head; int i; while (true) { head = m_head; if (head == null) { poppedHead = null; return 0; } Node node = head; for (i = 1; i < count; i++) { if (node.m_next == null) { break; } node = node.m_next; } if (Interlocked.CompareExchange(ref m_head, node.m_next, head) == head) { break; } for (int j = 0; j < num; j++) { spinWait.SpinOnce(); } num = (spinWait.NextSpinWillYield ? random.Next(1, 8) : (num * 2)); } poppedHead = head; return i; } private void CopyRemovedItems(Node head, T[] collection, int startIndex, int nodesCount) { Node node = head; for (int i = startIndex; i < startIndex + nodesCount; i++) { collection[i] = node.m_value; node = node.m_next; } } bool IProducerConsumerCollection<T>.TryTake(out T item) { return TryPop(out item); } public T[] ToArray() { return ToList().ToArray(); } private List<T> ToList() { List<T> list = new List<T>(); for (Node node = m_head; node != null; node = node.m_next) { list.Add(node.m_value); } return list; } public IEnumerator<T> GetEnumerator() { return GetEnumerator(m_head); } private IEnumerator<T> GetEnumerator(Node head) { for (Node current = head; current != null; current = current.m_next) { yield return current.m_value; } } IEnumerator IEnumerable.GetEnumerator() { return ((IEnumerable<T>)this).GetEnumerator(); } } internal sealed class SystemCollectionsConcurrent_ProducerConsumerCollectionDebugView<T> { private IProducerConsumerCollection<T> m_collection; [DebuggerBrowsable(DebuggerBrowsableState.RootHidden)] public T[] Items => m_collection.ToArray(); public SystemCollectionsConcurrent_ProducerConsumerCollectionDebugView(IProducerConsumerCollection<T> collection) { if (collection == null) { throw new ArgumentNullException("collection"); } m_collection = collection; } } [HostProtection(SecurityAction.LinkDemand, Synchronization = true, ExternalThreading = true)] public abstract class Partitioner<TSource> { public virtual bool SupportsDynamicPartitions => false; public abstract IList<IEnumerator<TSource>> GetPartitions(int partitionCount); public virtual IEnumerable<TSource> GetDynamicPartitions() { throw new NotSupportedException(Environment2.GetResourceString("Partitioner_DynamicPartitionsNotSupported")); } } [HostProtection(SecurityAction.LinkDemand, Synchronization = true, ExternalThreading = true)] public abstract class OrderablePartitioner<TSource> : Partitioner<TSource> { private class EnumerableDropIndices : IEnumerable<TSource>, IEnumerable, IDisposable { private readonly IEnumerable<KeyValuePair<long, TSource>> m_source; public EnumerableDropIndices(IEnumerable<KeyValuePair<long, TSource>> source) { m_source = source; } public IEnumerator<TSource> GetEnumerator() { return new EnumeratorDropIndices(m_source.GetEnumerator()); } IEnumerator IEnumerable.GetEnumerator() { return GetEnumerator(); } public void Dispose() { if (m_source is IDisposable disposable) { disposable.Dispose(); } } } private class EnumeratorDropIndices : IEnumerator<TSource>, IDisposable, IEnumerator { private readonly IEnumerator<KeyValuePair<long, TSource>> m_source; public TSource Current => m_source.Current.Value; object IEnumerator.Current => Current; public EnumeratorDropIndices(IEnumerator<KeyValuePair<long, TSource>> source) { m_source = source; } public bool MoveNext() { return m_source.MoveNext(); } public void Dispose() { m_source.Dispose(); } public void Reset() { m_source.Reset(); } } public bool KeysOrderedInEachPartition { get; private set; } public bool KeysOrderedAcrossPartitions { get; private set; } public bool KeysNormalized { get; private set; } protected OrderablePartitioner(bool keysOrderedInEachPartition, bool keysOrderedAcrossPartitions, bool keysNormalized) { KeysOrderedInEachPartition = keysOrderedInEachPartition; KeysOrderedAcrossPartitions = keysOrderedAcrossPartitions; KeysNormalized = keysNormalized; } public abstract IList<IEnumerator<KeyValuePair<long, TSource>>> GetOrderablePartitions(int partitionCount); public virtual IEnumerable<KeyValuePair<long, TSource>> GetOrderableDynamicPartitions() { throw new NotSupportedException(Environment2.GetResourceString("Partitioner_DynamicPartitionsNotSupported")); } public override IList<IEnumerator<TSource>> GetPartitions(int partitionCount) { IList<IEnumerator<KeyValuePair<long, TSource>>> orderablePartitions = GetOrderablePartitions(partitionCount); if (orderablePartitions.Count != partitionCount) { throw new InvalidOperationException("OrderablePartitioner_GetPartitions_WrongNumberOfPartitions"); } IEnumerator<TSource>[] array = new IEnumerator<TSource>[partitionCount]; for (int i = 0; i < partitionCount; i++) { array[i] = new EnumeratorDropIndices(orderablePartitions[i]); } return array; } public override IEnumerable<TSource> GetDynamicPartitions() { IEnumerable<KeyValuePair<long, TSource>> orderableDynamicPartitions = GetOrderableDynamicPartitions(); return new EnumerableDropIndices(orderableDynamicPartitions); } } [HostProtection(SecurityAction.LinkDemand, Synchronization = true, ExternalThreading = true)] public static class Partitioner { private abstract class DynamicPartitionEnumerator_Abstract<TSource, TSourceReader> : IEnumerator<KeyValuePair<long, TSource>>, IDisposable, IEnumerator { private const int CHUNK_DOUBLING_RATE = 3; protected readonly TSourceReader m_sharedReader; protected static int s_defaultMaxChunkSize = GetDefaultChunkSize<TSource>(); protected Shared<int> m_currentChunkSize; protected Shared<int> m_localOffset; private int m_doublingCountdown; protected readonly int m_maxChunkSize; protected readonly Shared<long> m_sharedIndex; protected abstract bool HasNoElementsLeft { get; set; } public abstract KeyValuePair<long, TSource> Current { get; } object IEnumerator.Current => Current; protected DynamicPartitionEnumerator_Abstract(TSourceReader sharedReader, Shared<long> sharedIndex) : this(sharedReader, sharedIndex, -1) { } protected DynamicPartitionEnumerator_Abstract(TSourceReader sharedReader, Shared<long> sharedIndex, int maxChunkSize) { m_sharedReader = sharedReader; m_sharedIndex = sharedIndex; if (maxChunkSize == -1) { m_maxChunkSize = s_defaultMaxChunkSize; } else { m_maxChunkSize = maxChunkSize; } } protected abstract bool GrabNextChunk(int requestedChunkSize); public abstract void Dispose(); public void Reset() { throw new NotSupportedException(); } public bool MoveNext() { if (m_localOffset == null) { m_localOffset = new Shared<int>(-1); m_currentChunkSize = new Shared<int>(0); m_doublingCountdown = 3; } if (m_localOffset.Value < m_currentChunkSize.Value - 1) { m_localOffset.Value++; return true; } int requestedChunkSize; if (m_currentChunkSize.Value == 0) { requestedChunkSize = 1; } else if (m_doublingCountdown > 0) { requestedChunkSize = m_currentChunkSize.Value; } else { requestedChunkSize = Math.Min(m_currentChunkSize.Value * 2, m_maxChunkSize); m_doublingCountdown = 3; } m_doublingCountdown--; if (GrabNextChunk(requestedChunkSize)) { m_localOffset.Value = 0; return true; } return false; } } private class DynamicPartitionerForIEnumerable<TSource> : OrderablePartitioner<TSource> { private class InternalPartitionEnumerable : IEnumerable<KeyValuePair<long, TSource>>, IEnumerable, IDisposable { private readonly IEnumerator<TSource> m_sharedReader; private Shared<long> m_sharedIndex; private Shared<bool> m_hasNoElementsLeft; private object m_sharedLock; private bool m_disposed; private Shared<int> m_activePartitionCount; private readonly int m_maxChunkSize; internal InternalPartitionEnumerable(IEnumerator<TSource> sharedReader, int maxChunkSize) { m_sharedReader = sharedReader; m_sharedIndex = new Shared<long>(-1L); m_hasNoElementsLeft = new Shared<bool>(value: false); m_sharedLock = new object(); m_activePartitionCount = new Shared<int>(0); m_maxChunkSize = maxChunkSize; } public IEnumerator<KeyValuePair<long, TSource>> GetEnumerator() { if (m_disposed) { throw new ObjectDisposedException(Environment2.GetResourceString("PartitionerStatic_CanNotCallGetEnumeratorAfterSourceHasBeenDisposed")); } return new InternalPartitionEnumerator(m_sharedReader, m_sharedIndex, m_hasNoElementsLeft, m_sharedLock, m_activePartitionCount, this, m_maxChunkSize); } IEnumerator IEnumerable.GetEnumerator() { return GetEnumerator(); } public void Dispose() { if (!m_disposed) { m_disposed = true; m_sharedReader.Dispose(); } } } private class InternalPartitionEnumerator : DynamicPartitionEnumerator_Abstract<TSource, IEnumerator<TSource>> { private KeyValuePair<long, TSource>[] m_localList; private readonly Shared<bool> m_hasNoElementsLeft; private readonly object m_sharedLock; private readonly Shared<int> m_activePartitionCount; private InternalPartitionEnumerable m_enumerable; protected override bool HasNoElementsLeft { get { return m_hasNoElementsLeft.Value; } set { m_hasNoElementsLeft.Value = true; } } public override KeyValuePair<long, TSource> Current { get { if (m_currentChunkSize == null) { throw new InvalidOperationException(Environment2.GetResourceString("PartitionerStatic_CurrentCalledBeforeMoveNext")); } return m_localList[m_localOffset.Value]; } } internal InternalPartitionEnumerator(IEnumerator<TSource> sharedReader, Shared<long> sharedIndex, Shared<bool> hasNoElementsLeft, object sharedLock, Shared<int> activePartitionCount, InternalPartitionEnumerable enumerable, int maxChunkSize) : base(sharedReader, sharedIndex, maxChunkSize) { m_hasNoElementsLeft = hasNoElementsLeft; m_sharedLock = sharedLock; m_enumerable = enumerable; m_activePartitionCount = activePartitionCount; Interlocked.Increment(ref m_activePartitionCount.Value); } protected override bool GrabNextChunk(int requestedChunkSize) { if (HasNoElementsLeft) { return false; } lock (m_sharedLock) { if (HasNoElementsLeft) { return false; } try { int i; for (i = 0; i < requestedChunkSize; i++) { if (m_sharedReader.MoveNext()) { if (m_localList == null) { m_localList = new KeyValuePair<long, TSource>[m_maxChunkSize]; } m_sharedIndex.Value = checked(m_sharedIndex.Value + 1); ref KeyValuePair<long, TSource> reference = ref m_localList[i]; reference = new KeyValuePair<long, TSource>(m_sharedIndex.Value, m_sharedReader.Current); continue; } HasNoElementsLeft = true; break; } if (i > 0) { m_currentChunkSize.Value = i; return true; } return false; } catch { HasNoElementsLeft = true; throw; } } } public override void Dispose() { if (Interlocked.Decrement(ref m_activePartitionCount.Value) == 0) { m_enumerable.Dispose(); } } } private IEnumerable<TSource> m_source; private int m_maxChunkSize; public override bool SupportsDynamicPartitions => true; internal DynamicPartitionerForIEnumerable(IEnumerable<TSource> source, int maxChunkSize) : base(keysOrderedInEachPartition: true, keysOrderedAcrossPartitions: false, keysNormalized: true) { m_source = source; m_maxChunkSize = maxChunkSize; } public override IList<IEnumerator<KeyValuePair<long, TSource>>> GetOrderablePartitions(int partitionCount) { if (partitionCount <= 0) { throw new ArgumentOutOfRangeException("partitionCount"); } IEnumerator<KeyValuePair<long, TSource>>[] array = new IEnumerator<KeyValuePair<long, TSource>>[partitionCount]; IEnumerable<KeyValuePair<long, TSource>> enumerable = new InternalPartitionEnumerable(m_source.GetEnumerator(), m_maxChunkSize); for (int i = 0; i < partitionCount; i++) { array[i] = enumerable.GetEnumerator(); } return array; } public override IEnumerable<KeyValuePair<long, TSource>> GetOrderableDynamicPartitions() { return new InternalPartitionEnumerable(m_source.GetEnumerator(), m_maxChunkSize); } } private abstract class DynamicPartitionerForIndexRange_Abstract<TSource, TCollection> : OrderablePartitioner<TSource> { private TCollection m_data; public override bool SupportsDynamicPartitions => true; protected DynamicPartitionerForIndexRange_Abstract(TCollection data) : base(keysOrderedInEachPartition: true, keysOrderedAcrossPartitions: false, keysNormalized: true) { m_data = data; } protected abstract IEnumerable<KeyValuePair<long, TSource>> GetOrderableDynamicPartitions_Factory(TCollection data); public override IList<IEnumerator<KeyValuePair<long, TSource>>> GetOrderablePartitions(int partitionCount) { if (partitionCount <= 0) { throw new ArgumentOutOfRangeException("partitionCount"); } IEnumerator<KeyValuePair<long, TSource>>[] array = new IEnumerator<KeyValuePair<long, TSource>>[partitionCount]; IEnumerable<KeyValuePair<long, TSource>> orderableDynamicPartitions_Factory = GetOrderableDynamicPartitions_Factory(m_data); for (int i = 0; i < partitionCount; i++) { array[i] = orderableDynamicPartitions_Factory.GetEnumerator(); } return array; } public override IEnumerable<KeyValuePair<long, TSource>> GetOrderableDynamicPartitions() { return GetOrderableDynamicPartitions_Factory(m_data); } } private abstract class DynamicPartitionEnumeratorForIndexRange_Abstract<TSource, TSourceReader> : DynamicPartitionEnumerator_Abstract<TSource, TSourceReader> { protected int m_startIndex; protected abstract int SourceCount { get; } protected override bool HasNoElementsLeft { get { return m_sharedIndex.Value >= SourceCount - 1; } set { } } protected DynamicPartitionEnumeratorForIndexRange_Abstract(TSourceReader sharedReader, Shared<long> sharedIndex) : base(sharedReader, sharedIndex) { } protected override bool GrabNextChunk(int requestedChunkSize) { while (!HasNoElementsLeft) { long value = m_sharedIndex.Value; if (HasNoElementsLeft) { return false; } long num = Math.Min(SourceCount - 1, value + requestedChunkSize); if (Interlocked.CompareExchange(ref m_sharedIndex.Value, num, value) == value) { m_currentChunkSize.Value = (int)(num - value); m_localOffset.Value = -1; m_startIndex = (int)(value + 1); return true; } } return false; } public override void Dispose() { } } private class DynamicPartitionerForIList<TSource> : DynamicPartitionerForIndexRange_Abstract<TSource, IList<TSource>> { private class InternalPartitionEnumerable : IEnumerable<KeyValuePair<long, TSource>>, IEnumerable { private readonly IList<TSource> m_sharedReader; private Shared<long> m_sharedIndex; internal InternalPartitionEnumerable(IList<TSource> sharedReader) { m_sharedReader = sharedReader; m_sharedIndex = new Shared<long>(-1L); } public IEnumerator<KeyValuePair<long, TSource>> GetEnumerator() { return new InternalPartitionEnumerator(m_sharedReader, m_sharedIndex); } IEnumerator IEnumerable.GetEnumerator() { return GetEnumerator(); } } private class InternalPartitionEnumerator : DynamicPartitionEnumeratorForIndexRange_Abstract<TSource, IList<TSource>> { protected override int SourceCount => m_sharedReader.Count; public override KeyValuePair<long, TSource> Current { get { if (m_currentChunkSize == null) { throw new InvalidOperationException(Environment2.GetResourceString("PartitionerStatic_CurrentCalledBeforeMoveNext")); } return new KeyValuePair<long, TSource>(m_startIndex + m_localOffset.Value, m_sharedReader[m_startIndex + m_localOffset.Value]); } } internal InternalPartitionEnumerator(IList<TSource> sharedReader, Shared<long> sharedIndex) : base(sharedReader, sharedIndex) { } } internal DynamicPartitionerForIList(IList<TSource> source) : base(source) { } protected override IEnumerable<KeyValuePair<long, TSource>> GetOrderableDynamicPartitions_Factory(IList<TSource> m_data) { return new InternalPartitionEnumerable(m_data); } } private class DynamicPartitionerForArray<TSource> : DynamicPartitionerForIndexRange_Abstract<TSource, TSource[]> { private class InternalPartitionEnumerable : IEnumerable<KeyValuePair<long, TSource>>, IEnumerable { private readonly TSource[] m_sharedReader; private Shared<long> m_sharedIndex; internal InternalPartitionEnumerable(TSource[] sharedReader) { m_sharedReader = sharedReader; m_sharedIndex = new Shared<long>(-1L); } IEnumerator IEnumerable.GetEnumerator() { return GetEnumerator(); } public IEnumerator<KeyValuePair<long, TSource>> GetEnumerator() { return new InternalPartitionEnumerator(m_sharedReader, m_sharedIndex); } } private class InternalPartitionEnumerator : DynamicPartitionEnumeratorForIndexRange_Abstract<TSource, TSource[]> { protected override int SourceCount => m_sharedReader.Length; public override KeyValuePair<long, TSource> Current { get { if (m_currentChunkSize == null) { throw new InvalidOperationException(Environment2.GetResourceString("PartitionerStatic_CurrentCalledBeforeMoveNext")); } return new KeyValuePair<long, TSource>(m_startIndex + m_localOffset.Value, m_sharedReader[m_startIndex + m_localOffset.Value]); } } internal InternalPartitionEnumerator(TSource[] sharedReader, Shared<long> sharedIndex) : base(sharedReader, sharedIndex) { } } internal DynamicPartitionerForArray(TSource[] source) : base(source) { } protected override IEnumerable<KeyValuePair<long, TSource>> GetOrderableDynamicPartitions_Factory(TSource[] m_data) { return new InternalPartitionEnumerable(m_data); } } private abstract class StaticIndexRangePartitioner<TSource, TCollection> : OrderablePartitioner<TSource> { protected abstract int SourceCount { get; } protected StaticIndexRangePartitioner() : base(keysOrderedInEachPartition: true, keysOrderedAcrossPartitions: true, keysNormalized: true) { } protected abstract IEnumerator<KeyValuePair<long, TSource>> CreatePartition(int startIndex, int endIndex); public override IList<IEnumerator<KeyValuePair<long, TSource>>> GetOrderablePartitions(int partitionCount) { if (partitionCount <= 0) { throw new ArgumentOutOfRangeException("partitionCount"); } int result; int num = Math.DivRem(SourceCount, partitionCount, out result); IEnumerator<KeyValuePair<long, TSource>>[] array = new IEnumerator<KeyValuePair<long, TSource>>[partitionCount]; int num2 = -1; for (int i = 0; i < partitionCount; i++) { int num3 = num2 + 1; num2 = ((i >= result) ? (num3 + num - 1) : (num3 + num)); array[i] = CreatePartition(num3, num2); } return array; } } private abstract class StaticIndexRangePartition<TSource> : IEnumerator<KeyValuePair<long, TSource>>, IDisposable, IEnumerator { protected readonly int m_startIndex; protected readonly int m_endIndex; protected volatile int m_offset; public abstract KeyValuePair<long, TSource> Current { get; } object IEnumerator.Current => Current; protected StaticIndexRangePartition(int startIndex, int endIndex) { m_startIndex = startIndex; m_endIndex = endIndex; m_offset = startIndex - 1; } public void Dispose() { } public void Reset() { throw new NotSupportedException(); } public bool MoveNext() { if (m_offset < m_endIndex) { m_offset++; return true; } m_offset = m_endIndex + 1; return false; } } private class StaticIndexRangePartitionerForIList<TSource> : StaticIndexRangePartitioner<TSource, IList<TSource>> { private IList<TSource> m_list; protected override int SourceCount => m_list.Count; internal StaticIndexRangePartitionerForIList(IList<TSource> list) { m_list = list; } protected override IEnumerator<KeyValuePair<long, TSource>> CreatePartition(int startIndex, int endIndex) { return new StaticIndexRangePartitionForIList<TSource>(m_list, startIndex, endIndex); } } private class StaticIndexRangePartitionForIList<TSource> : StaticIndexRangePartition<TSource> { private volatile IList<TSource> m_list; public override KeyValuePair<long, TSource> Current { get { if (m_offset < m_startIndex) { throw new InvalidOperationException(Environment2.GetResourceString("PartitionerStatic_CurrentCalledBeforeMoveNext")); } return new KeyValuePair<long, TSource>(m_offset, m_list[m_offset]); } } internal StaticIndexRangePartitionForIList(IList<TSource> list, int startIndex, int endIndex) : base(startIndex, endIndex) { m_list = list; } } private class StaticIndexRangePartitionerForArray<TSource> : StaticIndexRangePartitioner<TSource, TSource[]> { private TSource[] m_array; protected override int SourceCount => m_array.Length; internal StaticIndexRangePartitionerForArray(TSource[] array) { m_array = array; } protected override IEnumerator<KeyValuePair<long, TSource>> CreatePartition(int startIndex, int endIndex) { return new StaticIndexRangePartitionForArray<TSource>(m_array, startIndex, endIndex); } } private class StaticIndexRangePartitionForArray<TSource> : StaticIndexRangePartition<TSource> { private volatile TSource[] m_array; public override KeyValuePair<long, TSource> Current { get { if (m_offset < m_startIndex) { throw new InvalidOperationException(Environment2.GetResourceString("PartitionerStatic_CurrentCalledBeforeMoveNext")); } return new KeyValuePair<long, TSource>(m_offset, m_array[m_offset]); } } internal StaticIndexRangePartitionForArray(TSource[] array, int startIndex, int endIndex) : base(startIndex, endIndex) { m_array = array; } } private class Shared<TSource> { internal TSource Value; internal Shared(TSource value) { Value = value; } } private const int DEFAULT_BYTES_PER_CHUNK = 512; public static OrderablePartitioner<TSource> Create<TSource>(IList<TSource> list, bool loadBalance) { if (list == null) { throw new ArgumentNullException("list"); } if (loadBalance) { return new DynamicPartitionerForIList<TSource>(list); } return new StaticIndexRangePartitionerForIList<TSource>(list); } public static OrderablePartitioner<TSource> Create<TSource>(TSource[] array, bool loadBalance) { if (array == null) { throw new ArgumentNullException("array"); } if (loadBalance) { return new DynamicPartitionerForArray<TSource>(array); } return new StaticIndexRangePartitionerForArray<TSource>(array); } public static OrderablePartitioner<TSource> Create<TSource>(IEnumerable<TSource> source) { return Create(source, -1); } internal static OrderablePartitioner<TSource> Create<TSource>(IEnumerable<TSource> source, int maxChunkSize) { if (source == null) { throw new ArgumentNullException("source"); } return new DynamicPartitionerForIEnumerable<TSource>(source, maxChunkSize); } private static int GetDefaultChunkSize<TSource>() { if (typeof(TSource).IsValueType) { if (typeof(TSource).StructLayoutAttribute.Value == LayoutKind.Explicit) { return Math.Max(1, 512 / Marshal.SizeOf(typeof(TSource))); } return 128; } return 512 / IntPtr.Size; } } } namespace System { [Serializable] [DebuggerDisplay("Count = {InnerExceptions.Count}")] public class AggregateException : Exception { private ReadOnlyCollection<Exception> m_innerExceptions; public ReadOnlyCollection<Exception> InnerExceptions => m_innerExceptions; public AggregateException() : base(Environment2.GetResourceString("AggregateException_ctor_DefaultMessage")) { m_innerExceptions = new ReadOnlyCollection<Exception>(new Exception[0]); } public AggregateException(string message) : base(message) { m_innerExceptions = new ReadOnlyCollection<Exception>(new Exception[0]); } public AggregateException(string message, Exception innerException) : base(message, innerException) { if (innerException == null) { throw new ArgumentNullException("innerException"); } m_innerExceptions = new ReadOnlyCollection<Exception>(new Exception[1] { innerException }); } public AggregateException(IEnumerable<Exception> innerExceptions) : this(Environment2.GetResourceString("AggregateException_ctor_DefaultMessage"), innerExceptions) { } public AggregateException(params Exception[] innerExceptions) : this(Environment2.GetResourceString("AggregateException_ctor_DefaultMessage"), innerExceptions) { } public AggregateException(string message, IEnumerable<Exception> innerExceptions) : this(message, (innerExceptions == null) ? null : new List<Exception>(innerExceptions)) { } public AggregateException(string message, params Exception[] innerExceptions) : this(message, (IList<Exception>)innerExceptions) { } private AggregateException(string message, IList<Exception> innerExceptions) : base(message, (innerExceptions != null && innerExceptions.Count > 0) ? innerExceptions[0] : null) { if (innerExceptions == null) { throw new ArgumentNullException("innerExceptions"); } Exception[] array = new Exception[innerExceptions.Count]; for (int i = 0; i < array.Length; i++) { array[i] = innerExceptions[i]; if (array[i] == null) { throw new ArgumentException(Environment2.GetResourceString("AggregateException_ctor_InnerExceptionNull")); } } m_innerExceptions = new ReadOnlyCollection<Exception>(array); } [SecurityCritical] protected AggregateException(SerializationInfo info, StreamingContext context) : base(info, context) { if (info == null) { throw new ArgumentNullException("info"); } if (!(info.GetValue("InnerExceptions", typeof(Exception[])) is Exception[] list)) { throw new SerializationException(Environment2.GetResourceString("AggregateException_DeserializationFailure")); } m_innerExceptions = new ReadOnlyCollection<Exception>(list); } [SecurityCritical] public override void GetObjectData(SerializationInfo info, StreamingContext context) { if (info == null) { throw new ArgumentNullException("info"); } base.GetObjectData(info, context); Exception[] array = new Exception[m_innerExceptions.Count]; m_innerExceptions.CopyTo(array, 0); info.AddValue("InnerExceptions", array, typeof(Exception[])); } public override Exception GetBaseException() { Exception ex = this; AggregateException ex2 = this; while (ex2 != null && ex2.InnerExceptions.Count == 1) { ex = ex.InnerException; ex2 = ex as AggregateException; } return ex; } public void Handle(Func<Exception, bool> predicate) { if (predicate == null) { throw new ArgumentNullException("predicate"); } List<Exception> list = null; for (int i = 0; i < m_innerExceptions.Count; i++) { if (!predicate(m_innerExceptions[i])) { if (list == null) { list = new List<Exception>(); } list.Add(m_innerExceptions[i]); } } if (list != null) { throw new AggregateException(Message, list); } } public AggregateException Flatten() { List<Exception> list = new List<Exception>(); List<AggregateException> list2 = new List<AggregateException>(); list2.Add(this); int num = 0; while (list2.Count > num) { IList<Exception> innerExceptions = list2[num++].InnerExceptions; for (int i = 0; i < innerExceptions.Count; i++) { Exception ex = innerExceptions[i]; if (ex != null) { if (ex is AggregateException item) { list2.Add(item); } else { list.Add(ex); } } } } return new AggregateException(Message, list); } public override string ToString() { string text = base.ToString(); for (int i = 0; i < m_innerExceptions.Count; i++) { text = string.Format(CultureInfo.InvariantCulture, Environment2.GetResourceString("AggregateException_ToString"), text, Environment.NewLine, i, m_innerExceptions[i].ToString(), "<---", Environment.NewLine); } return text; } } public delegate TResult Func_<T1, T2, T3, T4, T5, TResult>(T1 arg1, T2 arg2, T3 arg3, T4 arg4, T5 arg5); } namespace System.Threading { [ComVisible(false)] [DebuggerDisplay("IsCancellationRequested = {IsCancellationRequested}")] [HostProtection(SecurityAction.LinkDemand, Synchronization = true, ExternalThreading = true)] public struct CancellationToken { private CancellationTokenSource m_source; private static Action<object> s_ActionToActionObjShunt = ActionToActionObjShunt; public static CancellationToken None => default(CancellationToken); public bool IsCancellationRequested { get { if (m_source != null) { return m_source.IsCancellationRequested; } return false; } } public bool CanBeCanceled { get { if (m_source != null) { return m_source.CanBeCanceled; } return false; } } public WaitHandle WaitHandle { get { if (m_source == null) { InitializeDefaultSource(); } return m_source.WaitHandle; } } internal CancellationToken(CancellationTokenSource source) { m_source = source; } public CancellationToken(bool canceled) { this = default(CancellationToken); if (canceled) { m_source = CancellationTokenSource.InternalGetStaticSource(canceled); } } private static void ActionToActionObjShunt(object obj) { Action action = obj as Action; action(); } public CancellationTokenRegistration Register(Action callback) { if (callback == null) { throw new ArgumentNullException("callback"); } return Register(s_ActionToActionObjShunt, callback, useSynchronizationContext: false, useExecutionContext: true); } public CancellationTokenRegistration Register(Action callback, bool useSynchronizationContext) { if (callback == null) { throw new ArgumentNullException("callback"); } return Register(s_ActionToActionObjShunt, callback, useSynchronizationContext, useExecutionContext: true); } public CancellationTokenRegistration Register(Action<object> callback, object state) { if (callback == null) { throw new ArgumentNullException("callback"); } return Register(callback, state, useSynchronizationContext: false, useExecutionContext: true); } public CancellationTokenRegistration Register(Action<object> callback, object state, bool useSynchronizationContext) { return Register(callback, state, useSynchronizationContext, useExecutionContext: true); } internal CancellationTokenRegistration InternalRegisterWithoutEC(Action<object> callback, object state) { return Register(callback, state, useSynchronizationContext: false, useExecutionContext: false); } private CancellationTokenRegistration Register(Action<object> callback, object state, bool useSynchronizationContext, bool useExecutionContext) { if (callback == null) { throw new ArgumentNullException("callback"); } if (!CanBeCanceled) { return default(CancellationTokenRegistration); } SynchronizationContext targetSyncContext = null; if (!IsCancellationRequested && useSynchronizationContext) { targetSyncContext = SynchronizationContext.Current; } ExecutionContext executionContext = null; if (!IsCancellationRequested && useExecutionContext) { executionContext = ExecutionContext.Capture(); } return m_source.InternalRegister(callback, state, targetSyncContext, executionContext); } public bool Equals(CancellationToken other) { if (m_source == null && other.m_source == null) { return true; } if (m_source == null) { return other.m_source == CancellationTokenSource.InternalGetStaticSource(set: false); } if (other.m_source == null) { return m_source == CancellationTokenSource.InternalGetStaticSource(set: false); } return m_source == other.m_source; } public override bool Equals(object other) { if (other is CancellationToken) { return Equals((CancellationToken)other); } return false; } public override int GetHashCode() { if (m_source == null) { return CancellationTokenSource.InternalGetStaticSource(set: false).GetHashCode(); } return m_source.GetHashCode(); } public static bool operator ==(CancellationToken left, CancellationToken right) { return left.Equals(right); } public static bool operator !=(CancellationToken left, CancellationToken right) { return !left.Equals(right); } public void ThrowIfCancellationRequested() { if (IsCancellationRequested) { throw new OperationCanceledException2(Environment2.GetResourceString("OperationCanceled"), this); } } internal void ThrowIfSourceDisposed() { if (m_source != null && m_source.IsDisposed) { throw new ObjectDisposedException(null, Environment2.GetResourceString("CancellationToken_SourceDisposed")); } } private void InitializeDefaultSource() { m_source = CancellationTokenSource.InternalGetStaticSource(set: false); } } [HostProtection(SecurityAction.LinkDemand, Synchronization = true, ExternalThreading = true)] public struct CancellationTokenRegistration : IEquatable<CancellationTokenRegistration>, IDisposable { private readonly CancellationTokenSource m_tokenSource; private readonly CancellationCallbackInfo m_callbackInfo; private readonly SparselyPopulatedArrayAddInfo<CancellationCallbackInfo> m_registrationInfo; internal CancellationTokenRegistration(CancellationTokenSource tokenSource, CancellationCallbackInfo callbackInfo, SparselyPopulatedArrayAddInfo<CancellationCallbackInfo> registrationInfo) { m_tokenSource = tokenSource; m_callbackInfo = callbackInfo; m_registrationInfo = registrationInfo; } internal bool TryDeregister() { if (m_registrationInfo.Source == null) { return false; } CancellationCallbackInfo cancellationCallbackInfo = m_registrationInfo.Source.SafeAtomicRemove(m_registrationInfo.Index, m_callbackInfo); if (cancellationCallbackInfo != m_callbackInfo) { return false; } return true; } public void Dispose() { if (m_tokenSource != null) { m_tokenSource.ThrowIfDisposed(); } bool flag = TryDeregister(); if (m_tokenSource != null && m_tokenSource.IsCancellationRequested && !m_tokenSource.IsCancellationCompleted && !flag && m_tokenSource.ThreadIDExecutingCallbacks != Thread.CurrentThread.ManagedThreadId) { m_tokenSource.WaitForCallbackToComplete(m_callbackInfo); } } public static bool operator ==(CancellationTokenRegistration left, CancellationTokenRegistration right) { return left.Equals(right); } public static bool operator !=(CancellationTokenRegistration left, CancellationTokenRegistration right) { return !left.Equals(right); } public override bool Equals(object obj) { if (obj is CancellationTokenRegistration) { return Equals((CancellationTokenRegistration)obj); } return false; } public bool Equals(CancellationTokenRegistration other) { if (m_tokenSource == other.m_tokenSource && m_callbackInfo == other.m_callbackInfo && m_registrationInfo.Source == other.m_registrationInfo.Source) { return m_registrationInfo.Index == other.m_registrationInfo.Index; } return false; } public override int GetHashCode() { if (m_registrationInfo.Source != null) { return m_registrationInfo.Source.GetHashCode() ^ m_registrationInfo.Index.GetHashCode(); } return m_registrationInfo.Index.GetHashCode(); } } [ComVisible(false)] [HostProtection(SecurityAction.LinkDemand, Synchronization = true, ExternalThreading = true)] public sealed class CancellationTokenSource : IDisposable { private const int CANNOT_BE_CANCELED = 0; private const int NOT_CANCELED = 1; private const int NOTIFYING = 2; private const int NOTIFYINGCOMPLETE = 3; private static readonly CancellationTokenSource _staticSource_Set = new CancellationTokenSource(set: true); private static readonly CancellationTokenSource _staticSource_NotCancelable = new CancellationTokenSource(set: false); private static readonly int s_nLists = ((PlatformHelper.ProcessorCount > 24) ? 24 : PlatformHelper.ProcessorCount); private volatile ManualResetEvent m_kernelEvent; private volatile SparselyPopulatedArray<CancellationCallbackInfo>[] m_registeredCallbacksLists; private volatile int m_state; private volatile int m_threadIDExecutingCallbacks = -1; private bool m_disposed; private List<CancellationTokenRegistration> m_linkingRegistrations; private static readonly Action<object> s_LinkedTokenCancelDelegate = LinkedTokenCancelDelegate; private volatile CancellationCallbackInfo m_executingCallback; public bool IsCancellationRequested => m_state >= 2; internal bool IsCancellationCompleted => m_state == 3; internal bool IsDisposed => m_disposed; internal int ThreadIDExecutingCallbacks { get { return m_threadIDExecutingCallbacks; } set { m_threadIDExecutingCallbacks = value; } } public CancellationToken Token { get { ThrowIfDisposed(); return new CancellationToken(this); } } internal bool CanBeCanceled => m_state != 0; internal WaitHandle WaitHandle { get { ThrowIfDisposed(); if (m_kernelEvent != null) { return m_kernelEvent; } ManualResetEvent manualResetEvent = new ManualResetEvent(initialState: false); if (Interlocked.CompareExchange(ref m_kernelEvent, manualResetEvent, null) != null) { ((IDisposable)manualResetEvent).Dispose(); } if (IsCancellationRequested) { m_kernelEvent.Set(); } return m_kernelEvent; } } internal CancellationCallbackInfo ExecutingCallback => m_executingCallback; private static void LinkedTokenCancelDelegate(object source) { CancellationTokenSource cancellationTokenSource = source as CancellationTokenSource; cancellationTokenSource.Cancel(); } public CancellationTokenSource() { m_state = 1; } private CancellationTokenSource(bool set) { m_state = (set ? 3 : 0); } public void Cancel() { Cancel(throwOnFirstException: false); } public void Cancel(bool throwOnFirstException) { ThrowIfDisposed(); NotifyCancellation(throwOnFirstException); } public void Dispose() { if (m_disposed) { return; } if (m_linkingRegistrations != null) { foreach (CancellationTokenRegistration linkingRegistration in m_linkingRegistrations) { linkingRegistration.Dispose(); } m_linkingRegistrations = null; } m_registeredCallbacksLists = null; if (m_kernelEvent != null) { m_kernelEvent.Close(); m_kernelEvent = null; } m_disposed = true; } internal void ThrowIfDisposed() { if (m_disposed) { throw new ObjectDisposedException(null, Environment2.GetResourceString("CancellationTokenSource_Disposed")); } } internal static CancellationTokenSource InternalGetStaticSource(bool set) { if (!set) { return _staticSource_NotCancelable; } return _staticSource_Set; } internal CancellationTokenRegistration InternalRegister(Action<object> callback, object stateForCallback, SynchronizationContext targetSyncContext, ExecutionContext executionContext) { ThrowIfDisposed(); if (!IsCancellationRequested) { int num = Thread.CurrentThread.ManagedThreadId % s_nLists; CancellationCallbackInfo cancellationCallbackInfo = new CancellationCallbackInfo(callback, stateForCallback, targetSyncContext, executionContext, this); if (m_registeredCallbacksLists == null) { SparselyPopulatedArray<CancellationCallbackInfo>[] value = new SparselyPopulatedArray<CancellationCallbackInfo>[s_nLists]; Interlocked.CompareExchange(ref m_registeredCallbacksLists, value, null); } if (m_registeredCallbacksLists[num] == null) { SparselyPopulatedArray<CancellationCallbackInfo> value2 = new SparselyPopulatedArray<CancellationCallbackInfo>(4); Interlocked.CompareExchange(ref m_registeredCallbacksLists[num], value2, null); } SparselyPopulatedArray<CancellationCallbackInfo> sparselyPopulatedArray = m_registeredCallbacksLists[num]; SparselyPopulatedArrayAddInfo<CancellationCallbackInfo> registrationInfo = sparselyPopulatedArray.Add(cancellationCallbackInfo); CancellationTokenRegistration result = new CancellationTokenRegistration(this, cancellationCallbackInfo, registrationInfo); if (!IsCancellationRequested) { return result; } if (!result.TryDeregister()) { WaitForCallbackToComplete(cancellationCallbackInfo); return default(CancellationTokenRegistration); } } callback(stateForCallback); return default(CancellationTokenRegistration); } private void NotifyCancellation(bool throwOnFirstException) { if (!IsCancellationRequested && Interlocked.CompareExchange(ref m_state, 2, 1) == 1) { ThreadIDExecutingCallbacks = Thread.CurrentThread.ManagedThreadId; if (m_kernelEvent != null) { m_kernelEvent.Set(); } ExecuteCallbackHandlers(throwOnFirstException); } } private void ExecuteCallbackHandlers(bool throwOnFirstException) { List<Exception> list = null; SparselyPopulatedArray<CancellationCallbackInfo>[] registeredCallbacksLists = m_registeredCallbacksLists; if (registeredCallbacksLists == null) { Interlocked.Exchange(ref m_state, 3); return; } try { foreach (SparselyPopulatedArray<CancellationCallbackInfo> sparselyPopulatedArray in registeredCallbacksLists) { if (sparselyPopulatedArray == null) { continue; } for (SparselyPopulatedArrayFragment<CancellationCallbackInfo> sparselyPopulatedArrayFragment = sparselyPopulatedArray.Tail; sparselyPopulatedArrayFragment != null; sparselyPopulatedArrayFragment = sparselyPopulatedArrayFragment.Prev) { for (int num = sparselyPopulatedArrayFragment.Length - 1; num >= 0; num--) { m_executingCallback = sparselyPopulatedArrayFragment[num]; if (m_executingCallback != null) { CancellationCallbackCoreWorkArguments cancellationCallbackCoreWorkArguments = new CancellationCallbackCoreWorkArguments(sparselyPopulatedArrayFragment, num); try { if (m_executingCallback.TargetSyncContext != null) { m_executingCallback.TargetSyncContext.Send(CancellationCallbackCoreWork_OnSyncContext, cancellationCallbackCoreWorkArguments); ThreadIDExecutingCallbacks = Thread.CurrentThread.ManagedThreadId; } else { CancellationCallbackCoreWork_OnSyncContext(cancellationCallbackCoreWorkArguments); } } catch (Exception item) { if (throwOnFirstException) { throw; } if (list == null) { list = new List<Exception>(); } list.Add(item); } } } } } } finally { m_state = 3; m_executingCallback = null; Thread.MemoryBarrier(); } if (list == null) { return; } throw new AggregateException(list); } private void CancellationCallbackCoreWork_OnSyncContext(object obj) { CancellationCallbackCoreWorkArguments cancellationCallbackCoreWorkArguments = (CancellationCallbackCoreWorkArguments)obj; CancellationCallbackInfo cancellationCallbackInfo = cancellationCallbackCoreWorkArguments.m_currArrayFragment.SafeAtomicRemove(cancellationCallbackCoreWorkArguments.m_currArrayIndex, m_executingCallback); if (cancellationCallbackInfo == m_executingCallback) { if (cancellationCallbackInfo.TargetExecutionContext != null) { cancellationCallbackInfo.CancellationTokenSource.ThreadIDExecutingCallbacks = Thread.CurrentThread.ManagedThreadId; } cancellationCallbackInfo.ExecuteCallback(); } } public static CancellationTokenSource CreateLinkedTokenSource(CancellationToken token1, CancellationToken token2) { CancellationTokenSource cancellationTokenSource = new CancellationTokenSource(); if (token1.CanBeCanceled) { cancellationTokenSource.m_linkingRegistrations = new List<CancellationTokenRegistration>(); cancellationTokenSource.m_linkingRegistrations.Add(token1.InternalRegisterWithoutEC(s_LinkedTokenCancelDelegate, cancellationTokenSource)); } if (token2.CanBeCanceled) { if (cancellationTokenSource.m_linkingRegistrations == null) { cancellationTokenSource.m_linkingRegistrations = new List<CancellationTokenRegistration>(); } cancellationTokenSource.m_linkingRegistrations.Add(token2.InternalRegisterWithoutEC(s_LinkedTokenCancelDelegate, cancellationTokenSource)); } return cancellationTokenSource; } public static CancellationTokenSource CreateLinkedTokenSource(params CancellationToken[] tokens) { if (tokens == null) { throw new ArgumentNullException("tokens"); } if (tokens.Length == 0) { throw new ArgumentException(Environment2.GetResourceString("CancellationToken_CreateLinkedToken_TokensIsEmpty")); } CancellationTokenSource cancellationTokenSource = new CancellationTokenSource(); cancellationTokenSource.m_linkingRegistrations = new List<CancellationTokenRegistration>(); for (int i = 0; i < tokens.Length; i++) { if (tokens[i].CanBeCanceled) { cancellationTokenSource.m_linkingRegistrations.Add(tokens[i].InternalRegisterWithoutEC(s_LinkedTokenCancelDelegate, cancellationTokenSource)); } } return cancellationTokenSource; } internal void WaitForCallbackToComplete(CancellationCallbackInfo callbackInfo) { SpinWait spinWait = default(SpinWait); while (ExecutingCallback == callbackInfo) { spinWait.SpinOnce(); } } } internal struct CancellationCallbackCoreWorkArguments { internal SparselyPopulatedArrayFragment<CancellationCallbackInfo> m_currArrayFragment; internal int m_currArrayIndex; public CancellationCallbackCoreWorkArguments(SparselyPopulatedArrayFragment<CancellationCallbackInfo> currArrayFragment, int currArrayIndex) { m_currArrayFragment = currArrayFragment; m_currArrayIndex = currArrayIndex; } } internal class CancellationCallbackInfo { internal readonly Action<object> Callback; internal readonly object StateForCallback; internal readonly SynchronizationContext TargetSyncContext; internal readonly ExecutionContext TargetExecutionContext; internal readonly CancellationTokenSource CancellationTokenSource; internal CancellationCallbackInfo(Action<object> callback, object stateForCallback, SynchronizationContext targetSyncContext, ExecutionContext targetExecutionContext, CancellationTokenSource cancellationTokenSource) { Callback = callback; StateForCallback = stateForCallback; TargetSyncContext = targetSyncContext; TargetExecutionContext = targetExecutionContext; CancellationTokenSource = cancellationTokenSource; } [SecuritySafeCritical] internal void ExecuteCallback() { if (TargetExecutionContext != null) { ExecutionContext.Run(TargetExecutionContext, ExecutionContextCallback, this); } else { ExecutionContextCallback(this); } } private static void ExecutionContextCallback(object obj) { CancellationCallbackInfo cancellationCallbackInfo = obj as CancellationCallbackInfo; cancellationCallbackInfo.Callback(cancellationCallbackInfo.StateForCallback); } } internal class SparselyPopulatedArray<T> where T : class { private readonly SparselyPopulatedArrayFragment<T> m_head; private volatile SparselyPopulatedArrayFragment<T> m_tail; internal SparselyPopulatedArrayFragment<T> Head => m_head; internal SparselyPopulatedArrayFragment<T> Tail => m_tail; internal SparselyPopulatedArray(int initialSize) { m_head = (m_tail = new SparselyPopulatedArrayFragment<T>(initialSize)); } internal SparselyPopulatedArrayAddInfo<T> Add(T element) { while (true) { SparselyPopulatedArrayFragment<T> sparselyPopulatedArrayFragment = m_tail; while (sparselyPopulatedArrayFragment.m_next != null) { sparselyPopulatedArrayFragment = (m_tail = sparselyPopulatedArrayFragment.m_next); } for (SparselyPopulatedArrayFragment<T> sparselyPopulatedArrayFragment2 = sparselyPopulatedArrayFragment; sparselyPopulatedArrayFragment2 != null; sparselyPopulatedArrayFragment2 = sparselyPopulatedArrayFragment2.m_prev) { if (sparselyPopulatedArrayFragment2.m_freeCount < 1) { sparselyPopulatedArrayFragment2.m_freeCount--; } if (sparselyPopulatedArrayFragment2.m_freeCount > 0 || sparselyPopulatedArrayFragment2.m_freeCount < -10) { int length = sparselyPopulatedArrayFragment2.Length; int num = (length - sparselyPopulatedArrayFragment2.m_freeCount) % length; if (num < 0) { num = 0; sparselyPopulatedArrayFragment2.m_freeCount--; } for (int i = 0; i < length; i++) { int num2 = (num + i) % length; if (sparselyPopulatedArrayFragment2.m_elements[num2] == null && Interlocked.CompareExchange(ref sparselyPopulatedArrayFragment2.m_elements[num2], element, null) == null) { int num3 = sparselyPopulatedArrayFragment2.m_freeCount - 1; sparselyPopulatedArrayFragment2.m_freeCount = ((num3 > 0) ? num3 : 0); return new SparselyPopulatedArrayAddInfo<T>(sparselyPopulatedArrayFragment2, num2); } } } } SparselyPopulatedArrayFragment<T> sparselyPopulatedArrayFragment3 = new SparselyPopulatedArrayFragment<T>((sparselyPopulatedArrayFragment.m_elements.Length == 4096) ? 4096 : (sparselyPopulatedArrayFragment.m_elements.Length * 2), sparselyPopulatedArrayFragment); if (Interlocked.CompareExchange(ref sparselyPopulatedArrayFragment.m_next, sparselyPopulatedArrayFragment3, null) == null) { m_tail = sparselyPopulatedArrayFragment3; } } } } internal struct SparselyPopulatedArrayAddInfo<T> where T : class { private SparselyPopulatedArrayFragment<T> m_source; private int m_index; internal SparselyPopulatedArrayFragment<T> Source => m_source; internal int Index => m_index; internal SparselyPopulatedArrayAddInfo(SparselyPopulatedArrayFragment<T> source, int index) { m_source = source; m_index = index; } } internal class SparselyPopulatedArrayFragment<T> where T : class { internal readonly T[] m_elements; internal volatile int m_freeCount; internal volatile SparselyPopulatedArrayFragment<T> m_next; internal volatile SparselyPopulatedArrayFragment<T> m_prev; internal T this[int index] => m_elements[index]; internal int Length => m_elements.Length; internal SparselyPopulatedArrayFragment<T> Next => m_next; internal SparselyPopulatedArrayFragment<T> Prev => m_prev; internal SparselyPopulatedArrayFragment(int size) : this(size, (SparselyPopulatedArrayFragment<T>)null) { } internal SparselyPopulatedArrayFragment(int size, SparselyPopulatedArrayFragment<T> prev) { m_elements = new T[size]; m_freeCount = size; m_prev = prev; } internal T SafeAtomicRemove(int index, T expectedElement) { T val = Interlocked.CompareExchange(ref m_elements[index], null, expectedElement); if (val != null) { m_freeCount++; } return val; } } [DebuggerDisplay("Initial Count={InitialCount}, Current Count={CurrentCount}")] [ComVisible(false)] [HostProtection(SecurityAction.LinkDemand, Synchronization = true, ExternalThreading = true)] public class CountdownEvent : IDisposable { private int m_initialCount; private volatile int m_currentCount; private ManualResetEventSlim m_event; private volatile bool m_disposed; public int CurrentCount => m_currentCount; public int InitialCount => m_initialCount; public bool IsSet => m_currentCount == 0; public WaitHandle WaitHandle { get { ThrowIfDisposed(); return m_event.WaitHandle; } } public CountdownEvent(int initialCount) { if (initialCount < 0) { throw new ArgumentOutOfRangeException("initialCount"); } m_initialCount = initialCount; m_currentCount = initialCount; m_event = new ManualResetEventSlim(); if (initialCount == 0) { m_event.Set(); } } public void Dispose() { Dispose(disposing: true); GC.SuppressFinalize(this); } protected virtual void Dispose(bool disposing) { if (disposing) { m_event.Dispose(); m_disposed = true; } } public bool Signal() { return Signal(1); } public bool Signal(int signalCount) { if (signalCount <= 0) { throw new ArgumentOutOfRangeException("signalCount"); } ThrowIfDisposed(); SpinWait spinWait = default(SpinWait); int currentCount; while (true) { currentCount = m_currentCount; if (currentCount < signalCount) { throw new InvalidOperationException(Environment2.GetResourceString("CountdownEvent_Decrement_BelowZero")); } if (Interlocked.CompareExchange(ref m_currentCount, currentCount - signalCount, currentCount) == currentCount) { break; } spinWait.SpinOnce(); } if (currentCount == signalCount) { m_event.Set(); return true; } return false; } public void AddCount() { AddCount(1); } public bool TryAddCount() { return TryAddCount(1); } public void AddCount(int signalCount) { if (!TryAddCount(signalCount)) { throw new InvalidOperationException(Environment2.GetResourceString("CountdownEvent_Increment_AlreadyZero")); } } public bool TryAddCount(int signalCount) { if (signalCount <= 0) { throw new ArgumentOutOfRangeException("signalCount"); } ThrowIfDisposed(); SpinWait spinWait = default(SpinWait); while (true) { int currentCount = m_currentCount; if (currentCount == 0) { return false; } if (currentCount > int.MaxValue - signalCount) { throw new InvalidOperationException(Environment2.GetResourceString("CountdownEvent_Increment_AlreadyMax")); } if (Interlocked.CompareExchange(ref m_currentCount, currentCount + signalCount, currentCount) == currentCount) { break; } spinWait.SpinOnce(); } return true; } public void Reset() { Reset(m_initialCount); } public void Reset(int count) { ThrowIfDisposed(); if (count < 0) { throw new ArgumentOutOfRangeException("count"); } m_currentCount = count; m_initialCount = count; if (count == 0) { m_event.Set(); } else { m_event.Reset(); } } public void Wait() { Wait(-1, default(CancellationToken)); } public void Wait(CancellationToken cancellationToken) { Wait(-1, cancellationToken); } public bool Wait(TimeSpan timeout) { long num = (long)timeout.TotalMilliseconds; if (num < -1 || num > int.MaxValue) { throw new ArgumentOutOfRangeException("timeout"); } return Wait((int)num, default(CancellationToken)); } public bool Wait(TimeSpan timeout, CancellationToken cancellationToken) { long num = (long)timeout.TotalMilliseconds; if (num < -1 || num > int.MaxValue) { throw new ArgumentOutOfRangeException("timeout"); } return Wait((int)num, cancellationToken); } public bool Wait(int millisecondsTimeout) { return Wait(millisecondsTimeout, default(CancellationToken)); } public bool Wait(int millisecondsTimeout, CancellationToken cancellationToken) { if (millisecondsTimeout < -1) { throw new ArgumentOutOfRangeException("millisecondsTimeout"); } ThrowIfDisposed(); cancellationToken.ThrowIfCancellationRequested(); bool flag = IsSet; if (!flag) { flag = m_event.Wait(millisecondsTimeout, cancellationToken); } return flag; } private void ThrowIfDisposed() { if (m_disposed) { throw new ObjectDisposedException("CountdownEvent"); } } } [ComVisible(false)] [DebuggerDisplay("Set = {IsSet}")] [HostProtection(SecurityAction.LinkDemand, Synchronization = true, ExternalThreading = true)] public class ManualResetEventSlim : IDisposable { private const int DEFAULT_SPIN_SP = 1; private const int DEFAULT_SPIN_MP = 10; private const int SignalledState_BitMask = int.MinValue; private const int SignalledState_ShiftCount = 31; private const int Dispose_BitMask = 1073741824; private const int SpinCountState_BitMask = 1073217536; private const int SpinCountState_ShiftCount = 19; private const int SpinCountState_MaxValue = 2047; private const int NumWaitersState_BitMask = 524287; private const int NumWaitersState_ShiftCount = 0; private const int NumWaitersState_MaxValue = 524287; private object m_lock; private ManualResetEvent m_eventObj; private volatile int m_combinedState; private static Action<object> s_cancellationTokenCallback = CancellationTokenCallback; public WaitHandle WaitHandle { get { ThrowIfDisposed(); if (m_eventObj == null) { LazyInitializeEvent(); } return m_eventObj; } } public bool IsSet { get { return 0 != ExtractStatePortion(m_combinedState, int.MinValue); } private set { UpdateStateAtomically((value ? 1 : 0) << 31, int.MinValue); } } public int SpinCount { get { return ExtractStatePortionAndShiftRight(m_combinedState, 1073217536, 19); } private set { m_combinedState = (m_combinedState & -1073217537) | (value << 19); } } private int Waiter
plugins/Open.Nat.dll
Decompiled 2 years ago#define TRACE using System; using System.Collections.Generic; using System.Diagnostics; using System.Globalization; using System.IO; using System.Linq; using System.Net; using System.Net.NetworkInformation; using System.Net.Sockets; using System.Reflection; using System.Runtime.CompilerServices; using System.Runtime.InteropServices; using System.Runtime.Serialization; using System.Security.Permissions; using System.Text; using System.Threading; using System.Threading.Tasks; using System.Xml; [assembly: CompilationRelaxations(8)] [assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)] [assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)] [assembly: AssemblyTitle("Open.Nat")] [assembly: AssemblyDescription(".NET Library for automatic network address translation")] [assembly: AssemblyConfiguration("")] [assembly: AssemblyCompany("")] [assembly: AssemblyProduct("Open.Nat")] [assembly: AssemblyCopyright("Copyright Alan McGovern, Ben Motmans, Lucas Ontivero © 2006-2014")] [assembly: AssemblyTrademark("")] [assembly: ComVisible(false)] [assembly: Guid("c8e81e95-9f15-4eb8-8982-3d2c9cd95dee")] [assembly: AssemblyFileVersion("1.1.0.0")] [assembly: CLSCompliant(false)] [assembly: AssemblyVersion("1.0.0.0")] namespace Open.Nat; internal sealed class Finalizer { ~Finalizer() { NatDiscoverer.TraceSource.LogInfo("Closing ports opened in this session"); NatDiscoverer.RenewTimer.Dispose(); NatDiscoverer.ReleaseSessionMappings(); } } internal class Guard { private Guard() { } internal static void IsInRange(int paramValue, int lowerBound, int upperBound, string paramName) { if (paramValue < lowerBound || paramValue > upperBound) { throw new ArgumentOutOfRangeException(paramName); } } internal static void IsTrue(bool exp, string paramName) { if (!exp) { throw new ArgumentOutOfRangeException(paramName); } } internal static void IsNotNull(object obj, string paramName) { if (obj == null) { throw new ArgumentNullException(paramName); } } } public abstract class NatDevice { private readonly HashSet<Mapping> _openedMapping = new HashSet<Mapping>(); protected DateTime LastSeen { get; private set; } internal void Touch() { LastSeen = DateTime.Now; } public abstract Task CreatePortMapAsync(Mapping mapping); public abstract Task DeletePortMapAsync(Mapping mapping); public abstract Task<IEnumerable<Mapping>> GetAllMappingsAsync(); public abstract Task<IPAddress> GetExternalIPAsync(); public abstract Task<Mapping> GetSpecificMappingAsync(Protocol protocol, int port); protected void RegisterMapping(Mapping mapping) { _openedMapping.Remove(mapping); _openedMapping.Add(mapping); } protected void UnregisterMapping(Mapping mapping) { _openedMapping.RemoveWhere((Mapping x) => x.Equals(mapping)); } internal void ReleaseMapping(IEnumerable<Mapping> mappings) { int num = mappings.ToArray().Length; NatDiscoverer.TraceSource.LogInfo("{0} ports to close", num); for (int i = 0; i < num; i = checked(i + 1)) { Mapping mapping = _openedMapping.ElementAt(i); try { DeletePortMapAsync(mapping); NatDiscoverer.TraceSource.LogInfo(string.Concat(mapping, " port successfully closed")); } catch (Exception) { NatDiscoverer.TraceSource.LogError(string.Concat(mapping, " port couldn't be close")); } } } internal void ReleaseAll() { ReleaseMapping(_openedMapping); } internal void ReleaseSessionMappings() { IEnumerable<Mapping> mappings = _openedMapping.Where((Mapping m) => m.LifetimeType == MappingLifetime.Session); ReleaseMapping(mappings); } internal Task RenewMappings() { Task val = null; Mapping[] array = _openedMapping.Where((Mapping x) => x.ShoundRenew()).ToArray(); foreach (Mapping mapping in array) { Mapping i = mapping; val = ((val == null) ? RenewMapping(i) : TaskExtensions.Unwrap(val.ContinueWith<Task>((Func<Task, Task>)((Task t) => RenewMapping(i))))); } return val; } private Task RenewMapping(Mapping mapping) { Mapping renewMapping = new Mapping(mapping); renewMapping.Expiration = DateTime.UtcNow.AddSeconds(mapping.Lifetime); NatDiscoverer.TraceSource.LogInfo("Renewing mapping {0}", renewMapping); return CreatePortMapAsync(renewMapping).ContinueWith((Action<Task>)delegate(Task task) { if (task.IsFaulted) { NatDiscoverer.TraceSource.LogWarn("Renew {0} failed", mapping); } else { NatDiscoverer.TraceSource.LogInfo("Next renew scheduled at: {0}", renewMapping.Expiration.ToLocalTime().TimeOfDay); } }); } } public enum Protocol { Tcp, Udp } internal class DeviceEventArgs : EventArgs { public NatDevice Device { get; private set; } public DeviceEventArgs(NatDevice device) { Device = device; } } [Serializable] public class MappingException : Exception { public int ErrorCode { get; private set; } public string ErrorText { get; private set; } internal MappingException() { } internal MappingException(string message) : base(message) { } internal MappingException(int errorCode, string errorText) : base($"Error {errorCode}: {errorText}") { ErrorCode = errorCode; ErrorText = errorText; } internal MappingException(string message, Exception innerException) : base(message, innerException) { } protected MappingException(SerializationInfo info, StreamingContext context) : base(info, context) { } [SecurityPermission(SecurityAction.Demand, SerializationFormatter = true)] public override void GetObjectData(SerializationInfo info, StreamingContext context) { if (info == null) { throw new ArgumentNullException("info"); } ErrorCode = info.GetInt32("errorCode"); ErrorText = info.GetString("errorText"); base.GetObjectData(info, context); } } internal interface ISearcher { void Search(CancellationToken cancellationToken); IEnumerable<NatDevice> Receive(); NatDevice AnalyseReceivedResponse(IPAddress localAddress, byte[] response, IPEndPoint endpoint); } internal enum MappingLifetime { Permanent, Session, Manual, ForcedSession } public class Mapping { private DateTime _expiration; private int _lifetime; internal MappingLifetime LifetimeType { get; set; } public string Description { get; internal set; } public IPAddress PrivateIP { get; internal set; } public Protocol Protocol { get; internal set; } public int PrivatePort { get; internal set; } public IPAddress PublicIP { get; internal set; } public int PublicPort { get; internal set; } public int Lifetime { get { return _lifetime; } internal set { switch (value) { case int.MaxValue: LifetimeType = MappingLifetime.Session; _lifetime = 600; _expiration = DateTime.UtcNow.AddSeconds(_lifetime); break; case 0: LifetimeType = MappingLifetime.Permanent; _lifetime = 0; _expiration = DateTime.UtcNow; break; default: LifetimeType = MappingLifetime.Manual; _lifetime = value; _expiration = DateTime.UtcNow.AddSeconds(_lifetime); break; } } } public DateTime Expiration { get { return _expiration; } internal set { _expiration = value; _lifetime = checked((int)(_expiration - DateTime.UtcNow).TotalSeconds); } } internal Mapping(Protocol protocol, IPAddress privateIP, int privatePort, int publicPort) : this(protocol, privateIP, privatePort, publicPort, 0, "Open.Nat") { } public Mapping(Protocol protocol, IPAddress privateIP, int privatePort, int publicPort, int lifetime, string description) { Guard.IsInRange(privatePort, 0, 65535, "privatePort"); Guard.IsInRange(publicPort, 0, 65535, "publicPort"); Guard.IsInRange(lifetime, 0, int.MaxValue, "lifetime"); Guard.IsTrue(protocol == Protocol.Tcp || protocol == Protocol.Udp, "protocol"); Guard.IsNotNull(privateIP, "privateIP"); Protocol = protocol; PrivateIP = privateIP; PrivatePort = privatePort; PublicIP = IPAddress.None; PublicPort = publicPort; Lifetime = lifetime; Description = description; } public Mapping(Protocol protocol, int privatePort, int publicPort) : this(protocol, IPAddress.None, privatePort, publicPort, 0, "Open.NAT") { } public Mapping(Protocol protocol, int privatePort, int publicPort, string description) : this(protocol, IPAddress.None, privatePort, publicPort, int.MaxValue, description) { } public Mapping(Protocol protocol, int privatePort, int publicPort, int lifetime, string description) : this(protocol, IPAddress.None, privatePort, publicPort, lifetime, description) { } internal Mapping(Mapping mapping) { PrivateIP = mapping.PrivateIP; PrivatePort = mapping.PrivatePort; Protocol = mapping.Protocol; PublicIP = mapping.PublicIP; PublicPort = mapping.PublicPort; LifetimeType = mapping.LifetimeType; Description = mapping.Description; _lifetime = mapping._lifetime; _expiration = mapping._expiration; } public bool IsExpired() { if (LifetimeType != 0 && LifetimeType != MappingLifetime.ForcedSession) { return Expiration < DateTime.UtcNow; } return false; } internal bool ShoundRenew() { if (LifetimeType == MappingLifetime.Session) { return IsExpired(); } return false; } public override bool Equals(object obj) { if (obj == null) { return false; } if (this == obj) { return true; } if (!(obj is Mapping mapping)) { return false; } if (PublicPort == mapping.PublicPort) { return PrivatePort == mapping.PrivatePort; } return false; } public override int GetHashCode() { return (((PublicPort * 397) ^ ((PrivateIP != null) ? PrivateIP.GetHashCode() : 0)) * 397) ^ PrivatePort; } public override string ToString() { return string.Format("{0} {1} --> {2}:{3} ({4})", (Protocol == Protocol.Tcp) ? "Tcp" : "Udp", PublicPort, PrivateIP, PrivatePort, Description); } } [Serializable] public class NatDeviceNotFoundException : Exception { public NatDeviceNotFoundException() { } public NatDeviceNotFoundException(string message) : base(message) { } public NatDeviceNotFoundException(string message, Exception innerException) : base(message, innerException) { } protected NatDeviceNotFoundException(SerializationInfo info, StreamingContext context) : base(info, context) { } } public class NatDiscoverer { public static readonly TraceSource TraceSource = new TraceSource("Open.NAT"); private static readonly Dictionary<string, NatDevice> Devices = new Dictionary<string, NatDevice>(); private static readonly Finalizer Finalizer = new Finalizer(); internal static readonly Timer RenewTimer = new Timer(RenewMappings, null, 5000, 2000); public Task<NatDevice> DiscoverDeviceAsync() { //IL_0000: Unknown result type (might be due to invalid IL or missing references) //IL_0006: Expected O, but got Unknown CancellationTokenSource val = new CancellationTokenSource(); val.CancelAfter(3000); return DiscoverDeviceAsync(PortMapper.Pmp | PortMapper.Upnp, val); } public Task<NatDevice> DiscoverDeviceAsync(PortMapper portMapper, CancellationTokenSource cancellationTokenSource) { Guard.IsTrue(EnumExtension.HasFlag(portMapper, PortMapper.Upnp) || EnumExtension.HasFlag(portMapper, PortMapper.Pmp), "portMapper"); Guard.IsNotNull(cancellationTokenSource, "cancellationTokenSource"); return DiscoverAsync(portMapper, onlyOne: true, cancellationTokenSource).ContinueWith<NatDevice>((Func<Task<IEnumerable<NatDevice>>, NatDevice>)delegate(Task<IEnumerable<NatDevice>> task) { NatDevice natDevice = task.Result.FirstOrDefault(); if (natDevice == null) { TraceSource.LogInfo("Device not found. Common reasons:"); TraceSource.LogInfo("\t* No device is present or,"); TraceSource.LogInfo("\t* Upnp is disabled in the router or"); TraceSource.LogInfo("\t* Antivirus software is filtering SSDP (discovery protocol)."); throw new NatDeviceNotFoundException(); } return natDevice; }); } public Task<IEnumerable<NatDevice>> DiscoverDevicesAsync(PortMapper portMapper, CancellationTokenSource cancellationTokenSource) { Guard.IsTrue(EnumExtension.HasFlag(portMapper, PortMapper.Upnp) || EnumExtension.HasFlag(portMapper, PortMapper.Pmp), "portMapper"); Guard.IsNotNull(cancellationTokenSource, "cancellationTokenSource"); return DiscoverAsync(portMapper, onlyOne: false, cancellationTokenSource).ContinueWith<IEnumerable<NatDevice>>((Func<Task<IEnumerable<NatDevice>>, IEnumerable<NatDevice>>)((Task<IEnumerable<NatDevice>> t) => t.Result.ToArray())); } private Task<IEnumerable<NatDevice>> DiscoverAsync(PortMapper portMapper, bool onlyOne, CancellationTokenSource cts) { //IL_0081: Unknown result type (might be due to invalid IL or missing references) //IL_00dd: Unknown result type (might be due to invalid IL or missing references) TraceSource.LogInfo("Start Discovery"); List<Task<IEnumerable<NatDevice>>> searcherTasks = new List<Task<IEnumerable<NatDevice>>>(); if (EnumExtension.HasFlag(portMapper, PortMapper.Upnp)) { UpnpSearcher upnpSearcher = new UpnpSearcher(new IPAddressesProvider()); upnpSearcher.DeviceFound = (EventHandler<DeviceEventArgs>)Delegate.Combine(upnpSearcher.DeviceFound, (EventHandler<DeviceEventArgs>)delegate { if (onlyOne) { cts.Cancel(); } }); searcherTasks.Add(upnpSearcher.Search(cts.Token)); } if (EnumExtension.HasFlag(portMapper, PortMapper.Pmp)) { PmpSearcher pmpSearcher = new PmpSearcher(new IPAddressesProvider()); pmpSearcher.DeviceFound = (EventHandler<DeviceEventArgs>)Delegate.Combine(pmpSearcher.DeviceFound, (EventHandler<DeviceEventArgs>)delegate { if (onlyOne) { cts.Cancel(); } }); searcherTasks.Add(pmpSearcher.Search(cts.Token)); } return TaskExtension.WhenAll((Task[])(object)searcherTasks.ToArray()).ContinueWith<IEnumerable<NatDevice>>((Func<Task, IEnumerable<NatDevice>>)delegate { TraceSource.LogInfo("Stop Discovery"); IEnumerable<NatDevice> enumerable = searcherTasks.SelectMany((Task<IEnumerable<NatDevice>> x) => x.Result); foreach (NatDevice item in enumerable) { string key = item.ToString(); if (Devices.TryGetValue(key, out var value)) { value.Touch(); } else { Devices.Add(key, item); } } return enumerable; }); } public static void ReleaseAll() { foreach (NatDevice value in Devices.Values) { value.ReleaseAll(); } } internal static void ReleaseSessionMappings() { foreach (NatDevice value in Devices.Values) { value.ReleaseSessionMappings(); } } private static void RenewMappings(object state) { Task.Factory.StartNew((Action)delegate { Task val = null; foreach (NatDevice value in Devices.Values) { NatDevice d = value; val = (Task)((val == null) ? ((object)value.RenewMappings()) : ((object)val.ContinueWith<Task>((Func<Task, Task>)((Task t) => d.RenewMappings())))); } }); } } internal class PmpSearcher : Searcher { private readonly IIPAddressesProvider _ipprovider; private Dictionary<UdpClient, IEnumerable<IPEndPoint>> _gatewayLists; private int _timeout; internal PmpSearcher(IIPAddressesProvider ipprovider) { _ipprovider = ipprovider; _timeout = 250; CreateSocketsAndAddGateways(); } private void CreateSocketsAndAddGateways() { Sockets = new List<UdpClient>(); _gatewayLists = new Dictionary<UdpClient, IEnumerable<IPEndPoint>>(); try { List<IPEndPoint> list = (from ip in _ipprovider.GatewayAddresses() select new IPEndPoint(ip, 5351)).ToList(); if (!list.Any()) { list.AddRange(from ip in _ipprovider.DnsAddresses() select new IPEndPoint(ip, 5351)); } if (!list.Any()) { return; } foreach (IPAddress item in _ipprovider.UnicastAddresses()) { UdpClient udpClient; try { udpClient = new UdpClient(new IPEndPoint(item, 0)); } catch (SocketException) { continue; } _gatewayLists.Add(udpClient, list); Sockets.Add(udpClient); } } catch (Exception ex2) { NatDiscoverer.TraceSource.LogError("There was a problem finding gateways: " + ex2); } } protected override void Discover(UdpClient client, CancellationToken cancelationToken) { NextSearch = DateTime.UtcNow.AddMilliseconds(_timeout); checked { _timeout *= 2; if (_timeout >= 3000) { _timeout = 250; NextSearch = DateTime.UtcNow.AddSeconds(10.0); return; } byte[] array = new byte[2]; foreach (IPEndPoint item in _gatewayLists[client]) { if (((CancellationToken)(ref cancelationToken)).IsCancellationRequested) { break; } client.Send(array, array.Length, item); } } } private bool IsSearchAddress(IPAddress address) { return _gatewayLists.Values.SelectMany((IEnumerable<IPEndPoint> x) => x).Any((IPEndPoint x) => x.Address.Equals(address)); } public override NatDevice AnalyseReceivedResponse(IPAddress localAddress, byte[] response, IPEndPoint endpoint) { if (!IsSearchAddress(endpoint.Address) || response.Length != 12 || response[0] != 0 || response[1] != 128) { return null; } int num = IPAddress.NetworkToHostOrder(BitConverter.ToInt16(response, 2)); if (num != 0) { NatDiscoverer.TraceSource.LogError("Non zero error: {0}", num); } IPAddress publicAddress = new IPAddress(new byte[4] { response[8], response[9], response[10], response[11] }); _timeout = 250; return new PmpNatDevice(endpoint.Address, publicAddress); } } internal static class PmpConstants { public const byte Version = 0; public const byte OperationExternalAddressRequest = 0; public const byte OperationCodeUdp = 1; public const byte OperationCodeTcp = 2; public const byte ServerNoop = 128; public const int ClientPort = 5350; public const int ServerPort = 5351; public const int RetryDelay = 250; public const int RetryAttempts = 9; public const int RecommendedLeaseTime = 3600; public const int DefaultLeaseTime = 3600; public const short ResultCodeSuccess = 0; public const short ResultCodeUnsupportedVersion = 1; public const short ResultCodeNotAuthorized = 2; public const short ResultCodeNetworkFailure = 3; public const short ResultCodeOutOfResources = 4; public const short ResultCodeUnsupportedOperationCode = 5; } internal sealed class PmpNatDevice : NatDevice { private readonly IPAddress _publicAddress; internal IPAddress LocalAddress { get; private set; } internal PmpNatDevice(IPAddress localAddress, IPAddress publicAddress) { LocalAddress = localAddress; _publicAddress = publicAddress; } public override Task CreatePortMapAsync(Mapping mapping) { return InternalCreatePortMapAsync(mapping, create: true).TimeoutAfter<Mapping>(TimeSpan.FromSeconds(4.0)).ContinueWith((Action<Task<Mapping>>)delegate { RegisterMapping(mapping); }); } public override Task DeletePortMapAsync(Mapping mapping) { return InternalCreatePortMapAsync(mapping, create: false).TimeoutAfter<Mapping>(TimeSpan.FromSeconds(4.0)).ContinueWith((Action<Task<Mapping>>)delegate { UnregisterMapping(mapping); }); } public override Task<IEnumerable<Mapping>> GetAllMappingsAsync() { throw new NotSupportedException(); } public override Task<IPAddress> GetExternalIPAsync() { return Task.Factory.StartNew<IPAddress>((Func<IPAddress>)(() => _publicAddress)).TimeoutAfter<IPAddress>(TimeSpan.FromSeconds(4.0)); } public override Task<Mapping> GetSpecificMappingAsync(Protocol protocol, int port) { throw new NotSupportedException("NAT-PMP does not specify a way to get a specific port map"); } private Task<Mapping> InternalCreatePortMapAsync(Mapping mapping, bool create) { List<byte> list = new List<byte>(); list.Add(0); list.Add((byte)((mapping.Protocol != 0) ? 1 : 2)); list.Add(0); list.Add(0); list.AddRange(BitConverter.GetBytes(IPAddress.HostToNetworkOrder(checked((short)mapping.PrivatePort)))); list.AddRange(BitConverter.GetBytes((short)(create ? IPAddress.HostToNetworkOrder(checked((short)mapping.PublicPort)) : 0))); list.AddRange(BitConverter.GetBytes(IPAddress.HostToNetworkOrder(mapping.Lifetime))); byte[] buffer = list.ToArray(); int num = 0; int num2 = 250; UdpClient udpClient = new UdpClient(); CreatePortMapListen(udpClient, mapping); Task val = (Task)(object)Task.Factory.FromAsync<byte[], int, IPEndPoint, int>((Func_<byte[], int, IPEndPoint, AsyncCallback, object, IAsyncResult>)udpClient.BeginSend, (Func<IAsyncResult, int>)udpClient.EndSend, buffer, buffer.Length, new IPEndPoint(LocalAddress, 5351), (object)null); checked { while (num < 8) { val = (Task)(object)TaskExtensions.Unwrap<int>(val.ContinueWith<Task<int>>((Func<Task, Task<int>>)delegate(Task t) { if (t.IsFaulted) { string arg = (create ? "create" : "delete"); string text = $"Failed to {arg} portmap (protocol={mapping.Protocol}, private port={mapping.PrivatePort})"; NatDiscoverer.TraceSource.LogError(text); throw new MappingException(text, (Exception)(object)t.Exception); } return Task.Factory.FromAsync<byte[], int, IPEndPoint, int>((Func_<byte[], int, IPEndPoint, AsyncCallback, object, IAsyncResult>)udpClient.BeginSend, (Func<IAsyncResult, int>)udpClient.EndSend, buffer, buffer.Length, new IPEndPoint(LocalAddress, 5351), (object)null); })); num++; num2 *= 2; Thread.Sleep(num2); } return val.ContinueWith<Mapping>((Func<Task, Mapping>)delegate { udpClient.Close(); return mapping; }); } } private void CreatePortMapListen(UdpClient udpClient, Mapping mapping) { IPEndPoint remoteEP = new IPEndPoint(LocalAddress, 5351); byte[] array; do { array = udpClient.Receive(ref remoteEP); } while (array.Length < 16 || array[0] != 0); checked { byte num = (byte)(array[1] & 0x7F); Protocol protocol = Protocol.Tcp; if (num == 1) { protocol = Protocol.Udp; } short num2 = IPAddress.NetworkToHostOrder(BitConverter.ToInt16(array, 2)); IPAddress.NetworkToHostOrder(BitConverter.ToInt32(array, 4)); short num3 = IPAddress.NetworkToHostOrder(BitConverter.ToInt16(array, 8)); short num4 = IPAddress.NetworkToHostOrder(BitConverter.ToInt16(array, 10)); uint num5 = (uint)IPAddress.NetworkToHostOrder(BitConverter.ToInt32(array, 12)); if (num3 < 0 || num4 < 0 || num2 != 0) { string[] array2 = new string[6] { "Success", "Unsupported Version", "Not Authorized/Refused (e.g. box supports mapping, but user has turned feature off)", "Network Failure (e.g. NAT box itself has not obtained a DHCP lease)", "Out of resources (NAT box cannot create any more mappings at this time)", "Unsupported opcode" }; throw new MappingException(num2, array2[num2]); } if (num5 != 0) { mapping.PublicPort = num4; mapping.Protocol = protocol; mapping.Expiration = DateTime.Now.AddSeconds(num5); } } } public override string ToString() { return $"Local Address: {LocalAddress}\nPublic IP: {_publicAddress}\nLast Seen: {base.LastSeen}"; } } [Flags] public enum PortMapper { Pmp = 1, Upnp = 2 } internal abstract class Searcher { private readonly List<NatDevice> _devices = new List<NatDevice>(); protected List<UdpClient> Sockets; public EventHandler<DeviceEventArgs> DeviceFound; internal DateTime NextSearch = DateTime.UtcNow; public Task<IEnumerable<NatDevice>> Search(CancellationToken cancelationToken) { //IL_000e: Unknown result type (might be due to invalid IL or missing references) //IL_000f: Unknown result type (might be due to invalid IL or missing references) //IL_0026: Unknown result type (might be due to invalid IL or missing references) return Task.Factory.StartNew((Action<object>)delegate { //IL_0031: Unknown result type (might be due to invalid IL or missing references) //IL_0042: Unknown result type (might be due to invalid IL or missing references) NatDiscoverer.TraceSource.LogInfo("Searching for: {0}", GetType().Name); while (!((CancellationToken)(ref cancelationToken)).IsCancellationRequested) { Discover(cancelationToken); Receive(cancelationToken); } CloseSockets(); }, (object)cancelationToken).ContinueWith<IEnumerable<NatDevice>>((Func<Task, IEnumerable<NatDevice>>)((Task task) => _devices)); } private void Discover(CancellationToken cancelationToken) { //IL_002b: Unknown result type (might be due to invalid IL or missing references) if (DateTime.UtcNow < NextSearch) { return; } foreach (UdpClient socket in Sockets) { try { Discover(socket, cancelationToken); } catch (Exception ex) { NatDiscoverer.TraceSource.LogError("Error searching {0} - Details:", GetType().Name); NatDiscoverer.TraceSource.LogError(ex.ToString()); } } } private void Receive(CancellationToken cancelationToken) { foreach (UdpClient item in Sockets.Where((UdpClient x) => x.Available > 0)) { if (((CancellationToken)(ref cancelationToken)).IsCancellationRequested) { break; } IPAddress address = ((IPEndPoint)item.Client.LocalEndPoint).Address; IPEndPoint remoteEP = new IPEndPoint(IPAddress.None, 0); byte[] response = item.Receive(ref remoteEP); NatDevice natDevice = AnalyseReceivedResponse(address, response, remoteEP); if (natDevice != null) { RaiseDeviceFound(natDevice); } } } protected abstract void Discover(UdpClient client, CancellationToken cancelationToken); public abstract NatDevice AnalyseReceivedResponse(IPAddress localAddress, byte[] response, IPEndPoint endpoint); public void CloseSockets() { foreach (UdpClient socket in Sockets) { socket.Close(); } } private void RaiseDeviceFound(NatDevice device) { _devices.Add(device); DeviceFound?.Invoke(this, new DeviceEventArgs(device)); } } internal class UpnpSearcher : Searcher { private readonly IIPAddressesProvider _ipprovider; private readonly IDictionary<Uri, NatDevice> _devices; private readonly Dictionary<IPAddress, DateTime> _lastFetched; private static readonly string[] ServiceTypes = new string[4] { "WANIPConnection:2", "WANPPPConnection:2", "WANIPConnection:1", "WANPPPConnection:1" }; internal UpnpSearcher(IIPAddressesProvider ipprovider) { _ipprovider = ipprovider; Sockets = CreateSockets(); _devices = new Dictionary<Uri, NatDevice>(); _lastFetched = new Dictionary<IPAddress, DateTime>(); } private List<UdpClient> CreateSockets() { List<UdpClient> list = new List<UdpClient>(); try { foreach (IPAddress item in _ipprovider.UnicastAddresses()) { try { list.Add(new UdpClient(new IPEndPoint(item, 0))); } catch (Exception) { } } } catch (Exception) { list.Add(new UdpClient(0)); } return list; } protected override void Discover(UdpClient client, CancellationToken cancelationToken) { NextSearch = DateTime.UtcNow.AddSeconds(1.0); IPEndPoint endPoint = new IPEndPoint(WellKnownConstants.IPv4MulticastAddress, 1900); string[] serviceTypes = ServiceTypes; for (int i = 0; i < serviceTypes.Length; i++) { string s = DiscoverDeviceMessage.Encode(serviceTypes[i]); byte[] bytes = Encoding.ASCII.GetBytes(s); for (int j = 0; j < 2; j = checked(j + 1)) { if (((CancellationToken)(ref cancelationToken)).IsCancellationRequested) { return; } client.Send(bytes, bytes.Length, endPoint); } } } public override NatDevice AnalyseReceivedResponse(IPAddress localAddress, byte[] response, IPEndPoint endpoint) { string text = null; try { text = Encoding.UTF8.GetString(response); DiscoveryResponseMessage discoveryResponseMessage = new DiscoveryResponseMessage(text); string text2 = discoveryResponseMessage["ST"]; if (!IsValidControllerService(text2)) { NatDiscoverer.TraceSource.LogWarn("Invalid controller service. Ignoring."); return null; } NatDiscoverer.TraceSource.LogInfo("UPnP Response: Router advertised a '{0}' service!!!", text2); Uri uri = new Uri(discoveryResponseMessage["Location"] ?? discoveryResponseMessage["AL"]); NatDiscoverer.TraceSource.LogInfo("Found device at: {0}", uri.ToString()); if (_devices.ContainsKey(uri)) { NatDiscoverer.TraceSource.LogInfo("Already found - Ignored"); _devices[uri].Touch(); return null; } if (_lastFetched.ContainsKey(endpoint.Address)) { DateTime dateTime = _lastFetched[endpoint.Address]; if (DateTime.Now - dateTime < TimeSpan.FromSeconds(20.0)) { return null; } } _lastFetched[endpoint.Address] = DateTime.Now; NatDiscoverer.TraceSource.LogInfo("{0}:{1}: Fetching service list", uri.Host, uri.Port); UpnpNatDeviceInfo deviceInfo = BuildUpnpNatDeviceInfo(localAddress, uri); UpnpNatDevice upnpNatDevice; lock (_devices) { upnpNatDevice = new UpnpNatDevice(deviceInfo); if (!_devices.ContainsKey(uri)) { _devices.Add(uri, upnpNatDevice); } } return upnpNatDevice; } catch (Exception ex) { NatDiscoverer.TraceSource.LogError("Unhandled exception when trying to decode a device's response. "); NatDiscoverer.TraceSource.LogError("Report the issue in https://github.com/lontivero/Open.Nat/issues"); NatDiscoverer.TraceSource.LogError("Also copy and paste the following info:"); NatDiscoverer.TraceSource.LogError("-- beging ---------------------------------"); NatDiscoverer.TraceSource.LogError(ex.Message); NatDiscoverer.TraceSource.LogError("Data string:"); NatDiscoverer.TraceSource.LogError(text ?? "No data available"); NatDiscoverer.TraceSource.LogError("-- end ------------------------------------"); } return null; } private static bool IsValidControllerService(string serviceType) { return (from serviceName in ServiceTypes let serviceUrn = $"urn:schemas-upnp-org:service:{serviceName}" where serviceType.ContainsIgnoreCase(serviceUrn) select new { ServiceName = serviceName, ServiceUrn = serviceUrn }).Any(); } private UpnpNatDeviceInfo BuildUpnpNatDeviceInfo(IPAddress localAddress, Uri location) { NatDiscoverer.TraceSource.LogInfo("Found device at: {0}", location.ToString()); IPEndPoint iPEndPoint = new IPEndPoint(IPAddress.Parse(location.Host), location.Port); WebResponse webResponse = null; try { WebRequest webRequest = WebRequest.Create(location); webRequest.Headers.Add("ACCEPT-LANGUAGE", "en"); webRequest.Method = "GET"; webResponse = webRequest.GetResponse(); if (webResponse is HttpWebResponse httpWebResponse && httpWebResponse.StatusCode != HttpStatusCode.OK) { throw new Exception($"Couldn't get services list: {httpWebResponse.StatusCode} {httpWebResponse.StatusDescription}"); } XmlDocument xmlDocument = ReadXmlResponse(webResponse); NatDiscoverer.TraceSource.LogInfo("{0}: Parsed services list", iPEndPoint); XmlNamespaceManager xmlNamespaceManager = new XmlNamespaceManager(xmlDocument.NameTable); xmlNamespaceManager.AddNamespace("ns", "urn:schemas-upnp-org:device-1-0"); foreach (XmlNode item in xmlDocument.SelectNodes("//ns:service", xmlNamespaceManager)) { string xmlElementText = item.GetXmlElementText("serviceType"); if (IsValidControllerService(xmlElementText)) { NatDiscoverer.TraceSource.LogInfo("{0}: Found service: {1}", iPEndPoint, xmlElementText); string xmlElementText2 = item.GetXmlElementText("controlURL"); NatDiscoverer.TraceSource.LogInfo("{0}: Found upnp service at: {1}", iPEndPoint, xmlElementText2); NatDiscoverer.TraceSource.LogInfo("{0}: Handshake Complete", iPEndPoint); return new UpnpNatDeviceInfo(localAddress, location, xmlElementText2, xmlElementText); } } throw new Exception("No valid control service was found in the service descriptor document"); } catch (WebException ex) { NatDiscoverer.TraceSource.LogError("{0}: Device denied the connection attempt: {1}", iPEndPoint, ex); if (ex.InnerException is SocketException ex2) { NatDiscoverer.TraceSource.LogError("{0}: ErrorCode:{1}", iPEndPoint, ex2.ErrorCode); NatDiscoverer.TraceSource.LogError("Go to http://msdn.microsoft.com/en-us/library/system.net.sockets.socketerror.aspx"); NatDiscoverer.TraceSource.LogError("Usually this happens. Try resetting the device and try again. If you are in a VPN, disconnect and try again."); } throw; } finally { webResponse?.Close(); } } private static XmlDocument ReadXmlResponse(WebResponse response) { using StreamReader streamReader = new StreamReader(response.GetResponseStream(), Encoding.UTF8); string xml = streamReader.ReadToEnd(); XmlDocument xmlDocument = new XmlDocument(); xmlDocument.LoadXml(xml); return xmlDocument; } } internal class DiscoveryResponseMessage { private readonly IDictionary<string, string> _headers; public string this[string key] => _headers[key.ToUpperInvariant()]; public DiscoveryResponseMessage(string message) { var source = from h in message.Split(new string[1] { "\r\n" }, StringSplitOptions.RemoveEmptyEntries).Skip(1) let c = h.Split(new char[1] { ':' }) let key = c[0] let value = (c.Length > 1) ? string.Join(":", c.Skip(1).ToArray()) : string.Empty select new { Key = key, Value = value.Trim() }; _headers = source.ToDictionary(x => x.Key.ToUpperInvariant(), x => x.Value); } } internal static class DiscoverDeviceMessage { public static string Encode(string serviceType) { return string.Format(CultureInfo.InvariantCulture, "M-SEARCH * HTTP/1.1\r\nHOST: 239.255.255.250:1900\r\nMAN: \"ssdp:discover\"\r\nMX: 3\r\nST: urn:schemas-upnp-org:service:{0}\r\n\r\n", new object[1] { serviceType }); } } internal class CreatePortMappingRequestMessage : RequestMessageBase { private readonly Mapping _mapping; public CreatePortMappingRequestMessage(Mapping mapping) { _mapping = mapping; } public override IDictionary<string, object> ToXml() { string value = (_mapping.PublicIP.Equals(IPAddress.None) ? string.Empty : _mapping.PublicIP.ToString()); return new Dictionary<string, object> { { "NewRemoteHost", value }, { "NewExternalPort", _mapping.PublicPort }, { "NewProtocol", (_mapping.Protocol == Protocol.Tcp) ? "TCP" : "UDP" }, { "NewInternalPort", _mapping.PrivatePort }, { "NewInternalClient", _mapping.PrivateIP }, { "NewEnabled", 1 }, { "NewPortMappingDescription", _mapping.Description }, { "NewLeaseDuration", _mapping.Lifetime } }; } } internal class DeletePortMappingRequestMessage : RequestMessageBase { private readonly Mapping _mapping; public DeletePortMappingRequestMessage(Mapping mapping) { _mapping = mapping; } public override IDictionary<string, object> ToXml() { return new Dictionary<string, object> { { "NewRemoteHost", string.Empty }, { "NewExternalPort", _mapping.PublicPort }, { "NewProtocol", (_mapping.Protocol == Protocol.Tcp) ? "TCP" : "UDP" } }; } } internal class GetExternalIPAddressRequestMessage : RequestMessageBase { public override IDictionary<string, object> ToXml() { return new Dictionary<string, object>(); } } internal class GetGenericPortMappingEntry : RequestMessageBase { private readonly int _index; public GetGenericPortMappingEntry(int index) { _index = index; } public override IDictionary<string, object> ToXml() { return new Dictionary<string, object> { { "NewPortMappingIndex", _index } }; } } internal class GetSpecificPortMappingEntryRequestMessage : RequestMessageBase { private readonly int _externalPort; private readonly Protocol _protocol; public GetSpecificPortMappingEntryRequestMessage(Protocol protocol, int externalPort) { _protocol = protocol; _externalPort = externalPort; } public override IDictionary<string, object> ToXml() { return new Dictionary<string, object> { { "NewRemoteHost", string.Empty }, { "NewExternalPort", _externalPort }, { "NewProtocol", (_protocol == Protocol.Tcp) ? "TCP" : "UDP" } }; } } internal abstract class ResponseMessageBase { private readonly XmlDocument _document; protected string ServiceType; private readonly string _typeName; protected ResponseMessageBase(XmlDocument response, string serviceType, string typeName) { _document = response; ServiceType = serviceType; _typeName = typeName; } protected XmlNode GetNode() { XmlNamespaceManager xmlNamespaceManager = new XmlNamespaceManager(_document.NameTable); xmlNamespaceManager.AddNamespace("responseNs", ServiceType); string typeName = _typeName; string text = typeName.Substring(0, checked(typeName.Length - "Message".Length)); return _document.SelectSingleNode("//responseNs:" + text, xmlNamespaceManager) ?? throw new InvalidOperationException("The response is invalid: " + text); } } internal class GetExternalIPAddressResponseMessage : ResponseMessageBase { public IPAddress ExternalIPAddress { get; private set; } public GetExternalIPAddressResponseMessage(XmlDocument response, string serviceType) : base(response, serviceType, "GetExternalIPAddressResponseMessage") { string xmlElementText = GetNode().GetXmlElementText("NewExternalIPAddress"); ExternalIPAddress = IPAddress.Parse(xmlElementText); } } internal class GetPortMappingEntryResponseMessage : ResponseMessageBase { public string RemoteHost { get; private set; } public int ExternalPort { get; private set; } public Protocol Protocol { get; private set; } public int InternalPort { get; private set; } public string InternalClient { get; private set; } public bool Enabled { get; private set; } public string PortMappingDescription { get; private set; } public int LeaseDuration { get; private set; } internal GetPortMappingEntryResponseMessage(XmlDocument response, string serviceType, bool genericMapping) : base(response, serviceType, genericMapping ? "GetGenericPortMappingEntryResponseMessage" : "GetSpecificPortMappingEntryResponseMessage") { XmlNode node = GetNode(); RemoteHost = (genericMapping ? node.GetXmlElementText("NewRemoteHost") : string.Empty); ExternalPort = (genericMapping ? Convert.ToInt32(node.GetXmlElementText("NewExternalPort")) : 65535); if (genericMapping) { Protocol = ((!node.GetXmlElementText("NewProtocol").Equals("TCP", StringComparison.InvariantCultureIgnoreCase)) ? Protocol.Udp : Protocol.Tcp); } else { Protocol = Protocol.Udp; } InternalPort = Convert.ToInt32(node.GetXmlElementText("NewInternalPort")); InternalClient = node.GetXmlElementText("NewInternalClient"); Enabled = node.GetXmlElementText("NewEnabled") == "1"; PortMappingDescription = node.GetXmlElementText("NewPortMappingDescription"); LeaseDuration = Convert.ToInt32(node.GetXmlElementText("NewLeaseDuration")); } } internal abstract class RequestMessageBase { public abstract IDictionary<string, object> ToXml(); } internal class SoapClient { private readonly string _serviceType; private readonly Uri _url; public SoapClient(Uri url, string serviceType) { _url = url; _serviceType = serviceType; } public Task<XmlDocument> InvokeAsync(string operationName, IDictionary<string, object> args) { NatDiscoverer.TraceSource.TraceEvent(TraceEventType.Verbose, 0, "SOAPACTION: **{0}** url:{1}", operationName, _url); byte[] messageBody = BuildMessageBody(operationName, args); HttpWebRequest request = BuildHttpWebRequest(operationName, messageBody); Task<WebResponse> val; if (messageBody.Length != 0) { Stream requestStream = null; val = TaskExtensions.Unwrap<WebResponse>(TaskExtensions.Unwrap(Task.Factory.FromAsync<Stream>((Func<AsyncCallback, object, IAsyncResult>)request.BeginGetRequestStream, (Func<IAsyncResult, Stream>)request.EndGetRequestStream, (object)null).ContinueWith<Task>((Func<Task<Stream>, Task>)delegate(Task<Stream> requestSteamTask) { requestStream = requestSteamTask.Result; TaskFactory factory = Task.Factory; Stream stream = requestStream; return factory.FromAsync<byte[], int, int>((Func_<byte[], int, int, AsyncCallback, object, IAsyncResult>)stream.BeginWrite, (Action<IAsyncResult>)requestStream.EndWrite, messageBody, 0, messageBody.Length, (object)null); })).ContinueWith<Task<WebResponse>>((Func<Task, Task<WebResponse>>)delegate { requestStream.Close(); return GetWebResponse(request); })); } else { val = GetWebResponse(request); } return val.ContinueWith<XmlDocument>((Func<Task<WebResponse>, XmlDocument>)delegate(Task<WebResponse> task) { using WebResponse webResponse = task.Result; Stream responseStream = webResponse.GetResponseStream(); long contentLength = webResponse.ContentLength; StreamReader streamReader = new StreamReader(responseStream, Encoding.UTF8); string response = ((contentLength != -1) ? streamReader.ReadAsMany(checked((int)contentLength)) : streamReader.ReadToEnd()); XmlDocument xmlDocument = GetXmlDocument(response); webResponse.Close(); return xmlDocument; }); } private static Task<WebResponse> GetWebResponse(WebRequest request) { return Task.Factory.FromAsync<WebResponse>((Func<AsyncCallback, object, IAsyncResult>)request.BeginGetResponse, (Func<IAsyncResult, WebResponse>)request.EndGetResponse, (object)null).ContinueWith<WebResponse>((Func<Task<WebResponse>, WebResponse>)delegate(Task<WebResponse> task) { WebResponse webResponse; if (!((Task)task).IsFaulted) { webResponse = task.Result; } else { if (!(((Exception)(object)((Task)task).Exception).InnerException is WebException ex)) { throw ((Task)task).Exception; } NatDiscoverer.TraceSource.TraceEvent(TraceEventType.Verbose, 0, "WebException status: {0}", ex.Status); webResponse = ex.Response as HttpWebResponse; if (webResponse == null) { throw ((Task)task).Exception; } } return webResponse; }); } private HttpWebRequest BuildHttpWebRequest(string operationName, byte[] messageBody) { HttpWebRequest httpWebRequest = (HttpWebRequest)WebRequest.Create(_url); httpWebRequest.KeepAlive = false; httpWebRequest.Method = "POST"; httpWebRequest.ContentType = "text/xml; charset=\"utf-8\""; httpWebRequest.Headers.Add("SOAPACTION", "\"" + _serviceType + "#" + operationName + "\""); httpWebRequest.ContentLength = messageBody.Length; return httpWebRequest; } private byte[] BuildMessageBody(string operationName, IEnumerable<KeyValuePair<string, object>> args) { StringBuilder stringBuilder = new StringBuilder(); stringBuilder.AppendLine("<s:Envelope "); stringBuilder.AppendLine(" xmlns:s=\"http://schemas.xmlsoap.org/soap/envelope/\" "); stringBuilder.AppendLine(" s:encodingStyle=\"http://schemas.xmlsoap.org/soap/encoding/\">"); stringBuilder.AppendLine(" <s:Body>"); stringBuilder.AppendLine("\t <u:" + operationName + " xmlns:u=\"" + _serviceType + "\">"); foreach (KeyValuePair<string, object> arg in args) { stringBuilder.AppendLine("\t\t <" + arg.Key + ">" + Convert.ToString(arg.Value, CultureInfo.InvariantCulture) + "</" + arg.Key + ">"); } stringBuilder.AppendLine("\t </u:" + operationName + ">"); stringBuilder.AppendLine(" </s:Body>"); stringBuilder.Append("</s:Envelope>\r\n\r\n"); string s = stringBuilder.ToString(); return Encoding.UTF8.GetBytes(s); } private XmlDocument GetXmlDocument(string response) { XmlDocument xmlDocument = new XmlDocument(); xmlDocument.LoadXml(response); XmlNamespaceManager xmlNamespaceManager = new XmlNamespaceManager(xmlDocument.NameTable); xmlNamespaceManager.AddNamespace("errorNs", "urn:schemas-upnp-org:control-1-0"); XmlNode node; if ((node = xmlDocument.SelectSingleNode("//errorNs:UPnPError", xmlNamespaceManager)) != null) { int num = Convert.ToInt32(node.GetXmlElementText("errorCode"), CultureInfo.InvariantCulture); string xmlElementText = node.GetXmlElementText("errorDescription"); NatDiscoverer.TraceSource.LogWarn("Server failed with error: {0} - {1}", num, xmlElementText); throw new MappingException(num, xmlElementText); } return xmlDocument; } } internal static class UpnpConstants { public const int InvalidArguments = 402; public const int ActionFailed = 501; public const int Unathorized = 606; public const int SpecifiedArrayIndexInvalid = 713; public const int NoSuchEntryInArray = 714; public const int WildCardNotPermittedInSourceIp = 715; public const int WildCardNotPermittedInExternalPort = 716; public const int ConflictInMappingEntry = 718; public const int SamePortValuesRequired = 724; public const int OnlyPermanentLeasesSupported = 725; public const int RemoteHostOnlySupportsWildcard = 726; public const int ExternalPortOnlySupportsWildcard = 727; public const int NoPortMapsAvailable = 728; public const int ConflictWithOtherMechanisms = 729; public const int WildCardNotPermittedInIntPort = 732; } internal class UpnpNatDeviceInfo { public IPEndPoint HostEndPoint { get; private set; } public IPAddress LocalAddress { get; private set; } public string ServiceType { get; private set; } public Uri ServiceControlUri { get; private set; } public UpnpNatDeviceInfo(IPAddress localAddress, Uri locationUri, string serviceControlUrl, string serviceType) { LocalAddress = localAddress; ServiceType = serviceType; HostEndPoint = new IPEndPoint(IPAddress.Parse(locationUri.Host), locationUri.Port); if (Uri.IsWellFormedUriString(serviceControlUrl, UriKind.Absolute)) { Uri uri = new Uri(serviceControlUrl); IPEndPoint hostEndPoint = HostEndPoint; serviceControlUrl = uri.PathAndQuery; NatDiscoverer.TraceSource.LogInfo("{0}: Absolute URI detected. Host address is now: {1}", hostEndPoint, HostEndPoint); NatDiscoverer.TraceSource.LogInfo("{0}: New control url: {1}", HostEndPoint, serviceControlUrl); } UriBuilder uriBuilder = new UriBuilder("http", locationUri.Host, locationUri.Port); ServiceControlUri = new Uri(uriBuilder.Uri, serviceControlUrl); } } internal sealed class UpnpNatDevice : NatDevice { internal readonly UpnpNatDeviceInfo DeviceInfo; private readonly SoapClient _soapClient; internal UpnpNatDevice(UpnpNatDeviceInfo deviceInfo) { Touch(); DeviceInfo = deviceInfo; _soapClient = new SoapClient(DeviceInfo.ServiceControlUri, DeviceInfo.ServiceType); } public override Task<IPAddress> GetExternalIPAsync() { NatDiscoverer.TraceSource.LogInfo("GetExternalIPAsync - Getting external IP address"); GetExternalIPAddressRequestMessage getExternalIPAddressRequestMessage = new GetExternalIPAddressRequestMessage(); return _soapClient.InvokeAsync("GetExternalIPAddress", getExternalIPAddressRequestMessage.ToXml()).TimeoutAfter<XmlDocument>(TimeSpan.FromSeconds(4.0)).ContinueWith<IPAddress>((Func<Task<XmlDocument>, IPAddress>)((Task<XmlDocument> task) => new GetExternalIPAddressResponseMessage(task.Result, DeviceInfo.ServiceType).ExternalIPAddress)); } public override Task CreatePortMapAsync(Mapping mapping) { Guard.IsNotNull(mapping, "mapping"); if (mapping.PrivateIP.Equals(IPAddress.None)) { mapping.PrivateIP = DeviceInfo.LocalAddress; } NatDiscoverer.TraceSource.LogInfo("CreatePortMapAsync - Creating port mapping {0}", mapping); CreatePortMappingRequestMessage createPortMappingRequestMessage = new CreatePortMappingRequestMessage(mapping); return _soapClient.InvokeAsync("AddPortMapping", createPortMappingRequestMessage.ToXml()).TimeoutAfter<XmlDocument>(TimeSpan.FromSeconds(4.0)).ContinueWith((Action<Task<XmlDocument>>)delegate(Task<XmlDocument> task) { if (!((Task)task).IsFaulted) { RegisterMapping(mapping); } else { if (!(((Exception)(object)((Task)task).Exception).InnerException is MappingException ex)) { throw ((Exception)(object)((Task)task).Exception).InnerException; } switch (ex.ErrorCode) { case 725: NatDiscoverer.TraceSource.LogWarn("Only Permanent Leases Supported - There is no warranty it will be closed"); mapping.Lifetime = 0; mapping.LifetimeType = MappingLifetime.ForcedSession; CreatePortMapAsync(mapping); break; case 724: NatDiscoverer.TraceSource.LogWarn("Same Port Values Required - Using internal port {0}", mapping.PrivatePort); mapping.PublicPort = mapping.PrivatePort; CreatePortMapAsync(mapping); break; case 726: NatDiscoverer.TraceSource.LogWarn("Remote Host Only Supports Wildcard"); mapping.PublicIP = IPAddress.None; CreatePortMapAsync(mapping); break; case 727: NatDiscoverer.TraceSource.LogWarn("External Port Only Supports Wildcard"); throw ex; case 718: NatDiscoverer.TraceSource.LogWarn("Conflict with an already existing mapping"); throw ex; default: throw ex; } } }); } public override Task DeletePortMapAsync(Mapping mapping) { Guard.IsNotNull(mapping, "mapping"); if (mapping.PrivateIP.Equals(IPAddress.None)) { mapping.PrivateIP = DeviceInfo.LocalAddress; } NatDiscoverer.TraceSource.LogInfo("DeletePortMapAsync - Deleteing port mapping {0}", mapping); DeletePortMappingRequestMessage deletePortMappingRequestMessage = new DeletePortMappingRequestMessage(mapping); return _soapClient.InvokeAsync("DeletePortMapping", deletePortMappingRequestMessage.ToXml()).TimeoutAfter<XmlDocument>(TimeSpan.FromSeconds(4.0)).ContinueWith((Action<Task<XmlDocument>>)delegate(Task<XmlDocument> task) { if (!((Task)task).IsFaulted) { UnregisterMapping(mapping); } else if (((Exception)(object)((Task)task).Exception).InnerException is MappingException ex && ex.ErrorCode != 714) { throw ex; } }); } public void GetGenericMappingAsync(int index, List<Mapping> mappings, TaskCompletionSource<IEnumerable<Mapping>> taskCompletionSource) { GetGenericPortMappingEntry getGenericPortMappingEntry = new GetGenericPortMappingEntry(index); _soapClient.InvokeAsync("GetGenericPortMappingEntry", getGenericPortMappingEntry.ToXml()).TimeoutAfter<XmlDocument>(TimeSpan.FromSeconds(4.0)).ContinueWith((Action<Task<XmlDocument>>)delegate(Task<XmlDocument> task) { if (!((Task)task).IsFaulted) { GetPortMappingEntryResponseMessage getPortMappingEntryResponseMessage = new GetPortMappingEntryResponseMessage(task.Result, DeviceInfo.ServiceType, genericMapping: true); if (!IPAddress.TryParse(getPortMappingEntryResponseMessage.InternalClient, out IPAddress address)) { NatDiscoverer.TraceSource.LogWarn("InternalClient is not an IP address. Mapping ignored!"); } else { Mapping item = new Mapping(getPortMappingEntryResponseMessage.Protocol, address, getPortMappingEntryResponseMessage.InternalPort, getPortMappingEntryResponseMessage.ExternalPort, getPortMappingEntryResponseMessage.LeaseDuration, getPortMappingEntryResponseMessage.PortMappingDescription); mappings.Add(item); } GetGenericMappingAsync(checked(index + 1), mappings, taskCompletionSource); } else { if (!(((Exception)(object)((Task)task).Exception).InnerException is MappingException ex)) { throw ((Exception)(object)((Task)task).Exception).InnerException; } if (ex.ErrorCode == 713 || ex.ErrorCode == 714) { taskCompletionSource.SetResult((IEnumerable<Mapping>)mappings); } else { if (ex.ErrorCode != 402) { throw ((Exception)(object)((Task)task).Exception).InnerException; } NatDiscoverer.TraceSource.LogWarn("Router failed with 402-InvalidArgument. No more mappings is assumed."); taskCompletionSource.SetResult((IEnumerable<Mapping>)mappings); } } }); } public override Task<IEnumerable<Mapping>> GetAllMappingsAsync() { TaskCompletionSource<IEnumerable<Mapping>> val = new TaskCompletionSource<IEnumerable<Mapping>>(); NatDiscoverer.TraceSource.LogInfo("GetAllMappingsAsync - Getting all mappings"); GetGenericMappingAsync(0, new List<Mapping>(), val); return val.Task; } public override Task<Mapping> GetSpecificMappingAsync(Protocol protocol, int publicPort) { Guard.IsTrue(protocol == Protocol.Tcp || protocol == Protocol.Udp, "protocol"); Guard.IsInRange(publicPort, 0, 65535, "port"); NatDiscoverer.TraceSource.LogInfo("GetSpecificMappingAsync - Getting mapping for protocol: {0} port: {1}", Enum.GetName(typeof(Protocol), protocol), publicPort); GetSpecificPortMappingEntryRequestMessage getSpecificPortMappingEntryRequestMessage = new GetSpecificPortMappingEntryRequestMessage(protocol, publicPort); return _soapClient.InvokeAsync("GetSpecificPortMappingEntry", getSpecificPortMappingEntryRequestMessage.ToXml()).TimeoutAfter<XmlDocument>(TimeSpan.FromSeconds(4.0)).ContinueWith<Mapping>((Func<Task<XmlDocument>, Mapping>)delegate(Task<XmlDocument> task) { if (!((Task)task).IsFaulted) { GetPortMappingEntryResponseMessage getPortMappingEntryResponseMessage = new GetPortMappingEntryResponseMessage(task.Result, DeviceInfo.ServiceType, genericMapping: false); return new Mapping(getPortMappingEntryResponseMessage.Protocol, IPAddress.Parse(getPortMappingEntryResponseMessage.InternalClient), getPortMappingEntryResponseMessage.InternalPort, publicPort, getPortMappingEntryResponseMessage.LeaseDuration, getPortMappingEntryResponseMessage.PortMappingDescription); } MappingException ex = ((Exception)(object)((Task)task).Exception).InnerException as MappingException; if (ex != null && ex.ErrorCode == 714) { return null; } if (ex != null && ex.ErrorCode == 402) { NatDiscoverer.TraceSource.LogWarn("Router failed with 402-InvalidArgument. Mapping not found is assumed."); return null; } throw ((Exception)(object)((Task)task).Exception).InnerException; }); } public override string ToString() { return $"EndPoint: {DeviceInfo.HostEndPoint}\nControl Url: {DeviceInfo.ServiceControlUri}\nService Type: {DeviceInfo.ServiceType}\nLast Seen: {base.LastSeen}"; } } internal static class StreamExtensions { internal static string ReadAsMany(this StreamReader stream, int bytesToRead) { char[] array = new char[bytesToRead]; stream.ReadBlock(array, 0, bytesToRead); return new string(array); } internal static string GetXmlElementText(this XmlNode node, string elementName) { XmlElement xmlElement = node[elementName]; if (xmlElement == null) { return string.Empty; } return xmlElement.InnerText; } internal static bool ContainsIgnoreCase(this string s, string pattern) { return s.IndexOf(pattern, StringComparison.OrdinalIgnoreCase) >= 0; } internal static void LogInfo(this TraceSource source, string format, params object[] args) { source.TraceEvent(TraceEventType.Information, 0, format, args); } internal static void LogWarn(this TraceSource source, string format, params object[] args) { source.TraceEvent(TraceEventType.Warning, 0, format, args); } internal static void LogError(this TraceSource source, string format, params object[] args) { source.TraceEvent(TraceEventType.Error, 0, format, args); } internal static string ToPrintableXml(this XmlDocument document) { using MemoryStream memoryStream = new MemoryStream(); using XmlTextWriter xmlTextWriter = new XmlTextWriter(memoryStream, Encoding.Unicode); try { xmlTextWriter.Formatting = Formatting.Indented; document.WriteContentTo(xmlTextWriter); xmlTextWriter.Flush(); memoryStream.Flush(); memoryStream.Position = 0L; return new StreamReader(memoryStream).ReadToEnd(); } catch (Exception) { return document.ToString(); } } public static Task<TResult> TimeoutAfter<TResult>(this Task<TResult> task, TimeSpan timeout) { //IL_000e: Unknown result type (might be due to invalid IL or missing references) //IL_0018: Expected O, but got Unknown //IL_0030: Unknown result type (might be due to invalid IL or missing references) CancellationTokenSource timeoutCancellationTokenSource = new CancellationTokenSource(); return TaskExtensions.Unwrap<TResult>(TaskExtension.WhenAny((Task)task, TaskExtension.Delay(timeout, timeoutCancellationTokenSource.Token)).ContinueWith<Task<TResult>>((Func<Task<Task>, Task<TResult>>)delegate(Task<Task> t) { if (t.Result == task) { timeoutCancellationTokenSource.Cancel(); return task; } throw new TimeoutException("The operation has timed out. The network is broken, router has gone or is too busy."); })); } } internal static class EnumExtension { public static bool HasFlag(this Enum value, Enum flag) { int num = (int)(object)value; int num2 = (int)(object)flag; return (num & num2) == num2; } } public static class CancellationTokenSourceExtension { public static void CancelAfter(this CancellationTokenSource source, int millisecondsDelay) { if (millisecondsDelay < -1) { throw new ArgumentOutOfRangeException("millisecondsDelay"); } new Timer(delegate(object self) { ((Timer)self).Dispose(); try { source.Cancel(); } catch (ObjectDisposedException) { } }).Change(millisecondsDelay, -1); } } public static class TaskExtension { public static Task Delay(TimeSpan delay, CancellationToken token) { //IL_005c: Unknown result type (might be due to invalid IL or missing references) long num = checked((long)delay.TotalMilliseconds); if (num < -1 || num > int.MaxValue) { throw new ArgumentOutOfRangeException("delay"); } TaskCompletionSource<object> tcs = new TaskCompletionSource<object>(); Timer timer = new Timer(delegate { tcs.TrySetResult((object)null); }, null, num, -1L); ((CancellationToken)(ref token)).Register((Action)delegate { timer.Dispose(); tcs.TrySetCanceled(); }); return (Task)(object)tcs.Task; } public static Task<Task> WhenAny(params Task[] tasks) { return Task.Factory.ContinueWhenAny<Task>(tasks, (Func<Task, Task>)((Task t) => t)); } public static Task WhenAll(params Task[] tasks) { return (Task)(object)Task.Factory.ContinueWhenAll<Task[]>(tasks, (Func<Task[], Task[]>)((Task[] t) => t)); } } internal interface IIPAddressesProvider { IEnumerable<IPAddress> DnsAddresses(); IEnumerable<IPAddress> GatewayAddresses(); IEnumerable<IPAddress> UnicastAddresses(); } internal class IPAddressesProvider : IIPAddressesProvider { public IEnumerable<IPAddress> UnicastAddresses() { return IPAddresses((IPInterfaceProperties p) => p.UnicastAddresses.Select((UnicastIPAddressInformation x) => x.Address)); } public IEnumerable<IPAddress> DnsAddresses() { return IPAddresses((IPInterfaceProperties p) => p.DnsAddresses); } public IEnumerable<IPAddress> GatewayAddresses() { return IPAddresses((IPInterfaceProperties p) => p.GatewayAddresses.Select((GatewayIPAddressInformation x) => x.Address)); } private static IEnumerable<IPAddress> IPAddresses(Func<IPInterfaceProperties, IEnumerable<IPAddress>> ipExtractor) { return from networkInterface in NetworkInterface.GetAllNetworkInterfaces() where networkInterface.OperationalStatus == OperationalStatus.Up || networkInterface.OperationalStatus == OperationalStatus.Unknown let properties = networkInterface.GetIPProperties() from address in ipExtractor(properties) where address.AddressFamily == AddressFamily.InterNetwork select address; } } internal static class WellKnownConstants { public static IPAddress IPv4MulticastAddress = IPAddress.Parse("239.255.255.250"); public static IPEndPoint NatPmpEndPoint = new IPEndPoint(IPAddress.Parse("192.168.0.1"), 5351); }