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); }
/// <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); }