IIIM server code reading note (part 1)

* UML static structure:
+----------+
| <<if>>   |---o request_accept ()
| IMAccept |---o request_connect ()
+----------+                          +--------+
     A                    +---------|>| IMAuth |
     |                    |           +--------+
     |                    |
 +-------+           +-----------+       +--------+
 | IMSvr |<>----+----| IMUserMgr |<>-----| IMUser |
 +-------+      |    +-----------+ 1   * +--------+
    |           |
    .           |    +-------+       +--------+        +--------+
    |           +----| LEMgr |<>-----| LEBase |-.-.-.->| libiml |
    .           |    +-------+ 1   * +--------+        +--------+
    |           |
    .           |    +------------+       +---------+       +---------+
    |           +----| IMProtocol |<>-----| IMState |<>-----| ICState |
    V                +------------+ 1   * +---------+ 1   * +---------+
+-------------+               A                 A
|<<singleton>>|---o start ()  |                 |
| IMScheduler |---o stop ()   |                 +-------------------------+
+-------------+               +--+                                        |
       A                         |                                        |
       |                         |                                        |
+------------------+          +--------------+       +----------------+   |
| IMScheduler_MTPC |-.-.-.-.->| IIIMProtocol |<>-----| IMSocketListen |   |
+------------------+          +--------------+ 1   1 +----------------+   |
        \                                <>                               |
         \                                |                               |
  +-------------------------------+       +----------map {IIMPTrans*, IIIMP_IMState}
 / Make a thread per connection.  |
| Invoke thread func IMScheduler_ |
| MTPC_thread_entry ()            |
+---------------------------------+
                                          +-------+
                               +-.-.-.-.->| LEMgr |
                               |          +-------+
+-----------+                  |
| <<if>>    |       +--------------+      +--------+
| IMHandler |<|-----| IMConnection |----->| IMUser |
+-----------+       +--------------+ 1  1 +--------+
                      |1   |1  |1            | 1
                      |    |   |             |
                      |    |   |             V *
                      |    |   |         +-----------+
                      |    |   +-------->| IMDesktop |
                      |    |           1 +-----------+
                      |    |
                      |    |             +-------+
                      |    +-------------| IMSvr |
    <<create>>        |                1 +-------+
 +--------------------+
 |
 |      +---------+       +-----------------+
 |      | ICState |<>-----| IMLExec_ICState |
 |      +---------+ 1   1 +-----------------+
 |          |
 |          . <>
 |          |
 V *        V
+---------------+
|   <<if>>      |----o send_event ()
|   ICHandler   |----o ...
+---------------+
      A
      |
+----------------+       +--------------+
| IMInputContext |<----->| IMConnection |
+----------------+ *   1 +--------------+
    |    | 1
    .    |               +-----------+        +-----------------------+
    |    +-------------->| LEContext |-------/ One ic may corresponds |
    .                  * +-----------+      | to several LE context   |
    |                                       +-------------------------+
    .          +-------+
    +-.-.-.-.->| LEMgr | Note: LEMgr should be a singleton?
    .          +-------+
    |
    .          +---------+
    |          | <<if>>  |       +-----------------+
    +-.-.-.-.->| IMLExec |<|-----| IMLExec_ICState |
               +---------+       +-----------------+

+------------+       +---------------+       +------------------+
| IIIMPTrans |<>-----| IMSocketTrans |<|-----| IMSocketTransTLS |
+------------+ 1   1 +---------------+       +------------------+ 

