Ejemplo n.º 1
0
		internal void DispatchResponse(Dictionary<string, string> buffer, ManagerResponse response)
		{
			string responseActionId = string.Empty;
			string actionId = string.Empty;
			IResponseHandler responseHandler = null;

			if (buffer != null)
			{
				if (buffer["response"].ToLower(Helper.CultureInfo) == "error")
					response = new ManagerError(buffer);
				else if (buffer.ContainsKey("actionid"))
					actionId = buffer["actionid"];
			}

			if (response != null)
				actionId = response.ActionId;

			if (!string.IsNullOrEmpty(actionId))
			{
				int hash = Helper.GetInternalActionId(actionId).GetHashCode();
				responseActionId = Helper.StripInternalActionId(actionId);
				responseHandler = GetRemoveResponseHandler(hash);

				if (response != null)
					response.ActionId = responseActionId;
				if (responseHandler != null)
				{
					if (response == null)
					{
						ManagerActionResponse action = responseHandler.Action as ManagerActionResponse;
						if (action == null || (response = action.ActionCompleteResponseClass() as ManagerResponse) == null)
							response = Helper.BuildResponse(buffer);
						else
							Helper.SetAttributes(response, buffer);
						response.ActionId = responseActionId;
					}

					try
					{
						responseHandler.HandleResponse(response);
					}
					catch (Exception ex)
					{
#if LOGGER
						logger.Error("Unexpected exception in responseHandler {0}\n{1}", response, ex);
#else
						throw new ManagerException("Unexpected exception in responseHandler " + responseHandler.GetType().FullName, ex);
#endif
					}
				}
			}
			
			if (response == null && buffer.ContainsKey("ping") && buffer["ping"] == "Pong")
			{
				response = Helper.BuildResponse(buffer);
				foreach (ResponseHandler pingHandler in pingHandlers.Values)
					pingHandler.HandleResponse(response);
				pingHandlers.Clear();
			}

			if (!reconnected)
				return;

			if (response == null)
			{
				response = Helper.BuildResponse(buffer);
				response.ActionId = responseActionId;
			}
#if LOGGER
			logger.Info("Reconnected - DispatchEvent : " + response);
#endif
			#region Support background reconnect
			if (response is ChallengeResponse)
			{
				string key = null;
				if (response.IsSuccess())
				{
					ChallengeResponse challengeResponse = (ChallengeResponse)response;
					string challenge = challengeResponse.Challenge;
					try
					{
						Util.MD5Support md = Util.MD5Support.GetInstance();
						if (challenge != null)
							md.Update(UTF8Encoding.UTF8.GetBytes(challenge));
						if (password != null)
							md.Update(UTF8Encoding.UTF8.GetBytes(password));
						key = Helper.ToHexString(md.DigestData);
					}
#if LOGGER
					catch (Exception ex)
					{
						logger.Error("Unable to create login key using MD5 Message Digest", ex);
#else
					catch
					{
#endif
						key = null;
					}
				}
				bool fail = true;
				if (!string.IsNullOrEmpty(key))
					try
					{
						Action.LoginAction loginAction = new Action.LoginAction(username, "MD5", key);
						SendAction(loginAction, null);
						fail = false;
					}
					catch { }
				if (fail)
					if (keepAliveAfterAuthenticationFailure)
						reconnect(true);
					else
						disconnect(true);
			}
			else if (response is ManagerError)
			{
				if (keepAliveAfterAuthenticationFailure)
					reconnect(true);
				else
					disconnect(true);
			}
			else if (response is ManagerResponse)
			{
				if (response.IsSuccess())
				{
					reconnected = false;
					enableEvents = true;
					reconnectEnable = keepAlive;
					ConnectEvent ce = new ConnectEvent(this);
					ce.Reconnect = true;
					ce.ProtocolIdentifier = protocolIdentifier;
					fireEvent(ce);
				}
				else if (keepAliveAfterAuthenticationFailure)
					reconnect(true);
				else
					disconnect(true);
			}
			#endregion
		}
Ejemplo n.º 2
0
		/// <summary>
		/// Does the real login, following the steps outlined below.<br/>
		/// Connects to the asterisk server by calling connect() if not already connected<br/>
		/// Waits until the protocol identifier is received. This is checked every sleepTime ms but not longer than timeout ms in total.<br/>
		/// Sends a ChallengeAction requesting a challenge for authType MD5.<br/>
		/// When the ChallengeResponse is received a LoginAction is sent using the calculated key (MD5 hash of the password appended to the received challenge).<br/>
		/// </summary>
		/// <param name="timeout">the maximum time to wait for the protocol identifier (in ms)</param>
		/// <throws>
		/// AuthenticationFailedException if username or password are incorrect and the login action returns an error or if the MD5
		/// hash cannot be computed. The connection is closed in this case.
		/// </throws>
		/// <throws>
		/// TimeoutException if a timeout occurs either while waiting for the
		/// protocol identifier or when sending the challenge or login
		/// action. The connection is closed in this case.
		/// </throws>
		private void login(int timeout)
		{
			enableEvents = false;
			if (reconnected)
			{
#if LOGGER
				logger.Error("Login during reconnect state.");
#endif
				throw new AuthenticationFailedException("Unable login during reconnect state.");
			}

			reconnectEnable = false;
			DateTime start = DateTime.Now;
			do
			{
				if (connect())
				{
					// Increase delay after connection up to 500 ms
					Thread.Sleep(10 * sleepTime);	// 200 milliseconds delay
				}
				try
				{
					Thread.Sleep(4 * sleepTime);	// 200 milliseconds delay
				}
				catch
				{ }

				if (string.IsNullOrEmpty(protocolIdentifier) && timeout > 0 && Helper.GetMillisecondsFrom(start) > timeout)
				{
					disconnect(true);
					throw new TimeoutException("Timeout waiting for protocol identifier");
				}
			} while (string.IsNullOrEmpty(protocolIdentifier));

			ChallengeAction challengeAction = new ChallengeAction();
			Response.ManagerResponse response = SendAction(challengeAction, defaultResponseTimeout * 2);
			if (response is ChallengeResponse)
			{
				ChallengeResponse challengeResponse = (ChallengeResponse)response;
				string key, challenge = challengeResponse.Challenge;
				try
				{
					Util.MD5Support md = Util.MD5Support.GetInstance();
					if (challenge != null)
						md.Update(UTF8Encoding.UTF8.GetBytes(challenge));
					if (password != null)
						md.Update(UTF8Encoding.UTF8.GetBytes(password));
					key = Helper.ToHexString(md.DigestData);
				}
				catch (Exception ex)
				{
					disconnect(true);
#if LOGGER
					logger.Error("Unable to create login key using MD5 Message Digest.", ex);
#endif
					throw new AuthenticationFailedException("Unable to create login key using MD5 Message Digest.", ex);
				}

				Action.LoginAction loginAction = new Action.LoginAction(username, "MD5", key);
				Response.ManagerResponse loginResponse = SendAction(loginAction);
				if (loginResponse is Response.ManagerError)
				{
					disconnect(true);
					throw new AuthenticationFailedException(loginResponse.Message);
				}

				// successfully logged in so assure that we keep trying to reconnect when disconnected
				reconnectEnable = keepAlive;

#if LOGGER
				logger.Info("Successfully logged in");
#endif
				asteriskVersion = determineVersion();
#if LOGGER
				logger.Info("Determined Asterisk version: " + asteriskVersion);
#endif
				enableEvents = true;
				ConnectEvent ce = new ConnectEvent(this);
				ce.ProtocolIdentifier = this.protocolIdentifier;
				DispatchEvent(ce);
			}
			else if (response is ManagerError)
				throw new ManagerException("Unable login to Asterisk - " + response.Message);
			else
				throw new ManagerException("Unknown response during login to Asterisk - " + response.GetType().Name + " with message " + response.Message);

		}