| | | 1 | | using System; |
| | | 2 | | using System.Threading; |
| | | 3 | | |
| | | 4 | | namespace Renci.SshNet |
| | | 5 | | { |
| | | 6 | | internal sealed class ForwardedPortStatus |
| | | 7 | | { |
| | 4 | 8 | | public static readonly ForwardedPortStatus Stopped = new ForwardedPortStatus(1, "Stopped"); |
| | 4 | 9 | | public static readonly ForwardedPortStatus Stopping = new ForwardedPortStatus(2, "Stopping"); |
| | 4 | 10 | | public static readonly ForwardedPortStatus Started = new ForwardedPortStatus(3, "Started"); |
| | 4 | 11 | | public static readonly ForwardedPortStatus Starting = new ForwardedPortStatus(4, "Starting"); |
| | | 12 | | |
| | | 13 | | private readonly int _value; |
| | | 14 | | private readonly string _name; |
| | | 15 | | |
| | 16 | 16 | | private ForwardedPortStatus(int value, string name) |
| | 16 | 17 | | { |
| | 16 | 18 | | _value = value; |
| | 16 | 19 | | _name = name; |
| | 16 | 20 | | } |
| | | 21 | | |
| | | 22 | | public override bool Equals(object obj) |
| | 5876 | 23 | | { |
| | 5876 | 24 | | if (ReferenceEquals(this, obj)) |
| | 2599 | 25 | | { |
| | 2599 | 26 | | return true; |
| | | 27 | | } |
| | | 28 | | |
| | 3277 | 29 | | if (obj is not ForwardedPortStatus forwardedPortStatus) |
| | 0 | 30 | | { |
| | 0 | 31 | | return false; |
| | | 32 | | } |
| | | 33 | | |
| | 3277 | 34 | | return forwardedPortStatus._value == _value; |
| | 5876 | 35 | | } |
| | | 36 | | |
| | | 37 | | #pragma warning disable S3875 // "operator==" should not be overloaded on reference types |
| | | 38 | | public static bool operator ==(ForwardedPortStatus left, ForwardedPortStatus right) |
| | | 39 | | #pragma warning restore S3875 // "operator==" should not be overloaded on reference types |
| | 5876 | 40 | | { |
| | | 41 | | // check if lhs is null |
| | 5876 | 42 | | if (left is null) |
| | 0 | 43 | | { |
| | | 44 | | // check if both lhs and rhs are null |
| | 0 | 45 | | return right is null; |
| | | 46 | | } |
| | | 47 | | |
| | 5876 | 48 | | return left.Equals(right); |
| | 5876 | 49 | | } |
| | | 50 | | |
| | | 51 | | public static bool operator !=(ForwardedPortStatus left, ForwardedPortStatus right) |
| | 0 | 52 | | { |
| | 0 | 53 | | return !(left==right); |
| | 0 | 54 | | } |
| | | 55 | | |
| | | 56 | | public override int GetHashCode() |
| | 0 | 57 | | { |
| | 0 | 58 | | return _value; |
| | 0 | 59 | | } |
| | | 60 | | |
| | | 61 | | public override string ToString() |
| | 0 | 62 | | { |
| | 0 | 63 | | return _name; |
| | 0 | 64 | | } |
| | | 65 | | |
| | | 66 | | /// <summary> |
| | | 67 | | /// Returns a value indicating whether <paramref name="status"/> has been changed to <see cref="Stopping"/>. |
| | | 68 | | /// </summary> |
| | | 69 | | /// <param name="status">The status to transition from.</param> |
| | | 70 | | /// <returns> |
| | | 71 | | /// <see langword="true"/> if <paramref name="status"/> has been changed to <see cref="Stopping"/>; otherwise, < |
| | | 72 | | /// </returns> |
| | | 73 | | /// <exception cref="InvalidOperationException">Cannot transition <paramref name="status"/> to <see cref="Stoppi |
| | | 74 | | /// <remarks> |
| | | 75 | | /// While a transition from <see cref="Stopped"/> to <see cref="Stopping"/> is not possible, this method will |
| | | 76 | | /// return <see langword="false"/> for any such attempts. This is related to concurrency. |
| | | 77 | | /// </remarks> |
| | | 78 | | public static bool ToStopping(ref ForwardedPortStatus status) |
| | 829 | 79 | | { |
| | | 80 | | // attempt to transition from Started to Stopping |
| | 829 | 81 | | var previousStatus = Interlocked.CompareExchange(ref status, Stopping, Started); |
| | 829 | 82 | | if (previousStatus == Stopping || previousStatus == Stopped) |
| | 304 | 83 | | { |
| | | 84 | | // status is already Stopping or Stopped, so no transition to Stopping is necessary |
| | 304 | 85 | | return false; |
| | | 86 | | } |
| | | 87 | | |
| | | 88 | | // we've successfully transitioned from Started to Stopping |
| | 525 | 89 | | if (status == Stopping) |
| | 525 | 90 | | { |
| | 525 | 91 | | return true; |
| | | 92 | | } |
| | | 93 | | |
| | | 94 | | // attempt to transition from Starting to Stopping |
| | 0 | 95 | | previousStatus = Interlocked.CompareExchange(ref status, Stopping, Starting); |
| | 0 | 96 | | if (previousStatus == Stopping || previousStatus == Stopped) |
| | 0 | 97 | | { |
| | | 98 | | // status is already Stopping or Stopped, so no transition to Stopping is necessary |
| | 0 | 99 | | return false; |
| | | 100 | | } |
| | | 101 | | |
| | | 102 | | // we've successfully transitioned from Starting to Stopping |
| | 0 | 103 | | if (status == Stopping) |
| | 0 | 104 | | { |
| | 0 | 105 | | return true; |
| | | 106 | | } |
| | | 107 | | |
| | | 108 | | // there's no valid transition from status to Stopping |
| | 0 | 109 | | throw new InvalidOperationException(string.Format("Forwarded port cannot transition from '{0}' to '{1}'.", |
| | 0 | 110 | | previousStatus, |
| | 0 | 111 | | Stopping)); |
| | 829 | 112 | | } |
| | | 113 | | |
| | | 114 | | /// <summary> |
| | | 115 | | /// Returns a value indicating whether <paramref name="status"/> has been changed to <see cref="Starting"/>. |
| | | 116 | | /// </summary> |
| | | 117 | | /// <param name="status">The status to transition from.</param> |
| | | 118 | | /// <returns> |
| | | 119 | | /// <see langword="true"/> if <paramref name="status"/> has been changed to <see cref="Starting"/>; otherwise, < |
| | | 120 | | /// </returns> |
| | | 121 | | /// <exception cref="InvalidOperationException">Cannot transition <paramref name="status"/> to <see cref="Starti |
| | | 122 | | /// <remarks> |
| | | 123 | | /// While a transition from <see cref="Started"/> to <see cref="Starting"/> is not possible, this method will |
| | | 124 | | /// return <see langword="false"/> for any such attempts. This is related to concurrency. |
| | | 125 | | /// </remarks> |
| | | 126 | | public static bool ToStarting(ref ForwardedPortStatus status) |
| | 525 | 127 | | { |
| | | 128 | | // attemp to transition from Stopped to Starting |
| | 525 | 129 | | var previousStatus = Interlocked.CompareExchange(ref status, Starting, Stopped); |
| | 525 | 130 | | if (previousStatus == Starting || previousStatus == Started) |
| | 0 | 131 | | { |
| | | 132 | | // port is already Starting or Started, so no transition to Starting is necessary |
| | 0 | 133 | | return false; |
| | | 134 | | } |
| | | 135 | | |
| | | 136 | | // we've successfully transitioned from Stopped to Starting |
| | 525 | 137 | | if (status == Starting) |
| | 525 | 138 | | { |
| | 525 | 139 | | return true; |
| | | 140 | | } |
| | | 141 | | |
| | | 142 | | // there's no valid transition from status to Starting |
| | 0 | 143 | | throw new InvalidOperationException(string.Format("Forwarded port cannot transition from '{0}' to '{1}'.", |
| | 0 | 144 | | previousStatus, |
| | 0 | 145 | | Starting)); |
| | 525 | 146 | | } |
| | | 147 | | } |
| | | 148 | | } |