Our Products:   CompleteFTP  edtFTPnet/Free  edtFTPnet/PRO  edtFTPj/Free  edtFTPj/PRO
0 votes
3.5k views
in .NET FTP by (280 points)
I found some posts from 2006 discussing fxp being implemented in the .net version of edtftp.
Nothing seems to have eventuated. I did notice that it had been implemented in the java version.
I have tried to cobble together my own fxp function but I am obviously missing something as it isn't working correctly. :(
I added it into the .net 1.2.6 version of edtftpnet in the FTPClient module.

CODE:
public void FxpFile(FTPClient dest, string filename)
{
FTPReply reply = control.SendCommand("SSCN ON");
control.ValidateReply(reply, "200");
FTPReply replyObj = control.SendCommand("PASV");
control.ValidateReply(replyObj, "227");

// The reply to PASV is in the form:
// 227 Entering Passive Mode (h1,h2,h3,h4,p1,p2).
// where h1..h4 are the IP address to connect and
// p1,p2 the port number
// Example:
// 227 Entering Passive Mode (128,3,122,1,15,87).
// NOTE: Some FTP servers miss the brackets out completely
Regex regEx = new Regex(@"(?<a0>\d{1,3}),(?<a1>\d{1,3}),(?<a2>\d{1,3}),(?<a3>\d{1,3}),(?<p0>\d{1,3}),(?<p1>\d{1,3})");
Match m1 = regEx.Match(replyObj.ReplyText);

FTPReply dreply = dest.control.SendCommand("PORT " + m1);
dest.control.ValidateReply(dreply, "200");

dreply = dest.control.SendCommand("STOR " + filename);
dest.control.ValidateReply(dreply, "150");

reply = control.SendCommand("RETR " + filename);
control.ValidateReply(reply, "150");

}

What am I missing?

Thanks in Advance :)

6 Answers

0 votes
by (280 points)
I have just done a test ... seems the transfer starts ... but as I am not waiting for a return of completion the program exits closing the control channel and dropping the data connection.
0 votes
by (280 points)
Looking at the file upload and download an eventhandler is used ... guess I will have to set up one for each ftpclient one on the up and the other on the down.

Any better suggestions?
0 votes
by (162k points)
I can tell you that it proved to be pretty tricky to implement in the Java version. You've got to get the sequence exactly right.

We plan to implement this in edtFTPnet/Express soonish. If you are interested, let us know by emailing support@enterprisedt.com. We're always keener to implement a feature if someone wants it right now.
0 votes
by (280 points)
Ok ... got it to sort of work with ...

reply = control.SendCommand("RETR " + filename);
control.ValidateReply(reply, "150");
int oldTimeout = control.Timeout;
int destoldTimeout = dest.control.Timeout;
control.Timeout = 6000000;
dest.control.Timeout = 6000000;
reply = control.ReadReply();
control.ValidateReply(reply, "226");
reply = dest.control.ReadReply();
control.ValidateReply(reply, "226");
control.Timeout = oldTimeout;
dest.control.Timeout = destoldTimeout;

The timeout value needs to be large enough to allow the file to transfer ... when it is finished first the sending server will return 226 then the recieving server.

but now I have troubles fxping from behind firewalls ... but that seems to be a pasv problem with the library.
0 votes
by (162k points)
Firewalls mess with port numbers so they can be a big problem with FXP.
0 votes
by (280 points)
Ok this seems to be doing the trick
public void FxpFile(FTPClient dest, string filename)
{
  FTPReply reply = control.SendCommand("SSCN ON");
  control.ValidateReply(reply, "200");
  FTPReply replyObj = control.SendCommand("PASV");
  control.ValidateReply(replyObj, "227");

  // The reply to PASV is in the form:
  // 227 Entering Passive Mode (h1,h2,h3,h4,p1,p2).
  // where h1..h4 are the IP address to connect and
  // p1,p2 the port number
  // Example:
  // 227 Entering Passive Mode (128,3,122,1,15,87).
  // NOTE: Some FTP servers miss the brackets out completely
  Regex regEx = new Regex(@"(?<a0>\d{1,3}),(?<a1>\d{1,3}),(?<a2>\d{1,3}),(?<a3>\d{1,3}),(?<p0>\d{1,3}),(?<p1>\d{1,3})");
  Match m1 = regEx.Match(replyObj.ReplyText);

  // assemble the IP address
  // we try connecting, so we don't bother checking digits etc
  string ipAddress = m1.Groups["a0"].Value + "." + m1.Groups["a1"].Value + "." + m1.Groups["a2"].Value + "." + m1.Groups["a3"].Value;
  log.Debug("Server supplied address=" + ipAddress);

  // assemble the port number
  int[] portParts = new int[2];
  portParts[0] = Int32.Parse(m1.Groups["p0"].Value);
  portParts[1] = Int32.Parse(m1.Groups["p1"].Value);
  int port = (portParts[0] << 8) + portParts[1];
  log.Debug("Server supplied port=" + port);

  string hostIP = ipAddress;
  string IPPstr = null;
  if (autoPassiveIPSubstitution)
  {
    char[] period = { '.' };
    string[] ipParts = remoteAddr.ToString().Split(period);
    hostIP = String.Join("," , ipParts);
    if (log.IsEnabledFor(Level.DEBUG))
        log.Debug(string.Format("Substituting server supplied IP ({0}) with remote host IP ({1})",
            ipAddress, remoteAddr));
    IPPstr = hostIP + "," + portParts[0] + "," + portParts[1];
  }
  else
    IPPstr = m1.ToString();

  FTPReply dreply = dest.control.SendCommand("PORT " + IPPstr);
  dest.control.ValidateReply(dreply, "200");

  dreply = dest.control.SendCommand("STOR " + filename);
  dest.control.ValidateReply(dreply, "150");

  reply = control.SendCommand("RETR " + filename);
  control.ValidateReply(reply, "150");
  int oldTimeout = control.Timeout;
  int destoldTimeout = dest.control.Timeout;
  control.Timeout = 6000000;
  dest.control.Timeout = 6000000;
  reply = control.ReadReply();
  control.ValidateReply(reply, "226");
  reply = dest.control.ReadReply();
  control.ValidateReply(reply, "226");
  control.Timeout = oldTimeout;
  dest.control.Timeout = destoldTimeout;
}


Make sure that autoipsubstitution is true for ftp servers behind firewalls

I would have thought that checking the control ip against the ip returned from the PASV command and then just doing a substitution if they are not the same. But I guess that there are reasons not to that I can'tthink of :)

Categories

...