EldoS | Feel safer!

Software components for data protection, secure storage and transfer

ElSftpClient Put/Get file sample code or outline

Also by EldoS: CallbackDisk
Create virtual disks backed by memory or custom location, expose disk images as disks and more.
#13232
Posted: 05/06/2010 14:15:45
by Ken Ivanov (EldoS Corp.)

Low-level components work in asynchronous way. I.e., TElSSHClient.Open() just starts the negotiation procedure and returns immediately [even though the connection is not established yet]. Instead, the component reports that the connection has been negotiated with OnOpenConnection event.

Dealing with asynchronous components is not a trivial task, so I recommend you to take a look at the C# SophisticatedSSHClient sample. It illustrates the logical connections between the components and suggests the way in which they should be used.
#13234
Posted: 05/07/2010 00:47:21
by Ken Ivanov (EldoS Corp.)

Please accept my apologies if my reply has sounded insulting. I really wish all the things to be worked out in the most productive and easy way, and my response aimed to help, not to insult or humiliate you nor to get rid of you. I am really glad to hear that you are one of those "genuine" software developers who used to do a really hard work, having no Intellisenses, online helps and Googles doing most of the things for them.

The reason why I have referred you to the sample application is that the demo outlines basic milestones of SSH/SFTP negotiation stage along with the corresponding actions to be performed with SBB components. I considered that it would be easier for you (as a software developer) to work with the compilable and working code. I am sorry if it has offended you.

All the calls to TElSFTPClient's methods should be only performed after its OnOpenConnection event has fired. That is the reason why you get the "SFTP component not connected error".

Quote
Although I'm doing the .Open on the SSHClient, I'm not getting either the OnOpenConnection or the OnError events to trigger.

Could you please show the code of your OnSend and OnReceive event handlers (seeing the entire code responsible for communication between socket and TElSSHClient layers would be even better)?

You will also have to handle the OnKeyValidate event to perform server key validation. The component will throw an exception if OnKeyValidate is not handled appropriately.
#13250
Posted: 05/10/2010 11:30:04
by Ken Ivanov (EldoS Corp.)

Greg, I have reopened the topic. If you would not mind, let's continue the conversation here.

I would also like to paste the technical aspects you have described in your private letter here, as they might be useful for other users in future. May I do it?
#13254
Posted: 05/11/2010 01:33:43
by Greg  (Standard support level)
Joined: 12/09/2009
Posts: 20

Innokentiy,

Thank you for all of your help, I really appreciate it. I also wish to apologize for getting bent out of shape over a misunderstanding on my part.

Moving onward:
I was not even getting the OnSend and OnReceive to trigger, much less the OnValidate. I traced it down to a missing Socket.BeginReceive. The code in the VB Sophisticated client just did not have it.

I found, by tracing the C# version (I'm not too good in C#) that this seemed to be the key. When I stopped the C# version short of the BeginReceive, I got the same problems as I was seeing in my code.

So, I put it in and pointed it to an event handler (OnSocketReceiveCallback) and modeled it after what I was seeing in C#. The VB one is probably incomplete.

Adding this to my code started things perking along finally.

