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
...@@ -11,8 +11,8 @@ ...@@ -11,8 +11,8 @@
package org.jivesoftware.messenger.net; package org.jivesoftware.messenger.net;
import org.dom4j.Element;
import org.dom4j.DocumentException; import org.dom4j.DocumentException;
import org.dom4j.Element;
import org.dom4j.io.XPPPacketReader; import org.dom4j.io.XPPPacketReader;
import org.jivesoftware.messenger.*; import org.jivesoftware.messenger.*;
import org.jivesoftware.messenger.auth.UnauthorizedException; import org.jivesoftware.messenger.auth.UnauthorizedException;
...@@ -33,6 +33,7 @@ import java.io.InputStreamReader; ...@@ -33,6 +33,7 @@ import java.io.InputStreamReader;
import java.net.Socket; import java.net.Socket;
import java.net.SocketException; import java.net.SocketException;
import java.nio.channels.AsynchronousCloseException; import java.nio.channels.AsynchronousCloseException;
import java.util.zip.ZipInputStream;
/** /**
* A SocketReader creates the appropriate {@link Session} based on the defined namespace in the * A SocketReader creates the appropriate {@link Session} based on the defined namespace in the
...@@ -260,7 +261,6 @@ public abstract class SocketReader implements Runnable { ...@@ -260,7 +261,6 @@ public abstract class SocketReader implements Runnable {
open = false; open = false;
session = null; session = null;
} }
continue;
} }
else if ("auth".equals(tag)) { else if ("auth".equals(tag)) {
// User is trying to authenticate using SASL // User is trying to authenticate using SASL
...@@ -273,9 +273,22 @@ public abstract class SocketReader implements Runnable { ...@@ -273,9 +273,22 @@ public abstract class SocketReader implements Runnable {
open = false; open = false;
session = null; session = null;
} }
continue;
} }
else { 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 {
open = false;
session = null;
}
}
else
{
if (!processUnknowPacket(doc)) { if (!processUnknowPacket(doc)) {
Log.warn(LocaleUtils.getLocalizedString("admin.error.packet.tag") + Log.warn(LocaleUtils.getLocalizedString("admin.error.packet.tag") +
doc.asXML()); doc.asXML());
...@@ -288,7 +301,7 @@ public abstract class SocketReader implements Runnable { ...@@ -288,7 +301,7 @@ public abstract class SocketReader implements Runnable {
private boolean authenticateClient(Element doc) throws DocumentException, IOException, private boolean authenticateClient(Element doc) throws DocumentException, IOException,
XmlPullParserException { XmlPullParserException {
// Ensure that connection was secured if TLS was required // Ensure that connection was secured if TLS was required
if (connection.getTlsPolicy() == SocketConnection.TLSPolicy.required && if (connection.getTlsPolicy() == Connection.TLSPolicy.required &&
!connection.isSecure()) { !connection.isSecure()) {
closeNeverSecuredConnection(); closeNeverSecuredConnection();
return false; return false;
...@@ -297,6 +310,59 @@ public abstract class SocketReader implements Runnable { ...@@ -297,6 +310,59 @@ public abstract class SocketReader implements Runnable {
return saslAuth.doHandshake(doc); return saslAuth.doHandshake(doc);
} }
/**
* 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.
*/
private boolean compressClient(Element doc) throws IOException {
String error = null;
if (connection.getCompressionPolicy() == Connection.CompressionPolicy.disabled) {
// Client requested compression but this feature is disabled
error = "<failure xmlns='http://jabber.org/protocol/compress'><setup-failed/></failure>";
// 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 : " + connection);
}
else if (connection.isCompressed()) {
// Client requested compression but connection is already compressed
error = "<failure xmlns='http://jabber.org/protocol/compress'><setup-failed/></failure>";
// 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 : " + connection);
}
else {
// Check that the requested method is supported
String method = doc.elementText("method");
if (!"zlib".equals(method)) {
error = "<failure xmlns='http://jabber.org/protocol/compress'><unsupported-method/></failure>";
// 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 : " + connection);
}
}
if (error != null) {
// Deliver stanza
connection.deliverRawText(error);
// Close the underlying connection
connection.close();
return false;
}
else {
// Start using compression
connection.startCompression();
return true;
}
}
/** /**
* Process the received IQ packet. Registered * Process the received IQ packet. Registered
* {@link org.jivesoftware.messenger.interceptor.PacketInterceptor} will be invoked before * {@link org.jivesoftware.messenger.interceptor.PacketInterceptor} will be invoked before
...@@ -310,7 +376,7 @@ public abstract class SocketReader implements Runnable { ...@@ -310,7 +376,7 @@ public abstract class SocketReader implements Runnable {
*/ */
protected void processIQ(IQ packet) throws UnauthorizedException { protected void processIQ(IQ packet) throws UnauthorizedException {
// Ensure that connection was secured if TLS was required // Ensure that connection was secured if TLS was required
if (connection.getTlsPolicy() == SocketConnection.TLSPolicy.required && if (connection.getTlsPolicy() == Connection.TLSPolicy.required &&
!connection.isSecure()) { !connection.isSecure()) {
closeNeverSecuredConnection(); closeNeverSecuredConnection();
return; return;
...@@ -359,7 +425,7 @@ public abstract class SocketReader implements Runnable { ...@@ -359,7 +425,7 @@ public abstract class SocketReader implements Runnable {
*/ */
protected void processPresence(Presence packet) throws UnauthorizedException { protected void processPresence(Presence packet) throws UnauthorizedException {
// Ensure that connection was secured if TLS was required // Ensure that connection was secured if TLS was required
if (connection.getTlsPolicy() == SocketConnection.TLSPolicy.required && if (connection.getTlsPolicy() == Connection.TLSPolicy.required &&
!connection.isSecure()) { !connection.isSecure()) {
closeNeverSecuredConnection(); closeNeverSecuredConnection();
return; return;
...@@ -407,7 +473,7 @@ public abstract class SocketReader implements Runnable { ...@@ -407,7 +473,7 @@ public abstract class SocketReader implements Runnable {
*/ */
protected void processMessage(Message packet) throws UnauthorizedException { protected void processMessage(Message packet) throws UnauthorizedException {
// Ensure that connection was secured if TLS was required // Ensure that connection was secured if TLS was required
if (connection.getTlsPolicy() == SocketConnection.TLSPolicy.required && if (connection.getTlsPolicy() == Connection.TLSPolicy.required &&
!connection.isSecure()) { !connection.isSecure()) {
closeNeverSecuredConnection(); closeNeverSecuredConnection();
return; return;
...@@ -576,7 +642,7 @@ public abstract class SocketReader implements Runnable { ...@@ -576,7 +642,7 @@ public abstract class SocketReader implements Runnable {
* @throws XmlPullParserException if an error occures while parsing. * @throws XmlPullParserException if an error occures while parsing.
*/ */
private boolean negotiateTLS() throws IOException, XmlPullParserException { private boolean negotiateTLS() throws IOException, XmlPullParserException {
if (connection.getTlsPolicy() == SocketConnection.TLSPolicy.disabled) { if (connection.getTlsPolicy() == Connection.TLSPolicy.disabled) {
// Set the not_authorized error // Set the not_authorized error
StreamError error = new StreamError(StreamError.Condition.not_authorized); StreamError error = new StreamError(StreamError.Condition.not_authorized);
// Deliver stanza // Deliver stanza
...@@ -617,13 +683,13 @@ public abstract class SocketReader implements Runnable { ...@@ -617,13 +683,13 @@ public abstract class SocketReader implements Runnable {
*/ */
private void tlsNegotiated() { private void tlsNegotiated() {
// Offer stream features including SASL Mechanisms // Offer stream features including SASL Mechanisms
StringBuilder sb = new StringBuilder(340); StringBuilder sb = new StringBuilder(620);
sb.append(geStreamHeader()); sb.append(geStreamHeader());
sb.append("<stream:features>"); sb.append("<stream:features>");
// Include available SASL Mechanisms // Include available SASL Mechanisms
sb.append(SASLAuthentication.getSASLMechanisms(session)); sb.append(SASLAuthentication.getSASLMechanisms(session));
// Include specific features such as auth and register for client sessions // Include specific features such as auth and register for client sessions
String specificFeatures = getAvailableStreamFeatures(); String specificFeatures = session.getAvailableStreamFeatures();
if (specificFeatures != null) { if (specificFeatures != null) {
sb.append(specificFeatures); sb.append(specificFeatures);
} }
...@@ -638,43 +704,84 @@ public abstract class SocketReader implements Runnable { ...@@ -638,43 +704,84 @@ public abstract class SocketReader implements Runnable {
* to servers or external components) * to servers or external components)
*/ */
private void saslSuccessful() throws XmlPullParserException, IOException { private void saslSuccessful() throws XmlPullParserException, IOException {
StringBuilder sb = new StringBuilder(145); XmlPullParser xpp = reader.getXPPParser();
// Reset the parser since a new stream header has been sent from the client
if (connection.getTLSStreamHandler() == null)
{
xpp.setInput(new InputStreamReader(socket.getInputStream(), CHARSET));
}
else
{
xpp.setInput(new InputStreamReader(connection.getTLSStreamHandler().getInputStream(),
CHARSET));
}
// Skip the opening stream sent by the client
for (int eventType = xpp.getEventType(); eventType != XmlPullParser.START_TAG;)
{
eventType = xpp.next();
}
StringBuilder sb = new StringBuilder(420);
sb.append(geStreamHeader()); sb.append(geStreamHeader());
sb.append("<stream:features>"); sb.append("<stream:features>");
// Include specific features such as resource binding and session establishment // Include specific features such as resource binding and session establishment
// for client sessions // for client sessions
String specificFeatures = getAvailableStreamFeatures(); String specificFeatures = session.getAvailableStreamFeatures();
if (specificFeatures != null) { if (specificFeatures != null) {
sb.append(specificFeatures); sb.append(specificFeatures);
} }
sb.append("</stream:features>"); sb.append("</stream:features>");
connection.deliverRawText(sb.toString()); connection.deliverRawText(sb.toString());
}
/**
* 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)
*/
private void compressionSuccessful() throws XmlPullParserException, IOException
{
connection.deliverRawText("<compressed xmlns='http://jabber.org/protocol/compress'/>");
XmlPullParser xpp = reader.getXPPParser(); XmlPullParser xpp = reader.getXPPParser();
// Reset the parser since a new stream header has been sent from the client // Reset the parser since a new stream header has been sent from the client
if (connection.getTLSStreamHandler() == null) { if (connection.getTLSStreamHandler() == null)
xpp.setInput(new InputStreamReader(socket.getInputStream(), CHARSET)); {
xpp.setInput(new InputStreamReader(new ZipInputStream (socket.getInputStream()), CHARSET));
} }
else { else
xpp.setInput(new InputStreamReader(connection.getTLSStreamHandler().getInputStream(), {
xpp.setInput(new InputStreamReader(new ZipInputStream (connection.getTLSStreamHandler().getInputStream()),
CHARSET)); CHARSET));
} }
// Skip the opening stream sent by the client // Skip the opening stream sent by the client
for (int eventType = xpp.getEventType(); eventType != XmlPullParser.START_TAG;) { for (int eventType = xpp.getEventType(); eventType != XmlPullParser.START_TAG;)
{
eventType = xpp.next(); eventType = xpp.next();
} }
}
/** StringBuilder sb = new StringBuilder(340);
* Returns a text with the available stream features. Each subclass may return different sb.append(geStreamHeader());
* values depending whether the session has been authenticated or not. sb.append("<stream:features>");
* // Include SASL mechanisms only if client has not been authenticated
* @return a text with the available stream features or <tt>null</tt> to add nothing. if (session.getStatus() != Session.STATUS_AUTHENTICATED) {
*/ // Include available SASL Mechanisms
abstract String getAvailableStreamFeatures(); sb.append(SASLAuthentication.getSASLMechanisms(session));
}
// Include specific features such as resource binding and session establishment
// for client sessions
String specificFeatures = session.getAvailableStreamFeatures();
if (specificFeatures != null)
{
sb.append(specificFeatures);
}
sb.append("</stream:features>");
connection.deliverRawText(sb.toString());
}
/** /**
* Returns the stream namespace. (E.g. jabber:client, jabber:server, etc.). * Returns the stream namespace. (E.g. jabber:client, jabber:server, etc.).
......
...@@ -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