Differences
This shows you the differences between two versions of the page.
Both sides previous revision Previous revision Next revision | Previous revision | ||
ref_manual:selects [2012/03/15 09:03] 109.230.216.225 FQMiCeqSQnI |
ref_manual:selects [2012/05/24 21:17] (current) oej |
||
---|---|---|---|
Line 1: | Line 1: | ||
- | Hmm it seems like your site ate my first comment | + | ====== The Select Framework ====== |
+ | //(written by Michal Matyska)// | ||
+ | |||
+ | You might ask, why the select framework | ||
+ | was that everytime you wanted to check any part (header, etc.) of the | ||
+ | incoming message you had to write new module/new function which did that. | ||
+ | Moreover this function (due to historic limitations) might get at most two | ||
+ | parameters. If you need more you have to use workaround and set attributes | ||
+ | which are then checked from this function. So to make the route script more | ||
+ | readable and understandable a new element has started to be supported - the | ||
+ | select framework. | ||
+ | |||
+ | In the script the select is identified by it's unique name. The intention is | ||
+ | to make the identifier as much understandable as possible, | ||
+ | '' | ||
+ | present in the " | ||
+ | script, it is actually its value, which is then used during the route script | ||
+ | process. | ||
+ | |||
+ | To make the select framework speed efficient, the identifier of the select is | ||
+ | parsed and fixed on the SER startup. If it is not valid select identifier, | ||
+ | error message is dumped and SER does not start at all. But then, during the | ||
+ | request route script execution, there is just single function call invocation, | ||
+ | which gets the parsed select identifier as parameter if it needs it for any | ||
+ | purpose. From the performance point of view there is almost no difference | ||
+ | between calling specialized function from any module | ||
+ | which represents the select identifier. | ||
+ | |||
+ | ===== Overview of Operation ===== | ||
+ | What we call select is basically unified notation for calling function which | ||
+ | is defined as select function either in SER's core or from any module. The | ||
+ | identifier starts with at sign and consists of few text elements denoted by | ||
+ | dot optionally adding single integer or string parameter enclosed in square | ||
+ | brackets. | ||
+ | |||
+ | You can use selects in the routing script in the expression evaluation, as | ||
+ | right side of attribute assignment and as parameters in some function calls. | ||
+ | (This is limited to functions which support this and the parameter is actually | ||
+ | text with the select identifier, so it must be enclosed in double quotes.) | ||
+ | Xlog formatting also support selects as a element while composing the final | ||
+ | value - the formatting element is '' | ||
+ | |||
+ | Return value of the select is text string, | ||
+ | string with 0 length (empty string) if such value is allowed (e.g. some uri | ||
+ | parameter value) or when select function signalizes that expected value was | ||
+ | not found in the header or message parsing encountered syntax error. This kind | ||
+ | of error has influence on the conditional expression - if there is problem | ||
+ | with the select evaluation, the result is false regardless it matches the | ||
+ | empty string. | ||
+ | |||
+ | ===== Select Identifiers ===== | ||
+ | Select identifier starts with at sign (@) followed by at least one (at most | ||
+ | 30) text elements each separated by dot (.) from the previous one. The | ||
+ | identifier elements are case insensitive, | ||
+ | emphasize some of them, but lower case is preferred. Some of the select | ||
+ | functions accept parameters (like index of the repetead headers, or the header | ||
+ | name or authorization realm) - this parameter is expressed in the identifier | ||
+ | by enclosing it with square brackets. The index starts counting from 1 | ||
+ | (programmers be aware), because it is more natural and you can also express | ||
+ | that you want count the headers in the opposite direction and get the last | ||
+ | header (using -1 as the index). | ||
+ | |||
+ | Examples of identifiers (syntactically valid): | ||
+ | * '' | ||
+ | * '' | ||
+ | * '' | ||
+ | * '' | ||
+ | |||
+ | ===== Nested Selects ===== | ||
+ | You might find some repeating patterns in the SIP requests, like that there is | ||
+ | URI element present in quite a lot of SIP headers. The select framework has | ||
+ | possibility | ||
+ | function already included in the core (or parser of parameter values (either | ||
+ | header or URI), or any other if you are able to think it off) and apply it on | ||
+ | intermediate select result. This so called nested select (see developers' | ||
+ | if you are interested) divides the select call to two (or more) separate | ||
+ | function calls, where the first one returns the URI text as temporary result, | ||
+ | which is then passed to the built-in URI select machinery as the value which | ||
+ | should be used for the final result. | ||
+ | '' | ||
+ | header, assuming it is conforming to the name-addr RFC specification and | ||
+ | passes the header value to the name-addr select-parser, | ||
+ | username from the URI and returns that as the final value of the select. | ||
+ | |||
+ | So every of these URIs (select' | ||
+ | select, which makes individual URI parts accessible. | ||
+ | |||
+ | @request_uri, | ||
+ | @rpid.uri, @contact.uri, | ||
+ | @hf_value![" | ||
+ | |||
+ | Now if you want just the username, append .user to the select identifier and | ||
+ | you get the username. The .user identifier part is everytime same regardless | ||
+ | which URI was selected in the first step. | ||
+ | |||
+ | Here is the list of all URI's nested select identifiers: | ||
+ | * '' | ||
+ | * '' | ||
+ | * '' | ||
+ | * '' | ||
+ | * '' | ||
+ | |||
+ | * '' | ||
+ | * '' | ||
+ | * '' | ||
+ | * '' | ||
+ | |||
+ | ===== Selects in Expressions ===== | ||
+ | You can use the select in the conditional expressions like these: | ||
+ | |||
+ | if (@select.value) {...} | ||
+ | |||
+ | the test is true, when the select returns NON-EMPTY string. | ||
+ | |||
+ | < | ||
+ | This way of using select is obsolete and it will generate a warning message on start-up. | ||
+ | For sip-router the if will be true only if it returns a non-empty, non-zero numerical string (e.g. " | ||
+ | The preferred correct ways for sip-router are: | ||
+ | |||
+ | if (@select.value!="" | ||
+ | |||
+ | or | ||
+ | |||
+ | if (!strempty(@select.value)) | ||
+ | |||
+ | </ | ||
+ | |||
+ | |||
+ | if (@select.value==" | ||
+ | if (" | ||
+ | |||
+ | the result is true, when the select is error-free and its return value is equal to " | ||
+ | Instead of a constant value, you can use any expression (it could involve avps, pvars or other selects). | ||
+ | |||
+ | if (@select.value!=" | ||
+ | if (" | ||
+ | |||
+ | in this case the test checks whether the two strings are different. If | ||
+ | there is error during the select evaluation, the result is also false. | ||
+ | |||
+ | if (@select.value=~" | ||
+ | |||
+ | true, when the string returned by select function matches the regular | ||
+ | expression. In this case swapping of the left and right values matter, so | ||
+ | |||
+ | if (" | ||
+ | |||
+ | is true when the " | ||
+ | obtained as select's return value. This is what you usually don't want. | ||
+ | |||
+ | You can also use the select in any kind of expression, be it in the right hand of an assignment, in an if, while() or switch(). | ||
+ | |||
+ | E.g.: | ||
+ | $attribute=@the.select.you.want | ||
+ | |||
+ | ===== Selects in Parameters ===== | ||
+ | Some functions allow to pass the select' | ||
+ | function must support that, so it is not possible for every function. The | ||
+ | parameter holds the select identifier and the function is responsible to | ||
+ | resolve and fixup the indetifier at SER startup and then call the select | ||
+ | function to obtain the return value. | ||
+ | |||
+ | If the select' | ||
+ | the function is false and the rest of the function' | ||
+ | over. | ||
+ | |||
+ | ===== System Selects ===== | ||
+ | As the select framework has begun to show its strength, new ideas whatever | ||
+ | else could be accessible using select call has emerged. The example of that | ||
+ | are system selects which' | ||
+ | |||
+ | * '' | ||
+ | * '' | ||
+ | * '' | ||
+ | * '' | ||
+ | |||
+ | ===== Selects in Modules ===== | ||
+ | As you can see, the select framework is very powerfull tool, which can be | ||
+ | easily extended using the SER's modules concept. E.g. the TLS module, there is | ||
+ | lot of TLS information you can get/check in the script, but only when the TLS | ||
+ | module is used. So all the TLS related selects are part of the TLS module... | ||
+ | if you use the module, then they are available, if you don't use the module, | ||
+ | they are not and SER will complain about the wrong select identifier and | ||
+ | decline to start. | ||
+ | |||
+ | On the other hand, there is no difference between the module' | ||
+ | core's selects, so you don't really need to care where is the source of the | ||
+ | select, just make sure you have loaded all neccessary modules. | ||
+ | |||
+ | |||
+ | ===== Select List ===== | ||
+ | |||
+ | For a list with all the defined selects in the sip-router devel version (master branch), see | ||
+ | [[http:// |