This shows you the differences between two versions of the page.
Both sides previous revision Previous revision Next revision | Previous revision Next revision Both sides next revision | ||
cookbooks:devel:core [2019/10/10 14:52] miconda |
cookbooks:devel:core [2020/04/03 09:28] henningw [sip_warning (noisy feedback)] |
||
---|---|---|---|
Line 9: | Line 9: | ||
===== Structure ===== | ===== Structure ===== | ||
- | The structure of the kamailio.cfg can be seen as thee parts: | + | The structure of the kamailio.cfg can be seen as three parts: |
* global parameters | * global parameters | ||
Line 253: | Line 253: | ||
* **# | * **# | ||
* **# | * **# | ||
+ | |||
+ | Predefined keywords: | ||
+ | * **KAMAILIO_X[_Y[_Z]]** - Kamailio versions | ||
+ | * **MOD_X** - when module X has been loaded | ||
+ | See ' | ||
Among benefits: | Among benefits: | ||
Line 1053: | Line 1058: | ||
==== listen ==== | ==== listen ==== | ||
- | Set the network addresses the SIP server should listen to. It can be an IP address, hostname or network | + | Set the network addresses the SIP server should listen to. It can be an IP address, hostname or network |
Example of usage: | Example of usage: | ||
Line 1068: | Line 1073: | ||
<code c> | <code c> | ||
- | listen=udp: | + | listen=udp: |
</ | </ | ||
Line 1074: | Line 1079: | ||
<code c> | <code c> | ||
- | listen=udp: | + | listen=udp: |
</ | </ | ||
Line 1080: | Line 1085: | ||
A typical use case for advertise address is when running SIP server behind a NAT/ | A typical use case for advertise address is when running SIP server behind a NAT/ | ||
+ | |||
+ | A unique name can be set for sockets to simplify the selection of the socket for sending out. For example, the rr and path modules can use the socket name to advertise it in header URI parameter and use it as a shortcut to select the corresponding socket for routing subsequent requests. | ||
+ | |||
+ | The name has to be provided as a string enclosed in between quotes after the **name** identifier. | ||
+ | |||
+ | <code c> | ||
+ | listen=udp: | ||
+ | listen=udp: | ||
+ | listen=udp: | ||
+ | listen=udp: | ||
+ | ... | ||
+ | $fsn = " | ||
+ | t_relay(); | ||
+ | </ | ||
+ | |||
+ | Note that there is no internal check for uniqueness of the socket names, the admin has to ensure it in order to be sure the desired socket is selected, otherwise the first socket with a matching name is used. | ||
==== loadmodule ==== | ==== loadmodule ==== | ||
Line 1574: | Line 1595: | ||
==== sip_warning (noisy feedback) ==== | ==== sip_warning (noisy feedback) ==== | ||
- | Can be 0 or 1. If set to 1 (default value) a ' | + | Can be 0 or 1. If set to 1 (default value is 0) a ' |
The header contains several details that help troubleshooting using the network traffic dumps, but might reveal details of your network infrastructure and internal SIP routing. | The header contains several details that help troubleshooting using the network traffic dumps, but might reveal details of your network infrastructure and internal SIP routing. | ||
Line 1688: | Line 1709: | ||
udp_mtu_try_proto = TCP|TLS|SCTP|UDP | udp_mtu_try_proto = TCP|TLS|SCTP|UDP | ||
+ | |||
+ | |||
+ | ==== uri_host_extra_chars ==== | ||
+ | |||
+ | Specify additional chars that should be allowed in the host part of URI. | ||
+ | |||
+ | <code c> | ||
+ | uri_host_extra_chars = " | ||
+ | </ | ||
==== user ==== | ==== user ==== | ||
Line 2622: | Line 2652: | ||
Force to send the message from the specified socket (it _must_ be one of the sockets specified with the " | Force to send the message from the specified socket (it _must_ be one of the sockets specified with the " | ||
+ | |||
+ | This function does not support pseudo-variables, | ||
Example of usage: | Example of usage: | ||
Line 2978: | Line 3010: | ||
Add " | Add " | ||
+ | |||
===== Custom Global Parameters ===== | ===== Custom Global Parameters ===== | ||
- | These are parameters that can be defined by the writer of kamailio.cfg in order to be used inside routing blocks. | + | These are parameters that can be defined by the writer of kamailio.cfg in order to be used inside routing blocks. |
+ | |||
+ | The definition of a custom global parameter must follow the pattern: | ||
+ | |||
+ | < | ||
+ | group.variable = value desc " | ||
+ | |||
+ | </ | ||
+ | |||
+ | The value can be a quoted string or integer number. | ||
+ | |||
+ | Example: | ||
+ | |||
+ | <code c> | ||
+ | pstn.gw_ip = " | ||
+ | </ | ||
+ | |||
+ | The custom global parameter can be accessed inside a routing block via: | ||
+ | |||
+ | < | ||
+ | $sel(cfg_get.group.variable) | ||
+ | </ | ||
+ | |||
+ | Example: | ||
+ | |||
+ | <code c> | ||
+ | $ru = " | ||
+ | </ | ||
+ | |||
+ | **Note:** Some words cannot be used as (part of) names for custom variables or groups, and if they are used a syntax error is logged | ||
+ | |||
+ | ===== Routing Blocks ===== | ||
+ | |||
+ | The routing blocks are the parts of the configuration file executed by kamailio at runtime. They can be seen as blocks of actions similar to functions (or procedures) from common programming languages. | ||
+ | |||
+ | A routing block is identified by a specific token, followed by a name in between square brackets and actions in between curly braces. | ||
+ | |||
+ | <code c> | ||
+ | route_block_id[NAME] { | ||
+ | ACTIONS | ||
+ | } | ||
+ | </ | ||
+ | |||
+ | The name can be any alphanumeric string, with specific routing blocks enforcing a particular format. | ||
+ | |||
+ | <fc # | ||
+ | |||
+ | Route blocks can be executed on network events (e.g., receiving a SIP message), timer events (e.g., retransmission timeout) or particular events specific to modules. | ||
+ | |||
+ | There can be so called sub-route blocks, which can be invoked from another route blocks, like a function. Invocation is done with ' | ||
+ | |||
+ | Example: | ||
+ | |||
+ | <code c> | ||
+ | request_route{ | ||
+ | ... | ||
+ | route(" | ||
+ | ... | ||
+ | } | ||
+ | |||
+ | route[" | ||
+ | ... | ||
+ | } | ||
+ | </ | ||
+ | |||
+ | ==== request_route ==== | ||
+ | |||
+ | Request routing block - is executed for each SIP request. | ||
+ | |||
+ | It contains a set of actions to be executed for SIP requests received from the network. It is the equivalent of *main()* function for handling the SIP requests. | ||
+ | |||
+ | <fc # | ||
+ | |||
+ | The implicit action after execution of the main route block is to drop the SIP request. To send a reply or forward the request, explicit actions (e.g., sl_send_reply(), | ||
+ | |||
+ | Example of usage: | ||
+ | |||
+ | <code c> | ||
+ | request_route { | ||
+ | | ||
+ | # send reply for each options request | ||
+ | sl_send_reply(" | ||
+ | exit(); | ||
+ | } | ||
+ | | ||
+ | } | ||
+ | route[FWD] { | ||
+ | # forward according to uri | ||
+ | | ||
+ | } | ||
+ | </ | ||
+ | |||
+ | ==== route ==== | ||
+ | |||
+ | This block is used to define ' | ||
+ | |||
+ | The definition of the sub-route block follows the general rules, with a name in between square brackets and actions between curly braces. A sub-route can return an integer value back to the routing block that executed it. The return code can be retrieved via $rc variables. | ||
+ | |||
+ | Evaluation of the return of a subroute is done with following rules: | ||
+ | * negative value is evaluated as false | ||
+ | * 0 - is interpreted as **exit** | ||
+ | * positive value is evaluated as true | ||
+ | |||
+ | |||
+ | <code c> | ||
+ | request_route { | ||
+ | if(route(POSITIVE)) { | ||
+ | xlog(" | ||
+ | } | ||
+ | if( ! route(NEGATIVE)) { | ||
+ | xlog(" | ||
+ | } | ||
+ | if( route(ZERO)) { | ||
+ | xlog(" | ||
+ | } | ||
+ | } | ||
+ | |||
+ | route[POSITIVE] { | ||
+ | return 10; | ||
+ | } | ||
+ | |||
+ | route[NEGATIVE] { | ||
+ | return -8; | ||
+ | } | ||
+ | |||
+ | route[ZERO] { | ||
+ | return 0; | ||
+ | } | ||
+ | </ | ||
+ | |||
+ | A sub-route can execute another sub-route. There is a limit to the number of recursive levels, avoiding ending up in infinite loops -- see **max_recursive_level** global parameter. | ||
+ | |||
+ | The sub-route blocks allow to make the configuration file modular, simplifying the logic and helping to avoid duplication of actions. | ||
+ | ==== branch_route ==== | ||
+ | |||
+ | Request' | ||
+ | |||
+ | Example of usage: | ||
+ | |||
+ | <code c> | ||
+ | request_route { | ||
+ | lookup(" | ||
+ | t_on_branch(" | ||
+ | if(!t_relay()) { | ||
+ | sl_send_reply(" | ||
+ | } | ||
+ | } | ||
+ | branch_route[OUT] { | ||
+ | if(uri=~" | ||
+ | # discard branches that go to 10.10.10.10 | ||
+ | drop(); | ||
+ | } | ||
+ | } | ||
+ | </ | ||
+ | |||
+ | ==== failure_route ==== | ||
+ | |||
+ | Failed transaction routing block. It contains a set of actions to be taken each transaction that received only negative replies (>=300) for all branches. The ' | ||
+ | |||
+ | Note that in ' | ||
+ | |||
+ | |||
+ | Example of usage: | ||
+ | |||
+ | <code c> | ||
+ | request_route { | ||
+ | lookup(" | ||
+ | t_on_failure(" | ||
+ | if(!t_relay()) { | ||
+ | sl_send_reply(" | ||
+ | } | ||
+ | } | ||
+ | failure_route[TOVOICEMAIL] { | ||
+ | if(is_method(" | ||
+ | # call failed - relay to voice mail | ||
+ | | ||
+ | } | ||
+ | } | ||
+ | </ | ||
+ | |||
+ | ==== reply_route ==== | ||
+ | |||
+ | Main SIP response (reply) handling block - it contains a set of actions to be executed for SIP replies. It is executed for all replies received from the network. | ||
+ | |||
+ | It does not have a name and it is executed by the core, before any other module handling the SIP reply. It is triggered only by SIP replies received on the network. | ||
+ | |||
+ | There is no network route that can be enforced for a SIP reply - it is sent based on Via header, according to SIP RFC3261 - therefore no dedicated actions for forwarding the reply must be used in this block. | ||
+ | |||
+ | This routing block is optional, if missing, the SIP reply is sent to the address in 2nd Via header. | ||
+ | |||
+ | One can decide to drop a SIP reply by using **drop** action. | ||
+ | |||
+ | Example: | ||
+ | |||
+ | <code c> | ||
+ | reply_route { | ||
+ | if(status==" | ||
+ | drop; | ||
+ | } | ||
+ | } | ||
+ | </ | ||
+ | |||
+ | <fc # | ||
+ | |||
+ | ==== onreply_route ==== | ||
+ | |||
+ | |||
+ | SIP reply routing block executed by **tm** module. It contains a set of actions to be taken for SIP replies in the contect of an active transaction. | ||
+ | |||
+ | The ' | ||
+ | |||
+ | Core ' | ||
+ | |||
+ | <code c> | ||
+ | request_route { | ||
+ | lookup(" | ||
+ | t_on_reply(" | ||
+ | if(!t_relay()) { | ||
+ | sl_send_reply(" | ||
+ | } | ||
+ | } | ||
+ | |||
+ | reply_route { | ||
+ | if(!t_check_trans()) { | ||
+ | drop; | ||
+ | } | ||
+ | } | ||
+ | |||
+ | onreply_route[LOGRPL] { | ||
+ | if(status=~" | ||
+ | | ||
+ | } | ||
+ | } | ||
+ | </ | ||
+ | ==== onsend_route ==== | ||
+ | |||
+ | The route is executed in when a SIP request is sent out. Only a limited number of commands are allowed (drop, if + all the checks, msg flag manipulations, | ||
+ | |||
+ | In this route the final destination of the message is available and can be checked (with snd_ip, snd_port, to_ip, to_port, snd_proto, snd_af). | ||
+ | |||
+ | This route is executed only when forwarding requests - it is not executed for replies, retransmissions, | ||
+ | |||
+ | Example: | ||
+ | |||
+ | <code c> | ||
+ | onsend_route { | ||
+ | if(to_ip==1.2.3.4 && !isflagset(12)){ | ||
+ | log(1, " | ||
+ | drop; | ||
+ | } | ||
+ | } | ||
+ | </ | ||
+ | |||
+ | * snd_ip, snd_port - behave like src_ip/ | ||
+ | * to_ip, to_port - like above, but contain the ip/port the message will be sent to (not to be confused with dst_ip/ | ||
+ | * snd_proto, snd_af - behave like proto/af but contain the protocol/ | ||
+ | * msg:len - when used in an onsend_route, | ||
+ | |||
+ | ==== event_route ==== | ||
+ | |||
+ | Generic type of route executed when specific events happen. | ||
+ | |||
+ | Prototype: event_route[groupid: | ||
+ | * groupid - should be the name of the module that triggers the event | ||
+ | * eventid - some meaningful short text describing the event | ||
+ | |||
+ | === Core Event Routes === | ||
+ | |||
+ | Implementations: | ||
+ | |||
+ | * **event_route[core: | ||
+ | * note that due to forking, other sip workers can get faster to listening for sip traffic | ||
+ | |||
+ | <code c> | ||
+ | event_route[core: | ||
+ | xlog(" | ||
+ | } | ||
+ | </ | ||
+ | |||
+ | * **event_route[core: | ||
+ | * it has to be enabled with received_route_mode global parameter. For usage via Kemi, set kemi.received_route_callback global parameter. | ||
+ | * if drop is executed, the received message is no longer processed | ||
+ | |||
+ | <code c> | ||
+ | event_route[core: | ||
+ | xlog(" | ||
+ | if($rcv(srcip) == " | ||
+ | drop; | ||
+ | } | ||
+ | } | ||
+ | </ | ||
+ | === Module Event Routes === | ||
+ | |||
+ | Here are only a few examples, to see if a module exports event_route blocks and when they are executed, check the readme of the module. | ||
+ | |||
+ | |||
+ | * **event_route[htable: | ||
+ | <code c> | ||
+ | modparam(" | ||
+ | |||
+ | event_route[htable: | ||
+ | $sht(a=> | ||
+ | $sht(a=> | ||
+ | } | ||
+ | |||
+ | request_route { | ||
+ | if(is_method(" | ||
+ | { | ||
+ | switch($rd) { | ||
+ | case " | ||
+ | lock(" | ||
+ | $sht(a=> | ||
+ | $sht(a=> | ||
+ | unlock(" | ||
+ | if($sht(a=> | ||
+ | { | ||
+ | | ||
+ | | ||
+ | } | ||
+ | break; | ||
+ | ... | ||
+ | } | ||
+ | } | ||
+ | } | ||
+ | </ | ||
+ | * **event_route [tm: | ||
+ | <code c> | ||
+ | event_route [tm: | ||
+ | xlog(" | ||
+ | t_set_fr(10000, | ||
+ | } | ||
+ | </ | ||
+ | |||
+ | * **event_route [tm: | ||
+ | <code c> | ||
+ | request_route { | ||
+ | ... | ||
+ | t_on_branch_failure(" | ||
+ | t_relay(); | ||
+ | } | ||
+ | |||
+ | event_route[tm: | ||
+ | xlog(" | ||
+ | if (t_check_status(" | ||
+ | unregister(" | ||
+ | if (t_next_contact_flow()) { | ||
+ | t_relay(); | ||
+ | } | ||
+ | } | ||
+ | } | ||
+ | |||
+ | </ | ||
+ | |||
+ | ===== Script Statements ===== | ||
+ | |||
+ | ==== if ==== | ||
+ | IF-ELSE statement | ||
+ | |||
+ | Prototype: | ||
+ | |||
+ | < | ||
+ | if(expr) { | ||
+ | | ||
+ | } else { | ||
+ | | ||
+ | } | ||
+ | </ | ||
+ | |||
+ | The ' | ||
+ | |||
+ | The logical operators that can be used in ' | ||
+ | |||
+ | < | ||
+ | == equal | ||
+ | != not equal | ||
+ | =~ regular expression matching: Note: Posix regular expressions will be used, e.g. use [[: | ||
+ | !~ regular expression not-matching (NOT PORTED from Kamailio 1.x, use '!(x =~ y)') | ||
+ | > | ||
+ | >= greater or equal | ||
+ | < | ||
+ | <= less or equal | ||
+ | && | ||
+ | || logical OR | ||
+ | ! | ||
+ | [ ... ] test operator - inside can be any arithmetic expression | ||
+ | </ | ||
+ | |||
+ | Example of usage: | ||
+ | |||
+ | if(is_method(" | ||
+ | { | ||
+ | log(" | ||
+ | } else { | ||
+ | log(" | ||
+ | } | ||
+ | |||
+ | |||
+ | ==== switch ==== | ||
+ | |||
+ | SWITCH statement - it can be used to test the value of a pseudo-variable. | ||
+ | |||
+ | IMPORTANT NOTE: ' | ||
+ | |||
+ | |||
+ | Example of usage: | ||
+ | < | ||
+ | route { | ||
+ | route(1); | ||
+ | switch($retcode) | ||
+ | { | ||
+ | case -1: | ||
+ | log(" | ||
+ | break; | ||
+ | case 1: | ||
+ | log(" | ||
+ | break; | ||
+ | case 2: | ||
+ | case 3: | ||
+ | log(" | ||
+ | break; | ||
+ | default: | ||
+ | log(" | ||
+ | } | ||
+ | |||
+ | # switch of R-URI username | ||
+ | switch($rU) | ||
+ | { | ||
+ | case " | ||
+ | log(" | ||
+ | break; | ||
+ | case " | ||
+ | log(" | ||
+ | break; | ||
+ | case " | ||
+ | case " | ||
+ | log(" | ||
+ | break; | ||
+ | default: | ||
+ | log(" | ||
+ | } | ||
+ | } | ||
+ | |||
+ | route[1]{ | ||
+ | if(is_method(" | ||
+ | { | ||
+ | return(-1); | ||
+ | }; | ||
+ | if(is_method(" | ||
+ | return(1); | ||
+ | } | ||
+ | if(is_method(" | ||
+ | return(2); | ||
+ | } | ||
+ | if(is_method(" | ||
+ | return(3); | ||
+ | } | ||
+ | return(-2); | ||
+ | } | ||
+ | </ | ||
+ | |||
+ | NOTE: take care while using ' | ||
+ | |||
+ | |||
+ | ==== while ==== | ||
+ | |||
+ | while statement | ||
+ | |||
+ | Example of usage: | ||
+ | |||
+ | $var(i) = 0; | ||
+ | while($var(i) < 10) | ||
+ | { | ||
+ | xlog(" | ||
+ | $var(i) = $var(i) + 1; | ||
+ | } | ||
+ | |||
+ | ===== Script Operations ===== | ||
+ | |||
+ | Assignments together with string and arithmetic operations can be done directly in configuration file. | ||
+ | ==== Assignment ==== | ||
+ | |||
+ | Assignments can be done like in C, via ' | ||
+ | * Unordered List Item AVPs - to set the value of an AVP | ||
+ | * script variables ($var(...)) - to set the value of a script variable | ||
+ | * shared variables ($shv(...)) | ||
+ | * $ru - to set R-URI | ||
+ | * $rd - to set domain part of R-URI | ||
+ | * $rU - to set user part of R-URI | ||
+ | * $rp - to set the port of R-URI | ||
+ | * $du - to set dst URI | ||
+ | * $fs - to set send socket | ||
+ | * $br - to set branch | ||
+ | * $mf - to set message flags value | ||
+ | * $sf - to set script flags value | ||
+ | * $bf - to set branch flags value | ||
+ | |||
+ | < | ||
+ | $var(a) = 123; | ||
+ | </ | ||
+ | |||
+ | For avp's there a way to remove all values and assign a single value in one statement (in other words, delete existing AVPs with same name, add a new one with the right side value). This replaces the := assignment operator from kamailio < 3.0. | ||
+ | < | ||
+ | $(avp(i: | ||
+ | $(avp(i: | ||
+ | </ | ||
+ | |||
+ | ==== String Operations ==== | ||
+ | For strings, ' | ||
+ | |||
+ | < | ||
+ | $var(a) = " | ||
+ | $var(b) = " | ||
+ | </ | ||
+ | ==== Arithmetic Operations ==== | ||
+ | |||
+ | For numbers, one can use: | ||
+ | * + : plus | ||
+ | * - : minus | ||
+ | * / : divide | ||
+ | * * : multiply | ||
+ | * % : modulo (Kamailio uses ' | ||
+ | * | : bitwise OR | ||
+ | * & : bitwise AND | ||
+ | * ^ : bitwise XOR | ||
+ | * ~ : bitwise NOT | ||
+ | * < | ||
+ | * < | ||
+ | |||
+ | |||
+ | Example: | ||
+ | |||
+ | < | ||
+ | $var(a) = 4 + ( 7 & ( ~2 ) ); | ||
+ | </ | ||
+ | |||
+ | NOTE: to ensure the priority of operands in expression evaluations do use __parenthesis__. | ||
+ | |||
+ | Arithmetic expressions can be used in condition expressions. | ||
+ | |||
+ | < | ||
+ | if( $var(a) & 4 ) | ||
+ | log(" | ||
+ | </ | ||
+ | |||
+ | ===== Operators ===== | ||
+ | |||
+ | - type casts operators: (int), (str). | ||
+ | - string comparison: eq, ne | ||
+ | - integer comparison: ieq, ine | ||
+ | |||
+ | Note: The names are not yet final (use them at your own risk). Future version might use ==/!= only for ints (ieq/ine) and eq/ne for strings (under debate). They are almost equivalent to == or !=, but they force the conversion of their operands (eq to string and ieq to int), allowing among other things better type checking on startup and more optimizations. | ||
+ | |||
+ | Non equiv. examples: | ||
+ | |||
+ | 0 == "" | ||
+ | |||
+ | " | ||
+ | |||
+ | Note: internally == and != are converted on startup to eq/ | ||
+ | |||
+ | - Kamailio tries to guess what the user wanted when operators that support multiple types are used on different typed operands. In general convert the right operand to the type of the left operand and then perform the operation. Exception: the left operand is undef. This applies to the following operators: +, == and !=. | ||
+ | | ||
+ | For +: undef + expr -> undef is converted to string => "" | ||
+ | For == and !=: undef == expr -> undef is converted to type_of expr. | ||
+ | If expr is undef, then undef == undef is true (internally is converted | ||
+ | to string). | ||
+ | |||
+ | - expression evaluation changes: Kamailio will auto-convert to integer or string in function of the operators: | ||
+ | | ||
+ | | ||
+ | |||
+ | - script operators for dealing with empty/ | ||
+ | defined expr - returns true if expr is defined, and false if not. | ||
+ | Note: only a standalone avp or pvar can be | ||
+ | | ||
+ | strlen(expr) - returns the lenght of expr evaluated as string. | ||
+ | strempty(expr) - returns true if expr evaluates to the empty | ||
+ | | ||
+ | Example: if (defined $v && !strempty($v)) $len=strlen($v); |