mirror of https://github.com/sipwise/kamailio.git
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
708 lines
20 KiB
708 lines
20 KiB
|
|
UID AVP DB Module
|
|
|
|
Jiri Kuthan
|
|
|
|
FhG FOKUS
|
|
<jiri@iptel.org>
|
|
|
|
Copyright © 2004, 2005 FhG FOKUS
|
|
_________________________________________________________________
|
|
|
|
Table of Contents
|
|
|
|
1. Admin Guide
|
|
|
|
1. Overview
|
|
2. Dependencies
|
|
3. Parameters
|
|
|
|
3.1. db_url (string)
|
|
3.2. user_attrs_table (string)
|
|
3.3. uri_attrs_table (string)
|
|
3.4. uid_column (string)
|
|
3.5. username_column (string)
|
|
3.6. did_column (string)
|
|
3.7. name (string)
|
|
3.8. value_column (string)
|
|
3.9. type_column (string)
|
|
3.10. flags_column (string)
|
|
3.11. scheme_column (string)
|
|
3.12. attr_group (string)
|
|
3.13. auto_unlock_extra_attrs (string)
|
|
|
|
4. Functions
|
|
|
|
4.1. load_attrs (track, id)
|
|
4.2. load_extra_attrs (group_id, id)
|
|
4.3. save_extra_attrs (group_id, id)
|
|
4.4. remove_extra_attrs (group_id, id)
|
|
4.5. lock_extra_attrs (group_id, id)
|
|
4.6. unlock_extra_attrs (group_id, id)
|
|
|
|
5. Example extra attributes usage
|
|
|
|
List of Examples
|
|
|
|
1.1. attribute group definition
|
|
|
|
Chapter 1. Admin Guide
|
|
|
|
Table of Contents
|
|
|
|
1. Overview
|
|
2. Dependencies
|
|
3. Parameters
|
|
|
|
3.1. db_url (string)
|
|
3.2. user_attrs_table (string)
|
|
3.3. uri_attrs_table (string)
|
|
3.4. uid_column (string)
|
|
3.5. username_column (string)
|
|
3.6. did_column (string)
|
|
3.7. name (string)
|
|
3.8. value_column (string)
|
|
3.9. type_column (string)
|
|
3.10. flags_column (string)
|
|
3.11. scheme_column (string)
|
|
3.12. attr_group (string)
|
|
3.13. auto_unlock_extra_attrs (string)
|
|
|
|
4. Functions
|
|
|
|
4.1. load_attrs (track, id)
|
|
4.2. load_extra_attrs (group_id, id)
|
|
4.3. save_extra_attrs (group_id, id)
|
|
4.4. remove_extra_attrs (group_id, id)
|
|
4.5. lock_extra_attrs (group_id, id)
|
|
4.6. unlock_extra_attrs (group_id, id)
|
|
|
|
5. Example extra attributes usage
|
|
|
|
1. Overview
|
|
|
|
This module contains several functions that can be used to manipulate
|
|
the contents of AVPs (Attribute-Value pairs). The AVPs are variables
|
|
attached to the SIP message being processed. Each variable has its
|
|
name and value. AVPs can be used to store arbitrary data or as a means
|
|
of inter-module comminication.
|
|
|
|
You may also want to check the avpops module which is more flexible
|
|
and contains more functions. In future SER releases the avp module
|
|
will be probably deprecated in favor of avpops module.
|
|
|
|
Domain module operates in caching mode. Domain module reads the
|
|
default values of AVPs into cache memory when the module is loaded.
|
|
After that default values is re-read only when module is given
|
|
avp_list_reload fifo command. Any changes in usr_preferences_types
|
|
table must thus be followed by avp_list_reload command in order to
|
|
reflect them in module behavior.
|
|
|
|
2. Dependencies
|
|
|
|
A database module, such as mysql, postgres, or dbtext.
|
|
|
|
3. Parameters
|
|
|
|
3.1. db_url (string)
|
|
3.2. user_attrs_table (string)
|
|
3.3. uri_attrs_table (string)
|
|
3.4. uid_column (string)
|
|
3.5. username_column (string)
|
|
3.6. did_column (string)
|
|
3.7. name (string)
|
|
3.8. value_column (string)
|
|
3.9. type_column (string)
|
|
3.10. flags_column (string)
|
|
3.11. scheme_column (string)
|
|
3.12. attr_group (string)
|
|
3.13. auto_unlock_extra_attrs (string)
|
|
|
|
3.1. db_url (string)
|
|
|
|
The URL of the database to be used.
|
|
|
|
Default value is "mysql://ser:heslo@localhost/ser".
|
|
|
|
3.2. user_attrs_table (string)
|
|
|
|
Name of the table with user attributes.
|
|
|
|
Default value is "user_attrs".
|
|
|
|
3.3. uri_attrs_table (string)
|
|
|
|
Name of the table with uri attributes.
|
|
|
|
Default value is "uri_attrs".
|
|
|
|
3.4. uid_column (string)
|
|
|
|
Name of the column that stores UID in the user attributes table.
|
|
|
|
Default value is "uid".
|
|
|
|
3.5. username_column (string)
|
|
|
|
Name of the column containing the username of the subscriber in uri
|
|
attributes table.
|
|
|
|
Default value is "username".
|
|
|
|
3.6. did_column (string)
|
|
|
|
Name of the column in uri attributes table containing the ID of domain
|
|
that the subscriber belongs to.
|
|
|
|
Default value is "did".
|
|
|
|
3.7. name (string)
|
|
|
|
The name of the column containing attribute names.
|
|
|
|
Default value is "name".
|
|
|
|
3.8. value_column (string)
|
|
|
|
The name of the column containing attribute values.
|
|
|
|
Default value is "value".
|
|
|
|
3.9. type_column (string)
|
|
|
|
The name of the column containing attribute value type.
|
|
|
|
Default value is "type".
|
|
|
|
3.10. flags_column (string)
|
|
|
|
The name of the column containing attribute flags.
|
|
|
|
Default value is "flags".
|
|
|
|
3.11. scheme_column (string)
|
|
|
|
The name of the column containing subscriber's scheme in uri
|
|
attributes.
|
|
|
|
Default value is "scheme".
|
|
|
|
3.12. attr_group (string)
|
|
|
|
'Extra attribute' group definition. It can be repeated to define more
|
|
attribute groups.
|
|
|
|
The group definition contains one or more assignments in the form
|
|
key=value. Possible keys are:
|
|
|
|
id
|
|
Attribute group identifier. Must be set.
|
|
|
|
table
|
|
Table name used for storing attributes from this attribute
|
|
group. Must be set.
|
|
|
|
flag
|
|
Attribute flag name used to mark attributes in this group. Must
|
|
be set.
|
|
|
|
key_column
|
|
Column name holding key. Default value is "id".
|
|
|
|
name_column
|
|
Column name used for storing attribute name. Default value is
|
|
"name".
|
|
|
|
value_column
|
|
Column name used for storing attribute value. Default value is
|
|
"value".
|
|
|
|
type_column
|
|
Column name used for storing attribute type. Default value is
|
|
"type".
|
|
|
|
flags_column
|
|
Column name used for storing attribute flags. Default value is
|
|
"flags".
|
|
|
|
None defined by default.
|
|
|
|
Example 1.1. attribute group definition
|
|
modparam("avp_db", "attr_group", "id=dlg,flag=dialog_flag,table=dlg_attrs,key_c
|
|
olumn=dlg_id");
|
|
|
|
Table used for these attributes:
|
|
mysql> describe dlg_attrs;
|
|
+--------+------------------+------+-----+---------+-------+
|
|
| Field | Type | Null | Key | Default | Extra |
|
|
+--------+------------------+------+-----+---------+-------+
|
|
| dlg_id | varchar(256) | NO | MUL | | |
|
|
| name | varchar(32) | NO | | | |
|
|
| value | varchar(255) | YES | | NULL | |
|
|
| type | int(11) | NO | | 0 | |
|
|
| flags | int(10) unsigned | NO | | 0 | |
|
|
+--------+------------------+------+-----+---------+-------+
|
|
5 rows in set (0.00 sec)
|
|
|
|
Setting flags from code (all attrs beginning with "dlg_"):
|
|
avpflags dialog_flag;
|
|
...
|
|
route {
|
|
...
|
|
setavpflag("$f./^dlg_/", "dialog_flag");
|
|
...
|
|
}
|
|
|
|
3.13. auto_unlock_extra_attrs (string)
|
|
|
|
Determines the action when any of the 'extra attributes' lock is
|
|
detected when routing script execution was finished. When the value of
|
|
this parameter is zero (default) BUG level message is logged, but the
|
|
lock is kept, so another process trying to obtain the lock might get
|
|
stuck. If the value is nonzero, DEBUG level message is sent to the log
|
|
and all the locks are released.
|
|
|
|
Default value is 0.
|
|
|
|
4. Functions
|
|
|
|
4.1. load_attrs (track, id)
|
|
4.2. load_extra_attrs (group_id, id)
|
|
4.3. save_extra_attrs (group_id, id)
|
|
4.4. remove_extra_attrs (group_id, id)
|
|
4.5. lock_extra_attrs (group_id, id)
|
|
4.6. unlock_extra_attrs (group_id, id)
|
|
|
|
4.1. load_attrs (track, id)
|
|
|
|
Loads attributes from the database.
|
|
|
|
track
|
|
|
|
$fu
|
|
Load user attributes into from track. In this case the
|
|
second parameter is UID used to search attributes.
|
|
|
|
$tu
|
|
Load user attributes into to track. In this case the
|
|
second parameter is UID used to search attributes.
|
|
|
|
$fr
|
|
Load uri attributes into from track. In this case the
|
|
second parameter is URI used to search attributes.
|
|
|
|
$tr
|
|
Load uri attributes into to track. In this case the
|
|
second parameter is URI used to search attributes.
|
|
|
|
id
|
|
Identifier used for searching attributes. When searching for
|
|
user attributes it is UID, when searchnig uri attributes it is
|
|
URI.
|
|
|
|
4.2. load_extra_attrs (group_id, id)
|
|
|
|
Loads 'extra attributes' stored by previous call to save_extra_attrs.
|
|
|
|
group_id
|
|
Identifies attribute group, see Section 3.12, "attr_group
|
|
(string)".
|
|
|
|
id
|
|
Identifies attributes which should be loaded.
|
|
|
|
4.3. save_extra_attrs (group_id, id)
|
|
|
|
Saves 'extra attributes' flagged by group flag under given id.
|
|
|
|
group_id
|
|
Identifies attribute group, see Section 3.12, "attr_group
|
|
(string)".
|
|
|
|
id
|
|
Identifier stored with flagged attributes.
|
|
|
|
4.4. remove_extra_attrs (group_id, id)
|
|
|
|
Removes all extra attributes with given id.
|
|
|
|
group_id
|
|
Identifies attribute group, see Section 3.12, "attr_group
|
|
(string)".
|
|
|
|
id
|
|
Identifies attributes which should be removed.
|
|
|
|
4.5. lock_extra_attrs (group_id, id)
|
|
|
|
Locks extra attributes. Currently locks whole attribute group (not
|
|
only id).
|
|
|
|
group_id
|
|
Identifies attribute group, see Section 3.12, "attr_group
|
|
(string)".
|
|
|
|
id
|
|
Identifies attributes which should be locked.
|
|
|
|
4.6. unlock_extra_attrs (group_id, id)
|
|
|
|
Unlocks extra attributes. Currently unlocks whole attribute group (not
|
|
only id).
|
|
|
|
group_id
|
|
Identifies attribute group, see Section 3.12, "attr_group
|
|
(string)".
|
|
|
|
id
|
|
Identifies attributes which should be unlocked.
|
|
|
|
5. Example extra attributes usage
|
|
|
|
debug=3
|
|
memdbg=5
|
|
server_signature=0
|
|
sip_warning=0
|
|
check_via=yes;
|
|
dns=no;
|
|
rev_dns=no;
|
|
|
|
children=4;
|
|
tcp_children=4;
|
|
tcp_max_connections=2048;
|
|
port=5060
|
|
|
|
loadmodule "/home/kubartv/SER/lib/ser/modules/sl.so";
|
|
#loadmodule "/home/kubartv/SER/lib/ser/modules/maxfwd.so";
|
|
loadmodule "/home/kubartv/SER/lib/ser/modules/tm.so";
|
|
loadmodule "/home/kubartv/SER/lib/ser/modules/rr.so";
|
|
#loadmodule "/home/kubartv/SER/lib/ser/modules/xmlrpc.so";
|
|
loadmodule "/home/kubartv/SER/lib/ser/modules/mysql.so";
|
|
loadmodule "/home/kubartv/SER/lib/ser/modules/domain.so";
|
|
loadmodule "/home/kubartv/SER/lib/ser/modules/uri_db.so";
|
|
loadmodule "/home/kubartv/SER/lib/ser/modules/avp.so";
|
|
loadmodule "/home/kubartv/SER/lib/ser/modules/avp_db.so";
|
|
|
|
loadmodule "/home/kubartv/SER/lib/ser/modules/usrloc.so";
|
|
loadmodule "/home/kubartv/SER/lib/ser/modules/registrar.so";
|
|
loadmodule "/home/kubartv/SER/lib/ser/modules/xprint.so";
|
|
loadmodule "/home/kubartv/SER/lib/ser/modules/eval.so";
|
|
|
|
loadmodule "/home/kubartv/SER/lib/ser/modules/gflags.so"
|
|
|
|
#modparam("maxfwd", "max_limit", 70);
|
|
|
|
modparam("usrloc", "db_mode", 1);
|
|
modparam("usrloc|avp_db", "db_url", "mysql://ser:heslo@127.0.0.1/ser")
|
|
|
|
modparam("avp_db", "attr_group", "id=dlg,flag=dialog_flag,table=dlg_attrs,key_c
|
|
olumn=dlg_id");
|
|
|
|
modparam("gflags", "load_global_attrs", 1);
|
|
|
|
avpflags dialog_flag;
|
|
|
|
route["create_dialog"] {
|
|
# sets attributes needed by dialog (stored when processing reply)
|
|
$dlg_caller = @contact;
|
|
$dlg_caller_cseq = @cseq.num;
|
|
$dlg_status = "new";
|
|
$dlg_init_method = @cseq.method;
|
|
$dir = "caller2callee";
|
|
|
|
t_on_reply("dialog_creation_reply");
|
|
return 1;
|
|
}
|
|
|
|
onreply_route["dialog_creation_reply"] {
|
|
xplog("L_ERR", "dialog creation reply (%rs, %@cseq.method) [%@from.tag,
|
|
%@to.tag]\n");
|
|
|
|
$res = @msg.response.code;
|
|
xplog("L_ERR", " ... response: %$res\n");
|
|
if ((!@to.tag) || (@to.tag=="")) {
|
|
# don't create dialog from response without to tag
|
|
break;
|
|
}
|
|
if ($res < 101) {
|
|
xplog("L_ERR", " ... I won't create dialog from 100 response.\n
|
|
");
|
|
break;
|
|
}
|
|
|
|
del_attr("$id"); # xlset_attr works strange when the attribute already
|
|
exists
|
|
xlset_attr("$id", "call-id:%@call_id caller_tag:%@from.tag callee_tag:%
|
|
@to.tag");
|
|
if ($res > 299) {
|
|
xplog("L_ERR", " ... dialog terminated\n");
|
|
remove_extra_attrs("dlg", "$id");
|
|
break;
|
|
}
|
|
|
|
xplog("L_ERR", " ... creating dialog '%$id'\n");
|
|
# generate dialog id
|
|
|
|
lock_extra_attrs("dlg", "$id");
|
|
|
|
# TODO: try to load the dialog (early dialog may exist)?
|
|
|
|
# update dialog data
|
|
|
|
if (($dlg_status == "new") && ($res < 200)) {
|
|
# early response may arrive after final one
|
|
$dlg_callee = @contact;
|
|
$dlg_status = "early";
|
|
xplog("L_ERR", " ... creating early dialog\n");
|
|
}
|
|
if ($res >= 200) {
|
|
$dlg_callee = @contact;
|
|
$dlg_status = "confirmed";
|
|
$dlg_confirmed_at = @sys.now.local;
|
|
xplog("L_ERR", " ... confirming dialog\n");
|
|
}
|
|
|
|
route("save_dialog");
|
|
}
|
|
|
|
route["save_dialog"] {
|
|
if ($dlg_status == "destroyed") {
|
|
xplog("L_ERR", " ... destroying dialog %$id\n");
|
|
|
|
# use this if you want to delete destroyed dialogs:
|
|
# remove_extra_attrs("dlg", "$id");
|
|
|
|
# else if you want leave them in DB (with the time of terminati
|
|
on)
|
|
$dlg_destroyed_at = @sys.now.local;
|
|
|
|
# set flag for attributes with name beggining with dlg_
|
|
setavpflag("$f./^dlg_/", "dialog_flag");
|
|
save_extra_attrs("dlg", "$id");
|
|
}
|
|
else {
|
|
# set flag for attributes with name beggining with dlg_
|
|
setavpflag("$f./^dlg_/", "dialog_flag");
|
|
|
|
save_extra_attrs("dlg", "$id");
|
|
}
|
|
unlock_extra_attrs("dlg", "$id");
|
|
}
|
|
|
|
route["load_dialog_data"] {
|
|
lock_extra_attrs("dlg", "$id");
|
|
|
|
del_attr("$dlg_init_method"); # used as flag of succesful read of data
|
|
|
|
# delete all used dlg attrs (because load_extra_attrs doesn't delete th
|
|
em itself before adding)
|
|
del_attr("$dlg_init_method");
|
|
del_attr("$dlg_caller");
|
|
del_attr("$dlg_callee");
|
|
del_attr("$dlg_caller_cseq");
|
|
del_attr("$dlg_callee_cseq");
|
|
del_attr("$dlg_status");
|
|
|
|
load_extra_attrs("dlg", "$id");
|
|
if (!$dlg_init_method) {
|
|
# dialog was not loaded
|
|
unlock_extra_attrs("dlg", "$id");
|
|
return -1;
|
|
}
|
|
return 1;
|
|
}
|
|
|
|
route["load_dialog"] {
|
|
# tries to load dialog according tags and callid
|
|
|
|
# try to load dialog
|
|
del_attr("$id"); # xlset_attr works strange when the attribute already
|
|
exists
|
|
xlset_attr("$id", "call-id:%@call_id caller_tag:%@from.tag callee_tag:%
|
|
@to.tag");
|
|
if (route("load_dialog_data")) {
|
|
$dir = "caller2callee";
|
|
return 1;
|
|
}
|
|
|
|
# try to load dialog in other direction
|
|
del_attr("$id"); # xlset_attr works strange when the attribute already
|
|
exists
|
|
xlset_attr("$id", "call-id:%@call_id caller_tag:%@to.tag callee_tag:%@f
|
|
rom.tag");
|
|
if (route("load_dialog_data")) {
|
|
$dir = "callee2caller";
|
|
return 1;
|
|
}
|
|
|
|
$id = "error";
|
|
|
|
return -1;
|
|
}
|
|
|
|
route["update_dialog_reply"] {
|
|
if ((@cseq.method == "INVITE") || (@cseq.method == "UPDATE")) {
|
|
# target refresh for INVITE dialogs
|
|
|
|
if ($dir == "caller2calle") { # if request from caller
|
|
$dlg_callee = @contact; # update callee's contact (resp
|
|
onse!)
|
|
}
|
|
else {
|
|
$dlg_caller = @contact;
|
|
}
|
|
}
|
|
if (@cseq.method=="BYE") {
|
|
$dlg_status = "destroyed"; # will be removed in save_dialog
|
|
}
|
|
}
|
|
|
|
route["update_dialog"] {
|
|
if ((@cseq.method == "INVITE") || (@cseq.method == "UPDATE")) {
|
|
# target refresh for INVITE dialogs
|
|
|
|
if ($dir == "caller2calle") { # if request from caller
|
|
$dlg_caller = @contact; # update caller's contact (requ
|
|
est!)
|
|
}
|
|
else {
|
|
$dlg_callee = @contact;
|
|
}
|
|
}
|
|
|
|
if ($dir == "caller2callee") { # if request from caller
|
|
# TODO: verify CSeq before modifying and return 500 if lower th
|
|
an last one
|
|
$dlg_caller_cseq = @cseq.num;
|
|
}
|
|
else {
|
|
# TODO: verify CSeq before modifying and return 500 if lower th
|
|
an last one
|
|
$dlg_callee_cseq = @cseq.num;
|
|
}
|
|
|
|
if (method=="BYE") {
|
|
$dlg_status = "pre-destroyed"; # to see that BYE already went t
|
|
hrough
|
|
}
|
|
return 1;
|
|
}
|
|
|
|
route["trace_dialog"] {
|
|
xplog("L_ERR", " ... dialog '%$id'\n");
|
|
xplog("L_ERR", " -> initial method: %$dlg_init_method\n");
|
|
xplog("L_ERR", " -> request dir: %$dir\n");
|
|
xplog("L_ERR", " -> caller: %$dlg_caller\n");
|
|
xplog("L_ERR", " -> caller's CSeq: %$dlg_caller_cseq\n");
|
|
xplog("L_ERR", " -> callee: %$dlg_callee\n");
|
|
xplog("L_ERR", " -> callee's CSeq: %$dlg_callee_cseq\n");
|
|
xplog("L_ERR", " -> status: %$dlg_status\n");
|
|
return 1;
|
|
}
|
|
|
|
onreply_route["dialog_reply"] {
|
|
if ($id) {
|
|
xplog("L_ERR", "In-dialog reply (%rs, %@cseq.method) [%@to.tag,
|
|
%@from.tag]\n");
|
|
if (!route("load_dialog")) {
|
|
xplog("L_ERR", "Can't load dialog data\n");
|
|
}
|
|
else {
|
|
route("update_dialog_reply");
|
|
route("trace_dialog");
|
|
route("save_dialog");
|
|
}
|
|
}
|
|
}
|
|
|
|
route {
|
|
if (method=="SUBSCRIBE") {
|
|
# here we support only INVITE/BYE dialogs
|
|
sl_reply("400", "Unsupported");
|
|
break;
|
|
}
|
|
|
|
if (!lookup_domain("$td", "@to.uri.host")) {
|
|
sl_send_reply("404", "Domain Not Found");
|
|
break;
|
|
}
|
|
|
|
if (!lookup_user("To")) {
|
|
sl_send_reply("404", "Unknown user");
|
|
break;
|
|
}
|
|
|
|
if (method=="REGISTER") {
|
|
save("location");
|
|
break;
|
|
};
|
|
|
|
xplog("L_ERR", "----> processing request %@cseq.method\n");
|
|
|
|
if (!lookup_domain("$fd", "@from.uri.host")) {
|
|
sl_send_reply("404", "From domain Not Found");
|
|
break;
|
|
}
|
|
|
|
if (!lookup_user("From")) {
|
|
sl_send_reply("404", "Unknown user in From");
|
|
break;
|
|
}
|
|
|
|
if (method != "REGISTER") record_route();
|
|
|
|
# dialog needs transactions
|
|
if (!t_newtran()) {
|
|
sl_send_reply("500", "Can not start transaction");
|
|
drop;
|
|
}
|
|
|
|
# dialog creation/loading
|
|
if (!@to.tag || (@to.tag == "")) {
|
|
# initial request or non-dialog message
|
|
if (method=="INVITE") {
|
|
route("create_dialog");
|
|
# we don't save the dialog here because AVPs will be se
|
|
t
|
|
# when reply comes and the dialog will be stored then
|
|
}
|
|
else {
|
|
xplog("L_ERR", "Non-dialog message: %@cseq\n");
|
|
}
|
|
}
|
|
else {
|
|
# message within dialog
|
|
if (route("load_dialog")) {
|
|
route("update_dialog");
|
|
route("trace_dialog");
|
|
route("save_dialog");
|
|
t_on_reply("dialog_reply");
|
|
}
|
|
else {
|
|
xplog("L_ERR", "Message within unknown dialog: %@cseq,
|
|
to_tag=%@to.tag from_tag=%@from.tag\n");
|
|
}
|
|
}
|
|
|
|
if (loose_route()) {
|
|
route(1);
|
|
break;
|
|
}
|
|
|
|
if (!lookup("location")) {
|
|
t_reply("404", "Not Found");
|
|
break;
|
|
};
|
|
route(1);
|
|
}
|
|
|
|
route[1]
|
|
{
|
|
xplog("L_ERR", "<---- request %@cseq.method processed\n");
|
|
# send it out now; use stateful forwarding as it works reliably
|
|
# even for UDP2TCP
|
|
if (!t_relay()) {
|
|
sl_reply_error();
|
|
};
|
|
}
|