Tuesday, July 26, 2011

FTPS also known as FTP over SSL example with C++ and libCURL


In this post I showed how to use C# and libcurl.NET to connect to FTPS. Now I will use C++ so you could compare both implementations.

Read the following Wikipedia article for background about FTPS.

And here follows the code...
#include <string>
#include <iostream>
#include "CURLWrapper.h"

using std::cout;
using std::endl;
using std::string;

static string buffer;

static int writer(char *data, size_t size, size_t nmemb, string *buffer)
{
    int result = 0;
    if (buffer != NULL)
    {
        buffer->append(data, size * nmemb);
        result = size * nmemb;
    }

    return result;
}

int main()
{
    string url = "ftp://user:thepassword@ftp.somesite.com/dir/";

    cout << "Will retrive from url: '" << url << "'" << endl;

    CURLcode code = CURLWrapper::GlobalInit(CURL_GLOBAL_ALL);
    if (code != CURLE_OK)
    {
        cout << "CURL init failed" << endl;
        return 0;
    }

    CURLWrapper::Easy easy;
    easy.SetOption(CURLOPT_URL, url.c_str());
    easy.SetOption(CURLOPT_SSL_VERIFYPEER, 0);
    easy.SetOption(CURLOPT_SSL_VERIFYHOST, 0);
    easy.SetOption(CURLOPT_FTP_SSL, CURLFTPSSL_TRY);

    easy.SetOption(CURLOPT_FTPLISTONLY, 1);

    easy.SetOption(CURLOPT_WRITEFUNCTION, writer);
    easy.SetOption(CURLOPT_WRITEDATA, &buffer);
    easy.Perform();

    if (easy.IsOK())
    {
        cout << "CURL: response is OK " << endl;
 
        if (!buffer.empty())
        {
            cout << buffer << endl;
        }
        else
        {
            cout << "CURL: respose is empty! " << endl;
        }
    }
    else
    {
        cout << "CURL Error: [ " << easy.GetError() <<  ] - " 
            << easy.GetErrorMessage() << endl;
    }

    CURLWrapper::GlobalCleanup();
}

And here is code for CURLWrapper class (I have added GlobalInit and GlobalCleanup procedures from the previous libCURL post here)...

"CURLWrapper.h"
#ifndef CURL_WRAPPER_H
#define CURL_WRAPPER_H

#include <string>
#include "curl/curl.h"

namespace CURLWrapper 
{
    CURLcode GlobalInit(int flags);
    void GlobalCleanup();
    
    class Easy
    {
    public:
        Easy();
        ~Easy();

        void Init();
        void Cleanup();
        void Reset();

        template <typename T, typename V>
        void SetOption(T option, V parameter)
        {
            curl_easy_setopt(mCurl, option, parameter);
        }

        void Perform();
        bool IsOK();
        CURLcode GetError();
        std::string GetErrorMessage();
    
    private:
        void ErrorBuffer(char* buffer); 
    
    private:
        CURL* mCurl;
        char mErrorBuffer[CURL_ERROR_SIZE + 1];
        CURLcode mCode;
    };
}
#endif //#ifndef CURL_WRAPPER_H

"CURLWrapper.cpp"
#include <memory>
#include <algorithm>
#include "CURLWrapper.h"
#include "curl/curl.h"

CURLcode CURLWrapper::GlobalInit(int flags)
{
    return curl_global_init(flags);
}

void CURLWrapper::GlobalCleanup()
{
    curl_global_cleanup();
}

CURLWrapper::Easy::Easy()
    : mCurl(curl_easy_init()),
    mCode(CURLE_OK)
{
}

CURLWrapper::Easy::~Easy()
{
    curl_easy_cleanup(mCurl);
}

void CURLWrapper::Easy::Init()
{
}

void CURLWrapper::Easy::Cleanup()
{
    curl_easy_cleanup(mCurl);
}

void CURLWrapper::Easy::Reset()
{
    curl_easy_reset(mCurl);
    std::fill(mErrorBuffer, mErrorBuffer + CURL_ERROR_SIZE + 1, 0);
    ErrorBuffer(mErrorBuffer);
    mCode = CURLE_OK;
}

void CURLWrapper::Easy::ErrorBuffer(char* buffer)
{
    SetOption(CURLOPT_ERRORBUFFER, (void*)buffer);
}

void CURLWrapper::Easy::Perform()
{
    mCode = curl_easy_perform(mCurl);
}

bool CURLWrapper::Easy::IsOK()
{
    return mCode == CURLE_OK;
}

CURLcode CURLWrapper::Easy::GetError()
{
    return mCode;
}

std::string CURLWrapper::Easy::GetErrorMessage()
{
    return std::string(mErrorBuffer);
}

And as always the magic command:
g++ -g -Wall -o prog prog.cpp CURLWrapper.cpp -lcurl


So this is it, I hope that this post will help you to discover this wonderful libCURL library ;)