Example #1
0
        private Task StartAuthentication(Features features)
        {
            var tcs = new TaskCompletionSource <bool>();

            Task.Run(() =>
            {
                var authenticator = SASLHandler.Create(features.SaslMechanisms, Jid, Password);
                if (authenticator == null)
                {
                    OnConnectionFailed(new ConnFailedArgs {
                        Message = "supported sasl mechanism not available"
                    });
                    tcs.SetResult(false);
                    return;
                }
                authenticator.Authenticated += sender =>
                {
                    RestartXmlStreams();
                    var session             = new SessionHandler();
                    session.SessionStarted += connection =>
                    {
                        OnSignedIn(new SignedInArgs {
                            Jid = connection.Jid
                        });
                        tcs.SetResult(true);
                    };
                    // TODO make async
                    // Locks stream with SessionLoop
                    session.Start(this);
                };
                authenticator.AuthenticationFailed += sender =>
                {
                    OnConnectionFailed(new ConnFailedArgs {
                        Message = "Authentication failed"
                    });
                    tcs.SetResult(true);
                };
                authenticator.Start(this);
            });
            return(tcs.Task);
        }
        public override async void Connect()
        {
            List <IPAddress> HostAddresses = new List <IPAddress>();

            var srvs = await Resolver.ResolveXMPPClient(Jid.Domain);

            if (srvs.Any())
            {
                foreach (var srv in srvs)
                {
                    var addresses = await Dns.GetHostAddressesAsync(srv.Host);

                    HostAddresses.AddRange(addresses);
                }
            }
            else
            {
                HostAddresses.AddRange(await Dns.GetHostAddressesAsync(Jid.Domain));
            }
            _client = new TcpClient();
            await _client.ConnectAsync(HostAddresses.ToArray(), TcpPort); // TODO: check ports

            ConnectionStream = _client.GetStream();
            Iq += (sender, iq) => new IqManager(this)
            {
                PayloadHandlers = new List <PayloadHandler>
                {
                    new InfoHandler(Capabilities),
                    new ItemsHandler()
                }
            }.Handle(iq);
            RestartXmlStreams();
            var features = Stanza.Parse <Features>(NextElement());

            if (features.Tls)
            {
                Send(new StartTLS());
                var res = Stanza.Parse <Proceed>(NextElement());
                if (res != null)
                {
                    ConnectionStream = new SslStream(ConnectionStream, true);
                    await((SslStream)ConnectionStream).AuthenticateAsClientAsync(Jid.Domain);
                    RestartXmlStreams();
                    features = Stanza.Parse <Features>(NextElement());
                }
            }

            var authenticator = SASLHandler.Create(features.SaslMechanisms, Jid, Password);

            if (authenticator == null)
            {
                OnConnectionFailed(new ConnFailedArgs {
                    Message = "supported sasl mechanism not available"
                });
                return;
            }
            authenticator.Authenticated += sender =>
            {
                RestartXmlStreams();
                var session = new SessionHandler();
                session.SessionStarted += connection => OnSignedIn(new SignedInArgs {
                    Jid = connection.Jid
                });
                session.Start(this);
            };
            authenticator.AuthenticationFailed += sender =>
            {
                OnConnectionFailed(new ConnFailedArgs {
                    Message = "Authentication failed"
                });
                return;
            };
            authenticator.Start(this);
        }
        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();
            }));
        }
Example #4
0
        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");
                    }
                }
            };
        }