[03] FlowSsh Technical Support


For technical or licensing inquiries about FlowSsh, please open a new support case.

Listing files from SFTP server

Hi,
I am using the licensed version of bitvise. I want to implement SFTP in my application. I found SftpManager3 class most useful, but it will be helpful if some clear example is given for the usage. I mean, i am unable to use List method of the SftpManager3 class. Please explain me how to use List method in my program.
saisyam Send private email
Tuesday, December 20, 2005
 
 
Hello,

first I'd like to remind you that SftpcManager2 or SftpcManager3 must both be driven in a separate thread. You must not call SftpcManager3::Upload, Download or List inside the SSH thread. That goes for most of the SftpcManager2's methods as well.
Therefore, if you're going to use SftpcManager3 (or SftpcManager2) then you'll need to have at least 2 threads: an SSH thread, and a thread driving SftpcManager3. SftpcManager3 is usually driven by the User Interface so usually one ends up with an SSH and an User Interface thread. That makes sence.

Here is how SftpcManager3::List can be used:

CODE// Create a ListInterface derivate first,
class LsInterface : public ListInterface
{
public:
    bool OnStart(BasicInfo const& basicInfo)
    {
        // The fist method being called. Called only once (per SftpcManager3::List).
        wcout << L"Listing directory: " << basicInfo.m_ucs2StartDirPath << endl;
        return true;
    }
    
    bool OnList(ListInfo const& listInfo)
    {
        // Can be called multiple times.
        vector<SftpFile2>::const_iterator it;
        for (it = listInfo.m_vFile.begin(); it != listInfo.m_vFile.end(); ++it)
            wcout << it->ucs2LongName << endl;
        return true;
    }

    bool OnFailure(FailureInfo const& failureInfo)
    {
        wcout << DescribeFailedOperation(failureInfo.m_operation) << endl;
        // Check out failureInfo for more info about the failure.
        return true;
    }

    bool OnEnd(BasicInfo const& basicInfo)
    {
        // The last method being called. Called only once even in case of failure.
        wcout << endl;
        return true;
    }
};

// Then simply call.
sftpcManager3.List(ListParam(L"/"), LsInterface());

Best regards,
Andrej
Andrej Andolsek Send private email
Wednesday, December 21, 2005
 
 
hi,
Thanks for your assistance. It works fine. But our requirement is, I have to pull files with specific extension say, .log extension. The List implementation is throwing an error, "unable to list files" when i add extension to the directory path.
    sftp3->List(ListParam(L"./pull/*.log"), LsInterface());

Does sftp lib supports this or i have to filter the file list. Please let me know.

Thanks and Regards,
Saisyam
saisyam Send private email
Monday, January 02, 2006
 
 
Hello Saisyam,

---- Quote: ----
sftp3->List(ListParam(L"./pull/*.log"), LsInterface());
----------------

No, you cannot do that. ListParam accepts directory paths only. No wildcards can be used.

What you need to do is create a different ListInterface and filter out the *.log files in ListInterface::OnList override. You can use TextPattern class (from mulib project) to do the filtering for you.

CODEbool SomeListInterface::OnList(ListInfo const& listInfo)
{
    TextPattern pattern(L"*.log");
    vector<SftpFile2>::const_iterator it;
    for (it = listInfo.m_vFile.begin(); it != listInfo.m_vFile.end(); ++it)
    {
        wstring wsFilteredFileName = pattern.ResolvePattern(it->ucs2FileName.c_str(), caseSensitive);
        if (!wsFilteredFileName.empty())
        {
            // Add to download list or issue download directly from here
        }
    }
    return true;
}

Best regards,
Andrej
Andrej Andolsek Send private email
Tuesday, January 03, 2006
 
 
hi Andrej,
Thank you once again. I will tell you how we want to use your SFTP....We are already having one application which downloads and uploads files to local or ftp locations. now we have to add the SFTP functionality to the application. The existing application is not multithreaded. But your SFTP is a threading application. I am trying to implement a class which supports the same FTP functions as our existing applications, say for example, Open, Close, ListFiles, Download, Upload etc...but I am unable to separate the code given by you in the example programs....and i donno whether i will be in trouble when integrating SFTP with our existing application......I hope you will provide some help to solve this problem..presently i am on the task of preparing a class that hides all the internal implementation....

Thanks and regards,
Saisyam
saisyam Send private email
Tuesday, January 03, 2006
 
 
Well if you need to keep your application single-threaded, then you&#39;ll have to work with SftpcManager class. You&#39;ll have to implement SftpcResponseInterface&#39;s methods (all except for the Version). You&#39;ll also have to somehow deal with packet IDs (the first parameter of SftpcManager::Open, Close, Read, etc.). Consult with the SFTP draft on that. Note that sftplib implements SFTP version <= 4.

