-SILC Client Library
-===================
-
-This directory includes the SILC Client implementation. The library uses
-common and core components of SILC protocol from lib/silccore library and
-normal utility routines from lib/silcutil library. The library has been
-designed to be complete SILC Client implementation without actual user
-interface. The library provides the API for the application which it can
-use to implement generally whatever user interface it wants.
-
-The `ops.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.
-
-
-Creating Client
-===============
-
-The client is context or entity based (which ever) thus 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);
-
-`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 = {
- say: silc_say,
- channel_message: silc_channel_message,
- private_message: silc_private_message,
- notify: silc_notify,
- command: silc_command,
- command_reply: silc_command_reply,
- connect: silc_connect,
- disconnect: silc_disconnect,
- get_auth_method: silc_get_auth_method,
- verify_server_key: silc_verify_server_key,
- ask_passphrase: silc_ask_passphrase,
- failure: silc_failure,
-};
-
-
-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. Following
-pointers must be set 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.
-
-
-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.
-
-
-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 the application (window or something
-else).
-
-
-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);
-
-These calls are performed only and only if application did not call
-silc_client_connect_to_server function.
+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 event signalling?
+
+ FSM event 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_EVENT_SIGNAL 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 event signalling.
+
+ Event signals should be pre-allocated SilcFSMEventStruct structures
+ and for signalling use they are always initialized as:
+
+ silc_fsm_event_init(&event, fsm);
+
+ The call cannot fail. Events 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
+ and notify 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;
+ return SILC_FSM_FINISH;
+ }
+
+ If disconnected the thread must finish immediately by returning
+ SILC_FSM_FINISH.
+
+Entry locking
+
+ All entires have a read/write lock. It is used to protect the entries
+ when library updates them at the same time application is reading data
+ from the entries. An API for application to read-lock the entires
+ exist. Library only needs to use write-lock. Using read-lock is not
+ necessary inside library because all connection related stuff, including
+ updating connection related entries are done in one thread. When library
+ is reading data from the entries it cannot be updating them at the same
+ time. Hence, using read-lock inside library is not necessary.