diff --git a/src/java/org/jivesoftware/multiplexer/ServerPort.java b/src/java/org/jivesoftware/multiplexer/ServerPort.java deleted file mode 100644 index 034445d..0000000 --- a/src/java/org/jivesoftware/multiplexer/ServerPort.java +++ /dev/null @@ -1,138 +0,0 @@ -/** - * $RCSfile$ - * $Revision: $ - * $Date: $ - * - * Copyright (C) 2006 Jive Software. All rights reserved. - * - * This software is published under the terms of the GNU Public License (GPL), - * a copy of which is included in this distribution. - */ - -package org.jivesoftware.multiplexer; - -import java.util.ArrayList; -import java.util.Iterator; - -/** - * Represents a port on which the server will listen for connections. - * Used to aggregate information that the rest of the system needs - * regarding the port while hiding implementation details. - * - * @author Iain Shigeoka - */ -public class ServerPort { - - private int port; - private ArrayList names; - private String address; - private boolean secure; - private String algorithm; - private Type type; - - public ServerPort(int port, String name, String address, - boolean isSecure, String algorithm, Type type) - { - this.port = port; - this.names = new ArrayList(1); - this.names.add(name); - this.address = address; - this.secure = isSecure; - this.algorithm = algorithm; - this.type = type; - } - - /** - * Returns the port number that is being used. - * - * @return the port number this server port is listening on. - */ - public int getPort() { - return port; - } - - /** - * Returns the logical domains for this server port. As multiple - * domains may point to the same server, this helps to define what - * the server considers "local". - * - * @return the server domain name(s) as Strings. - */ - public Iterator getDomainNames() { - return names.iterator(); - } - - /** - * Returns the dot separated IP address for the server. - * - * @return The dot separated IP address for the server - */ - public String getIPAddress() { - return address; - } - - /** - * Determines if the connection is secure. - * - * @return True if the connection is secure - */ - public boolean isSecure() { - return secure; - } - - /** - * Returns the basic protocol/algorithm being used to secure - * the port connections. An example would be "SSL" or "TLS". - * - * @return The protocol used or null if this is not a secure server port - */ - public String getSecurityType() { - return algorithm; - } - - /** - * Returns true if other servers can connect to this port for s2s communication. - * - * @return true if other servers can connect to this port for s2s communication. - */ - public boolean isServerPort() { - return type == Type.server; - } - - /** - * Returns true if clients can connect to this port. - * - * @return true if clients can connect to this port. - */ - public boolean isClientPort() { - return type == Type.client; - } - - /** - * Returns true if external components can connect to this port. - * - * @return true if external components can connect to this port. - */ - public boolean isComponentPort() { - return type == Type.component; - } - - /** - * Returns true if connection managers can connect to this port. - * - * @return true if connection managers can connect to this port. - */ - public boolean isConnectionManagerPort() { - return type == Type.connectionManager; - } - - public static enum Type { - client, - - server, - - component, - - connectionManager - } -} diff --git a/src/java/org/jivesoftware/multiplexer/net/BlockingAcceptingMode.java b/src/java/org/jivesoftware/multiplexer/net/BlockingAcceptingMode.java deleted file mode 100644 index d9008b3..0000000 --- a/src/java/org/jivesoftware/multiplexer/net/BlockingAcceptingMode.java +++ /dev/null @@ -1,65 +0,0 @@ -/** - * $RCSfile$ - * $Revision: $ - * $Date: $ - * - * Copyright (C) 2006 Jive Software. All rights reserved. - * - * This software is published under the terms of the GNU Public License (GPL), - * a copy of which is included in this distribution. - */ - -package org.jivesoftware.multiplexer.net; - -import org.jivesoftware.util.LocaleUtils; -import org.jivesoftware.util.Log; -import org.jivesoftware.multiplexer.ServerPort; - -import java.io.IOException; -import java.net.InetAddress; -import java.net.ServerSocket; -import java.net.Socket; - -/** - * Accepts new socket connections and uses a thread for each new connection. - * - * @author Gaston Dombiak - */ -class BlockingAcceptingMode extends SocketAcceptingMode { - - protected BlockingAcceptingMode(ServerPort serverPort, - InetAddress bindInterface) throws IOException { - super(serverPort); - serverSocket = new ServerSocket(serverPort.getPort(), -1, bindInterface); - } - - /** - * About as simple as it gets. The thread spins around an accept - * call getting sockets and creating new reading threads for each new connection. - */ - public void run() { - while (notTerminated) { - try { - Socket sock = serverSocket.accept(); - if (sock != null) { - Log.debug("Connect " + sock.toString()); - SocketReader reader = - SocketReaderFactory.createSocketReader(sock, false, serverPort, true); - Thread thread = new Thread(reader, reader.getName()); - thread.setDaemon(true); - thread.setPriority(Thread.NORM_PRIORITY); - thread.start(); - } - } - catch (IOException ie) { - if (notTerminated) { - Log.error(LocaleUtils.getLocalizedString("admin.error.accept"), - ie); - } - } - catch (Throwable e) { - Log.error(LocaleUtils.getLocalizedString("admin.error.accept"), e); - } - } - } -} diff --git a/src/java/org/jivesoftware/multiplexer/net/BlockingReadingMode.java b/src/java/org/jivesoftware/multiplexer/net/BlockingReadingMode.java deleted file mode 100644 index 3a8d2ed..0000000 --- a/src/java/org/jivesoftware/multiplexer/net/BlockingReadingMode.java +++ /dev/null @@ -1,296 +0,0 @@ -/** - * $RCSfile$ - * $Revision: $ - * $Date: $ - * - * Copyright (C) 2006 Jive Software. All rights reserved. - * - * This software is published under the terms of the GNU Public License (GPL), - * a copy of which is included in this distribution. - */ - -package org.jivesoftware.multiplexer.net; - -import com.jcraft.jzlib.JZlib; -import com.jcraft.jzlib.ZInputStream; -import org.dom4j.Element; -import org.jivesoftware.multiplexer.Connection; -import org.jivesoftware.multiplexer.Session; -import org.jivesoftware.util.LocaleUtils; -import org.jivesoftware.util.Log; -import org.xmlpull.v1.XmlPullParser; -import org.xmlpull.v1.XmlPullParserException; - -import java.io.EOFException; -import java.io.IOException; -import java.io.InputStreamReader; -import java.net.Socket; -import java.net.SocketException; -import java.nio.channels.AsynchronousCloseException; - -/** - * Process incoming packets using a blocking model. Once a session has been created - * an endless loop is used to process incoming packets. Packets are processed - * sequentially. - * - * @author Gaston Dombiak - */ -class BlockingReadingMode extends SocketReadingMode { - - private Status saslStatus = Status.waitingServer; - - public BlockingReadingMode(Socket socket, SocketReader socketReader) { - super(socket, socketReader); - } - - /** - * A dedicated thread loop for reading the stream and sending incoming - * packets to the appropriate router. - */ - public void run() { - try { - socketReader.reader.getXPPParser().setInput(new InputStreamReader(socket.getInputStream(), - CHARSET)); - - // Read in the opening tag and prepare for packet stream - try { - socketReader.createSession(); - } - catch (IOException e) { - Log.debug("Error creating session", e); - throw e; - } - - // Read the packet stream until it ends - if (socketReader.session != null) { - readStream(); - } - - } - catch (EOFException eof) { - // Normal disconnect - } - catch (SocketException se) { - // The socket was closed. The server may close the connection for several - // reasons (e.g. user requested to remove his account). Do nothing here. - } - catch (AsynchronousCloseException ace) { - // The socket was closed. - } - catch (XmlPullParserException ie) { - // It is normal for clients to abruptly cut a connection - // rather than closing the stream document. Since this is - // normal behavior, we won't log it as an error. - // Log.error(LocaleUtils.getLocalizedString("admin.disconnect"),ie); - } - catch (Exception e) { - Log.warn(LocaleUtils.getLocalizedString("admin.error.stream") + ". Connection: " + - socketReader.connection, e); - } - finally { - if (socketReader.session != null) { - if (Log.isDebugEnabled()) { - Log.debug("Logging off " + socketReader.connection); - } - try { - socketReader.session.close(); - } - catch (Exception e) { - Log.warn(LocaleUtils.getLocalizedString("admin.error.connection") - + "\n" + socket.toString()); - } - } - else { - // Close and release the created connection - socketReader.connection.close(); - Log.error(LocaleUtils.getLocalizedString("admin.error.connection") - + "\n" + socket.toString()); - } - socketReader.shutdown(); - } - } - - /** - * Read the incoming stream until it ends. - */ - private void readStream() throws Exception { - socketReader.open = true; - while (socketReader.open) { - Element doc = socketReader.reader.parseDocument().getRootElement(); - if (doc == null) { - // Stop reading the stream since the client has sent an end of - // stream element and probably closed the connection. - return; - } - String tag = doc.getName(); - if ("starttls".equals(tag)) { - // Negotiate TLS - if (negotiateTLS()) { - tlsNegotiated(); - } - else { - socketReader.open = false; - } - } - else if ("auth".equals(tag)) { - // User is trying to authenticate using SASL - if (authenticateClient(doc)) { - // SASL authentication was successful so open a new stream and offer - // resource binding and session establishment (to client sessions only) - saslSuccessful(); - } - } - else if ("compress".equals(tag)) - { - // Client is trying to initiate compression - if (compressClient(doc)) { - // Compression was successful so open a new stream and offer - // resource binding and session establishment (to client sessions only) - compressionSuccessful(); - } - } - else { - socketReader.process(doc); - } - } - } - - protected void tlsNegotiated() throws XmlPullParserException, IOException { - XmlPullParser xpp = socketReader.reader.getXPPParser(); - // Reset the parser to use the new reader - xpp.setInput(new InputStreamReader( - socketReader.connection.getTLSStreamHandler().getInputStream(), CHARSET)); - // Skip new stream element - for (int eventType = xpp.getEventType(); eventType != XmlPullParser.START_TAG;) { - eventType = xpp.next(); - } - super.tlsNegotiated(); - } - - protected boolean authenticateClient(Element doc) throws Exception { - // Ensure that connection was secured if TLS was required - if (socketReader.connection.getTlsPolicy() == Connection.TLSPolicy.required && - !socketReader.connection.isSecure()) { - socketReader.closeNeverSecuredConnection(); - return false; - } - - boolean isComplete = false; - boolean success = false; - while (!isComplete && !socketReader.connection.isClosed()) { - // Forward stanza to the server - socketReader.process(doc); - // Wait 5 minutes to get a response from the server - synchronized (this) { - wait(5 * 60 * 1000); - } - // Raise an error if no response from the server was received - if (saslStatus == Status.waitingServer) { - throw new Exception("No answer was received from the server"); - } - - // If client was challenged then wait for client answer - if (saslStatus == Status.needResponse) { - doc = socketReader.reader.parseDocument().getRootElement(); - if (doc == null) { - // Nothing was read because the connection was closed or dropped - isComplete = true; - } - } - else { - success = socketReader.session.getStatus() == Session.STATUS_AUTHENTICATED; - isComplete = true; - } - } - return success; - } - - /** - * Notification message indicating that a client needs to response to a SASL - * challenge. - */ - void clientChallenged() { - // Set that client needs to send response - saslStatus = Status.needResponse; - synchronized (this) { - notify(); - } - } - - /** - * Notification message indicating that sasl authentication has finished. The - * success parameter indicates whether authentication was successful or not. - * - * @param success true when authentication was successful. - */ - void clientAuthenticated(boolean success) { - // Set result of authentication process - saslStatus = success ? Status.authenticated : Status.failed; - synchronized (this) { - notify(); - } - } - - protected void saslSuccessful() throws XmlPullParserException, IOException { - MXParser xpp = socketReader.reader.getXPPParser(); - // Reset the parser since a new stream header has been sent from the client - xpp.resetInput(); - - // Skip the opening stream sent by the client - for (int eventType = xpp.getEventType(); eventType != XmlPullParser.START_TAG;) { - eventType = xpp.next(); - } - super.saslSuccessful(); - } - - protected boolean compressClient(Element doc) throws XmlPullParserException, IOException { - boolean answer = super.compressClient(doc); - if (answer) { - XmlPullParser xpp = socketReader.reader.getXPPParser(); - // Reset the parser since a new stream header has been sent from the client - if (socketReader.connection.getTLSStreamHandler() == null) { - ZInputStream in = new ZInputStream(socket.getInputStream()); - in.setFlushMode(JZlib.Z_PARTIAL_FLUSH); - xpp.setInput(new InputStreamReader(in, CHARSET)); - } - else { - ZInputStream in = new ZInputStream( - socketReader.connection.getTLSStreamHandler().getInputStream()); - in.setFlushMode(JZlib.Z_PARTIAL_FLUSH); - xpp.setInput(new InputStreamReader(in, CHARSET)); - } - } - return answer; - } - - protected void compressionSuccessful() throws XmlPullParserException, IOException { - XmlPullParser xpp = socketReader.reader.getXPPParser(); - // Skip the opening stream sent by the client - for (int eventType = xpp.getEventType(); eventType != XmlPullParser.START_TAG;) { - eventType = xpp.next(); - } - super.compressionSuccessful(); - } - - public enum Status { - /** - * Server needs to process sasl stanza and send its answer to the client. - */ - waitingServer, - /** - * Entity needs to respond last challenge. Session is still negotiating - * SASL authentication. - */ - needResponse, - /** - * SASL negotiation has failed. The entity may retry a few times before the connection - * is closed. - */ - failed, - /** - * SASL negotiation has been successful. - */ - authenticated - } - -} diff --git a/src/java/org/jivesoftware/multiplexer/net/ClientSocketReader.java b/src/java/org/jivesoftware/multiplexer/net/ClientSocketReader.java deleted file mode 100644 index 7364a22..0000000 --- a/src/java/org/jivesoftware/multiplexer/net/ClientSocketReader.java +++ /dev/null @@ -1,68 +0,0 @@ -/** - * $RCSfile$ - * $Revision: $ - * $Date: $ - * - * Copyright (C) 2006 Jive Software. All rights reserved. - * - * This software is published under the terms of the GNU Public License (GPL), - * a copy of which is included in this distribution. - */ - -package org.jivesoftware.multiplexer.net; - -import org.jivesoftware.multiplexer.ClientSession; -import org.jivesoftware.multiplexer.PacketRouter; -import org.jivesoftware.util.JiveGlobals; -import org.xmlpull.v1.XmlPullParserException; - -import java.io.IOException; -import java.net.Socket; - -/** - * A SocketReader specialized for client connections. This reader will be used when the open - * stream contains a jabber:client namespace. Received packet will have their FROM attribute - * overriden to avoid spoofing.

- * - * By default the hostname specified in the stream header sent by clients will not be validated. - * When validated the TO attribute of the stream header has to match the server name or a valid - * subdomain. If the value of the 'to' attribute is not valid then a host-unknown error - * will be returned. To enable the validation set the system property - * xmpp.client.validate.host to true.

- * - * Stanzas that do not have a FROM attribute will be wrapped before forwarding them to the - * server. The wrapping element will include the stream ID that uniquely identifies the client - * in the server. The server will then be able to use the proper client session for processing - * the stanza. - * - * @author Gaston Dombiak - */ -public class ClientSocketReader extends SocketReader { - - public ClientSocketReader(PacketRouter router, String serverName, - Socket socket, SocketConnection connection, boolean useBlockingMode) { - super(router, serverName, socket, connection, useBlockingMode); - } - - boolean createSession(String namespace) throws XmlPullParserException, - IOException { - if ("jabber:client".equals(namespace)) { - // The connected client is a regular client so create a ClientSession - session = ClientSession.createSession(serverName, this, reader, connection); - return true; - } - return false; - } - - String getNamespace() { - return "jabber:client"; - } - - String getName() { - return "Client SR - " + hashCode(); - } - - boolean validateHost() { - return JiveGlobals.getBooleanProperty("xmpp.client.validate.host",false); - } -} diff --git a/src/java/org/jivesoftware/multiplexer/net/NonBlockingAcceptingMode.java b/src/java/org/jivesoftware/multiplexer/net/NonBlockingAcceptingMode.java deleted file mode 100644 index 866078e..0000000 --- a/src/java/org/jivesoftware/multiplexer/net/NonBlockingAcceptingMode.java +++ /dev/null @@ -1,160 +0,0 @@ -/** - * $RCSfile$ - * $Revision: $ - * $Date: $ - * - * Copyright (C) 2006 Jive Software. All rights reserved. - * - * This software is published under the terms of the GNU Public License (GPL), - * a copy of which is included in this distribution. - */ - -package org.jivesoftware.multiplexer.net; - -import org.jivesoftware.util.LocaleUtils; -import org.jivesoftware.util.Log; -import org.jivesoftware.multiplexer.ServerPort; - -import java.io.IOException; -import java.net.InetAddress; -import java.net.InetSocketAddress; -import java.net.Socket; -import java.nio.channels.SelectionKey; -import java.nio.channels.Selector; -import java.nio.channels.ServerSocketChannel; -import java.nio.channels.SocketChannel; -import java.util.Iterator; -import java.util.Set; - -/** - * Accepts new socket connections using a non-blocking model. A single selector is - * used for all connected clients and also for accepting new connections. - * - * @author Daniele Piras - */ -class NonBlockingAcceptingMode extends SocketAcceptingMode { - - // Time (in ms) to sleep from a reading-cycle to another - private static final long CYCLE_TIME = 10; - - // Selector to collect messages from client connections. - private Selector selector; - - protected NonBlockingAcceptingMode(ServerPort serverPort, - InetAddress bindInterface) throws IOException { - super(serverPort); - - // Chaning server to use NIO - // Open selector... - selector = Selector.open(); - // Create a new ServerSocketChannel - ServerSocketChannel serverSocketChannel = ServerSocketChannel.open(); - // Retrieve socket and bind socket with specified address - this.serverSocket = serverSocketChannel.socket(); - this.serverSocket.bind(new InetSocketAddress(bindInterface, serverPort.getPort())); - // Configure Blocking to unblocking - serverSocketChannel.configureBlocking(false); - // Registering connection with selector. - SelectionKey sk = serverSocketChannel.register(selector, SelectionKey.OP_ACCEPT); - AcceptConnection acceptConnection = new AcceptConnection(); - sk.attach(acceptConnection); - } - - /** - * DANIELE: - * This thread use the selector NIO features to retrieve client connections - * and messages. - */ - public void run() { - while (notTerminated && !Thread.interrupted()) { - try { - selector.select(); - Set selected = selector.selectedKeys(); - Iterator it = selected.iterator(); - while (it.hasNext()) { - SelectionKey key = (SelectionKey) it.next(); - it.remove(); - SelectorAction action = (SelectorAction) key.attachment(); - if (action == null) { - continue; - } - if (key.isAcceptable()) { - action.connect(key); - } - else if (key.isReadable()) { - action.read(key); - } - } - Thread.sleep(CYCLE_TIME); - } - catch (IOException ie) { - if (notTerminated) { - Log.error(LocaleUtils.getLocalizedString("admin.error.accept"), - ie); - } - } - catch (Exception e) { - Log.error(LocaleUtils.getLocalizedString("admin.error.accept"), e); - } - } - } - - /* - * InnerClass that is use when a new client arrive. - * It's use the reactor pattern to register an abstract action - * to the selector. - */ - class AcceptConnection implements SelectorAction { - - - public void read(SelectionKey key) throws IOException { - } - - /* - * A client arrive... - */ - public void connect(SelectionKey key) throws IOException { - // Retrieve the server socket channel... - ServerSocketChannel sChannel = (ServerSocketChannel) key.channel(); - // Accept the connection - SocketChannel socketChannel = sChannel.accept(); - // Retrieve socket for incoming connection - Socket sock = socketChannel.socket(); - socketChannel.configureBlocking(false); - // Registering READING operation into the selector - SelectionKey sockKey = socketChannel.register(selector, SelectionKey.OP_READ); - if (sock != null) { - System.out.println("Connect " + sock.toString()); - Log.debug("Connect " + sock.toString()); - try { - SocketReader reader = - SocketReaderFactory.createSocketReader(sock, false, serverPort, false); - SelectorAction action = new ReadAction(reader); - sockKey.attach(action); - } - catch (Exception e) { - // There is an exception... - Log.error(LocaleUtils.getLocalizedString("admin.error.accept"), e); - } - } - } - } - - class ReadAction implements SelectorAction { - - SocketReader reader; - - public ReadAction(SocketReader reader) { - this.reader = reader; - } - - public void read(SelectionKey key) throws IOException { - // Socket reader (using non-blocking mode) will read the stream and process, in - // another thread, any number of stanzas found in the stream. - reader.run(); - } - - public void connect(SelectionKey key) throws IOException { - } - } -} diff --git a/src/java/org/jivesoftware/multiplexer/net/SSLSocketAcceptThread.java b/src/java/org/jivesoftware/multiplexer/net/SSLSocketAcceptThread.java deleted file mode 100644 index b9f543a..0000000 --- a/src/java/org/jivesoftware/multiplexer/net/SSLSocketAcceptThread.java +++ /dev/null @@ -1,185 +0,0 @@ -/** - * $RCSfile$ - * $Revision: 1583 $ - * $Date: 2005-07-03 17:55:39 -0300 (Sun, 03 Jul 2005) $ - * - * Copyright (C) 2006 Jive Software. All rights reserved. - * - * This software is published under the terms of the GNU Public License (GPL), - * a copy of which is included in this distribution. - */ - -package org.jivesoftware.multiplexer.net; - -import org.jivesoftware.multiplexer.ServerPort; -import org.jivesoftware.util.JiveGlobals; -import org.jivesoftware.util.LocaleUtils; -import org.jivesoftware.util.Log; - -import javax.net.ssl.SSLException; -import java.io.IOException; -import java.net.InetAddress; -import java.net.ServerSocket; -import java.net.Socket; -import java.net.UnknownHostException; - -/** - * Implements a network front end with a dedicated thread reading - * each incoming socket. The old SSL method always uses a blocking model. - * - * @author Gaston Dombiak - */ -public class SSLSocketAcceptThread extends Thread { - - /** - * The default Jabber socket - */ - public static final int DEFAULT_PORT = 5223; - - /** - * Holds information about the port on which the server will listen for connections. - */ - private ServerPort serverPort; - - /** - * True while this thread should continue running. - */ - private boolean notTerminated = true; - - /** - * The accept socket we're running - */ - private ServerSocket serverSocket; - - /** - * The number of SSL related exceptions occuring rapidly that should signal a need - * to shutdown the SSL port. - */ - private static final int MAX_SSL_EXCEPTIONS = 10; - - /** - * Creates an instance using the default port, TLS transport security, and - * JVM defaults for all security settings. - * - * @throws IOException if there was trouble initializing the SSL configuration. - */ - public SSLSocketAcceptThread(ServerPort serverPort) - throws IOException { - super("Secure Socket Listener"); - this.serverPort = serverPort; - int port = serverPort.getPort(); - // 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) { - try { - if (interfaceName.trim().length() > 0) { - bindInterface = InetAddress.getByName(interfaceName); - } - } - catch (UnknownHostException e) { - Log.error(LocaleUtils.getLocalizedString("admin.error"), e); - } - } - serverSocket = SSLConfig.createServerSocket(port, bindInterface); - } - - /** - * Retrieve the port this server socket is bound to. - * - * @return the port the socket is bound to. - */ - public int getPort() { - return serverSocket.getLocalPort(); - } - - /** - * Returns information about the port on which the server is listening for connections. - * - * @return information about the port on which the server is listening for connections. - */ - public ServerPort getServerPort() { - return serverPort; - } - - /** - * Unblock the thread and force it to terminate. - */ - public void shutdown() { - notTerminated = false; - try { - ServerSocket sSock = serverSocket; - serverSocket = null; - if (sSock != null) { - sSock.close(); - } - } - catch (IOException e) { - // we don't care, no matter what, the socket should be dead - } - } - - /** - * About as simple as it gets. The thread spins around an accept - * call getting sockets and handing them to the SocketManager. - * We need to detect run away failures since an SSL configuration - * problem can cause the loop to spin, constantly rethrowing SSLExceptions - * (e.g. if a certificate is in the keystore that can't be verified). - */ - public void run() { - long lastExceptionTime = 0; - int exceptionCounter = 0; - while (notTerminated) { - try { - Socket sock = serverSocket.accept(); - Log.debug("SSL Connect " + sock.toString()); - SocketReader reader = - SocketReaderFactory.createSocketReader(sock, true, serverPort, true); - // Create a new reading thread for each new connected client - Thread thread = new Thread(reader, reader.getName()); - thread.setDaemon(true); - thread.setPriority(Thread.NORM_PRIORITY); - thread.start(); - } - catch (SSLException se) { - long exceptionTime = System.currentTimeMillis(); - if (exceptionTime - lastExceptionTime > 1000) { - // if the time between SSL exceptions is too long - // reset the counter - exceptionCounter = 1; - } - else { - // If this exception occured within a second of the last one - // we need to count it - exceptionCounter++; - } - lastExceptionTime = exceptionTime; - Log.error(LocaleUtils.getLocalizedString("admin.error.ssl"), se); - // and if the number of consecutive exceptions exceeds the limit - // we should assume there's an SSL problem or DOS attack and shutdown - if (exceptionCounter > MAX_SSL_EXCEPTIONS) { - String msg = "Shutting down SSL port - " + - "suspected configuration problem"; - Log.error(msg); - Log.info(msg); - shutdown(); - } - } - catch (Throwable e) { - if (notTerminated) { - Log.error(LocaleUtils.getLocalizedString("admin.error.ssl"), e); - } - } - } - try { - ServerSocket sSock = serverSocket; - serverSocket = null; - if (sSock != null) { - sSock.close(); - } - } - catch (IOException e) { - // we don't care, no matter what, the socket should be dead - } - } -} diff --git a/src/java/org/jivesoftware/multiplexer/net/SelectorAction.java b/src/java/org/jivesoftware/multiplexer/net/SelectorAction.java deleted file mode 100644 index 7c827e2..0000000 --- a/src/java/org/jivesoftware/multiplexer/net/SelectorAction.java +++ /dev/null @@ -1,24 +0,0 @@ -/** - * $RCSfile$ - * $Revision: $ - * $Date: $ - * - * Copyright (C) 2006 Jive Software. All rights reserved. - * - * This software is published under the terms of the GNU Public License (GPL), - * a copy of which is included in this distribution. - */ - -package org.jivesoftware.multiplexer.net; - -import java.io.IOException; -import java.nio.channels.SelectionKey; - -/** - * @author Daniele Piras - */ -interface SelectorAction -{ - public abstract void read( SelectionKey key ) throws IOException; - public abstract void connect( SelectionKey key ) throws IOException; -} diff --git a/src/java/org/jivesoftware/multiplexer/net/SocketAcceptThread.java b/src/java/org/jivesoftware/multiplexer/net/SocketAcceptThread.java deleted file mode 100644 index 9880f44..0000000 --- a/src/java/org/jivesoftware/multiplexer/net/SocketAcceptThread.java +++ /dev/null @@ -1,109 +0,0 @@ -/** - * $RCSfile$ - * $Revision: 1583 $ - * $Date: 2005-07-03 17:55:39 -0300 (Sun, 03 Jul 2005) $ - * - * Copyright (C) 2006 Jive Software. All rights reserved. - * - * This software is published under the terms of the GNU Public License (GPL), - * a copy of which is included in this distribution. - */ - -package org.jivesoftware.multiplexer.net; - -import org.jivesoftware.multiplexer.ServerPort; -import org.jivesoftware.util.JiveGlobals; - -import java.io.IOException; -import java.net.InetAddress; - -/** - * Implements a network front end with a dedicated thread reading - * each incoming socket. Blocking and non-blocking modes are supported. - * By default blocking mode is used. Use the xmpp.socket.blocking - * system property to change the blocking mode. Restart the server after making - * changes to the system property. - * - * @author Gaston Dombiak - */ -public class SocketAcceptThread extends Thread { - - /** - * The default XMPP port for clients. - */ - public static final int DEFAULT_PORT = 5222; - - /** - * The default XMPP port for server2server communication. - */ - public static final int DEFAULT_SERVER_PORT = 5269; - - /** - * The default XMPP port for connection multiplex. - */ - public static final int DEFAULT_MULTIPLEX_PORT = 5262; - - /** - * Holds information about the port on which the server will listen for connections. - */ - private ServerPort serverPort; - - private SocketAcceptingMode acceptingMode; - - public SocketAcceptThread(ServerPort serverPort) - throws IOException { - super("Socket Listener at port " + serverPort.getPort()); - this.serverPort = serverPort; - // 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); - } - } - // Set the blocking reading mode to use - boolean useBlockingMode = JiveGlobals.getBooleanProperty("xmpp.socket.blocking", true); - if (useBlockingMode) { - acceptingMode = new BlockingAcceptingMode(serverPort, bindInterface); - } - else { - acceptingMode = new NonBlockingAcceptingMode(serverPort, bindInterface); - } - } - - /** - * Retrieve the port this server socket is bound to. - * - * @return the port the socket is bound to. - */ - public int getPort() { - return serverPort.getPort(); - } - - /** - * Returns information about the port on which the server is listening for connections. - * - * @return information about the port on which the server is listening for connections. - */ - public ServerPort getServerPort() { - return serverPort; - } - - /** - * Unblock the thread and force it to terminate. - */ - public void shutdown() { - acceptingMode.shutdown(); - } - - /** - * About as simple as it gets. The thread spins around an accept - * call getting sockets and handing them to the SocketManager. - */ - public void run() { - acceptingMode.run(); - // We stopped accepting new connections so close the listener - shutdown(); - } -} diff --git a/src/java/org/jivesoftware/multiplexer/net/SocketAcceptingMode.java b/src/java/org/jivesoftware/multiplexer/net/SocketAcceptingMode.java deleted file mode 100644 index 8c0dbaf..0000000 --- a/src/java/org/jivesoftware/multiplexer/net/SocketAcceptingMode.java +++ /dev/null @@ -1,60 +0,0 @@ -/** - * $RCSfile$ - * $Revision: $ - * $Date: $ - * - * Copyright (C) 2006 Jive Software. All rights reserved. - * - * This software is published under the terms of the GNU Public License (GPL), - * a copy of which is included in this distribution. - */ - -package org.jivesoftware.multiplexer.net; - -import org.jivesoftware.multiplexer.ServerPort; - -import java.io.IOException; -import java.net.ServerSocket; - -/** - * Abstract class for {@link BlockingAcceptingMode} and {@link NonBlockingAcceptingMode}. - * - * @author Gaston Dombiak - */ -abstract class SocketAcceptingMode { - - /** - * True while this thread should continue running. - */ - protected boolean notTerminated = true; - - /** - * Holds information about the port on which the server will listen for connections. - */ - protected ServerPort serverPort; - - /** - * socket that listens for connections. - */ - protected ServerSocket serverSocket; - - protected SocketAcceptingMode(ServerPort serverPort) { - this.serverPort = serverPort; - } - - public abstract void run(); - - public void shutdown() { - notTerminated = false; - try { - ServerSocket sSock = serverSocket; - serverSocket = null; - if (sSock != null) { - sSock.close(); - } - } - catch (IOException e) { - // we don't care, no matter what, the socket should be dead - } - } -} diff --git a/src/java/org/jivesoftware/multiplexer/net/SocketReader.java b/src/java/org/jivesoftware/multiplexer/net/SocketReader.java deleted file mode 100644 index 5c5bae6..0000000 --- a/src/java/org/jivesoftware/multiplexer/net/SocketReader.java +++ /dev/null @@ -1,295 +0,0 @@ -/** - * $RCSfile$ - * $Revision: 3187 $ - * $Date: 2005-12-11 13:34:34 -0300 (Sun, 11 Dec 2005) $ - * - * Copyright (C) 2006 Jive Software. All rights reserved. - * - * This software is published under the terms of the GNU Public License (GPL), - * a copy of which is included in this distribution. - */ - -package org.jivesoftware.multiplexer.net; - -import org.dom4j.Element; -import org.dom4j.io.XMPPPacketReader; -import org.jivesoftware.multiplexer.*; -import org.jivesoftware.util.Log; -import org.jivesoftware.util.StringUtils; -import org.xmlpull.v1.XmlPullParser; -import org.xmlpull.v1.XmlPullParserException; -import org.xmlpull.v1.XmlPullParserFactory; - -import java.io.IOException; -import java.net.Socket; - -/** - * A SocketReader creates the appropriate {@link Session} based on the defined namespace in the - * stream element and will then keep reading and routing the received packets.

- * - * This class was copied from Wildfire. PacketInterceptors were removed. Session concept was - * removed. - * - * @author Gaston Dombiak - */ -public abstract class SocketReader implements Runnable, SocketStatistic { - - /** - * The utf-8 charset for decoding and encoding Jabber packet streams. - */ - private static String CHARSET = "UTF-8"; - /** - * Reuse the same factory for all the connections. - */ - private static XmlPullParserFactory factory = null; - - /** - * Session associated with the socket reader. - */ - protected Session session; - /** - * Reference to the physical connection. - */ - protected SocketConnection connection; - /** - * Server name for which we are attending clients. - */ - protected String serverName; - - /** - * Router used to route incoming packets to the correct channels. - */ - private PacketRouter router; - /** - * Specifies whether the socket is using blocking or non-blocking connections. - */ - private SocketReadingMode readingMode; - XMPPPacketReader reader = null; - protected boolean open; - - static { - try { - factory = XmlPullParserFactory.newInstance(MXParser.class.getName(), null); - } - catch (XmlPullParserException e) { - Log.error("Error creating a parser factory", e); - } - } - - /** - * Creates a dedicated reader for a socket. - * - * @param router the router for sending packets that were read. - * @param serverName the name of the server this socket is working for. - * @param socket the socket to read from. - * @param connection the connection being read. - * @param useBlockingMode true means that the server will use a thread per connection. - */ - public SocketReader(PacketRouter router, String serverName, - Socket socket, SocketConnection connection, boolean useBlockingMode) { - this.serverName = serverName; - this.router = router; - this.connection = connection; - - connection.setSocketStatistic(this); - - // Reader is associated with a new XMPPPacketReader - reader = new XMPPPacketReader(); - reader.setXPPFactory(factory); - - // Set the blocking reading mode to use - if (useBlockingMode) { - readingMode = new BlockingReadingMode(socket, this); - } - else { - //TODO readingMode = new NonBlockingReadingMode(socket, this); - } - } - - /** - * A dedicated thread loop for reading the stream and sending incoming - * packets to the appropriate router. - */ - public void run() { - readingMode.run(); - } - - /** - * Notification message indicating that a client needs to response to a SASL - * challenge. - */ - public void clientChallenged() { - readingMode.clientChallenged(); - } - - /** - * Notification message indicating that sasl authentication has finished. The - * success parameter indicates whether authentication was successful or not. - * - * @param success true when authentication was successful. - */ - public void clientAuthenticated(boolean success) { - readingMode.clientAuthenticated(success); - } - - protected void process(Element doc) throws Exception { - if (doc == null) { - return; - } - - // Ensure that connection was secured if TLS was required - if (connection.getTlsPolicy() == Connection.TLSPolicy.required && - !connection.isSecure()) { - closeNeverSecuredConnection(); - return; - } - router.route(doc, session.getStreamID()); - } - - public long getLastActive() { - return reader.getLastActive(); - } - - /** - * Returns a name that identifies the type of reader and the unique instance. - * - * @return a name that identifies the type of reader and the unique instance. - */ - abstract String getName(); - - /** - * Close the connection since TLS was mandatory and the entity never negotiated TLS. Before - * closing the connection a stream error will be sent to the entity. - */ - void closeNeverSecuredConnection() { - // Set the not_authorized error - StreamError error = new StreamError(StreamError.Condition.not_authorized); - // Deliver stanza - connection.deliverRawText(error.toXML()); - // Close the underlying connection - connection.close(); - // Log a warning so that admins can track this case from the server side - Log.warn("TLS was required by the server and connection was never secured. " + - "Closing connection : " + connection); - } - - /** - * Uses the XPP to grab the opening stream tag and create an active session - * object. The session to create will depend on the sent namespace. In all - * cases, the method obtains the opening stream tag, checks for errors, and - * either creates a session or returns an error and kills the connection. - * If the connection remains open, the XPP will be set to be ready for the - * first packet. A call to next() should result in an START_TAG state with - * the first packet in the stream. - */ - protected void createSession() throws XmlPullParserException, IOException { - XmlPullParser xpp = reader.getXPPParser(); - for (int eventType = xpp.getEventType(); eventType != XmlPullParser.START_TAG;) { - eventType = xpp.next(); - } - - // Check that the TO attribute of the stream header matches the server name or a valid - // subdomain. If the value of the 'to' attribute is not valid then return a host-unknown - // error and close the underlying connection. - String host = reader.getXPPParser().getAttributeValue("", "to"); - if (validateHost() && isHostUnknown(host)) { - StringBuilder sb = new StringBuilder(250); - sb.append(""); - // Append stream header - sb.append(""); - // Set the host_unknown error - StreamError error = new StreamError(StreamError.Condition.host_unknown); - sb.append(error.toXML()); - // Deliver stanza - connection.deliverRawText(sb.toString()); - // Close the underlying connection - connection.close(); - // Log a warning so that admins can track this cases from the server side - Log.warn("Closing session due to incorrect hostname in stream header. Host: " + host + - ". Connection: " + connection); - } - - // Create the correct session based on the sent namespace. At this point the server - // may offer the client to secure the connection. If the client decides to secure - // the connection then a stanza should be received - else if (!createSession(xpp.getNamespace(null))) { - // No session was created because of an invalid namespace prefix so answer a stream - // error and close the underlying connection - StringBuilder sb = new StringBuilder(250); - sb.append(""); - // Append stream header - sb.append(""); - // Include the bad-namespace-prefix in the response - StreamError error = new StreamError(StreamError.Condition.bad_namespace_prefix); - sb.append(error.toXML()); - connection.deliverRawText(sb.toString()); - // Close the underlying connection - connection.close(); - // Log a warning so that admins can track this cases from the server side - Log.warn("Closing session due to bad_namespace_prefix in stream header. Prefix: " + - xpp.getNamespace(null) + ". Connection: " + connection); - } - } - - private boolean isHostUnknown(String host) { - if (host == null) { - // Answer false since when using server dialback the stream header will not - // have a TO attribute - return false; - } - if (serverName.equals(host)) { - // requested host matched the server name - return false; - } - return true; - } - - /** - * Returns the stream namespace. (E.g. jabber:client, jabber:server, etc.). - * - * @return the stream namespace. - */ - abstract String getNamespace(); - - /** - * Returns true if the value of the 'to' attribute in the stream header should be - * validated. If the value of the 'to' attribute is not valid then a host-unknown error - * will be returned and the underlying connection will be closed. - * - * @return true if the value of the 'to' attribute in the initial stream header should be - * validated. - */ - abstract boolean validateHost(); - - /** - * Notification message indicating that the SocketReader is shutting down. The thread will - * stop reading and processing new requests. Subclasses may want to redefine this message - * for releasing any resource they might need. - */ - protected void shutdown() { - } - - /** - * Creates the appropriate {@link Session} subclass based on the specified namespace. - * - * @param namespace the namespace sent in the stream element. eg. jabber:client. - * @return the created session or null. - * @throws XmlPullParserException - * @throws IOException - */ - abstract boolean createSession(String namespace) throws XmlPullParserException, IOException; -} diff --git a/src/java/org/jivesoftware/multiplexer/net/SocketReaderFactory.java b/src/java/org/jivesoftware/multiplexer/net/SocketReaderFactory.java deleted file mode 100644 index d836506..0000000 --- a/src/java/org/jivesoftware/multiplexer/net/SocketReaderFactory.java +++ /dev/null @@ -1,48 +0,0 @@ -/** - * $RCSfile$ - * $Revision: $ - * $Date: $ - * - * Copyright (C) 2006 Jive Software. All rights reserved. - * - * This software is published under the terms of the GNU Public License (GPL), - * a copy of which is included in this distribution. - */ - -package org.jivesoftware.multiplexer.net; - -import org.jivesoftware.multiplexer.ConnectionManager; -import org.jivesoftware.multiplexer.PacketRouter; -import org.jivesoftware.multiplexer.ServerPort; -import org.jivesoftware.multiplexer.spi.ClientFailoverDeliverer; -import org.jivesoftware.multiplexer.spi.ServerRouter; -import org.jivesoftware.util.Log; - -import java.io.IOException; -import java.net.Socket; - -/** - * Factory of {@link SocketReader}. Currently only socket readers for clients are - * supported. - * - * @author Gaston Dombiak - */ -class SocketReaderFactory { - - private static PacketRouter router = new ServerRouter(); - private static String serverName = ConnectionManager.getInstance().getServerName(); - - static SocketReader createSocketReader(Socket sock, boolean isSecure, ServerPort serverPort, - boolean useBlockingMode) throws IOException { - if (serverPort.isClientPort()) { - SocketConnection conn = - new SocketConnection(new ClientFailoverDeliverer(), sock, isSecure); - return new ClientSocketReader(router, serverName, sock, conn, useBlockingMode); - } else { - Log.warn("Invalid socket reader was requested. Only clients are allowed to connect,"); - return null; - } - } - - -} diff --git a/src/java/org/jivesoftware/multiplexer/net/SocketReadingMode.java b/src/java/org/jivesoftware/multiplexer/net/SocketReadingMode.java deleted file mode 100644 index f8eac6c..0000000 --- a/src/java/org/jivesoftware/multiplexer/net/SocketReadingMode.java +++ /dev/null @@ -1,243 +0,0 @@ -/** - * $RCSfile$ - * $Revision: $ - * $Date: $ - * - * Copyright (C) 2006 Jive Software. All rights reserved. - * - * This software is published under the terms of the GNU Public License (GPL), - * a copy of which is included in this distribution. - */ - -package org.jivesoftware.multiplexer.net; - -import org.dom4j.Element; -import org.jivesoftware.multiplexer.*; -import org.jivesoftware.util.Log; -import org.xmlpull.v1.XmlPullParserException; - -import java.io.IOException; -import java.net.Socket; - -/** - * Abstract class for {@link BlockingReadingMode} and {@link NonBlockingReadingMode}. - * - * @author Gaston Dombiak - */ -abstract class SocketReadingMode { - - /** - * The utf-8 charset for decoding and encoding Jabber packet streams. - */ - protected static String CHARSET = "UTF-8"; - - protected SocketReader socketReader; - protected Socket socket; - - protected SocketReadingMode(Socket socket, SocketReader socketReader) { - this.socket = socket; - this.socketReader = socketReader; - } - - /* - * This method is invoked when client send data to the channel. - */ - abstract void run(); - - /** - * Tries to secure the connection using TLS. If the connection is secured then reset - * the parser to use the new secured reader. But if the connection failed to be secured - * then send a stanza and close the connection. - * - * @return true if the connection was secured. - */ - protected boolean negotiateTLS() { - if (socketReader.connection.getTlsPolicy() == Connection.TLSPolicy.disabled) { - // Set the not_authorized error - StreamError error = new StreamError(StreamError.Condition.not_authorized); - // Deliver stanza - socketReader.connection.deliverRawText(error.toXML()); - // Close the underlying connection - socketReader.connection.close(); - // Log a warning so that admins can track this case from the server side - Log.warn("TLS requested by initiator when TLS was never offered by server. " + - "Closing connection : " + socketReader.connection); - return false; - } - // Client requested to secure the connection using TLS. Negotiate TLS. - try { - socketReader.connection.startTLS(false, null); - } - catch (IOException e) { - Log.error("Error while negotiating TLS", e); - socketReader.connection.deliverRawText(""); - socketReader.connection.close(); - return false; - } - return true; - } - - /** - * TLS negotiation was successful so open a new stream and offer the new stream features. - * The new stream features will include available SASL mechanisms and specific features - * depending on the session type such as auth for Non-SASL authentication and register - * for in-band registration. - */ - protected void tlsNegotiated() throws XmlPullParserException, IOException { - // Offer stream features including SASL Mechanisms - StringBuilder sb = new StringBuilder(620); - sb.append(geStreamHeader()); - sb.append(""); - // Include available SASL Mechanisms - sb.append(ConnectionManager.getInstance().getServerSurrogate().getSASLMechanisms( - socketReader.session)); - // Include specific features such as auth and register for client sessions - String specificFeatures = socketReader.session.getAvailableStreamFeatures(); - if (specificFeatures != null) { - sb.append(specificFeatures); - } - sb.append(""); - socketReader.connection.deliverRawText(sb.toString()); - } - - /** - * Notification message indicating that a client needs to response to a SASL - * challenge. - */ - abstract void clientChallenged(); - - /** - * Notification message indicating that sasl authentication has finished. The - * success parameter indicates whether authentication was successful or not. - * - * @param success true when authentication was successful. - */ - abstract void clientAuthenticated(boolean success); - - /** - * After SASL authentication was successful we should open a new stream and offer - * new stream features such as resource binding and session establishment. Notice that - * resource binding and session establishment should only be offered to clients (i.e. not - * to servers or external components) - */ - protected void saslSuccessful() throws XmlPullParserException, IOException { - StringBuilder sb = new StringBuilder(420); - sb.append(geStreamHeader()); - sb.append(""); - - // Include specific features such as resource binding and session establishment - // for client sessions - String specificFeatures = socketReader.session.getAvailableStreamFeatures(); - if (specificFeatures != null) { - sb.append(specificFeatures); - } - sb.append(""); - socketReader.connection.deliverRawText(sb.toString()); - } - - /** - * Start using compression but first check if the connection can and should use compression. - * The connection will be closed if the requested method is not supported, if the connection - * is already using compression or if client requested to use compression but this feature - * is disabled. - * - * @param doc the element sent by the client requesting compression. Compression method is - * included. - * @return true if it was possible to use compression. - * @throws IOException if an error occurs while starting using compression. - */ - protected boolean compressClient(Element doc) throws IOException, XmlPullParserException { - String error = null; - if (socketReader.connection.getCompressionPolicy() == Connection.CompressionPolicy.disabled) { - // Client requested compression but this feature is disabled - error = ""; - // Log a warning so that admins can track this case from the server side - Log.warn("Client requested compression while compression is disabled. Closing " + - "connection : " + socketReader.connection); - } - else if (socketReader.connection.isCompressed()) { - // Client requested compression but connection is already compressed - error = ""; - // Log a warning so that admins can track this case from the server side - Log.warn("Client requested compression and connection is already compressed. Closing " + - "connection : " + socketReader.connection); - } - else { - // Check that the requested method is supported - String method = doc.elementText("method"); - if (!"zlib".equals(method)) { - error = ""; - // Log a warning so that admins can track this case from the server side - Log.warn("Requested compression method is not supported: " + method + - ". Closing connection : " + socketReader.connection); - } - } - - if (error != null) { - // Deliver stanza - socketReader.connection.deliverRawText(error); - return false; - } - else { - // Indicate client that he can proceed and compress the socket - socketReader.connection.deliverRawText(""); - - // Start using compression - socketReader.connection.startCompression(); - return true; - } - } - - /** - * After compression was successful we should open a new stream and offer - * new stream features such as resource binding and session establishment. Notice that - * resource binding and session establishment should only be offered to clients (i.e. not - * to servers or external components) - */ - protected void compressionSuccessful() throws XmlPullParserException, IOException - { - StringBuilder sb = new StringBuilder(340); - sb.append(geStreamHeader()); - sb.append(""); - // Include SASL mechanisms only if client has not been authenticated - if (socketReader.session.getStatus() != Session.STATUS_AUTHENTICATED) { - // Include available SASL Mechanisms - sb.append(ConnectionManager.getInstance().getServerSurrogate().getSASLMechanisms( - socketReader.session)); - } - // Include specific features such as resource binding and session establishment - // for client sessions - String specificFeatures = socketReader.session.getAvailableStreamFeatures(); - if (specificFeatures != null) - { - sb.append(specificFeatures); - } - sb.append(""); - socketReader.connection.deliverRawText(sb.toString()); - } - - private String geStreamHeader() { - StringBuilder sb = new StringBuilder(200); - sb.append(""); - if (socketReader.connection.isFlashClient()) { - sb.append(""); - return sb.toString(); - } - -}