|
@@ -126,13 +126,13 @@ Juha Heinanen
|
|
|
|
|
|
1.1. Overview
|
|
|
|
|
|
- TM module enables stateful processing of SIP transactions. The main use
|
|
|
- of stateful logic, which is costly in terms of memory and CPU, is some
|
|
|
- services inherently need state. For example, transaction-based
|
|
|
- accounting (module acc) needs to process transaction state as opposed
|
|
|
- to individual messages, and any kinds of forking must be implemented
|
|
|
- statefully. Other use of stateful processing is it trading CPU caused
|
|
|
- by retransmission processing for memory. That makes however only sense
|
|
|
+ The TM module enables stateful processing of SIP transactions. Stateful
|
|
|
+ logic is costly in terms of memory and CPU. The main use is services
|
|
|
+ that inherently need state. For example, transaction-based accounting
|
|
|
+ (module acc) needs to process transaction state as opposed to
|
|
|
+ individual messages. Any kind of forking must be implemented
|
|
|
+ transaction statefully. By using transaction states you trade CPU
|
|
|
+ caused by retransmission processing for memory. That only makes sense
|
|
|
if CPU consumption per request is huge. For example, if you want to
|
|
|
avoid costly DNS resolution for every retransmission of a request to an
|
|
|
unresolvable destination, use stateful mode. Then, only the initial
|
|
@@ -141,7 +141,7 @@ Juha Heinanen
|
|
|
resolution. The price is more memory consumption and higher processing
|
|
|
latency.
|
|
|
|
|
|
- From user's perspective, there are these major functions : t_relay,
|
|
|
+ From the admin's perspective, these are the major functions : t_relay,
|
|
|
t_relay_to_udp and t_relay_to_tcp. All of them setup transaction state,
|
|
|
absorb retransmissions from upstream, generate downstream
|
|
|
retransmissions and correlate replies to requests. t_relay forwards to
|
|
@@ -151,55 +151,56 @@ Juha Heinanen
|
|
|
respectively.
|
|
|
|
|
|
In general, if TM is used, it copies clones of received SIP messages in
|
|
|
- shared memory. That costs the memory and also CPU time (memcpys,
|
|
|
- lookups, shmem locks, etc.) Note that non-TM functions operate over the
|
|
|
- received message in private memory, that means that any core operations
|
|
|
- will have no effect on statefully processed messages after creating the
|
|
|
+ shared memory. That costs memory and also CPU time (memcpys, lookups,
|
|
|
+ shmem locks, etc.) Note that non-TM functions operate over the received
|
|
|
+ message in private memory, that means that any core operations will
|
|
|
+ have no effect on statefully processed messages after creating the
|
|
|
transactional state. For example, calling record_route after t_relay is
|
|
|
pretty useless, as the RR is added to privately held message whereas
|
|
|
its TM clone is being forwarded.
|
|
|
|
|
|
- TM is quite big and uneasy to program--lot of mutexes, shared memory
|
|
|
- access, malloc and free, timers--you really need to be careful when you
|
|
|
- do anything. To simplify TM programming, there is the instrument of
|
|
|
- callbacks. The callback mechanisms allow programmers to register their
|
|
|
- functions to specific event. See t_hooks.h for a list of possible
|
|
|
- events.
|
|
|
+ The TM module is quite big and uneasy to program --lots of mutexes,
|
|
|
+ shared memory access, malloc and free, timers--you really need to be
|
|
|
+ careful when you do anything. To simplify TM programming, there is the
|
|
|
+ instrument of callbacks. The callback mechanisms allow programmers to
|
|
|
+ register their functions to a specific event. See t_hooks.h for a list
|
|
|
+ of possible events.
|
|
|
|
|
|
Other things programmers may want to know is UAC--it is a very
|
|
|
simplistic code which allows you to generate your own transactions.
|
|
|
Particularly useful for things like NOTIFYs or IM gateways. The UAC
|
|
|
- takes care of all the transaction machinery: retransmissions , FR
|
|
|
+ takes care of all the transaction machinery: retransmissions, FR
|
|
|
timeouts, forking, etc. See t_uac prototype in uac.h for more details.
|
|
|
- Who wants to see the transaction result may register for a callback.
|
|
|
+ If you want to see the transaction result the code can register for a
|
|
|
+ callback.
|
|
|
|
|
|
Note
|
|
|
|
|
|
- Several Kamailio (OpenSER) TM module functionalities are now
|
|
|
- implemented in the TMX module: "modules_k/tmx". Check it to see if what
|
|
|
- you are looking for is there.
|
|
|
+ Several Kamailio TM module functions are now implemented in the TMX
|
|
|
+ module: "modules_k/tmx". Check it to see if what you are looking for is
|
|
|
+ there.
|
|
|
|
|
|
1.2. Serial Forking Based on Q Value
|
|
|
|
|
|
A single SIP INVITE request may be forked to multiple destinations. We
|
|
|
- call the set of all such destinations a destination set. Individual
|
|
|
+ call the set of all such destinations a "destination set". Individual
|
|
|
elements within the destination sets are called branches. The script
|
|
|
writer can add URIs to the destination set from the configuration file,
|
|
|
- or they can be loaded from the user location database, each registered
|
|
|
+ or they can be loaded from the user location database. Each registered
|
|
|
contact then becomes one branch in the destination set.
|
|
|
|
|
|
- The default behavior of the tm module, if it encounters a SIP message
|
|
|
- with multiple branches in the destination set, it to forward the SIP
|
|
|
+ The default behavior of the TM module, if it encounters a SIP message
|
|
|
+ with multiple branches in the destination set, is to forward the SIP
|
|
|
message to all the branches in parallel. That means it sends the
|
|
|
message to all the branch destinations before it waits for replies from
|
|
|
any of them. This is the default behavior if you call t_relay() and
|
|
|
- similar functions without anything else.
|
|
|
+ similar functions without any other arguments.
|
|
|
|
|
|
- Another approach of handling multiple branches in a destination set it
|
|
|
+ Another approach of handling multiple branches in a destination set is
|
|
|
serial forking. When configured to do serial forking, the server takes
|
|
|
the first branch out of the destination set, forwards the message to
|
|
|
its destination and waits for a reply or timeout. Only after a reply
|
|
|
- has been received or the timeout occurred, the server takes another
|
|
|
+ has been received or a timeout occurred, the server takes another
|
|
|
destination from the destination set and tries again, until it receives
|
|
|
a positive final reply or until all branches from the destination set
|
|
|
have been tried.
|
|
@@ -211,21 +212,21 @@ Note
|
|
|
the destination set. Branches can be tried sequentially in the
|
|
|
descending priority order and all branches that have the same priority
|
|
|
can be tried in parallel. Such combined serial/parallel forking can be
|
|
|
- achieved in the tm module with the help of functions t_load_contacts()
|
|
|
+ achieved in the TM module with the help of functions t_load_contacts()
|
|
|
and t_next_contacts().
|
|
|
|
|
|
Every branch in the destination set is assigned a priority number, also
|
|
|
- known as the q value. The q value is a floating point number in a range
|
|
|
- 0 to 1.0. The higher the q value number, the more priority is the
|
|
|
- particular branch in the destination set is given. Branches with q
|
|
|
- value 1.0 have maximum priority, such branches should be always tried
|
|
|
- first in serial forking. Branches with q value 0 have the lowest
|
|
|
+ known as the "q value". The q value is a floating point number in a
|
|
|
+ range 0 to 1.0. The higher the q value number, the more priority is
|
|
|
+ given to the particular branch in the destination set. Branches with q
|
|
|
+ value 1.0 have maximum priority, such branches should be always be
|
|
|
+ tried first in serial forking. Branches with q value 0 have the lowest
|
|
|
priority and they should by tried after all other branches with higher
|
|
|
priority in the destination set.
|
|
|
|
|
|
As an example, consider the following simple configuration file. When
|
|
|
- the server receives an INVITE, it creates four branches for it with
|
|
|
- usernames A through D and then forwards the request using t_relay():
|
|
|
+ the server receives an INVITE, it creates four branches with usernames
|
|
|
+ A through D and then forwards the request using t_relay():
|
|
|
route {
|
|
|
seturi("sip:[email protected]");
|
|
|
append_branch("sip:[email protected]");
|
|
@@ -236,10 +237,11 @@ route {
|
|
|
break;
|
|
|
}
|
|
|
|
|
|
- With this configuratin the server forwards the request to all four
|
|
|
- branches at once, performing parallel forking described above. We did
|
|
|
- not set the q value for individual branches in this example but we can
|
|
|
- do that by slightly modifying the arguments given to append_branch():
|
|
|
+ With this configuration the server forwards the request to all four
|
|
|
+ branches at once, performing parallel forking as described above. We
|
|
|
+ did not set the q value for individual branches in this example but we
|
|
|
+ can do that by slightly modifying the arguments given to
|
|
|
+ append_branch():
|
|
|
route {
|
|
|
seturi("sip:[email protected]");
|
|
|
append_branch("sip:[email protected]", "0.5");
|
|
@@ -343,12 +345,11 @@ failure_route["serial"]
|
|
|
And that's the whole example, we achieved combined serial/parallel
|
|
|
forking based on the q value of individual branches. In real-world
|
|
|
configuration files the script writer would need to check the return
|
|
|
- value of all functions and restart_fr_on_each_reply. Also the
|
|
|
- destination set would not be configured directly in the configuration
|
|
|
- file, but can be retrieved from the user location database, for
|
|
|
- example. In that case registered contacts will be stored in the
|
|
|
- destination set as branches and their q values (provided by UAs) will
|
|
|
- be used.
|
|
|
+ value of all functions and restart_fr_on_each_reply. The destination
|
|
|
+ set would not be configured directly in the configuration file, but can
|
|
|
+ be retrieved from the user location database. In that case registered
|
|
|
+ contacts will be stored in the destination set as branches and their q
|
|
|
+ values (provided by UAs) will be used.
|
|
|
|
|
|
1.3. Known Issues
|
|
|
|
|
@@ -356,7 +357,7 @@ failure_route["serial"]
|
|
|
as they do not be replied with 100, and do not result in
|
|
|
ACK/CANCELs, and other things which take parsing. However, we need
|
|
|
to rethink whether we don't need parsed headers later for something
|
|
|
- else. Remember, when we now conserver a request in sh_mem, we can't
|
|
|
+ else. Remember, when we now store a request in sh_mem, we can't
|
|
|
apply any pkg_mem operations to it any more. (that might be
|
|
|
redesigned too).
|
|
|
* Another performance improvement may be achieved by not parsing CSeq
|