/// <summary> /// Called once the connection timer got triggered. /// </summary> private async Task OnConnetionTimerTimeoutAsync() { string errorMessage = "Connection timeout got triggered for account: " + account.getBareJid(); Logger.Warn(LOGGER_TAG + errorMessage); lastConnectionError = new ConnectionError(ConnectionErrorCode.XMPP_CONNECTION_TIMEOUT, errorMessage); await OnConnectionErrorAsync(); }
/// <summary> /// Called once the connection timer got triggered. /// </summary> private async Task onConnetionTimerTimeoutAsync() { string errorMessage = "Connection timeout got triggered for account: " + account.getIdAndDomain(); Logger.Warn(errorMessage); lastConnectionError = new ConnectionError(ConnectionErrorCode.XMPP_CONNECTION_TIMEOUT, errorMessage); await onConnectionErrorAsync(); }
private async void TCPConnection_ConnectionStateChanged(AbstractConnection2 connection, ConnectionStateChangedEventArgs args) { switch (args.newState) { case ConnectionState.CONNECTED: // TCP connection established start reading: TCP_CONNECTION.startReaderTask(); // Send initial stream header: await softRestartAsync(); break; case ConnectionState.ERROR: if (args.param is ConnectionError cError) { lastConnectionError = cError; } if (args.oldState == ConnectionState.CONNECTED) { switch (state) { case ConnectionState.CONNECTING: case ConnectionState.CONNECTED: await onConnectionErrorAsync(); break; case ConnectionState.DISCONNECTING: setState(ConnectionState.DISCONNECTED); break; } } else { // Unable to connect to server: connectionErrorCount = 3; await internalDisconnectAsync(); setState(ConnectionState.ERROR, args.param); } break; case ConnectionState.DISCONNECTED when holdConnection: await reconnectAsync(false); break; } }
//--------------------------------------------------------Set-, Get- Methods:---------------------------------------------------------\\ #region --Set-, Get- Methods-- protected override void setState(ConnectionState newState, object param) { base.setState(newState, param); switch (newState) { case ConnectionState.DISCONNECTED: onDisconnected(); break; case ConnectionState.CONNECTED: // Reset last error message: lastConnectionError = null; break; } }
//--------------------------------------------------------Constructor:----------------------------------------------------------------\\ #region --Constructors-- /// <summary> /// Basic Constructor /// </summary> /// <history> /// 05/05/2018 Created [Fabian Sauter] /// </history> public XMPPConnection2(XMPPAccount account) : base(account) { this.holdConnection = false; this.connectionErrorCount = 0; this.lastConnectionError = null; this.TCP_CONNECTION = new TCPConnection2(account); this.TCP_CONNECTION.ConnectionStateChanged += TCPConnection_ConnectionStateChanged; this.TCP_CONNECTION.NewDataReceived += TCPConnection_NewDataReceived; this.PARSER = new MessageParser2(); this.MESSAGE_PROCESSORS = new AbstractMessageProcessor[4]; this.streamId = null; this.messageIdCache = new TSTimedList <string>(); this.connectionTimer = null; this.reconnectRequested = false; this.timeout = TimeSpan.FromMilliseconds(CONNECTION_TIMEOUT); this.GENERAL_COMMAND_HELPER = new GeneralCommandHelper(this); this.MUC_COMMAND_HELPER = new MUCCommandHelper(this); this.PUB_SUB_COMMAND_HELPER = new PubSubCommandHelper(this); this.OMEMO_COMMAND_HELPER = new OmemoCommandHelper(this); // The order in which new messages should get processed (TLS -- SASL -- Stream Management -- Resource binding -- ...). // https://xmpp.org/extensions/xep-0170.html //------------------------------------------------------------- // TLS: this.MESSAGE_PROCESSORS[0] = new TLSConnection(TCP_CONNECTION, this); // SASL: this.MESSAGE_PROCESSORS[1] = new SASLConnection(TCP_CONNECTION, this); // XEP-0198 (Stream Management): this.MESSAGE_PROCESSORS[2] = new SMConnection(TCP_CONNECTION, this); // Resource binding: RecourceBindingConnection recourceBindingConnection = new RecourceBindingConnection(TCP_CONNECTION, this); recourceBindingConnection.ResourceBound += RecourceBindingConnection_ResourceBound; this.MESSAGE_PROCESSORS[3] = recourceBindingConnection; //------------------------------------------------------------- NetworkHelper.Instance.NetworkChanged += Instance_NetworkChanged; this.omemoHelper = null; this.DISCO_FEATURE_HELPER = new DiscoFeatureHelper(this); }
/// <summary> /// Connects to the XMPP server. /// </summary> private async Task connectAsync() { if (!NetworkHelper.Instance.ConnectionInformation.IsInternetAvailable) { connectionErrorCount = 3; lastConnectionError = new ConnectionError(ConnectionErrorCode.NO_INTERNET); setState(ConnectionState.ERROR, lastConnectionError); reconnectRequested = false; holdConnection = false; Logger.Warn("[XMPPConnection2]: Unable to connect to " + account.serverAddress + " - no internet!"); return; } switch (state) { case ConnectionState.DISCONNECTED: case ConnectionState.ERROR: if (connectionErrorCount < 3) { setState(ConnectionState.CONNECTING); // Reset stuff: streamId = null; messageIdCache = new TSTimedList <string>(); resetMessageProcessors(); await TCP_CONNECTION.connectAsync(); } break; default: Logger.Warn("[XMPPConnection2]: Trying to connect but state is not " + ConnectionState.DISCONNECTED + " or " + ConnectionState.ERROR + "! State = " + state); await reconnectAsync(false); break; } }
/// <summary> /// Parses the given messages and invokes the ConnectionNewValidMessage event for each message. /// </summary> /// <param name="data">The messages string to parse.</param> private async Task ParseMessageAsync(string data) { // Parse message: List <AbstractMessage> messages = null; try { messages = PARSER.parseMessages(ref data); } catch (Exception e) { Logger.Error("[XMPPConnection2]: Error during message parsing." + e); return; } // Process messages: foreach (AbstractMessage msg in messages) { // Stream error messages: if (msg is StreamErrorMessage errorMessage) { Logger.Warn("[XMPPConnection2]: Received stream error message: " + errorMessage.ToString()); lastConnectionError = new ConnectionError(ConnectionErrorCode.SERVER_ERROR, errorMessage.ToString()); await OnConnectionErrorAsync(); await SendStreamCloseMessageAsync(); return; } // Filter IQ messages which ids are not valid: if (msg is IQMessage iq) { if (iq.GetType().Equals(IQMessage.RESULT) && messageIdCache.GetTimed(iq.ID) != null) { Logger.Warn("[XMPPConnection2]: Invalid message id received!"); return; } } // Respond to XEP-0199 (XMPP Ping) messages: if (msg is PingMessage pingMsg) { Logger.Debug("[XMPPConnection2]: XMPP ping received from " + pingMsg.getFrom()); await SendAsync(pingMsg.generateResponse(), true); } // Invoke message processors: NewValidMessage?.Invoke(this, new NewValidMessageEventArgs(msg)); // Should restart connection? if (msg.getRestartConnection() != AbstractMessage.NO_RESTART) { if (msg.getRestartConnection() == AbstractMessage.SOFT_RESTART) { await SoftRestartAsync(); } else if (msg.getRestartConnection() == AbstractMessage.HARD_RESTART) { await HardRestartAsync(); } else { throw new ArgumentException("[XMPPConnection2]: Invalid restart type: " + msg.getRestartConnection()); } } // Filter already processed messages: if (msg.isProcessed()) { return; } // -------------------------------------------------------------------- // Open stream: if (msg is OpenStreamAnswerMessage oA) { if (oA.ID is null) { // TODO Handle OpenStreamAnswerMessage id is null //Error throw exception?! return; } } // Close stream message: else if (msg is CloseStreamMessage) { switch (state) { case ConnectionState.CONNECTING: case ConnectionState.CONNECTED: await InternalDisconnectAsync(false); break; } } // Rooster: else if (msg is RosterResultMessage) { NewRoosterMessage?.Invoke(this, new NewValidMessageEventArgs(msg)); } // Presence: else if (msg is PresenceMessage presenceMessage && !(presenceMessage.getFrom() is null)) { NewPresenceMessage?.Invoke(this, new NewValidMessageEventArgs(msg)); }