Commit 36dd1311 authored by Gaston Dombiak's avatar Gaston Dombiak Committed by gato

Added compression support. JM-333

git-svn-id: http://svn.igniterealtime.org/svn/repos/messenger/trunk@3174 b35dd754-fafc-0310-a699-88a17e54d16e
parent 81eb384e
/** /**
* $RCSfile$ * $RCSfile: Connection.java,v $
* $Revision$ * $Revision$
* $Date$ * $Date$
* *
...@@ -13,6 +13,7 @@ package org.jivesoftware.messenger; ...@@ -13,6 +13,7 @@ package org.jivesoftware.messenger;
import org.xmpp.packet.Packet; import org.xmpp.packet.Packet;
import org.jivesoftware.messenger.auth.UnauthorizedException; import org.jivesoftware.messenger.auth.UnauthorizedException;
import org.jivesoftware.messenger.net.SocketConnection;
import java.net.InetAddress; import java.net.InetAddress;
import java.net.UnknownHostException; import java.net.UnknownHostException;
...@@ -176,4 +177,88 @@ public interface Connection { ...@@ -176,4 +177,88 @@ public interface Connection {
* @return the language code for the connection. * @return the language code for the connection.
*/ */
public String getLanguage(); public String getLanguage();
/**
* Returns true if the connection is using compression.
*
* @return true if the connection is using compression.
*/
boolean isCompressed();
/**
* Returns whether compression is optional or is disabled.
*
* @return whether compression is optional or is disabled.
*/
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
* using TLS. Their connections will be closed if they try to secure the connection. in this
* last case.
*
* @return whether TLS is mandatory, optional or is disabled.
*/
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);
/**
* Enumeration of possible compression policies required to interact with the server.
*/
enum CompressionPolicy {
/**
* compression is optional to interact with the server.
*/
optional,
/**
* compression is not available. Entities that request a compression negotiation
* will get a stream error and their connections will be closed.
*/
disabled;
}
/**
* Enumeration of possible TLS policies required to interact with the server.
*/
enum TLSPolicy {
/**
* TLS is required to interact with the server. Entities that do not secure their
* connections using TLS will get a stream error and their connections will be closed.
*/
required,
/**
* TLS is optional to interact with the server. Entities may or may not secure their
* connections using TLS.
*/
optional,
/**
* TLS is not available. Entities that request a TLS negotiation will get a stream
* error and their connections will be closed.
*/
disabled;
}
} }
...@@ -260,6 +260,14 @@ public abstract class Session implements RoutableChannelHandler { ...@@ -260,6 +260,14 @@ public abstract class Session implements RoutableChannelHandler {
sessionData.remove(key); sessionData.remove(key);
} }
/**
* Returns a text with the available stream features. Each subclass may return different
* values depending whether the session has been authenticated or not.
*
* @return a text with the available stream features or <tt>null</tt> to add nothing.
*/
public abstract String getAvailableStreamFeatures();
public String toString() { public String toString() {
return super.toString() + " status: " + status + " address: " + address + " id: " + streamID; return super.toString() + " status: " + status + " address: " + address + " id: " + streamID;
} }
......
...@@ -199,6 +199,11 @@ public class ComponentSession extends Session { ...@@ -199,6 +199,11 @@ public class ComponentSession extends Session {
super(serverName, conn, id); super(serverName, conn, id);
} }
public String getAvailableStreamFeatures() {
// Nothing special to add
return null;
}
public void process(Packet packet) throws PacketException { public void process(Packet packet) throws PacketException {
// Since ComponentSessions are not being stored in the RoutingTable this messages is very // Since ComponentSessions are not being stored in the RoutingTable this messages is very
// unlikely to be sent // unlikely to be sent
......
...@@ -14,7 +14,6 @@ package org.jivesoftware.messenger.net; ...@@ -14,7 +14,6 @@ package org.jivesoftware.messenger.net;
import org.dom4j.Element; import org.dom4j.Element;
import org.jivesoftware.messenger.ClientSession; import org.jivesoftware.messenger.ClientSession;
import org.jivesoftware.messenger.PacketRouter; import org.jivesoftware.messenger.PacketRouter;
import org.jivesoftware.messenger.XMPPServer;
import org.jivesoftware.messenger.auth.UnauthorizedException; import org.jivesoftware.messenger.auth.UnauthorizedException;
import org.jivesoftware.util.JiveGlobals; import org.jivesoftware.util.JiveGlobals;
import org.xmlpull.v1.XmlPullParserException; import org.xmlpull.v1.XmlPullParserException;
...@@ -91,26 +90,4 @@ public class ClientSocketReader extends SocketReader { ...@@ -91,26 +90,4 @@ public class ClientSocketReader extends SocketReader {
boolean validateHost() { boolean validateHost() {
return JiveGlobals.getBooleanProperty("xmpp.client.validate.host",false); return JiveGlobals.getBooleanProperty("xmpp.client.validate.host",false);
} }
protected String getAvailableStreamFeatures() {
StringBuilder sb = new StringBuilder(110);
// TODO Create and use #hasSASLAuthentication
if (((ClientSession)session).getAuthToken() == null) {
// Advertise that the server supports Non-SASL Authentication
if (XMPPServer.getInstance().getIQAuthHandler().isAllowAnonymous()) {
sb.append("<auth xmlns=\"http://jabber.org/features/iq-auth\"/>");
}
// Advertise that the server supports In-Band Registration
if (XMPPServer.getInstance().getIQRegisterHandler().isInbandRegEnabled()) {
sb.append("<register xmlns=\"http://jabber.org/features/iq-register\"/>");
}
}
else {
// If the session has been authenticated then offer resource binding
// and session establishment
sb.append("<bind xmlns=\"urn:ietf:params:xml:ns:xmpp-bind\"/>");
sb.append("<session xmlns=\"urn:ietf:params:xml:ns:xmpp-session\"/>");
}
return sb.toString();
}
} }
...@@ -61,9 +61,4 @@ public class ComponentSocketReader extends SocketReader { ...@@ -61,9 +61,4 @@ public class ComponentSocketReader extends SocketReader {
boolean validateHost() { boolean validateHost() {
return false; return false;
} }
String getAvailableStreamFeatures() {
// Nothing special to add
return null;
}
} }
...@@ -218,9 +218,4 @@ public class ServerSocketReader extends SocketReader { ...@@ -218,9 +218,4 @@ public class ServerSocketReader extends SocketReader {
boolean validateHost() { boolean validateHost() {
return true; return true;
} }
String getAvailableStreamFeatures() {
// Nothing special to add
return null;
}
} }
...@@ -31,6 +31,7 @@ import java.util.Map; ...@@ -31,6 +31,7 @@ import java.util.Map;
import java.util.Collection; import java.util.Collection;
import java.util.Date; import java.util.Date;
import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ConcurrentHashMap;
import java.util.zip.*;
/** /**
* An object to track the state of a XMPP client-server session. * An object to track the state of a XMPP client-server session.
...@@ -59,6 +60,7 @@ public class SocketConnection implements Connection { ...@@ -59,6 +60,7 @@ public class SocketConnection implements Connection {
private Session session; private Session session;
private boolean secure; private boolean secure;
private boolean compressed;
private org.jivesoftware.util.XMLWriter xmlSerializer; private org.jivesoftware.util.XMLWriter xmlSerializer;
private boolean flashClient = false; private boolean flashClient = false;
private int majorVersion = 1; private int majorVersion = 1;
...@@ -73,6 +75,11 @@ public class SocketConnection implements Connection { ...@@ -73,6 +75,11 @@ public class SocketConnection implements Connection {
*/ */
private TLSPolicy tlsPolicy = TLSPolicy.optional; private TLSPolicy tlsPolicy = TLSPolicy.optional;
/**
* Compression policy currently in use for this connection.
*/
private CompressionPolicy compressionPolicy = CompressionPolicy.disabled;
public static Collection<SocketConnection> getInstances() { public static Collection<SocketConnection> getInstances() {
return instances.keySet(); return instances.keySet();
} }
...@@ -86,8 +93,7 @@ public class SocketConnection implements Connection { ...@@ -86,8 +93,7 @@ public class SocketConnection implements Connection {
* @throws NullPointerException if the socket is null. * @throws NullPointerException if the socket is null.
*/ */
public SocketConnection(PacketDeliverer deliverer, Socket socket, boolean isSecure) public SocketConnection(PacketDeliverer deliverer, Socket socket, boolean isSecure)
throws IOException throws IOException {
{
if (socket == null) { if (socket == null) {
throw new NullPointerException("Socket channel must be non-null"); throw new NullPointerException("Socket channel must be non-null");
} }
...@@ -127,6 +133,26 @@ public class SocketConnection implements Connection { ...@@ -127,6 +133,26 @@ public class SocketConnection implements Connection {
} }
} }
/**
* 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 {
compressed = true;
if (tlsStreamHandler == null) {
writer = new BufferedWriter(
new OutputStreamWriter(new ZipOutputStream(socket.getOutputStream()), CHARSET));
}
else {
writer = new BufferedWriter(new OutputStreamWriter(
new ZipOutputStream(tlsStreamHandler.getOutputStream()), CHARSET));
}
}
public boolean validate() { public boolean validate() {
if (isClosed()) { if (isClosed()) {
return false; return false;
...@@ -188,32 +214,26 @@ public class SocketConnection implements Connection { ...@@ -188,32 +214,26 @@ public class SocketConnection implements Connection {
return secure; return secure;
} }
/** public boolean isCompressed() {
* Returns whether TLS is mandatory, optional or is disabled. When TLS is mandatory clients return compressed;
* 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.
*
* @return whether TLS is mandatory, optional or is disabled.
*/
public TLSPolicy getTlsPolicy() { public TLSPolicy getTlsPolicy() {
return tlsPolicy; return tlsPolicy;
} }
/**
* 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.
*/
public void setTlsPolicy(TLSPolicy tlsPolicy) { public void setTlsPolicy(TLSPolicy tlsPolicy) {
this.tlsPolicy = tlsPolicy; this.tlsPolicy = tlsPolicy;
} }
public CompressionPolicy getCompressionPolicy() {
return compressionPolicy;
}
public void setCompressionPolicy(CompressionPolicy compressionPolicy) {
this.compressionPolicy = compressionPolicy;
}
public int getMajorXMPPVersion() { public int getMajorXMPPVersion() {
return majorVersion; return majorVersion;
} }
...@@ -334,7 +354,7 @@ public class SocketConnection implements Connection { ...@@ -334,7 +354,7 @@ public class SocketConnection implements Connection {
* sending data over the socket has taken a long time and we need to close the socket, discard * sending data over the socket has taken a long time and we need to close the socket, discard
* the connection and its session. * the connection and its session.
*/ */
void forceClose() { private void forceClose() {
if (session != null) { if (session != null) {
// Set that the session is closed. This will prevent threads from trying to // Set that the session is closed. This will prevent threads from trying to
// deliver packets to this session thus preventing future locks. // deliver packets to this session thus preventing future locks.
...@@ -439,7 +459,12 @@ public class SocketConnection implements Connection { ...@@ -439,7 +459,12 @@ public class SocketConnection implements Connection {
private void notifyCloseListeners() { private void notifyCloseListeners() {
synchronized (listeners) { synchronized (listeners) {
for (ConnectionCloseListener listener : listeners.keySet()) { for (ConnectionCloseListener listener : listeners.keySet()) {
listener.onConnectionClose(listeners.get(listener)); try {
listener.onConnectionClose(listeners.get(listener));
}
catch (Exception e) {
Log.error("Error notifying listener: " + listener, e);
}
} }
} }
} }
...@@ -448,27 +473,4 @@ public class SocketConnection implements Connection { ...@@ -448,27 +473,4 @@ public class SocketConnection implements Connection {
return super.toString() + " socket: " + socket + " session: " + session; return super.toString() + " socket: " + socket + " session: " + session;
} }
/**
* Enumeration of possible TLS policies required to interact with the server.
*/
public enum TLSPolicy {
/**
* TLS is required to interact with the server. Entities that do not secure their
* connections using TLS will get a stream error and their connections will be closed.
*/
required,
/**
* TLS is optional to interact with the server. Entities may or may not secure their
* connections using TLS.
*/
optional,
/**
* TLS is not available. Entities that request a TLS negotiation will get a stream
* error and their connections will be closed.
*/
disabled;
}
} }
\ No newline at end of file
...@@ -280,4 +280,9 @@ public class IncomingServerSession extends Session { ...@@ -280,4 +280,9 @@ public class IncomingServerSession extends Session {
public void verifyReceivedKey(Element doc) { public void verifyReceivedKey(Element doc) {
ServerDialback.verifyReceivedKey(doc, getConnection()); ServerDialback.verifyReceivedKey(doc, getConnection());
} }
public String getAvailableStreamFeatures() {
// Nothing special to add
return null;
}
} }
...@@ -503,4 +503,8 @@ public class OutgoingServerSession extends Session { ...@@ -503,4 +503,8 @@ public class OutgoingServerSession extends Session {
} }
} }
public String getAvailableStreamFeatures() {
// Nothing special to add
return null;
}
} }
...@@ -21,6 +21,7 @@ ...@@ -21,6 +21,7 @@
<%@ page import="org.jivesoftware.messenger.net.SocketConnection"%> <%@ page import="org.jivesoftware.messenger.net.SocketConnection"%>
<%@ page import="org.jivesoftware.messenger.XMPPServer"%> <%@ page import="org.jivesoftware.messenger.XMPPServer"%>
<%@ page import="org.jivesoftware.messenger.ConnectionManager"%> <%@ page import="org.jivesoftware.messenger.ConnectionManager"%>
<%@ page import="org.jivesoftware.messenger.Connection"%>
<%@ taglib uri="http://java.sun.com/jstl/core_rt" prefix="c" %> <%@ taglib uri="http://java.sun.com/jstl/core_rt" prefix="c" %>
<%@ taglib uri="http://java.sun.com/jstl/fmt_rt" prefix="fmt" %> <%@ taglib uri="http://java.sun.com/jstl/fmt_rt" prefix="fmt" %>
...@@ -49,7 +50,7 @@ ...@@ -49,7 +50,7 @@
// Enable 5222 port and make TLS required // Enable 5222 port and make TLS required
XMPPServer.getInstance().getConnectionManager().enableClientListener(true); XMPPServer.getInstance().getConnectionManager().enableClientListener(true);
ClientSession.setTLSPolicy(SocketConnection.TLSPolicy.required); ClientSession.setTLSPolicy(Connection.TLSPolicy.required);
// Enable 5223 port (old SSL port) // Enable 5223 port (old SSL port)
XMPPServer.getInstance().getConnectionManager().enableClientSSLListener(true); XMPPServer.getInstance().getConnectionManager().enableClientSSLListener(true);
} }
...@@ -58,7 +59,7 @@ ...@@ -58,7 +59,7 @@
// Enable 5222 port and make TLS optional // Enable 5222 port and make TLS optional
XMPPServer.getInstance().getConnectionManager().enableClientListener(true); XMPPServer.getInstance().getConnectionManager().enableClientListener(true);
ClientSession.setTLSPolicy(SocketConnection.TLSPolicy.optional); ClientSession.setTLSPolicy(Connection.TLSPolicy.optional);
// Enable 5223 port (old SSL port) // Enable 5223 port (old SSL port)
XMPPServer.getInstance().getConnectionManager().enableClientSSLListener(true); XMPPServer.getInstance().getConnectionManager().enableClientSSLListener(true);
} }
...@@ -71,13 +72,13 @@ ...@@ -71,13 +72,13 @@
// Enable port 5222 and configure TLS policy // Enable port 5222 and configure TLS policy
XMPPServer.getInstance().getConnectionManager().enableClientListener(true); XMPPServer.getInstance().getConnectionManager().enableClientListener(true);
if ("notavailable".equals(tls)) { if ("notavailable".equals(tls)) {
ClientSession.setTLSPolicy(SocketConnection.TLSPolicy.disabled); ClientSession.setTLSPolicy(Connection.TLSPolicy.disabled);
} }
else if ("optional".equals(tls)) { else if ("optional".equals(tls)) {
ClientSession.setTLSPolicy(SocketConnection.TLSPolicy.optional); ClientSession.setTLSPolicy(Connection.TLSPolicy.optional);
} }
else { else {
ClientSession.setTLSPolicy(SocketConnection.TLSPolicy.required); ClientSession.setTLSPolicy(Connection.TLSPolicy.required);
} }
} }
success = true; success = true;
...@@ -86,12 +87,12 @@ ...@@ -86,12 +87,12 @@
// Set page vars // Set page vars
ConnectionManager connectionManager = XMPPServer.getInstance().getConnectionManager(); ConnectionManager connectionManager = XMPPServer.getInstance().getConnectionManager();
if (connectionManager.isClientListenerEnabled() && connectionManager.isClientSSLListenerEnabled()) { if (connectionManager.isClientListenerEnabled() && connectionManager.isClientSSLListenerEnabled()) {
if (SocketConnection.TLSPolicy.required.equals(ClientSession.getTLSPolicy())) { if (Connection.TLSPolicy.required.equals(ClientSession.getTLSPolicy())) {
clientSecurityRequired = "req"; clientSecurityRequired = "req";
ssl = "available"; ssl = "available";
tls = "required"; tls = "required";
} }
else if (SocketConnection.TLSPolicy.optional.equals(ClientSession.getTLSPolicy())) { else if (Connection.TLSPolicy.optional.equals(ClientSession.getTLSPolicy())) {
clientSecurityRequired = "notreq"; clientSecurityRequired = "notreq";
ssl = "available"; ssl = "available";
tls = "optional"; tls = "optional";
...@@ -105,7 +106,7 @@ ...@@ -105,7 +106,7 @@
else { else {
clientSecurityRequired = "custom"; clientSecurityRequired = "custom";
ssl = connectionManager.isClientSSLListenerEnabled() ? "available" : "notavailable"; ssl = connectionManager.isClientSSLListenerEnabled() ? "available" : "notavailable";
tls = SocketConnection.TLSPolicy.disabled.equals(ClientSession.getTLSPolicy()) ? "notavailable" : ClientSession.getTLSPolicy().toString(); tls = Connection.TLSPolicy.disabled.equals(ClientSession.getTLSPolicy()) ? "notavailable" : ClientSession.getTLSPolicy().toString();
} }
if (install) { if (install) {
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment