cURL / Mailing Lists / curl-library / Single Mail

curl-library

LibCurlNet problem reusing easy handle

From: Lukasz Buczkowski <lukasz.buczkowski_at_gmail.com>
Date: Mon, 21 May 2012 09:38:37 +0200

Hi,

Thanks for great library!

I'm having some trouble reusing easy handle. What I do.

1) setup connection to use ssl
2) start first transfer it returns ok
3) next transfer returns CURLE_FTP_WRITE_ERROR

Additional info. When I read debug information I find following message:

"522 SSL connection failed; session reuse required: see require_ssl_reuse option
in vsftpd.conf man page

server did not report OK, got 522"

I double checked that my vsftpd has require_ssl_reuse set to YES

I include my code below. What I'm I missing or doing wrong?

using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.IO;

using SeasideResearch.LibCurlNet;
using System.Threading;

namespace Exnui
{
    static class Global
    {
        public static void Init()
        {
            Curl.GlobalInit((int)CURLinitFlag.CURL_GLOBAL_ALL);
        }

        public static void CleanUp()
        {
            Curl.GlobalCleanup();
        }
    }

    public enum OpStatus
    {
        Waiting,
        Cancelled,
        Success,
        Error
    }

    static class FtpsManager
    {
        private static Queue<FtpsOp> ops;
        private static Easy conn;
        private static bool cancelCurrentOpValue;
        private static bool runningValue;

        private static readonly object cancelSyncRoot = new object();
        private static readonly object stopSyncRoot = new object();
        private static readonly object runningSyncRoot = new object();

        static FtpsManager()
        {
            ops = new Queue<FtpsOp>(200); // initial size 200
            conn = new Easy();

            cancelCurrentOpValue = false;
            runningValue = false;

            // setup credential
            conn.SetOpt(CURLoption.CURLOPT_USERPWD, Config.FtpsLogin +
":" + Config.FtpsPassword);

            // short dir list, names only
            conn.SetOpt(CURLoption.CURLOPT_FTPLISTONLY, true);

            // enable ssl
            conn.SetOpt(CURLoption.CURLOPT_FTP_SSL, CURLftpSSL.CURLFTPSSL_TRY);

            // fuck server certificate
            conn.SetOpt(CURLoption.CURLOPT_SSL_VERIFYPEER, false);
            conn.SetOpt(CURLoption.CURLOPT_SSL_VERIFYHOST, 1); // 1
means - check cert existence, screw content

            // make curl more talkative
            conn.SetOpt(CURLoption.CURLOPT_VERBOSE, true);

            // enable progress callback
            conn.SetOpt(CURLoption.CURLOPT_NOPROGRESS, 0);
            Easy.ProgressFunction delegProgress = new
Easy.ProgressFunction(Progress);
            conn.SetOpt(CURLoption.CURLOPT_PROGRESSFUNCTION, delegProgress);

            // debug
            Easy.DebugFunction delegDebug = new Easy.DebugFunction(Debug);
            conn.SetOpt(CURLoption.CURLOPT_DEBUGFUNCTION, delegDebug);
            conn.SetOpt(CURLoption.CURLOPT_VERBOSE, true);

            // test
            // conn.SetOpt(CURLoption.CURLOPT_SSL_SESSIONID_CACHE,
        }

        public static void Entry()
        {
            while (Running)
            {
                try
                {
                    FtpsOp currentOp;

                    object opsSyncRoot = (ops as ICollection).SyncRoot;

                    lock (opsSyncRoot)
                    {
                        if (ops.Count == 0)
                        {
                            Monitor.Wait(opsSyncRoot);
                        }
                        currentOp = ops.First();
                    }

                    bool res = currentOp.Execute(conn);

                    if (CancelCurrent)
                    {
                        Console.WriteLine("Manager cancelled op");
                        CancelCurrent = false;
                    }

                    if (res)
                    {
                        // remove op from queue
                        lock (opsSyncRoot)
                        {
                            ops.Dequeue();
                        }
                    }
                    else
                    {
                        // for now just act like everything was allright
                        lock (opsSyncRoot)
                        {
                            ops.Dequeue();
                        }

                        // todo
                        // retry x time
                        // check internet connection
                        // - some .net connection state
                        // - ping always on servies google, etc.
                    }
                }
                catch (ThreadAbortException abort)
                {
                    // nasty error - tis shouldn't happen
                    Running = false;
                    CancelCurrent = true;

                    Log.Error("FtpsManager thread aborted");
                    Log.Exception(abort);

                    // todo
                    // dump queue to file or restore it from
"commands" database
                    // "commands" database are json structs I get from exnui
                }
                catch (ThreadInterruptedException)
                {
                    // nasty but we eat this exception
                }
                finally
                {
                    // clean up
                }
            }
        }

        public static void Start()
        {
            // Only one thread can work on Ops Queue
            if (Running == false)
            {
                Running = true;

                Thread managerThread = new Thread(new ThreadStart(Entry));
                managerThread.Start();
            }
        }

        // Cancels current op
        public static void Cancel()
        {
            CancelCurrent = true;
        }

        public static void Stop()
        {
            Running = false;
        }

        private static bool Running
        {
            get
            {
                lock (runningSyncRoot)
                {
                    return runningValue;
                }
            }

            set
            {
                lock (runningSyncRoot)
                {
                    runningValue = value;
                }
            }
        }