So, to issue a file open request in SftpcManager you simply call SftpcManager::Open. SftpcManager will then, upon receiving a response, call SftpcManager::Status (on failure) or SftpcManager::Handle (on success). You could also receive other type of responses (e.g. SftpcManager::Data, Name, Attrs, Reply) which you should treat as SFTP protocol error for this particular request. Btw. SftpcManager2 validates the response type automatically by calling SftpcManager2::CheckResponseType; checking out its implementation should prove helpful.

Regards,
Andrej
Andrej Andolsek Send private email
Tuesday, January 03, 2006
 
 
Hi Andrej,
Nice to see your reply. But now i don&#39;t have time to do that, so what i did is i created a DLL from your sample code and presenlty using it in my application. It works fine but the problem when ever the control goes to SFTP it is not returning to by calling program, in other words, if i configure FTP after completing the SFTP only the SFTP session is running the FTP is not running and the program exits after performing SFTP operations. Is this because of the threading apporoach in SFTP or my mistake? If its my mistake please ignore this....

thanks and regards,
Saisyam
saisyam Send private email
Thursday, January 05, 2006
 
 
Hello Saisyam,

if your program exits after the SFTP session is done, you probably aren&#39;t catching the exception with which the SSH thread exits. Let&#39;s assume your DLL interface function is something like DoSftpTransfers(). Let&#39;s say that this function establishes an SSH session, does SFTP file transfers and is intended to return when all transfers are done. When your SFTP code decides it&#39;s time to terminate the session, it should throw a UserExit exception. Your DoSftpTransfer() function should catch this exception, along with other possible exception types that an SSH session can exit with, and then return control to the caller. If you don&#39;t catch an exception, it will propagate to the caller and, if not caught by the caller either, will cause the program to terminate.

denis
denis bider Send private email
Thursday, January 05, 2006
 
 
hi,
As per your suggestion I catched the UserExit in my program. I will explain u clearly. I am having SFTPList method for which i will send the details such as host name, password etc and i am having a simgle function ExecuteSFTP which will establish a connection and start the SFTP session and do the needy for me and return to SFTPList. These are all done inside a DLL. Now i used mu DLL in my application, when the SFTPList method runs it exits the application without returning to my calling program. I am pasting the code for SFTPList and ExecuteSFTP please look at the major portions so that you can get the idea.

