Commit c2c0d409 authored by Alex Wenckus's avatar Alex Wenckus Committed by alex

Refactored file transfer manager code out of file transfer proxy and into file trasnfer manager

git-svn-id: http://svn.igniterealtime.org/svn/repos/wildfire/trunk@4333 b35dd754-fafc-0310-a699-88a17e54d16e
parent 6fbd2e7a
......@@ -30,6 +30,8 @@ import org.jivesoftware.wildfire.disco.IQDiscoItemsHandler;
import org.jivesoftware.wildfire.disco.ServerFeaturesProvider;
import org.jivesoftware.wildfire.disco.ServerItemsProvider;
import org.jivesoftware.wildfire.filetransfer.FileTransferProxy;
import org.jivesoftware.wildfire.filetransfer.FileTransferManager;
import org.jivesoftware.wildfire.filetransfer.spi.DefaultFileTransferManager;
import org.jivesoftware.wildfire.handler.*;
import org.jivesoftware.wildfire.muc.MultiUserChatServer;
import org.jivesoftware.wildfire.muc.spi.MultiUserChatServerImpl;
......@@ -447,6 +449,7 @@ public class XMPPServer {
loadModule(IQSharedGroupHandler.class.getName());
loadModule(AdHocCommandHandler.class.getName());
loadModule(IQPrivacyHandler.class.getName());
loadModule(DefaultFileTransferManager.class.getName());
loadModule(FileTransferProxy.class.getName());
loadModule(PubSubModule.class.getName());
loadModule(UpdateManager.class.getName());
......@@ -1177,4 +1180,15 @@ public class XMPPServer {
public FileTransferProxy getFileTransferProxy() {
return (FileTransferProxy) modules.get(FileTransferProxy.class);
}
/**
* Returns the <code>FileTransferManager</code> registered with this server. The
* <code>FileTransferManager</code> was registered with the server as a module while starting up
* the server.
*
* @return the <code>FileTransferProxy</code> registered with this server.
*/
public FileTransferManager getFileTransferManager() {
return (FileTransferManager) modules.get(DefaultFileTransferManager.class);
}
}
......@@ -13,17 +13,32 @@ package org.jivesoftware.wildfire.filetransfer;
import org.jivesoftware.util.JiveGlobals;
import org.jivesoftware.util.Cache;
import org.jivesoftware.wildfire.auth.UnauthorizedException;
import org.jivesoftware.wildfire.container.BasicModule;
import org.jivesoftware.wildfire.interceptor.InterceptorManager;
import org.jivesoftware.wildfire.interceptor.PacketInterceptor;
import org.jivesoftware.wildfire.interceptor.PacketRejectedException;
import org.jivesoftware.wildfire.Session;
import org.dom4j.Element;
import org.xmpp.packet.Packet;
import org.xmpp.packet.IQ;
import org.xmpp.packet.JID;
import java.util.Map;
import java.util.List;
import java.util.Arrays;
/**
* Provides several utility methods for file transfer manager implementaions to utilize.
*
* @author Alexander Wenckus
*/
public abstract class AbstractFileTransferManager implements FileTransferManager {
public abstract class AbstractFileTransferManager
extends BasicModule implements FileTransferManager
{
private static final List<String> FILETRANSFER_NAMESPACES
= Arrays.asList(NAMESPACE_BYTESTREAMS, NAMESPACE_SI);
private static final String CACHE_NAME = "File Transfer Cache";
private final Map<String, FileTransfer> fileTransferMap;
......@@ -32,10 +47,14 @@ public abstract class AbstractFileTransferManager implements FileTransferManager
* Default constructor creates the cache.
*/
public AbstractFileTransferManager() {
super("File Transfer Manager");
fileTransferMap = createCache(CACHE_NAME, "fileTransfer", 128 * 1024, 1000 * 60 * 10);
InterceptorManager.getInstance().addInterceptor(new FileTransferInterceptor());
}
private Cache<String, FileTransfer> createCache(String name, String propertiesName, int size, long expirationTime) {
private Cache<String, FileTransfer> createCache(String name, String propertiesName, int size,
long expirationTime)
{
size = JiveGlobals.getIntProperty("cache." + propertiesName + ".size", size);
expirationTime = (long) JiveGlobals.getIntProperty(
"cache." + propertiesName + ".expirationTime", (int) expirationTime);
......@@ -43,23 +62,25 @@ public abstract class AbstractFileTransferManager implements FileTransferManager
}
/**
* Returns true if the proxy transfer should be matched to an existing file transfer in the system.
* Returns true if the proxy transfer should be matched to an existing file transfer
* in the system.
*
* @return Returns true if the proxy transfer should be matched to an existing file transfer in the system.
* @return Returns true if the proxy transfer should be matched to an existing file
* transfer in the system.
*/
public boolean isMatchProxyTransfer() {
return JiveGlobals.getBooleanProperty("xmpp.proxy.transfer.required", true);
}
public void cacheFileTransfer(String key, FileTransfer transfer) {
protected void cacheFileTransfer(String key, FileTransfer transfer) {
fileTransferMap.put(key, transfer);
}
public FileTransfer retrieveFileTransfer(String key) {
protected FileTransfer retrieveFileTransfer(String key) {
return fileTransferMap.get(key);
}
public static Element getChildElement(Element element, String namespace) {
protected static Element getChildElement(Element element, String namespace) {
List elements = element.elements();
if (elements.isEmpty()) {
return null;
......@@ -89,4 +110,49 @@ public abstract class AbstractFileTransferManager implements FileTransferManager
transfer.setProgress(proxyTransfer);
cacheFileTransfer(transferDigest, transfer);
}
public void enableFileTransfer(boolean isEnabled) {
JiveGlobals.setProperty(JIVEPROPERTY_FILE_TRANSFER_ENABLED, Boolean.toString(isEnabled));
}
public boolean isFileTransferEnabled() {
return JiveGlobals.getBooleanProperty(JIVEPROPERTY_FILE_TRANSFER_ENABLED,
DEFAULT_IS_FILE_TRANSFER_ENABLED);
}
/**
* Interceptor to grab and validate file transfer meta information.
*/
private class FileTransferInterceptor implements PacketInterceptor {
public void interceptPacket(Packet packet, Session session, boolean incoming,
boolean processed)
throws PacketRejectedException
{
// We only want packets recieved by the server
if (!processed && incoming && packet instanceof IQ) {
IQ iq = (IQ) packet;
Element childElement = iq.getChildElement();
if(childElement == null) {
return;
}
String namespace = childElement.getNamespaceURI();
if(!isFileTransferEnabled() && FILETRANSFER_NAMESPACES.contains(namespace)) {
throw new PacketRejectedException("File Transfer Disabled");
}
if (NAMESPACE_SI.equals(namespace)) {
// If this is a set, check the feature offer
if (iq.getType().equals(IQ.Type.set)) {
JID from = iq.getFrom();
JID to = iq.getTo();
String packetID = iq.getID();
if (!acceptIncomingFileTransferRequest(packetID, from, to, childElement)) {
throw new PacketRejectedException();
}
}
}
}
}
}
}
......@@ -13,33 +13,74 @@ package org.jivesoftware.wildfire.filetransfer;
import org.xmpp.packet.JID;
import org.dom4j.Element;
import org.jivesoftware.wildfire.auth.UnauthorizedException;
import org.jivesoftware.wildfire.container.Module;
/**
* Manages all file transfer currently happening originating from and/or ending at users of the server. From here,
* file transfers can be administered and stats can be tracked.
* Manages all file transfer currently happening originating from and/or ending at users of the
* server. From here, file transfers can be administered and stats can be tracked.
*
* @author Alexander Wenckus
*/
public interface FileTransferManager {
public interface FileTransferManager extends Module {
/**
* The JiveProperty relating to whether or not file transfer is currently enabled. If file
* transfer is disabled all known file transfer related packets are blocked, it also goes
* with out saying that the file transfer proxy is then disabled.
*/
public static final String JIVEPROPERTY_FILE_TRANSFER_ENABLED = "xmpp.filetransfer.enabled";
/**
* Whether or not the file transfer is enabled by default.
*/
public static final boolean DEFAULT_IS_FILE_TRANSFER_ENABLED = true;
/**
* Stream Initiation, SI, namespace
*/
public static final String NAMESPACE_SI = "http://jabber.org/protocol/si";
/**
* Bytestreams namespace
*/
public static final String NAMESPACE_BYTESTREAMS = "http://jabber.org/protocol/bytestreams";
/**
* Checks an incoming file transfer request to see if it should be accepted or rejected.
* If it is accepted true will be returned and if it is rejected false will be returned.
*
* @param packetID The packet ID of the packet being parsed.
* @param from The offerer The offerer of the file transfer.
* @param to The receiver The potential reciever of the file transfer.
* @param siElement The Stream Initiation element
* @return True if it should be accepted false if it should not.
* @param packetID the packet ID of the packet being parsed.
* @param from the offerer The offerer of the file transfer.
* @param to The receiver the potential reciever of the file transfer.
* @param siElement the Stream Initiation element
* @return true if it should be accepted false if it should not.
*/
boolean acceptIncomingFileTransferRequest(String packetID, JID from, JID to, Element siElement);
/**
* Registers that a transfer has begun through the proxy connected to the server.
*
* @param transferDigest The digest of the initiator + target + sessionID that uniquely identifies a file transfer
* @param proxyTransfer The related proxy transfer.
* @throws UnauthorizedException Thrown when in the current server configuration this transfer should not be
* permitted.
* @param transferDigest the digest of the initiator + target + sessionID that uniquely
* identifies a file transfer
* @param proxyTransfer the related proxy transfer.
* @throws UnauthorizedException when in the current server configuration this transfer
* should not be permitted.
*/
public void registerProxyTransfer(String transferDigest, ProxyTransfer proxyTransfer)
throws UnauthorizedException;
/**
* Enables or disable all file transfers going through the server. This includes the blocking
* of file transfer related packets from reaching their recipients.
*
* @param isEnabled true if file transfer should be enabled and false if it should not be.
*/
public void enableFileTransfer(boolean isEnabled);
/**
* Returns whether or not file transfer is currently enabled in the server.
*
* @return true if file transfer is enabled and false if it is not
*/
public void registerProxyTransfer(String transferDigest, ProxyTransfer proxyTransfer) throws UnauthorizedException;
public boolean isFileTransferEnabled();
}
......@@ -18,10 +18,6 @@ import org.jivesoftware.util.Log;
import org.jivesoftware.util.PropertyEventDispatcher;
import org.jivesoftware.util.PropertyEventListener;
import org.jivesoftware.wildfire.*;
import org.jivesoftware.wildfire.filetransfer.spi.DefaultFileTransferManager;
import org.jivesoftware.wildfire.interceptor.InterceptorManager;
import org.jivesoftware.wildfire.interceptor.PacketInterceptor;
import org.jivesoftware.wildfire.interceptor.PacketRejectedException;
import org.jivesoftware.wildfire.auth.UnauthorizedException;
import org.jivesoftware.wildfire.container.BasicModule;
import org.jivesoftware.wildfire.disco.*;
......@@ -45,13 +41,6 @@ import java.util.*;
public class FileTransferProxy extends BasicModule
implements ServerItemsProvider, DiscoInfoProvider, DiscoItemsProvider,
RoutableChannelHandler {
/**
* The JiveProperty relating to whether or not file transfer is currently enabled. If file transfer is disabled
* all known file transfer related packets are blocked, it also goes with out saying that the file transfer proxy
* is then disabled.
*/
public static final String JIVEPROPERTY_FILE_TRANSFER_ENABLED = "xmpp.filetransfer.enabled";
/**
* The JiveProperty relating to whether or not the file treansfer proxy is enabled.
*/
......@@ -68,26 +57,11 @@ public class FileTransferProxy extends BasicModule
*/
public static final boolean DEFAULT_IS_PROXY_ENABLED = true;
/**
* Whether or not the file transfer is enabled.
*/
public static final boolean DEFAULT_IS_FILE_TRANSFER_ENABLED = true;
/**
* The default port of the file transfer proxy
*/
public static final int DEFAULT_PORT = 7777;
private static final String NAMESPACE_BYTESTREAMS = "http://jabber.org/protocol/bytestreams";
/**
* Stream Initiation, SI, namespace
*/
private static final String NAMESPACE_SI = "http://jabber.org/protocol/si";
private static final List<String> FILETRANSFER_NAMESPACES
= Arrays.asList(NAMESPACE_BYTESTREAMS, NAMESPACE_SI);
private String proxyServiceName;
private IQHandlerInfo info;
......@@ -96,15 +70,15 @@ public class FileTransferProxy extends BasicModule
private String proxyIP;
private ProxyConnectionManager connectionManager;
private FileTransferManager transferManager;
private boolean isFileTransferEnabled;
private InetAddress bindInterface;
public FileTransferProxy() {
super("SOCKS5 file transfer proxy");
info = new IQHandlerInfo("query", NAMESPACE_BYTESTREAMS);
InterceptorManager.getInstance().addInterceptor(new FileTransferInterceptor());
info = new IQHandlerInfo("query", FileTransferManager.NAMESPACE_BYTESTREAMS);
PropertyEventDispatcher.addListener(new FileTransferPropertyListener());
}
......@@ -141,10 +115,11 @@ public class FileTransferProxy extends BasicModule
// Do nothing. This error should never happen
}
}
else if (NAMESPACE_BYTESTREAMS.equals(namespace)) {
else if (FileTransferManager.NAMESPACE_BYTESTREAMS.equals(namespace)) {
if (packet.getType() == IQ.Type.get) {
IQ reply = IQ.createResultIQ(packet);
Element newChild = reply.setChildElement("query", NAMESPACE_BYTESTREAMS);
Element newChild = reply.setChildElement("query",
FileTransferManager.NAMESPACE_BYTESTREAMS);
Element response = newChild.addElement("streamhost");
response.addAttribute("jid", getServiceDomain());
response.addAttribute("host", proxyIP);
......@@ -208,13 +183,12 @@ public class FileTransferProxy extends BasicModule
Log.error("Couldn't discover local host", e);
}
transferManager = getFileTransferManager();
transferManager = getFileTransferManager(server);
connectionManager = new ProxyConnectionManager(transferManager);
isFileTransferEnabled = isFileTransferEnabled();
}
private FileTransferManager getFileTransferManager() {
return new DefaultFileTransferManager();
private FileTransferManager getFileTransferManager(XMPPServer server) {
return server.getFileTransferManager();
}
public void start() {
......@@ -251,12 +225,9 @@ public class FileTransferProxy extends BasicModule
connectionManager.shutdown();
}
public void enableFileTransfer(boolean isEnabled) {
JiveGlobals.setProperty(JIVEPROPERTY_FILE_TRANSFER_ENABLED, Boolean.toString(isEnabled));
}
public void enableFileTransferProxy(boolean isEnabled) {
JiveGlobals.setProperty(FileTransferProxy.JIVEPROPERTY_PROXY_ENABLED, Boolean.toString(isEnabled));
JiveGlobals.setProperty(FileTransferProxy.JIVEPROPERTY_PROXY_ENABLED,
Boolean.toString(isEnabled));
}
private void setEnabled(boolean isEnabled) {
......@@ -268,15 +239,6 @@ public class FileTransferProxy extends BasicModule
}
}
private void setEnabledFileTransfer(boolean isEnabled) {
isFileTransferEnabled = isEnabled;
setEnabled(isEnabled && JiveGlobals.getBooleanProperty(JIVEPROPERTY_PROXY_ENABLED, DEFAULT_IS_PROXY_ENABLED));
}
public boolean isFileTransferEnabled() {
return JiveGlobals.getBooleanProperty(JIVEPROPERTY_FILE_TRANSFER_ENABLED, DEFAULT_IS_FILE_TRANSFER_ENABLED);
}
/**
* Returns true if the file transfer proxy is currently enabled and false if it is not.
*
......@@ -288,8 +250,8 @@ public class FileTransferProxy extends BasicModule
}
private boolean isEnabled() {
return isFileTransferEnabled() && (connectionManager.isRunning() ||
JiveGlobals.getBooleanProperty(JIVEPROPERTY_PROXY_ENABLED, DEFAULT_IS_PROXY_ENABLED));
return transferManager.isFileTransferEnabled() &&
JiveGlobals.getBooleanProperty(JIVEPROPERTY_PROXY_ENABLED, DEFAULT_IS_PROXY_ENABLED);
}
/**
......@@ -373,8 +335,8 @@ public class FileTransferProxy extends BasicModule
}
public Iterator<String> getFeatures(String name, String node, JID senderJID) {
return Arrays.asList(NAMESPACE_BYTESTREAMS, "http://jabber.org/protocol/disco#info")
.iterator();
return Arrays.asList(FileTransferManager.NAMESPACE_BYTESTREAMS,
"http://jabber.org/protocol/disco#info").iterator();
}
public XDataFormImpl getExtendedInfo(String name, String node, JID senderJID) {
......@@ -405,61 +367,33 @@ public class FileTransferProxy extends BasicModule
}
}
/**
* Interceptor to grab and validate file transfer meta information.
*/
private class FileTransferInterceptor implements PacketInterceptor {
public void interceptPacket(Packet packet, Session session, boolean incoming, boolean processed)
throws PacketRejectedException {
// We only want packets recieved by the server
if (!processed && incoming && packet instanceof IQ) {
IQ iq = (IQ) packet;
Element childElement = iq.getChildElement();
if(childElement == null) {
return;
}
String namespace = childElement.getNamespaceURI();
if(!isFileTransferEnabled && FILETRANSFER_NAMESPACES.contains(namespace)) {
throw new PacketRejectedException("File Transfer Disabled");
}
if (NAMESPACE_SI.equals(namespace)) {
// If this is a set, check the feature offer
if (iq.getType().equals(IQ.Type.set)) {
JID from = iq.getFrom();
JID to = iq.getTo();
String packetID = iq.getID();
if (!transferManager.acceptIncomingFileTransferRequest(packetID, from, to, childElement)) {
throw new PacketRejectedException();
}
}
}
}
}
}
private class FileTransferPropertyListener implements PropertyEventListener {
public void propertySet(String property, Map params) {
if(JIVEPROPERTY_PROXY_ENABLED.equalsIgnoreCase(property)) {
Object value = params.get("value");
boolean isEnabled = (value != null ? Boolean.parseBoolean(value.toString()) : DEFAULT_IS_PROXY_ENABLED);
setEnabled(isEnabled && isFileTransferEnabled());
boolean isEnabled = (value != null ? Boolean.parseBoolean(value.toString()) :
DEFAULT_IS_PROXY_ENABLED);
setEnabled(isEnabled && transferManager.isFileTransferEnabled());
}
else if(JIVEPROPERTY_FILE_TRANSFER_ENABLED.equalsIgnoreCase(property)) {
else if(FileTransferManager.JIVEPROPERTY_FILE_TRANSFER_ENABLED
.equalsIgnoreCase(property))
{
Object value = params.get("value");
boolean isEnabled = (value != null ? Boolean.parseBoolean(value.toString())
: DEFAULT_IS_FILE_TRANSFER_ENABLED);
setEnabledFileTransfer(isEnabled);
: FileTransferManager.DEFAULT_IS_FILE_TRANSFER_ENABLED);
setEnabled(isEnabled && JiveGlobals.getBooleanProperty(JIVEPROPERTY_PROXY_ENABLED,
DEFAULT_IS_PROXY_ENABLED));
}
}
public void propertyDeleted(String property, Map params) {
if(JIVEPROPERTY_PROXY_ENABLED.equalsIgnoreCase(property)) {
setEnabled(DEFAULT_IS_PROXY_ENABLED && isFileTransferEnabled());
setEnabled(DEFAULT_IS_PROXY_ENABLED && transferManager.isFileTransferEnabled());
}
else if(JIVEPROPERTY_FILE_TRANSFER_ENABLED.equalsIgnoreCase(property)){
setEnabledFileTransfer(DEFAULT_IS_FILE_TRANSFER_ENABLED);
else if(FileTransferManager.JIVEPROPERTY_FILE_TRANSFER_ENABLED.
equalsIgnoreCase(property)){setEnabled(FileTransferManager.
DEFAULT_IS_FILE_TRANSFER_ENABLED && JiveGlobals.
getBooleanProperty(JIVEPROPERTY_PROXY_ENABLED, DEFAULT_IS_PROXY_ENABLED));
}
}
......
......@@ -55,8 +55,6 @@ public class ProxyConnectionManager {
private String className;
private ProxyTracker proxyTracker;
public ProxyConnectionManager(FileTransferManager manager) {
String cacheName = "File Transfer";
connectionMap = new Cache<String, ProxyTransfer>(cacheName, -1, 1000 * 60 * 10);
......@@ -65,7 +63,7 @@ public class ProxyConnectionManager {
"org.jivesoftware.wildfire.filetransfer.spi.DefaultProxyTransfer");
transferManager = manager;
this.proxyTracker = new ProxyTracker();
StatisticsManager.getInstance().addStatistic(proxyTransferRate, new ProxyTracker());
}
/*
......@@ -79,7 +77,6 @@ public class ProxyConnectionManager {
}
}
reset();
socketProcess = executor.submit(new Runnable() {
public void run() {
try {
......@@ -124,7 +121,6 @@ public class ProxyConnectionManager {
}
});
proxyPort = port;
StatisticsManager.getInstance().addStatistic(proxyTransferRate, proxyTracker);
}
public int getProxyPort() {
......
......@@ -17,9 +17,9 @@ import org.jivesoftware.wildfire.filetransfer.FileTransfer;
import org.jivesoftware.wildfire.filetransfer.ProxyConnectionManager;
/**
* The default implementation of the file transfer manager. The only acceptance criteria for a proxy
* The default implementation of the file transfer manager. The only acceptance criteria for a proxy
* transfer is employed in the <i>ProxyConnectionManager</i>, it checks that the file transfers stored
* hre
* here.
*/
public class DefaultFileTransferManager extends AbstractFileTransferManager {
public boolean acceptIncomingFileTransferRequest(String packetID, JID from, JID to, Element siElement) {
......
......@@ -12,6 +12,7 @@
<%@ page import="java.util.HashMap" %>
<%@ page import="java.util.Map" %>
<%@ page import="org.jivesoftware.wildfire.XMPPServer"%>
<%@ page import="org.jivesoftware.wildfire.filetransfer.FileTransferManager"%>
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<%@ taglib uri="http://java.sun.com/jstl/fmt_rt" prefix="fmt" %>
......@@ -22,8 +23,9 @@
<%
Map<String, String> errors = new HashMap<String, String>();
FileTransferProxy transferProxy = XMPPServer.getInstance().getFileTransferProxy();
FileTransferManager manager = XMPPServer.getInstance().getFileTransferManager();
boolean isFileTransferEnabled = transferProxy.isFileTransferEnabled();
boolean isFileTransferEnabled = manager.isFileTransferEnabled();
boolean isUpdated = request.getParameter("update") != null;
boolean isProxyEnabled = ParamUtils.getBooleanParameter(request, "proxyEnabled");
......
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