* Before connected: 1. IIIMProtocol::accept ()    IIIMProtocol::restart (), initialize the private member    IMSocketListen *pimsl.    use pimsl to accetp a client socket, and return an IMSocketTrans    instance, if passes the authorization, create an IIIMP_IMState    object and return. 2. IMScheduler_MTPC::start ()    create a pthread for this client's connection 3. IIIMProtocol::receive_and_dispatch ()    pthread loop IMScheduler_MTPC_thread_entry call this function to    handle client requests.    IIIMPTrans::receive () to receive an IIIMP_message, then call 4. 4. IIIMP_IMState::dispatch ()    if ic_id is invalid, call IMState::deliver (). Since the connection    has not been established, the IMState::pproc_state should be null,    so it then call IIIMP_IMState::message_proc (). 5. IIIMP_IMState::message_proc()    in case of IM_CONNECT message, get userinfo from request, call    IMSvr::request_connect (). This IMAccetp interface tries to    authorize this user, if successed, create an IMConnection and    returned as IMHandler*. Change imstate to IIIMP_IMState_Identified. 6. IIIMP_IMState_Identified::message_proc ()    If connected clients request an operation for im instead of ic,    (e.g., IM_CREATEIC, IM_DISCONNECT etc), this method will be    invoked, while in this case the ic_id must be invalid.    in case of IM_CREATEIC, call IMConnection::createic () to create an    IMInputContext instance and returned as ICHandler*. call    IIIMP_ICState::create(ic_id, this, pich) to create an icstate    instance, add it to icmap, then send a reply to client. * After connected: 1. IIIMProtocol::receive_and_dispatch () 2. IMState::dispatch ()    if ic_id is valid, from the IMState::IMShared::ICStateMap, look up    the matched ICState, then call ICState::deliver () to handle the    client's request or reply. 3. ICState::deliver ()    get current ICState, and then call its message_proc ().    IIIMP_ICState::start_request() will turn the current state to    IIIMP_ICState_REQUESTED. While IIIMP_ICState_REQUESTED::finish ()    will restore to previous state, and destory itself.    if current state is requested, its message_proc () will return    false, since it can not handle any request at that time.    if current state is waiting, its message_proc () will see whether    the incoming message is what it's waiting for. if not, it calls    IIIMP_ICState::message_proc () to handle this message, so in    waiting state will not block the normal request. or, it retrieves    and restore to the previous back-up request state, and then call its    dealing method. this method in trun calls get_imlexec()->execute(),
   this method execute all pending iml instructions.

   IIIMP_ICState_REQUESTED::wait ()
   IIIMP_ICState_REQUESTED::wait_aux ()
   These two methods can change the current icstate from "requested"
   to "waiting" (for the replies from client).

   IIIMP_ICState::message_proc()
   in case of IM_SETICFOCUS:
     start_request()->toggle_icfocus () [REQUESTED::toggle_focus ()]
       get_ichandler()->toggle_focus () [IMInputContext::toggle_focus ()]
         get_current_lecontext()->toggle_focus () [LEContext::toggle_focus ()]
           if_SetSCFocus () [SunIM.c: if_SetSCFocus ()]
             s->If->ifm->if_SetSCFocus () [specified LE's setfocus function]
       dealing ()
         execute remaining IML instructions (pushed by LEs)
         finish (), restore to previous state

* How does LE invoke server?
LE can not directly call server functions to send reply/messages to
client. LE calls iml methods (defined at iiimsf/lib/iml/SunIMSubr.c)
to create iml instructions, and append them to the operation list
(via iml_execute(), virtually is iml_execute_iml_wrapper() in LE.cpp).

As we mentioned early, IIIMP_ICState_REQUESTED::dealing() calls
IMLExec_ICState::execute() to process the pending instructions.

IMLExec_ICState::execute_opcode(), in turn calls imli_xxx methods,
these methods then call IIIMP_ICState_REQUESTED member functions which
actually send messages to client.

iml_make_commit_inst()/iml_execute()
               |
               | through an async flow
               V
in IMLExec_ICState::execute_opcode()
  case IMM_COMMIT:
    IMLExec_ICState::imli_commit ()
      IIIMP_ICState_REQUESTED::commit_string ()
        new an iiimp message
        send ()
          IIIMP_ICState::send ()
            IIIMP_IMState::send ()
              IIIMPTrans::send ()
                iiimf_stream_send ()
                  IIIMPTrans_write ()
                    IMSocketTrans::send () or
                    IMSocketTransTLS::send ()

* NameSpace I/O functions:
NameSpace I/O functions are passively invoked by LEs.

in each nsio function, there is a nested event dispatching loop.
Take open_ns () as an example:

   send_message = iiimp_open_ns_new (...);
   xims->send (send_message, true);

   for (;;) {
       xims->get_iiimptrans ()->receive ();
       if (opcode == IM_OPEN_NS_REPLY) {
           break;
       } else {
           xims->dispatch (...);
       }
   }

this loop is very simliar with IIIMProtocol::receive_and_dispatch.

* Misc:
ICState::send_avail_p ()
  IIIMP_ICState::state_send_available_p () { return false; }
  IIIMP_ICState_REQUESTED::state_send_available_p () { return true; }
  IIIMP_ICState_WAITING::state_send_available_p () { return false; }

-----------ICState::deliver ()--------------
if (!p->message_proc(message)) return false;
if (send_avail_p() && get_imlexec()) {
    result = get_imlexec()->execute();
}
--------------------------------------------

only when the icstate in requested, ICState::deliver () will try to
execute the buffered iml instructions. Because only in this state, the
server side (LEs) need to respond to client, and then LE may push iml
instructions in the queue.

Basicly, every branch in IIIMP_ICState::message_proc () will call
IIIMP_ICState_REQUESTED::dealing (), which actually calls
get_imlexec()->execute(). Is it a dup invoke in ICState::deliver ()?

Leave a Reply

Your email address will not be published. Required fields are marked *

You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>

To submit your comment, click the image below where it asks you to...
Clickcha - The One-Click Captcha