+During client library implementation, few things to keep in mind.
+
+Threads and locking in client library
+
+ The client library is multithreaded in so that the actual SilcClient
+ runs in one main thread (may be application main thread or its created
+ thread for the client), and each connection to a remote host runs in
+ an own thread. There are no other threads in client library. If there
+ is only one connection in the client, then most likely there is only
+ one thread in addition of main thread.
+
+ The SilcClient context must be protected with lock (client->internal->lock),
+ because it may be accessed from connection threads and by application.
+ It is guaranteed that the client main thread never access the connection
+ thread, and it is guaranteed that no other connection thread access
+ another connection thread. Even still, the SilcClientConnection has
+ a lock (conn->internal->lock) because it may be accessed by application.
+
+ Practically everything in the client is executed in the connection thread.
+ Receiving packets, commands, notifys, etc all happen in connection thread.
+ It is not possible to receive packets in two different threads that would
+ be destined to one specific connection thread. But, because packets and
+ commands may be sent from application thread the connection lock is
+ used to protect shared data in the SilcClientConnection. It is, however,
+ guaranteed that the main client thread, or other connection thread will
+ not send any packets or commands to another connection. When remembered
+ this makes programming easier. Everything happens in one thread that
+ has something to do with the connection. When packet is received and
+ it is processed asynchronously, it is always guaranteed that it is
+ processed in that same thread, even if it is processed asynchronously.
+ No other thread will process it. If it is processed synchronously, no
+ other packet may arrive at the same time, not for that connection.
+ But it is possible that while we are processing incoming command reply,
+ application sends another command from application thread. Because of
+ this, the lock exist in the connection context.
+
+
+Using locks
+
+ Use locking only if necessary. For performance reasons SILC Atomic
+ Operations API should be preferred if it can be used to achieve what
+ needs to be achieved. All reference counters must be atomic integers
+ and locking must not be used with them.
+
+
+Using FSM
+
+ The client library internals are to be rewritten with SILC FSM and all
+ major operations should be implemented as FSM.
+
+ Always return SILC_FSM_CONTINUE if you need to move to next state
+ synchronously. Use SILC_FSM_YIELD if you are in FSM thread and
+ peformance is not an issue, but only if there really are other FSM
+ threads that need execution time also.
+
+
+When to use FSM semaphore signalling?
+
+ FSM semaphore signalling should be used only when multiple threads
+ (FSM threads) may be waiting for something to happen. If only one thread
+ is waiting for something it should merely return SILC_FSM_WAIT and when
+ that something happens it should use silc_fsm_continue or
+ silc_fsm_continue_sync to continue in the waiting thread. OTOH, if
+ multiple threads are waiting SILC_FSM_SEMA_POST is the only way to
+ deliver the signal. Always remember that posting is signal is not
+ donbe synchronously (it won't be delivered immediately).
+
+ OTOH, if there is only one thread waiting for somtehing to happen but
+ there can be multiple threads signalling that something has happened
+ only way to do this is to use semaphore signalling.
+
+ Semaphore signals should be pre-allocated SilcFSMSemaStruct structures
+ and for signalling use they are always initialized as:
+
+ silc_fsm_sema_init(&sema, fsm, 0);
+
+ The call cannot fail. Semaphores need not be uninitialized and the same
+ context may be reused.
+
+Finishing threads when closing connection
+
+ When closing SilcClientConnection all threads must first be finished
+ before the connection machine is finished. This is done by finishing
+ all running command threads. That will also finish all waiting packet
+ threads as they are always waiting for a command. If any thread is
+ waiting for something else than a command (such as event threads) they
+ must be explicitly finished. The threads are finished by continuing
+ them synchronously. The threads will detect that we are disconnected
+ (see below). SILC_FSM_YIELD must be returned in st_close() as that
+ gives the FSM scheduler time to finish the threads first. After that
+ the machine can be finished.
+
+ Also, any thread that runs in SilcClientConnection machine must always
+ after returning from wait state to check if we are disconnected by doing
+
+ if (conn->internal->disconnected)
+ xxx;
+
+ If disconnected the thread must finish immediately by returning
+ SILC_FSM_FINISH.
- SILC Client Library Manual
-
- Version 0.7.4
-
-1.0 Introduction
-
-SILC Client library is a full featured SILC Client protocolimplementation.
-The library has been designed to be complete SILC client without actual
-user interface. The library provides the API for the appliation which
-it can use to implement generally whatever user interface it wants. The
-SILC Client Library recides in the lib/silcclient/ directory. It uses
-common and core compomnent of SILC protocol from the lib/silccore, SKE
-from lib/silcske and general utility routines from lib/silcutil.
-
-The `silcapi.h' file defines the function prototypes that application
-must implement in order to be able to create the user interface with the
-library. The idea is that the application can implement whatever user
-interface routines in the functions and display the data whatever way
-it wants. The library is entirely transparent to the user interface and
-it does not include any user interface specific issues such as window
-handling or item handling on the screen etc. These does not interest
-the library. The `silcapi.h' also defines the client libary interface
-the application can call. The interface includes for example functions
-for sending channel and private messages, client and channel retrieval
-and other utility functions.
-
-
-1.0.1 Including Library Headers
-
-Your application must include the following includes in your sources to
-get access all SILC Client Library routines:
-
-#include "silcincludes.h"
-#include "clientlibincludes.h"
-
-If you are compiling with C++ compiler then you need to include the
-headers as follows:
-
-extern "C" {
-#include "silcincludes.h"
-#include "clientlibincludes.h"
-}
-
-
-1.1 Creating Client
-
-The client is context or entity based, so several client entitites can
-be created in the application if needed. However, it should be noted
-that they are completely independent from each other and can be seen
-as different applications. Usually only one client entity is needed
-per application.
-
-The client object is SilcClient which is usually allocated in following
-manner:
-
- SilcClient client = silc_client_alloc(&ops, context, version);
-
-`ops' is the static structure of client operations that library will call.
-`context' can be some application specific context that will be saved into
-the SilcClient object. It is up to the caller to free this context.
-SilcClient is always passed to the application thus the application
-specific context can be retrieved from the SilcClient object. See
-`client.h' file for detailed definition of SilcClient object.
-
-`ops' can be defined for example as follows:
-
-SilcClientOperations ops = {
- silc_say,
- silc_channel_message,
- silc_private_message,
- silc_notify,
- silc_command,
- silc_command_reply,
- silc_connect,
- silc_disconnect,
- silc_get_auth_method,
- silc_verify_public_key,
- silc_ask_passphrase,
- silc_failure,
- silc_key_agreement,
-};
-
-Please see the `client_ops_example.c' source file in lib/silcclient/
-directory for predefined structure and stub functions for your
-convenince. It is provided for programmers so that they can copy
-it and use it directly in their application.
-
-
-1.2 Initializing the Client
-
-The client must be initialized before running. However, there are also
-some other tasks that must be done before initializing the client.
-The following pointers must be set by the application before calling
-the initializing function:
-
- client->username
- client->hostname
- client->realname
- client->pkcs
- client->public_key
- client->private_key
-
-You may also set client->nickname if you want. If it is set then the
-library will change the nickname to that one after the client is connected
-to the server. If not set, then server will initially give the nickname
-which is same as the username.
-
-After setting the pointers one must call:
-
- silc_client_init(client);
-
-which then initializes the client library for the `client'. If the
-pointers mentioned above are not initialized the silc_client_init will
-fail. The application should check the return value of the silc_client_init
-function.
-
-
-1.3 Running the Client
-
-The client is run by calling silc_client_run. The function will call
-the scheduler from utility library that will be run until the program is
-ended. When silc_client_run returns the application is ended. Thus,
-to run the client, call:
-
- silc_client_run(client);
-
-Usually application may do some other initializations before calling
-this function. For example before calling this function application
-should initialize the user interface.
-
-
-1.3.1 Running the Client in GUI application
-
-Many GUI applications has their own main loop or event loop, which they
-would like to use or are forced to use by the underlaying system. If you
-are developing for example GUI application on Unix system, and you are
-using GTK+ or QT as GUI library you would probably like to use their own
-main loop. SILC Client can be run under external main loop as well. The
-interface provides a function silc_client_run_one which will run the
-client library once, and returns immediately. During that running it can
-process incoming data and send outgoing data, but it is guaranteed that it
-will not block the calling process.
-
-It is suggested that you would call this function as many times in a
-second as possible to provide smooth action for the client library. You
-can use an timeout task, or an idle task provided by your GUI library to
-accomplish this. After you have initialized the client library with
-silc_client_init, you should register the timeout task or idle task that
-will call the silc_client_run_one periodically. In the Toolkit package
-there is GTK-- GUI example in silcer/ directory. That example calls the
-silc_client_run_one every 50 milliseconds, and it should be sufficient for
-smooth working.
-
-For Win32 the silc_client_run can be used instead of using the Windows's
-own event loop. However, if you would like to use the silc_client_run_one
-also on Win32 systems it is possible.
-
-
-1.3.1.1 Running Client in GTK--
-
-Here is a short example how to run the SILC Client libary under the
-Gnome/GTK--'s main loop:
-
-gint YourClass::silc_scheduler()
-{
- // Run the SILC client once, and return immediately. This function
- // is called every 50 milliseconds by the Gnome main loop, to process
- // SILC stuff. This function will read data, and write data to network,
- // etc. Makes the client library tick! :)
- silc_client_run_one(silc_client);
- return 1;
-}
-
-then, during initialization of the SILC Client call:
-
- // Setup SILC scheduler as timeout task. This will handle the SILC
- // client library every 50 milliseconds. It will actually make the
- // SILC client work on background.
- Gnome::Main::timeout.connect(slot(this, &YourClass::silc_scheduler), 50);
-
-This will call the function silc_scheduler every 50 millisecconds, which
-on the otherhand will call silc_client_run_one, which will make the SILC
-Client library work on the background of the GUI application.
-
-
-1.4 Creating Connection to Server
-
-Connection to remote SILC server is done by calling:
-
- silc_client_connect_to_server(client, port, hostname, context);
-
-The function will create the connection asynchronously to the server, ie.
-the function will return before the actual connection is created. After
-the connection is created the client->ops->connect operation is called.
-
-Generally speaking the connections are associated with windows' on the
-screen. IRC is usually implemented this way, however it is not the
-necessary way to associate the client's connections. SilcClientConnection
-object is provided by the library (and is always passed to the application)
-that can be used in the application to associate the connection from the
-library. Application specific context can be saved to the
-SilcClientConnection object which then can be retrieved in the application,
-thus perhaps associate the connection with what ever object in
-application (window or something else).
-
-
-1.4.1 Using Own Connecting
-
-Application might not want to use silc_client_connect_to_server function
-if it wants to perform its own connecting for some reason. In this case
-application must call function silc_client_start_key_exchange after it
-has created the connection by itself. This function starts the key
-exhange protocol between the client and server and the library takes care
-of everything after that.
-
-After connection has been created application must call:
-
- SilcClientConnection conn;
-
- /* Add new connection to client */
- conn = silc_client_add_connection(client, hostname, port, context);
-
- /* Start key exchange and let the library handle everything
- after this point on. */
- silc_client_start_key_exchange(client, conn, sock);
-
-NOTE: These calls are performed only and only if application did not call
-silc_client_connect_to_server function, but performed the connecting
-process manually.
-
-
-1.5 Example Client
-
-This section includes an example SILC client implementation in pseudo-like
-C code. It creates and initializes the client and sets up an imaginary
-user interface. The user will use the user interface then to create
-the connections. The SilcClientOperations are expected to be implemented.
-
-#include "silcincludes.h"
-#include "silcapi.h"
-
-int main()
-{
- SilcClientOperations ops = {
- silc_say,
- silc_channel_message,
- silc_private_message,
- silc_notify,
- silc_command,
- silc_command_reply,
- silc_connect,
- silc_disconnect,
- silc_get_auth_method,
- silc_verify_public_key,
- silc_ask_passphrase,
- silc_failure,
- silc_key_agreement,
- };
-
- SilcClient client;
-
- /* Allocate SILC client. The `silc_version_string' is defined
- in includes/version.h file. */
- client = silc_client_alloc(&ops, NULL, silc_version_string);
-
- /* Register default ciphers, pkcs, hash funtions and hmacs. */
- silc_cipher_register_default();
- silc_pkcs_register_default();
- silc_hash_register_default();
- silc_hmac_register_default();
-
- /* Set the mandatory pointers, read public and private key from
- files (or somewhere) and return pointers and PKCS context. */
- client->username = silc_get_username();
- client->hostname = silc_net_localhost();
- client->realname = silc_get_real_name();
- client->pkcs = get_public_and_private_key(&client->public_key,
- &client->private_key);
-
- /* If the keys does not exist, create a key pair since we must
- provide key pair to the library. */
- if (!client->pkcs)
- generate_key_new_key_pair(client);
-
- /* Iinitialize client */
- if (!silc_client_init(client))
- fatal_error("Could not initialize client");
-
- /* Initialize user interface. The user interface can be generally
- initialized at any phase, including before actually allocating
- and initializing the client, if wished. */
- InitUserInterface();
- DoCoolThings();
-
- /* Start the client. This will start the scheduler. At this phase
- the user might have the user interface in front of him already.
- He will use the user interface to create the connection to the
- server for example. When this function returns the program is
- ended. */
- silc_client_run(client);
-
- /* Client is ended */
- return 0;
-}