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

First work on FileTransferInterceptor

git-svn-id: http://svn.igniterealtime.org/svn/repos/wildfire/trunk@4384 b35dd754-fafc-0310-a699-88a17e54d16e
parent 17f199b4
...@@ -49,7 +49,7 @@ public abstract class AbstractFileTransferManager ...@@ -49,7 +49,7 @@ public abstract class AbstractFileTransferManager
public AbstractFileTransferManager() { public AbstractFileTransferManager() {
super("File Transfer Manager"); super("File Transfer Manager");
fileTransferMap = createCache(CACHE_NAME, "fileTransfer", 128 * 1024, 1000 * 60 * 10); fileTransferMap = createCache(CACHE_NAME, "fileTransfer", 128 * 1024, 1000 * 60 * 10);
InterceptorManager.getInstance().addInterceptor(new FileTransferInterceptor()); InterceptorManager.getInstance().addInterceptor(new MetaFileTransferInterceptor());
} }
private Cache<String, FileTransfer> createCache(String name, String propertiesName, int size, private Cache<String, FileTransfer> createCache(String name, String propertiesName, int size,
...@@ -120,10 +120,21 @@ public abstract class AbstractFileTransferManager ...@@ -120,10 +120,21 @@ public abstract class AbstractFileTransferManager
DEFAULT_IS_FILE_TRANSFER_ENABLED); DEFAULT_IS_FILE_TRANSFER_ENABLED);
} }
public void addFileTransferInterceptor(FileTransferInterceptor interceptor) {
}
public void removeFileTransferInterceptor(FileTransferInterceptor interceptor) {
}
public void fireFileTransferIntercept(String transferDigest)
throws FileTransferRejectedException
{
}
/** /**
* Interceptor to grab and validate file transfer meta information. * Interceptor to grab and validate file transfer meta information.
*/ */
private class FileTransferInterceptor implements PacketInterceptor { private class MetaFileTransferInterceptor implements PacketInterceptor {
public void interceptPacket(Packet packet, Session session, boolean incoming, public void interceptPacket(Packet packet, Session session, boolean incoming,
boolean processed) boolean processed)
throws PacketRejectedException throws PacketRejectedException
......
/**
* $RCSfile: $
* $Revision: $
* $Date: $
*
* Copyright (C) 2006 Jive Software. All rights reserved.
* This software is the proprietary information of Jive Software. Use is subject to license terms.
*/
package org.jivesoftware.wildfire.filetransfer;
/**
* Interface used to capture a file transfer before it begins.
*
* @author Alexander Wenckus
*/
public interface FileTransferInterceptor {
/**
* Invokes the interceptor on the specified file transfer. The interceptor can either modify
* the file transfer or throw a FileTransferRejectedException.
*
* @param transfer
*/
void interceptFileTransfer(FileTransfer transfer) throws FileTransferRejectedException;
}
...@@ -28,22 +28,22 @@ public interface FileTransferManager extends Module { ...@@ -28,22 +28,22 @@ public interface FileTransferManager extends Module {
* transfer is disabled all known file transfer related packets are blocked, it also goes * 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. * with out saying that the file transfer proxy is then disabled.
*/ */
public static final String JIVEPROPERTY_FILE_TRANSFER_ENABLED = "xmpp.filetransfer.enabled"; static final String JIVEPROPERTY_FILE_TRANSFER_ENABLED = "xmpp.filetransfer.enabled";
/** /**
* Whether or not the file transfer is enabled by default. * Whether or not the file transfer is enabled by default.
*/ */
public static final boolean DEFAULT_IS_FILE_TRANSFER_ENABLED = true; static final boolean DEFAULT_IS_FILE_TRANSFER_ENABLED = true;
/** /**
* Stream Initiation, SI, namespace * Stream Initiation, SI, namespace
*/ */
public static final String NAMESPACE_SI = "http://jabber.org/protocol/si"; static final String NAMESPACE_SI = "http://jabber.org/protocol/si";
/** /**
* Bytestreams namespace * Bytestreams namespace
*/ */
public static final String NAMESPACE_BYTESTREAMS = "http://jabber.org/protocol/bytestreams"; 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. * Checks an incoming file transfer request to see if it should be accepted or rejected.
...@@ -66,7 +66,7 @@ public interface FileTransferManager extends Module { ...@@ -66,7 +66,7 @@ public interface FileTransferManager extends Module {
* @throws UnauthorizedException when in the current server configuration this transfer * @throws UnauthorizedException when in the current server configuration this transfer
* should not be permitted. * should not be permitted.
*/ */
public void registerProxyTransfer(String transferDigest, ProxyTransfer proxyTransfer) void registerProxyTransfer(String transferDigest, ProxyTransfer proxyTransfer)
throws UnauthorizedException; throws UnauthorizedException;
/** /**
...@@ -75,12 +75,18 @@ public interface FileTransferManager extends Module { ...@@ -75,12 +75,18 @@ public interface FileTransferManager extends Module {
* *
* @param isEnabled true if file transfer should be enabled and false if it should not be. * @param isEnabled true if file transfer should be enabled and false if it should not be.
*/ */
public void enableFileTransfer(boolean isEnabled); void enableFileTransfer(boolean isEnabled);
/** /**
* Returns whether or not file transfer is currently enabled in the server. * 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 * @return true if file transfer is enabled and false if it is not
*/ */
public boolean isFileTransferEnabled(); boolean isFileTransferEnabled();
void addFileTransferInterceptor(FileTransferInterceptor interceptor);
void removeFileTransferInterceptor(FileTransferInterceptor interceptor);
void fireFileTransferIntercept(String transferDigest) throws FileTransferRejectedException;
} }
...@@ -10,16 +10,59 @@ ...@@ -10,16 +10,59 @@
*/ */
package org.jivesoftware.wildfire.filetransfer; package org.jivesoftware.wildfire.filetransfer;
import java.util.concurrent.Future;
import java.io.InputStream;
import java.io.OutputStream;
/** /**
* An interface to track the progress of a file transfer through the server. This interface is used * An interface to track the progress of a file transfer through the server. This interface is used
* by {@link FileTransfer} to make this information available if it is in the system. * by {@link FileTransfer} to make this information available if it is in the system.
*
* @author Alexander Wenckus
*/ */
public interface FileTransferProgress { public interface FileTransferProgress {
public long getAmountTransfered() throws UnsupportedOperationException; public long getAmountTransfered() throws UnsupportedOperationException;
/**
* Returns the fully qualified JID of the initiator of the file transfer.
*
* @return the fully qualified JID of the initiator of the file transfer.
*/
public String getInitiator(); public String getInitiator();
public void setInitiator(String initiator);
/**
* Returns the full qualified JID of the target of the file transfer.
*
* @return the fully qualified JID of the target
*/
public String getTarget(); public String getTarget();
public void setTarget(String target);
/**
* Returns the unique session id that correlates to the file transfer.
*
* @return Returns the unique session id that correlates to the file transfer.
*/
public String getSessionID(); public String getSessionID();
public void setSessionID(String streamID);
/**
* When the file transfer is being caried out by another thread this will set the Future
* relating to the thread that is carrying out the transfer.
*
* @param future the furute that is carrying out the transfer
*/
public void setTransferFuture(Future<?> future);
public void setInputStream(InputStream initiatorInputStream);
public InputStream getInputStream();
public void setOutputStream(OutputStream targetOutputStream);
public OutputStream getOutputStream();
} }
/**
* $RCSfile: $
* $Revision: $
* $Date: $
*
* Copyright (C) 2006 Jive Software. All rights reserved.
* This software is the proprietary information of Jive Software. Use is subject to license terms.
*/
package org.jivesoftware.wildfire.filetransfer;
import java.io.PrintStream;
import java.io.PrintWriter;
/**
* Thrown by a FileTransferInterceptor when a file transfer is rejected my the Interceptor. The file
* transfer is aborted and the participating parties are notified.
*
* @author Alexander Wenckus
*/
public class FileTransferRejectedException extends Exception {
private static final long serialVersionUID = 1L;
private Throwable nestedThrowable = null;
/**
* Text to include in a message that will be sent to the sender of the packet that got
* rejected. If no text is specified then no message will be sent to the user.
*/
private String rejectionMessage;
public FileTransferRejectedException() {
super();
}
public FileTransferRejectedException(String msg) {
super(msg);
}
public FileTransferRejectedException(Throwable nestedThrowable) {
this.nestedThrowable = nestedThrowable;
}
public FileTransferRejectedException(String msg, Throwable nestedThrowable) {
super(msg);
this.nestedThrowable = nestedThrowable;
}
public void printStackTrace() {
super.printStackTrace();
if (nestedThrowable != null) {
nestedThrowable.printStackTrace();
}
}
public void printStackTrace(PrintStream ps) {
super.printStackTrace(ps);
if (nestedThrowable != null) {
nestedThrowable.printStackTrace(ps);
}
}
public void printStackTrace(PrintWriter pw) {
super.printStackTrace(pw);
if (nestedThrowable != null) {
nestedThrowable.printStackTrace(pw);
}
}
/**
* Retuns the text to include in a message that will be sent to the intitiator and target
* of the file transfer that got rejected or <tt>null</tt> if none was defined. If no text was
* specified then no message will be sent to the parties of the rejected file transfer.
*
* @return the text to include in a message that will be sent to the parties of the file
* transfer that got rejected or <tt>null</tt> if none was defined.
*/
public String getRejectionMessage() {
return rejectionMessage;
}
/**
* Sets the text to include in a message that will be sent to the intiator and target of the
* file transfer that got rejected or <tt>null</tt> if no message will be sent to the parties
* of the rejected file transfer. Bt default, no message will be sent.
*
* @param rejectionMessage the text to include in the notification message for the rejection.
*/
public void setRejectionMessage(String rejectionMessage) {
this.rejectionMessage = rejectionMessage;
}
}
...@@ -72,7 +72,7 @@ public class ProxyConnectionManager { ...@@ -72,7 +72,7 @@ public class ProxyConnectionManager {
*/ */
synchronized void processConnections(final InetAddress bindInterface, final int port) { synchronized void processConnections(final InetAddress bindInterface, final int port) {
if (socketProcess != null) { if (socketProcess != null) {
if(proxyPort == port) { if (proxyPort == port) {
return; return;
} }
} }
...@@ -92,7 +92,7 @@ public class ProxyConnectionManager { ...@@ -92,7 +92,7 @@ public class ProxyConnectionManager {
socket = serverSocket.accept(); socket = serverSocket.accept();
} }
catch (IOException e) { catch (IOException e) {
if(!serverSocket.isClosed()) { if (!serverSocket.isClosed()) {
Log.error("Error accepting proxy connection", e); Log.error("Error accepting proxy connection", e);
continue; continue;
} }
...@@ -174,7 +174,7 @@ public class ProxyConnectionManager { ...@@ -174,7 +174,7 @@ public class ProxyConnectionManager {
connectionMap.put(responseDigest, transfer); connectionMap.put(responseDigest, transfer);
} }
else { else {
transfer.setInitiatorSocket(connection); transfer.setInputStream(connection.getInputStream());
} }
} }
cmd = createOutgoingSocks5Message(0, responseDigest); cmd = createOutgoingSocks5Message(0, responseDigest);
...@@ -187,7 +187,8 @@ public class ProxyConnectionManager { ...@@ -187,7 +187,8 @@ public class ProxyConnectionManager {
} }
} }
private ProxyTransfer createProxyTransfer(String transferDigest, Socket initiatorSocket) { private ProxyTransfer createProxyTransfer(String transferDigest, Socket targetSocket)
throws IOException {
ProxyTransfer provider; ProxyTransfer provider;
try { try {
Class c = ClassUtils.forName(className); Class c = ClassUtils.forName(className);
...@@ -199,7 +200,7 @@ public class ProxyConnectionManager { ...@@ -199,7 +200,7 @@ public class ProxyConnectionManager {
} }
provider.setTransferDigest(transferDigest); provider.setTransferDigest(transferDigest);
provider.setTargetSocket(initiatorSocket); provider.setOutputStream(targetSocket.getOutputStream());
return provider; return provider;
} }
...@@ -280,6 +281,13 @@ public class ProxyConnectionManager { ...@@ -280,6 +281,13 @@ public class ProxyConnectionManager {
transfer.setSessionID(sid); transfer.setSessionID(sid);
transfer.setTransferFuture(executor.submit(new Runnable() { transfer.setTransferFuture(executor.submit(new Runnable() {
public void run() { public void run() {
try {
transferManager.fireFileTransferIntercept(digest);
}
catch (FileTransferRejectedException e) {
notifyFailure(transfer, e);
return;
}
try { try {
transfer.doTransfer(); transfer.doTransfer();
} }
...@@ -293,6 +301,10 @@ public class ProxyConnectionManager { ...@@ -293,6 +301,10 @@ public class ProxyConnectionManager {
})); }));
} }
private void notifyFailure(ProxyTransfer transfer, FileTransferRejectedException e) {
}
/** /**
* Creates the digest needed for a byte stream. It is the SHA1(sessionID + * Creates the digest needed for a byte stream. It is the SHA1(sessionID +
* initiator + target). * initiator + target).
......
...@@ -11,59 +11,27 @@ package org.jivesoftware.wildfire.filetransfer; ...@@ -11,59 +11,27 @@ package org.jivesoftware.wildfire.filetransfer;
import org.jivesoftware.util.Cacheable; import org.jivesoftware.util.Cacheable;
import java.net.Socket;
import java.io.IOException; import java.io.IOException;
import java.util.concurrent.Future;
/** /**
* Tracks the different connections related to a proxy file transfer. There are two connections, the * Tracks the different connections related to a proxy file transfer. There are two connections, the
* initiator and the target and when both connections are completed the transfer can begin. * initiator and the target and when both connections are completed the transfer can begin.
*/ */
public interface ProxyTransfer extends Cacheable, FileTransferProgress { public interface ProxyTransfer extends Cacheable, FileTransferProgress {
/**
* Returns the fully qualified JID of the initiator of the file transfer.
*
* @return Returns the fully qualified JID of the initiator of the file transfer.
*/
public String getInitiator();
public void setInitiatorSocket(Socket initiatorSocket);
public Socket getInitiatorSocket();
public void setTargetSocket(Socket targetSocket);
public Socket getTargetSocket();
public void setTarget(String target);
public String getTarget();
public void setTransferDigest(String digest); public void setTransferDigest(String digest);
public String getTransferDigest(); public String getTransferDigest();
public String getSessionID();
public void setSessionID(String streamID);
/** /**
* Returns true if the Bytestream is ready to be activated and the transfer can begin. * Returns true if the Bytestream is ready to be activated and the proxy transfer can begin.
* *
* @return Returns true if the Bytestream is ready to be activated. * @return Returns true if the Bytestream is ready to be activated.
*/ */
public boolean isActivatable(); public boolean isActivatable();
public long getAmountTransfered();
public int getCachedSize();
public void setTransferFuture(Future<?> future);
/** /**
* Transfers the file from the initiator to the target. * Transfers the file from the initiator to the target.
*/ */
public void doTransfer() throws IOException; public void doTransfer() throws IOException;
void setInitiator(String s);
} }
...@@ -14,7 +14,6 @@ import org.jivesoftware.util.CacheSizes; ...@@ -14,7 +14,6 @@ import org.jivesoftware.util.CacheSizes;
import org.jivesoftware.wildfire.filetransfer.ProxyTransfer; import org.jivesoftware.wildfire.filetransfer.ProxyTransfer;
import org.jivesoftware.wildfire.filetransfer.ProxyOutputStream; import org.jivesoftware.wildfire.filetransfer.ProxyOutputStream;
import java.net.Socket;
import java.util.concurrent.Future; import java.util.concurrent.Future;
import java.io.IOException; import java.io.IOException;
import java.io.InputStream; import java.io.InputStream;
...@@ -28,9 +27,9 @@ public class DefaultProxyTransfer implements ProxyTransfer { ...@@ -28,9 +27,9 @@ public class DefaultProxyTransfer implements ProxyTransfer {
private String initiator; private String initiator;
private Socket initiatorSocket; private InputStream inputStream;
private Socket targetSocket; private OutputStream outputStream;
private String target; private String target;
...@@ -51,29 +50,24 @@ public class DefaultProxyTransfer implements ProxyTransfer { ...@@ -51,29 +50,24 @@ public class DefaultProxyTransfer implements ProxyTransfer {
return initiator; return initiator;
} }
/**
* Sets the fully qualified JID of the initiator of the file transfer.
*
* @param initiator The fully qualified JID of the initiator of the file transfer.
*/
public void setInitiator(String initiator) { public void setInitiator(String initiator) {
this.initiator = initiator; this.initiator = initiator;
} }
public Socket getInitiatorSocket() { public InputStream getInputStream() {
return initiatorSocket; return inputStream;
} }
public void setInitiatorSocket(Socket initiatorSocket) { public void setInputStream(InputStream initiatorInputStream) {
this.initiatorSocket = initiatorSocket; this.inputStream = initiatorInputStream;
} }
public Socket getTargetSocket() { public OutputStream getOutputStream() {
return targetSocket; return outputStream;
} }
public void setTargetSocket(Socket targetSocket) { public void setOutputStream(OutputStream outputStream) {
this.targetSocket = targetSocket; this.outputStream = outputStream;
} }
public String getTarget() { public String getTarget() {
...@@ -102,7 +96,7 @@ public class DefaultProxyTransfer implements ProxyTransfer { ...@@ -102,7 +96,7 @@ public class DefaultProxyTransfer implements ProxyTransfer {
public boolean isActivatable() { public boolean isActivatable() {
return ((initiatorSocket != null) && (targetSocket != null)); return ((inputStream != null) && (outputStream != null));
} }
public synchronized void setTransferFuture(Future<?> future) { public synchronized void setTransferFuture(Future<?> future) {
...@@ -120,8 +114,8 @@ public class DefaultProxyTransfer implements ProxyTransfer { ...@@ -120,8 +114,8 @@ public class DefaultProxyTransfer implements ProxyTransfer {
if(!isActivatable()) { if(!isActivatable()) {
throw new IOException("Transfer missing party"); throw new IOException("Transfer missing party");
} }
InputStream in = getInitiatorSocket().getInputStream(); InputStream in = getInputStream();
OutputStream out = new ProxyOutputStream(getTargetSocket().getOutputStream()); OutputStream out = new ProxyOutputStream(getOutputStream());
final byte[] b = new byte[BUFFER_SIZE]; final byte[] b = new byte[BUFFER_SIZE];
int count = 0; int count = 0;
...@@ -137,8 +131,8 @@ public class DefaultProxyTransfer implements ProxyTransfer { ...@@ -137,8 +131,8 @@ public class DefaultProxyTransfer implements ProxyTransfer {
count = in.read(b); count = in.read(b);
} while (count >= 0); } while (count >= 0);
getInitiatorSocket().close(); getInputStream().close();
getTargetSocket().close(); getOutputStream().close();
} }
public int getCachedSize() { public int getCachedSize() {
......
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