The VB OnReceive is not correct either (It's using a synchronous method), so I modeled a replacement based upon what I found in C# and that started working. OnSend was just fine.

After I got those elements in place, then I did get the OnKeyValidate to trigger (I'm using the cheat at the moment while testing - just setting it to true as in the sample.)

The OnAuthenticationSuccess triggered, as did OnOpenConnection (SSH & SFTP).

I rebuilt the VB.Net SFTP Sophisticated Client (from the C# code) and have been exercising that. I sent a copy by private letter to Eugene (I have no email for you directly) in case you all would find it useful.

Now that I've got my connection working right, I think I need to wait on the OnValidateSuccess & both OnOpenConnection events (or their failures) before I can continue with the transfer.

In my testing, the sequence seems to be OnValidateSuccess, (SSH) OnOpenConnection, then (SFTP) OnOpenConnection. Would it be reasonable to WaitAny on a pair of waithandles? One for error and one for SFTP ?

-greg
#13256
Posted: 05/11/2010 02:42:32
by Ken Ivanov (EldoS Corp.)

There can be three possible event sequences depending on specifics of particular SSH/SFTP negotiation:

1) Successful negotiation (some informational non-important events are omitted):
- TElSSHClient.OnKeyValidate,
- 0 or more TElSSHClient.OnAuthenticationFailed calls,
- TElSSHClient.OnAuthenticationSuccess,
- TElSSHClient.OnOpenConnection,
- TElSFTPClient.OnOpenConnection.

2) Unsuccessful negotiation due to fatal SSH problem (bad credentials, compatibility issues):
- TElSSHClient.OnKeyValidate,
- 0 or more TElSSHClient.OnAuthenticationFailed,
- TElSSHClient.OnError.

3) Unsuccessful negotiation due to server-side restrictions that result in impossibility to open SFTP subsystem (SSH session is opened fine though):
- TElSSHClient.OnKeyValidate,
- 0 or more TElSSHClient.OnAuthenticationFailed calls,
- TElSSHClient.OnAuthenticationSuccess,
- TElSSHClient.OnOpenConnection,
- TElSubsystemSSHTunnel.OnError / TElSSHClient.OnError / TElSFTPClient.OnError (depends on the particular server).

As TElSSHClient.OnError may not be invoked in (3), it is preferable to wait for all of the TElSSHClient.OnError, TElSubsystemSSHTunnel.OnError and TElSFTPClient.OnError events. Successful negotiation result is always indicated by TElSFTPClient.OnOpenConnection call.
#13278
Posted: 05/11/2010 13:30:34
by Greg  (Standard support level)
Joined: 12/09/2009
Posts: 20

I have a question on how to correctly handle Authentication Success/Failure. Not quite sure how to pose the question, but here goes.

For example purposes, suppose I have 2 authentication types.

Case 1. OnAuthenticationSuccess happens (no Failures [yet?]).
Does this mean that no further authentication attempts will be made since success happened? If so, I can flag this piece as success and wake up the main thread.

Case 2. OnAuthenticationFailure followed by AuthenticationSuccess.
From reading the help, I take it that a success can happen after a failure and that the connection will proceed (may fail later, but not due to authentication). In the Failure, I can flag failure which will then be re-flag as success (if case one is valid) and wake up the main thread.

Case 3. No OnAuthenticationSuccess happens at all (all failures).
Each time I go through the OnAuthenticationFaiure it can flag as failure, but it can't wake up the main thread because there may be another Authentication attempt which may succeed.

The question is: Where can I test my flag settings and wake up my waiting main thread that things have Succeeded or Failed? If authentication checking stops with Success, then I can wake up the main thread in success. But how do I wake up the main thread in Case 3 (all failure)?

My main thread is waiting on a handle and will timeout, but it would be better to wake it up once I know I have a complete fail.

-g
#13284
Posted: 05/11/2010 15:21:09
by Ken Ivanov (EldoS Corp.)

Quote
Case 1. OnAuthenticationSuccess happens (no Failures [yet?]).
Does this mean that no further authentication attempts will be made since success happened? If so, I can flag this piece as success and wake up the main thread.

Yes. OnAuthenticationSuccess indicates the completeness of the "authentication" stage. Once this event has fired, the component goes forward to the "connection" stage and begins to open tunnels listed in the tunnel list object assigned to its TunnelList property (the ones having the AutoOpen property set to true, to be exact).

Quote
Case 2. OnAuthenticationFailure followed by AuthenticationSuccess.
From reading the help, I take it that a success can happen after a failure and that the connection will proceed (may fail later, but not due to authentication). In the Failure, I can flag failure which will then be re-flag as success (if case one is valid) and wake up the main thread.

