public void Start(XmppConnection connection) { var auth = new SASLAuth(); auth.SetAttributeValue("mechanism", SASLMethod); auth.SetValue(Initiate()); connection.Send(auth); var authResponse = connection.NextElement(); var nextResponse = string.Empty; Task.Run(() => { while ((nextResponse = NextChallenge(authResponse.Value)) != "") { if (nextResponse == "error") { OnAuthenticationFailed(connection); return; } var response = new SASLResponse(); response.SetValue(nextResponse); connection.Send(response); authResponse = connection.NextElement(); } OnAuthenticated(connection); }); }
public override Task ConnectAsync(CancellationToken token) { return(Task.Run(async() => { if (string.IsNullOrEmpty(websocketUri)) { var lookup = new LookupClient(); var response = await lookup.QueryAsync("_xmppconnect." + Jid.Domain, QueryType.TXT); if (response.Answers.TxtRecords().Any()) { foreach (var srv in response.Answers.TxtRecords()) { foreach (var addr in srv.Text) { if (addr.StartsWith("_xmpp-client-websocket")) { websocketUri = addr.Split('=')[1]; break; } } } } } if (string.IsNullOrEmpty(websocketUri)) { OnConnectionFailed(new ConnFailedArgs { Message = "WebSocket URI is not resolved or set." }); return; } _connection = new WebSocket(websocketUri, "xmpp", WebSocketVersion.Rfc6455); _connection.Opened += (sender, args) => { _currentState = XmppConnectionState.Connected; RestartStream(); }; _connection.MessageReceived += (sender, args) => { OnElement(new ElementArgs { IsInput = true, Stanza = XElement.Parse(args.Message) }); if (_currentState == XmppConnectionState.Connected) { ReadStreamStart(args.Message); _currentState = XmppConnectionState.StreamInitiated; } else if (_currentState == XmppConnectionState.StreamAuthenticated) { ReadStreamStart(args.Message); _currentState = XmppConnectionState.StreamResourceBindingRequest; } else { var currentStanza = XElement.Parse(args.Message); var error = Stanza.Parse <StreamError>(currentStanza); if (error != null) { OnConnectionFailed(new ConnFailedArgs { Message = error.Value }); return; } switch (_currentState) { case XmppConnectionState.StreamInitiated: var features = Stanza.Parse <Features>(currentStanza); authenticator = SASLHandler.Create(features.SaslMechanisms, Jid, Password); if (authenticator == null) { OnConnectionFailed(new ConnFailedArgs { Message = "supported sasl mechanism not available" }); return; } var auth = new SASLAuth(); auth.SetAttributeValue("mechanism", authenticator.SASLMethod); var authInit = authenticator.Initiate(); if (!string.IsNullOrEmpty(authInit)) { auth.SetValue(authInit); } Send(auth); _currentState = XmppConnectionState.StreamAuthenticating; break; case XmppConnectionState.StreamAuthenticating: switch (currentStanza.Name.LocalName) { case "success": _currentState = XmppConnectionState.StreamAuthenticated; RestartStream(); break; case "failure": OnConnectionFailed(new ConnFailedArgs { Message = currentStanza.Value }); _currentState = XmppConnectionState.Disconnected; return; case "challenge": var response = new SASLResponse(); response.SetValue( authenticator.NextChallenge(currentStanza.Value)); Send(response); break; } break; case XmppConnectionState.StreamResourceBindingRequest: // todo: parse features of negotiated stream //Stanza.Parse<Features>(currentStanza); var bind = new Bind(Jid.Resource); var iq = new XMPPIq(XMPPIq.IqTypes.set); iq.Add(bind); Send(iq); _currentState = XmppConnectionState.StreamResourceBindingResponse; break; case XmppConnectionState.StreamResourceBindingResponse: var bindedJid = currentStanza.Element( XNamespace.Get(Namespaces.XmppBind) + "bind"); if (bindedJid == null) { OnConnectionFailed(new ConnFailedArgs { Message = "bind failed" }); _currentState = XmppConnectionState.Disconnected; } else { var sess = new XElement( XNamespace.Get(Namespaces.XmppSession) + "session"); var sessIq = new XMPPIq(XMPPIq.IqTypes.set); sessIq.Add(sess); Send(sessIq); _currentState = XmppConnectionState.StreamSessionNoOp; Jid = new JID( bindedJid.Element( XNamespace.Get(Namespaces.XmppBind) + "jid") .Value); } break; case XmppConnectionState.StreamSessionNoOp: OnSignedIn(new SignedInArgs { Jid = Jid }); _currentState = XmppConnectionState.StreamNegotiated; break; case XmppConnectionState.StreamNegotiated: if (currentStanza.Name.LocalName.Equals("iq")) { OnIq(Stanza.Parse <XMPPIq>(currentStanza)); } if (currentStanza.Name.LocalName.Equals("message")) { OnMessage(Stanza.Parse <XMPPMessage>(currentStanza)); } if (currentStanza.Name.LocalName.Equals("presence")) { OnPresence(Stanza.Parse <XMPPPresence>(currentStanza)); } break; default: throw new IOException("Invalid state"); } } }; _connection.Open(); })); }
public XmppWebSocketConnection(JID jid, string password, string websocketUri) : base(jid, password) { Capabilities = new CapabilitiesManager { Identity = new Identity { Category = "client", IdentityType = "mobile", IdentityName = "SharpXMPP" }, Node = "http://bggg.net.ru/caps", Features = new List <string> { Namespaces.DiscoInfo, Namespaces.DiscoItems } }; IqTracker = new XMPP.Client.IqHandler(this) { ResponseHandlers = new Dictionary <string, ResponseHandler>(), PayloadHandlers = new List <PayloadHandler> { new InfoHandler(Capabilities), new ItemsHandler() } }; Iq += (sender, iq) => IqTracker.Handle(iq); // ReSharper disable RedundantArgumentDefaultValue _connection = new WebSocket(websocketUri, "xmpp", cookies: (List <KeyValuePair <string, string> >)null); // ReSharper restore RedundantArgumentDefaultValue _connection.Opened += (sender, args) => { _currentState = XmppConnectionState.Connected; RestartStream(); }; _connection.MessageReceived += (sender, args) => { if (_currentState == XmppConnectionState.Connected) { ReadStreamStart(args.Message); _currentState = XmppConnectionState.StreamInitiated; } else if (_currentState == XmppConnectionState.StreamAuthenticated) { ReadStreamStart(args.Message); _currentState = XmppConnectionState.StreamResourceBindingRequest; } else { var currentStanza = Stanza.Parse(args.Message); OnElement(new ElementArgs { IsInput = false, Stanza = currentStanza }); var error = Stanza.Parse <StreamError>(currentStanza); if (error != null) { OnConnectionFailed(new ConnFailedArgs { Message = error.Value }); return; } switch (_currentState) { case XmppConnectionState.StreamInitiated: var features = Stanza.Parse <Features>(currentStanza); authenticator = SASLHandler.Create(features.SaslMechanisms, Jid, Password); if (authenticator == null) { OnConnectionFailed(new ConnFailedArgs { Message = "supported sasl mechanism not available" }); return; } var auth = new SASLAuth(); auth.SetAttributeValue("mechanism", authenticator.SASLMethod); var authInit = authenticator.Initiate(); if (!string.IsNullOrEmpty(authInit)) { auth.SetValue(authInit); } Send(auth); _currentState = XmppConnectionState.StreamAuthenticating; break; case XmppConnectionState.StreamAuthenticating: switch (currentStanza.Name.LocalName) { case "success": _currentState = XmppConnectionState.StreamAuthenticated; RestartStream(); break; case "failure": OnConnectionFailed(new ConnFailedArgs { Message = currentStanza.Value }); _currentState = XmppConnectionState.Disconnected; return; case "challenge": var response = new SASLResponse(); response.SetValue( authenticator.NextChallenge(currentStanza.Value)); Send(response); break; } break; case XmppConnectionState.StreamResourceBindingRequest: // todo: parse features of negotiated stream //Stanza.Parse<Features>(currentStanza); var bind = new Bind(Jid.Resource); var iq = new Iq(XMPP.Client.Elements.Iq.IqTypes.set); iq.Add(bind); Send(iq); _currentState = XmppConnectionState.StreamResourceBindingResponse; break; case XmppConnectionState.StreamResourceBindingResponse: var bindedJid = currentStanza.Element( XNamespace.Get(Namespaces.XmppBind) + "bind"); if (bindedJid == null) { OnConnectionFailed(new ConnFailedArgs { Message = "bind failed" }); _currentState = XmppConnectionState.Disconnected; } else { var sess = new XElement( XNamespace.Get(Namespaces.XmppSession) + "session"); var sessIq = new Iq(XMPP.Client.Elements.Iq.IqTypes.set); sessIq.Add(sess); Send(sessIq); _currentState = XmppConnectionState.StreamSessionNoOp; Jid = new JID( bindedJid.Element( XNamespace.Get(Namespaces.XmppBind) + "jid") .Value); } break; case XmppConnectionState.StreamSessionNoOp: OnSignedIn(new SignedInArgs { Jid = Jid }); Roster.Query(this); var initPresence = new Presence(Capabilities); Send(initPresence); _currentState = XmppConnectionState.StreamNegotiated; break; case XmppConnectionState.StreamNegotiated: if (currentStanza.Name.LocalName.Equals("iq")) { OnIq(Stanza.Parse <Iq>(currentStanza)); } if (currentStanza.Name.LocalName.Equals("message")) { OnMessage(Stanza.Parse <Message>(currentStanza)); } break; default: throw new IOException("Invalid state"); } } }; }