-
- SILC Client Library Manual
-
- Version 0.5
-
-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.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,
-};
-
-
-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
-
-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.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;
-}
+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.