|   |  | 1 |  | // Copyright (c) Microsoft. All rights reserved. | 
|   |  | 2 |  | // Licensed under the MIT license. See LICENSE file in the project root for full license information. | 
|   |  | 3 |  |  | 
|   |  | 4 |  | namespace Microsoft.Azure.ServiceBus.Amqp | 
|   |  | 5 |  | { | 
|   |  | 6 |  |     using System; | 
|   |  | 7 |  |     using System.Collections.Generic; | 
|   |  | 8 |  |     using System.Globalization; | 
|   |  | 9 |  |     using System.IO; | 
|   |  | 10 |  |     using System.Net.Sockets; | 
|   |  | 11 |  |     using System.Text; | 
|   |  | 12 |  |     using Microsoft.Azure.Amqp; | 
|   |  | 13 |  |     using Microsoft.Azure.Amqp.Encoding; | 
|   |  | 14 |  |     using Microsoft.Azure.Amqp.Framing; | 
|   |  | 15 |  |  | 
|   |  | 16 |  |     static class AmqpExceptionHelper | 
|   |  | 17 |  |     { | 
|   | 0 | 18 |  |         static readonly Dictionary<string, AmqpResponseStatusCode> ConditionToStatusMap = new Dictionary<string, AmqpRes | 
|   | 0 | 19 |  |         { | 
|   | 0 | 20 |  |             { AmqpClientConstants.TimeoutError.Value, AmqpResponseStatusCode.RequestTimeout }, | 
|   | 0 | 21 |  |             { AmqpErrorCode.NotFound.Value, AmqpResponseStatusCode.NotFound }, | 
|   | 0 | 22 |  |             { AmqpErrorCode.NotImplemented.Value, AmqpResponseStatusCode.NotImplemented }, | 
|   | 0 | 23 |  |             { AmqpClientConstants.EntityAlreadyExistsError.Value, AmqpResponseStatusCode.Conflict }, | 
|   | 0 | 24 |  |             { AmqpClientConstants.MessageLockLostError.Value, AmqpResponseStatusCode.Gone }, | 
|   | 0 | 25 |  |             { AmqpClientConstants.SessionLockLostError.Value, AmqpResponseStatusCode.Gone }, | 
|   | 0 | 26 |  |             { AmqpErrorCode.ResourceLimitExceeded.Value, AmqpResponseStatusCode.Forbidden }, | 
|   | 0 | 27 |  |             { AmqpClientConstants.NoMatchingSubscriptionError.Value, AmqpResponseStatusCode.InternalServerError }, | 
|   | 0 | 28 |  |             { AmqpErrorCode.NotAllowed.Value, AmqpResponseStatusCode.BadRequest }, | 
|   | 0 | 29 |  |             { AmqpErrorCode.UnauthorizedAccess.Value, AmqpResponseStatusCode.Unauthorized }, | 
|   | 0 | 30 |  |             { AmqpErrorCode.MessageSizeExceeded.Value, AmqpResponseStatusCode.Forbidden }, | 
|   | 0 | 31 |  |             { AmqpClientConstants.ServerBusyError.Value, AmqpResponseStatusCode.ServiceUnavailable }, | 
|   | 0 | 32 |  |             { AmqpClientConstants.ArgumentError.Value, AmqpResponseStatusCode.BadRequest }, | 
|   | 0 | 33 |  |             { AmqpClientConstants.ArgumentOutOfRangeError.Value, AmqpResponseStatusCode.BadRequest }, | 
|   | 0 | 34 |  |             { AmqpClientConstants.StoreLockLostError.Value, AmqpResponseStatusCode.Gone }, | 
|   | 0 | 35 |  |             { AmqpClientConstants.SessionCannotBeLockedError.Value, AmqpResponseStatusCode.Gone }, | 
|   | 0 | 36 |  |             { AmqpClientConstants.PartitionNotOwnedError.Value, AmqpResponseStatusCode.Gone }, | 
|   | 0 | 37 |  |             { AmqpClientConstants.EntityDisabledError.Value, AmqpResponseStatusCode.BadRequest }, | 
|   | 0 | 38 |  |             { AmqpClientConstants.PublisherRevokedError.Value, AmqpResponseStatusCode.Unauthorized }, | 
|   | 0 | 39 |  |             { AmqpClientConstants.AuthorizationFailedError.Value, AmqpResponseStatusCode.Unauthorized}, | 
|   | 0 | 40 |  |             { AmqpErrorCode.Stolen.Value, AmqpResponseStatusCode.Gone } | 
|   | 0 | 41 |  |         }; | 
|   |  | 42 |  |  | 
|   |  | 43 |  |         public static AmqpSymbol GetResponseErrorCondition(AmqpMessage response, AmqpResponseStatusCode statusCode) | 
|   |  | 44 |  |         { | 
|   | 0 | 45 |  |             object condition = response.ApplicationProperties.Map[ManagementConstants.Response.ErrorCondition]; | 
|   | 0 | 46 |  |             if (condition != null) | 
|   |  | 47 |  |             { | 
|   | 0 | 48 |  |                 return (AmqpSymbol)condition; | 
|   |  | 49 |  |             } | 
|   |  | 50 |  |  | 
|   |  | 51 |  |             // Most of the time we should have an error condition | 
|   | 0 | 52 |  |             foreach (var kvp in ConditionToStatusMap) | 
|   |  | 53 |  |             { | 
|   | 0 | 54 |  |                 if (kvp.Value == statusCode) | 
|   |  | 55 |  |                 { | 
|   | 0 | 56 |  |                     return kvp.Key; | 
|   |  | 57 |  |                 } | 
|   |  | 58 |  |             } | 
|   |  | 59 |  |  | 
|   | 0 | 60 |  |             return AmqpErrorCode.InternalError; | 
|   | 0 | 61 |  |         } | 
|   |  | 62 |  |  | 
|   |  | 63 |  |         public static AmqpResponseStatusCode GetResponseStatusCode(this AmqpMessage responseMessage) | 
|   |  | 64 |  |         { | 
|   | 0 | 65 |  |             var amqpResponseStatusCode = AmqpResponseStatusCode.Unused; | 
|   | 0 | 66 |  |             object statusCodeValue = responseMessage?.ApplicationProperties.Map[ManagementConstants.Response.StatusCode] | 
|   | 0 | 67 |  |             if (statusCodeValue is int && Enum.IsDefined(typeof(AmqpResponseStatusCode), statusCodeValue)) | 
|   |  | 68 |  |             { | 
|   | 0 | 69 |  |                 amqpResponseStatusCode = (AmqpResponseStatusCode)statusCodeValue; | 
|   |  | 70 |  |             } | 
|   |  | 71 |  |  | 
|   | 0 | 72 |  |             return amqpResponseStatusCode; | 
|   |  | 73 |  |         } | 
|   |  | 74 |  |  | 
|   |  | 75 |  |         public static Exception ToMessagingContractException(this AmqpMessage responseMessage, AmqpResponseStatusCode st | 
|   |  | 76 |  |         { | 
|   | 0 | 77 |  |             AmqpSymbol errorCondition = AmqpExceptionHelper.GetResponseErrorCondition(responseMessage, statusCode); | 
|   | 0 | 78 |  |             var statusDescription = responseMessage.ApplicationProperties.Map[ManagementConstants.Response.StatusDescrip | 
|   | 0 | 79 |  |             return AmqpExceptionHelper.ToMessagingContractException(errorCondition.Value, statusDescription); | 
|   |  | 80 |  |         } | 
|   |  | 81 |  |  | 
|   |  | 82 |  |         public static Exception ToMessagingContractException(this Error error, bool connectionError = false) | 
|   |  | 83 |  |         { | 
|   | 0 | 84 |  |             if (error == null) | 
|   |  | 85 |  |             { | 
|   | 0 | 86 |  |                 return new ServiceBusException(true, "Unknown error."); | 
|   |  | 87 |  |             } | 
|   |  | 88 |  |  | 
|   | 0 | 89 |  |             return ToMessagingContractException(error.Condition.Value, error.Description, connectionError); | 
|   |  | 90 |  |         } | 
|   |  | 91 |  |  | 
|   |  | 92 |  |         static Exception ToMessagingContractException(string condition, string message, bool connectionError = false) | 
|   |  | 93 |  |         { | 
|   | 0 | 94 |  |             if (string.Equals(condition, AmqpClientConstants.TimeoutError.Value)) | 
|   |  | 95 |  |             { | 
|   | 0 | 96 |  |                 return new ServiceBusTimeoutException(message); | 
|   |  | 97 |  |             } | 
|   |  | 98 |  |  | 
|   | 0 | 99 |  |             if (string.Equals(condition, AmqpErrorCode.NotFound.Value)) | 
|   |  | 100 |  |             { | 
|   | 0 | 101 |  |                 if (connectionError) | 
|   |  | 102 |  |                 { | 
|   | 0 | 103 |  |                     return new ServiceBusCommunicationException(message, null); | 
|   |  | 104 |  |                 } | 
|   |  | 105 |  |  | 
|   | 0 | 106 |  |                 return new MessagingEntityNotFoundException(message, null); | 
|   |  | 107 |  |             } | 
|   |  | 108 |  |  | 
|   | 0 | 109 |  |             if (string.Equals(condition, AmqpErrorCode.NotImplemented.Value)) | 
|   |  | 110 |  |             { | 
|   | 0 | 111 |  |                 return new NotSupportedException(message); | 
|   |  | 112 |  |             } | 
|   |  | 113 |  |  | 
|   | 0 | 114 |  |             if (string.Equals(condition, AmqpErrorCode.NotAllowed.Value)) | 
|   |  | 115 |  |             { | 
|   | 0 | 116 |  |                 return new InvalidOperationException(message); | 
|   |  | 117 |  |             } | 
|   |  | 118 |  |  | 
|   | 0 | 119 |  |             if (string.Equals(condition, AmqpErrorCode.UnauthorizedAccess.Value) || | 
|   | 0 | 120 |  |                 string.Equals(condition, AmqpClientConstants.AuthorizationFailedError.Value)) | 
|   |  | 121 |  |             { | 
|   | 0 | 122 |  |                 return new UnauthorizedException(message); | 
|   |  | 123 |  |             } | 
|   |  | 124 |  |  | 
|   | 0 | 125 |  |             if (string.Equals(condition, AmqpClientConstants.ServerBusyError.Value)) | 
|   |  | 126 |  |             { | 
|   | 0 | 127 |  |                 return new ServerBusyException(message); | 
|   |  | 128 |  |             } | 
|   |  | 129 |  |  | 
|   | 0 | 130 |  |             if (string.Equals(condition, AmqpClientConstants.ArgumentError.Value)) | 
|   |  | 131 |  |             { | 
|   | 0 | 132 |  |                 return new ArgumentException(message); | 
|   |  | 133 |  |             } | 
|   |  | 134 |  |  | 
|   | 0 | 135 |  |             if (string.Equals(condition, AmqpClientConstants.ArgumentOutOfRangeError.Value)) | 
|   |  | 136 |  |             { | 
|   | 0 | 137 |  |                 return new ArgumentOutOfRangeException(message); | 
|   |  | 138 |  |             } | 
|   |  | 139 |  |  | 
|   | 0 | 140 |  |             if (string.Equals(condition, AmqpClientConstants.EntityDisabledError.Value)) | 
|   |  | 141 |  |             { | 
|   | 0 | 142 |  |                 return new MessagingEntityDisabledException(message, null); | 
|   |  | 143 |  |             } | 
|   |  | 144 |  |  | 
|   | 0 | 145 |  |             if (string.Equals(condition, AmqpClientConstants.MessageLockLostError.Value)) | 
|   |  | 146 |  |             { | 
|   | 0 | 147 |  |                 return new MessageLockLostException(message); | 
|   |  | 148 |  |             } | 
|   |  | 149 |  |  | 
|   | 0 | 150 |  |             if (string.Equals(condition, AmqpClientConstants.SessionLockLostError.Value)) | 
|   |  | 151 |  |             { | 
|   | 0 | 152 |  |                 return new SessionLockLostException(message); | 
|   |  | 153 |  |             } | 
|   |  | 154 |  |  | 
|   | 0 | 155 |  |             if (string.Equals(condition, AmqpErrorCode.ResourceLimitExceeded.Value)) | 
|   |  | 156 |  |             { | 
|   | 0 | 157 |  |                 return new QuotaExceededException(message); | 
|   |  | 158 |  |             } | 
|   |  | 159 |  |  | 
|   | 0 | 160 |  |             if (string.Equals(condition, AmqpErrorCode.MessageSizeExceeded.Value)) | 
|   |  | 161 |  |             { | 
|   | 0 | 162 |  |                 return new MessageSizeExceededException(message); | 
|   |  | 163 |  |             } | 
|   |  | 164 |  |  | 
|   | 0 | 165 |  |             if (string.Equals(condition, AmqpClientConstants.MessageNotFoundError.Value)) | 
|   |  | 166 |  |             { | 
|   | 0 | 167 |  |                 return new MessageNotFoundException(message); | 
|   |  | 168 |  |             } | 
|   |  | 169 |  |  | 
|   | 0 | 170 |  |             if (string.Equals(condition, AmqpClientConstants.SessionCannotBeLockedError.Value)) | 
|   |  | 171 |  |             { | 
|   | 0 | 172 |  |                 return new SessionCannotBeLockedException(message); | 
|   |  | 173 |  |             } | 
|   |  | 174 |  |  | 
|   | 0 | 175 |  |             return new ServiceBusException(true, message); | 
|   |  | 176 |  |         } | 
|   |  | 177 |  |  | 
|   |  | 178 |  |         public static Exception GetClientException(Exception exception, string referenceId = null, Exception innerExcept | 
|   |  | 179 |  |         { | 
|   | 0 | 180 |  |             var stringBuilder = new StringBuilder(); | 
|   | 0 | 181 |  |             stringBuilder.AppendFormat(CultureInfo.InvariantCulture, exception.Message); | 
|   | 0 | 182 |  |             if (referenceId != null) | 
|   |  | 183 |  |             { | 
|   | 0 | 184 |  |                 stringBuilder.AppendFormat(CultureInfo.InvariantCulture, $"Reference: {referenceId}, {DateTime.UtcNow}") | 
|   |  | 185 |  |             } | 
|   |  | 186 |  |  | 
|   | 0 | 187 |  |             var message = stringBuilder.ToString(); | 
|   | 0 | 188 |  |             var aggregateException = innerException == null ? exception : new AggregateException(exception, innerExcepti | 
|   |  | 189 |  |  | 
|   | 0 | 190 |  |             switch (exception) | 
|   |  | 191 |  |             { | 
|   |  | 192 |  |                 case SocketException _: | 
|   | 0 | 193 |  |                     message = stringBuilder.AppendFormat(CultureInfo.InvariantCulture, $" ErrorCode: {((SocketException) | 
|   | 0 | 194 |  |                     return new ServiceBusCommunicationException(message, aggregateException); | 
|   |  | 195 |  |  | 
|   |  | 196 |  |                 case IOException _: | 
|   | 0 | 197 |  |                     if (exception.InnerException is SocketException socketException) | 
|   |  | 198 |  |                     { | 
|   | 0 | 199 |  |                         message = stringBuilder.AppendFormat(CultureInfo.InvariantCulture, $" ErrorCode: {socketExceptio | 
|   |  | 200 |  |                     } | 
|   | 0 | 201 |  |                     return new ServiceBusCommunicationException(message, aggregateException); | 
|   |  | 202 |  |  | 
|   |  | 203 |  |                 case AmqpException amqpException: | 
|   | 0 | 204 |  |                     return amqpException.Error.ToMessagingContractException(connectionError); | 
|   |  | 205 |  |  | 
|   | 0 | 206 |  |                 case OperationCanceledException operationCanceledException when operationCanceledException.InnerExceptio | 
|   | 0 | 207 |  |                     return amqpException.Error.ToMessagingContractException(connectionError); | 
|   |  | 208 |  |  | 
|   | 0 | 209 |  |                 case OperationCanceledException _ when connectionError: | 
|   | 0 | 210 |  |                     return new ServiceBusCommunicationException(message, aggregateException); | 
|   |  | 211 |  |  | 
|   |  | 212 |  |                 case OperationCanceledException _: | 
|   | 0 | 213 |  |                     return new ServiceBusException(true, message, aggregateException); | 
|   |  | 214 |  |  | 
|   |  | 215 |  |                 case TimeoutException _: | 
|   | 0 | 216 |  |                     return new ServiceBusTimeoutException(message, aggregateException); | 
|   |  | 217 |  |  | 
|   | 0 | 218 |  |                 case InvalidOperationException _ when connectionError: | 
|   | 0 | 219 |  |                     return new ServiceBusCommunicationException(message, aggregateException); | 
|   |  | 220 |  |             } | 
|   |  | 221 |  |  | 
|   | 0 | 222 |  |             if (connectionError) | 
|   |  | 223 |  |             { | 
|   | 0 | 224 |  |                 return new ServiceBusCommunicationException(message, aggregateException); | 
|   |  | 225 |  |             } | 
|   |  | 226 |  |  | 
|   | 0 | 227 |  |             return aggregateException; | 
|   |  | 228 |  |         } | 
|   |  | 229 |  |  | 
|   |  | 230 |  |         public static string GetTrackingId(this AmqpLink link) | 
|   |  | 231 |  |         { | 
|   | 0 | 232 |  |             if (link.Settings.Properties != null && | 
|   | 0 | 233 |  |                 link.Settings.Properties.TryGetValue<string>(AmqpClientConstants.TrackingIdName, out var trackingContext | 
|   |  | 234 |  |             { | 
|   | 0 | 235 |  |                 return trackingContext; | 
|   |  | 236 |  |             } | 
|   |  | 237 |  |  | 
|   | 0 | 238 |  |             return null; | 
|   |  | 239 |  |         } | 
|   |  | 240 |  |  | 
|   |  | 241 |  |         public static Exception GetInnerException(this AmqpObject amqpObject) | 
|   |  | 242 |  |         { | 
|   | 0 | 243 |  |             var connectionError = false; | 
|   |  | 244 |  |             Exception innerException; | 
|   |  | 245 |  |             switch (amqpObject) | 
|   |  | 246 |  |             { | 
|   |  | 247 |  |                 case AmqpSession amqpSession: | 
|   | 0 | 248 |  |                     innerException = amqpSession.TerminalException ?? amqpSession.Connection.TerminalException; | 
|   | 0 | 249 |  |                     break; | 
|   |  | 250 |  |  | 
|   |  | 251 |  |                 case AmqpLink amqpLink: | 
|   | 0 | 252 |  |                     connectionError = amqpLink.Session.IsClosing(); | 
|   | 0 | 253 |  |                     innerException = amqpLink.TerminalException ?? amqpLink.Session.TerminalException ?? amqpLink.Sessio | 
|   | 0 | 254 |  |                     break; | 
|   |  | 255 |  |  | 
|   |  | 256 |  |                 case RequestResponseAmqpLink amqpReqRespLink: | 
|   | 0 | 257 |  |                     innerException = amqpReqRespLink.TerminalException ?? amqpReqRespLink.Session.TerminalException ?? a | 
|   | 0 | 258 |  |                     break; | 
|   |  | 259 |  |  | 
|   |  | 260 |  |                 default: | 
|   | 0 | 261 |  |                     return null; | 
|   |  | 262 |  |             } | 
|   |  | 263 |  |  | 
|   | 0 | 264 |  |             return innerException == null ? null : GetClientException(innerException, null, null, connectionError); | 
|   |  | 265 |  |         } | 
|   |  | 266 |  |     } | 
|   |  | 267 |  | } |