/*
Copyright 2009 David Revell
This file is part of SwiFTP.
SwiFTP is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
SwiFTP is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with SwiFTP. If not, see <http://www.gnu.org/licenses/>.
*/
package org.swiftp;
import java.net.InetAddress;
import java.net.Socket;
import android.util.Log;
/**
* @author david
*
*/
public class ProxyDataSocketFactory extends DataSocketFactory {
/**
* Implements data socket connections that go through our proxy server
* out on the net. The proxy sits between the FTP client and us, the server.
* We have to build in some coordination between the server and proxy in order
* for data sockets to be handled properly.
*
* When we receive a "PASV" command from a client, we have to request that the
* proxy server open a port, accept a connection, and proxy all data on that
* socket between ourself and the FTP client.
*
* When we receive a PORT command, we store the client's connection info,
* and when it's time to being transferring data, we request that the proxy
* make a connection to the client's IP & port and then proxy all data between
* ourself and the FTP client.
*/
private Socket socket;
private int proxyListenPort;
ProxyConnector proxyConnector;
InetAddress clientAddress;
int clientPort;
public ProxyDataSocketFactory() {
clearState();
}
private void clearState() {
if(socket != null) {
try {
socket.close();
} catch (Exception e) {}
}
socket = null;
proxyConnector = null;
clientAddress = null;
proxyListenPort = 0;
clientPort = 0;
}
public InetAddress getPasvIp() {
ProxyConnector pc = Globals.getProxyConnector();
if(pc == null) {
return null;
}
return pc.getProxyIp();
}
// public int getPortNumber() {
// if(socket == )
// return 0;
// }
public int onPasv() {
clearState();
proxyConnector = Globals.getProxyConnector();
if(proxyConnector == null) {
myLog.l(Log.INFO, "Unexpected null proxyConnector in onPasv");
clearState();
return 0;
}
ProxyDataSocketInfo info = proxyConnector.pasvListen();
if(info == null) {
myLog.l(Log.INFO, "Null ProxyDataSocketInfo");
clearState();
return 0;
}
socket = info.getSocket();
proxyListenPort = info.getRemotePublicPort();
return proxyListenPort;
}
public boolean onPort(InetAddress dest, int port) {
clearState();
proxyConnector = Globals.getProxyConnector();
this.clientAddress = dest;
this.clientPort = port;
myLog.d("ProxyDataSocketFactory client port settings stored");
return true;
}
/**
* When the it's time for the SessionThread to actually begin PASV
* data transfer with the client, it will call this function to get
* a valid socket. The socket will have been created earlier with
* a call to onPasv(). The result of calling onTransfer() will be
* to cause the proxy to accept the incoming connection from the FTP
* client and start proxying back to us (the FTP server). The socket
* can then be handed back to the SessionThread which can use it as
* if it were directly connected to the client.
*/
public Socket onTransfer() {
if(proxyConnector == null) {
myLog.w("Unexpected null proxyConnector in onTransfer");
return null;
}
if(socket == null) {
// We are in PORT mode (not PASV mode)
if(proxyConnector == null) {
myLog.l(Log.INFO, "Unexpected null proxyConnector in onTransfer");
return null;
}
// May return null, that's fine. ProxyConnector will log errors.
socket = proxyConnector.dataPortConnect(clientAddress, clientPort);
return socket;
} else {
// We are in PASV mode (not PORT mode)
if(proxyConnector.pasvAccept(socket)) {
return socket;
} else {
myLog.w("proxyConnector pasvAccept failed");
return null;
}
}
}
public void reportTraffic(long bytes) {
ProxyConnector pc = Globals.getProxyConnector();
if(pc == null) {
myLog.d("Can't report traffic, null ProxyConnector");
} else {
pc.incrementProxyUsage(bytes);
}
}
}