diff --git a/ConnectionManager.iml b/ConnectionManager.iml index 90f2de7..95c0b9b 100644 --- a/ConnectionManager.iml +++ b/ConnectionManager.iml @@ -8,6 +8,7 @@ + @@ -45,7 +46,9 @@ - + + + @@ -54,7 +57,11 @@ - + + + + + @@ -102,6 +109,66 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/build/lib/merge/xpp3.jar b/build/lib/merge/xpp3.jar index c9822e6..451ac82 100644 --- a/build/lib/merge/xpp3.jar +++ b/build/lib/merge/xpp3.jar Binary files differ diff --git a/build/lib/versions.txt b/build/lib/versions.txt index da0365f..f5f9027 100644 --- a/build/lib/versions.txt +++ b/build/lib/versions.txt @@ -15,4 +15,4 @@ pack200task.jar | August 5, 2004 servlet-api.jar | 2.5-6.0.1 xmltask.jar | 1.11 -xpp3.jar | XPP_3 1.1.3.8 \ No newline at end of file +xpp3.jar | XPP_3 1.1.4c \ No newline at end of file diff --git a/src/conf/manager.xml b/src/conf/manager.xml index 1849d54..5c7c397 100644 --- a/src/conf/manager.xml +++ b/src/conf/manager.xml @@ -25,7 +25,7 @@ This property is optional. A random name is generated if none was defined. --> - 5 + 1 5 @@ -73,7 +73,34 @@ + + + 50 + + + -1 + + -1 + + + -1 + + + + + + + + false diff --git a/src/java/org/dom4j/io/XMPPPacketReader.java b/src/java/org/dom4j/io/XMPPPacketReader.java index d0b3d79..31e381f 100644 --- a/src/java/org/dom4j/io/XMPPPacketReader.java +++ b/src/java/org/dom4j/io/XMPPPacketReader.java @@ -273,23 +273,6 @@ return lastActive > lastHeartbeat ? lastActive : lastHeartbeat; } - /* - * DANIELE: Add parse document by string - */ - public Document parseDocument(String xml) throws DocumentException { - /* - // Long way with reuse of DocumentFactory. - DocumentFactory df = getDocumentFactory(); - SAXReader reader = new SAXReader( df ); - Document document = reader.read( new StringReader( xml );*/ - - // Simple way - // TODO Optimize. Do not create a sax reader for each parsing - Document document = DocumentHelper.parseText(xml); - - return document; - } - // Implementation methods //------------------------------------------------------------------------- public Document parseDocument() throws DocumentException, IOException, XmlPullParserException { diff --git a/src/java/org/jivesoftware/multiplexer/ClientSession.java b/src/java/org/jivesoftware/multiplexer/ClientSession.java index 9c6221b..15f6bf6 100644 --- a/src/java/org/jivesoftware/multiplexer/ClientSession.java +++ b/src/java/org/jivesoftware/multiplexer/ClientSession.java @@ -12,13 +12,9 @@ package org.jivesoftware.multiplexer; import org.dom4j.Element; -import org.dom4j.io.XMPPPacketReader; -import org.jivesoftware.multiplexer.net.SocketConnection; -import org.jivesoftware.multiplexer.net.SocketReader; import org.jivesoftware.multiplexer.spi.ClientFailoverDeliverer; import org.jivesoftware.util.LocaleUtils; import org.jivesoftware.util.Log; -import org.jivesoftware.util.JiveGlobals; import org.xmlpull.v1.XmlPullParser; import org.xmlpull.v1.XmlPullParserException; @@ -32,30 +28,8 @@ private static final String ETHERX_NAMESPACE = "http://etherx.jabber.org/streams"; private static final String FLASH_NAMESPACE = "http://www.jabber.com/streams/flash"; - /** - * Milliseconds a connection has to be idle to be closed. Default is 30 minutes. Sending - * stanzas to the client is not considered as activity. We are only considering the connection - * active when the client sends some data or hearbeats (i.e. whitespaces) to the server. - * The reason for this is that sending data will fail if the connection is closed. And if - * the thread is blocked while sending data (because the socket is closed) then the clean up - * thread will close the socket anyway. - */ - private static long idleTimeout; - - /** - * Socket reader that is processing incoming packets from the client. - */ - private SocketReader socketReader; - - static { - // Set the default read idle timeout. If none was set then assume 30 minutes - idleTimeout = JiveGlobals.getIntProperty("xmpp.client.idle", 30 * 60 * 1000); - } - - public static Session createSession(String serverName, SocketReader socketReader, - XMPPPacketReader reader, SocketConnection connection) + public static Session createSession(String serverName, XmlPullParser xpp, Connection connection) throws XmlPullParserException { - XmlPullParser xpp = reader.getXPPParser(); boolean isFlashClient = xpp.getPrefix().equals("flash"); connection.setFlashClient(isFlashClient); @@ -125,17 +99,20 @@ // Indicate the compression policy to use for this connection connection.setCompressionPolicy(serverSurrogate.getCompressionPolicy()); - // Set the max number of milliseconds the connection may not receive data from the - // client before closing the connection - connection.setIdleTimeout(idleTimeout); - // Create a ClientSession for this user. String streamID = idFactory.createStreamID(); ClientSession session = new ClientSession(serverName, connection, streamID); connection.init(session); - session.socketReader = socketReader; // Set the stream ID that identifies the client when forwarding traffic to a client fails ((ClientFailoverDeliverer) connection.getPacketDeliverer()).setStreamID(streamID); + // Listen when the connection is closed + connection.registerCloseListener(new ConnectionCloseListener() { + public void onConnectionClose(Object handback) { + ClientSession session = (ClientSession) handback; + // Mark the session as closed + session.close(false); + } + }, session); // Register that the new session is associated with the specified stream ID Session.addSession(streamID, session); // Send to the server that a new client session has been created @@ -207,13 +184,13 @@ } StringBuilder sb = new StringBuilder(200); - + // TODO Fix compression with MINA and re-enable this code // Include Stream Compression Mechanism - if (conn.getCompressionPolicy() != Connection.CompressionPolicy.disabled && + /*if (conn.getCompressionPolicy() != Connection.CompressionPolicy.disabled && !conn.isCompressed()) { sb.append( "zlib"); - } + }*/ if (getStatus() != Session.STATUS_AUTHENTICATED) { ServerSurrogate serverSurrogate = ConnectionManager.getInstance().getServerSurrogate(); @@ -247,16 +224,14 @@ if ("success".equals(tag)) { // Session has been authenticated (using SASL). Update status setStatus(Session.STATUS_AUTHENTICATED); - // Notify the socket reader that sasl authentication has finished - socketReader.clientAuthenticated(true); } else if ("failure".equals(tag)) { - // Notify the socket reader that sasl authentication has finished - socketReader.clientAuthenticated(false); + // Sasl authentication has failed + // Ignore for now } else if ("challenge".equals(tag)) { - // Notify the socket reader that client needs to respond to challenge - socketReader.clientChallenged(); + // A challenge was sent to the client. Client needs to respond + // Ignore for now } } // Deliver stanza to client @@ -284,6 +259,8 @@ */ public void close(boolean systemStopped) { if (status != STATUS_CLOSED) { + // Change the status to closed + status = STATUS_CLOSED; // Close the connection of the client if (systemStopped) { conn.systemShutdown(); @@ -291,8 +268,6 @@ else { conn.close(); } - // Changhe the status to closed - status = STATUS_CLOSED; // Remove session from list of sessions removeSession(getStreamID()); // Tell the server that the client session has been closed diff --git a/src/java/org/jivesoftware/multiplexer/Connection.java b/src/java/org/jivesoftware/multiplexer/Connection.java index 6fbface..a5aa158 100644 --- a/src/java/org/jivesoftware/multiplexer/Connection.java +++ b/src/java/org/jivesoftware/multiplexer/Connection.java @@ -32,9 +32,25 @@ public boolean validate(); /** + * Registers a new listener that will react when this connection is closed. + * + * @param listener the new listener. + * @param handbackMessage the object to send back when notifying that the connection was closed. + */ + public void registerCloseListener(ConnectionCloseListener listener, Object handbackMessage); + + /** + * Removes a listener that was reacting when this connection was closed. + * + * @param listener the listener to remove. + */ + public void removeCloseListener(ConnectionCloseListener listener); + + /** * Returns the InetAddress describing the connection. * * @return the InetAddress describing the underlying connection properties. + * @throws java.net.UnknownHostException if IP address of host could not be determined. */ public InetAddress getInetAddress() throws UnknownHostException; @@ -102,6 +118,16 @@ public boolean isFlashClient(); /** + * Sets whether the connected client is a flash client. Flash clients need to + * receive a special character (i.e. \0) at the end of each xml packet. Flash + * clients may send the character \0 in incoming packets and may start a + * connection using another openning tag such as: "flash:client". + * + * @param flashClient true if the if the connection is a flash client. + */ + public void setFlashClient(boolean flashClient); + + /** * Returns the major version of XMPP being used by this connection * (major_version.minor_version. In most cases, the version should be * "1.0". However, older clients using the "Jabber" protocol do not set a @@ -122,6 +148,16 @@ public int getMinorXMPPVersion(); /** + * Sets the XMPP version information. In most cases, the version should be "1.0". + * However, older clients using the "Jabber" protocol do not set a version. In that + * case, the version is "0.0". + * + * @param majorVersion the major version. + * @param minorVersion the minor version. + */ + public void setXMPPVersion(int majorVersion, int minorVersion); + + /** * Returns the language code that should be used for this connection * (e.g. "en"). * @@ -130,6 +166,13 @@ public String getLanguage(); /** + * Sets the language code that should be used for this connection (e.g. "en"). + * + * @param language the language code. + */ + public void setLanaguage(String language); + + /** * Returns true if the connection is using compression. * * @return true if the connection is using compression. @@ -144,6 +187,13 @@ CompressionPolicy getCompressionPolicy(); /** + * Sets whether compression is enabled or is disabled. + * + * @param compressionPolicy whether Compression is enabled or is disabled. + */ + void setCompressionPolicy(CompressionPolicy compressionPolicy); + + /** * Returns whether TLS is mandatory, optional or is disabled. When TLS is mandatory clients * are required to secure their connections or otherwise their connections will be closed. * On the other hand, when TLS is disabled clients are not allowed to secure their connections @@ -155,6 +205,54 @@ TLSPolicy getTlsPolicy(); /** + * Sets whether TLS is mandatory, optional or is disabled. When TLS is mandatory clients + * are required to secure their connections or otherwise their connections will be closed. + * On the other hand, when TLS is disabled clients are not allowed to secure their connections + * using TLS. Their connections will be closed if they try to secure the connection. in this + * last case. + * + * @param tlsPolicy whether TLS is mandatory, optional or is disabled. + */ + void setTlsPolicy(TLSPolicy tlsPolicy); + + /** + * Returns the packet deliverer to use when delivering a packet over the socket fails. The + * packet deliverer will retry to send the packet using some other connection, will store + * the packet offline for later retrieval or will just drop it. + * + * @return the packet deliverer to use when delivering a packet over the socket fails. + */ + PacketDeliverer getPacketDeliverer(); + + /** + * Secures the plain connection by negotiating TLS with the client. When connecting + * to a remote server then clientMode will be true and + * remoteServer is the server name of the remote server. Otherwise clientMode + * will be false and remoteServer null. + * + * @param clientMode boolean indicating if this entity is a client or a server. + * @param remoteServer server name of the remote server we are connecting to or null + * when not in client mode. + * @throws Exception if an error occured while securing the connection. + */ + void startTLS(boolean clientMode, String remoteServer) throws Exception; + + /** + * Start using compression for this connection. Compression will only be available after TLS + * has been negotiated. This means that a connection can never be using compression before + * TLS. However, it is possible to use compression without TLS. + */ + void startCompression(); + + /** + * Initializes the connection that is related to the specified session. The session is the + * only owner of this connection. + * + * @param session the Session that owns this connection. + */ + void init(Session session); + + /** * Enumeration of possible compression policies required to interact with the server. */ enum CompressionPolicy { diff --git a/src/java/org/jivesoftware/multiplexer/ConnectionManager.java b/src/java/org/jivesoftware/multiplexer/ConnectionManager.java index 93eee10..1c7ccf7 100644 --- a/src/java/org/jivesoftware/multiplexer/ConnectionManager.java +++ b/src/java/org/jivesoftware/multiplexer/ConnectionManager.java @@ -11,24 +11,39 @@ package org.jivesoftware.multiplexer; +import org.apache.mina.common.ExecutorThreadModel; +import org.apache.mina.filter.SSLFilter; +import org.apache.mina.filter.codec.ProtocolCodecFilter; +import org.apache.mina.transport.socket.nio.SocketAcceptor; +import org.apache.mina.transport.socket.nio.SocketAcceptorConfig; +import org.apache.mina.transport.socket.nio.SocketSessionConfig; import org.dom4j.Document; import org.dom4j.io.SAXReader; -import org.jivesoftware.multiplexer.net.SSLSocketAcceptThread; -import org.jivesoftware.multiplexer.net.SocketAcceptThread; +import org.jivesoftware.multiplexer.net.ClientConnectionHandler; +import org.jivesoftware.multiplexer.net.SSLConfig; import org.jivesoftware.multiplexer.net.SocketSendingTracker; +import org.jivesoftware.multiplexer.net.XMPPCodecFactory; import org.jivesoftware.multiplexer.net.http.HttpBindManager; import org.jivesoftware.util.*; +import javax.net.ssl.KeyManagerFactory; +import javax.net.ssl.SSLContext; +import javax.net.ssl.TrustManagerFactory; import java.io.File; import java.io.FileNotFoundException; import java.io.IOException; import java.io.InputStream; import java.lang.reflect.Method; import java.net.InetAddress; +import java.net.InetSocketAddress; import java.net.UnknownHostException; import java.util.ArrayList; import java.util.Date; import java.util.List; +import java.util.concurrent.Executor; +import java.util.concurrent.LinkedBlockingQueue; +import java.util.concurrent.ThreadPoolExecutor; +import java.util.concurrent.TimeUnit; /** * Connection managers handle connections of clients that want to connect to a server. Each @@ -101,8 +116,8 @@ "org.tanukisoftware.wrapper.WrapperManager"; private ServerSurrogate serverSurrogate; - private SocketAcceptThread socketThread; - private SSLSocketAcceptThread sslSocketThread; + private SocketAcceptor socketAcceptor; + private SocketAcceptor sslSocketAcceptor; private HttpBindManager httpBindManager; /** @@ -255,6 +270,8 @@ } private void startClientListeners(String localIPAddress) { + // TODO Does MINA uses MAX_PRIORITY for threads? + // TODO Are threads running as daemon? Can we stop de server? // Start clients plain socket unless it's been disabled. int port = 5222; // Check if old property is being used for storing c2s port @@ -265,16 +282,32 @@ else if (JiveGlobals.getXMLProperty("xmpp.socket.default.port") != null) { port = JiveGlobals.getIntProperty("xmpp.socket.default.port", 5222); } - ServerPort serverPort = new ServerPort(port, serverName, localIPAddress, - false, null, ServerPort.Type.client); + // Create SocketAcceptor with correct number of processors + socketAcceptor = buildSocketAcceptor(); + // Customize Executor that will be used by processors to process incoming stanzas + ExecutorThreadModel threadModel = ExecutorThreadModel.getInstance("client"); + int eventThreads = JiveGlobals.getIntProperty("xmpp.processor.threads.standard", 16); + Executor eventExecutor = new ThreadPoolExecutor( + eventThreads + 1, eventThreads + 1, 60, TimeUnit.SECONDS, new LinkedBlockingQueue() ); + threadModel.setExecutor(eventExecutor); + socketAcceptor.getDefaultConfig().setThreadModel(threadModel); + // Add the XMPP codec filter + socketAcceptor.getFilterChain().addFirst("xmpp", new ProtocolCodecFilter(new XMPPCodecFactory())); + try { - socketThread = new SocketAcceptThread(serverPort); - //socketThread.setDaemon(true); - socketThread.setPriority(Thread.MAX_PRIORITY); - socketThread.start(); + // Listen on a specific network interface if it has been set. + String interfaceName = JiveGlobals.getXMLProperty("xmpp.socket.network.interface"); + InetAddress bindInterface = null; + if (interfaceName != null) { + if (interfaceName.trim().length() > 0) { + bindInterface = InetAddress.getByName(interfaceName); + } + } + // Start accepting connections + socketAcceptor.bind(new InetSocketAddress(bindInterface, port), new ClientConnectionHandler()); List params = new ArrayList(); - params.add(Integer.toString(socketThread.getPort())); + params.add(Integer.toString(port)); Log.info(LocaleUtils.getLocalizedString("startup.plain", params)); } catch (Exception e) { @@ -285,9 +318,9 @@ } private void stopClientListeners() { - if (socketThread != null) { - socketThread.shutdown(); - socketThread = null; + if (socketAcceptor != null) { + socketAcceptor.unbindAll(); + socketAcceptor = null; } } @@ -298,16 +331,45 @@ if ("".equals(algorithm) || algorithm == null) { algorithm = "TLS"; } - ServerPort serverPort = new ServerPort(port, serverName, localIPAddress, - true, algorithm, ServerPort.Type.client); + // Create SocketAcceptor with correct number of processors + sslSocketAcceptor = buildSocketAcceptor(); + // Customize thread model for c2s (old ssl port) + ExecutorThreadModel threadModel = ExecutorThreadModel.getInstance("client_ssl"); + int eventThreads = JiveGlobals.getIntProperty("xmpp.processor.threads.ssl", 16); + Executor eventExecutor = new ThreadPoolExecutor( + eventThreads + 1, eventThreads + 1, 60, TimeUnit.SECONDS, new LinkedBlockingQueue() ); + threadModel.setExecutor(eventExecutor); + sslSocketAcceptor.getDefaultConfig().setThreadModel(threadModel); + // Add the XMPP codec filter + sslSocketAcceptor.getFilterChain().addFirst("xmpp", new ProtocolCodecFilter(new XMPPCodecFactory())); + try { - sslSocketThread = new SSLSocketAcceptThread(serverPort); - //sslSocketThread.setDaemon(true); - sslSocketThread.setPriority(Thread.MAX_PRIORITY); - sslSocketThread.start(); + // Add the SSL filter now since sockets are "borned" encrypted in the old ssl method + SSLContext sslContext = SSLContext.getInstance(algorithm); + KeyManagerFactory keyFactory = KeyManagerFactory.getInstance(KeyManagerFactory.getDefaultAlgorithm()); + keyFactory.init(SSLConfig.getKeyStore(), SSLConfig.getKeyPassword().toCharArray()); + TrustManagerFactory trustFactory = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm()); + trustFactory.init(SSLConfig.getTrustStore()); + + sslContext.init(keyFactory.getKeyManagers(), + trustFactory.getTrustManagers(), + new java.security.SecureRandom()); + + sslSocketAcceptor.getFilterChain().addFirst("tls", new SSLFilter(sslContext)); + + // Listen on a specific network interface if it has been set. + String interfaceName = JiveGlobals.getXMLProperty("xmpp.socket.network.interface"); + InetAddress bindInterface = null; + if (interfaceName != null) { + if (interfaceName.trim().length() > 0) { + bindInterface = InetAddress.getByName(interfaceName); + } + } + // Start accepting connections + sslSocketAcceptor.bind(new InetSocketAddress(bindInterface, port), new ClientConnectionHandler()); List params = new ArrayList(); - params.add(Integer.toString(sslSocketThread.getPort())); + params.add(Integer.toString(port)); Log.info(LocaleUtils.getLocalizedString("startup.ssl", params)); } catch (Exception e) { @@ -318,9 +380,9 @@ } private void stopClientSSLListeners() { - if (sslSocketThread != null) { - sslSocketThread.shutdown(); - sslSocketThread = null; + if (sslSocketAcceptor != null) { + sslSocketAcceptor.unbindAll(); + sslSocketAcceptor = null; } } @@ -488,6 +550,41 @@ return name; } + private SocketAcceptor buildSocketAcceptor() { + SocketAcceptor socketAcceptor; + // Create SocketAcceptor with correct number of processors + int ioThreads = JiveGlobals.getIntProperty("xmpp.processor.count", Runtime.getRuntime().availableProcessors()); + // Set the executor that processors will use. Note that processors will use another executor + // for processing events (i.e. incoming traffic) + Executor ioExecutor = new ThreadPoolExecutor( + ioThreads + 1, ioThreads + 1, 60, TimeUnit.SECONDS, new LinkedBlockingQueue() ); + socketAcceptor = new SocketAcceptor(ioThreads, ioExecutor); + // Set that it will be possible to bind a socket if there is a connection in the timeout state + SocketAcceptorConfig socketAcceptorConfig = (SocketAcceptorConfig) socketAcceptor.getDefaultConfig(); + socketAcceptorConfig.setReuseAddress(true); + // Set the listen backlog (queue) length. Default is 50. + socketAcceptorConfig.setBacklog(JiveGlobals.getIntProperty("xmpp.socket.backlog", 50)); + + // Set default (low level) settings for new socket connections + SocketSessionConfig socketSessionConfig = socketAcceptorConfig.getSessionConfig(); + //socketSessionConfig.setKeepAlive(); + int receiveBuffer = JiveGlobals.getIntProperty("xmpp.socket.buffer.receive", -1); + if (receiveBuffer > 0 ) { + socketSessionConfig.setReceiveBufferSize(receiveBuffer); + } + int sendBuffer = JiveGlobals.getIntProperty("xmpp.socket.buffer.send", -1); + if (sendBuffer > 0 ) { + socketSessionConfig.setSendBufferSize(sendBuffer); + } + int linger = JiveGlobals.getIntProperty("xmpp.socket.linger", -1); + if (linger > 0 ) { + socketSessionConfig.setSoLinger(linger); + } + socketSessionConfig.setTcpNoDelay( + JiveGlobals.getBooleanProperty("xmpp.socket.tcp-nodelay", socketSessionConfig.isTcpNoDelay())); + return socketAcceptor; + } + /** * Verifies that the given home guess is a real Connection Manager home directory. * We do the verification by checking for the Connection Manager config file in diff --git a/src/java/org/jivesoftware/multiplexer/ConnectionWorkerThread.java b/src/java/org/jivesoftware/multiplexer/ConnectionWorkerThread.java index 54470a1..0e2fbea 100644 --- a/src/java/org/jivesoftware/multiplexer/ConnectionWorkerThread.java +++ b/src/java/org/jivesoftware/multiplexer/ConnectionWorkerThread.java @@ -18,7 +18,6 @@ import org.dom4j.io.XMPPPacketReader; import org.jivesoftware.multiplexer.net.DNSUtil; import org.jivesoftware.multiplexer.net.MXParser; -import org.jivesoftware.multiplexer.net.SocketAcceptThread; import org.jivesoftware.multiplexer.net.SocketConnection; import org.jivesoftware.multiplexer.spi.ServerFailoverDeliverer; import org.jivesoftware.util.JiveGlobals; @@ -50,6 +49,10 @@ * The utf-8 charset for decoding and encoding Jabber packet streams. */ private static String CHARSET = "UTF-8"; + /** + * The default XMPP port for connection multiplex. + */ + public static final int DEFAULT_MULTIPLEX_PORT = 5262; private static DocumentFactory docFactory = DocumentFactory.getInstance(); // Sequence and random number generator used for creating unique IQ ID's. @@ -121,7 +124,7 @@ private boolean createConnection() { String realHostname = null; int port = - JiveGlobals.getIntProperty("xmpp.port", SocketAcceptThread.DEFAULT_MULTIPLEX_PORT); + JiveGlobals.getIntProperty("xmpp.port", DEFAULT_MULTIPLEX_PORT); Socket socket = new Socket(); try { // Get the real hostname to connect to using DNS lookup of the specified hostname @@ -189,20 +192,6 @@ return false; } } - /*if (features != null && features.element("mechanisms") != null) { - // Try to authenticate with the server using SASL authentication - // TODO Compression should be done before SASL - if (!doSASLAuthentication(reader, openingStream)) { - // Failed to authenticate with the server - connection = null; - return false; - } - } - else { - // Server didn't offer SASL authentication - connection = null; - return false; - }*/ if (features != null && features.element("compression") != null) { // Try to use stream compression since the server supports it if (!compressConnection(reader, openingStream)) { diff --git a/src/java/org/jivesoftware/multiplexer/net/ServerTrustManager.java b/src/java/org/jivesoftware/multiplexer/net/ServerTrustManager.java index fa757ec..b386f86 100644 --- a/src/java/org/jivesoftware/multiplexer/net/ServerTrustManager.java +++ b/src/java/org/jivesoftware/multiplexer/net/ServerTrustManager.java @@ -7,6 +7,7 @@ package org.jivesoftware.multiplexer.net; +import org.jivesoftware.util.CertificateManager; import org.jivesoftware.util.JiveGlobals; import org.jivesoftware.util.Log; @@ -80,7 +81,7 @@ if (verify) { int nSize = x509Certificates.length; - List peerIdentities = TLSStreamHandler.getPeerIdentities(x509Certificates[0]); + List peerIdentities = CertificateManager.getPeerIdentities(x509Certificates[0]); if (JiveGlobals.getBooleanProperty("xmpp.server.certificate.verify.chain", true)) { // Working down the chain, for every certificate in the chain, diff --git a/src/java/org/jivesoftware/multiplexer/net/SocketConnection.java b/src/java/org/jivesoftware/multiplexer/net/SocketConnection.java index 189dafb..043d31d 100644 --- a/src/java/org/jivesoftware/multiplexer/net/SocketConnection.java +++ b/src/java/org/jivesoftware/multiplexer/net/SocketConnection.java @@ -29,8 +29,8 @@ import java.nio.channels.Channels; import java.util.Collection; import java.util.Date; -import java.util.Map; import java.util.HashMap; +import java.util.Map; import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.atomic.AtomicBoolean; @@ -145,17 +145,6 @@ return tlsStreamHandler; } - /** - * Secures the plain connection by negotiating TLS with the client. When connecting - * to a remote server then clientMode will be true and - * remoteServer is the server name of the remote server. Otherwise clientMode - * will be false and remoteServer null. - * - * @param clientMode boolean indicating if this entity is a client or a server. - * @param remoteServer server name of the remote server we are connecting to or null - * when not in client mode. - * @throws IOException if an error occured while securing the connection. - */ public void startTLS(boolean clientMode, String remoteServer) throws IOException { if (!secure) { secure = true; @@ -173,27 +162,26 @@ } } - /** - * Start using compression for this connection. Compression will only be available after TLS - * has been negotiated. This means that a connection can never be using compression before - * TLS. However, it is possible to use compression without TLS. - * - * @throws IOException if an error occured while starting compression. - */ - public void startCompression() throws IOException { + public void startCompression() { compressed = true; - if (tlsStreamHandler == null) { - ZOutputStream out = new ZOutputStream(socket.getOutputStream(), JZlib.Z_BEST_COMPRESSION); - out.setFlushMode(JZlib.Z_PARTIAL_FLUSH); - writer = new BufferedWriter(new OutputStreamWriter(out, CHARSET)); - xmlSerializer = new XMLSocketWriter(writer, this); - } - else { - ZOutputStream out = new ZOutputStream(tlsStreamHandler.getOutputStream(), JZlib.Z_BEST_COMPRESSION); - out.setFlushMode(JZlib.Z_PARTIAL_FLUSH); - writer = new BufferedWriter(new OutputStreamWriter(out, CHARSET)); - xmlSerializer = new XMLSocketWriter(writer, this); + try { + if (tlsStreamHandler == null) { + ZOutputStream out = new ZOutputStream(socket.getOutputStream(), JZlib.Z_BEST_COMPRESSION); + out.setFlushMode(JZlib.Z_PARTIAL_FLUSH); + writer = new BufferedWriter(new OutputStreamWriter(out, CHARSET)); + xmlSerializer = new XMLSocketWriter(writer, this); + } + else { + ZOutputStream out = new ZOutputStream(tlsStreamHandler.getOutputStream(), JZlib.Z_BEST_COMPRESSION); + out.setFlushMode(JZlib.Z_PARTIAL_FLUSH); + writer = new BufferedWriter(new OutputStreamWriter(out, CHARSET)); + xmlSerializer = new XMLSocketWriter(writer, this); + } + } catch (IOException e) { + // TODO Would be nice to still be able to throw the exception and not catch it here + Log.error("Error while starting compression", e); + compressed = false; } } @@ -228,19 +216,17 @@ session = owner; } - public Object registerCloseListener(ConnectionCloseListener listener, Object handbackMessage) { - Object status = null; + public void registerCloseListener(ConnectionCloseListener listener, Object handbackMessage) { if (isClosed()) { listener.onConnectionClose(handbackMessage); } else { - status = listeners.put(listener, handbackMessage); + listeners.put(listener, handbackMessage); } - return status; } - public Object removeCloseListener(ConnectionCloseListener listener) { - return listeners.remove(listener); + public void removeCloseListener(ConnectionCloseListener listener) { + listeners.remove(listener); } public InetAddress getInetAddress() { @@ -374,13 +360,6 @@ return null; } - /** - * Returns the packet deliverer to use when delivering a packet over the socket fails. The - * packet deliverer will retry to send the packet using some other connection, will store - * the packet offline for later retrieval or will just drop it. - * - * @return the packet deliverer to use when delivering a packet over the socket fails. - */ public PacketDeliverer getPacketDeliverer() { return backupDeliverer; }