/** * Notification message saying that the server supports TLS so confirm the server that we want to * secure the connection. * * @param required true when the server indicates that TLS is required. */ void startTLSReceived(boolean required) { if (required && config.getSecurityMode() == ConnectionConfiguration.SecurityMode.disabled) { packetReader.notifyConnectionError( new IllegalStateException( "TLS required by server but not allowed by connection configuration")); return; } if (required && usingSSL) { packetReader.notifyConnectionError( new IllegalStateException("TLS required by server but legacy SSL already enabled")); return; } if ((config.getSecurityMode() == ConnectionConfiguration.SecurityMode.disabled) || (config.getSecurityMode() == ConnectionConfiguration.SecurityMode.legacy)) { // Do not secure the connection using TLS since TLS was disabled or we are using SSL. return; } try { writer.write("<starttls xmlns=\"urn:ietf:params:xml:ns:xmpp-tls\"/>"); writer.flush(); } catch (IOException e) { packetReader.notifyConnectionError(e); } }
/** * Closes the connection by setting presence to unavailable then closing the stream to the XMPP * server. The shutdown logic will be used during a planned disconnection or when dealing with an * unexpected disconnection. Unlike {@link #disconnect()} the connection's packet reader, packet * writer, and {@link Roster} will not be removed; thus connection's state is kept. * * @param unavailablePresence the presence packet to send during shutdown. */ protected void shutdown(Presence unavailablePresence) { // Set presence to offline. PacketWriter packetWriter = this.packetWriter; if (packetWriter != null) { packetWriter.sendPacket(unavailablePresence); } this.setWasAuthenticated(authenticated); authenticated = false; connected = false; PacketReader packetReader = this.packetReader; if (packetReader != null) { packetReader.shutdown(); } packetWriter = this.packetWriter; if (packetWriter != null) { packetWriter.shutdown(); } // Wait 150 ms for processes to clean-up, then shutdown. try { Thread.sleep(150); } catch (Exception e) { // Ignore. } // Close down the readers and writers. Reader reader = this.reader; if (reader != null) { try { reader.close(); } catch (Throwable ignore) { /* ignore */ } this.reader = null; } Writer writer = this.writer; if (writer != null) { try { writer.close(); } catch (Throwable ignore) { /* ignore */ } this.writer = null; } try { socket.close(); } catch (Exception e) { // Ignore. } saslAuthentication.init(); }
/** * Request the server that we want to start using stream compression. When using TLS then * negotiation of stream compression can only happen after TLS was negotiated. If TLS compression * is being used the stream compression should not be used. */ private void requestStreamCompression() { try { writer.write("<compress xmlns='http://jabber.org/protocol/compress'>"); writer.write("<method>zlib</method></compress>"); writer.flush(); } catch (IOException e) { packetReader.notifyConnectionError(e); } }
public void disconnect(Presence unavailablePresence) { // If not connected, ignore this request. PacketReader packetReader = this.packetReader; PacketWriter packetWriter = this.packetWriter; if (packetReader == null || packetWriter == null) { return; } shutdown(unavailablePresence); if (roster != null) { roster.cleanup(); roster = null; } chatManager = null; wasAuthenticated = false; packetWriter.cleanup(); this.packetWriter = null; packetReader.cleanup(); this.packetReader = null; }
/** * Establishes a connection to the XMPP server and performs an automatic login only if the * previous connection state was logged (authenticated). It basically creates and maintains a * socket connection to the server. * * <p> * * <p>Listeners will be preserved from a previous connection if the reconnection occurs after an * abrupt termination. * * @throws XMPPException if an error occurs while trying to establish the connection. Two possible * errors can occur which will be wrapped by an XMPPException -- UnknownHostException (XMPP * error code 504), and IOException (XMPP error code 502). The error codes and wrapped * exceptions can be used to present more appropiate error messages to end-users. */ public void connect() throws XMPPException { // Stablishes the connection, readers and writers connectUsingConfiguration(config); // Automatically makes the login if the user was previouslly connected successfully // to the server and the connection was terminated abruptly if (connected && wasAuthenticated) { // Make the login try { if (isAnonymous()) { // Make the anonymous login loginAnonymously(); } else { login(config.getUsername(), config.getPassword(), config.getResource()); } packetReader.notifyReconnection(); } catch (XMPPException e) { e.printStackTrace(); } } }
/** * Initializes the connection by creating a packet reader and writer and opening a XMPP stream to * the server. * * @throws XMPPException if establishing a connection to the server fails. */ private void initConnection() throws XMPPException { PacketReader packetReader = this.packetReader; PacketWriter packetWriter = this.packetWriter; boolean isFirstInitialization = packetReader == null || packetWriter == null; usingCompression = false; // Set the reader and writer instance variables initReaderAndWriter(); try { if (isFirstInitialization) { this.packetWriter = packetWriter = new PacketWriter(this); this.packetReader = packetReader = new PacketReader(this); // If debugging is enabled, we should start the thread that will listen for // all packets and then log them. if (config.isDebuggerEnabled()) { addPacketListener(debugger.getReaderListener(), null); if (debugger.getWriterListener() != null) { addPacketSendingListener(debugger.getWriterListener(), null); } } } else { packetWriter.init(); packetReader.init(); } // Start the packet writer. This will open a XMPP stream to the server packetWriter.startup(); // Start the packet reader. The startup() method will block until we // get an opening stream packet back from server. packetReader.startup(); // Make note of the fact that we're now connected. connected = true; // Start keep alive process (after TLS was negotiated - if available) packetWriter.startKeepAliveProcess(); if (isFirstInitialization) { // Notify listeners that a new connection has been established for (ConnectionCreationListener listener : getConnectionCreationListeners()) { listener.connectionCreated(this); } } else if (!wasAuthenticated) { packetReader.notifyReconnection(); } } catch (XMPPException ex) { // An exception occurred in setting up the connection. Make sure we shut down the // readers and writers and close the socket. if (packetWriter != null) { try { packetWriter.shutdown(); } catch (Throwable ignore) { /* ignore */ } this.packetWriter = null; } if (packetReader != null) { try { packetReader.shutdown(); } catch (Throwable ignore) { /* ignore */ } this.packetReader = null; } if (reader != null) { try { reader.close(); } catch (Throwable ignore) { /* ignore */ } reader = null; } if (writer != null) { try { writer.close(); } catch (Throwable ignore) { /* ignore */ } writer = null; } if (socket != null) { try { socket.close(); } catch (Exception e) { /* ignore */ } socket = null; } this.setWasAuthenticated(authenticated); chatManager = null; authenticated = false; connected = false; throw ex; // Everything stoppped. Now throw the exception. } }