What are Handlers?
What are handlers and how are they used? Handlers are, essentially, call-back functions that the FlowSsh user registers. Handlers might be called if something interesting happens, or if the library needs some additional information from the user. For example, a handler might be called to notify the user about the progress of a connection the user is establishing, about a channel that has been closed by the server, or in order to request a password needed for further authentication. The reason for such a call-back architecture is that several SSH operations might be in progress simultaneously. With call-backs, each operation gets conveniently managed by its own handler.
Before reading on, we recommend taking a look at our Client interface and studying the examples alongside it. Note that two handlers are registered there, namely [Client]OnHostKey and a progress handler. While [Client]Connect returns immediately without blocking, both handlers are called asynchronously and very likely after [Client]Connect itself returns. In this example, [Client]OnHostKey verifies the public-key of the server, to ensure that FlowSsh is connecting to the right server. It is the user's code inside this handler that decides if the connection should succeed or fail. The progress handler, on the other hand, merely informs the user about the progress of the connection being established, and about the final success or failure.
This design is typical for virtually all requests in FlowSshC/Cpp/Net. The initiating call itself never blocks nor waits for an operation to finish. If internally a request is made to the server, then any results or further actions related to that request are handled asynchronously in corresponding handler(s).
Also apparent from the example is that the handler syntax differs with regard to the FlowSsh interface being used. With FlowSshC, handlers are simple C functions registered by the user. FlowSshCpp wraps the functionality through a higher level abstraction and brings handlers to the user through classes and virtual methods which can be overrided as needed. FlowSshNet handlers come in the form of .NET events which the user can subscribe to in a standardized and straightforward manner. Although the exact usage and syntax is slightly different, the underlying meaning and mechanism is the same.
While most handlers are used to provide feedback to actions initiated by the user, there are also handlers that notify the user about events initiated by the server or network. For example, the server might disconnect a client or close a channel, or the connection itself can get interrupted.
While some handlers are purely optional, others must be provided for specific operations to succeed. For example, there is no sense in requesting a folder listing with the SFTP channel if there is no handler to receive the resulting list.
Handlers will only be called for objects that are active. Clients are active if they are either connected or connecting. Similarly, channels are active if they are open or opening. The global error handler is active as long as there is an active client or channel. Additionally in [C++/.NET] handler objects are said to be active when they are in progress, this is between and including their OnStart and OnDone calls.
A final but very important note: handlers get called by Win32 worker threads from FlowSshC.dll. This means that:
- The user must synchronize data access from handler threads with any other threads.
- It is not possible to use MFC (Microsoft Foundation Classes) from within FlowSshC or FlowSshCpp handlers directly. As handlers are ordinary Win32 threads, they lack the necessary MFC initializations. One possible solution is to forward the handling to a MFC capable thread via Win32 SendMesssage or PostMessage. Our Sftp sample application uses this approach extensively.
- For similar reasons, FlowSshNet users cannot change or update Control based GUI elements from within handler events directly. Note that in .NET, only a thread that owns (has created) a control can modify it. This can be solved easily via the "Invoke Control Pattern". Check out the MSDN examples and discussions on this topic, and the Control.InvokeRequired and Control.Invoke methods in particular.