In this H.323 terminal project all signalling entities are controlled by the same user (called Supervisory Thread). From such a point of view, H.245 Subsystem is treated as a monolith. There is no need to distinguish separate signalling entities' instances.
As shows Figure 3-1, the Supervisory Thread (S in the figure) passes primitives to the H.245 Subsystem (C3 in the figure) and the Subsystem responses (in case of outgoing procedure) or the H.245 Subsystem passes primitives to the supervisory thread (incoming procedures). The Supervisory Thread must be ready for signals from the User Control Module (U in the figure), which are ordered by the human user. At the peer side there is a similar functionality.A primitive passed by the Supervisory Thread is delivered to the proper entity, which is previously created if needed. Unlike in Figure 1-2, signalling entities are not connected directly to the TCP and to the user. Creation and choosing the proper entity is performed by two threads called "Managers".
Note that, the responsibility of the H.245 user (as described in the previous chapter) is in this implementation divided among the managers and the supervisory thread. The primitives described here are slightly modified comparing to H.245 primitives : to distinguish every entity instance, some additional parameters were introduced. Commands and indications have the same form as the primitives passed to the entities.
The first manager, the "User Manager", is responsible for communication with the user; the second one, "TCP Manager", communicates with other terminals over a TCP socket (Figure 3-2). Primitive manager is a looped thread, being blocked on queue of primitives almost all the time. When the Supervisory Thread passes a primitive, the User Manager gets it and starts analyzing. It checks whether it is a system control primitive, making manager (and all H.245 subsystem) terminate. If it is so, all H.245 threads are killed and H.245 is stopped. If not, the User Manager looks whether the primitive can be cast to simple message (command or indication). In this case, a message is prepared and sent to remote terminal. Otherwise, a primitive must be passed to a signalling entity. First, the type of entity is determined. Next, decides whether create new instance of the entity; if so, new entity instance is created. Then, primitive is sent directly to this entity. Entity instances are implemented as separate threads, created by managers. If the entity instance is no longer needed, it destroys itself. Entities sent primitives and messages directly to the user and to the remote terminal, respectively. The (C-like) pseudocode of the entity is presented in Figure 3-3.
while( !stop_condition() )
{
p = get_a_primitive_from_the_queue(); /* blocking function */
if ( is_a_special_primitive(p) ) {
take_appropriate_action(p); /* e.g. Terminate Manager */
} else if ( is_command_or_indication(p) ) {
m = prepare_an_appropriate_message(p);
send_the_message_to_the_peer(m);
} else if ( is_an_h245_primitive(p) ) {
e = determine_entity_type(p);
if (new_instance_must_be_created(p) ) {
i = create_new_instance(e);
} else { /* The instance exists */
i = get_instance(p);
}
pass_primitive_to_the_instance(i, p);
}
} /* while */
Figure 3-3. User Manager Pseudocode
The second manager, the TCP Manager, is also a looped thread, but it blocks on the Control Channel's TCP socket, waiting for messages from the remote terminal. First, it looks whether it is a command or indication message. If positive, the message is directly cast into a command primitive or indication primitive. If not, the message is passed to a proper entity instance (the instance is created if needed). The pseudocode of this manager is presented in Figure 3-4.
while( !stop_condition() )
{
m = get_a_message_from_an_assigned_socket(); /* blocking function */
if ( is_command_or_indication(m) ) {
p = prepare_an_appropriate_primitive(m);
pass_primitive_to_the_suprevisory_thread(p);
} else if ( is_a_well-known_request_or_response(m) ){
e = determine_entity_type(m);
if ( new_instance_must_be_created(m) ) {
i = create_instance(m);
} else { /* The instance exists */
i = get_instance(m);
}
pass_the_message_to_instance(i, m);
} else if ( is_an_unknown_message(m) ){
m1 = prepare_message_parameters("FunctionNotUnderstood", m);
send_the_message_to_the_peer(m1);
}
} /* while */
Figure 3-4. TCP Manager Pseudocode
After passing a primitive to the entity, it starts analyzing the primitive and its parameters and, depending on the internal state of the entity, appropriate action is taken. This first steps of the action are usually:
A fill-up of message's parameters,
A ASN.1 message's encoding,
Starting of a timer,
Sending a message to the peer.
The exact internals of designed H.245 subsystem are shown at Figure 3-5.
At the left side of Figure 3-5 there is the user, communicating with the subsystem. Primitives are queued in special queues. The most often, the managers have to parse the message, to create the entity, and to prepare the proper primitives for the entity. It takes some time and if the primitives were not queued, some of them would be lost. Functions sending and receiving primitives are just functions which put and get nodes from the queues. At the bottom of the figure there are signalling entities starting procedures - if one of the managers wants to create a new instance of the procedure, it just calls the proper function. Outgoing entities are creating by the "User Manager", incoming ones by the "TCP Manager". Once an entity instance is created, it can send and receive messages as well as primitives. Some of the entities must be created while creation of the entire subsystem (MSDSE and RTDSE) .