bool wtdaNewFTP::SFTPList(LPSTR hostName, int portNumber, LPSTR userName, LPSTR passWord, LPSTR keyFileName, int slot, LPSTR passphrase, LPSTR directory, LPSTR filename, LPSTR filter)
{
    this->userName = userName;
    this->passWord = passWord;
    this->keyFileName = keyFileName;
    this->hostName = hostName;
    this->portNumber = portNumber;
    this->slot = slot;
    this->passPhrase = passphrase;
    this->sourcePath = directory;
    this->filter = filter;
    this->rename = false;
    this->listFiles = true;
    this->oneFile = false;

    ExecuteSFTP(false);
    
    FILE *fp = fopen(filename, "w");
    if (fp == NULL)
    {
        cout<<"Error opening file"<<endl;
        return false;
    }
    list<string> mylist;
    GetFiles(mylist);
    list<string>::iterator iter;
    string str;
    for (iter=mylist.begin(); iter&#33;=mylist.end();++iter)
    {
      str = *iter;
      fprintf(fp,"%s&#092;n",str.c_str());
    }

    fclose(fp);    
    return true;
    
}


bool wtdaNewFTP::ExecuteSFTP(bool pullFlag)//cmdParam param)
{
    cmdParam param;
    param.hostname = this->hostName.c_str();
    param.port = this->portNumber;
    param.username = this->userName.c_str();
    param.password = this->passWord.c_str();
    param.publickeyfilename = this->keyFileName.c_str();
    param.path = this->sourcePath.c_str();
    param.destfile = this->destinationPath.c_str();
    param.filter = this->filter.c_str();
    param.slotNumber=(word32)this->slot;
    param.passPhrase=this->passPhrase.c_str();
    param.listFiles = this->listFiles;
    param.oneFile = this->oneFile;
    
    if (pullFlag)
    {
        param.download = true;
        param.upload = false;
    }
    else
    {
        if(this->rename)
        {
          param.download = false;
          param.upload = false;
        }
        else
        {
          param.download = false;
          param.upload = true;
        }
    }

/****from here the connection establishment starts***/
    try
    {        
        SocketsInitializer socketsInitializer;
        ConnectingSocket connectingSocket;
        connectingSocket.SetTarget(AddressInfo().Make(hostName, 22));
        if (&#33;connectingSocket.StartConnect())
        {
            do
            {
                if (_kbhit())
                    switch (getch())
                    {
                    case 27: case &#39;Q&#39;: case &#39;q&#39;:
                        LogOut("User selects exit, aborting connect attempt");
                        return false;
                    }

                connectingSocket.Wait(1000, CallStack("NewSftpClient main() connecting", 0));
            }
            while (&#33;connectingSocket.ContinueConnect());
        }

        if (connectingSocket.ConnectFailed())
        {
            ostringstream oss;
            oss << "Connect attempt failed:" << endl
                << "Operation: " << connectingSocket.GetOperation() << endl
                << "Error code: " << connectingSocket.GetErrorCode() << endl
                << "Description: " << connectingSocket.GetErrorDescription() << endl;
            LogOut(oss.str());
            return false;
        }
        LogOut("Connected");
        // Initialize TransportState and key exchange handlers
        AutoSeededRandomPool rng;
        SftpClientTracer tracer(SSHDIAGCLIENT_TRACELEVEL);
        TransportState transportState(rng, &tracer);
        transportState.SetCompressionAlgorithms("none");
        ClientDhKexHandler clientDhKexHandler;
        transportState.AddKexHandler(clientDhKexHandler);
        
        // Initialize the Authenticator
        SftpClientAuthenticator authenticator;
        authenticator.m_username = param.username;
        unsigned int nPwdLen = strlen(param.password);
        authenticator.m_password.resize(nPwdLen);
        copy(param.password, param.password+nPwdLen, authenticator.m_password.begin());
        

        authenticator.m_passPhrase=ToUcs2(dbcsstring(param.passPhrase));
        authenticator.m_slot=(word32)param.slotNumber;


        // Initialize the Manager
        SftpClientManager manager(transportState, authenticator);
        manager.param = param;

        clientDhKexHandler.SetHostKeyHandler(manager);
        try
        {
            manager.DoLoop(connectingSocket, Version(&quot;SftpClient&quot;));
        
        }
        catch (RemoteDisconnect const&amp;)
        {
            if (manager.GetDisconnectExchangeState() &#33;= DISCONNECT_RECEIVED)
                LogOut(&quot;Remote disconnected without sending a disconnect message&quot;);
            else
            {
                ostringstream oss;
                oss &lt;&lt; &quot;Disconnect packet received:&quot; &lt;&lt; endl
                    &lt;&lt; &quot;Disconnect reason: &quot; &lt;&lt; DescribeDisconnectReason(manager.GetDisconnectReason()) &lt;&lt; endl
                    &lt;&lt; &quot;Disconnect description: &quot; &lt;&lt; manager.GetDisconnectDescription() &lt;&lt; endl
                    &lt;&lt; &quot;Disconnect language: &quot; &lt;&lt; manager.GetDisconnectLanguage() &lt;&lt; endl;
                LogOut(oss.str());
            }
        }
        
        catch (UserExit const&amp;)
        {
            // This message is displayed in my application and the application exits without returning    
                    cout &lt;&lt; &quot;Session terminated on user&#39;s request.&#092;n&quot;;

        }
        
        catch (CauseToDisconnect const&amp; c)
        {
            ostringstream oss;
            oss &lt;&lt; &quot;Disconnect packet sent:&quot; &lt;&lt; endl
                &lt;&lt; &quot;Disconnect reason: &quot; &lt;&lt; DescribeDisconnectReason(c.GetReason()) &lt;&lt; endl
                &lt;&lt; &quot;Disconnect description: &quot; &lt;&lt; c.GetDescription() &lt;&lt; endl
                &lt;&lt; &quot;Disconnect language: &quot; &lt;&lt; c.GetLanguage() &lt;&lt; endl;
            LogOut(oss.str());
        }
        
    
        
        catch (Socket::Err const&amp; e)
        {
            LogOut(&quot;Session terminated by socket error: &quot; + string(e.what()));
        }
        
        catch (exception const&amp; e)
        {
            LogOut(&quot;Session terminated by exception: &quot; + string(e.what()));
        }
        
        catch (...)
        {
            LogOut(&quot;Session terminated by unrecognized exception&quot;);
        }
    }
    catch (exception const&amp; e)
    {
        LogOut(&quot;Terminated by exception: &quot; + string(e.what()));
    }
    catch (...)
    {
        LogOut(&quot;Terminated by unrecognized exception&quot;);
    }

    return true;
}
saisyam Send private email
Friday, February 24, 2006
 
 
Have you tried running this code in a debugger? A debugger should be able to flag the cause of the exit. Also, you can set a breakpoint at the cout line, switch to disassembly view, and then step through the assembler code to pinpoint the exact location where the program exit is occurring.

It might be that the cause is in some of the destructors that get called after the &#39;cout&#39; line is executed, or it might be something obscure like the &#39;cout&#39; line itself (if perhaps there is conflict between the C run-times).
denis bider Send private email
Friday, February 24, 2006
 
 

This topic is archived. No further replies will be accepted.

Other recent topics Other recent topics
 
Powered by FogBugz