        public static bool CancelCurrent
        {
            get
            {
                lock (cancelSyncRoot)
                {
                    return cancelCurrentOpValue;
                }
            }

            set
            {
                lock (cancelSyncRoot)
                {
                    cancelCurrentOpValue = value;
                }
            }
        }

        public static void EnqueOp(FtpsOp op)
        {
            Object syncRoot = (ops as ICollection).SyncRoot;
            lock (syncRoot)
            {
                if (op != null)
                {
                    ops.Enqueue(op);
                }
                Monitor.Pulse(syncRoot);
            }
        }

        public static void Debug(CURLINFOTYPE infoType, String msg,
Object userData)
        {
            //Console.WriteLine(msg);
        }

        public static Int32 Progress(Object extraData, Double dlTotal,
            Double dlNow, Double ulTotal, Double ulNow)
        {
            // 0 - ok
            // 1 - abort
            Console.WriteLine("Progress");
            int res = CancelCurrent ? 1 : 0;
            return res;
        }

        public static void Close()
        {
            conn.Cleanup();
        }
    }

    abstract class FtpsOp
    {
        protected string localPath;
        protected string remotePath;
        protected OpStatus opStatus;

        public FtpsOp(string localPath, string remotePath)
        {
            this.localPath = localPath;
            this.remotePath = remotePath;
            this.opStatus = OpStatus.Waiting;
        }

        public abstract bool Execute(Easy conn);
    }

    class FtpsUploadFile : FtpsOp
    {
        static int elapsedTime = 0;
        static int totalWritten = 0;

        public FtpsUploadFile(string localPath, string remotePath)
            : base(localPath, remotePath)
        {
        }

        public override bool Execute(Easy conn)
        {
            FileStream ifs = null;

            try
            {
                // Debug
                Console.WriteLine("Uploading file: {0}", localPath);

                ifs = File.OpenRead(localPath);

                // setup url
                string url = Config.FtpsUrl + remotePath.Replace(@"\", @"/");
                conn.SetOpt(CURLoption.CURLOPT_URL, url);

                // setup upload info
                conn.SetOpt(CURLoption.CURLOPT_UPLOAD, true);
                conn.SetOpt(CURLoption.CURLOPT_INFILESIZE_LARGE, ifs.Length);

                // setup delegate for reading binary data
                Easy.ReadFunction delegReadBinary = new
Easy.ReadFunction(ReadBinary);
                conn.SetOpt(CURLoption.CURLOPT_READFUNCTION, delegReadBinary);
                conn.SetOpt(CURLoption.CURLOPT_READDATA, ifs);

                // do transfer
                CURLcode curlStatus = conn.Perform();

                bool succ = false;

                if (curlStatus == CURLcode.CURLE_OK)
                {
                    succ = true;
                    opStatus = OpStatus.Success;
                }

                // Debug
                Console.WriteLine("CurlStatus: {0} OpStatus: {1}",
curlStatus, opStatus);

                return succ;
            }
            catch (Exception e)
            {
                Log.Exception(e);
                throw;
            }
            finally
            {
                if (ifs != null)
                {
                    ifs.Close();

                    //conn.SetOpt(CURLoption.CURLOPT_UPLOAD, false);
                    //conn.SetOpt(CURLoption.CURLOPT_INFILESIZE_LARGE, 0L);
                }
            }
        }

        private Int32 ReadBinary(Byte[] buf, Int32 size, Int32 count,
Object userData)
        {
            // Debug
            //Console.WriteLine("Size: {0} Count: {1}", size, count);
            /*
            if (FtpsManager.CancelCurrent)
            {
                opStatus = OpStatus.Cancelled;

                // Debug
                Console.WriteLine("Transfer cancelled");

                // Return value CURL_READFUNC_ABORT abort transfer -
libcurl doc, don't return 0
                // Curl.net you should return 0 to abort
                return 0;
            }
            */
            FileStream fs = (FileStream)userData;
            int total = size * count;

            // Debug
            // Console.WriteLine("Just before stream.Read");
            int res = 0;
            try
            {
                res = fs.Read(buf, 0, total);
            }
            catch(Exception)
            {
                Console.WriteLine("Exception in ReadBinary");
            }

            return res;
        }
    }
}

/*
 *
 * MAIN
 *
 */

using System;
using System.Collections;
using System.Threading;

namespace Exnui
{
    class App
    {
        static void Main(string[] args)
        {
            Global.Init();

            string[] files =
            {
                @"\prayer.mp3",
                @"\tekst.txt",
                @"\tekst.txt"
            };

            FtpsManager.Start();

            foreach (var file in files)
            {
                FtpsUploadFile op = new
FtpsUploadFile(Config.CachePath + file, file);
                FtpsManager.EnqueOp(op);
            }

            int second = 1000;
            int minute = 60000;

            Thread.Sleep(200 * minute);

            FtpsManager.Stop();

            Global.CleanUp();
        }
    }
}

Any help would be welcomed!

Best regards,
Lukasz
-------------------------------------------------------------------
List admin: http://cool.haxx.se/list/listinfo/curl-library
Etiquette: http://curl.haxx.se/mail/etiquette.html
Received on 2012-05-21