/// <summary> /// Got the stream:stream. Start the handshake. /// </summary> /// <param name="sender"></param> /// <param name="tag"></param> protected override void OnDocumentStart(object sender, System.Xml.XmlElement tag) { base.OnDocumentStart(sender, tag); if (this.Type == ComponentType.Connect) { lock (StateLock) { State = HandshakingState.Instance; } Kixeye.Jabber.Protocol.Stream.Stream str = new Kixeye.Jabber.Protocol.Stream.Stream(this.Document, NS); str.To = this.ComponentID; this.StreamID = str.ID; if (ServerVersion.StartsWith("1.")) str.Version = "1.0"; WriteStartTag(str); if (ServerVersion.StartsWith("1.")) { Features f = new Features(this.Document); if (AutoStartTLS && !SSLon && (this[Options.LOCAL_CERTIFICATE] != null)) f.StartTLS = new StartTLS(this.Document); Write(f); } } }
private void FakeTimer(object state) { // HACK: stream restart is null for older versions of XEP-124. if (!FakeReceivedStream()) return; Features f = new Features(m_doc); f.AddChild(new Bind(m_doc)); f.AddChild(new Session(m_doc)); byte[] p = ENC.GetBytes(f.OuterXml); if (!m_listener.OnRead(this, p, 0, p.Length)) { Close(); return; } }
/// <summary> /// Informs the client that an XML element was received and /// invokes the OnProtocol event. /// </summary> /// <param name="sender">The object that called this method.</param> /// <param name="tag">XML element that contains the new tag.</param> protected virtual void OnElement(object sender, System.Xml.XmlElement tag) { //Debug.WriteLine(tag.OuterXml); if (tag is Kixeye.Jabber.Protocol.Stream.Error) { // Stream error. Race condition! Two cases: // 1) OnClose has already fired, in which case we are in ClosedState, and the reconnect timer is pending. // 2) OnClose hasn't fired, in which case we trick it into not starting the reconnect timer. lock (m_stateLock) { if (m_state != ClosedState.Instance) { State = ClosingState.Instance; } else if (m_reconnectTimer != null) { Debug.WriteLine("Disposing of timer"); m_reconnectTimer.Dispose(); } } if (OnStreamError != null) { OnStreamError(this, tag); } return; } if (State == ServerFeaturesState.Instance) { Features f = tag as Features; if (f == null) { FireOnError(new InvalidOperationException("Expecting stream:features from a version='1.0' server")); return; } m_features = f; ProcessFeatures(); return; } else if (State == SASLState.Instance) { if (tag is Success) { // restart the stream again SendNewStreamHeader(); } else if (tag is SASLFailure) { m_saslProc = null; lock (m_stateLock) { State = SASLFailedState.Instance; } SASLFailure sf = tag as SASLFailure; // TODO: I18N if (OnSASLError != null) { m_reconnect = false; OnSASLError(this, sf); } else FireOnError(new SASLException("SASL failure: " + sf.InnerXml)); return; } else if (tag is Step) { try { Step s = m_saslProc.step(tag as Step, this.Document); if (s != null) Write(s); } catch (Exception e) { FireOnError(new SASLException(e.Message)); return; } } else { m_saslProc = null; FireOnError(new SASLException("Invalid SASL protocol")); return; } } else if (State == StartTLSState.Instance) { switch (tag.Name) { case "proceed": if (!StartTLS()) return; SendNewStreamHeader(); break; case "failure": FireOnError(new AuthenticationFailedException()); return; } } else if (State == CompressionState.Instance) { switch (tag.Name) { case "compressed": if (!StartCompression()) return; SendNewStreamHeader(); break; case "failure": CompressionFailure fail = tag as CompressionFailure; FireOnError(new Kixeye.Bedrock.IO.CompressionFailedException(fail.Error)); return; } } else if (State == SASLAuthedState.Instance) { Features f = tag as Features; if (f == null) { FireOnError(new InvalidOperationException("Expecting stream:features from a version='1.0' server")); return; } if (OnSASLEnd != null) OnSASLEnd(this, f); m_saslProc = null; } else { if (OnProtocol != null) { OnProtocol(this, tag); } } CheckAll(tag); }