Home Forums .NET libraries Xceed SFTP/FTP for .NET FTP connection hangs but does not timeout

Viewing 4 posts - 1 through 4 (of 4 total)
  • Author
    Posts
  • User (Old forums)
    Member
    Post count: 23064
    #21228 |

    I’m having an odd issue using FTP for .NET 3.3.7467.13330 on a production server running Windows Server 2003 R2.

    Sometimes (apparently randomly) the FTP connection seems to just freeze. I can see from the trace writer that a command is sent to the server, but no response is being written, and the method neither returns nor throws an exception (I’d expect a timeout to occur). The connection is over SSL and I’ve tried setting keep-alive or removing it – this makes no difference. The job is run every two minutes and there would normally only be one or two files to retrieve. The “hang” can occur on calling AbstractFolder.GetFiles, AbstractFile.Exists, AbstractFile.CopyTo or AbstractFile.Delete.

    This job is running inside an ASP.NET application, but on a background thread with some locking logic in place to ensure that only one instance can be running at any one time. Because there is no exception thrown when this problem arises the process never ends, so my only solution is to recycle the server’s app pools, which is very annoying!

    Can anyone help on why this might be happening and how to fix it? If an exception would fire on timeout it would solve all this at a stroke!

    Edited version of my code is below. I have a general Transfer method that’s designed to accept either an FTP or local directory as source or destination. I’ve stripped out all the logging calls and other unnecessary stuff to give an idea of what I’m doing. I’ve not included the Location class – it just defines either an FTP location or a local disk location.


     public IList<string> Transfer(
        string sourceFolder,
        string sourceFilePattern,
        string destinationFolder,
        bool deleteOriginal,
        bool overwriteExisting,
        int maxTransfers,
        bool throwExceptions)
    {
        //… null checks etc …
       
        IList<string> result = new List<string>();
        Location source = new Location(sourceFolder);
        Location destination = new Location(destinationFolder);

        // Check for source and destination both being FTP – we don’t want this!
        if (source.Type == LocationType.Ftp && destination.Type == LocationType.Ftp)
        {
            throw new InvalidOperationException(“Source and destination cannot both be FTP”);
        }

        // Check for an FTP requirement
        FtpConnection connection = null;
        if (source.Type == LocationType.Ftp)
        {
            connection = this.GetConnection(source);
        }
        else if (destination.Type == LocationType.Ftp)
        {
            connection = this.GetConnection(destination);
        }

        // Wrap the connection in a wrapper to correctly dispose of logging
        ConnectionWrapper connectionWrapper = new ConnectionWrapper(connection);

        using (connectionWrapper)
        {
            // FTP connection handling
            if (connectionWrapper.Connection != null)
            {
                // Delegate the CertificateReceived event
                connectionWrapper.Connection.CertificateReceived += this.OnCertificateReceived;

                // Ping the connection
                connectionWrapper.Connection.TestConnection();
            }

            // Get the source abstract folder and check it exists
            AbstractFolder sourceAbstract = this.GetAbstractFolder(source, ref connectionWrapper);
            if (!sourceAbstract.Exists)
            {
                throw new ApplicationException(“Folder ” + sourceAbstract.HostedFullName + ” does not appear to exist”);
            }

            // Get the destination abstract folder and check it exists
            AbstractFolder destinationAbstract = this.GetAbstractFolder(destination, ref connectionWrapper);
            if (!sourceAbstract.Exists)
            {
                throw new ApplicationException(“Folder ” + destinationAbstract.HostedFullName + ” does not appear to exist”);
            }

            // Get the list of files to transfer
            AbstractFile[] sourceFiles = sourceAbstract.GetFiles(false, sourceFilePattern);

            // Count transfers
            int count = 0;

            // Perform the transfer
            foreach (AbstractFile sourceFile in sourceFiles)
            {
                try
                {
                    // Need to check that the source file exists
                    if (sourceFile.Exists)
                    {
                        AbstractFile transferred =
                                (AbstractFile)sourceFile.CopyTo(destinationAbstract, overwriteExisting);

                        // Verify the modified date if destination is local
                        if (destination.Type == LocationType.Local
                            && transferred.LastWriteDateTime != sourceFile.LastWriteDateTime)
                        {
                            throw new ApplicationException(
                                    “Donwloaded file ” + transferred.FullName + ” has modified date “
                                    + transferred.LastWriteDateTime + ” which does not match”
                                    + sourceFile.HostedFullName + ” which has a modified date of “
                                    + sourceFile.LastWriteDateTime);
                        }

                        // Verify the size
                        if (transferred.Size != sourceFile.Size)
                        {
                            throw new ApplicationException(
                                    “Downloaded file ” + transferred.FullName + ” has size ” + transferred.Size
                                    + ” which does not match” + sourceFile.HostedFullName + ” which has a size of “
                                    + sourceFile.Size);
                        }

                        if (deleteOriginal)
                        {
                            sourceFile.Delete();
                        }

                        result.Add(transferred.HostedFullName);
                    }
                }
                catch (Exception ex)
                {
                    if (throwExceptions)
                    {
                        throw ex;
                    }
                }

                count++;

                if (maxTransfers > 0 && count >= maxTransfers)
                {
                    break;
                }
            }
        }

        return result;
    }

    /// <summary>
    /// Returns an Xceed base AbstractFolder object that is either a DiskFolder for
    /// a local location, or FtpFolder for FTP locations
    /// </summary>
    /// <param name=”location”>The Location to retrieve an AbstractFolder</param>
    /// <param name=”connectionWrapper”>The current FTP connection (or null) wrapped</param>
    /// <returns>An AbstractFolder</returns>
    private AbstractFolder GetAbstractFolder(Location location, ref ConnectionWrapper connectionWrapper)
    {
        if (location.Type == LocationType.Local)
        {
            return new DiskFolder(location.Folder);
        }

        if (location.Folder.Equals(“/”))
        {
            return new FtpFolder(connectionWrapper.Connection);
        }

        return new FtpFolder(connectionWrapper.Connection, location.Folder.Substring(1));
    }

    /// <summary>
    /// A method to create a connection using the values
    /// in this service’s fields
    /// </summary>
    /// <param name=”location”>
    /// The location.
    /// </param>
    /// <returns>
    /// An FtpConnection to use when communicating with the remote server
    /// </returns>
    private FtpConnection GetConnection(Location location)
    {
        if (string.IsNullOrEmpty(location.Server) || location.Port == 0)
        {
            throw new InvalidOperationException(“You cannot create an FTP connection without a server and port.”);
        }

        FtpConnection result;
        if (location.Secure)
        {
            result = new FtpConnection(
                    location.Server,
                    location.Port,
                    location.Username,
                    location.Password,
                    AuthenticationMethod.Tls,
                    VerificationFlags.None,
                    null,
                    DataChannelProtection.Private,
                    false);
        }
        else
        {
            return new FtpConnection(location.Server, location.Port, location.Username, location.Password);
        }

        // Set up FTP logging
        result.TraceWriter = new StreamWriter(**********, true);
        return result;
    }

    /// <summary>
    /// A delegate for the OnCertificateReceived event that always accepts
    /// </summary>
    /// <param name=”sender”>
    /// The sender.
    /// </param>
    /// <param name=”e”>
    /// The CertificateReceivedEventArgs.
    /// </param>
    private void OnCertificateReceived(object sender, CertificateReceivedEventArgs e)
    {
        e.Action = VerificationAction.Accept;
    }

    /// <summary>
    /// A little class to wrap a connection so that we can dispose of the tracewriter
    /// </summary>
    private class ConnectionWrapper : IDisposable
    {
        public ConnectionWrapper(FtpConnection connection)
        {
            this.Connection = connection;
        }

        public FtpConnection Connection
        {
            get;
            set;
        }

        public void Dispose()
        {
            if (this.Connection != null)
            {
                if (this.Connection.TraceWriter != null)
                {
                    this.Connection.TraceWriter.Close();
                    this.Connection.TraceWriter.Dispose();
                }

                this.Connection.Dispose();
            }
        }
    }

    Applies to Xceed FTP for .NET. Imported from legacy forums. Posted by Richard (had 3417 views)

    User (Old forums)
    Member
    Post count: 23064

    Hi,

    I’m not sure what could be causing this.  You mentioned that you are using Ftp for .NET version 3.3.7467.13330.  Although your current license key wouldn’t work with the latest version (at the moment of writing this article) since we are now at version 4.0.9257.9160 (a registered key will usually work with every subversions, i.e. a FTP for .NET 3.3.7467.13330 license key will unlock everything up to 3.3.9999.9999 – sometimes some even earlier versions of 3.4 if they are released only a few months after the 3.3.6467.13330 license key was made), it could be worth trying to run the same application with a more recent version of our library.  I am absolutely not positive that this would solve your current problem.

    I suggest that you installed the latest general package (.NET) on another workstation (or, perhaps, the same machine but in a sandbox, i.e. on VMWare virtual machine, to make sure you don’t alter your current settings) since launching a new Xceed installer would overwrite your existing settings and libraries and you wouldn’t like this, I assume.

    If you can confirm us that the problem persists even with the latest version of our FTP for .NET component, it would be easier for us to investigate the issue, although it could still be pretty complicated (since we can hardly reproduce the ftp server settings, the network topology, the firewall rules, router rules, the web server rules).

    Applies to Xceed FTP for .NET. Imported from legacy forums. Posted by Ghislain (had 380 views)

    User (Old forums)
    Member
    Post count: 23064

    I just received an update from a developer.  There is a known bug that is causing the random “hangs” when multithreading Xceed FTP for .Net prior to version 4.0 since the SSL library we were using was also multithreaded. 

    Version 4.0 of Xceed FTP for .NET is now using the .NET framework 2.0 SslStream class which is not multithreaded and this has solved the issue you are having.

    Applies to Xceed FTP for .NET. Imported from legacy forums. Posted by Ghislain (had 2124 views)

    User (Old forums)
    Member
    Post count: 23064
    Hi Andre,
     
    I am also facing same kind of issue with multithreading and i am using the latest version.
     
    Please advise me to avoid these kind of issues in the future.
     
    Regards,
    Saravanan 

    Applies to Xceed FTP for .NET. Imported from legacy forums. Posted by Saravanan (had 1483 views)

Viewing 4 posts - 1 through 4 (of 4 total)
  • You must be logged in to reply to this topic.