예제 #1
0
		internal void DispatchEvent(ManagerEvent e)
		{
#if LOGGER
			logger.Debug("Dispatching event: {0}", e);
#endif

			if (e is ResponseEvent)
			{
				ResponseEvent responseEvent = (ResponseEvent)e;
				if (!string.IsNullOrEmpty(responseEvent.ActionId) && !string.IsNullOrEmpty(responseEvent.InternalActionId))
				{
					ResponseEventHandler eventHandler = (ResponseEventHandler)GetResponseEventHandler(responseEvent.InternalActionId.GetHashCode());
					if (eventHandler != null)
						try
						{
							eventHandler.HandleEvent(e);
						}
						catch (SystemException ex)
						{
#if LOGGER
						logger.Error("Unexpected exception", ex);
#else
							throw ex;
#endif
						}
				}
			}

			#region ConnectEvent
			if (e is ConnectEvent)
			{
				string protocol = ((ConnectEvent)e).ProtocolIdentifier;
#if LOGGER
				logger.Info("Connected via {0}", protocol);
#endif
				if (!string.IsNullOrEmpty(protocol) && protocol.StartsWith("Asterisk Call Manager"))
				{
					this.protocolIdentifier = protocol;
				}
				else
				{
					this.protocolIdentifier = (string.IsNullOrEmpty(protocol) ? "Empty" : protocol);
#if LOGGER
					logger.Warning("Unsupported protocol version '{0}'. Use at your own risk.", protocol);
#endif
				}
				if (reconnected)
				{
#if LOGGER
					logger.Info("Send Challenge action.");
#endif
					ChallengeAction challengeAction = new ChallengeAction();
					try
					{
						SendAction(challengeAction, null);
					}
#if LOGGER
					catch(Exception ex)
					{
						logger.Info("Send Challenge fail : ", ex.Message);
#else
					catch
					{
#endif
						disconnect(true);
					}
					return;
				}
			}
			#endregion

			if (reconnected && e is DisconnectEvent)
			{
				((DisconnectEvent)e).Reconnect = true;
				fireEvent(e);
				reconnect(false);
			}
			else if (!reconnected && reconnectEnable && (e is DisconnectEvent || e is ReloadEvent || e is ShutdownEvent))
			{
				((ConnectionStateEvent)e).Reconnect = true;
				fireEvent(e);
				reconnect(true);
			}
			else
				fireEvent(e);
		}
예제 #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);

		}