SSH supports a number of authentication methods (password-based, key-based and keyboard-interactive). Besides, each authentication type can be tried several times during one connection attempt. Each failing authentication attempt is reported via the OnAuthenticationFailed event. That is, OnAuthenticationFailed indicates not a failure of the entire authentication process, but a failure of one of the attempts performed.

Quote
The question is: Where can I test my flag settings and wake up my waiting main thread that things have Succeeded or Failed? If authentication checking stops with Success, then I can wake up the main thread in success. But how do I wake up the main thread in Case 3 (all failure)?

All the critical negotiation issues are reported via the OnError event. If the component has exhausted all the available authentication methods with no success, the ERROR_SSH_NO_MORE_AUTH_METHODS_AVAILABLE (=114) error will be returned after the sequence of OnAuthenticationFailed calls. There is actually no need in checking the error code before waking the waiting thread -- OnError is always an indication of general connection failure.
#13287
Posted: 05/11/2010 23:59:37
by Greg  (Standard support level)
Joined: 12/09/2009
Posts: 20

OK, I implemented an "AsyncWH" ManualResetEvent which I reset before a call to any async function and a AsyncAction Enum that works much like the STATE_ variables in the Sophisticated Client. I then use ConnectAsync for the Socket(vs BeginConnect/EndConnect) and ReceiveAsync for the reads (vs BeginReceive/EndReceive) along with AsyncWH.WaitOne(TimeoutMS) until an OnError or SFTP_OnOpenConnection or Timeout. The Enum values let me know which of the three happened. This is working great.

During this process I discovered that the Sophisticated client is using Socket.Send which is a blocking call on both the C# and the VB variants. I'll get to this directly (probably set .SendTimeout)

I extended the same method and created the "Send" operation and it works great also.

The current item I'm working through is what order to do the SSH/SFTP/Tunnel/Socket teardown. I've not found a combination that doesn't trip over itself. Is there some specific order that the teardown should be done?

The Sophisticated client does a close on the socket first, but if I then go and try and close the SSH, it gets sick over the socket being closed. If I close the SSH first, the OnSocketReceiveCallback get's sick at SSH.DataAvailable. I'm sure I can come up with some flagging to prevent the methods from tripping over missing elements (like testing for nothing & etc.) but was wondering if there is a preferable order.

Thanks,
-greg
#13288
Posted: 05/12/2010 01:26:37
by Ken Ivanov (EldoS Corp.)

Unfortunately, there is almost no possibility to bypass working with flags -- just because different servers behave quite differently when it comes to SSH/SFTP session closure. In most of the cases it would be enough to close SSH component first, then to close the socket connection. An easier way (not "legal" enough, but workable though) would be to close SSH connection forcibly, passing true to the TElSSHClient.Close() method. This will deliver you from the necessity to handle graceful session closure which involves certain data exchange after the Close() method is called.

Once TElSSHClient.Close() is called, you can close the socket. However, you must be prepared to the following:
1) the socket connection may be got closed by the remote side for the moment when TElSSHClient.Close() returns,
2) some data may arrive to the socket after Close() method returns.
#13413
Posted: 05/21/2010 15:19:11
by Greg  (Standard support level)
Joined: 12/09/2009
Posts: 20

I've got things sending just fine and my Async processes are working well now. I was cleaning up some stuff and ran across the OnSend and noted that I didn't have much in the way of error cleanup. So,

In the SSHClient.OnSend,

How should I indicate an error back to the SSHClient?

Suppose, during my send over the socket, I get a socket closed or some other error, how should I "tell" SSH?

Currently I'm logging and closing the whole process (SFTP, SSH, Socket, etc), but was wondering if there was a preferred way to tell SSH or should I just ".Close" ?

-g
Also by EldoS: MsgConnect
Cross-platform protocol-independent communication framework for building peer-to-peer and client-server applications and middleware components.

Reply

Statistics

Topic viewed 7697 times

Number of guests: 1, registered members: 0, in total hidden: 0




|

Back to top

As of July 15, 2016 EldoS Corporation will operate as a division of /n software inc. For more information, please read the announcement.

Got it!